onshape-to-robot/onshape_to_robot/processor_simplify_stls.py
Upstream Snapshot bb87928bce Import upstream snapshot 80e710700aac9573a2230f74f7ce9e094833a0bc
Upstream: https://github.com/Rhoban/onshape-to-robot
Upstream-Commit: 80e710700aac9573a2230f74f7ce9e094833a0bc
Upstream-Branch: master
2026-08-28 15:42:31 +08:00

90 lines
2.9 KiB
Python

import os
from .config import Config
from .robot import Robot
from .processor import Processor
from .message import bright, info, error
class ProcessorSimplifySTLs(Processor):
"""
Allow for mesh simplifications using MeshLab
"""
def __init__(self, config: Config):
super().__init__(config)
# STL merge / simplification
self.simplify_stls = config.get("simplify_stls", False)
self.max_stl_size = config.get("max_stl_size", 3)
if self.simplify_stls:
self.pymeshlab = self.check_meshlab()
def check_meshlab(self):
print(bright("* Checking pymeshlab presence..."))
try:
import pymeshlab
return pymeshlab
except ImportError:
self.simplify_stls = False
print(error("No pymeshlab, disabling STL simplification support"))
print(info("TIP: consider installing pymeshlab:"))
print(info("pip install pymeshlab"))
def process(self, robot: Robot):
if self.simplify_stls:
simplify_all = (
self.simplify_stls != "visual" and self.simplify_stls != "collision"
)
simplified = set()
getcwd = os.getcwd()
# Changing directory to output to have relative paths working
os.chdir(self.config.output_directory)
for link in robot.links:
for part in link.parts:
for mesh in part.meshes:
if (
simplify_all or mesh.is_type(self.simplify_stls)
) and mesh.filename not in simplified:
simplified.add(mesh.filename)
self.simplify_stl(mesh.filename)
os.chdir(getcwd)
def reduce_faces(self, filename: str, reduction: float = 0.9):
mesh_set = self.pymeshlab.MeshSet()
# Add input mesh
mesh_set.load_new_mesh(filename)
# Apply filter
mesh_set.apply_filter(
"meshing_decimation_quadric_edge_collapse",
targetperc=reduction,
qualitythr=0.5,
preserveboundary=False,
boundaryweight=1,
preservenormal=True,
preservetopology=False,
optimalplacement=True,
planarquadric=True,
qualityweight=False,
planarweight=0.001,
autoclean=True,
selected=False,
)
# Save mesh
mesh_set.save_current_mesh(filename)
def simplify_stl(self, filename: str):
size_M = os.path.getsize(filename) / (1024 * 1024)
if size_M > self.max_stl_size:
print(
info(
f"+ {os.path.basename(filename)} is {size_M:.2f} M, running mesh simplification"
)
)
self.reduce_faces(filename, self.max_stl_size / size_M)