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: Image:AttractorToolsScale.png


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)
Views