122 lines
3.5 KiB
Python
122 lines
3.5 KiB
Python
# SPDX-FileCopyrightText: 2025 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import bpy
|
|
from mathutils import Vector
|
|
from typing import List, Tuple
|
|
|
|
|
|
def clamp(val, _min=0, _max=1) -> float or int:
|
|
if val < _min:
|
|
return _min
|
|
if val > _max:
|
|
return _max
|
|
return val
|
|
|
|
|
|
def get_lattice_vertex_index(lattice: bpy.types.Lattice, xyz: List[int], do_clamp=True) -> int:
|
|
"""Get the index of a lattice vertex based on its position on the XYZ axes."""
|
|
|
|
# The lattice vertex indicies start in the -Y, -X, -Z corner,
|
|
# increase on X+, then moves to the next row on Y+, then moves up on Z+.
|
|
res_x, res_y, res_z = lattice.points_u, lattice.points_v, lattice.points_w
|
|
x, y, z = xyz[:]
|
|
if do_clamp:
|
|
x = clamp(x, 0, res_x)
|
|
y = clamp(y, 0, res_y)
|
|
z = clamp(z, 0, res_z)
|
|
|
|
assert x < res_x and y < res_y and z < res_z, "Error: Lattice vertex xyz index out of bounds"
|
|
|
|
index = (z * res_y * res_x) + (y * res_x) + x
|
|
return index
|
|
|
|
|
|
def get_lattice_vertex_xyz_position(lattice: bpy.types.Lattice, index: int) -> (int, int, int):
|
|
res_x, res_y, res_z = lattice.points_u, lattice.points_v, lattice.points_w
|
|
|
|
x = 0
|
|
remaining = index
|
|
z = int(remaining / (res_x * res_y))
|
|
remaining -= z * (res_x * res_y)
|
|
y = int(remaining / res_x)
|
|
remaining -= y * res_x
|
|
x = remaining # Maybe need to add or subtract 1 here?
|
|
|
|
return (x, y, z)
|
|
|
|
|
|
def get_lattice_point_original_position(lattice: bpy.types.Lattice, index: int) -> Vector:
|
|
"""Reset a lattice vertex to its original position."""
|
|
start_vec = Vector((-0.5, -0.5, -0.5))
|
|
if lattice.points_u == 1:
|
|
start_vec[0] = 0
|
|
if lattice.points_v == 1:
|
|
start_vec[1] = 0
|
|
if lattice.points_w == 1:
|
|
start_vec[2] = 0
|
|
|
|
unit_u = 1 / (lattice.points_u - 0.99)
|
|
unit_v = 1 / (lattice.points_v - 0.99)
|
|
unit_w = 1 / (lattice.points_w - 0.99)
|
|
|
|
unit_vec = Vector((unit_u, unit_v, unit_w))
|
|
xyz_vec = Vector(get_lattice_vertex_xyz_position(lattice, index))
|
|
|
|
return start_vec + xyz_vec * unit_vec
|
|
|
|
|
|
def simple_driver(
|
|
owner: bpy.types.ID,
|
|
driver_path: str,
|
|
target_ob: bpy.types.Object,
|
|
data_path: str,
|
|
array_index=-1,
|
|
) -> bpy.types.Driver:
|
|
if array_index > -1:
|
|
owner.driver_remove(driver_path, array_index)
|
|
driver = owner.driver_add(driver_path, array_index).driver
|
|
else:
|
|
owner.driver_remove(driver_path)
|
|
driver = owner.driver_add(driver_path).driver
|
|
|
|
driver.expression = 'var'
|
|
var = driver.variables.new()
|
|
var.targets[0].id = target_ob
|
|
var.targets[0].data_path = data_path
|
|
|
|
return driver
|
|
|
|
|
|
def bounding_box(points) -> Tuple[Vector, Vector]:
|
|
"""Return two vectors representing the lowest and highest coordinates of
|
|
a the bounding box of the passed points.
|
|
"""
|
|
|
|
lowest = points[0].copy()
|
|
highest = points[0].copy()
|
|
for p in points:
|
|
for i in range(len(p)):
|
|
if p[i] < lowest[i]:
|
|
lowest[i] = p[i]
|
|
if p[i] > highest[i]:
|
|
highest[i] = p[i]
|
|
|
|
return lowest, highest
|
|
|
|
|
|
def bounding_box_center(points) -> Vector:
|
|
"""Find the bounding box center of some points."""
|
|
bbox_low, bbox_high = bounding_box(points)
|
|
return bbox_low + (bbox_high - bbox_low) / 2
|
|
|
|
|
|
def bounding_box_center_of_objects(objects) -> Vector:
|
|
"""Find the bounding box center of some objects."""
|
|
all_points = []
|
|
for o in objects:
|
|
for p in o.bound_box:
|
|
all_points.append(o.matrix_world @ Vector(p))
|
|
return bounding_box_center(all_points)
|