Files
filam3d/backend/app/services/file_parser.py
2026-03-22 12:40:33 +03:00

63 lines
2.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
)