' Script to randomize controlpoints ' works with (preselected) grips of curves, surfaces or meshes ' © 2010 Clement Greiner, www.cg3d.de Option Explicit Sub MyGripRandomizer ' generally needed Dim strObject, intObjType, b, strMode, arrSelIndices, blnHideGrips, arrPoints, i, arrNew(2), arrResult(), arrPtOnCrv, arrTrans, arrTNormalized, arrNRandomized ' needed for curves Dim arrCrvEditPts, dblParam ' needed for surfaces Dim arrSrfEditPts, arrParam, arrPtOnSrf, arrNormal ' needed for meshes Dim arrMeshVNormals Dim bound ' get object to transform strObject = Rhino.GetObject("Select curve, surface, mesh or cage control to randomize", 4+8+32+131072, vbTrue, vbTrue) If IsNull(strObject) Then Exit Sub ' save obj type intObjType = Rhino.ObjectType(strObject) ' transformation distance b = Rhino.GetDocumentData("GripRandomizer", "b") If IsNull(b) Then b = 1 Else b = CDbl(b) b = Rhino.GetReal("maximum transformation distance", b) If IsNull(b) Then Exit Sub If b = 0 Then b = 0.001 Rhino.SetDocumentData "GripRandomizer", "b", b ' transformation direction strMode = Rhino.GetDocumentData("GripRandomizer", "strMode") If IsNull(strMode) Then ' set a default value if no value If intObjType <> 131072 Then strMode = "Normal" Else strMode = "XYZ" Else ' force xyz if normal option was saved to document data and cage is used If intObjType = 131072 And strMode = "Normal" Then strMode = "XYZ" End If If intObjType <> 131072 Then ' curves, surfaces and meshes can use the normal option strMode = Rhino.GetString("Choose a transformation mode", strMode, Array("Normal", "X", "Y", "Z", "XY", "XYZ")) Else ' for cage control, no normal option strMode = Rhino.GetString("Choose a transformation mode", strMode, Array("X", "Y", "Z", "XY", "XYZ")) End If If IsNull(strMode) Then Exit Sub If intObjType = 131072 And strMode = "Normal" Then Rhino.Print "the normal option cannot be used for cage controls." : Exit Sub If strMode = "Normal" Or strMode = "X" Or strMode = "Y" Or strMode = "Z" Or strMode = "XY" Or strMode = "XYZ" Then Rhino.SetDocumentData "GripRandomizer", "strMode", strMode Else Exit Sub ' check if there is a pre-selection of grips If Rhino.ObjectGripsOn(strObject) Then ' MsgBox "grips are on" ' check if object grips are selected If Rhino.ObjectGripsSelected(strObject) = True Then ' MsgBox "Grips selected" Rhino.EnableRedraw vbFalse blnHideGrips = False ' get indexes of all selected grips Else blnHideGrips = True ' MsgBox "no grips selected" ' grips on but none selected will transform/ select ALL grips Rhino.EnableRedraw vbFalse Rhino.SelectObjectGrips strObject ' transform all grips End If Else ' MsgBox "grips are off" blnHideGrips = True Rhino.EnableRedraw vbFalse ' turn grips on Rhino.EnableObjectGrips strObject, True ' select all Grips of this object Rhino.SelectObjectGrips strObject ' transform all grips End If ' get all grip locations arrPoints = Rhino.ObjectGripLocations(strObject) If Not IsArray(arrPoints) Then Exit Sub ' get all selected grip location indices arrSelIndices = Rhino.SelectedObjectGrips(strObject) ' exit if no grip indices are found If Not IsArray(arrSelIndices) Then Exit Sub Dim objDictionary Set objDictionary = CreateObject("Scripting.Dictionary") ' create a dictionary obj holding all grip indices Rhino.Prompt "Creating grip index list with " & UBound(arrSelIndices) + 1 & " indices..." bound = Ubound(arrSelIndices) For i = 0 To bound objDictionary.Add(arrSelIndices(i)), 0 Next ' all (selected) grip indices are now stored in the dictionary Rhino.Print 1+ CStr(UBound(arrSelIndices)) & " grips selected for random transformation along " & strMode ' MsgBox Join(arrSelIndices, " ") ' show something while it runs Rhino.Prompt "Randomizing " & UBound(arrPoints)+1 & " grips... press ESC to cancel" ' get infos needed if the "normal" option is used If strMode = "Normal" Then ' get infos needed for curves If Rhino.IsCurve(strObject) Then arrCrvEditPts = Rhino.CurveEditPoints(strObject) ' get infos needed for surfaces If Rhino.IsSurface(strObject) Then arrSrfEditPts = Rhino.SurfaceEditPoints(strObject) ' get infos needed for meshes If Rhino.IsMesh(strObject) Then arrMeshVNormals = Rhino.MeshVertexNormals(strObject) End If ' iterate through all grip points ! bound = UBound(arrPoints) For i = 0 To bound ' find out if is inside the dictionary, transfrom grip by index If objDictionary.Exists(i) Then ' needs transformation because it`s selected ' Rhino.AddPoint arrPoints(i) ' select transformation Select Case strMode Case "X" arrNew(0) = Rnd*b + arrPoints(i)(0) - Rnd*b arrNew(1) = arrPoints(i)(1) arrNew(2) = arrPoints(i)(2) Case "Y" arrNew(0) = arrPoints(i)(0) arrNew(1) = Rnd*b + arrPoints(i)(1) - Rnd*b arrNew(2) = arrPoints(i)(2) Case "Z" arrNew(0) = arrPoints(i)(0) arrNew(1) = arrPoints(i)(1) arrNew(2) = Rnd*b + arrPoints(i)(2) - Rnd*b Case "XY" arrNew(0) = Rnd*b + arrPoints(i)(0) - Rnd*b arrNew(1) = Rnd*b + arrPoints(i)(1) - Rnd*b arrNew(2) = arrPoints(i)(2) Case "XYZ" arrNew(0) = Rnd*b + arrPoints(i)(0) - Rnd*b arrNew(1) = Rnd*b + arrPoints(i)(1) - Rnd*b arrNew(2) = Rnd*b + arrPoints(i)(2) - Rnd*b Case "Normal" ' each object type has a different way... Select Case intObjType ' transformation along normal (or cp direction) for CURVES Case 4 ' get corresponding edit point for this grip arrPtOnCrv = arrCrvEditPts(i) ' check if grip is on curve If PtComp(arrPtOnCrv, arrPoints(i)) = 0 Then ' get tangent/curve normal vector, normalized at the origin dblParam = Rhino.CurveClosestPoint(strObject, arrPtOnCrv) arrTrans = Rhino.CurveFrame(strObject, dblParam)(2) ' reverse this vector, so it matches the normal direction of all other vectors arrTNormalized = Vector_Reverse(arrTrans) ' randomize the vector arrNRandomized = Vector_Scale(arrTNormalized, rnd*b) ' transform back arrTrans = Vector_Add(arrNRandomized, arrPoints(i)) Else ' transform this point and the grip point so the pt on crv is the origin arrTrans = Vector_Subtract(arrPoints(i), arrPtOnCrv) ' normalize to vector length = 1 arrTNormalized = Vector_Unitize(arrTrans) ' randomly scale this vector arrNRandomized = Vector_Scale (arrTNormalized, rnd*b) ' and ADD it to the transformed vector arrTrans = Vector_Add(arrNRandomized, arrTrans) ' transform back arrTrans = Vector_Add(arrTrans, arrPtOnCrv) End If ' create the point arrNew(0) = arrTrans(0) arrNew(1) = arrTrans(1) arrNew(2) = arrTrans(2) ' transformation along normal (or cp direction) for SURFACES Case 8 ' get closest point from grip to surface (1st derivative) arrPtOnSrf = arrSrfEditPts(i) ' check if grip is on surface (corners), use normal direction If PtComp(arrPtOnSrf, arrPoints(i)) = 0 Then ' get normalized surface normal at world origin arrParam = Rhino.SurfaceClosestPoint(strObject, arrPtOnSrf) arrNormal = Rhino.SurfaceNormal(strObject, arrParam) ' randomize this vector by scaling it arrNRandomized = Vector_Scale (arrNormal, rnd*b) ' transform back arrTrans = Vector_Add(arrNRandomized, arrPtOnSrf) Else ' use grip loctation as transform direction, transform grip to origin arrTrans = Vector_Subtract(arrPoints(i), arrPtOnSrf) ' Normalize transformed vector arrTNormalized = Vector_Unitize(arrTrans) ' randomize this vector arrNRandomized = Vector_Scale(arrTNormalized, rnd*b) ' and ADD it to the transformed vector arrTrans = Vector_Add(arrNRandomized, arrTrans) ' transform back arrTrans = Vector_Add(arrTrans, arrPtOnSrf) End If ' create the point arrNew(0) = arrTrans(0) arrNew(1) = arrTrans(1) arrNew(2) = arrTrans(2) ' transformation of MESHES Case 32 ' get vertex normal (unitized) arrTNormalized = arrMeshVNormals(i) ' randomize this vector arrNRandomized = Vector_Scale(arrTNormalized, rnd*b) ' transform back arrTrans = Vector_Add(arrNRandomized, arrPoints(i)) ' create the point arrNew(0) = arrTrans(0) arrNew(1) = arrTrans(1) arrNew(2) = arrTrans(2) ' transformation of Cages ' 1. get grip point location ' 2. find closest point on captive object ' 3. find the normal on this point ' 4. randomize the normal ' 5. transform back to cage grip location Case Else Print "Error 222" Rhino.EnableRedraw vbTrue Exit Sub End Select Case Else Print "ModeError" Rhino.EnableRedraw vbTrue Exit Sub End Select ' create a new grip location ReDim Preserve arrResult(i) arrResult(i) = arrNew Else ' if the grip is not selected write unselected, untransformed grip location(s) Redim Preserve arrResult(i) arrResult(i) = arrPoints(i) End If If ((i+1) Mod 5000) = 0 Then Rhino.StatusBarMessage i+1 & "/" & bound+1 Next If Not IsArray(arrResult) Then Rhino.EnableRedraw vbTrue Print "Error 255" Exit Sub End If ' transform all grips at once Rhino.ObjectGripLocations strObject, arrResult If Rhino.IsSurface(strObject) And Rhino.IsObjectSelected(strObject) Then Rhino.Command "_Refresh _Enter", vbFalse If blnHideGrips Then Rhino.EnableObjectGrips strObject, vbFalse Rhino.SelectObject strObject Rhino.EnableRedraw vbTrue Rhino.StatusBarMessage " GripRandomize.rvb ready." Erase arrResult ' cleanup Set objDictionary = Nothing End Sub ' function to compare two points Function PtComp(ByVal arrA, ByVal arrB) PtComp = vbNull Select Case StrComp(arrA(0),arrB(0),1) Case 0 If StrComp(arrA(1),arrB(1),1) = 0 And StrComp(arrA(2),arrB(2),1) = 0 Then PtComp = 0 Exit Function End If Case Else PtComp = 1 End Select End Function ' function to measure the distance between 2 points Function GET_Dist2Pt(A,B) GET_Dist2Pt = Sqr((A(0)-B(0))*(A(0)-B(0))+(A(1)-B(1))*(A(1)-B(1))+(A(2)-B(2))*(A(2)-B(2))) End Function Function Vector_Subtract(v1, v2) Vector_Subtract = Array((v1(0)-v2(0)),(v1(1)-v2(1)),(v1(2)-v2(2))) End Function Function Vector_Add(v1, v2) Vector_Add = Array((v1(0)+v2(0)),(v1(1)+v2(1)),(v1(2)+v2(2))) End Function Function Vector_Divide(v, val) Vector_Divide = Array((v(0)/val),(v(1)/val),(v(2)/val)) End Function Function Vector_Scale(v, val) Vector_Scale = Array((v(0)*val),(v(1)*val),(v(2)*val)) End Function Function Vector_Reverse(v) Vector_Reverse = Array(-v(0),-v(1),-v(2)) End Function Function Vector_Unitize(v) Vector_Unitize = Vector_Divide(v, Vector_Length(v)) End Function Function Vector_Length(v) Vector_Length = Sqr((v(0)*v(0))+(v(1)*v(1))+(v(2)*v(2))) End Function MyGripRandomizer