[Closed] Two vertices at same position
Hello,
I would like to know if two vertices are in the same position. The STL Ckeck modifier helps a lot, but I still have two vertices in the same position and the STL Check shows me 0 errors.
So, a script is the solution for my problem. If I use Editable Mesh, my script works fine with:
VertSel = #{}
..
Vertex1=GetVert Obj j
Vertex2=GetVert Obj (j+1)
if Vertex1.x==Vertex2.x and Vertex1.y==Vertex2.y and Vertex1.z==Vertex2.z then
(
append VertSel j
append VertSel (j+1)
)
setvertselection obj VertSel
But, I need to use Editable Poly, however when I use Editable Poly with the variation:
Vertex1=Obj.GetVertex j
Vertex2=Obj.GetVertex j+1
Obj.SetSelection #Vertex VerSel
I get this error:
鈥?Unable to convert: undefined to type: BitArray
The error is in the line:
Obj.SetSelection #Vertex VerSel
Any idea of this error?
Hi Renzo,
don鈥檛 know what鈥檚 the error cause, but you can get the same results in other ways. I took the liberty to write a useless piece of working code to give you some hints.
The script is not so smart because doesn鈥檛 test overlapping verts in the whole geometry but only if two verts with adjacent index share the same position. Remeber to use a threshold value for testing because you could miss matching verts because of rounding errors. I hope you don鈥檛 mind me asking what鈥檚 your script purpose.
(
obj = selection[1]
local fThresh = 1e-4
local baVertSel = #{}
local p3Vertex1 = [0,0,0]
local p3Vertex2 = [0,0,0]
local iNumVerts = 0
if ((classOf obj) == Editable_Mesh) then
(
iNumVerts = meshOp.getNumVerts obj
for j = 1 to (iNumVerts-1) do
(
p3Vertex1 = meshOp.getVert obj j
p3Vertex2 = meshOp.getVert obj (j+1)
if ((distance p3Vertex1 p3Vertex2) <= fThresh) then
(
baVertSel[j] = true
baVertSel[j+1] = true
)
)
setVertSelection obj baVertSel
forceCompleteRedraw()
)
else if ((classOf obj) == Editable_Poly) then
(
iNumVerts = polyOp.getNumVerts obj
for j = 1 to (iNumVerts-1) do
(
p3Vertex1 = polyOp.getVert obj j
p3Vertex2 = polyOp.getVert obj (j+1)
if ((distance p3Vertex1 p3Vertex2) <= fThresh) then
(
baVertSel[j] = true
baVertSel[j+1] = true
)
)
polyOp.setVertSelection obj baVertSel
forceCompleteRedraw()
)
)
- Enrico
Hi Enrico,
Thank you for your help and for taking the time to write a new code. It was my stupid mistake. In the 鈥榚ditable mesh鈥?code I am using:
setvertselection obj VertSel
And in the 鈥榚ditable poly鈥?code I am using:
Obj.SetSelection #Vertex VerSel
So, I was using VerSel instead of VertSel, it was the reason of the error code. Can you beleive that? I spent some hours in that stupid error. Shame on me!!!
I have a question anyway. Why the code with the 鈥榚ditable mesh鈥?is a lot much faster than the code with 鈥榚ditable poly鈥? I am using an object with 1998 vertices and both codes are working now, but if I use an editable mesh, the code run very quickly, but with an editable poly it takes a few seconds.
I hope you don鈥檛 mind me asking what鈥檚 your script purpose.
I need to export many objects for stencil shadows for a real time application (game). In order to a mesh to works for stencil shadow needs some features. No open edges, for example. So, I use the STL Check modifier, but also there is an error with stencil shadows if two vertices are in the same position, so I am making this script for that. I need to use Editable Poly because I need to connect and collapse the vertices that are in the same position.
The script is not so smart because doesn鈥檛 test overlapping verts in the whole geometry but only if two verts with adjacent index share the same position.
I am making the same in my code because the problem with two vertices at the same position happend in adjacent index vertex, and it would take longer time if I test each vertex with all the rest of vertices.
Remeber to use a threshold value for testing because you could miss matching verts because of rounding errors.
Yes, it is a good idea to use a threshold value. Thanks.
EDITED: Using your code, both editable mesh and editable poly works at the same speed, so I guess there is another bug with my code in the editable poly version.
Hi Renzo,
here is a function to do the job. It cycles over all selected objects and performs two test: find overlapped verts and detect open edges. An autoCollapse trigger allows to perform the collapse during check. I hope is what you need.
function geometryCheck fThresh autoCollapse:false =
(
local objs = selection as Array
local sOpenObjs = ""
local baVertSel = #{}
local ap3VertPos = #()
local baVertEdges = #{}
local iNumVerts = 0
local iNextVert = 0
local baEdgesToCollapse = #{}
for obj in objs do
(
baVertSel = #{}
ap3VertPos = #()
baVertEdges = #{}
baEdgesToCollapse = #{}
if ((classOf obj) == Editable_Mesh) then
(
iNumVerts = meshOp.getNumVerts obj
for i = 1 to iNumVerts do
append ap3VertPos (meshOp.getVert obj i)
for j = iNumVerts to 1 by -1 do
(
baVertEdges = meshOp.getEdgesUsingVert obj j
for iEdge in baVertEdges do
(
iNextVert = (((meshOp.getVertsUsingEdge obj iEdge) - #{j}) as Array)[1]
if ((distance ap3VertPos[j] ap3VertPos[iNextVert]) <= fThresh) then
(
baVertSel[j] = true
baVertSel[iNextVert] = true
if (autoCollapse) then
baEdgesToCollapse[iEdge] = true
)
)
)
setVertSelection obj baVertSel
if (autoCollapse) then
meshOp.collapseEdges obj baEdgesToCollapse
baOpenEdges = meshOp.getOpenEdges obj
if (baOpenEdges.isEmpty == false) then
(
setEdgeSelection obj baOpenEdges
sOpenObjs += ("
" + obj.name)
)
)
else if ((classOf obj) == Editable_Poly) then
(
iNumVerts = polyOp.getNumVerts obj
for i = 1 to iNumVerts do
append ap3VertPos (polyOp.getVert obj i)
for j = iNumVerts to 1 by -1 do
(
baVertEdges = polyOp.getEdgesUsingVert obj j
for iEdge in baVertEdges do
(
iNextVert = (((polyOp.getVertsUsingEdge obj iEdge) - #{j}) as Array)[1]
if ((distance ap3VertPos[j] ap3VertPos[iNextVert]) <= fThresh) then
(
baVertSel[j] = true
baVertSel[iNextVert] = true
if (autoCollapse) then
baEdgesToCollapse[iEdge] = true
)
)
)
polyOp.setVertSelection obj baVertSel
if (autoCollapse) then
polyOp.collapseEdges obj baEdgesToCollapse
baOpenEdges = polyOp.getOpenEdges obj
if (baOpenEdges.isEmpty == false) then
(
setEdgeSelection obj baOpenEdges
sOpenObjs += ("
" + obj.name)
)
)
forceCompleteRedraw()
)
if (sOpenObjs != "") then
messageBox ("Following objects have open edges:" + sOpenObjs)
return OK
)
- Enrico
Hi Enrico,
Thank you very much for your help. Finally I will use your code, I found some vertices that are not adjacent and are at the same position. Could you make this change for me please?
I don鈥檛 need to collapse the open edges, I just need to show the open edges like it is in your code and 鈥楥onnect鈥?(in Editable Poly) the vertices that share the same position and then 鈥楥ollapse鈥?these vertices. For example, given this list of vertices:
V1 (1, 4, 3)
V2 (1, 4, 3)
V3 (1, 2, 8)
V4 (1, 3, 9)
V5 (1, 3, 9)
I would need to connect and collapse V1 and V2 and then V4 and V5. So finally my object will have 3 vertices instead of 5.
So, how can I group data and make an operation to each group?
Hi Renzo,
I鈥檓 not sure to understand your request since the latest script version seems to already do what you鈥檙e asking. Right now the algorithm cycles over each vert in geometry and looks for every edge starting from it, then if the length of an edge is less than provided threshold, the two verts of such edge are selected, if autoCollapse is true, they鈥檙e collapsed too. You don鈥檛 need to connect verts if they already share an edge before collapsing it.
Maybe you mean you want to collapse verts in a face not sharing an edge? Like, giving numbers to verts in a quad clockwise from 1 to 4, you need to check and collapse overlapping pairs 1-3 or 2-4? In that case you would need a connect before.
Then algorithm searches then for open edges and if found selects them and shows a message box for feedback.
On the verts sample you provided, it should give as is now the result you鈥檙e looking for. Can you tell me if anything is wrong?
- Enrico
Hi Enrico,
My fault again. I thought that you were collapsing edges because of 鈥榩olyOp.collapseEdges鈥?instead of 鈥榩olyop.collapseVerts鈥? but I鈥檝e just tested your script in a model an it is working fine.
I don鈥檛 know much about 3ds max, I know max script because it is very similar to c++ and the listener helps a lot.
When I did this process manually, I remember to find some vertices in the same position that I coudn鈥檛 collapse unless I use the option 鈥榗onnect鈥?first. I guess that they were vertices that don鈥檛 share an edge.
Thank you for all your help. I appreciated that.
Hi Renzo,
here is a small update in the Editable Poly section. It now works on every vert that share a face with the checked one, so even if in a quad two verts are in the opposite position like pairs 1-3 and 2-4, and don鈥檛 share an edge, if their position matches they鈥檙e selected, connected and collapsed if autoConnectOption is set to true. Mind that if you run this on nGons like pentagons, you can end up with bad looking topology like a vert in the middle of an edge, because of collapsing effect. Anyway, I hope this works well for you.
function geometryCheck fThresh:1e-4 autoCollapse:false =
(
local objs = selection as Array
local sOpenObjs = ""
local iFlag = bit.set 0 30 true
local baVertSel = #{}
local ap3VertPos = #()
local baVertEdges = #{}
local iNumVerts = 0
local iNextVert = 0
local baEdgesToCollapse = #{}
for obj in objs do
(
baVertSel = #{}
ap3VertPos = #()
baVertEdges = #{}
baEdgesToCollapse = #{}
if ((classOf obj) == Editable_Mesh) then
(
iNumVerts = meshOp.getNumVerts obj
for i = 1 to iNumVerts do
append ap3VertPos (meshOp.getVert obj i)
for j = iNumVerts to 1 by -1 do
(
baVertEdges = meshOp.getEdgesUsingVert obj j
for iEdge in baVertEdges do
(
iNextVert = (((meshOp.getVertsUsingEdge obj iEdge) - #{j}) as Array)[1]
if ((distance ap3VertPos[j] ap3VertPos[iNextVert]) <= fThresh) then
(
baVertSel[j] = true
baVertSel[iNextVert] = true
if (autoCollapse) then
baEdgesToCollapse[iEdge] = true
)
)
)
setVertSelection obj baVertSel
if (autoCollapse) then
meshOp.collapseEdges obj baEdgesToCollapse
baOpenEdges = meshOp.getOpenEdges obj
if (baOpenEdges.isEmpty == false) then
(
setEdgeSelection obj baOpenEdges
sOpenObjs += ("
" + obj.name)
)
)
else if ((classOf obj) == Editable_Poly) then
(
local baVertFaces = #{}
local baNearVerts = #{}
local iNewEdge = 0
iNumVerts = polyOp.getNumVerts obj
for i = 1 to iNumVerts do
append ap3VertPos (polyOp.getVert obj i)
for j = iNumVerts to 1 by -1 do
(
baVertEdges = polyOp.getEdgesUsingVert obj j
baVertFaces = polyOp.getFacesUsingVert obj j
baNearVerts = (polyOp.getVertsUsingFace obj baVertFaces) - (polyOp.getVertsUsingEdge obj baVertEdges)
for iEdge in baVertEdges do
(
iNextVert = (((polyOp.getVertsUsingEdge obj iEdge) - #{j}) as Array)[1]
if ((distance ap3VertPos[j] ap3VertPos[iNextVert]) <= fThresh) then
(
baVertSel[j] = true
baVertSel[iNextVert] = true
if (autoCollapse) then
polyOp.setEdgeFlags obj iEdge iFlag
)
)
for iVert in baNearVerts do
(
if ((distance ap3VertPos[j] ap3VertPos[iVert]) <= fThresh) then
(
baVertSel[j] = true
baVertSel[iVert] = true
if (autoCollapse) then
(
iNewEdge = polyOp.createEdge obj j iVert
polyOp.setEdgeFlags obj iNewEdge iFlag
)
)
)
)
polyOp.setVertSelection obj baVertSel
if (autoCollapse) then
(
baEdgesToCollapse = polyOp.getEdgesByFlag obj iFlag
polyOp.collapseEdges obj baEdgesToCollapse
)
baOpenEdges = polyOp.getOpenEdges obj
if (baOpenEdges.isEmpty == false) then
(
setEdgeSelection obj baOpenEdges
sOpenObjs += ("
" + obj.name)
)
)
forceCompleteRedraw()
)
if (sOpenObjs != "") then
messageBox ("Following objects have open edges:" + sOpenObjs)
return OK
)
- Enrico
Hey Enrico,
Why sometimes I can not connect and collapse vertices that are in the same position. I鈥檝e attached an example, if you open the max file there are two vertices on the center of the screen that has the same position, vertex 540 and 547. It is not possible to connect and collapse those two vertices. Why?
BTW, your last script doesn鈥檛 identify those vertices.