PDA

View Full Version : python- selecting objects within certain distance?


cwisbg
08-14-2012, 05:26 PM
say i have a cube, at 0,0,0, and a bunch of other cubes surrounding it within 0-10 units away. Is there a way to get/select all the cubes within 0-2 of the first cube? iv looked into closestPoint to mesh but im a little to inexperienced with the api to know how to use it. anyone have a good alternative technique using python/pymel?

rgkovach123
08-14-2012, 05:39 PM
you can use the closestPointOnMesh node....
or use a distance locator between the pivot points of the cubes...

zoharl
08-14-2012, 07:13 PM
Traverse all the other cubes, and measure the distance from each cube vertex to any of the base cube vertex. Then filter by your criteria.

cwisbg
08-14-2012, 09:19 PM
anyway to find just the close ones without having to iterator though all of the cubes?

zoharl
08-15-2012, 04:12 AM
Impossible. Think about it, you'll have to test a cube at least once if it fits some criteria. Let me demonstrate: Can you find the maximum number in an unsorted random array without traversing all the array elements? Nonsense.
The question is if it's really necessary to check all four vertices, and probably not, but more probable that it's negligible.

cwisbg
08-15-2012, 05:07 PM
Impossible! NEVER! but that does makes sense. I was hoping there was a more efficient way.

rgkovach123
08-15-2012, 05:12 PM
there are methods for partitioning space, and placing objects into these partitions, and then only checking objects that are in the same partition.

it still does require iterating over all the cubes in the scene to sort them into partitions, but this is usually fast. its the comparison that usually takes longer, so limiting the number of comparisons can help overall performance.

ldunham1
08-15-2012, 07:16 PM
is it completely necessary to use the objects mesh? if not, then time will be saved using either the pivot or centerpoint of the mesh, and if thats too general look into the boundingBox via xform.

if you are using either the boundingBox or the mesh though make sure once an object matches the threshold and is added to the list of valid objects that it gets taken out of the list of objects to search.

You should also filter the objects by type before checking its distance from mesh.

but if you really want, instead of doing all the hard work yourself, just query the influenced objects via softSelection[object mode] in the maya.api :D

zoharl
08-15-2012, 07:42 PM
@cwisbg, how about you give it a try, time it, and when you find the bottlenecks (profiler), look for better solutions?

@ldunham1, I didn't understand your first suggestions, since we are talking about cubes.
But I am interested to know what you meant in the end about soft selection, I didn't understand what you meant?

ldunham1
08-15-2012, 08:40 PM
I was curious as to whether cwisbg specifically wanted to query objects within a radius of a mesh or whether using a single vector would be sufficient. The difference being calculating radius against a magnitude of vectors (from each vert) or 1 vector (pivot point).

The latter in which case its fairly simple - find the math behind calculating the distance between two vectors. Then loop over each filtered object in scene (minus target object), get its position (or position of each vert), calculate distance and filter against threshold.


The last part I mentioned was to use maya's softSelection to do the hard work for you, all you need to do is enable softSelection on a global scale, sets its falloff and query the influenced objects. like so.

import maya.cmds as mc
import maya.OpenMaya as om

# edited from script found here
'''
https://groups.google.com/forum/?fromgroups#!topic/python_inside_maya/q1JlddKybyM%5B1-25%5D
'''
def softSelection():
selection = om.MSelectionList()
softSelection = om.MRichSelection()
om.MGlobal.getRichSelection(softSelection)
softSelection.getSelection(selection)
dagPath = om.MDagPath()

iter = om.MItSelectionList(selection)
elements = []
while not iter.isDone():
iter.getDagPath(dagPath)
dagPath.pop()
elements.append('%s'%dagPath.fullPathName())
iter.next()
return elements

def getObjectsInRadius(object,radius=20.0):
mc.softSelect(softSelectEnabled=True,softSelectDistance=radius,softSelectFalloff=2)
return softSelection()

print getObjectsInRadius(mc.ls(sl=True)[0])[1:]

Its very untidy but does the job.

zoharl
08-16-2012, 12:12 AM
@cwisbg needs first to wrap is head around the idea of iterating all the objects.

I didn't understand your second paragraph, and you might have confused vectors with vertices.

That's a neat trick with the soft selection. I wasn't aware that it has object/global mode.

ldunham1
08-16-2012, 07:33 AM
good point.

haha no I haven't confused them, I just hadn't explained properly (not enough coffee). He's a kinda breakdown of what I meant.

A typical way I'd filter by proximity would be using the rotationalPivot of an object via xform(object,q=True,ws=True,rp=True), which returns with 1 vector ([0,0,0]).
In my head, if that same principle was to be used with the mesh of and object instead - then a basic way would be to query the ws translation of every vert in a mesh, (providing a vector per vert) - meaning more iterations.

What I meant was that instead of filtering via every translation node in scene - ls(type='translation'), narrow the search and filter by every node with a mesh child - which would also list the target object so removing it from the filtered list, there is one less object to iterate through.

for getting the distance between two vectors via something like
math.sqrt( math.pow( pointA[0] - pointB[0], 2) + math.pow( pointA[1] - pointB[1], 2) + math.pow( pointA[2] - pointB[2], 2) )
then comparing the result of the distance to the radius threshold.

If im missing anything out let me know?


Yeah Maya seems to have a wide range of options for tools that are rarely used/known about but can be really handy at times.

zoharl
08-16-2012, 09:10 AM
Okay, but still your formula is for a distance between pointA and pointB (I assume you refer here to the two pivot points). There isn't really a distance between vectors.

Also the problem can be much simplified if the cubes are really cubes (all edges equal) and if they are orthogonal.

ldunham1
08-16-2012, 09:54 AM
ah ok, my interpretation of vectors must be slightly off.

Im interested in that simplified version :D

zoharl
08-16-2012, 10:09 AM
Calculate the barycenter of each cube. If the pivot didn't change, then you can query it as you did, and take it as the barycenter.
Next, let's call half of the cube edge length a radius.
Now if the cubes are orthogonal to the axes (didn't rotate), given the radius and center of each cube we can filter the cubes in each axis according to the distance along this axis. For example in the x-axis you know the exact range that a cube is allowed to be. This filters the cube according to the Manhattan distance and not the Euclidean. The next step is to check the distance between the centers of the cubes which passed the first filtering to the center of the base cube (Euclidean distance as you did). There's nothing new here, it's a common procedure for collision detection using bounding boxes, only here the cubes are even simpler the the boxes.

tontonsuspect
08-16-2012, 10:26 AM
it may not be 100 percent relevant to your case but I wrote with a simple custom node here:

http://forums.cgsociety.org/showpost.php?p=7280472&postcount=14

it will just select the current voxel the joint lies in..
for this project i simply convert the joint world position into the voxel coordinates:( let say a voxel is 4*4*4 cm, we can simply divide the point translateX value by this side and find the nearest lowest index..

ldunham1
08-16-2012, 10:49 AM
ah! that actually make sense to me (its not often that happens...)
I think i'll be updating my functions...

Cheers!

zoharl
08-16-2012, 11:00 AM
Say, I just thought about something not related to the problem at hand, but is related to the soft selection. Usually when I'd like to select the vertices of some part, such as a toe nail, I select one vertex, and then like a monkey I press shift+> to grow the selection. Using the soft selection I can do it instead with the mouse which is much quicker. Is there a way to convert the soft selection vertices to regular selection? Meaning vertices that got values from the soft selection greater than zero would be selected (in a regular mode), the rest that got nothing won't be.

ldunham1
08-16-2012, 11:20 AM
yeah thats a neat idea. 2 ways to do it so far.
The long way (actually converts to selection)

import maya.OpenMaya as OpenMaya

def softSelection():
selection = OpenMaya.MSelectionList()
softSelection = OpenMaya.MRichSelection()
OpenMaya.MGlobal.getRichSelection(softSelection)
softSelection.getSelection(selection)

dagPath = OpenMaya.MDagPath()
component = OpenMaya.MObject()

iter = OpenMaya.MItSelectionList( selection,OpenMaya.MFn.kMeshVertComponent )
elements = []
while not iter.isDone():
iter.getDagPath( dagPath, component )
dagPath.pop()
node = dagPath.fullPathName()
fnComp = OpenMaya.MFnSingleIndexedComponent(component)

for i in range(fnComp.elementCount()):
elements.append('%s.vtx[%i]' % (node, fnComp.element(i)))
iter.next()
return elements


mc.select(softSelection())
mc.softSelect(softSelectEnabled=False)

and sneaky way (just sets falloff curve to linear instead)

mc.softSelect(softSelectEnabled=True,ssc='1,0,0,0,1,2')

zoharl
08-16-2012, 11:46 AM
You mean there isn't such an option from the gui, and you wrote something new? Cool! :thumbsup:

BTW, the sneaky method as you said, just sets the fall off curve, and pressing 'b' again loses the selection.

ldunham1
08-16-2012, 12:06 PM
haha, i cant take the credit, all ive done was modified Brian's script, but it is useful :D
its unfortunate that they dont make more use of the softSelection tools internally.

yeah the sneaky method does has some drawbacks but if its only for basic transformation then the use should be fine.

cwisbg
08-16-2012, 02:06 PM
awesome ldunham1 that is exactly what im lookin for.

CGTalk Moderation
08-16-2012, 02:06 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.