Skip to content

Instantly share code, notes, and snippets.

@viktorasm
Created December 7, 2023 22:52
Show Gist options
  • Save viktorasm/588ce45e8d637ce0f49ae7ad7d4767cd to your computer and use it in GitHub Desktop.
Save viktorasm/588ce45e8d637ce0f49ae7ad7d4767cd to your computer and use it in GitHub Desktop.
path from a to b, chatgpt edition
import maya.cmds as cmds
import maya.api.OpenMaya as om
from typing import List, Optional
def get_locator_position(locator_name: str) -> om.MVector:
"""Retrieve the position of a given locator"""
if not cmds.objExists(locator_name):
raise ValueError(f"Locator '{locator_name}' does not exist.")
return om.MVector(
cmds.xform(locator_name, query=True, translation=True, worldSpace=True)
)
def create_or_move_locator(name: str, position: om.MVector) -> None:
"""Create a new locator or move an existing one to the specified position"""
if cmds.objExists(name):
cmds.move(position.x, position.y, position.z, name)
else:
cmds.spaceLocator(name=name)
cmds.move(position.x, position.y, position.z, name)
# Retrieve positions of locatorA and locatorB
A = get_locator_position("locatorA")
B = get_locator_position("locatorB")
up = get_locator_position("locatorUP")
BA = B - A
plane_normal = (up - A) ^ BA
plane_normal.normalize()
up = BA ^ plane_normal
up.normalize()
def calculate_intersection(
plane_normal: om.MVector,
plane_point: om.MVector,
line_start: om.MVector,
line_end: om.MVector,
) -> Optional[om.MVector]:
"""Calculate the intersection point of a line with a plane"""
line_dir = line_end - line_start
# Calculate the dot product of the plane normal and the line direction
dot_product = plane_normal * line_dir
# If dot_product is 0, the line is parallel to the plane (no intersection or infinite intersections)
if dot_product == 0:
return None
# Calculate the value of t at the intersection point
t = ((plane_point - line_start) * plane_normal) / dot_product
# Check if the intersection point lies within the line segment
if 0 <= t <= 1:
intersection_point = line_start + t * line_dir
return intersection_point
else:
return None
# Define the normal vector and a point on the plane
plane_point = om.MVector(A)
# Get the MObject for the mesh
mesh_name = "pCylinder1" # Replace with your mesh name
selectionList = om.MSelectionList()
selectionList.add(mesh_name)
mesh_obj = selectionList.getDagPath(0)
# Create an edge iterator
edge_iter = om.MItMeshEdge(mesh_obj)
intersection_points = []
# Iterate over edges and check for intersections
while not edge_iter.isDone():
point1 = om.MVector(edge_iter.point(0, om.MSpace.kWorld))
point2 = om.MVector(edge_iter.point(1, om.MSpace.kWorld))
intersection = calculate_intersection(plane_normal, plane_point, point1, point2)
if intersection is not None:
intersection_points.append(intersection)
edge_iter.next()
def sort_vectors_by_angle(
intersection_points: List[om.MVector],
center: om.MVector,
up: om.MVector,
) -> List[om.MVector]:
"""
Sort a list of MVector objects based on their angle to a reference vector.
"""
# Define a function that calculates the angle between a vector and the reference vector
def angle_to_reference(vector: om.MVector) -> float:
return up.angle(vector - center)
return sorted(intersection_points, key=angle_to_reference)
intersection_points = [A] + sort_vectors_by_angle(intersection_points + [B], A, up)
def calc_hull(
intersection_points: List[om.MVector], plane_normal: om.MVector
) -> List[om.MVector]:
stack = [intersection_points[0], intersection_points[1]]
def is_clockwise(pt: om.MVector) -> bool:
this = pt - stack[-1]
prev = stack[-1] - stack[-2]
return (prev ^ this) * plane_normal >= 0
for pt in intersection_points[2:]:
while not is_clockwise(pt):
stack.pop()
stack.append(pt)
return stack
def create_or_update_curve(name, vectors):
# Convert MVector points to a list of tuples
points = [(v.x, v.y, v.z) for v in vectors]
# Check if the curve object already exists
if cmds.objExists(name):
# If the curve exists, rebuild it with the new points
cmds.delete(name)
# Create a new NURBS curve
curve = cmds.curve(p=points, d=1, n=name)
return curve
def set_curve_appearance(curve_name, color_index, line_width):
"""
Set the appearance of a NURBS curve.
:param curve_name: Name of the NURBS curve.
:param color_index: Index of the color to set (e.g., 13 for red).
:param line_width: Width of the line in the viewport.
"""
shape_node = cmds.listRelatives(curve_name, shapes=True)[0]
# Enable drawing overrides
cmds.setAttr(f"{shape_node}.overrideEnabled", 1)
# Set the color
cmds.setAttr(f"{shape_node}.overrideColor", color_index)
# Set the line width (Note: This may not be visible in all viewport renderers)
cmds.setAttr(f"{shape_node}.lineWidth", line_width)
hull_points = calc_hull(intersection_points, plane_normal)
hull_points = hull_points[: hull_points.index(B) + 1]
curve_name = "hull_line"
create_or_update_curve(curve_name, hull_points)
# Make the curve red and thick
set_curve_appearance(curve_name, 13, 2) # 13 is typically the index for red
# cmds.delete(cmds.ls("intersection*") or [])
# for index, pt in enumerate(intersection_points):
# create_or_move_locator(f"intersection_{index}", pt)
#
#
# layer_name = "l_intersections"
# if not cmds.objExists(layer_name):
# cmds.createDisplayLayer(name=layer_name, empty=True)
# color_index_for_red = 13
# cmds.setAttr(f"{layer_name}.color", color_index_for_red)
# cmds.editDisplayLayerMembers(layer_name, cmds.ls("intersection*") or [])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment