View Full Version : Selection vertex based on position

 shcmack10 October 2010, 07:13 PMI'm wondering if it's possible to select an object/a vertex just by knowing it's position? Lets say pSphere1.vtx[213] is positioned at wordspace position 21.31 4.22 4.66, is it then possible to select that vertex without knowing the name of the object? The reason why I'm asking, is that I want to create a 'Mirror Cluster' script. So if the object is symetrical and positioned in the center of the scene, I should be able to get the position (vertexes) on the other side.
aguirre
10 October 2010, 08:05 PM
hey, this should actually work

give a list of vertices that could be on that position
and a pos (eg.: [0, 1, 0])

import maya.cmds as mc

def pIdentifyVtxByPosition(possibleVertices, pos):
for vtx in possibleVertices:
vtxPos = mc.pointPosition(vtx)
if vtxPos == pos:
return vtx
break

Nyro
10 October 2010, 10:07 PM
Agh. This always happens to me :cry: I'm such a slow coder (i.e. not a coder at all, hence I have to look up every function as I go along) that it takes me ages to write a simple script. In that time someone else comes along and answers the question, rendering my solution obsolete...

Well, what the hell. I wrote it, here it is:

\$curVtx = `filterExpand -sm 31 -ex true`;

string \$mAxis = "X"; //mirror axis (default X); change to "Y" or "Z" according to symmetry axis
float \$tol = 0.01; //position tolerance margin; default to second decimal value, i.e. hundreth of a unit

if (size(\$curVtx) == 1) { //works only with a single vertex selected

float \$vPos[] = `xform -q -ws -t \$curVtx`;

switch(\$mAxis) { //different values depending on mirror axis

case "X":
float \$sAxis[] = {1,0,0};
float \$xPos = `abs \$vPos[0]`; //the absolute value of current vertex distance to mirror plane
\$xPos /= \$tol; //begin tolerance margin calculation
\$xPos = trunc(\$xPos);
\$xPos *= \$tol;
float \$xMin = \$xPos - \$tol;
float \$xMax = \$xPos + \$tol; //end tolerance margin calculation
float \$vDist[] = {\$xMin,\$xMax}; //the distance to search
break;

case "Y":
float \$sAxis[] = {0,1,0};
float \$xPos = `abs \$vPos[1]`;
float \$vDist[] = {\$xPos,\$xPos};
break;

case "Z":
float \$sAxis[] = {0,0,1};
float \$xPos = `abs \$vPos[2]`;
float \$vDist[] = {\$xPos,\$xPos};
break;

}

polySelectConstraint -m 3 -t 1 -d 3 -db \$vDist[0] \$vDist[1] -dp 0 0 0 -da \$sAxis[0] \$sAxis[1] \$sAxis[2];

select -d \$curVtx;

//this is the interesting result
\$mVtx = `ls -sl -fl`;
print("The mirrored vertex is: " + \$mVtx[0]);

polySelectConstraint -d 0;

};

What this basically does is this:

You select one vertex (and one only...)
The script analyses that vertex's position, adding an optional tolerance margin and the option to specify the mirror axis of your object, then uses the polySelectConstraint command to select any vertex that lies on either side of a mirror plane (defined by the mirror axis) that has the same distance (to the mirror plane) as the originally selected vertex.
After that it stores the new (mirrored) vertex in a variable (\$mVtx) for further usage and prints its ID.

The tolerance margin was added because I somehow don't trust Maya's internal rounding algorithms in conjunction with polySelectConstrain. As an example, if the original vertex is at X = 65.23242253 and the tolerance margin is \$tol = 0.001, then the script will search for the new vertex between 65.231 and 65.233. For ultra-dense meshes simply set a very low tolerance or delete that part of the script entirely.

I sincerely hope this was at all useful :)

shcmack
10 October 2010, 12:51 PM
Nyro: Hey thanks for your answere :) I can't really get the mirroring to work correctly though, not even with a simple pCube. When I select a vertex on the positive Y/X axis, it thinks the mirror-vertex is the negative Y/X axis. If I try it with a pSphere, it seems to just select a random vertex as long as it's negative X.

I've written a script for this that works now, it's pretty slow, but it works. Instead of it selecting the vertexes based on just the position, I compare the position of each vertex member of the cluster, to all the selected vertexes on the other side (which I select manually).
//Set the waitCursor state ON
waitCursor -state on;
//Get accuracity from the slider
global float \$accuracy;
//Get the selected vertexes
string \$selVtx[] = `ls -sl -fl`;
//Get the vertexes from the cluster
global string \$clusterSet[];
string \$clusterMembers[] = `sets -q \$clusterSet`;
string \$clusterVtx[] = `ls -fl \$clusterMembers`;
//Create two global variables for each side (the original and the mirror)
global string \$orgSide[];
global string \$newSide[];
clear \$orgSide;
clear \$newSide;
//Create a counter
int \$counter = 0;
//For each vertex of the cluster
for(\$a=0;\$a<`size \$clusterVtx`;\$a++)
{
//Get the current vertex's position
float \$pos[] = `xform -q -ws -t \$clusterVtx[\$a]`;
//Truncate the decimals
float \$vX = \$pos[0] - fmod(\$pos[0], \$accuracy);
float \$vY = \$pos[1] - fmod(\$pos[1], \$accuracy);
float \$vZ = \$pos[2] - fmod(\$pos[2], \$accuracy);
//For each vertex selected on the mirror side
for(\$b=0;\$b<`size \$selVtx`;\$b++)
{
//Get the current vertex's position
float \$tmpPos[] = `xform -q -ws -t \$selVtx[\$b]`;
//Truncate the decimals
float \$oX = \$tmpPos[0] - fmod(\$tmpPos[0], \$accuracy);
float \$oY = \$tmpPos[1] - fmod(\$tmpPos[1], \$accuracy);
float \$oZ = \$tmpPos[2] - fmod(\$tmpPos[2], \$accuracy);
//Check which axis it should mirror - If X
if(`checkBoxGrp -q -v1 mirrorX` == 1)
{
//See if the position matches
if(\$vX == \$oX * -1 && \$vY == \$oY && \$vZ == \$oZ)
{
//If it does, put each side in separate string-arrays
\$orgSide[\$counter] = \$clusterVtx[\$a];
\$newSide[\$counter] = \$selVtx[\$b];
\$counter = \$counter + 1;
}
}
//Check which axis it should mirror - If Y
if(`checkBoxGrp -q -v1 mirrorY` == 1)
{
if(\$vX == \$oX && \$vY == \$oY * -1 && \$vZ == \$oZ)
{
\$orgSide[\$counter] = \$clusterVtx[\$a];
\$newSide[\$counter] = \$selVtx[\$b];
\$counter = \$counter + 1;
}
}
//Check which axis it should mirror - If Z
if(`checkBoxGrp -q -v1 mirrorZ` == 1)
{
if(\$vX == \$oX && \$vY == \$oY && \$vZ == \$oZ * -1)
{
\$orgSide[\$counter] = \$clusterVtx[\$a];
\$newSide[\$counter] = \$selVtx[\$b];
\$counter = \$counter + 1;
}
}
}
}
//Select the vertexes on the opposite side
select \$newSide;
//Set the waitCursor state ON
waitCursor -state off;

Thanks guys :)

Nyro
10 October 2010, 03:08 PM
Hi Jorn,

First of all: I'm not quite sure what an "X/Y axis" is. Maybe you're referring to a plane?
Anyhow, you're right. My script fails in a very specific case: if the object is point-symmetrical, as opposed to axis/plane symmetry. Both the perfect cube (i.e. sides of same length) and the sphere fall into this specific case. My script simply selects any vertex that fulfils the condition "Vertex V lies on any side of the mirror plane A (which is centered to the world pivot 0,0,0) and has the distance d from the mirror plane."

Obviously, any of the vertices of a cube fulfil that condition, disregarding what the mirror plane is set to.
The Sphere, being the perfect symmetrical object, has the same problem. A polygonal sphere will have multiple vertices that lie at the same distance d opposite the mirror plane (depending on sphere resolution and tolerance value, this could be quite many).
Comment out the last line of my script ("// polySelectConstraint -d 0;") and run the script on any vertex of a sphere. It will probably show a selection of multiple vertices. These are the candidates the script finds (the script only outputs the first vertex in that list). If you now view the model from the top orthogonal view, you'll notice that all vertices lie roughly the same distance from the mirror plane, i.e. you could draw a line through them on either side and they'd all lie on the line.

Try my script with an arbitrary, slightly more organic mesh that is symmetrical only across a specific mirror plane and centered to [0,0,0]. Then my script should work flawlessly.

The reason I chose not to iterate through every vertex in the mesh is just the problem you're encountering: it's slow, especially on very complex meshes. My script executes immediatley, because it's basically just a selection conversion coupled with six simple math functions.

By the way, I just noticed that I only implemented the tolerance function in the "Case: X" case, not for "Y" and "Z".

CGTalk Moderation
10 October 2010, 03:08 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.

1