So, let’s formulate the minimum requirements from the information known to us:
- Arbitrary two (only two!) edges must be chosen.
1.1 Edges can belong to different meshes.
1.2. Edges may share a common vertex.
- Perform some manipulations so that the length of the second selected edge becomes equal to the length of the first selected edge.
2.1. The vertices of the second edge before and after the transformation must lie on the same straight line.
From these requirements it follows that:
- We must organize the memorization of the order of selection of components.
- We must provide mechanisms for valid selection content.
- To change the length of the target edge, we will move edge_vertex_ID(1) along this edge.
3.1. In case this vertex is shared between the target and source edges:
To keep the length of the source edge, to change the length of the target edge, we will move edge_vertex_ID(0) along this edge.
- In case the source mesh(es) have been transformed, we must ensure that the lengths of the source and target edges match in terms of world space.
*Optional 5. If we want to use this script as a tool, we need to provide a mechanism for interactive selection of components. For the script to work automatically with the correct selection of components.
*Optional 6. It is highly desirable to implement an undo function for “setPoint”!
import maya.api.OpenMaya as om
def maya_useNewAPI():
pass
maya_useNewAPI = True
# Set whether Maya should maintain an active selection list which
# maintains object and component selection order.
if not om.MGlobal.trackSelectionOrderEnabled():
om.MGlobal.setTrackSelectionOrderEnabled()
# Deselect
sel_list = om.MGlobal.getActiveSelectionList()
sel_list.clear()
om.MGlobal.setActiveSelectionList(sel_list)
#####
#... Here you can implement some code for interactive selection of edges.
####
def get_correct_selection():
# Return an MSelectionList containing the nodes, components and
# plugs currently selected in Maya. If orderedSelectionIfAvailable
# is True, and tracking is enabled, will return the selected items
# in the order that they were selected.
selection = om.MGlobal.getActiveSelectionList(orderedSelectionIfAvailable = True)
# Checking that only two items are selected.
if selection.isEmpty():
return [0, 0]
if selection.length() != 2:
return [0, 1]
# Get node and component from selection.
node_01, component_01 = selection.getComponent(0)
node_02, component_02 = selection.getComponent(1)
# Check yhat both selected components are edges.
if component_01.apiTypeStr != component_02.apiTypeStr != 'kMeshEdgeComponent':
return [0, 2]
# For the source edge, we get its length and IDs of its vertices (in world space).
it = om.MItMeshEdge(node_01, component_01)
reference_length = it.length(space = 4) # space = MSpace.kWorld or "4"
vertex_id_01_01 = it.vertexId(0)
vertex_id_01_02 = it.vertexId(1)
# For the target edge, we get the coordinates and IDs of its vertices (in world space).
it = om.MItMeshEdge(node_02, component_02)
point_02_01 = it.point(0, space = 4) # space = MSpace.kWorld or "4"
point_02_02 = it.point(1, space = 4) # space = MSpace.kWorld or "4"
vertex_id_02_01 = it.vertexId(0)
vertex_id_02_02 = it.vertexId(1)
# If vertex(0) of the target edge is common between the target and source edges,
# then we will move vertex(1) on the target edge.
if vertex_id_02_02 in (vertex_id_01_01, vertex_id_01_02):
point_a = point_02_02
point_b = point_02_01
edge_vertex_id = 0
else:
point_a = point_02_01
point_b = point_02_02
edge_vertex_id = 1
return [it,
point_a,
point_b,
edge_vertex_id,
reference_length]
all_ret = get_correct_selection()
# Processing the selection.
if not all_ret[0]:
if not all_ret[1]:
sel_error = 'Nothing selected. Select two edges.'
elif all_ret[1]:
sel_error = 'Selection must contain exactly two components. Select two edges.'
else:
sel_error = 'Selection is valid only for edges. Select two edges.'
# ... Here you can implement some code to handle the wrong selection (with "sel_error").
else:
(it,
point_a,
point_b,
edge_vertex_id,
reference_length
) = all_ret
# Calculate the vertex(1) position of the target edge so that the length
# of the target edge becomes equal to the length of the source edge.
# In addition, we want vertex(0), vertex(1) and vertex(1)(new position)to line on the same line.
vector_a = om.MVector(point_a.x, point_a.y, point_a.z)
vector_b = om.MVector(point_b.x, point_b.y, point_b.z)
new_point = om.MPoint(vector_a + (vector_b - vector_a).normalize()*reference_length)
# Move the vertex to a new position (in world space).
it.setPoint(new_point, edge_vertex_id, space = 4) # space = MSpace.kWorld or "4"
OpenMaya MSpace Class Reference
Coordinate Space Types:
int kInvalid = 0
int kLast = 5
int kObject = 2
int kPostTransform = 3
int kPreTransform = 2
int kTransform = 1
int kWorld = 4