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
This commit is contained in:
106
processing/model_validator.py
Normal file
106
processing/model_validator.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
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")
|
||||
6
processing/requirements.txt
Normal file
6
processing/requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
trimesh==4.1.0
|
||||
numpy==1.24.3
|
||||
scipy==1.11.2
|
||||
Pillow==10.0.0
|
||||
requests==2.31.0
|
||||
python-dotenv==1.0.0
|
||||
Reference in New Issue
Block a user