Notifications
Clear all

[Closed] How to find inner contour of an object?

I have a code which performs 2d shape intersection, so those objects can be excluded,
Are you still not using convertToPoly/Mesh?

Yes, I do not cenvert them. I just converted them to poly for the image.

Check your PM.

add finally with full undo…

I generate a mesh geometry first… but it all takes about 2 secs to generate both mesh and spline “floor plan”

there are two open shapes (lines**) in the source scene, I have to delete it them from convertion… also there are several shapes on deferent Z levels. I set them all on one…

the snap is not perferct sometimes, and I double check ‘snapping’.

I do everything on-the-fly, so it needs only load the file and the scene has to have splineshapes for convertion. I suggest to put all used shapes in special layer.

Here is what I have:

(
	
		poGetEdgeVerts = polyop.getEdgeVerts
		poGetVert = polyop.getVert
		poDivideEdge = polyop.divideEdge 
		poGetOpenEdges = polyop.getOpenEdges
		poGetVertsUsingEdge = polyop.getVertsUsingEdge
		poGetEdgesUsingVert = polyop.getEdgesUsingVert
		poWeldVertsByThreshold = polyop.weldVertsByThreshold
		poCreateShape = polyop.createShape
	
		function AttachSplines objArr =
		(
			j = 1
			undo off
			(
				while objArr.count > 1 do
				(
					if j+1 > objArr.count then (j = 1) else 
					(
						addAndWeld objArr[j] objArr[j+1] 0.0
						updateShape objArr[j]
						deleteItem objArr (j+1)
						j += 1
					)
				)
			)
			--
			objArr[1]
		)
		
		function DistanceToSegment p A B &param: &dist: =
		(
			v = B - A
			param = dot v (p - A) / dot v v
			proj = A + v * param
			
			dist = distance p proj
			
			if (param < 0) then distance p A else if (param > 1) then distance p B else dist
		)
		
		function GetPolyEdgeParamPoint poly edge param = 
		(
			vv = poGetEdgeVerts poly edge
			v1 = poGetVert poly vv[1]
			v2 = poGetVert poly vv[2]
			
			v1 * (1 - param) + v2 * param
		)	

		function DividePolyEdgeAt poly edge point = 
		(
			vv = poGetEdgeVerts poly edge
			v1 = poGetVert poly vv[1]
			v2 = poGetVert poly vv[2]
			
			param = distance v1 point / distance v1 v2
			poDivideEdge poly edge param
		)	

		function MultiDividePolyEdge poly edge params = 
		(
			sort params

			points = for param in params collect (GetPolyEdgeParamPoint poly edge param)
			new_verts = #()
			nume = poly.edges.count
			for point in points do 
			(
				v = DividePolyEdgeAt poly edge point
				if (v > 0) do
				(
					nume += 1
					edge = nume
					
					append new_verts v
				)
			)
			new_verts
		)
		
		function WeldClosePolyEdges poly threshold:0.01 weld:on select:on =
		(			
			poly.weldThreshold = threshold
			
			open_ee = poGetOpenEdges poly
			open_vv = poGetVertsUsingEdge poly open_ee

			ee_table = #()
			weld_vv = #{}
			
			for v in open_vv do
			(
				pt = poGetVert poly v	
				ee = poGetEdgesUsingVert poly v  
				
				found = off
				
				for e in open_ee while not found where not ee[e] do
				(
					vv = poGetEdgeVerts poly e
					v1 = poGetVert poly vv[1]
					v2 = poGetVert poly vv[2]

					DistanceToSegment pt v1 v2 param:&p dist:&d
					if (found = (p > 0 and p < 1 and d < threshold)) do
					(
						if ee_table[e] == undefined do ee_table[e] = #()
						append ee_table[e] p
						
						append weld_vv v
					)
				)
			)

			for e=1 to ee_table.count where (params = ee_table[e]) != undefined do
			(
				vv = MultiDividePolyEdge poly e params
				if vv.count > 0 do join weld_vv (vv as bitarray)
			)
			
			if weld do poWeldVertsByThreshold poly weld_vv
			
			weld_vv
		)
	
	t0 = timestamp()
	selObjsArr = selection as array
	splArr = for o in selObjsArr where superclassOf o == Shape collect ( copy (convertToSplineShape o))
	obj = AttachSplines splArr	 
	convertToPoly obj
	obj.weldThreshold = 0.01
	poWeldVertsByThreshold obj #{1..obj.numverts}
	WeldClosePolyEdges obj threshold:0.01 weld:true select:false	
	obj.weldThreshold = 0.01
	poWeldVertsByThreshold obj #{1..obj.numverts}
	
	selEdgesBA = poGetOpenEdges obj
		
	separateLoopsArr = #()
	while not selEdgesBA.isEmpty do
	(
		tmpEdgeLoopArr = #()
		
		firstEdge = (selEdgesBA as array)[1]
		
		append tmpEdgeLoopArr firstEdge
		
		firstEdgeVertsArr = poGetEdgeVerts obj firstEdge
		selEdgesBA -= #{firstEdge}
		vert01 = firstEdgeVertsArr[1]
		vert02 = firstEdgeVertsArr[2]
		stopLoop = false
		appendLoop = true
		while stopLoop == false do
		(
			vert01 = vert02
			neighborEdgesBA = (poGetEdgesUsingVert obj #{vert01}) * selEdgesBA
			cnt = neighborEdgesBA.numberSet
			
			if cnt > 1 do 
			(
				stopLoop = true
				appendLoop = false
			)
			
			if cnt == 0 then
			(
				deleteItem firstEdgeVertsArr firstEdgeVertsArr.count
				stopLoop = true
			)
			else
			(
				firstEdge = (neighborEdgesBA as array)[1]
				vert02 = (((poGetVertsUsingEdge obj #{firstEdge}) - #{vert01}) as array)[1]
				append firstEdgeVertsArr vert02
				append tmpEdgeLoopArr firstEdge
				selEdgesBA -= #{firstEdge}
			)
		)				
		if appendLoop == true do
		(		
			append separateLoopsArr tmpEdgeLoopArr
		)
	)	
	
	for arr in separateLoopsArr do
	(
		poCreateShape obj arr smooth:false node:obj		
		newSp = objects[objects.count]
		newSp.wirecolor = yellow
	)	
	t1 = timestamp()
	format "Time: % sec\n" ((t1 - t0)/1000.0)
	
)

Denis will recognise his code. The strange thing is that the script works this way(with the test scene + fixed objects with wrong knots position):

  • sometimes everything is perfect and all inner/outer contours are found properly
  • I run the script -> wrong result, the verts welding is not as it should be
  • I run the script -> wrong result, reloading the scene, running the script again -> max directly crash(no error message, direct kill).

could you send me more examples (including examples with problems)?

your solution looks too complicated … but I need more examples to make sure my solution is good enough

BTW. The TestScene_max2014_06.max file is unstable for some reason. MAX sometimes crashes, but I don’t see any issues in the file’s scene that could cause it.

2 Replies
(@miauu)
Joined: 10 months ago

Posts: 0

Exactly this scene causes problems. Sometimes everything works, sometimes not.
I will prepare new scene.

(@miauu)
Joined: 10 months ago

Posts: 0

I’ve sent you a new scene. With my code it also crashes max unless I put everything after the functions into the with undo off(). From what I fount the script does its job, the time of execution is printed in the maxscript listener and when I click in the viewport 3ds Max crashes. Onlywith undo off() solves the problem for now.

In pipelines like this, it is very important that the Environment artists do everything right and follow the rules. They, of course, have the right to make mistakes, but the task of the Technical artist is to help not to make them, to help to find them, but usually not to fix them! Most often, the automatic correction of mistakes by artists or designers leads to “fading into the shadows” of the mistakes, which causes even more problems.

Finally got it working.

  • Inner & Outer shapes
  • No mesh/poly conversion
  • Undo/Redo
  • No need to fix the scene (for tested scenes)
  • No need to check vertex snap (for tested scenes)

536ms

955ms

Thank you.

you use a #threshold. it’s the same as “shap check”…

could you tell about the algorithm? … just basic

1 Reply
(@polytools3d)
Joined: 10 months ago

Posts: 0

Sort of, but since Max isn’t perfect, this kind of tasks can’t be done without certain threshold.

-> PM

Page 3 / 4