I’ve written a Rhinoscript that given two lines, the script will join them if (a) they share an end point and (b) the angle of the tangent vector at their shared end point is less than a specified value. I’d like to expand this to do it for a large number of curves all at once.
Back up a bit to the bigger picture: people in my (architecture) firm like to design a surface/mass then subdivide the surface into a triangulated grid. Everybody uses different ways of doing this. I’ve been asked a number of times to take the resulting grid of lines and turn it into a set of triangular surfaces and sweep a profile along each curve/line to build an architectural model of glass/metal panels and steel structure. Sometimes the grid is a bunch of continuous degree-3 curves, sometimes degree-3 curves that go from node-to-node, sometimes straight lines that go from node-to-node, and sometimes polylines in each direction.
In any of these cases, I can create the sweeps for the structural members, that’s not a problem.
For panels, it’s another story. Given polylines or continous degree-3 curves along each diagonal (or in U and V directions), I have no problem creating panels. However, if they’ve split the curves/lines at the node intersections and haven’t sorted them previously by layer for each direction, it’s a tedious process. (I’d like to encourage/teach people how to create grids in a more useful way, but partly for practical reasons and partly for self-educational reasons, I think this is an interesting problem to solve.)
Any suggestions for working through a whole list of curves would be greatly appreciated. Here’s what I have so far that works for the simple case of testing two curves:
Call JoinCurvesToPath()
Sub JoinCurvesToPath()
Dim arrCrv : arrCrv = Rhino.GetObjects("Select two curves to join into a polycurve", 4)
If IsNull(arrCrv) Then Exit Sub
Call Rhino.EnableRedraw(False)
Dim crvA : crvA = arrCrv(0)
Dim crvB : crvB = arrCrv(1)
Dim arrParams
Dim angle : angle = 15
'Find joining ends
arrParams = JoiningEnds(crvA, crvB)
If Not (IsNull(arrParams)) Then
'Join curves if angle is met.
Call JoinCurves(crvA, crvB, arrParams, angle)
End If
Call Rhino.EnableRedraw(True)
End Sub
Function JoiningEnds(crvA, crvB)
Call Rhino.Print("In JoiningEnds function")
Dim startA, endA, startB, endB
Dim paramA, paramB
startA = Rhino.CurveStartPoint(crvA)
endA = Rhino.CurveEndPoint(crvA)
startB = Rhino.CurveStartPoint(crvB)
endB = Rhino.CurveEndPoint(crvB)
If (Rhino.Distance(startA, startB) < 0.1) Then
Call Rhino.Print("starts")
paramA = Rhino.CurveClosestPoint(crvA, startA)
paramB = Rhino.CurveClosestPoint(crvB, startB)
JoiningEnds = Array(paramA, paramB)
ElseIf (Rhino.Distance(startA, endB) < 0.1) Then
Call Rhino.Print("start, end")
paramA = Rhino.CurveClosestPoint(crvA, startA)
paramB = Rhino.CurveClosestPoint(crvB, endB)
JoiningEnds = Array(paramA, paramB)
ElseIf (Rhino.Distance(endA, endB) < 0.1) Then
Call Rhino.Print("ends")
paramA = Rhino.CurveClosestPoint(crvA, endA)
paramB = Rhino.CurveClosestPoint(crvB, endB)
JoiningEnds = Array(paramA, paramB)
ElseIf (Rhino.Distance(endA, startB) < 0.1) Then
Call Rhino.Print("end, start")
paramA = Rhino.CurveClosestPoint(crvA, endA)
paramB = Rhino.CurveClosestPoint(crvB, startB)
JoiningEnds = Array(paramA, paramB)
End If
End Function
Function JoinCurves(crvA, crvB, arrParams, minAngle)
Dim vecA, vecB
Dim joined
vecA = Rhino.CurveTangent(crvA, arrParams(0))
If IsNull(vecA) Then
Call Rhino.Print("CurveTangent at A failed")
Exit Function
End If
vecB = Rhino.CurveTangent(crvB, arrParams(1))
If IsNull(vecB) Then
Call Rhino.Print("CurveTangent at B failed")
Exit Function
End If
Dim angle: angle = Rhino.VectorAngle(vecA, vecB)
Call Rhino.Print("Angle = " & angle)
If (angle < minAngle) Then
joined = Rhino.JoinCurves(Array(crvA, crvB))
Call Rhino.Print("joined has " & Ubound(joined) + 1 & "objects")
JoinCurves = joined(0)
Call Rhino.DeleteObjects(Array(crvA, crvB))
Else
JoinCurves = Null
End If
End Function