899 lines
24 KiB
Plaintext
Executable File
899 lines
24 KiB
Plaintext
Executable File
struct RsSelectionToolsStruct
|
|
(
|
|
private
|
|
|
|
storedVertPositions = #(),
|
|
|
|
|
|
-- Abstracted methods to deal with differences between Editable_Mesh and Editable_Poly. Thanks max.
|
|
fn _getVertSelection obj =
|
|
(
|
|
case (classOf obj) of
|
|
(
|
|
Editable_Poly:(polyop.getVertSelection obj)
|
|
Editable_Mesh:(getVertSelection obj)
|
|
)
|
|
),
|
|
|
|
fn _setFaceSelection obj faceList =
|
|
(
|
|
case (classOf obj) of
|
|
(
|
|
Editable_Poly:(polyop.setFaceSelection obj faceList)
|
|
Editable_Mesh:(setFaceSelection obj faceList)
|
|
)
|
|
|
|
completeRedraw()
|
|
),
|
|
|
|
fn _getFaceSelection obj =
|
|
(
|
|
case (classOf obj) of
|
|
(
|
|
Editable_Poly:(polyop.getFaceSelection obj)
|
|
Editable_Mesh:(getFaceSelection obj)
|
|
)
|
|
),
|
|
|
|
fn _setVertSelection obj vertList =
|
|
(
|
|
case (classOf obj) of
|
|
(
|
|
Editable_Poly:(polyop.setVertSelection obj vertList)
|
|
Editable_Mesh:(setVertSelection obj vertList)
|
|
)
|
|
|
|
completeRedraw()
|
|
),
|
|
|
|
fn _getVertsUsingEdge obj edgeList =
|
|
(
|
|
local objOp = RsMeshPolyOp obj
|
|
if (objOp == undefined) do return undefined
|
|
|
|
objOp.getVertsUsingEdge obj edgeList
|
|
),
|
|
|
|
fn _getEdgesUsingFace obj faceIdx =
|
|
(
|
|
local objOp = RsMeshPolyOp obj
|
|
if (objOp == undefined) do return undefined
|
|
|
|
objOp.getEdgesUsingFace obj faceIdx
|
|
),
|
|
|
|
fn _setEdgeSelection obj edgeList =
|
|
(
|
|
case (classOf obj) of
|
|
(
|
|
Editable_Poly:(polyop.setEdgeSelection obj edgeList)
|
|
Editable_Mesh:(setEdgeSelection obj edgeList)
|
|
)
|
|
),
|
|
|
|
fn _getEdgeSelection obj =
|
|
(
|
|
case (classOf obj) of
|
|
(
|
|
Editable_Poly:(polyop.getEdgeSelection obj)
|
|
Editable_Mesh:(getEdgeSelection obj)
|
|
)
|
|
),
|
|
|
|
public
|
|
|
|
--------------------------------------
|
|
-- SUBOBJECT CONVERSION --
|
|
--------------------------------------
|
|
fn convertMapVertsToGeom obj chan vertNums =
|
|
(
|
|
vertNums = (vertNums as bitArray)
|
|
|
|
local objGetMapFace = RsGetMapFaceFunc obj
|
|
local objGetFace = RsGetFaceFunc obj
|
|
|
|
local faceCount = obj.numFaces
|
|
local polyVerts = for faceNum = 1 to faceCount collect (objGetFace obj faceNum)
|
|
local polyBitVerts = for item in polyVerts collect (item as bitArray)
|
|
|
|
local retVal = #{}
|
|
retVal.count = obj.numVerts
|
|
|
|
for faceNum = 1 to faceCount do
|
|
(
|
|
local mapFaceVerts = objGetMapFace obj chan faceNum
|
|
local usedMapFaceVerts = (vertNums * (mapFaceVerts as bitArray))
|
|
|
|
-- Bitarray will overlap with vertNums if face includes some of its verts:
|
|
if (usedMapFaceVerts.numberSet != 0) do
|
|
(
|
|
local geomFaceVerts = (objGetFace obj faceNum)
|
|
|
|
for vertIdx = 1 to mapFaceVerts.count do
|
|
(
|
|
local mapVertNum = mapFaceVerts[vertIdx]
|
|
|
|
if usedMapFaceVerts[mapVertNum] do
|
|
(
|
|
local geomVertNum = geomFaceVerts[vertIdx]
|
|
retVal[geomVertNum] = True
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
return retVal
|
|
),
|
|
|
|
fn getMaterialIds obj = (
|
|
if obj != undefined then (
|
|
local faces = #()
|
|
|
|
if ( classOf obj == Editable_Mesh ) then (
|
|
local numFaces = meshop.getNumFaces obj
|
|
|
|
for idx = 1 to numFaces do (
|
|
local faceMatId = getFaceMatId obj idx
|
|
|
|
if faceMatId != undefined do (
|
|
appendIfUnique faces faceMatId
|
|
)
|
|
)
|
|
|
|
) else if ( classof obj == Editable_Poly ) then (
|
|
local numFaces = polyOp.getNumFaces obj
|
|
|
|
for idx = 1 to numFaces do (
|
|
local faceMatId = polyop.getFaceMatId obj idx
|
|
|
|
if faceMatId != undefined do (
|
|
appendIfUnique faces faceMatId
|
|
)
|
|
)
|
|
)
|
|
|
|
sort faces
|
|
faces
|
|
)
|
|
),
|
|
|
|
fn getFacesUsingMaterialId obj matId = (
|
|
local faces = #()
|
|
|
|
if ( classOf obj == Editable_Mesh ) then (
|
|
local numFaces = meshop.getNumFaces obj
|
|
|
|
for idx = 1 to numFaces do (
|
|
local faceMatId = getFaceMatId obj idx
|
|
if faceMatId == matId then append faces idx
|
|
)
|
|
|
|
) else if ( classof obj == Editable_Poly ) then (
|
|
local numFaces = polyOp.getNumFaces obj
|
|
|
|
for idx = 1 to numFaces do (
|
|
local faceMatId = polyop.getFaceMatId obj idx
|
|
if faceMatId == matId then append faces idx
|
|
)
|
|
)
|
|
|
|
faces
|
|
),
|
|
|
|
fn growSelectionByMatId obj matId:undefined = (
|
|
-- Hayes: This code is from '\wildwest\script\max\rockstar_north\growSelectMatID.ms'
|
|
|
|
if ( classOf obj == Editable_Poly ) then (
|
|
|
|
local faces = #{}
|
|
|
|
local aSel = #()
|
|
local aBorder = #()
|
|
local aChecked = #()
|
|
|
|
sel = polyop.getFaceSelection obj
|
|
|
|
sel = sel as array
|
|
append aChecked sel[1]
|
|
|
|
--??what if you have faces with various matID selected at first??
|
|
--first add this selection to the final aSel array and get the matID for testing with
|
|
local selMatID = undefined
|
|
|
|
if matId != undefined then (
|
|
selMatID = matId
|
|
) else (
|
|
selMatID = polyop.getFaceMatID obj sel[1]
|
|
)
|
|
|
|
aSel = for item in sel where polyop.getFaceMatID obj item == selMatID collect item
|
|
--append aSel sel[1]
|
|
|
|
--Find the faces connected to this face
|
|
faceEdges = #()
|
|
for item in aSel do
|
|
(
|
|
edges = polyop.getFaceEdges obj item
|
|
join faceEdges edges
|
|
)
|
|
|
|
--faces from those faceEdges
|
|
connFaces = polyop.getFacesUsingEdge obj faceEdges
|
|
--set the first border faces
|
|
aBorder = connFaces as array
|
|
|
|
aMatch = #()
|
|
do
|
|
(
|
|
--fvFaces = #()
|
|
aNewBorder = #()
|
|
for f in aBorder do
|
|
(
|
|
--test this face for a match
|
|
if polyop.getFaceMatID obj f == selMatID then
|
|
(
|
|
--this face is the right matID so add it to the match array
|
|
append aMatch f
|
|
|
|
--Find the faces connected to this face
|
|
borderFaceEdges = polyop.getFaceEdges obj f
|
|
edgeFaces = polyop.getFacesUsingEdge obj borderFaceEdges
|
|
|
|
appendIfUnique aChecked f
|
|
--test if they've already been checked - or remove the already aSel values from this new array
|
|
aTesting = (edgeFaces - aChecked as BitArray ) as array
|
|
--the tested ones to checked
|
|
join aChecked aTesting
|
|
|
|
--check which if any are the same matID
|
|
aBorderMatch = for item in aTesting where polyop.getFaceMatID obj item == selMatID collect item
|
|
|
|
--Add the new mtahcing matID faces to the match array
|
|
join aMatch aBorderMatch
|
|
|
|
--add matching matID faces to new border
|
|
join aNewBorder aBorderMatch
|
|
)
|
|
)
|
|
--strip out duplicate array entries
|
|
aNewBorder = makeUniqueArray aNewBorder
|
|
--aMatch = makeUniqueArray aMatch
|
|
--ones that are the same add to aSel
|
|
join aSel aMatch
|
|
|
|
--the new border to check is the one we found
|
|
aBorder = aNewBorder
|
|
)
|
|
while aNewBorder.count > 0
|
|
|
|
--selectFaces on the model
|
|
obj.selectedFaces = aSel
|
|
|
|
faces = _getFaceSelection obj
|
|
faces
|
|
)
|
|
),
|
|
|
|
fn getBorderEdgesUsingMaterialId obj matId selectAllBorders:false = (
|
|
|
|
-- Collect all faces using the supplied material id.
|
|
local faces = #{}
|
|
|
|
if selectAllBorders == true then (
|
|
faces = getFacesUsingMaterialId obj matId
|
|
) else (
|
|
faces = growSelectionByMatId obj matId:matId
|
|
)
|
|
|
|
-- Select faces using the supplied material id.
|
|
_setFaceSelection obj faces
|
|
|
|
-- Collect all of the selected faces.
|
|
local materialFaces = _getFaceSelection obj
|
|
|
|
-- Now select every edge using the material faces.
|
|
_setEdgeSelection obj ( _getEdgesUsingFace obj materialFaces )
|
|
|
|
-- Keep track of which edges to remove.
|
|
local edgesToRemove = #{}
|
|
|
|
-- Collect all edges using the material faces.
|
|
local borderEdges = _getEdgeSelection obj
|
|
|
|
local objOp = RsMeshPolyOp obj
|
|
local objGetFaceMatID = RsGetFaceMatIDFunc obj
|
|
|
|
-- Iterate over each selected edge and determine if it is on the border. If not, deselect the edge.
|
|
for edgeIdx in borderEdges do (
|
|
local edgeFaces = ( objOp.getFacesUsingEdge obj #{ edgeIdx } ) as array
|
|
|
|
-- The faces on either side of this edge are using the same material id we are looking for. We don't
|
|
-- want this edge if it is.
|
|
local isInteriorEdge = false
|
|
|
|
-- The faces on either side of this edge are not the same material id we are looking for, so it
|
|
-- must be trying to connect island borders.
|
|
local isIslandEdge = false
|
|
|
|
local faceMatId1 = objGetFaceMatID obj edgeFaces[ 1 ]
|
|
|
|
if edgeFaces.count == 2 then (
|
|
local faceMatId2 = objGetFaceMatID obj edgeFaces[ 2 ]
|
|
|
|
if faceMatId1 == matId and faceMatId2 == matId then isInteriorEdge = true
|
|
if faceMatId1 != matId and faceMatId2 != matId then isIslandEdge = true
|
|
|
|
) else (
|
|
if faceMatId1 != matId then isIslandEdge = true
|
|
)
|
|
|
|
if isInteriorEdge or isIslandEdge then append edgesToRemove edgeIdx
|
|
)
|
|
|
|
borderEdges -= edgesToRemove
|
|
borderEdges
|
|
),
|
|
|
|
fn selectMaterialBorderVerts obj matId selectAllBorders:false = (
|
|
if obj != undefined do (
|
|
local borderEdges = getBorderEdgesUsingMaterialId obj matId selectAllBorders:selectAllBorders
|
|
|
|
if borderEdges.count > 0 do (
|
|
_setVertSelection obj ( _getVertsUsingEdge obj borderEdges )
|
|
|
|
subObjectLevel = 1
|
|
)
|
|
)
|
|
),
|
|
|
|
fn selectMaterialBorderEdges obj matId selectAllBorders:false = (
|
|
if obj != undefined do (
|
|
local borderEdges = getBorderEdgesUsingMaterialId obj matId selectAllBorders:selectAllBorders
|
|
|
|
if borderEdges.count > 0 do (
|
|
_setEdgeSelection obj borderEdges
|
|
|
|
subObjectLevel = 2
|
|
)
|
|
)
|
|
),
|
|
|
|
fn selectMaterialBorderFromFaceSelection obj type:#edges selectAllBorders:false = (
|
|
if obj != undefined do (
|
|
local selectedFaces = _getFaceSelection obj
|
|
|
|
if selectedFaces.count > 0 do (
|
|
local matIds = #()
|
|
|
|
local objOp = (RsMeshPolyOp obj)
|
|
local objGetFaceMatID = RsGetFaceMatIDFunc obj
|
|
|
|
for faceIdx in selectedFaces do (
|
|
appendIfUnique matIds ( objGetFaceMatID obj faceIdx )
|
|
)
|
|
|
|
local borderEdges = #{}
|
|
|
|
for matId in matIds do (
|
|
local currentBorderEdges = getBorderEdgesUsingMaterialId obj matId selectAllBorders:selectAllBorders
|
|
join borderEdges currentBorderEdges
|
|
)
|
|
|
|
local edgesToRemove = #{}
|
|
|
|
-- The union of borderEdges will likely result in interior edges still being selected if more than one material id was selected.
|
|
-- Attempt to deal with this now.
|
|
for edgeIdx in borderEdges do (
|
|
local edgeFaces = ( objOp.getFacesUsingEdge obj #{ edgeIdx } ) as array
|
|
|
|
if edgeFaces.count == 2 then (
|
|
local faceMatId1 = objGetFaceMatID obj edgeFaces[ 1 ]
|
|
local faceMatId2 = objGetFaceMatID obj edgeFaces[ 2 ]
|
|
|
|
if ( findItem matIds faceMatId1 ) != 0 and ( findItem matIds faceMatId2 ) != 0 then append edgesToRemove edgeIdx
|
|
)
|
|
)
|
|
|
|
borderEdges -= edgesToRemove
|
|
|
|
if type == #edges then (
|
|
_setEdgeSelection obj borderEdges
|
|
subObjectLevel = 2
|
|
|
|
) else if type == #verts then (
|
|
local borderVerts = _getVertsUsingEdge obj borderEdges
|
|
_setVertSelection obj borderVerts
|
|
subObjectLevel = 1
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
fn randomlyDeselectVerts obj pct = (
|
|
if obj != undefined do (
|
|
local selectedVerts = _getVertSelection obj as array
|
|
|
|
if selectedVerts.count > 1 then (
|
|
subObjectLevel = 1
|
|
|
|
local numVertsToDeselect = ( selectedVerts.count * ( pct / 100 as float ) + 0.5 ) as integer
|
|
|
|
local vertsToDeselect = #()
|
|
local finished = false
|
|
local numIterations = 0
|
|
|
|
-- Attempt to avoid an infinite loop, to avoid losing work. Theoretically, iterating over the number of selected vertices
|
|
-- three times should be sufficient to hit the number of verts to remove.
|
|
local maxNumIterations = selectedVerts.count * 3
|
|
|
|
while not finished do (
|
|
|
|
-- Avoid infinite loop. Don't want anyone to lose work.
|
|
if numIterations >= maxNumIterations then finished = true
|
|
|
|
if vertsToDeselect.count == numVertsToDeselect then (
|
|
finished = true
|
|
|
|
) else (
|
|
local vertIdx = random 1 selectedVerts.count
|
|
|
|
if ( findItem vertsToDeselect selectedVerts[ vertIdx ] ) == 0 then (
|
|
append vertsToDeselect selectedVerts[ vertIdx ]
|
|
)
|
|
)
|
|
|
|
numIterations += 1
|
|
)
|
|
|
|
if vertsToDeselect.count != numVertsToDeselect do (
|
|
format "Selection Tools: Did not hit the required percentage of verts to deselect! Only deselected % out of %.\n" vertsToDeselect.count numVertsToDeselect
|
|
)
|
|
|
|
selectedVerts = selectedVerts as bitarray
|
|
vertsToDeselect = vertsToDeselect as bitarray
|
|
|
|
selectedVerts -= vertsToDeselect
|
|
|
|
_setVertSelection obj selectedVerts
|
|
) else (
|
|
messageBox "Please select more than 1 vertex!" title:"R* Selection Tools"
|
|
)
|
|
)
|
|
),
|
|
|
|
fn snapVertsToTarget objA objB tolerance:0.05 =
|
|
(
|
|
-- Hayes: This code is from '\wildwest\script\max\rockstar_north\maps\sm_snap_verts.ms'
|
|
|
|
--Get exterior vertices
|
|
OpenEdges = polyOp.getOpenEdges objA
|
|
srcVerts = (polyOp.getVertsUsingEdge objA OpenEdges) as array
|
|
OpenEdges = polyOp.getOpenEdges objB
|
|
tarVerts = (polyOp.getVertsUsingEdge objB OpenEdges) as array
|
|
|
|
SrcNumVerts = srcVerts.count
|
|
TarNumVerts = tarVerts.count
|
|
|
|
For x=1 to TarNumVerts do
|
|
(
|
|
--get vert
|
|
tv = polyOp.getvert objB tarVerts[x]
|
|
rv = polyOp.getvert objA srcVerts[1]
|
|
|
|
targetVertDist = tolerance * tolerance
|
|
|
|
For i=1 to SrcNumVerts do (
|
|
try ( rv = getvert objA srcVerts[i] ) catch ( rv = polyOp.getvert objA srcVerts[i] )
|
|
dist = (tv.x - rv.x) * (tv.x - rv.x) + (tv.y - rv.y) * (tv.y - rv.y) + (tv.z - rv.z) * (tv.z - rv.z)
|
|
|
|
if dist < targetVertDist then (
|
|
polyOp.setVert objB tarVerts[x] rv
|
|
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
fn snapVertsToMidpoint objA objB tolerance:0.05 =
|
|
(
|
|
-- Hayes: This code is from '\wildwest\script\max\rockstar_north\maps\sm_snap_verts.ms'
|
|
|
|
--Get exterior vertices
|
|
OpenEdges = polyOp.getOpenEdges objA
|
|
srcVerts = (polyOp.getVertsUsingEdge objA OpenEdges) as array
|
|
OpenEdges = polyOp.getOpenEdges objB
|
|
tarVerts = (polyOp.getVertsUsingEdge objB OpenEdges) as array
|
|
|
|
SrcNumVerts = srcVerts.count
|
|
TarNumVerts = tarVerts.count
|
|
|
|
For x=1 to TarNumVerts do
|
|
(
|
|
--get vert
|
|
tv = polyOp.getvert objB tarVerts[x]
|
|
rv = polyOp.getvert objA srcVerts[1]
|
|
|
|
targetVertDist = tolerance * tolerance
|
|
|
|
For i=1 to SrcNumVerts do (
|
|
|
|
try ( rv = getvert objA srcVerts[i] ) catch ( rv = polyOp.getvert objA srcVerts[i] )
|
|
dist = (tv.x - rv.x) * (tv.x - rv.x) + (tv.y - rv.y) * (tv.y - rv.y) + (tv.z - rv.z) * (tv.z - rv.z)
|
|
|
|
if dist < targetVertDist then (
|
|
newpos = [0, 0, 0]
|
|
newpos.x = (tv.x + rv.x)/2
|
|
newpos.y = (tv.y + rv.y)/2
|
|
newpos.z = (tv.z + rv.z)/2
|
|
|
|
polyOp.setVert objB tarVerts[x] newpos
|
|
polyOp.setVert objA srcVerts[i] newpos
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
fn storeVertexPositions selObj =
|
|
(
|
|
-- Hayes: This code is from '\wildwest\script\3dsmax\maps\mesh_edits\reset_vert_position.ms'
|
|
|
|
storedVertPositions =#()
|
|
|
|
select selObj
|
|
max modify mode
|
|
modPanel.setCurrentObject selection[1].baseObject
|
|
|
|
-- detect Edge or Border selection
|
|
local vertSelection = undefined
|
|
|
|
if ( subobjectlevel == 1 ) then
|
|
(
|
|
vertSelection = true
|
|
)
|
|
|
|
if ( subobjectlevel == 2 or subobjectlevel == 3 ) then
|
|
(
|
|
vertSelection = false
|
|
)
|
|
|
|
edgeList = #()
|
|
vertList = #()
|
|
|
|
if ( vertSelection == false ) then
|
|
(
|
|
edgeList = polyop.getEdgeSelection selection[1]
|
|
vertList = (polyop.getVertsUsingEdge selection[1] edgeList) as array
|
|
)
|
|
else
|
|
(
|
|
vertList = (selection[1].GetSelection #Vertex ) as array
|
|
)
|
|
|
|
|
|
if (vertList.count < 1) do
|
|
(
|
|
MessageBox "Nothing selected - you need to select either edges or verts"
|
|
return false
|
|
)
|
|
|
|
-- Store these vert positions
|
|
SelectedVertData =#()
|
|
for v = 1 to vertList.count do
|
|
(
|
|
VertData =#()
|
|
append VertData vertList[v]
|
|
append VertData (polyop.getvert $ vertList[v])
|
|
append SelectedVertData VertData
|
|
)
|
|
|
|
-- Append this vert data to the main store
|
|
for vd = 1 to SelectedVertData.count do
|
|
(
|
|
append storedVertPositions SelectedVertData[vd]
|
|
)
|
|
),
|
|
|
|
fn restoreVertexPositions selObj =
|
|
(
|
|
-- Hayes: This code is from '\wildwest\script\3dsmax\maps\mesh_edits\reset_vert_position.ms'
|
|
|
|
select selObj
|
|
|
|
max modify mode
|
|
modPanel.setCurrentObject selection[1].baseObject
|
|
|
|
subobjectlevel == 1
|
|
|
|
-- Loop through the stored verts
|
|
for svd = 1 to storedVertPositions.count do
|
|
(
|
|
-- Read the stored data
|
|
theVertnumber = storedVertPositions[svd][1]
|
|
theVertPosition = storedVertPositions[svd][2]
|
|
|
|
-- Set the vert back to the original position
|
|
polyop.setvert $ theVertnumber theVertPosition
|
|
)
|
|
),
|
|
|
|
fn convertMapVertSelectionToMeshVertSelection obj =
|
|
(
|
|
if (isEditPolyMesh obj) then
|
|
(
|
|
local uvMod
|
|
for thisMod in obj.modifiers while (uvMod == undefined) do
|
|
(
|
|
if (isKindOf thisMod Unwrap_UVW) do
|
|
(
|
|
uvMod = thisMod
|
|
)
|
|
)
|
|
|
|
if (uvMod != undefined) then
|
|
(
|
|
local selectedMapVerts = uvMod.getSelectedVertices()
|
|
|
|
local mapChannel = ( uvmod.getMapChannel() + 1 ) --Unlike just about everything else in MXS that is 1-based, Autodesk decided to make this return a 0-based integer.
|
|
|
|
local geomVerts = convertMapVertsToGeom obj mapChannel selectedMapVerts
|
|
|
|
modPanel.setCurrentObject obj.baseObject
|
|
subObjectLevel = 1
|
|
|
|
_setVertSelection obj geomVerts
|
|
)
|
|
else
|
|
(
|
|
messageBox "You must have a 'Unwrap UVW' modifier applied to the selected object!" title:"Rockstar"
|
|
)
|
|
)
|
|
else
|
|
(
|
|
messageBox "You must have an object selected!" title:"Rockstar"
|
|
)
|
|
),
|
|
|
|
fn getFacesByArea obj sizeLimit inverted:False =
|
|
(
|
|
local objOp = (RsMeshPolyOp obj)
|
|
if (objOp == undefined) do
|
|
return Undefined
|
|
|
|
local numFaces = objOp.getNumFaces obj
|
|
local outFaces = #{}
|
|
outFaces.count = numFaces
|
|
|
|
for faceNum = 1 to numFaces do
|
|
(
|
|
local faceArea = objOp.getFaceArea obj faceNum
|
|
|
|
if (faceArea <= sizeLimit) do
|
|
outFaces[faceNum] = True
|
|
)
|
|
|
|
return outFaces
|
|
),
|
|
|
|
-- Returns list of faces on obj for elements where all dimensions are smaller than sizeLimit:
|
|
fn GetFacesByElemSize obj sizeLimit node: showProgress:True inverted:False =
|
|
(
|
|
local objOp = RsMeshPolyOp obj
|
|
|
|
-- Only return values for poly/mesh objects:
|
|
if (objOp == undefined) do
|
|
return Undefined
|
|
|
|
if (node == Unsupplied) do
|
|
node = obj
|
|
|
|
local vertCount = objOp.GetNumVerts obj
|
|
local faceCount = objOp.GetNumFaces obj
|
|
|
|
local getFaces = #{}
|
|
getFaces.count = faceCount
|
|
|
|
if showProgress do
|
|
(
|
|
progressStart "Finding small elements..."
|
|
progressUpdate (1.0)
|
|
)
|
|
|
|
local success = True
|
|
local doneFaces = #{}
|
|
doneFaces.count = faceCount
|
|
|
|
for faceNum = 1 to faceCount where (not doneFaces[faceNum]) while (success = progressUpdate (100.0 * faceNum / faceCount)) do
|
|
(
|
|
-- Get element-faces:
|
|
local elemFaces = objOp.getElementsUsingFace obj #{faceNum}
|
|
doneFaces += elemFaces
|
|
|
|
-- Get verts using element-faces:
|
|
local elemVerts = (objOp.getVertsUsingFace obj elemFaces)
|
|
|
|
-- Mark element-faces for deletion if their bounding-box is too small:
|
|
(
|
|
local elemVertPosList = (for vertNum = elemVerts collect (objOp.getVert obj vertNum))
|
|
local elemBox = RsFindMinBox elemVertPosList node:node
|
|
|
|
local boxDims = [elemBox.width, elemBox.length, elemBox.height]
|
|
|
|
local smallElem = True
|
|
for n = 1 to 3 while smallElem do
|
|
(
|
|
smallElem = (boxDims[n] < sizeLimit)
|
|
)
|
|
|
|
-- Mark faces for deletion if box was too small:
|
|
if smallElem do
|
|
(
|
|
getFaces += elemFaces
|
|
)
|
|
)
|
|
)
|
|
|
|
if showProgress do
|
|
ProgressEnd()
|
|
|
|
-- Return False if cancelled
|
|
if not success do
|
|
return False
|
|
|
|
return getFaces
|
|
),
|
|
|
|
-- Select faces on chosen nodes that are returned by 'FindFacesFunc'
|
|
-- If a selection-modifier is added, it will be named 'modName'
|
|
fn SelObjFaces FindFacesFunc objs: params:#() inverted:False modName:"Poly Select" =
|
|
(
|
|
-- Get suitable nodes from selection
|
|
if (objs == Unsupplied) do
|
|
objs = Selection
|
|
|
|
objs = for obj in objs where (IsEditPolyMesh obj) collect obj
|
|
|
|
if (objs.count == 0) do
|
|
return OK
|
|
|
|
undo "Select Faces" on
|
|
(
|
|
-- Get existing matching selection-modifier(s)
|
|
local selMods = MakeUniqueArray (for thisNode in objs collect thisNode.modifiers[modName])
|
|
selMods = for item in selMods where (item != Undefined) collect item
|
|
|
|
-- Reuse selection-modifier if a matching one (and only one) was found
|
|
local selMod = Undefined
|
|
if (selMods.count == 1) do
|
|
(
|
|
selMod = selMods[1]
|
|
|
|
-- We only want to use this modifier if it's the topmost modifier for the nodes that use it
|
|
-- (otherwise we can't show that specific modifier for multiple nodes)
|
|
for thisNode in objs while (selMod != Undefined) do
|
|
(
|
|
-- 'modIdx' will be 0 if missing, or 1 if it's at top of list
|
|
local modIdx = FindItem thisNode.modifiers selMod
|
|
if (modIdx > 1) do
|
|
selMod = Undefined
|
|
)
|
|
)
|
|
|
|
-- Create new selection-modifier if valid existing one wasn't found
|
|
if (objs.count > 1) and (selMod == Undefined) do
|
|
selMod = Poly_Select name:modName
|
|
|
|
if (GetCommandPanelTaskMode() != #Modify) do
|
|
(SetCommandPanelTaskMode #Modify)
|
|
|
|
-- Collect total number of found faces
|
|
local foundFacesCount = 0
|
|
|
|
fn _RunFindFacesFunc inObj inNode Func params inverted =
|
|
(
|
|
local outFaces = Undefined
|
|
case params.count of
|
|
(
|
|
0:(outFaces = Func inObj node:inNode)
|
|
1:(outFaces= Func inObj params[1] node:inNode)
|
|
Default:(Throw (params.count as String) + "params are not supported yet. You'll wanna fix that here!")
|
|
)
|
|
|
|
if inverted and (IsKindOf outFaces BitArray) do
|
|
outFaces = -outFaces
|
|
|
|
return outFaces
|
|
)
|
|
|
|
if (selMod == Undefined) then
|
|
(
|
|
-- SINGLE-NODE FACE-SELECTION (NO MODIFIER)
|
|
PushPrompt "Finding Faces..."
|
|
SetWaitCursor()
|
|
|
|
-- Get matching faces on baseObject (i.e. under any modifiers)
|
|
local thisNode = objs[1]
|
|
local baseObj = thisNode.baseObject
|
|
local foundFaces = _RunFindFacesFunc baseObj thisNode FindFacesFunc params inverted
|
|
|
|
if (not IsKindOf foundFaces BitArray) then
|
|
(
|
|
-- If function was cancelled
|
|
if (foundFaces == Face) do
|
|
success = False
|
|
)
|
|
else
|
|
(
|
|
-- Show baseObject, in Face mode
|
|
Select thisNode
|
|
ModPanel.SetCurrentObject baseObj node:thisNode
|
|
SetSelectionLevel baseObj #Face
|
|
SetFaceSelection thisNode foundFaces
|
|
Update thisNode
|
|
|
|
foundFacesCount += foundFaces.numberSet
|
|
)
|
|
|
|
SetArrowCursor()
|
|
PopPrompt()
|
|
)
|
|
else
|
|
(
|
|
-- FACE-SELECTION USING MODIFIER
|
|
|
|
-- Add selection-modifier to objects that don't have it yet
|
|
local addModNodes = for thisNode in objs where (FindItem thisNode.modifiers selMod == 0) collect thisNode
|
|
AddModifier addModNodes selMod
|
|
Select objs
|
|
|
|
-- Set face-selection in modifier for all nodes
|
|
ProgressStart "Finding Faces..."
|
|
local success = True
|
|
for nodeNum = 1 to objs.count while (success = ProgressUpdate (100 * nodeNum / objs.count)) do
|
|
(
|
|
local thisNode = objs[nodeNum]
|
|
|
|
-- Get faces-selection from a temp collapsed copy of object
|
|
undo off
|
|
(
|
|
local tempNode = (Copy thisNode)
|
|
tempNode.name = ("TEMPCOPY_" + thisNode.name)
|
|
ConvertToPoly tempNode
|
|
local foundFaces = _RunFindFacesFunc tempNode tempNode FindFacesFunc params inverted
|
|
Delete tempNode
|
|
)
|
|
|
|
if (foundFaces == False) then
|
|
(
|
|
success = False
|
|
)
|
|
else if (IsKindOf foundFaces BitArray) do
|
|
(
|
|
SetFaceSelection thisNode selMod foundFaces
|
|
foundFacesCount += foundFaces.numberSet
|
|
)
|
|
)
|
|
ProgressEnd()
|
|
|
|
-- Show modifier, which will be at top of all nodes' stacks
|
|
SetSelectionLevel selMod #Face
|
|
)
|
|
)
|
|
|
|
-- Print results, and briefly show them in status-prompt
|
|
local promptMsg = ((foundFacesCount as String) + " faces selected")
|
|
Format "%\n" promptMsg
|
|
DisplayTempPrompt promptMsg 5000
|
|
|
|
return OK
|
|
),
|
|
|
|
fn SelectFacesBySize inObjs sizeLimit elements:False inverted:False =
|
|
(
|
|
local FindFacesFunc = if elements then this.GetFacesByElemSize else this.GetFacesByArea
|
|
|
|
this.SelObjFaces FindFacesFunc objs:Selection params:#(sizeLimit) inverted:inverted
|
|
|
|
return OK
|
|
)
|
|
)
|
|
global gRsSelectionTools = RsSelectionToolsStruct() |