0

The following commands will convert a given controlPoint index to the corresponding object's component type:

import maya.cmds as mc

print (mc.ls('pCube1.controlPoints[3]'))       # ['pCube1.vtx[3]']
print (mc.ls('nurbsSphere1.controlPoints[3]')) # ['nurbsSphere1.cv[0][3]']
print (mc.ls('ffd1Lattice.controlPoints[3]'))  # ['ffd1Lattice.pt[1][1][0]']

I am looking for a way to query the opposite: given a component, return its corresponding controlPoint. To do so I wrote a naïve solution that requires building a flattened list and then match the query for the proper index.

import maya.cmds as mc
import re

def naive_control_point_lookup(query):
    obj, comp  = query.split('.')
    comp_      = comp.split('[')[0]
    everything = mc.ls(f'{obj}.{comp_}[*]', fl=True) # flattened component list

    r = re.compile(f'.*{re.escape(comp)}')
    match = next(filter(r.match, everything)) # match the query's component
    return f'{obj}.controlPoints[{everything.index(match)}]' # format the index in a string


query = 'ffd1Lattice.pt[1][1][0]'
cp = naive_control_point_lookup(query) # ffd1Lattice.controlPoints[3]
print (query == mc.ls(cp)[0]) # True

This works, but I would think there is a way to directly obtain what I want.

QUESTION

Is there a way to get this component --> controlPoint conversion done directly via a command, or via Maya's python API?

Fnord
  • 5,365
  • 4
  • 31
  • 48

2 Answers2

1

Yeah, this can be done. You need to query the contents of the selection list using MSelectionList::getDagPath(), but make sure you capture the 'component' MObject from that call! (it will store all the indices for the selected components)

Then it will depend on the indexing used for the surface in question. You should be able to pass the returned component MObject to one of the following:

MFnSingleIndexedComponent: For meshes & curves

MFnDoubleIndexedComponent: For nurbs surfaces

MFnTripleIndexedComponent: For lattices

IIRC, you can also pass the MObject to an MItGeometry which will let you iterate over them in a unified fashion (e.g. the indices returned will relate to the flattened points array indices, so you can use a single index for all of them). There are a few additional iterator types you can use if you want additional info (e.g. MItSurfaceCV, MItMeshVertex, etc).

robthebloke
  • 9,331
  • 9
  • 12
  • Thank you, i wasn't aware of MItGeometry (i think was introduced in Maya 2022) and its index method does exactly what I want. – Fnord Mar 23 '23 at 19:51
0

A million thanks to @robthebloke for suggesting MItGeometry, which I wasn't aware of until now and lets me get what I want with no need for iteration or list building. Here's a code snippet to illustrate and complement his answer:

import maya.api.OpenMaya as om

def api_control_point_lookup(query):
    tracker = om.MSelectionList()
    tracker.add(query)   
        
    component = tracker.getComponent(0)
    index = om.MItGeometry(*component).index()
    
    obj = query.split('.')[0]
    return (f'{obj}.controlPoints[{index}]')

# works on vtx, cv and pt
print (api_control_point_lookup('pCube1.vtx[3]'))           # pCube1.controlPoints[3]
print (api_control_point_lookup('nurbsSphere1.cv[0][3]'))   # nurbsSphere1.controlPoints[3]
print (api_control_point_lookup('ffd1Lattice.pt[1][1][0]')) # ffd1Lattice.controlPoints[3]
Fnord
  • 5,365
  • 4
  • 31
  • 48