Files
PozzettiAndrea-ComfyUI-Geom…/assets/libigl-tutorial-data/test_intersections.py
T
2025-11-14 22:04:06 +01:00

192 lines
5.6 KiB
Python

#!/usr/bin/env python3
"""
Test all meshes in this directory for self-intersections using libigl CGAL.
Reports which meshes have self-intersections and their statistics.
"""
import os
import sys
import numpy as np
import trimesh
def test_self_intersections(filepath):
"""
Test a mesh file for self-intersections using libigl CGAL.
Returns:
tuple: (has_intersections, num_intersection_pairs, num_intersecting_faces, error_msg)
"""
try:
# Load mesh
mesh = trimesh.load(filepath, force='mesh', process=False)
if not isinstance(mesh, trimesh.Trimesh):
return (False, 0, 0, "Not a single mesh object")
# Try to use libigl with CGAL
try:
import igl
import igl.copyleft.cgal as cgal
if not hasattr(cgal, 'remesh_self_intersections'):
return (False, 0, 0, "CGAL remesh_self_intersections not available")
except (ImportError, AttributeError) as e:
return (False, 0, 0, f"libigl CGAL not available: {e}")
# Convert to numpy arrays (note: libigl requires int64 for faces)
V = np.asarray(mesh.vertices, dtype=np.float64)
F = np.asarray(mesh.faces, dtype=np.int64)
# Run detection with keyword arguments
try:
# Call remesh_self_intersections with detect_only=True
VV, FF, IF, J, IM = cgal.remesh_self_intersections(
V, F,
detect_only=True,
first_only=False,
stitch_all=False
)
# IF contains pairs of intersecting faces [n x 2]
num_intersection_pairs = IF.shape[0] if IF is not None and hasattr(IF, 'shape') else 0
if num_intersection_pairs > 0:
# Get unique face indices
intersecting_faces = np.unique(IF.flatten())
num_intersecting_faces = len(intersecting_faces)
return (True, num_intersection_pairs, num_intersecting_faces, "")
else:
return (False, 0, 0, "")
except Exception as e:
return (False, 0, 0, f"Detection error: {e}")
except Exception as e:
return (False, 0, 0, f"Load error: {e}")
def main():
script_dir = os.path.dirname(os.path.abspath(__file__))
print("=" * 80)
print("Testing Meshes for Self-Intersections")
print("=" * 80)
print()
# Find all mesh files
mesh_extensions = ['.obj', '.off', '.mesh', '.stl', '.ply']
mesh_files = []
for filename in sorted(os.listdir(script_dir)):
ext = os.path.splitext(filename)[1].lower()
if ext in mesh_extensions:
mesh_files.append(filename)
if not mesh_files:
print("No mesh files found!")
return
print(f"Found {len(mesh_files)} mesh files to test:")
for f in mesh_files:
print(f" - {f}")
print()
# Test each mesh
results = []
print("Testing...")
print("-" * 80)
for filename in mesh_files:
filepath = os.path.join(script_dir, filename)
print(f"Testing {filename}...", end=" ")
sys.stdout.flush()
has_intersections, num_pairs, num_faces, error = test_self_intersections(filepath)
results.append({
'filename': filename,
'has_intersections': has_intersections,
'num_pairs': num_pairs,
'num_faces': num_faces,
'error': error
})
if error:
print(f"ERROR: {error}")
elif has_intersections:
print(f"✓ SELF-INTERSECTING ({num_pairs} pairs, {num_faces} faces)")
else:
print("✓ Clean (no intersections)")
print()
print("=" * 80)
print("SUMMARY")
print("=" * 80)
print()
# Separate into categories
self_intersecting = [r for r in results if r['has_intersections']]
clean = [r for r in results if not r['has_intersections'] and not r['error']]
errors = [r for r in results if r['error']]
print(f"Total meshes tested: {len(results)}")
print(f"Self-intersecting: {len(self_intersecting)}")
print(f"Clean: {len(clean)}")
print(f"Errors: {len(errors)}")
print()
if self_intersecting:
print("Self-Intersecting Meshes (KEEP THESE):")
print("-" * 80)
for r in self_intersecting:
print(f" ✓ {r['filename']}")
print(f" Intersection pairs: {r['num_pairs']}")
print(f" Intersecting faces: {r['num_faces']}")
print()
if clean:
print("Clean Meshes (DELETE THESE):")
print("-" * 80)
for r in clean:
print(f" ✗ {r['filename']}")
print()
if errors:
print("Errors:")
print("-" * 80)
for r in errors:
print(f" ? {r['filename']}: {r['error']}")
print()
# Save results to file
results_file = os.path.join(script_dir, "intersection_test_results.txt")
with open(results_file, 'w') as f:
f.write("Self-Intersection Test Results\n")
f.write("=" * 80 + "\n\n")
f.write("KEEP (Self-Intersecting):\n")
for r in self_intersecting:
f.write(f" {r['filename']} - {r['num_pairs']} pairs, {r['num_faces']} faces\n")
f.write("\n")
f.write("DELETE (Clean):\n")
for r in clean:
f.write(f" {r['filename']}\n")
f.write("\n")
if errors:
f.write("ERRORS:\n")
for r in errors:
f.write(f" {r['filename']}: {r['error']}\n")
print(f"Results saved to: {results_file}")
print()
return results
if __name__ == "__main__":
results = main()