Created
December 7, 2023 22:52
-
-
Save viktorasm/588ce45e8d637ce0f49ae7ad7d4767cd to your computer and use it in GitHub Desktop.
path from a to b, chatgpt edition
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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