78 lines
3.0 KiB
Python
78 lines
3.0 KiB
Python
import bpy
|
|
import mathutils
|
|
from mathutils import Vector
|
|
from bpy_extras import view3d_utils
|
|
|
|
|
|
#### ------------------------------ FUNCTIONS ------------------------------ ####
|
|
|
|
def distance_from_point_to_segment(point, start, end) -> float:
|
|
"""
|
|
Calculates the shortest distance between a point and a segment.
|
|
All three inputs should be `mathutils.Vector` objects.
|
|
This is an alternative to `mathutils.geometry.intersect_point_line`.
|
|
Adapted from "Blockout" extension by niewinny (https://github.com/niewinny/blockout).
|
|
"""
|
|
|
|
segment = end - start
|
|
start_to_point = point - start
|
|
|
|
# projection_along_segment
|
|
c1 = start_to_point.dot(segment)
|
|
if c1 <= 0:
|
|
return (point - start).length
|
|
|
|
# segment_length_squared
|
|
c2 = segment.dot(segment)
|
|
if c2 <= c1:
|
|
return (point - end).length
|
|
|
|
t = c1 / c2
|
|
closest_point = start + t * segment
|
|
distance = (point - closest_point).length
|
|
|
|
return distance
|
|
|
|
|
|
def region_2d_to_line_3d(region, rv3d, point_2d: Vector, line_origin: Vector, line_direction: Vector) -> tuple[Vector, Vector]:
|
|
"""
|
|
Converts a 2D screen-space point into a 3D ray and finds closest
|
|
points between that ray and a given 3D line.
|
|
"""
|
|
|
|
if line_origin is None or line_direction is None:
|
|
return None, None
|
|
|
|
# Convert the screen-space 2D point Vector into a world-space 3D ray (origin + direction).
|
|
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, point_2d)
|
|
ray_direction = view3d_utils.region_2d_to_vector_3d(region, rv3d, point_2d)
|
|
|
|
# Find closest points to each other on each line (second line being a ray).
|
|
closest_points = mathutils.geometry.intersect_line_line(ray_origin,
|
|
ray_origin + ray_direction,
|
|
line_origin,
|
|
line_origin + line_direction)
|
|
|
|
return closest_points
|
|
|
|
|
|
def region_2d_to_plane_3d(region, rv3d, point_2d: Vector, plane: tuple[Vector]) -> Vector:
|
|
"""
|
|
Converts a 2D screen-space point into a 3D point on a plane in world-space.
|
|
Adapted from "Blockout" extension by niewinny (https://github.com/niewinny/blockout).
|
|
"""
|
|
|
|
location, normal = plane
|
|
|
|
# Convert the screen-space 2D point Vector into a world-space 3D ray (origin + direction).
|
|
p3_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, point_2d)
|
|
p3_direction = view3d_utils.region_2d_to_vector_3d(region, rv3d, point_2d)
|
|
|
|
# Intersect the point with the plane.
|
|
p3_on_plane = mathutils.geometry.intersect_line_plane(p3_origin, # First point of line.
|
|
p3_origin + p3_direction, # Second point of line.
|
|
location, # `plane_co` (a point on the plane).
|
|
normal) # `plane_no` (the direction the plane is facing).
|
|
|
|
return p3_on_plane
|