#!/usr/bin/env python
#Sam Calisch, calisch@mit.edu, 2012
#paddle geom generation from parameters

from __future__ import division
import rhinoscriptsyntax as rs
from math import *
from convenience import *

def SetupLayers():
	rs.AddLayer ("cross", green)
	rs.AddLayer ("outline", blue)

#compute line-line intersection
def Intersection2D(p0,v0,p1,v1):
	if v0[1] - v0[0]*v1[1]/v1[0] == 0:
		return -1 #no intersection
	elif v1[0] != 0:
		s = (p1[1]-p0[1] + v1[1]/v1[0]*(p0[0]-p1[0]))/(v0[1]-v0[0]*v1[1]/v1[0])
		return ss(p0,sm(s,v0))
	else:
		t = (p1[0]-p0[0] + v1[0]/v1[1]*(p0[1]-p1[1]))/(v0[0]-v0[1]*v1[0]/v1[1])
		return ss(p0,sm(t,v0))

#def SimpleNurbs(pts):
#	degree = 2
#	knots = range(len(pts)-1)
#	knots.insert(0,0)
#	knots.append(len(pts)-2)
#	return rs.AddNurbsCurve(pts,knots,degree)

def DrawOutline(length, width, shaft_diam, collar_length, assym=0):
	objs = []
	assym = pi*assym/180.
	p0 = [0,shaft_diam/2,0]
	p1 = [length/2,width/2,0]
	p3 = [length,0,0]
	p2 = Intersection2D(p1,[1,0,0],p3,[sin(assym),cos(assym),0])
	p5 = [length/2,-width/2,0]
	p4 = Intersection2D(p5,[1,0,0],p3,[-sin(assym),-cos(assym),0])
	p6 = [0,-shaft_diam/2,0]

	pts = [p0,ss(p0,[.5*collar_length,0,0]),ss(p0,[collar_length,0,0]),ss(p0,[1.5*collar_length,0,0]),p1,p2,p4,p5,ss(p6,[1.5*collar_length,0,0]),ss(p6,[collar_length,0,0]),ss(p6,[.5*collar_length,0,0]),p6]
	pl = rs.AddPolyline(pts)
	cl = rs.CurveLength(pl)
	rs.DeleteObject(pl)
	degree = 2
	knots = range(len(pts)-1)
	knots.append(len(pts)-2)
	knots.insert(0,0)
	knots = [cl*i/len(pts) for i in knots]
	n = rs.AddNurbsCurve(pts,knots,degree)
	return n

#dir is 1 for right, -1 for left
def add_edge(p1,p2,dir=1):
	d = smag(sd(p1,p2))
	p3 = ss( sm(.5, ss(p1,p2) ) , [0,.5*dir*d,0])
	return rs.AddArc3Pt(p1,p2,p3)

def DrawCrossSections(length, width, shaft_diam, outline, collar_length,dihedral, res=10):
	dihedral = dihedral*pi/180.
	lat_taper = 5 #linear fade within width/2 of end
	thickness = 3
	taper_end = .75*(length-collar_length) + collar_length
	sections = []
	for i in range(res):
		objs = []
		x = i*length/res
		l = rs.AddLine([x,-width,0],[x,width,0])
		#p = rs.PlaneFromNormal([x,0,0],[1,0,0])
		result = rs.CurveCurveIntersection(outline,l)
		rs.DeleteObject(l)

		p0 = result[0][1]
		p0 = [p0.X,p0.Y,p0.Z]
		p1 = result[1][1]
		p1 = [p1.X,p1.Y,p1.Z]

		collar_ratio = min(1,(x-collar_length)/(.5*collar_length))
		if (dihedral != 0):
			p0 = [p0[0],p0[1],-p0[1]*tan(dihedral)*collar_ratio]
			p1 = [p1[0],p1[1],p1[1]*tan(dihedral)*collar_ratio]

		p6 = ss(p0,[0,0,-thickness*collar_ratio])
		p7 = ss(p1,[0,0,-thickness*collar_ratio])			

		r = .5*shaft_diam*(taper_end-(x-collar_length))/taper_end
		if collar_length < x < taper_end and r > lat_taper:
			ratio = (x-collar_length)/(taper_end-collar_length)
			p2 = [x,r-lat_taper*ratio,lat_taper*collar_ratio]
			p3 = [x,-r+lat_taper*ratio,lat_taper*collar_ratio]

			p4 = [x,r-lat_taper*ratio,-lat_taper*collar_ratio-thickness*collar_ratio]
			p5 = [x,-r+lat_taper*ratio,-lat_taper*collar_ratio-thickness*collar_ratio]

			objs.append(rs.AddArc3Pt(p2,p3,[x,0,r]))
			objs.append(rs.AddLine(p0,p2))
			objs.append(rs.AddLine(p1,p3))
			if -r < -lat_taper-thickness:
				objs.append(rs.AddArc3Pt(p4,p5,[x,0,-r]))
			else:
				objs.append(rs.AddLine(p4,p5))

			objs.append(rs.AddLine(p6,p4))
			objs.append(rs.AddLine(p7,p5))

			#objs.append(rs.AddLine(p0,p6))
			objs.append(add_edge(p0,p6,.8))
#			objs.append(rs.AddLine(p1,p7))
			objs.append(add_edge(p1,p7,-.8))

		elif x < collar_length:
			objs.append(rs.AddArc3Pt([x,shaft_diam/2.,0],[x,-shaft_diam/2.,0],[x,0,shaft_diam/2.]))
			objs.append(rs.AddArc3Pt([x,shaft_diam/2.,0],[x,-shaft_diam/2.,0],[x,0,-shaft_diam/2.]))
		else:
			lt = lat_taper
			if x > length - width/2.:
				lt = lat_taper*(length-x)/(width/2.)
			objs.append(rs.AddLine(p0,[x,0,lt]))
			objs.append(rs.AddLine(p1,[x,0,lt]))

			objs.append(rs.AddLine(p6,[x,0,-lt-thickness]))
			objs.append(rs.AddLine(p7,[x,0,-lt-thickness]))

#			objs.append(rs.AddLine(p0,p6))
			objs.append(add_edge(p0,p6,.8))
			objs.append(add_edge(p1,p7,-.8))
			#			objs.append(rs.AddLine(p1,p7))

		l = rs.JoinCurves(objs,delete_input=True)

		assert(len(l)==1)
		#test orientation
		n = rs.CurveNormal(l[0])
		if( n[0] < 0):
			rs.ReverseCurve(l[0])
		sections.append(l[0])
	i=i+1
	while True:
		objs = []
		x = i*length/res
		l = rs.AddLine([x,-width,0],[x,width,0]);
		result = rs.CurveCurveIntersection(outline,l);
		rs.DeleteObject(l);
		if (not result):
			break
#		print 'found section at %d. '%i, result
		p0 = result[0][1]
		p0 = [p0.X,p0.Y,p0.Z]
		p1 = result[1][1]
		p1 = [p1.X,p1.Y,p1.Z]
		if (dihedral != 0):
			p0 = [p0[0],p0[1],-p0[1]*tan(dihedral)]
			p1 = [p1[0],p1[1],-p1[1]*tan(dihedral)]
		objs.append(rs.AddLine(p0,p1))
		objs.append(rs.AddLine(ss(p0,[0,0,-thickness]),ss(p1,[0,0,-thickness])))
		objs.append(add_edge(p1,ss(p1,[0,0,-thickness]),-.8))
		objs.append(add_edge(ss(p0,[0,0,-thickness]),p0,.8))
		l = rs.JoinCurves(objs,delete_input=True)
		assert(len(l)==1)
		sections.append(l[0])
		i = i+1
	return sections
	#loft = rs.CapPlanarHoles(rs.AddLoftSrf(sections))
	#python loft is crappy

def ExportControlPoints(crvs):
	filter = "Text File (*.txt)|*.txt|All files (*.*)|*.*||"
	filename = rs.SaveFileName("Save Control Points As", filter)
	if not filename: return

	file = open( filename, 'w' )
	points = []
	for crv in crvs:
		points.extend(rs.CurvePoints(crv))
		#print 'point size = ',len(points)
    	#if not points: return

	#i=1
	print 'pts size = ',len(points)
	for pt in points:
#		print "At ", i, "Current file position : ", file.tell()
#		i=i+1
		file.write( ','.join(map(str,[pt.X,pt.Y,pt.Z]))+'\n' )
	file.close()


if __name__ == '__main__':
	SetupLayers()
	length = 450 #length of blade in mm
	width = 160 #max width of blade in mm
	shaft_diam = 25 #diameter of shaft in mm
	assym = 15 #angle of assymetry in degrees
	dihedral = 0. #dihedral angle in degrees
	collar_length = 50 #length of straight cylinder collar segment for attaching to shaft

	rs.CurrentLayer('outline')
	outline = DrawOutline(length, width, shaft_diam, collar_length, assym)
	rs.CurrentLayer('cross')
	sections = DrawCrossSections(length, width, shaft_diam, outline, collar_length, dihedral, 500)
	for i,s in enumerate(sections):
		#objs = rs.ExplodeCurves(s,delete_input=True)
		#reb = []
		#for c in objs:
			#if not rs.IsLine(c):
			#	rs.RebuildCurve(c,degree=1,point_count=50)
			#reb.append(c)
			#cycle reb by z coordinate of curve start?
		#sections[i] = rs.JoinCurves(reb,delete_input=True)
		rs.RebuildCurve(s,degree=1,point_count=1000)
	ExportControlPoints(sections)