Option Explicit
‘Script written by <Eric Tse>
‘Script copyrighted by <Eric Tse>
‘Script version Sunday, October 18, 2009 9:00:53 PM
Dim ZvectLim : ZvectLim = 45
Dim ZvectSize : ZvectSize = 1
Dim ZvectRotate : ZvectRotate = 0
Dim dbVectScale : dbVectScale = 0.5
Dim dbScale : dbScale = 0.5
Dim dbRadiusFactor : dbRadiusFactor = 0.25
Dim dbShortenV : dbShortenV = 1
Dim textSize : textSize = 0.15
Dim dotSize : dotSize = 0.05
Dim crossScale : crossScale = 2
Call Main()
Sub Main()
Dim i, j, k
Dim arrSrf : arrSrf = rhino.GetObjects(“Select surfaces”,8)
Dim strBox : strBox = rhino.GetObject(“Select box”,16)
Dim gridPts1 : gridPts1 = 3
Dim gridPts2 : gridPts2 = 2
Dim numSegments : numSegments = 4
Dim angleLim : angleLim = 15
Dim numPts1 : numPts1 = 30
Dim numPts2 : numPts2 = 30
Dim dbRadius : dbRadius = 0.35
rhino.HideObject strBox
Dim startPt, newVect, Zvect, ZvectPt, ZvectLine
Dim fx_SrfPts_output, arrStartPts, arrNvects, arrSrfs
Dim fx_Segment_output
Dim arrArrPts()
ReDim arrArrPts(0)
Dim arrArrVects()
ReDim arrArrVects(0)
Dim arrSegments()
ReDim arrSegments(0)
Dim arrRadius()
ReDim arrRadius(0)
Dim fx_IPOC_output
Dim startRadius
Dim blnZvect, ZvectPt1, ZvectPt2, plane, newText
blnZvect = rhino.GetInteger(“Zvect down (0) or choose Zvect (1)”,0,0,1)
If blnZvect = 0 Then
Zvect = array(0,0,-ZvectSize)
Else
ZvectPt1 = rhino.GetPoint(“Select start point for Zvect”)
ZvectPt2 = rhino.GetPoint(“Select end point for Zvect”)
Zvect = rhino.VectorCreate(ZvectPt1,ZvectPt2)
Zvect = rhino.VectorUnitize(Zvect)
Zvect = rhino.VectorReverse(Zvect)
Zvect = rhino.VectorScale(Zvect,ZvectSize)
End If
rhino.EnableRedraw False
‘for each selected surface,
‘divide surface into grid of points
fx_SrfPts_output = fx_SrfPts(arrSrf, gridPts1, gridPts2)
arrStartPts = fx_SrfPts_output(0) ‘array of grid points for each srf
arrNvects = fx_SrfPts_output(1) ‘nvect for each srf
For i = 0 To 0’Ubound(arrSrf) ‘for each surface
For j = 0 To 0’Ubound(arrStartPts(i)) ‘for each start point
ReDim arrArrPts(0)
ReDim arrArrVects(0)
ReDim arrSegments(0)
startPt = arrStartPts(i)(j)
newVect = arrNvects(i)
‘Zvect = array(0,0,-ZvectSize)
startRadius = dbRadius
For k = 0 To numSegments ‘draw number of segments
rhino.CurrentLayer(“text gen”)
plane = rhino.MovePlane(WorldXYPlane,startPt)
newText = rhino.AddText(” t=” & j+1 & “_” & k+1,plane,textSize)
Call fx_TextCoords(startPt)
fx_Segment_output = fx_Segment(startPt,newVect,Zvect,startRadius,angleLim,numPts1,numPts2,strBox,arrSrf,arrNvects)
arrArrPts(k) = fx_Segment_Output(0)
arrArrVects(k) = fx_Segment_Output(1)
arrSegments(k) = fx_Segment_Output(2)
arrRadius(k) = fx_Segment_Output(3)
fx_IPOC_output = fx_IPOC (arrArrPts,arrArrVects,arrSegments,Zvect, arrRadius)
startPt = fx_IPOC_output(0)
newVect = fx_IPOC_output(1)
startRadius = fx_IPOC_output(2)
If k < numSegments Then
ReDim Preserve arrArrPts(Ubound(arrArrPts)+1)
ReDim Preserve arrArrVects(Ubound(arrArrVects)+1)
ReDim Preserve arrSegments(Ubound(arrSegments)+1)
ReDim Preserve arrRadius(Ubound(arrRadius)+1)
End If
rhino.Command “selall ” & “group”
Next
Next
Next
rhino.EnableRedraw True
rhino.CurrentLayer(“Default”)
End Sub
Function fx_Segment (startPt, newVect, Zvect, startRadius, angleLim, numPts1, numPts2, strBox, arrSrf, arrNvects)
Dim i, j
Dim numPts : numPts = Int(fx_Random(numPts1,numPts2))
Dim arrPts()
ReDim arrPts(numPts)
Dim arrVects()
ReDim arrVects(numPts)
Dim angleDiff, EndPt, strCurve, scaleVect
Dim tempSrf, closestSrf, tempNvect, Nvect, minDist, tempDist, srfCentroid, srfOrigin, tempArr
Dim strPt, arrPtCoord, lowerLim, upperLim
Dim arrRadius()
ReDim arrRadius(numPts)
Dim arrCircles()
ReDim arrCircles(numPts)
Dim plane1, plane2, planeZvect, planePt, planeAngleX, planeAngleY, plane, length, newText
newVect = rhino.VectorScale(newVect,dbShortenV)
arrPts(0) = startPt
arrVects(0) = newVect
plane1 = rhino.PlaneFromNormal(startPt,newVect)
arrRadius(0) = startRadius
rhino.CurrentLayer(“circles”)
arrCircles(0) = Rhino.AddCircle(plane1,startRadius)
rhino.CurrentLayer(“branch pts”)
rhino.AddCircle rhino.Moveplane(WorldXYPlane,startPt),dotSize*1.5
rhino.CurrentLayer(“branch cross”)
rhino.InsertBlock “cross”,startPt,array(crossScale*1.5,crossScale*1.5,crossScale*1.5)
For i = 1 To numPts
scaleVect = rhino.VectorScale(newVect,fx_Random(1-dbVectScale,1+dbVectScale))
EndPt = Rhino.PointAdd(startPt,scaleVect)
If Rhino.IsPointInSurface(strBox,EndPt) Then
arrPts(i) = EndPt
Else
minDist = 100000
For j = 0 To Ubound(arrSrf)
tempSrf = arrSrf(j)
tempNvect = arrNvects(j)
srfCentroid = Rhino.SurfaceAreaCentroid(tempSrf)
srfOrigin = srfCentroid(0)
tempDist = rhino.Distance(EndPt,srfOrigin)
If tempDist < minDist Then
minDist = tempDist
closestSrf = tempSrf
Nvect = tempNvect
End If
Next
tempArr = Rhino.ProjectPointToSurface(EndPt, closestSrf, Nvect)
If Not IsNull(tempArr) Then
EndPt = tempArr(0)
Else
EndPt = arrPts(i – 1)
End If
arrPts(i) = EndPt
End If
arrVects(i) = scaleVect
startPt = EndPt
lowerLim = -angleLim
upperLim = angleLim
newVect = fx_RotateVect(newVect,lowerLim,upperLim,startPt,Zvect)
plane2 = rhino.PlaneFromNormal(startPt,newVect)
planeZvect = plane2(3)
planeAngleX = fx_AngleDiff(plane2(1),plane1(1))
If planeAngleX > 90 Then
plane2 = rhino.RotatePlane(plane2,planeAngleX,planeZvect)
End If
startRadius = startRadius * ((numPts-i/4+1)/numPts) ‘((numPts-(i/dbRadiusFactor)+1)/(numPts))
startRadius = startRadius * (1 + fx_Random(-dbRadiusFactor,dbRadiusFactor))
arrRadius(i) = startRadius
rhino.CurrentLayer(“circles”)
arrCircles(i) = Rhino.AddCircle(plane2,arrRadius(i))
rhino.CurrentLayer(“points”)
rhino.AddCircle rhino.Moveplane(WorldXYPlane,startPt),dotSize
rhino.CurrentLayer(“branch cross”)
rhino.InsertBlock “cross”,startPt,array(crossScale,crossScale,crossScale)
plane1 = plane2
Next
rhino.CurrentLayer(“lofts”)
Rhino.AddLoftSrf arrCircles
rhino.CurrentLayer(“segments”)
strCurve = rhino.AddInterpCurve(arrPts)
rhino.CurrentLayer(“text length”)
length = rhino.CurveLength(strCurve)
plane = rhino.MovePlane(WorldXYPlane,startPt)
rhino.AddText ” l=” & Int(length),plane,textSize
Call fx_TextCoords(startpt)
fx_Segment = array (arrPts, arrVects, strCurve, arrRadius)
End Function
Function fx_IPOC (arrArrPts, arrArrVects, arrSegments, Zvect, arrRadius)
Dim i, j, k
Dim strLine, arrPt, ptVect
Dim smallestAngle, angleDiff
Dim arrFork()
ReDim arrFork(0)
Dim startPt, newVect, tempPt, tempVect, startRadius
For i = 0 To Ubound(arrArrPts) ‘for each array of pts per segment
For j = 1 To Ubound(arrArrPts(i)) ‘FOR EACH PT IN ARRAY
arrPt = arrArrPts(i)(j)
ptVect = arrArrVects(i)(j)
startPt = arrPt
newVect = ptVect
startRadius = arrRadius(i)(j)
‘rhino.addpoint arrPt
‘check if pt on multiple curves
For k = 0 To Ubound(arrSegments) ‘for each segment
If k <> i Then ‘if segment different from set of pts
strLine = arrSegments(k)
smallestAngle = fx_AngleDiff(ptVect,Zvect)
If Rhino.IsPointOnCurve(strLine, arrPt) Then ‘if pt on segment
tempPt = arrArrPts(k)(j)
tempVect = arrArrVects(k)(j)
angleDiff = fx_AngleDiff(tempVect,Zvect)
If angleDiff < smallestAngle Then ‘find smallest angle
smallestAngle = angleDiff
startPt = tempPt
newVect = tempVect
j = Ubound(arrArrPts(i))
End If
End If
End If
Next
‘check if angleDiff > ZvectLim
angleDiff = fx_AngleDiff(newVect,Zvect)
If angleDiff > ZvectLim/2 Then
‘Rhino.AddPoint startPt
newVect = rhino.VectorAdd(newVect, Zvect)
newVect = rhino.VectorDivide(newVect, 2)
i = Ubound(arrArrPts)
j = Ubound(arrArrPts(i))
End If
Next
Next
fx_IPOC = array(startPt, newVect, startRadius)
End Function
Function fx_SrfPts (arrSrf, gridPts1, gridPts2)
Dim i
Dim num : num = Ubound(arrSrf)
Dim Udom, Vdom
Dim srfCentroid, srfOrigin, scaleSrf
Dim arrPts()
ReDim arrPts(num)
Dim Nvect()
ReDim Nvect(num)
For i = 0 To Ubound(arrSrf)
Udom = rhino.SurfaceDomain (arrSrf(i),0)
Vdom = rhino.SurfaceDomain (arrSrf(i),1)
srfCentroid = Rhino.SurfaceAreaCentroid(arrSrf(i))
srfOrigin = srfCentroid(0)
scaleSrf = Rhino.ScaleObject (arrSrf(i), srfOrigin, array(dbScale,dbScale,dbScale), True)
Rhino.RebuildSurface scaleSrf, Array(gridPts1,gridPts2), Array(gridPts1,gridPts2)
arrPts(i) = rhino.SurfacePoints (scaleSrf)
Rhino.deleteobject scaleSrf
Nvect(i) = Rhino.SurfaceNormal(arrSrf(i), array(Udom(0),Vdom(0)))
Nvect(i) = rhino.VectorScale(Nvect(i),ZvectSize/2)
Next
fx_SrfPts = array (arrPts, Nvect)
End Function
Function fx_RotateVect (newVect, lowerLim, upperLim, newPt, Zvect)
Dim skewAngle, lowerPt, upperPt, zPt, lowerVect, upperVect, drawPt, tempZvect, tempVect
Dim lowerVectX, upperVectX, lowerVectY, upperVectY, lowerVectZ, upperVectZ, arcZ
Dim angleDiff, endPt, midPt, strArc, arrAngleZ, angleZ, angleZPlane, vectLength, oldVect
oldVect = newVect
skewAngle = fx_Random(lowerLim,upperLim)
newVect = Rhino.VectorRotate(newVect,skewAngle,array(0,1,0))
skewAngle = fx_Random(lowerLim,upperLim)
newVect = Rhino.VectorRotate(newVect,skewAngle,array(1,0,0))
skewAngle = fx_Random(lowerLim,upperLim)
newVect = Rhino.VectorRotate(newVect,skewAngle,array(0,0,1))
rhino.CurrentLayer(“text angle”)
angleDiff = fx_AngleDiff(oldVect,newVect)
rhino.AddText ” Δtv=” & Int(angleDiff) & “°”,newPt,textSize
lowerVectX = Rhino.VectorRotate(newVect,lowerLim,array(0,1,0))
upperVectX = Rhino.VectorRotate(newVect,upperLim,array(0,1,0))
lowerVectY = Rhino.VectorRotate(newVect,lowerLim,array(1,0,0))
upperVectY = Rhino.VectorRotate(newVect,upperLim,array(1,0,0))
lowerVectZ = Rhino.VectorRotate(newVect,lowerLim,array(0,0,1))
upperVectZ = Rhino.VectorRotate(newVect,upperLim,array(0,0,1))
rhino.CurrentLayer(“rvects”)
lowerVect = rhino.VectorAdd(lowerVectX,lowerVectY)
lowerVect = rhino.VectorDivide(lowerVect,2)
lowerVect = rhino.VectorAdd(lowerVect,lowerVectZ)
lowerVect = rhino.VectorDivide(lowerVect,2)
lowerVect = rhino.VectorScale(lowerVect,2)
lowerPt = rhino.PointAdd(newPt,lowerVect)
rhino.AddLine newPt,lowerPt
upperVect = rhino.VectorAdd(upperVectX,upperVectY)
upperVect = rhino.VectorDivide(upperVect,2)
upperVect = rhino.VectorAdd(upperVect,upperVectZ)
upperVect = rhino.VectorDivide(upperVect,2)
upperVect = rhino.VectorScale(upperVect,2)
upperPt = rhino.PointAdd(newPt,upperVect)
rhino.AddLine newPt,upperPt
rhino.CurrentLayer(“zvects”)
vectLength = rhino.VectorLength(newVect)
tempZvect = rhino.VectorScale(Zvect,1)
tempZvect = rhino.VectorUnitize(tempZvect)
tempZvect = rhino.VectorScale(tempZvect,vectLength*2)
zPt = rhino.PointAdd(newPt,tempZvect)
rhino.AddLine newPt,zPt
rhino.CurrentLayer(“arcs”)
tempVect = rhino.VectorScale(newVect,2)
endPt = rhino.PointAdd(newPt,tempVect)
‘rhino.AddPoint midPt
strArc = rhino.AddArc3Pt (lowerPt,upperPt,endPt)
If rhino.ArcAngle(strArc) > 90 Then
rhino.DeleteObject(strArc)
strArc = rhino.AddArc3Pt (upperPt,lowerPt,endPt)
End If
rhino.CurrentLayer(“z arcs”)
angleZPlane = rhino.PlaneFromPoints(newPt,endPt,zPt)
vectLength = rhino.VectorLength(tempVect)
arrAngleZ = rhino.Angle2 (array(newPt,endPt),array(newPt,zPt))
arcZ = rhino.AddArc(angleZPlane,vectLength,arrAngleZ(0))
rhino.CurrentLayer(“text”)
angleZ = Int(arrAngleZ(0))
midPt = rhino.ArcMidPoint(arcZ)
rhino.AddText “-zv=” & angleZ & “°”,midPt,textSize
rhino.CurrentLayer(“vects”)
tempVect = rhino.VectorScale(newVect,2)
drawPt = rhino.PointAdd(newPt,tempVect)
rhino.AddLine newPt,drawPt
rhino.CurrentLayer(“tvects”)
angleDiff = fx_AngleDiff(newVect,Zvect)
If angleDiff > ZvectLim Then ‘ZvectLim is global limit on angle diff
‘rhino.addpoint startPt
newVect = rhino.VectorAdd(newVect, Zvect)
newVect = rhino.VectorDivide(newVect, 2)
tempVect = rhino.VectorScale(newVect,1.5)
drawPt = rhino.PointAdd(newPt,tempVect)
rhino.AddLine newPt,drawPt
End If
fx_RotateVect = newVect
End Function
Function fx_TextCoords(pt)
Dim plane, newText
rhino.CurrentLayer(“text coords”)
plane = rhino.MovePlane(WorldXYPlane,array(pt(0),pt(1)-textSize*1.5,pt(2)))
newText = rhino.AddText(” x=” & Int(pt(0)),plane,textSize)
plane = rhino.MovePlane(WorldXYPlane,array(pt(0),pt(1)-textSize*1.5*2,pt(2)))
newText = rhino.AddText(” y=” & Int(pt(1)),plane,textSize)
plane = rhino.MovePlane(WorldXYPlane,array(pt(0),pt(1)-textSize*1.5*3,pt(2)))
newText = rhino.AddText(” Z=” & Int(pt(2)),plane,textSize)
End Function
Function fx_RotateZvect (Zvect, angleLim)
Dim skewAngle
skewAngle = fx_Random(angleLim,angleLim)
Zvect = Rhino.VectorRotate(Zvect,skewAngle,array(0,1,0))
skewAngle = fx_Random(angleLim,angleLim)
Zvect = Rhino.VectorRotate(Zvect,skewAngle,array(1,0,0))
skewAngle = fx_Random(angleLim,angleLim)
Zvect = Rhino.VectorRotate(Zvect,skewAngle,array(0,0,1))
fx_RotateZvect = Zvect
End Function
Function fx_AngleDiff(v0, v1)
Dim u0 : u0 = Rhino.VectorUnitize(v0)
Dim u1 : u1 = Rhino.VectorUnitize(v1)
Dim dot : dot = Rhino.VectorDotProduct(u0, u1)
‘ domain for inverse cosine is -1 <= x <= 1
If (dot < -1.0) Then
dot = -1.0
ElseIf (dot > 1.0) Then
dot = 1.0
End If
fx_AngleDiff = Rhino.ToDegrees(Rhino.ACos(dot))
End Function
Function fx_Random (min, max)
fx_Random = Rnd*(max-min) + min
End Function