Files
Aggregator/processing/model_validator.py
Semen_Babenishev 4420c5c60a Initial: Nutshell Site Aggregator MVP Phase 1
- Backend: Express + TypeORM + PostgreSQL, JWT + OTP auth
- Frontend: React + Vite + Tailwind, 4 pages (Home/Login/Orders/404)
- Docker Compose: PostgreSQL 15 on port 5434
- Tests: 16 tests passing (API + Frontend)
- ai_state: rules.md, INSTRUCTIONS.md, session tasks
- Examples: brand book PDF, logos, page mockups
2026-07-16 11:38:08 +04:00

107 lines
3.5 KiB
Python

"""
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")