Notifications
Clear all

[Closed] Detach Specific Parts Of Object

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

1 Reply
(@gazybara)
Joined: 10 months ago

Posts: 0

This would be the right conditions for sure

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

1 Reply
(@gazybara)
Joined: 10 months ago

Posts: 0

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
	)
)
1 Reply
(@gazybara)
Joined: 10 months ago

Posts: 0

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.

1 Reply
(@polytools3d)
Joined: 10 months ago

Posts: 0

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.

I’ll have a solution for that before the year’s end.

Page 2 / 3