Some months ago I found an article about an exhibition titled The Machine organized by the Design Hub Limburg that includes a fascinating tool for designers. This tool is the result of a project called Computer Augmented Craft, which, the head of the project, Christian Feiberg, says, “is an attempt to utilise advanced technologies without sacrificing the unique qualities of craftsmanship.” The tool combines a set of sensors with Arduino and an interface created in Processing to enable a designer to have a real-time digital model of an artefact that they are physically producing. The software interface also provides “suggestions” at each step of construction to enable the designer to conform to an initial set of parameters or choose not to do so. The following video shows the system in use -
Reading about this tool and the exhibition reminded me of a student project I had done in the Command & Control design studio with Simon Kim, Skylar Tibbits and Juhong Park in 2009 at MIT. My project in this studio (focusing on using scripting as a design tool) included a script that created mass-customised joints for a post-earthquake shelter constructed as an irregular space frame out of found rubble. In this project the script did not dictate the form of the structure but only created fabrication data for a mass-customised joint component after the human builder had decided what member to use (from the post-earthquake rubble at hand) and where in the structure to place it. The script overcame the unpredictability of the materials at hand by taking inputs (on the length of a found member that the builder wanted to attach at a particular location) incrementally. The resulting digital model grew in tandem with the physical model allowing the builder to take independent design decisions while the script recorded the builder’s design moves and output fabrication data for the joint components needed at each step. If the builder got stuck and was unable to triangulate the space frame at any point then the script would suggest a method to triangulate.

My poster from the Command & Control studio in 2009. The green members in the main figure denote “found” members while the red members denote those added by the script to triangulate the space frame.
Re-visiting this old student project in the light of the “The Machine” exhibition resulted in a project for the Patterns and Performance 2nd year, B.Arch design studio I am teaching with Abhishek Bij at the University School of Architecture and Planning (USAP). For this exercise we collaborated with the studio taught by Malini Kochupillai and Kanishk Prasad to design a learning space for a group of 20 students. I wrote a new version of the script I had coded for my Command & Control project for use by the students. The new script did not focus on the joints and instead was designed for the specific design problem given to the students for this exercise – the design of a learning space housing 15 to 20 people using a space frame structure constructed from available members of irregular lengths. The students were given tutorials on space frames and introduced to the script written for them. They were introduced to different forms of education and their spatial implications – both interior and exterior.
After this, the students began their designs in groups of four, constructing 1:10 or 1:20 scale physical models of their structures and simultaneously using the script to “grow” a 3D computer model. This studio exercise exposed the students to the advantages and disadvantages of physical versus digital design processes, issues of error and tolerance in design and construction, the importance of improvisation and contingency and its incorporation into the design process.

The physical and digital models growing side-by-side in the studio.
While my initial script written for the Command & Control studio focused on creating digitally fabricated joints, the script written for the USAP students included a panelization tool. This tool allowed the students to choose where to place panels on the space frame and have the script add these panels to the 3D model and also provide fabrication data for the panels so that they could be printed as a 2D triangle, cut and be added to the physical model.
-
-
-
-
-
-
-
-
Some student projects from the studio.
The next step in the design studio will be to use what one has learnt constructing models and build a full-scale bamboo space frame as a learning space on the college campus. Observing the students work on the models I have updated the script for the full-scale structure. The updated script calculates the centre of gravity of the structure at each iteration of the design and construction process and gives a warning if the structure is likely to topple over without support. The reason for the addition of this feature in the script is that while it is easy to support a table-top model by hand if it is toppling over, this is not a trivial task during full-scale construction. This feature will allow the script to inform the steps in the physical construction process, while design decisions in response to space and material are taken in the physical world and fed into the script. Such a design process will aid in bringing the digital and physical worlds closer together to create a digitally augmented, craft-based, design process.
The latest version of the script written for the studio is given below (please note that there are still some bugs in calculating the centre of gravity) -
Option Explicit
‘Script written by <Ayodh Kamath>
‘Script version 18 November 2012 12:02:10
Call Main()
Sub Main()
Dim strStart, arrExist
Dim arrDots, arrLines, strExit
Dim i
Call Rhino.AddLayer(“uncut_members”, RGB(0,255,0))
Call Rhino.CurrentLayer(“uncut_members”)
Do
strStart = Rhino.GetString(“Start from scratch [S], use existing geometry[G], triangulate with a single member [T], panelize [P], or exit[X]?”,,Array(“S”,”G”,”T”,”P”,”X”))
arrExist = Rhino.AllObjects()
If strStart = “S” Then
If IsArray(arrExist) Then
Call Rhino.DeleteObjects(arrExist)
End If
arrDots = Triangle(arrLines)
Call Rhino.UnselectAllObjects
arrDots = Tetrahedron(arrDots, arrLines)
Call Rhino.UnselectAllObjects
ElseIf strStart = “G” Then
Call Rhino.ZoomExtents(,True)
arrDots = Rhino.GetObjects(“Please drag a selection box around the existing text dot points and ‘Click+Cntrl’ to de-select any unwanted geometry.”,8192)
arrLines = Rhino.GetObjects(“Please drag a selection box around the existing lines and ‘Click+Cntrl’ to de-select any unwanted geometry.”,4)
arrDots = Sort(arrDots)
strExit = “A”
Do
arrDots = Tetrahedron(arrDots, arrLines)
Call Rhino.UnselectAllObjects
strExit = Rhino.GetString(“Make another tetrahedron [A], or exit [X]?”,”A”, Array(“A”,”X”))
Loop While strExit <> “X”
ElseIf strStart = “T” Then
Call Triangulate(arrLines,arrDots)
ElseIf strStart = “P” Then
Call Panelize()
End If
Loop While strStart <> “X”
End Sub
Function Triangle(ByRef arrLines)
Dim dblLt1, dblLt2, dblLt3
Dim strLn0, strLn1, strLn2
Dim strDotP0, strDotP1, strDotP2a, strDotP2b, strDotP2
Dim strTempCirc1, strTempCirc2
Dim arrInt, arrIntPt0, arrIntPt1, strPt0, strPt1, strPt2
Dim strChoice, blnLoop
blnLoop = 0
Do While blnLoop = 0
dblLt1 = Rhino.GetReal(“Enter first lenght:”)
strLn0 = Rhino.AddLine(Array(0,0,0), Array(dblLt1,0,0))
strDotP0 = Rhino.AddTextDot(“P0″,Array(0,0,0))
strDotP1 = Rhino.AddTextDot(“P1″,Rhino.CurveEndPoint(strLn0))
Call Rhino.ZoomExtents(,True)
dblLt2 = Rhino.GetReal(“Enter second lenght:”)
strTempCirc1 = Rhino.AddCircle(Rhino.WorldXYPlane(),dblLt2)
strTempCirc1 = Rhino.MoveObject(strTempCirc1,Array(0,0,0),Array(dblLt1,0,0))
dblLt3 = Rhino.GetReal(“Enter third lenght:”)
strTempCirc2 = Rhino.AddCircle(Rhino.WorldXYPlane(),dblLt3)
arrInt = Rhino.CurveCurveIntersection(strTempCirc1,strTempCirc2)
Call Rhino.DeleteObject(strTempCirc1)
Call Rhino.DeleteObject(strTempCirc2)
If IsArray(arrInt) Then
arrIntPt0 = arrInt(0,1)
arrIntPt1 = arrInt(1,1)
strDotP2a = Rhino.AddTextDot(“P2a”,arrIntPt0)
strDotP2b = Rhino.AddTextDot(“P2b”,arrIntPt1)
Call Rhino.ZoomExtents(,True)
strChoice = Rhino.GetString(“Point P2a[A] or point P2b[B]?”,”A”, Array(“A”,”B”))
If strChoice = “A” Then
Call Rhino.DeleteObject(strDotP2b)
Call Rhino.DeleteObject(strDotP2a)
strDotP2 = Rhino.AddTextDot(“P2″,arrIntPt0)
strLn1 = Rhino.AddLine(Rhino.CurveEndPoint(strLn0),arrIntPt0)
strLn2 = Rhino.AddLine(arrIntPt0,Rhino.CurveStartPoint(strLn0))
ElseIf strChoice = “B” Then
Call Rhino.DeleteObject(strDotP2a)
Call Rhino.DeleteObject(strDotP2b)
strDotP2 = Rhino.AddTextDot(“P2″,arrIntPt1)
strLn1 = Rhino.AddLine(Rhino.CurveEndPoint(strLn0),arrIntPt1)
strLn2 = Rhino.AddLine(arrIntPt1,Rhino.CurveStartPoint(strLn0))
End If
Triangle = Array(strDotP0,strDotP1,strDotP2)
ReDim arrLines(2)
arrLines(0) = strLn0
arrLines(1) = strLn1
arrLines(2) = strLn2
blnLoop = 1
Else
Call Rhino.DeleteObject(strLn0)
Call Rhino.DeleteObject(strDotP0)
Call Rhino.DeleteObject(strDotP1)
Call Rhino.MessageBox(“The member lengths can not be triangulated. Please try a different set of members.”)
End If
Loop
End Function
Function Sort(arrTxtDot)
Dim strMin, blnSwap
Dim i, j, k
Do
blnSwap = False
For i = 1 To UBound(arrTxtDot)
If Rhino.TextDotText(arrTxtDot(i-1)) > Rhino.TextDotText(arrTxtDot(i)) Then
strMin = arrTxtDot(i)
arrTxtDot(i) = arrTxtDot(i-1)
arrTxtDot(i-1) = strMin
blnSwap = True
End If
Next
Loop While blnSwap = True
Sort = arrTxtDot
End Function
Function Tetrahedron(arrTxtDots, ByRef arrLines)
ReDim arrInPts(2)
ReDim arrTempDots(2)
ReDim arrInLts(2)
ReDim arrTempSphs(2)
Dim arrIntSrf, strJoinCrv, arrIntCrvSrf
ReDim arrIntDots(1)
Dim strChoice, arrIntPt
Dim i, j
Dim blnLoop
Dim intPtNum
Dim intCGChoice
ReDim arrTempLines(2)
Dim intLineCount
Dim blnGoal, arrGoalPt
blnLoop = 0
Do While blnLoop = 0
blnGoal = Rhino.GetString(“Select a goal point?”,,Array(“Y”,”N”))
If blnGoal = “Y” Then
arrGoalPt = Rhino.GetPoint(“Select goal point”)
Call GoalPoint(arrTxtDots,arrGoalPt)
End If
For i = 0 To 2
arrInPts(i) = Rhino.GetPoint(“Select point #”&CStr(i+1))
Call Rhino.UnselectAllObjects
arrTempDots(i) = Rhino.AddTextDot(CStr(i+1),arrInPts(i))
Call Rhino.SelectObject(arrTempDots(i))
arrInLts(i) = Rhino.GetReal(“Enter member length at this node:”)
arrTempSphs(i) = Rhino.AddSphere(arrInPts(i),arrInLts(i))
Call Rhino.ZoomExtents(,True)
If i = 1 Then
arrIntSrf = Rhino.SurfaceSurfaceIntersection(arrTempSphs(0),arrTempSphs(1),,True)
If IsArray(arrIntSrf) Then
If UBound(arrIntSrf,1)>0 Then
strJoinCrv = JoinCurve(arrIntSrf)
Else
strJoinCrv = arrIntSrf(0,1)
End If
Else
Call Rhino.DeleteObject(arrTempDots(0))
Call Rhino.DeleteObject(arrTempDots(1))
Call Rhino.DeleteObject(arrTempSphs(0))
Call Rhino.DeleteObject(arrTempSphs(1))
blnLoop = 0
Call Rhino.MessageBox(“The member lengths can not be triangulated. Please try a different set of members.”)
Exit For
End If
ElseIf i = 2 Then
arrIntCrvSrf = Rhino.CurveSurfaceIntersection(strJoinCrv,arrTempSphs(2))
If IsArray(arrIntCrvSrf) Then
blnLoop = 1
arrIntDots(0) = Rhino.AddTextDot(“IntA”,arrIntCrvSrf(0,1))
arrIntDots(1) = Rhino.AddTextDot(“IntB”,arrIntCrvSrf(1,1))
Call Rhino.SelectObjects(arrIntDots)
strChoice = Rhino.GetString(“Point IntA[A] or point IntB[B]?”,”A”, Array(“A”,”B”))
If strChoice = “A” Then
arrIntPt = arrIntCrvSrf(0,1)
ElseIf strChoice = “B” Then
arrIntPt = arrIntCrvSrf(1,1)
End If
Else
Call Rhino.DeleteObjects(arrTempDots)
Call Rhino.DeleteObjects(arrTempSphs)
Call Rhino.DeleteObject(strJoinCrv)
blnLoop = 0
Call Rhino.MessageBox(“The member lengths can not be triangulated. Please try a different set of members.”)
Exit For
End If
End If
Next
Loop
Call Rhino.DeleteObjects(arrIntDots)
Call Rhino.DeleteObjects(arrTempSphs)
Call Rhino.DeleteObjects(arrTempDots)
Call Rhino.DeleteObject(strJoinCrv)
For i = 0 To 2
arrTempLines(i) = Rhino.AddLine(arrInPts(i),arrIntPt)
Next
intLineCount = UBound(arrLines)
ReDim Preserve arrLines(intLineCount+3)
arrLines(intLineCount+1) = arrTempLines(0)
arrLines(intLineCount+2) = arrTempLines(1)
arrLines(intLineCount+3) = arrTempLines(2)
intPtNum = UBound(arrTxtDots)
ReDim Preserve arrTxtDots(intPtNum+1)
arrTxtDots(intPtNum+1) = Rhino.AddTextDot(“P”&CStr(intPtNum+1),arrIntPt)
intCGChoice = CG(arrTxtDots,arrLines)
If intCGChoice = 7 Then
Call Rhino.DeleteObjects(arrTempLines)
Call Rhino.DeleteObject(arrTxtDots(intPtNum+1))
ReDim Preserve arrTxtDots(intPtNum)
ReDim Preserve arrLines(intLineCount)
End If
Tetrahedron = arrTxtDots
End Function
Function JoinCurve(arrCrvs)
‘takes the two dimensional array resulting from a SurfaceSurfaceIntersection command and returns the string identifier of the joined intersection segments
Dim intSegments, arrJoin
Dim i
intSegments = UBound(arrCrvs,1)
ReDim arrJoinCrvs(intSegments)
For i = 0 To intSegments
arrJoinCrvs(i) = arrCrvs(i,1)
Next
arrJoin = Rhino.JoinCurves(arrJoinCrvs, True)
JoinCurve = arrJoin(0)
End Function
Function Triangulate(ByRef arrLines, arrTxtDots)
Dim arrInPt1, arrInPt2, strTempDot1, strTempDot2, strTempLine
Dim intMsg, intLineCount, intCGChoice
arrInPt1 = Rhino.GetPoint(“Select first point”)
strTempDot1 = Rhino.AddTextDot(“1″,arrInPt1)
Call Rhino.SelectObject(strTempDot1)
arrInPt2 = Rhino.GetPoint(“Select second point”)
strTempDot2 = Rhino.AddTextDot(“2″,arrInPt2)
Call Rhino.SelectObject(strTempDot2)
intMsg = Rhino.MessageBox(“The member length required between these points is “&CStr(Rhino.Distance(arrInPt1,arrInPt2)),4)
If intMsg = 6 Then
Call Rhino.AddLayer(“cut_members”, RGB(255,0,0))
Call Rhino.CurrentLayer(“cut_members”)
intLineCount = UBound(arrLines)
ReDim Preserve arrLines(intLineCount+1)
arrLines(intLineCount+1) = Rhino.AddLine(arrInPt1,arrInPt2)
Call Rhino.CurrentLayer(“uncut_members”)
End If
intCGChoice = CG(arrTxtDots,arrLines)
If intCGChoice = 7 Then
Call Rhino.DeleteObject(arrLines(intLineCount+1))
ReDim Preserve arrLines(intLineCount)
End If
Call Rhino.DeleteObject(strTempDot1)
Call Rhino.DeleteObject(strTempDot2)
End Function
Function Panelize
Dim strStart
Dim strDot1, strDot2, strDot3
ReDim arrPts(2)
Dim strSrf
ReDim arrEdges(2)
ReDim arrDgs(2)
Dim arrTempDiv
ReDim strDots(2)
Dim intMsg, arrFlat, arrFlatOrPt, arrBox
strDot1 = Rhino.GetObject(“Select first point”,8192)
Call Rhino.SelectObject(strDot1)
strDot2 = Rhino.GetObject(“Select second point”,8192)
Call Rhino.SelectObject(strDot2)
strDot3 = Rhino.GetObject(“Select third point”,8192)
Call Rhino.SelectObject(strDot3)
arrPts(0) = Rhino.TextDotPoint(strDot1)
arrPts(1) = Rhino.TextDotPoint(strDot2)
arrPts(2) = Rhino.TextDotPoint(strDot3)
strSrf = Rhino.AddSrfPt(arrPts)
arrEdges(0) = Rhino.AddLine(arrPts(0),arrPts(1))
arrEdges(1) = Rhino.AddLine(arrPts(1),arrPts(2))
arrEdges(2) = Rhino.AddLine(arrPts(2),arrPts(0))
arrDgs(0) = Rhino.AddLine(arrPts(0),Rhino.CurveMidPoint(arrEdges(1)))
arrDgs(1) = Rhino.AddLine(arrPts(1),Rhino.CurveMidPoint(arrEdges(2)))
arrDgs(2) = Rhino.AddLine(arrPts(2),Rhino.CurveMidPoint(arrEdges(0)))
arrTempDiv = Rhino.DivideCurve(arrDgs(0),4)
strDots(0) = Rhino.CopyObject(strDot1,arrPts(0),arrTempDiv(1))
arrTempDiv = Rhino.DivideCurve(arrDgs(1),4)
strDots(1) = Rhino.CopyObject(strDot2,arrPts(1),arrTempDiv(1))
arrTempDiv = Rhino.DivideCurve(arrDgs(2),4)
strDots(2) = Rhino.CopyObject(strDot3,arrPts(02),arrTempDiv(1))
Call Rhino.DeleteObjects(arrEdges)
Call Rhino.DeleteObjects(arrDgs)
Call Rhino.UnselectAllObjects()
intMsg = Rhino.MessageBox(“Flatten this panel?”,4)
If intMsg = 7 Then
Call Rhino.DeleteObject(strSrf)
Call Rhino.DeleteObjects(strDots)
ElseIf intMsg = 6 Then
If Not IsArray(arrFlatOrPt) Then
arrFlatOrPt = Rhino.GetPoint(“Select origin point for unroll”)
End If
arrFlat = RhinoUnrollSurface(strSrf,strDots,False,False)
arrFlat = Rhino.MoveObjects(arrFlat,Array(0,0,0),arrFlatOrPt)
arrBox = Rhino.BoundingBox(arrFlat)
arrFlatOrPt = arrBox(1)
Call Rhino.DeleteObjects(strDots)
End If
End Function
Function RhinoUnrollSurface(strSurface, arrCurves, blnExplode, blnLabels)
‘ Default return value
RhinoUnrollSurface = Null
‘ For speed, turn of screen redrawing
Call Rhino.EnableRedraw(False)
‘ Save any selected objects
Dim arrSaved : arrSaved = Rhino.SelectedObjects
‘ Unselect all objects
Rhino.UnSelectAllObjects
‘ Select the surface to unroll
Rhino.SelectObject strSurface
‘ Format curve string
Dim i : i = 0
Dim strCurves : strCurves = ” _Enter”
If IsArray(arrCurves) Then
strCurves = “”
For i = 0 To UBound(arrCurves)
strCurves = strCurves & ” _SelId ” & arrCurves(i)
Next
strCurves = strCurves & ” _Enter”
End If
‘ Format explode string
Dim strExplode : strExplode = ” _Explode=_Yes”
If (blnExplode = False) Then strExplode = ” _Explode=_No”
‘ Format labels string
Dim strLabels : strLabels = ” _Labels=_No”
If (blnLabels = True) Then strLabels = ” _Labels=_Yes”
‘ Script the command
Dim strCommand : strCommand = “_-UnrollSrf” & strExplode & strLabels & strCurves
Call Rhino.Command(strCommand, 0)
‘ Return the results
RhinoUnrollSurface = Rhino.LastCreatedObjects
‘ Unselect all objects
Rhino.UnSelectAllObjects
‘ If any objects were selected before calling
‘ this function, re-select them
If IsArray(arrSaved) Then Rhino.SelectObjects(arrSaved)
‘ Don’t forget to turn redrawing back on
Call Rhino.EnableRedraw(True)
End Function
Function CG(arrDots, ByRef arrLines)
ReDim arrDotPts(UBound(arrDots))
Dim dblSumLength, arrMidPt
Dim dblX, dblY, dblZ, dblLength
Dim i
ReDim arrMemCGPt(2)
ReDim arrJtCGPt(2)
ReDim arrCGPt(2)
Dim strTempCGPt, strTempCGLine, intCount
intCount = 0
ReDim arrBasePts(intCount)
Dim arrSortBasePts, strBaseCrv, intInside, arrCGBasePt
Dim intChoice
Dim dblMemDens, dblJtWt
dblMemDens = 1 ‘average bamboo density assumed to be 1kg/running meter = 1g/running mm
dblJtWt = 2000 ‘average weight per joint assumed to be 2kg = 2000g
For i = 0 To UBound(arrLines)
dblSumLength = dblSumLength+Rhino.CurveLength(arrLines(i))
Next
For i = 0 To UBound(arrLines)
arrMidPt = Rhino.CurveMidPoint(arrLines(i))
dblLength = Rhino.CurveLength(arrLines(i))
dblX = dblX+((arrMidPt(0))*(Rhino.CurveLength(arrLines(i))))
dblY = dblY+((arrMidPt(1))*(Rhino.CurveLength(arrLines(i))))
dblZ = dblZ+((arrMidPt(2))*(Rhino.CurveLength(arrLines(i))))
Next
arrMemCGPt(0) = dblX/dblSumLength
arrMemCGPt(1) = dblY/dblSumLength
arrMemCGPt(2) = dblZ/dblSumLength
dblX = 0
dblY = 0
dblZ = 0
For i = 0 To UBound(arrDots)
arrDotPts(i) = Rhino.TextDotPoint(arrDots(i))
dblX = dblX+arrDotPts(i)(0)
dblY = dblY+arrDotPts(i)(1)
dblZ = dblZ+arrDotPts(i)(2)
Next
arrJtCGPt(0) = dblX/i
arrJtCGPt(1) = dblY/i
arrJtCGPt(2) = dblZ/i
arrCGPt(0) = ((dblMemDens*dblSumLength*arrMemCGPt(0))+(dblJtWt*i*arrJtCGPt(0)))/((dblMemDens*dblSumLength)+(dblJtWt*i))
arrCGPt(1) = ((dblMemDens*dblSumLength*arrMemCGPt(1))+(dblJtWt*i*arrJtCGPt(1)))/((dblMemDens*dblSumLength)+(dblJtWt*i))
arrCGPt(2) = ((dblMemDens*dblSumLength*arrMemCGPt(2))+(dblJtWt*i*arrJtCGPt(2)))/((dblMemDens*dblSumLength)+(dblJtWt*i))
strTempCGPt = Rhino.AddPoint(arrCGPt)
strBaseCrv = Base(arrDotPts)
arrCGBasePt = arrCGPt
arrCGBasePt(2) = 0
strTempCGLine = Rhino.AddLine(arrCGPt,arrCGBasePt)
intInside = Rhino.PointInPlanarClosedCurve(arrCGBasePt,strBaseCrv)
Call Rhino.DeleteObject(strBaseCrv)
If intInside <> 1 Then
intChoice = Rhino.MessageBox(“The addition of this point will cause the structure to topple. Carry on anyway?”,4)
Else
intChoice = Rhino.MessageBox(“The addition of this point will not cause the structure to topple”)
End If
Call Rhino.DeleteObject(strTempCGPt)
Call Rhino.DeleteObject(strTempCGLine)
CG = intChoice
End Function
Function Base(arrAllPts)
Dim intPolyCount, intPtCount, intInOut
Dim i, j
Dim arrTempPoly, strTempPoly
Dim dblDist, dblMinDist, intMinPt, bolMin
Dim dblParam, arrClsPt
Dim arrTempPts
Dim arrJoin
intPtCount = 0
intPolyCount = 2
bolMin = 0
ReDim arrPts(intPtCount)
ReDim arrBasePts(intPolyCount)
ReDim arrBaseLns(intPolyCount)
For i = 0 To UBound(arrAllPts)
If arrAllPts(i)(2) = 0 Then
arrPts(intPtCount) = arrAllPts(i)
intPtCount = intPtCount+1
ReDim Preserve arrPts(intPtCount)
End If
Next
intPtCount = intPtCount-1
ReDim Preserve arrPts(intPtCount)
arrBasePts(0) = arrPts(0)
arrBasePts(1) = arrPts(1)
arrBasePts(2) = arrPts(2)
arrBaseLns(0) = Rhino.AddLine(arrBasePts(0),arrBasePts(1))
arrBaseLns(1) = Rhino.AddLine(arrBasePts(1),arrBasePts(2))
arrBaseLns(2) = Rhino.AddLine(arrBasePts(2),arrBasePts(0))
For i = 3 To intPtCount
arrTempPoly = Rhino.JoinCurves(arrBaseLns)
strTempPoly = arrTempPoly(0)
intInOut = Rhino.PointInPlanarClosedCurve(arrPts(i),strTempPoly)
Call Rhino.DeleteObject(strTempPoly)
If intInOut = 0 Then
For j = 0 To intPolyCount
dblDist = Rhino.Distance(arrBasePts(j),arrPts(i))
If j = 0 Then
dblMinDist = dblDist
intMinPt = j
bolMin = 0
Else
If dblDist < dblMinDist Then
dblMinDist = dblDist
intMinPt = j
bolMin = 0
End If
End If
Next
For j = 0 To intPolyCount
dblParam = Rhino.CurveClosestPoint(arrBaseLns(j),arrPts(i))
arrClsPt = Rhino.EvaluateCurve(arrBaseLns(j),dblParam)
dblDist = Rhino.Distance(arrClsPt,arrPts(i))
If dblDist < dblMinDist Then
dblMinDist = dblDist
intMinPt = j
bolMin = 1
End If
Next
If bolMin = 0 Then
arrBasePts(intMinPt) = arrPts(i)
Call Rhino.DeleteObjects(arrBaseLns)
For j = 0 To intPolyCount-1
arrBaseLns(j) = Rhino.AddLine(arrBasePts(j),arrBasePts(j+1))
Next
arrBaseLns(intPolyCount) = Rhino.AddLine(arrBasePts(intPolyCount),arrBasePts(0))
ElseIf bolMin = 1 Then
arrTempPts = arrBasePts
intPolyCount = intPolyCount+1
ReDim Preserve arrBasePts(intPolyCount)
arrBasePts(intMinPt+1) = arrPts(i)
For j = intMinPt+2 To intPolyCount
arrBasePts(j) = arrTempPts(j-1)
Next
Call Rhino.DeleteObjects(arrBaseLns)
ReDim Preserve arrBaseLns(intPolyCount)
For j = 0 To intPolyCount-1
arrBaseLns(j) = Rhino.AddLine(arrBasePts(j),arrBasePts(j+1))
Next
arrBaseLns(intPolyCount) = Rhino.AddLine(arrBasePts(intPolyCount),arrBasePts(0))
End If
End If
Next
arrJoin = Rhino.JoinCurves(arrBaseLns,True)
Base = arrJoin(0)
End Function
Function GoalPoint(arrTextDots,arrGoalPt)
Dim strMin, blnSwap
Dim i, j, k
ReDim arrDist(UBound(arrTextDots))
Do
blnSwap = False
For i = 1 To UBound(arrTextDots)
If Rhino.Distance(Rhino.TextDotPoint(arrTextDots(i-1)),arrGoalPt) > Rhino.Distance(Rhino.TextDotPoint(arrTextDots(i)),arrGoalPt) Then
strMin = arrTextDots(i)
arrTextDots(i) = arrTextDots(i-1)
arrTextDots(i-1) = strMin
blnSwap = True
End If
Next
Loop While blnSwap = True
Call Rhino.SelectObject(arrTextDots(0))
Call Rhino.MessageBox(“The closest node to the goal point has been selected”)
End Function