Last active
March 26, 2020 16:37
-
-
Save pgolay/f345a3bd65d33ae3c49167e80fcf65d3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import rhinoscriptsyntax as rs | |
import Rhino | |
import scriptcontext as sc | |
import math | |
import System | |
def CalculateTargets(Grevs, srf, crv): | |
pi = math.pi | |
tPlanes = [] | |
pPlanes = [] | |
tLines = [] | |
for pt in Grevs: | |
sPar = srf.ClosestPoint(pt) | |
tPlane = srf.FrameAt(sPar[1], sPar[2])[1] | |
cPar = crv.ClosestPoint(pt) | |
parRC,sParU, sParV = srf.ClosestPoint(pt) | |
vecNorm = srf.NormalAt(sParU, sParV) | |
crvPlane = crv.PerpendicularFrameAt(cPar[1])[1] | |
tVec = Rhino.Geometry.Vector3d(tPlane.ZAxis) | |
tVec.Rotate(pi/2,crvPlane.ZAxis) | |
tLine = Rhino.Geometry.Line(pt, pt+tVec) | |
#sc.doc.Objects.AddLine(tLine) | |
tPlanes.append(tPlane) | |
tLines.append(tLine) | |
pPlanes.append(Rhino.Geometry.Plane(pt, tVec, vecNorm)) | |
return tPlanes, tLines, pPlanes | |
def CustomGetPoint(plane, Grevs, srf, crv, vecNorm, tangent, tPlanes, tLines, pPlanes): | |
pass | |
pi = math.pi | |
valid = False | |
# Color to use when drawing dynamic lines | |
line_color = System.Drawing.Color.FromArgb(255,0,0) | |
arc_color = System.Drawing.Color.FromArgb(240,240,240) | |
vecTan = tangent.To - tangent.From | |
vecTan.Unitize() | |
#if flip: vecTan.Reverse() | |
normal = Rhino.Geometry.Line(plane.Origin, plane.Origin + vecNorm) | |
units = rs.UnitSystemName() | |
if units == "millimeter": | |
units = " mm" | |
elif units == "inch": | |
units = " in" | |
elif units == "meter": | |
units = " M" | |
elif units == "foot": | |
" ft" | |
elif units == "centimeter": | |
units = " cm" | |
def GetPointDynamicDrawFunc( sender, args ): | |
current_point = args.CurrentPoint | |
#tPlanes, tLines, pPlanes = CalculateTargets(Grevs, srf, crv) | |
xform = args.Viewport.GetTransform(Rhino.DocObjects.CoordinateSystem.World, Rhino.DocObjects.CoordinateSystem.Screen) | |
lType = Rhino.Geometry.LoftType.Normal | |
uPt = Rhino.Geometry.Point3d.Unset | |
mat = Rhino.Display.DisplayMaterial(System.Drawing.Color.CornflowerBlue, .5) | |
tracking = Rhino.Geometry.Line(plane.Origin, args.CurrentPoint) | |
vecDir = args.CurrentPoint-plane.Origin | |
#circlePlane = Rhino.Geometry.Plane(plane.Origin, tanPt, args.CurrentPoint) | |
angle = Rhino.Geometry.Vector3d.VectorAngle(vecTan, vecDir, plane) | |
# print angle | |
angleDeg = round(Rhino.RhinoMath.ToDegrees(angle),2) | |
if angleDeg == 360: angleDeg = 0 | |
drawAngle = angle | |
planePar, U, V = plane.ClosestParameter(current_point) | |
if planePar: | |
if V < 0: | |
pass | |
#angleDeg = - angleDeg | |
elif V > 0: | |
pass | |
#drawAngle = (2*pi)-angle | |
distance = round(plane.Origin.DistanceTo(args.CurrentPoint), 3) | |
lineCrvs = [Rhino.Geometry.LineCurve(Grevs[0], Grevs[0] + vecDir)] | |
lines = [Rhino.Geometry.Line(Grevs[0], Grevs[0]+ vecDir)] | |
targs = [Grevs[0]+vecDir] | |
x = len(Grevs) | |
for n in range(1,len(Grevs)): | |
testVec = (tLines[n].To - tLines[n].From)*vecDir.Length #local Tangent vector | |
testVec.Rotate( angle, pPlanes[n].ZAxis) | |
targ = Grevs[n]+testVec | |
targs.append(targ) | |
lines.append(Rhino.Geometry.Line(Grevs[n], targ)) | |
lineCrvs.append(Rhino.Geometry.LineCurve(Grevs[n], targ)) | |
for line in lines: | |
args.Display.DrawLine(line,System.Drawing.Color.Red, 1) | |
#preview lofts | |
preview_loft = False | |
lofts = Rhino.Geometry.Brep.CreateFromLoft(lineCrvs, uPt, uPt, lType, False) | |
if len(lofts) > 0: | |
preview_loft = True | |
brep = lofts[0] | |
loft = brep.Faces[0].ToNurbsSurface() | |
#vecTan is a line tangent to the surface | |
tanPt = plane.Origin +(vecTan*distance) | |
pass | |
#plane is pPlanes[0] (perp planes on input curve | |
circlePlane = Rhino.Geometry.Plane(plane.Origin, tanPt, args.CurrentPoint) | |
circle = Rhino.Geometry.Circle(plane, args.CurrentPoint.DistanceTo(plane.Origin)) | |
arc = Rhino.Geometry.Arc(circle, drawAngle) | |
#tracking = Rhino.Geometry.Line(current_point, plane.Origin) | |
# sc.doc.Objects.AddLine(tracking) | |
# sc.doc.Objects.AddArc(arc) | |
arc_mid = arc.MidPoint | |
#mid_pt = Rhino.Geometry.Point3d.Interpolate(current_point, plane.Origin, .5) | |
mid_pt = plane.Origin+(vecDir/2) | |
mid_pt.Transform(xform) | |
arc_mid.Transform(xform) | |
current_point.Transform(xform) | |
screen_point = Rhino.Geometry.Point2d(current_point.X+16, current_point.Y) | |
screen_mid = Rhino.Geometry.Point2d(mid_pt.X, mid_pt.Y) | |
screen_arc_mid = Rhino.Geometry.Point2d(arc_mid.X + 16, arc_mid.Y) | |
#args.Display.DrawLine(tracking, arc_color,1) | |
args.Display.Draw2dText(str(angleDeg)+ " deg", System.Drawing.Color.Black, screen_arc_mid, False, 16) | |
args.Display.Draw2dText(str(distance)+ units, System.Drawing.Color.Black, screen_mid, False, 16) | |
#args.Display.DrawCircle(circle, arc_color, 2) | |
args.Display.DrawArc( arc, arc_color, 2) | |
args.Display.DrawLine(plane.Origin, args.CurrentPoint, line_color, 2) | |
args.Display.DrawLine(plane.Origin, tanPt, System.Drawing.Color.LightSlateGray, 2) | |
if preview_loft: | |
args.Display.DrawBrepShaded(brep, mat) | |
args.Display.DrawBrepWires(brep, System.Drawing.Color.Black, 0 ) | |
constraint = None | |
dist = None | |
angleConstraint = None | |
while True: | |
flipAngle=False | |
deformable = False | |
if sc.sticky.has_key ("DEFORMABLE_FIN"): | |
deformable = sc.sticky["DEFORMABLE_FIN"] | |
finAngle = 10 | |
if sc.sticky.has_key('FIN_ANGLE'): | |
finAngle = sc.sticky['FIN_ANGLE'] | |
gp = Rhino.Input.Custom.GetPoint() | |
gp.DynamicDraw += GetPointDynamicDrawFunc | |
gp.AcceptNumber(True, True) | |
gp.AcceptNothing(True) | |
gp.SetBasePoint(plane.Origin, True) | |
opLinear = Rhino.Input.Custom.OptionToggle(deformable,"No","Yes") | |
gp.AddOptionToggle("Deformable", opLinear) | |
if dist is not None: | |
gp.ConstrainDistanceFromBasePoint(dist) | |
gp.SetCommandPrompt("Set fin depth and direction") | |
if constraint is None: | |
gp.SetCommandPrompt("Set fin depth and angle") | |
gp.Constrain( plane, False) | |
gp.AddOption("Normal") | |
gp.AddOption("Tangent") | |
gp.AddOption("Angle") | |
elif constraint == 2: | |
gp.Constrain( normal ) | |
elif constraint == 3: | |
gp.Constrain( tangent ) | |
if angleConstraint is not None: | |
gp.AddOption("FlipAngle") | |
angleVec = Rhino.Geometry.Vector3d(vecTan) | |
angleVec.Rotate(angleConstraint, plane.ZAxis) | |
angleLine = Rhino.Geometry.Line(plane.Origin+angleVec , plane.Origin) | |
gp.Constrain( angleLine ) | |
rc = gp.Get() | |
if ( gp.CommandResult() != Rhino.Commands.Result.Success ): | |
return | |
if rc==Rhino.Input.GetResult.Point: | |
pass | |
pt = gp.Point() | |
#sc.doc.Objects.AddPoint(pt) | |
#angle = (tangent.To-tangent.From).VectorAngle(gp.Point-plane.Origin) | |
angle = Rhino.Geometry.Vector3d.VectorAngle((tangent.To-tangent.From),(pt - plane.Origin),plane) | |
return pt, deformable, angle | |
elif rc == Rhino.Input.GetResult.Number: | |
dist = gp.Number() | |
continue | |
elif rc == Rhino.Input.GetResult.Nothing: | |
dist = None | |
elif rc == Rhino.Input.GetResult.Option: | |
if 4 > gp.OptionIndex() > 1: | |
constraint = gp.OptionIndex() | |
if gp.OptionIndex() == 4: | |
ga = Rhino.Input.Custom.GetNumber() | |
ga.SetCommandPrompt("Fin angle") | |
ga.SetLowerLimit(-180, False) | |
ga.SetUpperLimit(180, False) | |
ga.SetDefaultNumber(finAngle) | |
ga.Get() | |
if ga.CommandResult()!=Rhino.Commands.Result.Success: | |
return ga.CommandResult() | |
finAngle = ga.Number() | |
angleConstraint = Rhino.RhinoMath.ToRadians(finAngle) | |
sc.sticky['FIN_ANGLE'] = finAngle | |
if gp.OptionIndex() == 5: | |
flipAngle=True | |
angleConstraint = -angleConstraint | |
flipAngle=False | |
deformable = opLinear.CurrentValue | |
sc.sticky["DEFORMABLE_FIN"] = deformable | |
continue | |
def TangentIsInterior(brep,srf, plane1, idx, crv): | |
testPt1 = plane1.Origin + plane1.XAxis | |
tempVec = Rhino.Geometry.Vector3d(plane1.XAxis) | |
tempVec.Reverse() | |
testPt2 = plane1.Origin + tempVec | |
parRC, parU, parV = srf.ClosestPoint(testPt1) | |
if parRC: | |
inFace1 = brep.Faces[idx].IsPointOnFace(parU, parV) | |
parRC, parU, parV = srf.ClosestPoint(testPt2) | |
if parRC: | |
inFace2 = brep.Faces[idx].IsPointOnFace(parU, parV) | |
if inFace1 != inFace2: | |
return True | |
return False | |
def FinSimple(): | |
sr4 = False | |
version = Rhino.RhinoApp.Version.ToString() | |
if int(version.split(".")[0]) < 7 and int(version.split(".")[1])< 4: | |
sr4= True | |
pi = math.pi | |
uPt = Rhino.Geometry.Point3d.Unset | |
blnEdge = False | |
crvInput = rs.GetObject("Select a curve or surface edge.", 4, preselect=True, subobjects=True) | |
if not crvInput:return | |
brepId = crvInput.ObjectId | |
edgeIdx = crvInput.GeometryComponentIndex.Index | |
if edgeIdx != -1: | |
brep = crvInput.Brep() | |
if brep.Faces.Count>1: | |
srfInfo = rs.GetObject("Select the base surface.", 8,subobjects=True) | |
if not srfInfo: return | |
brepId = srfInfo.ObjectId | |
idx = srfInfo.GeometryComponentIndex.Index | |
srf = brep.Faces[idx].ToNurbsSurface() | |
else: | |
srf = brep.Faces[0].ToNurbsSurface() | |
idx = 0 | |
crv = brep.Edges[edgeIdx].ToNurbsCurve() | |
if not sr4: | |
crvId = sc.doc.Objects.AddCurve(crv) | |
blnEdge = True | |
else: | |
crvId = crvInput.ObjectId | |
crv = sc.doc.Objects.Find(crvId).Geometry | |
srfId = rs.GetObject("Select the base surface.", 8) | |
if not srfId: return | |
brep = sc.doc.Objects.Find(srfId).Geometry | |
idx =0 | |
srf = sc.doc.Objects.Find(srfId).Geometry.Faces[0].ToNurbsSurface() | |
crv = crv.ToNurbsCurve() | |
crv.Domain = Rhino.Geometry.Interval(0, crv.GetLength()) | |
Grevs = crv.GrevillePoints() | |
tPlanes, tLines, pPlanes = CalculateTargets(Grevs, srf, crv) | |
parRC, sParU, sParV = srf.ClosestPoint(Grevs[0]) | |
vecNorm = srf.NormalAt(sParU, sParV) | |
normal = Rhino.Geometry.Line(Grevs[0], tPlanes[0].Origin + tPlanes[0].ZAxis) | |
plane1 = Rhino.Geometry.Plane(Grevs[0], tLines[0].To - tLines[0].From, tPlanes[0].ZAxis) | |
#sc.doc.Objects.AddLine(normal) | |
#sc.doc.Objects.AddLine(tLines[0]) | |
circ = Rhino.Geometry.Circle(pPlanes[0], 10) | |
#sc.doc.Objects.AddCircle(circ) | |
flip = TangentIsInterior(brep, srf, plane1, idx, crv) | |
inputs = CustomGetPoint(plane1, Grevs, srf, crv, vecNorm, tLines[0], tPlanes, tLines, pPlanes) | |
if not inputs: | |
if blnEdge and crvId: rs.DeleteObject(crvId) | |
return | |
pt, deformable, angle= inputs | |
#print angle | |
pass | |
targs = [] | |
targs.append(pt) | |
vecDir = pt - Grevs[0] | |
for n in range(1,len(Grevs)): | |
testVec = (tLines[n].To - tLines[n].From)*vecDir.Length #local Tangent vector | |
testVec.Rotate( angle, pPlanes[n].ZAxis) | |
targs.append(Grevs[n]+testVec) | |
#rs.AddPoints(targs) | |
if sr4: | |
#Loft type | |
type = 2 | |
if deformable: | |
type = 0 | |
sc.doc.Objects.UnselectAll() | |
crvCopy = rs.CopyObject(crvId) | |
rs.EnableRedraw(False) | |
rs.SelectObject(crvCopy) | |
rs.Command("EditPtOn") | |
locs = rs.ObjectGripLocations(crvCopy, targs) | |
rs.AddLoftSrf([crvCopy,crvId], loft_type = type) | |
rs.DeleteObject(crvCopy) | |
else: | |
#Loft type | |
type = Rhino.Geometry.LoftType.Straight | |
if deformable: | |
type = Rhino.Geometry.LoftType.Normal | |
#crv.Simplify(Rhino.Geometry.CurveSimplifyOptions.All, .001, sc.doc.ModelAngleToleranceRadians) | |
crv2 = crv.DuplicateCurve() | |
if crv2.SetGrevillePoints(targs): | |
loft = Rhino.Geometry.Brep.CreateFromLoft([crv,crv2], uPt, uPt, type, False) | |
if loft: | |
if loft[0].IsValid: | |
sc.doc.Objects.AddBrep(loft[0]) | |
else: | |
print "Unable to create the fin surface. Try splitting closed loops into two pieces." | |
if blnEdge: | |
if rs.IsObject(crvId): | |
rs.DeleteObject(crvId) | |
rs.EnableRedraw(True) | |
if __name__ == "__main__": FinSimple() |
Added a fix to run cleanly in V7/WIP
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added user definable angle. Might need some work...