because a wonder can’t happen let’s do all step-by-step…
#1
find sets of edges corresponding to every cut.
what criteria are?
#1 selected
#2 opened
#3 lays in the same plane
OK…
#1 and #2 is easy.
for #3 we need edge vector and group it with parallel
This FILE is not cutted version. Open the file and run code below
fn cutMesh mesh nodes = with redraw off
(
clearSelection() ; hwnd = undefined
if GetCommandPanelTaskMode() != #modify do SetCommandPanelTaskMode #modify
node = ProBoolean ; mesh = snapshot mesh
object = Editable_Mesh pos:[0,0,0] wirecolor:yellow name:"Cards"
for i in nodes do attach object (snapshotasmesh i) ; nodes = #() --; update object
node.createBooleanObject mesh undefined 4 2 0 ; select mesh
node.SetImprint mesh on
node.SetPlanarEdgeRemoval mesh 2
-- press "Change operation" button to refresh current operation
for c in (windows.getChildrenHWND #max) while hwnd == undefined where c[4] == "RollupPanelTitle" and c[5] == "Parameters" do
(
hwnd = UIAccessor.GetParentWindow c[1]
)
if hwnd != undefined do
(
node.SetOperandSel mesh 0 on
if (bt = windows.getChildHWND hwnd "Change Operation") != undefined do UIAccessor.PressButton bt[1]
)
node.SetBoolOp mesh 2
node.SetOperandB mesh object 2 0
SetCommandPanelTaskMode #modify
node = converttopoly mesh
node.wirecolor = black
polyop.splitEdges node (polyOp.getedgeselection node)
polyop.collapseDeadStructs node
polyop.deleteIsoVerts node
free nodes ; gc light:on ; node
)
obj = cutMesh $Snake ($Plane* as array)
move obj [0,0,50]
SetCommandPanelTaskMode #modify
subobjectLevel = 2
We have Cut Planes and these direction can be used as a vector
in this case it’s easier. we only need to group edges by nearest plane (distance to plane from edge vert(s))
Maybe I’m wrong but despite having a lot of bugs, ProBoolean is solid solution for this example.
I used “Attach (no interpolations)” method for first operand A to preserve other elements and for 2nd operand “Substraction” and “Imprint”. But in max2014 everything works fine and in max2017 hmmm… not
Edit: this part of above code not works in max2017. I don’t know why can’t find “Parameter” rollout and press “Change Operation” button.
for c in (windows.getChildrenHWND #max) while hwnd == undefined where c[4] == "RollupPanelTitle" and c[5] == "Parameters" do
(
hwnd = UIAccessor.GetParentWindow c[1]
)
if hwnd != undefined do
(
node.SetOperandSel mesh 0 on
if (bt = windows.getChildHWND hwnd "Change Operation") != undefined do UIAccessor.PressButton bt[1]
)
after that extend every group to element…
but we will get some unselected elements… they might not intersect at all. so we have find some criteria by which add these elements to one of detached groups. i am thinking about distance. it’s not fast, but can be optimized
That’s what I thought at first. Probably is the best solution for now but I don’t know if we can use this for every situation. Let say we have model of the hand and we need cut fingers place Slice Planes are placed on every joint.
Here we go. Ugly and slow but seems to work with the model you uploaded. Needs to be optimized, a lot.
(
gc()
with undo off
(
offset = 7
tmesh = mesh mesh:(snapshotasmesh $)
edges = getedgeselection tmesh
faces = #{}
for j = 1 to tmesh.numfaces where getfacematid tmesh j == 7 do faces[j] = true
masterElements = #()
for j in faces do
(
element = meshop.getelementsusingface tmesh j
append masterElements element
for i in element do deleteitem faces i
)
for j in masterElements do
(
intersectedFaces = #{}
for i in j do
(
normal = -(getfacenormal tmesh i)
center = meshop.getfacecenter tmesh i
pos = center - (offset * normal)
r = ray pos normal
intersect = intersectRayEx tmesh r
if intersect != undefined do intersectedFaces[intersect[2]] = true
)
join j intersectedFaces
)
for j in masterElements do
(
verts = meshop.getvertsusingface tmesh j
polys = polyop.getfacesusingvert $ verts
element = polyop.getelementsusingface $ polys
polyop.detachFaces $ element delete:false asNode:true
)
delete tmesh
format "ELEMENTS: %
" masterElements.count
)
)
It works! Thanks “a lot”.
I placed just polyOp and meshOp in local vars for the start. Also trying to find way to fix max2017 bug for previous “cutMesh” function
(
gc()
with undo off
(
offset = 7 ; obj = $
tmesh = mesh mesh:(snapshotasmesh obj)
edges = getedgeselection tmesh
local getElementsUsingFaceMesh = meshop.getelementsusingface
local getElementsUsingFacePoly = polyop.getelementsusingface
local getFaceCenter = meshop.getfacecenter
local getVertsUsingFace = meshop.getvertsusingface
local getFacesUsingVert = polyop.getfacesusingvert
local detachFaces = polyop.detachFaces
local faces = #{}, masterElements = #()
for j = 1 to tmesh.numfaces where getfacematid tmesh j == 7 do faces[j] = true
for j in faces do
(
element = getElementsUsingFaceMesh tmesh j
append masterElements element
for i in element do deleteitem faces i
)
for j in masterElements do
(
intersectedFaces = #{}
for i in j do
(
normal = -(getfacenormal tmesh i)
center = getFaceCenter tmesh i
pos = center - (offset * normal)
r = ray pos normal
intersect = intersectRayEx tmesh r
if intersect != undefined do intersectedFaces[intersect[2]] = true
)
join j intersectedFaces
)
for j in masterElements do
(
verts = getVertsUsingFace tmesh j
polys = getFacesUsingVert obj verts
element = getElementsUsingFacePoly obj polys
detachFaces obj element delete:false asNode:true
)
delete tmesh
format "ELEMENTS: %
" masterElements.count
)
)
Hmm… but what if we clear all material id’s and smoothing groups and try this on the clean mesh with multiple elements? Don’t get me wrong your solution is awesome I just thinking out loud.
Every algorithm must follow a set of rules. If the rules are changed, the algorithm must be changed.
Depending on how wide the different scenarios might be, a generic algorithm can or cannot be developed.
For this new case you propose, and for the specific model you uploaded, we can see that the area of the central pipe is the largest one, so we can use it to find the different groups of elements.
Here is a modified version that should work as well if you clean up all the materials IDs and Smoothing Groups.
(
gc()
with undo off
(
offset = 7
tmesh = mesh mesh:(snapshotasmesh $)
edges = getedgeselection tmesh
/* NEW -----------------------------------------------*/
tmesh2 = copy tmesh
openedges = meshop.getopenedges tmesh2
openverts = meshop.getvertsusingedge tmesh2 openedges
meshop.weldvertsbythreshold tmesh2 openverts 0.0001
update tmesh2
allFaces = #{1..tmesh2.numfaces}
largestArea = 0
faces = #{}
for j in allFaces do
(
element = meshop.getelementsusingface tmesh2 j
area = meshop.getfacearea tmesh2 element
if area > largestArea do
(
largestArea = area
faces = element
)
for i in element do deleteitem allFaces i
)
delete tmesh2
/* NEW -----------------------------------------------*/
masterElements = #()
for j in faces do
(
element = meshop.getelementsusingface tmesh j
append masterElements element
for i in element do deleteitem faces i
)
for j in masterElements do
(
intersectedFaces = #{}
for i in j do
(
normal = -(getfacenormal tmesh i)
center = meshop.getfacecenter tmesh i
pos = center - (offset * normal)
r = ray pos normal
intersect = intersectRayEx tmesh r
if intersect != undefined do intersectedFaces[intersect[2]] = true
)
join j intersectedFaces
)
for j in masterElements do
(
verts = meshop.getvertsusingface tmesh j
polys = polyop.getfacesusingvert $ verts
element = polyop.getelementsusingface $ polys
polyop.detachFaces $ element delete:false asNode:true
)
delete tmesh
format "ELEMENTS: %
" masterElements.count
)
)
Again thanks Jorge I really appreciate all your hard work. First time in the morning I will check your code.
I must sleep. It’s (4AM) in my country
Cheers!
You’re very welcome Branko. Please note that the purpose of the code I proposed is to solve this very specific task you described in a quick way.
It is by no means a smart, clever or the best (if the best exists) way of approaching a more generic situation. It is indeed a quite bad approach, but if all you need is to get the job done, it may help.