Trajectories

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

Leave a comment