146 lines
4.6 KiB
Python
146 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
SUW Core - Geometry Utils Module
|
||
拆分自: suw_impl.py (Line 606-732)
|
||
用途: 3D几何类(Point3d、Vector3d、Transformation)和材质类型常量
|
||
版本: 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 # 薄材质
|