diff --git a/BRIDGE_NOTES.md b/BRIDGE_NOTES.md index b00cd01..7295320 100644 --- a/BRIDGE_NOTES.md +++ b/BRIDGE_NOTES.md @@ -436,3 +436,137 @@ Effetto collaterale **voluto**: i Component "container" (zero body propri, solo 4. Mentre ci sei: ricontrolla la tabella `swapPC` (X/Y/A/PEN/Z) che era ancora `(da verificare)` - una volta caricata la mesh pulita ha senso chiudere anche quel loop e marcare gli esiti. Se ne emergono altre di geometrie fantasma su altri nodi, postale qui con il `fullPathName` del padre: il pattern e' lo stesso e dovrebbe essere coperto dal fix. + +--- + +## Findings dal viewer ATL (2026-06-18) — richiesta secondo script export per ATL + +Croce ha consegnato il primo export della **macchina ATL** (cartella `ATL/` sul mio server: `ATL.glb`, `hierarchy.json`, `joints.json`). Ho preparato la pagina consumer dedicata (`/atl`, login-protected) con drop GLB, tree gerarchia + hide/isolate per nodo, view presets top/front/side/iso, slider per i giunti animabili, diagnosi motion link. + +**Premessa importante:** l'export del plotter (`ExportKinematicGraph.py` attuale) funziona bene, NON va toccato. La richiesta è quindi **affiancare un secondo script di export dedicato all'ATL** (es. `ExportKinematicGraph_ATL.py` o un parametro `--profile=atl`), così le specificità del nuovo modello non rischiano di rompere la pipeline plotter che ormai è stabile. + +Sotto la lista dei problemi che ho trovato nel JSON ATL e che il nuovo script (o il profilo ATL) dovrebbe risolvere, in ordine di priorità. + +### 🔴 Bloccanti + +#### 1) `joints` array completamente vuoto + +Conteggi ATL: `joints: 0`, `asBuiltJoints: 18`, `motionLinks: 3`, `rigidGroups: 6`. Per il plotter avevamo `329 joints + 28 asBuilt`. Qui invece **tutto finisce in `asBuiltJoints`**. È intenzionale? Domanda da girare a Croce: nel modello ATL ha creato solo "As-built Joint" e nessun "Joint" canonico? Se sì, il viewer si adatta. In ogni caso lo script per ATL dovrebbe **loggare a console quanti joint trova in ciascuna sezione** per accorgersi di un export incompleto. + +#### 2) Nomi joint NON univoci → impossibile fare matching + +Nel `joints.json` di ATL c'è il nome `"Rivoluzione 5"` ripetuto **3 volte** con parent/child diversi: + +``` +Rivoluzione 5 (revolute) | tubo silicone:1 -> cuscinetto:1 +Rivoluzione 5 (revolute) | Componente45:1 -> cinesada:1 +Rivoluzione 5 (revolute) | (terza occorrenza) +``` + +I motion link puntano ai joint per nome (`joint1`/`joint2: ""`). Con duplicati il viewer non sa quale matchare e ne sceglie uno a caso. + +**Fix richiesto:** disambigua automaticamente i duplicati nell'export, es. `Rivoluzione 5`, `Rivoluzione 5#2`, `Rivoluzione 5#3`. Oppure usa il `entityToken` del Joint come tie-breaker e aggiungilo come campo `_token` accanto al `name`. + +#### 3) `origin` sempre `null` su tutti i revolute + +Per i revolute serve l'**origine del giunto** (il punto attorno a cui ruotare). Senza, il viewer ruota il pezzo attorno alla sua origine locale → schizza via dal perno del cuscinetto. Sugli slider non serve. + +Da estrarre per ogni `AsBuiltJoint` revolute: +- `joint.geometry.origin` se disponibile; +- altrimenti ricostruisci dalla `joint.entityOne` / `entityTwo` (centro del cilindro/cerchio) come fai già per i `Joint` canonici nello script plotter; +- converti in cm world consistenti con il resto (`internalUnit: cm`, `scaleFactor: 0.01`). + +#### 4) Joint orfano con `parent: null` e `child: null` + +``` +portellina cinesada (revolute) | parent: null | child: null | parentFullPath: null +``` + +Riferisce entità non più presenti nel modello. Gestione richiesta: o **scarta** loggando un warning, oppure emetti con un flag esplicito `"_orphan": true` così il consumer lo ignora senza ambiguità. + +### 🟡 Migliorabili + +#### 5) `axis` con rumore numerico ~1e-16 + +``` +Scorrimento 8 axis: [-1.388e-16, -5.169e-32, -1.0] +``` + +Snap a zero per componenti `|x| < 1e-9`. Altrimenti il viewer interpola jitter visibile sui movimenti lunghi. + +#### 6) `rotationLimits`/`slideLimits` ambigui + +Molti revolute (`Rivoluzione 5`, `feed`, ...) hanno `isMinimumValueEnabled=False`, `isMaximumValueEnabled=False` ma `minimumValue=0, maximumValue=0`. Significa "limiti disattivati" → il joint è libero, ma il consumer ingenuo legge `0..0` e lo crede bloccato. + +**Fix:** quando entrambi i flag `isMinimum/MaximumValueEnabled` sono false, emetti `rotationLimits: null` (o `{free: true, restValue: ...}`) invece di un range `0..0`. Il viewer attualmente filtra fuori i joint con `max - min < 1e-6`, quindi questi joint scompaiono dalla lista degli animabili pur essendo concettualmente liberi. + +#### 7) `motionLinks` tutti con `joint1: null` AND `joint2: null` + +Per il plotter almeno `joint2` (il driver) era valorizzato. Per ATL **tutti e 3** i motion link hanno entrambi i campi null → record completamente inutilizzabili: + +``` +Collegamento movimento 6 | joint1: null | joint2: null | reversed: true +Collegamento movimento 14 | joint1: null | joint2: null +Collegamento movimento 15 | joint1: null | joint2: null +``` + +Conferma con Croce: nel modello ATL i motion link sono stati creati e poi le entità rinominate? Se sì, niente è recuperabile da Python (limite API noto). Suggerimento minimo per lo script ATL: emetti almeno `entityOneToken` ed `entityTwoToken` come stringhe hex grezze, così l'utente che conosce il modello può fare matching manuale invece di vedere tre record vuoti. + +#### 8) Materiali: la fibra di carbonio nel GLB non rende bene + +Nel GLB i material complessi di Fusion arrivano appiattiti a baseColor + metallic/roughness di default. Per la fibra di carbonio servirebbe almeno: +- una **normal map** del weave (procedurale o tile texture) +- estensione `KHR_materials_anisotropy` +- baseColor `#1c1c1f`, metallic ~0.0, roughness ~0.4 + +Capisco che mappare 1:1 i material Fusion al PBR GLB è grosso. Workaround minimale richiesto: **emetti il nome del material Fusion originale** nel `hierarchy.json`, campo `materialName`, accanto al `color` che già c'è. Così il viewer fa il mapping nominale (`materialName == "Carbon Fiber" → PBR custom`) come faccio già per l'alluminio brushed. Senza il nome originale non posso distinguere "alluminio anonimo" da "fibra di carbonio anonima". + +#### 9) Body-per-body: conferma stato + +Il fix di body-per-body (sezione del 2026-06-10 in questo file) è attivo anche per questo export ATL? Sull'ATL non vedo geometrie fantasma evidenti, ma meglio sapere se la pipeline è quella aggiornata o no. Una linea di log in cima all'export del tipo `[export] body-per-body mode: ON` aiuta. + +#### 10) Nomi nodi GLB ↔ occurrence JSON: garanzia di match esatto + +Il viewer cerca l'`Object3D` nella scena per `name === occurrenceName` (es. `"Linear Guide Block LML9B(Specchio)(Specchio)(Specchio):1"`). Se Blender sanitizza i nomi (parentesi → underscore, spazi rimossi, ecc.) il match fallisce silenziosamente e lo slider non muove nulla. + +**Richiesta:** documenta esplicitamente che convenzione applica il pipeline ATL ai nomi nel GLB (sanitizzazione o byte-per-byte identici). Se ci sono trasformazioni, **emetti nel `hierarchy.json` un campo `glbNodeName`** con il nome effettivo del nodo nel GLB, così posso usarlo per fare lookup invece di indovinare. + +### ✅ OK così + +- Schema generale `hierarchy.json` (53 nodi, `parentFullPathName` coerenti) ✓ +- `transform` per ogni nodo presente ✓ +- `rigidGroups[].occurrenceNames` valorizzato (6 gruppi, 5–7 occorrenze ciascuno) ✓ +- Tipi joint: 8 rigid + 6 slider + 4 revolute → modello esportato + +### Priorità suggerita + +1. **#2 (nomi unici)** — impedisce qualunque motion link, anche manuale +2. **#3 (origin sui revolute)** — senza non si animano correttamente +3. **#1 + #7** — chiarisci con Croce perché ATL ha `joints=[]` e tutti i motion link vuoti (modello incompleto vs limite API) +4. **#5, #6** — quality-of-life dell'export +5. **#10** — chiarimento sulla sanitizzazione nomi GLB +6. **#8** — render fibra di carbonio (non urgente) + +### Forma proposta per il secondo script + +- Nome: `ExportKinematicGraph_ATL.py` (oppure aggiungi a `ExportKinematicGraph.py` un parametro `--profile=atl` se preferisci tenere un unico file). +- Output dell'utente: cartella `C:\Users\croce\OneDrive\Desktop\export_ATL\` (per non sovrascrivere quella del plotter). +- Consegna sul mio server: cartella `/home/marco/automation_kriz/ATL/` (stessa dove sono ora i file attuali). GLB → vado avanti a tenere il symlink `frontend/public/atl.glb -> ATL/ATL.glb` che ho già preparato. +- Le path lato Django sono già pronte: `/api/atl/hierarchy/`, `/api/atl/joints/`, `/atl.glb`. + +### Cosa NON serve fare + +- ❌ Toccare `ExportKinematicGraph.py` (versione plotter) — funziona bene così, niente regressioni richieste. +- ❌ Modifiche al GLB del plotter o ai suoi JSON. +- ❌ Modifiche al contratto `FUSION_GLB_CONTRACT.md`: le voci ATL stanno nello stesso schema, solo l'estrazione cambia. + +### TODO #3 — Aggiorna note dopo il fix + +Quando hai applicato i fix nel nuovo script ATL, aggiungi qui sotto una sezione "Verifica export ATL del 2026-06-XX" con: +- quali punti hai chiuso +- eventuali nuovi limiti API trovati +- conferma del re-export consegnato in `ATL/` + +Io rifaccio il giro su `/atl` e marco gli esiti. + +Grazie 🙏