""" 3D Model Validation Module Validates STL, STEP, and other 3D model formats """ import trimesh import numpy as np from typing import Dict, Any import os class ModelValidator: """Validates 3D models for manufacturing""" def __init__(self): self.supported_formats = ['.stl', '.obj', '.ply', '.gltf', '.glb'] def validate_model(self, file_path: str) -> Dict[str, Any]: """ Validate 3D model file Returns validation report with mesh integrity, wall thickness, etc. """ try: # Load mesh mesh = trimesh.load(file_path, force='mesh') # Validate mesh report = { 'file_path': file_path, 'file_type': os.path.splitext(file_path)[1].lower(), 'is_valid': True, 'file_size': os.path.getsize(file_path), 'mesh_integrity': 'PASS', 'warnings': [], 'errors': [], } # Check if mesh is valid if not mesh.is_valid: report['mesh_integrity'] = 'FAIL' report['is_valid'] = False report['errors'].append('Mesh is not valid (non-manifold geometry detected)') # Check for empty mesh if len(mesh.vertices) == 0: report['is_valid'] = False report['errors'].append('Mesh is empty') return report # Calculate mesh properties report['volume_mm3'] = mesh.volume report['bounding_box'] = { 'x': float(mesh.bounds[1][0] - mesh.bounds[0][0]), 'y': float(mesh.bounds[1][1] - mesh.bounds[0][1]), 'z': float(mesh.bounds[1][2] - mesh.bounds[0][2]), } # Check wall thickness (simple check) # For better results, would need voxelization or distance field wall_thickness = self._estimate_wall_thickness(mesh) report['min_wall_thickness_mm'] = wall_thickness if wall_thickness < 0.5: report['warnings'].append(f'Wall thickness is very thin ({wall_thickness}mm)') # Check for non-manifold edges if not mesh.is_watertight: report['warnings'].append('Mesh is not watertight (may have gaps)') # Generate slicing preview data (simplified) report['slicing_preview'] = { 'layer_count': int(report['bounding_box']['z'] / 0.2), 'suggested_support': not mesh.is_watertight, } return report except Exception as e: return { 'file_path': file_path, 'is_valid': False, 'errors': [str(e)], 'mesh_integrity': 'FAIL', } def _estimate_wall_thickness(self, mesh: trimesh.Trimesh) -> float: """Estimate minimum wall thickness""" # Simplified estimation # In production, use voxel-based thickness analysis vertices = mesh.vertices if len(vertices) < 3: return 0.0 # Calculate approximate minimum distance distances = [] for v in vertices[:100]: # Sample vertices closest_distance = np.min(np.linalg.norm(vertices - v, axis=1)[1:]) distances.append(closest_distance) return float(np.min(distances)) if distances else 0.1 if __name__ == '__main__': # Test example validator = ModelValidator() print("Model Validator initialized and ready for use")