AI-Friendly Geometry Validation
This document describes efficient methods for AI agents to validate 3D geometry results without relying on visual rendering.
The Problem
Humans validate geometry by looking at rendered images. AI agents cannot efficiently:
- Parse bitmap pixels to understand 3D structure
- Use vision models at scale for every test
- Detect subtle geometry errors from 2D projections
The Solution: Use HiScene JSON
The best approach is to export HiScene - FCS's internal scene format. See 09-HISCENE-FORMAT.md for complete documentation.
# Export HiScene from fli.exe
fli.exe model.fcs "Main" --t 3JS --o output.hiscene.json
HiScene provides:
- Exact vertex coordinates as flat arrays
- Face topology - which vertices connect to which faces
- Edge/line data - wireframe geometry
- Material assignments - colors, transparency
- Named class hierarchy - semantic structure
Alternative: Geometric Fingerprints
For simpler validation without full scene export, extract numeric properties that characterize the geometry:
1. Topology Counts (Integers)
# Query these via fli.exe
validation := {
vertex_count := assembly.Vertices.Count,
curve_count := assembly.Curves.Count,
area_count := assembly.Areas.Count,
volume_count := assembly.Volumes.Count
}
Test assertion example:
{
"expected_vertices": 8,
"expected_curves": 12,
"expected_areas": 6
}
2. Bounding Box (6 numbers)
The axis-aligned bounding box captures overall shape extents:
bbox := Fcs.Geometry.BoundingBox(assembly)
# Access: bbox.Min.X, bbox.Min.Y, bbox.Min.Z
# bbox.Max.X, bbox.Max.Y, bbox.Max.Z
Fingerprint:
{
"bbox_min": [0, 0, 0],
"bbox_max": [10, 5, 3],
"tolerance": 0.001
}
3. Geometric Invariants (Single numbers)
| Property | Description | FCS Query |
|---|---|---|
| Total curve length | Sum of all edge lengths | curves.Select(c => c.Geometry.Length).Sum |
| Total area | Sum of all surface areas | areas.Select(a => a.Geometry.Area).Sum |
| Centroid | Center of mass | assembly.Centroid |
| Diagonal | Bounding box diagonal | Sqrt((bbox.Max.X-bbox.Min.X)^2 + ...) |
4. Vertex Coordinate Dump (Full geometry)
For exact validation, dump all vertex coordinates as text:
# Create parseable output
vertex_dump := vertices.Select(v => [v.X, v.Y, v.Z])
Expected format:
[[0,0,0], [10,0,0], [10,5,0], [0,5,0], ...]
5. Connectivity Matrix (Topology)
For structural models, validate element connectivity:
# Which vertices connect to which curves
connectivity := curves.Select(c => [c.StartVertex.Id, c.EndVertex.Id])
Validation Test Format
Simple Test (Numeric Invariants)
{
"id": "test-007-box-geometry",
"model": "simple_box.fcs",
"validation": {
"type": "invariants",
"checks": [
{ "expr": "vertices.Count", "expected": 8 },
{ "expr": "curves.Count", "expected": 12 },
{ "expr": "areas.Count", "expected": 6 },
{ "expr": "bbox.Max.X - bbox.Min.X", "expected": 10, "tolerance": 0.001 }
]
}
}
Full Geometry Test (Hash-based)
{
"id": "test-008-complex-model",
"model": "cooling_tower.fcs",
"validation": {
"type": "geometry-hash",
"expression": "Fcs.Geometry.Hash(assembly)",
"expected_hash": "a7f3b2c1d4e5..."
}
}
Comparison: Visual vs Numeric Validation
| Aspect | Visual (PNG) | Numeric (Invariants) |
|---|---|---|
| File size | ~50KB-500KB | ~100 bytes |
| Parse time | Requires vision model | Direct comparison |
| Precision | Pixel-level artifacts | Exact to machine epsilon |
| 3D depth | Lost in 2D projection | Fully preserved |
| Rotation invariance | ✗ (view-dependent) | ✓ (intrinsic properties) |
| AI-friendly | ✗ | ✓ |
Implementation Pattern
1. Define Expected Invariants
# In test-model-expected.fcs
expected := {
vertex_count := 4,
bbox_size := [10, 5, 0],
total_length := 30,
centroid := [5, 2.5, 0]
}
2. Query Actual Model
fli.exe model.fcs "vertices.Count"
fli.exe model.fcs "[bbox.Max.X - bbox.Min.X, bbox.Max.Y - bbox.Min.Y, bbox.Max.Z - bbox.Min.Z]"
fli.exe model.fcs "curves.Select(c => c.Geometry.Length).Sum"
3. Compare in Test Runner
$actual_count = & $fli $model "vertices.Count" | Select-Object -Last 1
$expected_count = 4
if ($actual_count -ne $expected_count) {
Write-Host "FAIL: vertex count $actual_count != $expected_count"
}
Advanced: Projection Fingerprints
If you truly need 2D projection validation, use coordinate projections not images:
# Project vertices to XY plane and compute basic stats
xy_projection := vertices.Select(v => [v.X, v.Y])
xy_centroid := [xy_projection.Select(p => p[0]).Average, xy_projection.Select(p => p[1]).Average]
xy_spread := xy_projection.Select(p => Sqrt(p[0]^2 + p[1]^2)).Max
This gives you:
- XY view centroid
- Maximum extent from origin
- All without rendering pixels
Summary
For AI agents, numbers beat pixels. Use:
- HiScene JSON - Complete 3D scene with exact geometry (best! see 09-HISCENE-FORMAT.md)
- Topology counts - vertex/curve/area counts
- Bounding box - 6 numbers capture overall shape
- Geometric invariants - total length, area, centroid
- Coordinate dumps - full vertex list for exact match
- Connectivity - topology relationships
This approach is:
- 10-100x smaller than image data
- Exact (no rasterization artifacts)
- Directly comparable (no vision model needed)
- 3D-complete (no information lost to projection)