PDA

View Full Version : select polys by angle function?


Gravey
04-13-2009, 04:47 AM
is there a maxscript function to select polys in and Editable_Poly by angle like using the interface. Ideally it would work something like:
getFacesByAngle <integer>faceIndex <float>angleThreshold

does it exist and I just can't find it in the reference?

SyncViewS
04-13-2009, 10:35 AM
Hi Joel,
the following function selects every face in an Editable Poly whose normal is within the specified angle threshold expressed in degrees. It returns a BitArray with bit set for matching faces. It doesn't consider continuity between faces, so there could be separated groups. To do that would require a littler more effort and a bit slower algorithm. If you plan to use this multiple times on a fixed selection, like varying the threshold with a spinner to see effects in realtime, it would be better to fill an array with face normals and then perform test on stored values rather than querying the Editable Poly each time.

Uhm... I just realized I didn't look in the MaxScript reference.

function getFacesByAngle oPoly iFace fDegThresh =
(
if ((classOf oPoly) != Editable_Poly) then
throw "Wrong input in function getFacesByAngle() - Editable Poly"

if ((classOf iFace) != Integer) then
throw "Wrong input in function getFacesByAngle() - Face Index"

if ( (iFace <= 0) or (iFace > (polyOp.getNumFaces oPoly)) ) then
throw "Wrong input in function getFacesByAngle() - Face Index out of boundaries"

if ( (classOf fDegThresh != Float) and (classOf fDegThresh != Integer) ) then
throw "Wrong input in function getFacesByAngle() - Angle Threshold"

-- I've become a little precautionary about errors,
-- remove all the previous if not necessary

local p3FaceNormal = polyOp.getFaceNormal oPoly iFace
local fTestDot = cos fDegThresh

local iNumFaces = polyOp.getNumFaces oPoly
local baSelFaces = #{1..iNumFaces}

for i = 1 to iNumFaces do
(
p3ItemNormal = polyOp.getFaceNormal oPoly i

if ((dot p3FaceNormal p3ItemNormal) < fTestDot) then
baSelFaces[i] = false
)

( -- just for visual feedback, remove if unneeded
polyOp.setFaceSelection oPoly baSelFaces
forceCompleteRedraw()
)

return baSelFaces
)
- Enrico

ZeBoxx2
04-13-2009, 10:45 AM
aw :\

fn getFacesByAngle obj faceIndex angleThreshold:10.0 ignoreBackfacing:true = (
local numFaces = obj.numFaces
local faceNormals = for i = 1 to numFaces collect (
polyOp.getFaceNormal obj i
)
local normalAround = faceNormals[faceIndex]
local angleDot = cos(angleThreshold)

local matchFaces
if (ignoreBackFacing) then (
matchFaces = for i = 1 to numFaces collect (
if ((dot normalAround faceNormals[i]) >= angleDot) then ( i )
else ( dontcollect )
)
)
else (
matchFaces = for i = 1 to numFaces collect (
if ((abs (dot normalAround faceNormals[i])) >= angleDot) then ( i )
else ( dontcollect )
)
)
)

SyncViewS
04-13-2009, 11:36 AM
Richard :D
just a bunch of ticks before you, but mine doesn't take into account backfacing, so it's a tie :beer:

ZeBoxx2
04-13-2009, 12:52 PM
hooray for backfacing (or lack thereof)! :beer:

Gravey
04-13-2009, 01:20 PM
thanks guys, that dot product thing is a better idea than what I was using (acos (dot normalize vec1 normalize vec2))

I was after something that does consider continuity between faces which also means backfacing is not required. I wrote this based off you're responses:fn getFacesByAngle obj faceIndex angleThreshold:20 restoreSelection:true =
(
local numFaces = obj.numfaces
local faceNormals = for i = 1 to numFaces collect polyOp.getFaceNormal obj i
local normalAround = faceNormals[faceIndex]
local angleDot = cos angleThreshold

local oldFaceSel = if restoreSelection then polyOp.getFaceSelection obj else undefined
local grow = obj.EditablePoly.GrowSelection
local matchFaces = #(faceIndex)
local oldCount = matchFaces.count
local notFinished = true

polyOp.setFaceSelection obj faceIndex
while notFinished do
(
if keyboard.escPressed do throw "*** ESCAPE KEY PRESSED ***" -- just in case (thanks Richard for this from another thread)
grow selLevel:#Face -- grow the face selection
matchFaces = (polyop.getFaceSelection obj) as array
matchFaces = for f in matchFaces where (dot normalAround faceNormals[f]) >= angleDot collect f

if matchFaces.count != oldCount then oldCount = matchFaces.count else notFinished = false
)

if restoreSelection do polyOp.setFaceSelection obj oldFaceSel

matchFaces
)

SyncViewS
04-13-2009, 02:52 PM
Hi Joel,
I just upgraded the function to take into account face contiguity. You can now choose between:

#none -> no contiguity limits
#byVert -> faces must be contiguous for (share) at least a vertex
#byEdge -> faces must be contiguous for (share) at least an edge

function getFacesByAngle oPoly iFace fDegThresh contig:#none =
(
if ((classOf oPoly) != Editable_Poly) then
throw "Wrong input in function getFacesByAngle() - Editable Poly"

if ((classOf iFace) != Integer) then
throw "Wrong input in function getFacesByAngle() - Face Index"

if ( (iFace <= 0) or (iFace > (polyOp.getNumFaces oPoly)) ) then
throw "Wrong input in function getFacesByAngle() - Face Index out of boundaries"

if ( (classOf fDegThresh != Float) and (classOf fDegThresh != Integer) ) then
throw "Wrong input in function getFacesByAngle() - Angle Threshold"

if ( (fDegThresh < 0) or (fDegThresh > 180) ) then
throw "Wrong input in function getFacesByAngle() - Angle Threshold out of boundaries"

-- remove all the previous test if not necessary

local p3FaceNormal = polyOp.getFaceNormal oPoly iFace
local fTestDot = cos fDegThresh

local iNumFaces = polyOp.getNumFaces oPoly

if (contig == #none) then
(
local baSelFaces = #{1..iNumFaces}

for i = 1 to iNumFaces do
(
p3ItemNormal = polyOp.getFaceNormal oPoly i

if ((dot p3FaceNormal p3ItemNormal) < fTestDot) then
baSelFaces[i] = false
)
)
else if (contig == #byVert) then
(
local baLimitVerts = #{}
local baLimitFaces = #{iFace}

local baSelFaces = #{iFace}
local baUnselFaces = #{}

while (baLimitFaces.numberSet > 0) do
(
baLimitVerts = (polyOp.getVertsUsingFace oPoly baSelFaces) - (polyOp.getVertsUsedOnlyByFaces oPoly baSelFaces)
baLimitFaces = (polyOp.getFacesUsingVert oPoly baLimitVerts) - baSelFaces - baUnselFaces

for item in baLimitFaces do
(
p3ItemNormal = polyOp.getFaceNormal oPoly item

if ((dot p3FaceNormal p3ItemNormal) >= fTestDot) then
(
baSelFaces[item] = true
)
else
(
baUnselFaces[item] = true
)
)
)
)
else if (contig == #byEdge) then
(
local iNumFaces = polyOp.getNumFaces oPoly

local baLimitVerts = #{}
local baLimitFaces = #{iFace}

local baSelFaces = #{iFace}
local baUnselFaces = #{}

local baEdgeSet01 = #{}
local baFaceSet01 = #{}
local baEdgeSet02 = #{}

while (baLimitFaces.numberSet > 0) do
(
baEdgeSet01 = polyOp.getEdgesUsingFace oPoly baSelFaces
baFaceSet01 = #{1..iNumFaces} - baSelFaces
baEdgeSet02 = polyOp.getEdgesUsingFace oPoly baFaceSet01

baLimitEdges = baEdgeSet01 * baEdgeSet02
baLimitFaces = (polyOp.getFacesUsingEdge oPoly baLimitEdges) - baSelFaces - baUnselFaces

for item in baLimitFaces do
(
p3ItemNormal = polyOp.getFaceNormal oPoly item

if ((dot p3FaceNormal p3ItemNormal) >= fTestDot) then
(
baSelFaces[item] = true
)
else
(
baUnselFaces[item] = true
)
)
)
)

( -- just for visual feedback, remove if unneeded
polyOp.setFaceSelection oPoly baSelFaces
forceCompleteRedraw()
)

return baSelFaces
)
- Enrico

Gravey
04-15-2009, 12:33 AM
Thanks Enrico

Your #byVertex method is nice and short and works correctly although I dont quite understand why... The method I posted sometimes returns some odd results so i'm using yours. Thanks again

CGTalk Moderation
04-15-2009, 12:33 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.