blenderpython/suw_core/geometry_utils.py

146 lines
4.6 KiB
Python
Raw Normal View History

2025-08-01 17:13:30 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SUW Core - Geometry Utils Module
拆分自: suw_impl.py (Line 606-732)
用途: 3D几何类Point3dVector3dTransformation和材质类型常量
版本: 1.0.0
作者: SUWood Team
"""
import re
import math
from typing import Dict, Optional
# ==================== 几何类扩展 ====================
class Point3d:
"""3D点类 - 对应Ruby的Geom::Point3d"""
def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0):
self.x = x
self.y = y
self.z = z
@classmethod
def parse(cls, value: str):
"""从字符串解析3D点"""
if not value or value.strip() == "":
return None
# 解析格式: "(x,y,z)" 或 "x,y,z"
clean_value = re.sub(r'[()]*', '', value)
xyz = [float(axis.strip()) for axis in clean_value.split(',')]
# 转换mm为内部单位假设输入是mm
return cls(xyz[0] * 0.001, xyz[1] * 0.001, xyz[2] * 0.001)
def to_s(self, unit: str = "mm", digits: int = -1) -> str:
"""转换为字符串"""
if unit == "cm":
x_val = self.x * 100 # 内部单位转换为cm
y_val = self.y * 100
z_val = self.z * 100
return f"({x_val:.3f}, {y_val:.3f}, {z_val:.3f})"
else: # mm
x_val = self.x * 1000 # 内部单位转换为mm
y_val = self.y * 1000
z_val = self.z * 1000
if digits == -1:
return f"({x_val}, {y_val}, {z_val})"
else:
return f"({x_val:.{digits}f}, {y_val:.{digits}f}, {z_val:.{digits}f})"
def __str__(self):
return self.to_s()
def __repr__(self):
return f"Point3d({self.x}, {self.y}, {self.z})"
class Vector3d:
"""3D向量类 - 对应Ruby的Geom::Vector3d"""
def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0):
self.x = x
self.y = y
self.z = z
@classmethod
def parse(cls, value: str):
"""从字符串解析3D向量"""
if not value or value.strip() == "":
return None
clean_value = re.sub(r'[()]*', '', value)
xyz = [float(axis.strip()) for axis in clean_value.split(',')]
return cls(xyz[0] * 0.001, xyz[1] * 0.001, xyz[2] * 0.001)
def to_s(self, unit: str = "mm") -> str:
"""转换为字符串"""
if unit == "cm":
x_val = self.x * 100 # 内部单位转换为cm
y_val = self.y * 100
z_val = self.z * 100
return f"({x_val:.3f}, {y_val:.3f}, {z_val:.3f})"
elif unit == "in":
return f"({self.x}, {self.y}, {self.z})"
else: # mm
x_val = self.x * 1000 # 内部单位转换为mm
y_val = self.y * 1000
z_val = self.z * 1000
return f"({x_val}, {y_val}, {z_val})"
def normalize(self):
"""归一化向量"""
length = math.sqrt(self.x**2 + self.y**2 + self.z**2)
if length > 0:
return Vector3d(self.x/length, self.y/length, self.z/length)
return Vector3d(0, 0, 0)
def __str__(self):
return self.to_s()
class Transformation:
"""变换矩阵类 - 对应Ruby的Geom::Transformation"""
def __init__(self, origin: Point3d = None, x_axis: Vector3d = None,
y_axis: Vector3d = None, z_axis: Vector3d = None):
self.origin = origin or Point3d(0, 0, 0)
self.x_axis = x_axis or Vector3d(1, 0, 0)
self.y_axis = y_axis or Vector3d(0, 1, 0)
self.z_axis = z_axis or Vector3d(0, 0, 1)
@classmethod
def parse(cls, data: Dict[str, str]):
"""从字典解析变换"""
origin = Point3d.parse(data.get("o"))
x_axis = Vector3d.parse(data.get("x"))
y_axis = Vector3d.parse(data.get("y"))
z_axis = Vector3d.parse(data.get("z"))
return cls(origin, x_axis, y_axis, z_axis)
def store(self, data: Dict[str, str]):
"""存储变换到字典"""
data["o"] = self.origin.to_s("mm")
data["x"] = self.x_axis.to_s("in")
data["y"] = self.y_axis.to_s("in")
data["z"] = self.z_axis.to_s("in")
# ==================== 材质类型常量 ====================
# 基础材质类型从suw_impl.py Line 725-727拆分
MAT_TYPE_NORMAL = 0 # 普通材质
MAT_TYPE_OBVERSE = 1 # 正面材质
MAT_TYPE_NATURE = 2 # 自然材质
# 扩展材质类型(为兼容性添加)
MAT_TYPE_REVERSE = 3 # 反面材质
MAT_TYPE_THIN = 4 # 薄材质