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 ¶m: &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.
Exactly this scene causes problems. Sometimes everything works, sometimes not.
I will prepare new scene.
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
you use a #threshold. it’s the same as “shap check”…
could you tell about the algorithm? … just basic
Sort of, but since Max isn’t perfect, this kind of tasks can’t be done without certain threshold.
-> PM