RhinoScript attractors
From KokkugiaWiki
this tutorial covers the basics of a morphodynamic design strategy based on attractors. the first script demonstrates how a field of geometry can undergo simple transformations at a local level based on the proximity of a field of attractors. the second script looks at how more complex parametric transformations can be developed.
attractor tools scale
this script is used for scaling up or down fields of objects. however it is easy to modify the script to do more interesting things than scaling. in its current format it generates things like the following:
download this rhino file which contains the base geometry to operate on.
the pseudo-code for the script looks something like the following:
'define the variables
' user defined input
' loop through each object and get the closest attractor
' get object center point
' loop through attractors to find the distance to the closest attractor
' get distance from the object center point to the attractor
' is it closer then keep track of the distance and the attractor
' if the object is within the threshold then operate on it
Option Explicit
Call attractor()
' sub routine
Sub attractor()
Dim attArr, objArr, attXYZArr(), i, xyzPt, thresholdDistance
attArr = Rhino.GetObjects("select the attractor points", 1)
objArr = Rhino.GetObjects("select the objects to scale", 12)
thresholdDistance = Rhino.GetReal("threshold distance", 100)
' loop through all the attractors
For i = 0 To UBound(attArr)
' extract xyz coords
xyzPt = Rhino.PointCoordinates(attArr(i))
' add xyz's to an array
ReDim Preserve attXYZArr(i)
attXYZArr(i) = xyzPt
Next
Dim centerPt, closestPtIndex, dist
' loop through all the objects
For i = 0 To UBound(objArr)
' find the center point
centerPt = bBoxCenter(objArr(i))
' find the closest attractor
closestPtIndex = Rhino.PointArrayClosestPoint(attXYZArr, centerPt)
' find distance to closest attractor
dist = Rhino.Distance(attXYZArr(closestPtIndex), centerPt)
' scale the obj
Dim adjAmount
If (dist < thresholdDistance) Then
adjAmount = 1 - ( (thresholdDistance - dist) / thresholdDistance )
Rhino.ScaleObject objArr(i), centerPt, Array(adjAmount, adjAmount, adjAmount)
End If
Next
End Sub
Function bBoxCenter(obj)
Dim bbox
' get the bounding box
bbox = Rhino.BoundingBox(obj)
' return the center
bBoxCenter = Array((bbox(0)(0) + bbox(6)(0)) / 2 , (bbox(0)(1) + bbox(6)(1)) / 2 , (bbox(0)(2) + bbox(6)(2)) / 2 )
End Function
curve attractor version
this version can input either curves or points as attractors however it is slower than the basic point only version
Option Explicit
Call Main()
Sub Main()
Dim attArr, objArr, thresholdDistance, xyzPt, attXYZArr(), i, crvParam, j
' user input - attractors, objs, threshold
attArr = Rhino.GetObjects("select some attractors", 5)
objArr = Rhino.GetObjects("select the objects to scale", 60)
thresholdDistance = Rhino.GetReal("threshold distance", 20)
Dim centerPtArr, centerPt, closestPtIndex, dist, adjAmount
' loop through all objs
For i = 0 To UBound(objArr)
' find the center of the objs
centerPt = bBoxCenter(objArr(i))
' loop through attractors - get positions
For j = 0 To UBound(attArr)
If isCurve(attArr(j)) Then
crvParam = Rhino.CurveClosestPoint(attArr(j), centerPt)
xyzPt = Rhino.EvaluateCurve(attArr(j), crvParam)
Else
xyzPt = Rhino.PointCoordinates(attArr(j))
End If
ReDim Preserve attXYZArr(j)
attXYZArr(j) = xyzPt
Next
' find the closest attractor
closestPtIndex = Rhino.PointArrayClosestPoint(attXYZArr, centerPt)
' get distance to closest att
dist = Rhino.Distance(centerPt, attXYZArr(closestPtIndex) )
' scale
If dist < thresholdDistance Then
adjAmount = 1 - ( (thresholdDistance - dist) / thresholdDistance )
Rhino.ScaleObject objArr(i), centerPt, Array(adjAmount,adjAmount,adjAmount)
End If
Next
End Sub
Function bBoxCenter(obj)
Dim bbox
bbox = Rhino.BoundingBox(obj)
bBoxCenter = Array( (bbox(0)(0) + bbox(6)(0))/2, (bbox(0)(1) + bbox(6)(1))/2, (bbox(0)(2) + bbox(6)(2))/2 )
End Function
previous version
this version of the script was written prior to the release of the PointArrayClosestPoint method and also colors based on the attractor
Option Explicit
' script written by roland snooks | 2007 | www.kokkugia.com
Call attractorToolsScale
Sub attractorToolsScale
Dim i, j, arrObjects, arrAttract, thresholdDist, scaleFactor, arrBBox, arrCntrPt, counter, arrAttPt
Dim dblAttDistTest, dblClosestAttDist, dblClosestAtt, adjAmount
' input
arrObjects = Rhino.GetObjects("select objects")
arrAttract = Rhino.GetObjects("select point attractors", 0)
thresholdDist = Rhino.GetReal("distance threshold", 10, 0)
scaleFactor = Rhino.GetReal("scale factor", 1, 0)
' loop through each object and get the closest attractor
For i = 0 To UBound(arrObjects)
' get object bounding box centerpoint
arrBBox = Rhino.BoundingBox(arrObjects(i))
arrCntrPt = array((((arrBBox(2)(0)) + (arrBBox(0)(0))) / 2), (((arrBBox(2)(1)) + (arrBBox(0)(1))) / 2), (((arrBBox(0)(2)) + (arrBBox(4)(2))) / 2))
' loop through attractors to find the distance to the closest
counter = 0
For j = 0 To UBound(arrAttract)
arrAttPt = Rhino.PointCoordinates(arrAttract(j))
' get distance
dblAttDistTest = Rhino.Distance(arrAttPt, arrCntrPt)
' is it closer
If counter < 1 Then
dblClosestAttDist = dblAttDistTest
dblClosestAtt = counter
Else
If dblAttDistTest < thresholdDist Then
If dblAttDistTest < dblClosestAttDist Then
dblClosestAttDist = dblAttDistTest
dblClosestAtt = counter
End If
End If
End If
counter = counter + 1
Next
' if the object is within the threshold then operate on it
If dblClosestAttDist < thresholdDist Then
' caculate the adjustment amount
' decrease infinite amount
adjAmount = 1 - ((thresholdDist - dblClosestAttDist)/thresholdDist)
' increase by factor of up to 100% x scaleFactor
'adjAmount = ((thresholdDist - dblClosestAttDist)/thresholdDist) * scaleFactor + 1
' based on attractor proximity do something to the object (eg scale)
' scale
Rhino.ScaleObject arrObjects(i), arrCntrPt, array(adjAmount,adjAmount,adjAmount)
End If
Next
End Sub
in addition to scaling the objects we could also modify their color. this is best done with a separate function:
Function at_ChangeColor(obj,tDist,aDist,sFactor) Dim objColor, newColor ' caculate color newColor = 255 - ((1 - ((tDist - aDist)/tDist)) * 255) ' change color objColor = Rhino.ObjectColor(obj, newColor) End Function
this function would need to be called in the same part of the script where we call the scale method.
at_ChangeColor arrObjects(i),thresholdDist,dblClosestAttDist,scaleFactor
to use curves instead of points as attractors you could replace the following line of code:
arrAttPt = Rhino.PointCoordinates(arrAttract(j))
this bit of code is effectively getting the parameter of the closest point on the attractor curve and then returning the coordinates of that point.
dblParam = Rhino.CurveClosestPoint(arrAttract(j), arrCntrPt) arrAttPt = Rhino.EvaluateCurve(arrAttract(j), dblParam)
