-- GlueMaker -- by Neal D Corbett, R*Leeds -- 26/01/2010 try (DestroyDialog RSL_GlueMaker) catch () rollout RSL_GlueMaker "R*Leeds GlueMaker" width:200 ( label GlueLabel "Creates \"glue\" objects from selected\nborder-edges of selected objects,\nso buildings sit on the ground better" align:#left height:46 spinner GlueWidthUI "Glue width:" range:[0.1,20,1] spinner CornerPushUI "Corner push-factor:" range:[0.0,2,0.0] spinner AllPushUI "Wall/floor offset:" range:[0.0,1,0.002] checkbox DelOldGlueUI "Delete object's old glue on create" checked:true button GlueMakeBtn "Make glue for selected objects" on GlueMakeBtn pressed do ( undo "make glue" on ( local OldSelect = for ThisObj in selection collect ThisObj for ThisObj in OldSelect where ( ((iskindOf ThisObj Editable_Poly) or (iskindOf ThisObj Editable_Mesh)) and (not (matchPattern ThisObj.name pattern:"*_glue??"))) do ( if DelOldGlueUI.checked do ( (execute ("delete $'" + ThisObj.name + "_glue*'")) ) local GlueWidth = GlueWidthUI.value local CornerPush = CornerPushUI.value * GlueWidth local AllPush = AllPushUI.value local NewObj = copy ThisObj NewObj.name = uniquename (ThisObj.name + "_glue") convertToPoly NewObj local GlueEdges = (polyOp.getEdgeSelection NewObj) * (polyOp.getOpenEdges NewObj) if (GlueEdges.numberSet == 0) then delete NewObj else ( polyOp.setEdgeSelection NewObj GlueEdges NewObj.ConvertSelectionToBorder #Edge #Edge -- Generate lists of contiguous edge-selections local EdgeVertGroups = for Edge in GlueEdges collect (polyOp.getVertsUsingEdge NewObj Edge) local VertsUsed = polyOp.getVertsUsingEdge NewObj GlueEdges local VertAdjacents = for n = 1 to VertsUsed.count collect #{} for Edge in EdgeVertGroups do (for VertNum in Edge do (VertAdjacents[VertNum] += Edge)) -- for n = 1 to VertAdjacents.count where (VertAdjacents[n].count != 0) do (format "%: %\n" n VertAdjacents[n]) local RemoveEdges, Conjunction local Rearrange = True while Rearrange do ( Rearrange = False RemoveEdges = #{} for EdgeNum = 1 to EdgeVertGroups.count where (not RemoveEdges[EdgeNum]) do ( for SearchEdge = (EdgeNum + 1) to EdgeVertGroups.count where (not RemoveEdges[SearchEdge]) do ( Conjunction = EdgeVertGroups[EdgeNum] + EdgeVertGroups[SearchEdge] if (Conjunction.numberSet != (EdgeVertGroups[EdgeNum].numberSet + EdgeVertGroups[SearchEdge].numberSet)) do ( EdgeVertGroups[EdgeNum] = Conjunction RemoveEdges[SearchEdge] = True Rearrange = True ) ) ) -- Remove now-combined edge-arrays, in reverse order RemoveEdges = RemoveEdges as array for n = RemoveEdges.count to 1 by -1 do ( deleteItem EdgeVertGroups RemoveEdges[n] ) ) EdgeVertGroups = for Group in EdgeVertGroups collect (Group as array) -- Create lists of verts, with all numbers correctly adjacent for GroupNum = 1 to EdgeVertGroups.count do ( local NewGroup, NotFound local OldGroup = EdgeVertGroups[GroupNum] local Placed = #{} while ((Placed.numberSet != OldGroup.count) and (not keyboard.escPressed)) do ( for n = 1 to OldGroup.count where (not Placed[n]) do ( VertNum = OldGroup[n] if (NewGroup == undefined) then (NewGroup = #(VertNum); Placed[n] = True) else ( case of ( (VertAdjacents[VertNum][NewGroup[NewGroup.count]]): ( append NewGroup VertNum Placed[n] = True ) (VertAdjacents[VertNum][NewGroup[1]]): ( insertItem VertNum NewGroup 1 Placed[n] = True ) ) ) ) ) -- Find and break edge-loops if (VertAdjacents[NewGroup[1]][NewGroup[NewGroup.count]]) do ( polyOp.breakVerts NewObj NewGroup[1] local OldVertNum = NewGroup[1] local NewVertNum = NewObj.numVerts if (polyOp.getVertsUsingEdge NewObj (polyOp.getEdgesUsingVert NewObj NewVertNum))[NewGroup[2]] then ( NewGroup[1] = NewVertNum append NewGroup OldVertNum ) else ( append NewGroup NewVertNum ) ) EdgeVertGroups[GroupNum] = NewGroup ) -- format "EdgeVertGroups: %\n" (EdgeVertGroups as string) -- Set out the initial mapping polyOp.defaultMapFaces NewObj 1 local UVDistance, PrevVertPos, VertPos for Group in EdgeVertGroups do ( PrevVertPos = undefined UVDistance = 0 for VertNum in Group do ( VertPos = polyOp.getVert NewObj VertNum if (PrevVertPos != undefined) do ( UVDistance += ((distance VertPos PrevVertPos) / GlueWidth) ) polyOp.setMapVert NewObj 1 VertNum [UVDistance,0.5,0] PrevVertPos = VertPos ) ) -- format "EdgeFaces: %\n" EdgeFaces max Modify Mode modPanel.setCurrentObject NewObj -- Extrusions: setSelectionLevel NewObj #edge NewObj.edgeChamfer = 0.0 NewObj.edgeExtrudeHeight = GlueWidth NewObj.edgeExtrudeWidth = 0.0 NewObj.edgeChamferOpen = True NewObj.EditablePoly.buttonOp #Extrude NewObj.EditablePoly.ConvertSelection #Edge #Face polyOp.deleteFaces NewObj -(polyOp.getFaceSelection NewObj) local OuterSelect = polyOp.getEdgeSelection NewObj NewObj.EditablePoly.GrowSelection() polyOp.weldEdgesByThreshold NewObj ((polyOp.getEdgeSelection NewObj) - OuterSelect) local ExtrudeEdges = -(polyOp.getEdgeSelection NewObj) polyOp.setEdgeSelection NewObj ExtrudeEdges NewObj.EditablePoly.buttonOp #Extrude -- White vertex colours polyOp.SetFaceColor NewObj -2 #{1..NewObj.numFaces} (color 255 255 255) -- White vertex alpha polyOp.SetFaceColor NewObj 0 #{1..NewObj.numFaces} (color 255 255 255) -- Move border-UVs to top & bottom of map local StartVertCount = (polyop.getNumMapVerts NewObj 1) / 3 local NextNum for VertNum = 1 to StartVertCount do ( polyOp.setMapVert NewObj 1 VertNum ((polyOp.getMapVert NewObj 1 VertNum) + [0,-0.5,0]) NextNum = VertNum + StartVertCount polyOp.setMapVert NewObj 1 NextNum ((polyOp.getMapVert NewObj 1 NextNum) + [0,0.5,0]) ) local VertFaceNums = #() local VertFaceNormals = #() local VertFaces, AvNormal VertFaceNormals = for n = 1 to NewObj.numVerts collect ( local VertFaces = (polyOp.getFacesUsingVert NewObj n) as array append VertFaceNums VertFaces case VertFaces.count of ( 4: ( AvNormal = [0,0,0] for FaceNum in VertFaces do (AvNormal += (polyOp.getFaceNormal NewObj FaceNum)) AvNormal /= 4.0 ) Default:Null ) ) local AvNormal, FaceVerts, FaceHash, FindNum, OppIndex local MakeEdges = #() local FaceSearchList = #() if (CornerPush != 0) do ( for n = 1 to NewObj.numVerts do ( case of ( (VertFaceNormals[n] != null): -- Move wall/floor corner-verts outward ( polyOp.moveVert NewObj #{n} (VertFaceNormals[n] * CornerPush) ) (VertFaceNums[n].count == 1): -- Add diagonal edge to single-quad verts ( -- Find other verts using the quad this vert uses FaceVerts = polyOp.getFaceVerts NewObj VertFaceNums[n][1] FaceHash = getHashValue FaceVerts 1 FindNum = findItem FaceSearchList FaceHash if (FindNum == 0) then ( -- Find the index of the vert on opposite side of quad, and create edge OppIndex = (findItem FaceVerts n) + 2 if (OppIndex > 4) do (OppIndex = mod OppIndex 4) append MakeEdges #(n,FaceVerts[OppIndex]) append FaceSearchList FaceHash ) else ( -- Don't add edges for single-length glue deleteItem MakeEdges FindNum deleteItem FaceSearchList FindNum ) ) ) ) for Edge in MakeEdges do ( polyOp.createEdge NewObj Edge[1] Edge[2] ) ) if (AllPush != 0) do (setSelectionLevel NewObj #face; addModifier NewObj (Push PushValue:AllPush); collapseStack NewObj) polyOp.autoSmooth NewObj setSelectionLevel NewObj #object /* NewObj.alledges = on NewObj.wirecolor = orange NewObj.material = StandardMaterial() -- NewObj.material.diffuseMap = Gradient() -- NewObj.material.diffuseMap = Gradient_Ramp() NewObj.material.diffuseMap = Checker() NewObj.material.diffuseMap.coords.U_Tiling = 8 NewObj.material.diffuseMap.coords.V_Tiling = 8 showTextureMap NewObj.material on */ ) ) select (for ThisObj in OldSelect where (isValidNode ThisObj) collect ThisObj) ) ) ) createDialog RSL_GlueMaker