This commit is contained in:
xds
2026-03-22 12:40:33 +03:00
commit 28a5d51389
61 changed files with 6085 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
import logging
from dataclasses import dataclass
import trimesh
logger = logging.getLogger("app.services.file_parser")
@dataclass
class FileInfo:
volume_cm3: float
surface_area_cm2: float
bounding_box_mm: dict[str, float]
is_watertight: bool
triangle_count: int
SUPPORTED_EXTENSIONS = {".stl", ".3mf", ".obj"}
def parse_3d_file(file_path: str, file_extension: str) -> FileInfo:
"""Parse a 3D file and return geometric properties."""
ext = file_extension.lower().lstrip(".")
logger.info("Parsing 3D file: path=%s, extension=%s", file_path, ext)
logger.debug("Loading mesh with trimesh (file_type=%s)...", ext)
mesh = trimesh.load(file_path, file_type=ext)
logger.debug("Trimesh loaded object type: %s", type(mesh).__name__)
if isinstance(mesh, trimesh.Scene):
meshes = list(mesh.dump())
logger.info("File is a Scene with %d geometries, concatenating...", len(meshes))
if not meshes:
logger.error("Scene contains no geometries")
raise ValueError("Файл не содержит 3D-геометрии")
mesh = trimesh.util.concatenate(meshes)
logger.debug("Concatenated into single Trimesh")
if not isinstance(mesh, trimesh.Trimesh):
logger.error("Could not extract Trimesh object, got: %s", type(mesh).__name__)
raise ValueError("Не удалось извлечь 3D-геометрию из файла")
volume_cm3 = abs(mesh.volume) / 1000.0
surface_area_cm2 = mesh.area / 100.0
bbox = {
"x": round(float(mesh.bounding_box.extents[0]), 2),
"y": round(float(mesh.bounding_box.extents[1]), 2),
"z": round(float(mesh.bounding_box.extents[2]), 2),
}
is_watertight = bool(mesh.is_watertight)
triangle_count = len(mesh.faces)
logger.info("Parse result: volume=%.2f cm3, area=%.2f cm2, bbox=%s, watertight=%s, triangles=%d",
volume_cm3, surface_area_cm2, bbox, is_watertight, triangle_count)
return FileInfo(
volume_cm3=volume_cm3,
surface_area_cm2=surface_area_cm2,
bounding_box_mm=bbox,
is_watertight=is_watertight,
triangle_count=triangle_count,
)