Mayaで反対側のfaceを取得したい1

反対側のfaceを取りたい場面に出くわしました。

selectionをシンメトリーにして取得ってのも考えたのですが、
なんかもっとダイレクトにとりたいなーと。

どうすれば？
--
faceそのものの位置ってのは存在しないので、

- faceを形成するvtxを取得する
- 反対側にあるvtxを取得する
- 反対側のvtxが形成するfaceを取得する
- 全てのvtxが所属しているfaceがそいつだ

という感じですかね。


反対側のvtxを取りたい
--

まずは反対側のvtxを取る処理単体を考えます。

OpenMaya.MFnMesh Class Reference　を眺めつつ

https://help.autodesk.com/view/MAYAUL/2022/JPN/?guid=Maya_SDK_py_ref_class_open_maya_1_1_m_fn_mesh_html

これなんか使えそう・・・

**OpenMaya.MFnMesh.getClosestPoint**

Returns a tuple containing the closest point on the mesh to the
given point and the ID of the face in which that closest point lies.

えー faceID返ってくるんですかー
とりあえず試してみます。

```python
import maya.cmds as cmds
import maya.api.OpenMaya as om

targetMesh = "pSphere1"

sellist = om.MGlobal.getSelectionListByName(targetMesh)
meshDagPath = sellist.getDagPath(0)
shapeFn = om.MFnMesh(meshDagPath)

target = cmds.ls(sl =True)[0]
position = cmds.xform(target , q =True , ws = True, t =True)
space =  om.MSpace.kWorld
otherSidePoint,faceID = shapeFn.getClosestPoint(om.MPoint(position),space)
print(faceID)
```

こんなシーンで試してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/5f223319-5c69-810e-e3f2-492b7a31a788.png)

実行結果
```python
196
```
該当のfaceはこれですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/a0b7cb6a-139e-fbab-7de5-7381c678d566.png)

1個かー　まぁclosestですからー

となると

- 指定したvexの位置を取得
- 反対側の位置を取得
- 反対側の位置のclosestなfaceを取得
- faceを形成しているvtxを取得
- 形成しているvtxの中から　反対側の位置に最も近いvtxがそいつだ

うーん　faceの取得案と並べると、なんか2度手間っぽくなってきましたね。
とりあえずやるだけやってみます。

```python
import maya.cmds as cmds
import maya.api.OpenMaya as om

def getPosition(target):
    nodeType = cmds.nodeType(target)
    
    if nodeType == "joint" or nodeType == "transform" or nodeType == "ikHandle" or nodeType == "place3dTexture":
        return cmds.xform(target , q =True , ws = True, rotatePivot =True)

    elif nodeType == "mesh" or nodeType == "nurbsCurve" or nodeType == "nurbsSurface" or nodeType == "lattice":
        return cmds.xform(target , q =True , ws = True, t =True)

def getDagNode(target):    
    try:
        sellist = om.MGlobal.getSelectionListByName(target)
        return sellist.getDagPath(0)
    except:
        return None

def mirrorMatrix(source,pivot,mirrorAxis):        

    nodeType = cmds.nodeType(source)
    
    if nodeType == "joint" or nodeType == "transform" or nodeType == "ikHandle" or nodeType == "place3dTexture":
        curMatrix = om.MMatrix(cmds.xform(source , q =True , ws = True, matrix =True))
    elif nodeType == "mesh" or nodeType == "nurbsCurve" or nodeType == "nurbsSurface" or nodeType == "lattice":
        position = getPosition(source)
        curMatrix = om.MTransformationMatrix(om.MMatrix.kIdentity).setTranslation(om.MVector(position),om.MSpace.kWorld).asMatrix()
    
    if mirrorAxis == "x":
        mirrorScale = [-1.0,1.0,1.0]
    elif mirrorAxis == "y":
        mirrorScale = [1.0,-1.0,1.0]
    elif mirrorAxis == "z":
        mirrorScale = [1.0,1.0,-1.0]

    mirrorScaleMatrix = om.MTransformationMatrix(om.MMatrix.kIdentity).setScale(mirrorScale,om.MSpace.kWorld).asMatrix()

    if pivot == "world" or pivot == None:
        pivotMatrix = om.MMatrix.kIdentity
    else:
        pivotMatrix = om.MMatrix(cmds.xform(pivot , q =True , ws = True, matrix =True))
    
    pivotMatrix_inverse = pivotMatrix.inverse()
    dist_matrix = curMatrix * pivotMatrix_inverse * mirrorScaleMatrix * pivotMatrix

    dist_matrix = om.MTransformationMatrix(dist_matrix).setScale([1.0,1.0,1.0],om.MSpace.kWorld).asMatrix()    
    dist_matrix = om.MTransformationMatrix(dist_matrix).setScale([-1.0,-1.0,-1.0],om.MSpace.kObject).asMatrix()    
    dist_matrix = om.MTransformationMatrix(dist_matrix).setScale([1.0,1.0,1.0],om.MSpace.kWorld).asMatrix()    
    dist_matrix = om.MTransformationMatrix(dist_matrix).setShear([0.0,0.0,0.0],om.MSpace.kWorld).asMatrix()

    return dist_matrix

def getMirrorPosition(source,pivot,mirrorAxis):
    setMatrix = mirrorMatrix(source,pivot,mirrorAxis)
    mirrorPosition = om.MTransformationMatrix(setMatrix).translation(om.MSpace.kWorld)    
    return mirrorPosition
    
def getMirrorPosition(source,pivot,mirrorAxis):
    setMatrix = mirrorMatrix(source,pivot,mirrorAxis)
    mirrorPosition = om.MTransformationMatrix(setMatrix).translation(om.MSpace.kWorld)    
    return mirrorPosition

def getOtherSideVtx(sourceVtxID,tagetMesh,pivot = "world",mirrorAxis = "x"):    
    mirrorPosition = getMirrorPosition(tagetMesh + ".vtx["+str(sourceVtxID)+"]",pivot,mirrorAxis)       
    mirrorPositionVector = om.MVector(mirrorPosition)

    meshDagPath = getDagNode(tagetMesh)
    shapeFn = om.MFnMesh(meshDagPath)
    
    space =  om.MSpace.kWorld    
    otherSidePoint,faceID = shapeFn.getClosestPoint(om.MPoint(mirrorPosition),space)

    faceIterator = om.MItMeshPolygon(meshDagPath)
    faceIterator.setIndex(faceID)
    vtxIDs = faceIterator.getVertices()
    faceVtxPositions = faceIterator.getPoints(om.MSpace.kWorld)

    minlength = None
    targetVtxID = None
    for faceVtxPosition,vtxID in zip(faceVtxPositions,vtxIDs):
        targetVector = om.MVector(faceVtxPosition)        
        length = (mirrorPositionVector - targetVector).length()
        
        if minlength == None:
            minlength = length
            targetVtxID = vtxID
        elif minlength > length:
            minlength = length
            targetVtxID = vtxID
            
    return targetVtxID
```

テストしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/fc541a5d-46d8-9ffa-c100-671711ec28da.png)


```python
targetVtxID = getOtherSideVtx(217,"pSphere1",pivot = "world",mirrorAxis = "x")   
cmds.select("pSphere1.vtx["+str(targetVtxID)+"]")
```

お、それっぽい位置に行きましたね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/ee354d6b-9e62-46be-1957-3953495ddbce.png)

シンメトリーをonにして
```python
cmds.ls(sl =True)
# Result: ['pSphere1.vtx[211]', 'pSphere1.vtx[217]'] # 
```

どうやらとれていそうですね。

vtxが重なってた場合はー・・・・・どうなるんだ？