Non-Planar Quad Sub-Division of a Surface Within a Given Quad Edge Length Range

This is a RhinoScript that allows a user to specify a range of the edge lengths for the non-planar quad sub-division of a surface. Where a quad sub-division in the given range of length is impossible the script creates a triangular sub-division instead.

I wrote this script while working on the design of the Table Cloth and was reminded of it when I was looking at files on my back-up hard drive today. I should add a disclaimer that the script is rather buggy since we decided not use it rather early in the design process and I never got a chance to refine it.

This script is probably not going to be of much direct use for panelization since it does not produce planar quads,  but I can see it having other uses. I’d love to hear of any uses people can think of for this script.

Option Explicit
‘Script written by <Ayodh Kamath>
‘Script copyrighted by <PostScript Design>
‘Script version Saturday, October 03, 2009 12:01:49 PM

Call Main()
Sub Main()
 
 Dim realMinLength, realMaxLength, realAvgLength, arrSurf, arrBoundingBox, arrCutPlane, arrCutSurf
 Dim arrIntersect, arrContour
 ReDim arrContours(1)
 Dim intDivNum, arrPoints1, arrPoints2
 Dim arrMovePoint, arrTempPoint, arrGreaterPoints, arrLesserPoints
 Dim i, j
 Dim realP2Pdist, realMaxP2Pdist, realMinP2Pdist
 Dim realPercentDiff, realMoveDist
 Dim arrLine
 Dim arrCutPlaneTemp, intEndCheck
 ReDim arrLines(0)
 Dim intLineCount, intLineCheck, arrEndPoint
 
 intLineCount = 0
 intEndCheck = 0
 realMinLength = Rhino.GetReal(“Enter minimum part length:”)
 realMaxLength = Rhino.GetReal(“Enter maximum part length:”)
 realAvgLength = Rhino.GetReal(“Enter average part length:”)
 arrSurf = Rhino.GetObject(“Select surface”,8 )
 ‘create plane for slicing plane
 arrBoundingBox = Rhino.BoundingBox(arrSurf)
 arrTempPoint = arrBoundingBox(4)
 arrCutPlane = Rhino.PlaneFromPoints(arrBoundingBox(5), arrBoundingBox(4), arrBoundingBox(7))
 arrCutSurf = Rhino.AddPlaneSurface(arrCutPlane, 20*(Rhino.Distance(arrBoundingBox(4), arrBoundingBox(5))), 20*(Rhino.Distance(arrBoundingBox(4), arrBoundingBox(7))))
 arrCutSurf = Rhino.MoveObject(arrCutSurf, arrBoundingBox(4), Rhino.CurveMidPoint(Rhino.AddLine(arrBoundingBox(5), arrBoundingBox(4))))
 ‘create first contour
 arrIntersect = Rhino.SurfaceSurfaceIntersection(arrSurf, arrCutSurf,, vbTrue)
 Rhino.Print arrIntersect(0,0)
 arrContours(0) = arrIntersect(0,1)
 ‘find number of divisions to divide the contour by
 intDivNum = Int(Rhino.CurveLength(arrContours(0))/realAvgLength)-1
 If intDivNum < 2 Then intDivNum = 2
 arrPoints1 = Rhino.DivideCurve(arrContours(0), intDivNum)
 ‘initialise the base point to move the slicing plane
 arrMovePoint = arrTempPoint
 
 Do
  ‘move the slicing surface base point by the average member length
  arrMovePoint(2) = arrMovePoint(2)-realAvgLength
  ‘move the slicing surface
  arrCutSurf = Rhino.MoveObject(arrCutSurf, arrTempPoint, arrMovePoint)
  arrTempPoint = arrMovePoint
  ‘intersect the slicing plane with the surface
  arrIntersect = Rhino.SurfaceSurfaceIntersection(arrSurf, arrCutSurf,, vbTrue)
  ‘check if the surface has been completely sliced
  If Not IsArray(arrIntersect) Then
   
   If intEndCheck > 1 Then
    ‘check if the last edge contour has already been made
    Rhino.DeleteObject arrCutSurf
    
    Exit Do
    
   Else
    ‘make the last contour on the edge of the surface
    Rhino.DeleteObject arrCutSurf
   
    arrCutPlaneTemp = Rhino.PlaneFromPoints(arrBoundingBox(0), arrBoundingBox(1), arrBoundingBox(3))
    arrCutSurf = Rhino.AddPlaneSurface(arrCutPlaneTemp, Rhino.Distance(arrBoundingBox(4), arrBoundingBox(5)), Rhino.Distance(arrBoundingBox(4), arrBoundingBox(7)))
    arrIntersect = Rhino.SurfaceSurfaceIntersection(arrSurf, arrCutSurf,, vbTrue)
    intEndCheck = intEndCheck + 1
   
   End If
   
  End If
  ‘divide the contour
  arrContours(1) = arrIntersect(0,1)
  intDivNum = Int(Rhino.CurveLength(arrContours(0))/realAvgLength)-1
  If intDivNum < 2 Then Exit Do
  arrPoints2 = Rhino.DivideCurve(arrContours(1), intDivNum)
  ‘find the contour with the greater number of points
  If UBound(arrPoints1)>UBound(arrPoints2) Then
   
   arrGreaterPoints = arrPoints1
   arrLesserPoints = arrPoints2
   
  Else
   
   arrGreaterPoints = arrPoints2
   arrLesserPoints = arrPoints1
   
  End If
  ‘connect the division points on adjacent contour lines
  For i = 0 To UBound(arrGreaterPoints)
   ‘find the fartherest division point on the contour with fewer division points for each division point on the contour with more division points
   realMaxP2Pdist = 0
   
   For j = 0 To UBound(arrLesserPoints)
    
    realP2Pdist = Rhino.Distance(arrGreaterPoints(i), arrLesserPoints(j))
    
    If realP2Pdist > realMaxP2Pdist Then realMaxP2Pdist = realP2Pdist
    
   Next
   ‘find the closest division point on the contour with fewer division points for each division point on the contour with more division points
   realMinP2Pdist = realMaxP2Pdist
   For j = 0 To UBound(arrLesserPoints)
    
    realP2Pdist = Rhino.Distance(arrGreaterPoints(i), arrLesserPoints(j))
    If realP2Pdist < realMinP2Pdist Then realMinP2Pdist = realP2Pdist
    
   Next
   ‘check if the closest point is farther than the maximum member length
   If realMinP2Pdist > realMaxLength Then
    
    Rhino.DeleteObject arrContours(1)
    ‘find the amount by which the closest member is longer than the maximum member length
    realPercentDiff = (realMinP2Pdist-realMaxLength)/realAvgLength
    ‘calculate the new position to move the slicing plane to
    realMoveDist = realPercentDiff*realAvgLength
    arrMovePoint(2) = arrMovePoint(2)+realMoveDist
    
    ‘arrMovePoint(2) = arrMovePoint(2)-realAvgLength
    ‘move the slicing plane
    arrCutSurf = Rhino.MoveObject(arrCutSurf, arrTempPoint, arrMovePoint)
    arrTempPoint = arrMovePoint
    ‘intersect the  new slicing plane with the surface 
    arrIntersect = Rhino.SurfaceSurfaceIntersection(arrSurf, arrCutSurf,, vbTrue)
    Rhino.Print arrIntersect(0,0)
  
    If Not IsArray(arrIntersect) Then
     ‘check if the last edge contour has already been made
     If intEndCheck > 1 Then
      
      Rhino.DeleteObject arrCutSurf
    
      Exit Do
    
     Else
      ‘make the last contour on the edge of the surface
      Rhino.DeleteObject arrCutSurf
   
      arrCutPlaneTemp = Rhino.PlaneFromPoints(arrBoundingBox(4), arrBoundingBox(5), arrBoundingBox(6))
      arrCutSurf = Rhino.AddPlaneSurface(arrCutPlane, 1.5*(Rhino.Distance(arrBoundingBox(0), arrBoundingBox(1))), 1.5*(Rhino.Distance(arrBoundingBox(0), arrBoundingBox(3))))
      arrIntersect = Rhino.SurfaceSurfaceIntersection(arrSurf, arrCutSurf,, vbTrue)
      intEndCheck = intEndCheck + 1
   
     End If
   
    End If
    ‘divide the contour
    arrContours(1) = arrIntersect(0,1)
    intDivNum = Int(Rhino.CurveLength(arrContours(0))/realAvgLength)-1
    If intDivNum < 2 Then Exit Do
    arrPoints2 = Rhino.DivideCurve(arrContours(1), intDivNum)
    ‘find the contour with the greater number of points
    If UBound(arrPoints1)>UBound(arrPoints2) Then
   
     arrGreaterPoints = arrPoints1
     arrLesserPoints = arrPoints2
   
    Else
   
     arrGreaterPoints = arrPoints2
     arrLesserPoints = arrPoints1
   
    End If
    
   End If
   
  Next
  ‘connect the division points on adjacent contour lines
  For i = 0 To UBound(arrGreaterPoints)
   ‘find the fartherest division point on the contour with fewer division points for each division point on the contour with more division points
   realMaxP2Pdist = 0
   
   For j = 0 To UBound(arrLesserPoints)
    
    realP2Pdist = Rhino.Distance(arrGreaterPoints(i), arrLesserPoints(j))
    
    If realP2Pdist > realMaxP2Pdist Then realMaxP2Pdist = realP2Pdist
    
   Next
   ‘find the closest division point on the contour with fewer division points for each division point on the contour with more division points and connect the points with a line
   realMinP2Pdist = realMaxP2Pdist
 
   arrLine = Rhino.AddLine(Array(0,0,0), Array(1,1,1))
   
   For j = 0 To UBound(arrLesserPoints)
    
    realP2Pdist = Rhino.Distance(arrGreaterPoints(i), arrLesserPoints(j))
    
    If realP2Pdist < realMinP2Pdist Then
     
     realMinP2Pdist = realP2Pdist
     Rhino.DeleteObject arrLine
     arrLine = Rhino.AddLine(arrGreaterPoints(i), arrLesserPoints(j))
     Rhino.AddPoint arrLesserPoints(j)
     
    End If
    
   Next
   
   arrLines(intLineCount) = arrLine
   intLineCount = intLineCOunt+1
   ReDim Preserve arrLines(intLineCount)
   
  Next
  
  For i = 0 To UBound(arrLesserPoints)
   
   intLineCheck = 0
   For j = 0 To intLineCount-1
     
    arrEndPoint = Rhino.CurveEndPoint(arrLines(j))
    If Rhino.PointCompare(arrEndPoint, arrLesserPoints(i)) = vbTrue Then intLineCheck = 1
    
   Next
   
   If intLineCheck = 0 Then
    
    Rhino.Print “No Line”
    realMaxP2Pdist = 0
    
    For j = 0 To UBound(arrGreaterPoints)
     
     realP2Pdist = Rhino.Distance(arrLesserPoints(i), arrGreaterPoints(j))
     If realP2Pdist > realMaxP2Pdist Then realMaxP2Pdist = realP2Pdist
     
    Next
    
    realMinP2Pdist = realMaxP2Pdist
    arrLine = Rhino.AddLine(Array(0,0,0), Array(1,1,1))
    
    For j = 0 To UBound(arrGreaterPoints)
     
     realP2Pdist = Rhino.Distance(arrLesserPoints(i), arrGreaterPoints(j))
     
     If realP2Pdist < realMinP2Pdist Then
     
      realMinP2Pdist = realP2Pdist
      Rhino.DeleteObject arrLine
      arrLine = Rhino.AddLine(arrLesserPoints(i), arrGreaterPoints(j))
     
     End If
     
    Next
    
    arrLines(intLineCount) = arrLine
    intLineCount = intLineCOunt+1
    ReDim Preserve arrLines(intLineCount)
    Rhino.Print intLineCount
    
   End If
   
  Next
  
  ‘polygonise the contour line
  For i = 0 To UBound(arrPoints1)-1
   
   Rhino.AddLine arrPoints1(i), arrPoints1(i+1)
   
  Next
  ‘prepare for the next iteration
  Rhino.DeleteObject arrContours(0)
  arrContours(0) = arrContours(1)
  arrPoints1 = arrPoints2
  
 Loop

End Sub

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s