From 5b11b3e8ca4269ba73ee59e967b77a4d89edf96c Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Wed, 21 Oct 2026 15:58:15 +0200 Subject: [PATCH] Documenta la decodifica dei .prt: albero delle feature, quote e geometria Reverse engineering di test.prt.1, 9252000507.prt e 9239901907.prt contro il model tree di Creo: contenitore e sezioni, ricostruzione dell'albero (nomi per contatore, gruppi, sezioni), numeri compatti, quote, foro, smusso e vincoli dei piani, con la tabella di cosa resta da decodificare. Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 5 + docs/README.md | 4 + docs/formato-prt-feature.md | Bin 0 -> 26458 bytes docs/formato-prt-geometria.md | 425 ++++++++++++++++++++++++++++++++++ 4 files changed, 434 insertions(+) create mode 100644 docs/formato-prt-feature.md create mode 100644 docs/formato-prt-geometria.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 071ddf5..bc018ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ aderisce a [Semantic Versioning](https://semver.org/lang/it/). ## [Non rilasciato] +### Aggiunto + +- `docs/formato-prt-feature.md`: decodifica (da reverse engineering) dell'albero delle feature di un `.prt`. +- `docs/formato-prt-geometria.md`: numeri, quote e geometria degli schizzi di un `.prt`, con la tabella di cosa resta da decodificare. + ## [1.1.0] - 2026-10-07 ### Aggiunto diff --git a/docs/README.md b/docs/README.md index 888e7e6..4d8d3e1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,6 +20,8 @@ e cambia solo quando cambia il programma. - [`db-cad-index.md`](db-cad-index.md) — schema, vista e query di `cad_index.db`. - [`formato-asm-record.md`](formato-asm-record.md) — parser esatto dei record `.asm`, casi limite (§7). - [`formato-asm.md`](formato-asm.md) — euristica testuale di fallback. +- [`formato-prt-feature.md`](formato-prt-feature.md) — come leggere l'albero delle feature di un `.prt` (reverse engineering, non ancora nel codice). +- [`formato-prt-geometria.md`](formato-prt-geometria.md) — numeri, quote e geometria degli schizzi di un `.prt`, con la tabella di cosa manca per determinarlo per intero. - [`glossario.md`](glossario.md) — i termini usati nei doc e nell'app. - [`../CHANGELOG.md`](../CHANGELOG.md) — storico delle versioni. @@ -37,6 +39,8 @@ Ogni informazione vive in **un** posto; altrove si mette un link, non una copia. | Versione e nome prodotto | `PrepStep/PrepStep.csproj` (``, ``) | | Schema e vista del DB | [`db-cad-index.md`](db-cad-index.md) | | Formato dei record `.asm` e casi limite | [`formato-asm-record.md`](formato-asm-record.md) | +| Albero delle feature di un `.prt` | [`formato-prt-feature.md`](formato-prt-feature.md) | +| Quote, coordinate e geometria degli schizzi di un `.prt` | [`formato-prt-geometria.md`](formato-prt-geometria.md) | | Processo delle 5 fasi, mappa dei file | [`architettura.md`](architettura.md) | | Passi dell'utente | [`guida-utente.md`](guida-utente.md) | | Build, test, regole sui doc | [`sviluppo.md`](sviluppo.md) | diff --git a/docs/formato-prt-feature.md b/docs/formato-prt-feature.md new file mode 100644 index 0000000000000000000000000000000000000000..13195403b53630cb5a38604280c549f64cd8d30e GIT binary patch literal 26458 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 XD7STH!bCL(_oX!rMEoz3tgrn)wl@BK literal 0 HcmV?d00001 diff --git a/docs/formato-prt-geometria.md b/docs/formato-prt-geometria.md new file mode 100644 index 0000000..105ce44 --- /dev/null +++ b/docs/formato-prt-geometria.md @@ -0,0 +1,425 @@ +# Decodifica del `.prt` Creo: numeri, quote e geometria degli schizzi + +Seguito di [`formato-prt-feature.md`](formato-prt-feature.md), che spiega come trovare le sezioni +del file e leggere l'**albero** delle feature (ordine, tipo, nome). Qui: come leggere i **numeri** +(quote, coordinate) e come ricostruire da quelli la forma di una feature. + +**Stato, da leggere prima di fidarsi.** Questo doc contiene *tutto quello che è stato decodificato +e verificato*, e dice per ogni cosa quanto è provata. **Non basta ancora a determinare in modo +univoco com'è fatto un `.prt`**: manca il posizionamento delle feature nello spazio e il +significato certo di alcuni codici (§7 elenca cosa manca, dove sta nel file, e come finire il +lavoro). Nessun codice del progetto lo usa: è reverse engineering fatto con script di prova. + +Livelli di prova, come negli altri doc: + +1. **Contro Creo** (schermate del modello aperto): `9252000507.prt.11`, feature *Rivoluzione 1* + (§5). Quote e coordinate dello schizzo coincidono con quelle mostrate da Creo. +2. **Coerenza e plausibilità**: `test.prt.1` e le altre feature di `9252000507.prt.11`. I valori + sono numeri "tondi" e coerenti fra sezioni diverse, ma nessuno li ha confrontati con Creo. + +## 1. Come sono scritti i numeri reali + +Nelle sezioni a marcatori ([`formato-asm-record.md`](formato-asm-record.md) §2) i `double` sono +scritti in forma compatta. Si distinguono per il primo byte, `tag`: + +| Tag (hex) | Byte dopo il tag | Valore | Prova | +|---|---|---|---| +| `18` | 0 | `0.0` | in ogni sezione | +| `0f` | 0 | `1.0` | diagonale delle matrici identità | +| `0e` | 0 | `0.5` | **livello 1**: la quota di *Smusso 1* (D = 0.500) è il solo byte `0e` | +| `10` | 0 | `-1.0` | ipotesi dal contesto | +| `2f` | 2 | `40 b1 b2 00 00 00 00 00` | **livello 1** (12,5; 69,5; 100; 139) e 2 (8, 20, 25, 75) | +| `2e` | 2 | `40 b1 b2 b2 b2 b2 b2 b2` (l'ultimo byte si ripete) | **livello 1**: `2e 1b 33` = 6,8, il diametro della punta mostrato da Creo | +| `2d` | 7 | `40 b1 .. b7` (precisione piena) | livello 2: `2d 39 7f ff ff ff ff ff` = 25,5 | +| `2a` | 2 | `3f b1 b2 00...` | livello 2: `2a f4 00` = 1,25, il passo di M8x1.25 | +| `48` | 2 | `c0 b1 b2 00...` (negativo) | **livello 1** (−12,5; −69,5) | +| `47` / `46` | 2 / 7 | stessa famiglia di `48`, con ripetizione / precisione piena | non isolati | +| `ed`, `32`... | 8-9 | altri byte alti | non decodificato | + +**La regola, ricavata dai dati** (non da una specifica): a ogni *byte alto* `T` del `double` +corrispondono **tre tag consecutivi**, e la base si sposta di 5 per ogni passo di `T`: + +``` +tag_zero(T) = 0x2f + 5 * (T - 0x40) per i positivi (negativi: 0x48 + 5 * (T - 0xc0)) +tag_zero -> T, b1, b2 e 5 byte a zero (valori "tondi") +tag_zero - 1 -> T, b1, b2 e b2 ripetuto 5 volte (es. 6,8 = 40 1b 33 33 33 33 33 33) +tag_zero - 2 -> T e 7 byte pieni (precisione piena) +``` + +Verifica: `T = 0x40` dà `2f`, `2e`, `2d`; `T = 0x3f` dà `2a` (1,25 con `f4 00`); `T = 0xc0` dà +`48`. Funziona solo finché i tag non si sovrappongono: i byte alti `0x41`-`0x43` e `0xb8`-`0xbf` +non li ho incontrati e non so se la regola regge (i tag di `0x45` collidono con quelli dei +negativi). Per i valori "non tondi" con ripetizione (come 6,8 o 3,4) serve il tag `2e`: senza +quello si leggerebbe `6.7998`. + +Come si ricostruisce un valore a 3 byte: si prende il `double` big-endian `40 b1 b2 00...` (per +`2f`) oppure `c0 b1 b2 00...` (per `48`). Esempi verificati (`struct.unpack('>d', ...)`): + +| Byte | Valore | Dove | +|---|---|---| +| `2f 59 00` | `100.0` | quota | +| `2f 52 c0` | `75.0` | quota | +| `2f 51 60` | `69.5` | coordinata y dello schizzo di Rivoluzione 1 (= 139 / 2) | +| `2f 29 00` | `12.5` | coordinata x (= 25 / 2) | +| `48 29 00` | `-12.5` | idem, lato opposto all'asse | +| `48 51 60` | `-69.5` | idem | +| `2f 61 60` | `139.0` | quota (lunghezza) | +| `48 59 00` | `-100.0` | estremo della linea d'asse | + +Le unità non sono scritte nel record. Nei campioni sono millimetri, ma il file ha una sezione +`UnitSystemDef` (nel contenitore compresso, §1.2 di `formato-prt-feature.md`) che non ho letto: +l'unità va presa da lì prima di dare un numero come "mm". + +## 2. Le quote: `dim_array` in `BasFullData` + +Ogni quota (dimensione guida) di ogni feature e di ogni schizzo è un record della sezione +`BasFullData`, array `dim_array`. Campi, nell'ordine in cui compaiono: + +``` +\xe1 nome della quota (qui sempre nullo: il nome "d12" si calcola altrove) +\x08 tipo del record + 1 byte: classe della quota (tabella sotto) + intero (formato asm-record §2.1): la feature a cui appartiene + \xf8 \x02 ... flag +\xe3 \xe3 ... due numeri uguali: value e bck_value +\xe3 \x09 \x01 ... ... blocco della tolleranza (nominal_value, bound...) +``` + +Per leggere solo valore e feature basta ancorarsi a `\xe1 \x08 ` e leggere il +primo numero che segue (§1). Il primo record dell'array è scritto con i nomi di campo per esteso +(layout diverso: non l'ho agganciato con lo stesso pattern, quindi **la prima quota dell'array può +mancare**). + +`feat_id` è lo stesso id di `AllFeatur` e dello storico (`formato-prt-feature.md` §2 e §5): è il +modo per attribuire la quota a "Foro 1" o a "Estrusione 2". + +### 2.1 Le quote lette sui due campioni + +`test.prt.1` (id → feature come in `formato-prt-feature.md` §6): + +| Feature | `dim_type` | Valore | Interpretazione | +|---|---|---|---| +| Estrusione 1 (79) | 62 | 75 | profondità (ipotesi) | +| Estrusione 1 (79) | 4 | 100 | diametro del cerchio dello schizzo: nello schizzo il raggio è 50 (`entity(circle)`, `radius`) | +| Foro 1 (100) | 4 | 19 | diametro (ipotesi) | +| Foro 1 (100) | 62 | 40 | profondità (ipotesi) | +| Arrotondamento 1 (125) | 3 | 3,5 | raggio (ipotesi) | +| Estrusione 2 (149) | 62 / 1 / 1 | 11 / 25 / 53 | profondità e due quote dello schizzo (ipotesi) | +| Smusso 1 (188) | 9 | 6 | distanza dello smusso (ipotesi) | + +`9252000507.prt.11`: + +| Feature | `dim_type` | Valore | Interpretazione | +|---|---|---|---| +| Rivoluzione 1 (73) | 2 | **25** | **diametro, confermato da Creo** (Ø25 h7) | +| Rivoluzione 1 (73) | 1 | **139** | **lunghezza, confermata da Creo** | +| Estrusione 1 / taglio (118) | 62 / 14 / 5 / 20 | 4 / 45 / 8 / 3 | non verificate | +| Foro 1 (157) | 4 / 9 / 2 / 10 / 2 | 8 / 20 / 6,8 / 118 / 25 | **confermate da Creo** (§6.4): 8 = diametro nominale, 20 = profondità filetto, 118 = angolo punta, 25 = profondità foro | + +**Cosa è provato e cosa no.** I valori `25` e `139` di *Rivoluzione 1* sono confermati da Creo +(§5). Per tutte le altre righe il *numero* è decodificato in modo plausibile ma il *significato* +(profondità? diametro?) è dedotto dal codice `dim_type`, da cui non ho una tabella certa. I codici +visti: `1` e `2` quote lineari/diametrali di schizzo, `3` raggio, `4` diametro, `9` distanza +(smusso), `62` profondità/estensione, altri (`5`, `10`, `14`, `37`) non interpretati. Per +distinguere con certezza serve un confronto riga per riga con un modello noto, o leggere il +nome della quota (`d0`, `d1`... del Creo). + +La *tolleranza* (es. `h7` di Ø25) sta nello stesso record, ma non l'ho decodificata: nel campo +`tol_class`/`tol_table_index` compaiono indici, non la stringa `h7`. + +## 3. La geometria di uno schizzo: `p_saved_result` + +Ogni schizzo (sezione) ha, dentro `BasFullData`, un blocco: + +``` +gsec_ptr ... name "Sezione 1" <- nome mostrato nel tree + gsec2d_ptr name "S2D0001" + segtab_ptr / dimtab_ptr / dim_ref <- segmenti, quote e a cosa si riferiscono + ... + p_saved_result + entity(line) ... <- le linee dello schizzo con le coordinate + entity(circle) ... <- i cerchi (centro, raggio) + local_sys 4x3 <- sistema di coordinate dello schizzo +``` + +Le coordinate delle entità sono **nel sistema dello schizzo**, non assolute (§6). + +Ogni `entity(line)` ha due estremi con tre coordinate ciascuno `(x, y, z)`; con z sempre `0` nello +schizzo. Le coordinate sono numeri come in §1. + +### 3.1 Esempio verificato: *Sezione 1* di Rivoluzione 1 + +Decodificando i numeri del blocco `entity(line)` di `9252000507.prt.11` si ottengono quattro +linee chiuse e una linea d'asse: + +| Linea | Da `(x, y)` | A `(x, y)` | +|---|---|---| +| 1 | (0, 69,5) | (−12,5, 69,5) | +| 2 | (−12,5, 69,5) | (−12,5, −69,5) | +| 3 | (−12,5, −69,5) | (0, −69,5) | +| 4 | (0, −69,5) | (0, 69,5) | +| asse | (0, −100) | (0, 100) | + +È il rettangolo di larghezza 12,5 (= raggio) e altezza 139, centrato in y sul piano di +riferimento, con il lato destro sull'asse x = 0, e una linea d'asse più lunga della figura. +**Coincide con quello che Creo mostra** nella vista dello schizzo (rettangolo di 139 di altezza, +quotato 25 come diametro rispetto all'asse tratteggiato, simmetrico rispetto a `TOP`). + +Nota: nel file la quota `25` è un **diametro** (Ø25), anche se in geometria il lato è 12,5. Per +questo non si può dedurre la forma dalle sole quote: servono anche le linee. + +## 4. Da schizzo + quote alla forma: la rivoluzione + +Con le due cose sopra, *Rivoluzione 1* è determinata così: + +``` +profilo (nel piano dello schizzo): x in [-12,5 ; 0], y in [-69,5 ; 69,5] +asse di rotazione: la linea x = 0 (la linea d'asse dello schizzo) +angolo: 360 (non decodificato, vedi §7) +risultato: cilindro Ø25 x 139, centrato sull'origine lungo y dello schizzo +``` + +Nell'albero di Creo il cilindro risulta con il fondo sul piano `DTM1` e l'asse come `A_1`: la +posizione assoluta (quale piano contiene lo schizzo, come è orientato `y`) **non è nello schizzo** +ma nella definizione della feature (§7). + +## 5. Verifica di *Rivoluzione 1* contro Creo + +`9252000507.prt` aperto in Creo (schermate del model tree e dello schizzo): + +| Cosa | Creo | Letto dal file | +|---|---|---| +| Lunghezza dello schizzo | 139.000 | quota `dim_type 1` = 139 | +| Diametro | Ø25 (h7) | quota `dim_type 2` = 25 | +| Rettangolo, simmetrico rispetto a `TOP` | sì | y da −69,5 a 69,5 | +| Rettangolo a sinistra dell'asse | sì | x da −12,5 a 0 | +| Asse (linea di costruzione) | più lungo della figura | da y = −100 a 100 | +| Assi A_3, A_4, A_5, punto PNT0 | presenti nel tree | `AllFeatur` + storico (`formato-prt-feature.md`) | + +## 6. Posizione nello spazio + +### 6.1 Matrici 4×3 + +Piani di riferimento, assi, sistemi di coordinate e schizzi hanno un `local_sys`: array `f9 04 03`, +cioè 4 righe per 3 colonne = 12 numeri (3 versori degli assi + l'origine). Lo schizzo sul piano +base ha la matrice identità, scritta `0f 18 e5 0f 18 e5 0f 18 e5`: tre gruppi uguali, ciascuno +`1, 0, 0, 0`, cioè 12 numeri `1,0,0,0, 1,0,0,0, 1,0,0,0`. Da qui l'ipotesi che `e4`-`e7` dopo uno +zero valgano "altri K−3 zeri". + +**Questa lettura è un'ipotesi, non verificata.** L'identità non permette di distinguere +"per righe" da "per colonne", né di sapere quale gruppo è l'origine. Servono matrici *non* +identità (un piano ruotato, un'origine fuori dallo zero) con il valore atteso da Creo. Finché non +c'è, rotazione e origine di piani e schizzi sono **non decodificate**. + +### 6.2 Dove stanno + +| Cosa | Dove nel file | +|---|---| +| Piani di riferimento (RIGHT, TOP, FRONT, DTM1) | `ActDatums` (`srf_prim_ptr(plane)` con `local_sys`), `feat_id` = id della feature; vincoli di posizionamento in `FeatDefsDtm` (§6.3) | +| Sistema di coordinate (`PRT_CSYS_DEF`) | `MdlRefInfo` (`ent_list(coord_sys)`) e `GeomDepen` | +| Assi, punti (A_3, PNT0...) | `ent_list(arc_z)`, `ent_list(point)` in `MdlRefInfo` | +| Piano che contiene lo schizzo | `gsec3d_ptr` -> `plane_id`, `ref_planes`; il piano è identificato da un id di geometria | +| Orientamento dello schizzo | `sec_orient_data`, `place_instruction_ptrs` (nella definizione di feature `feat_defs_`) | +| Offset di un piano da un altro (DTM1) | quota di tipo "offset" nel `dim_array` della feature, se esiste | + +### 6.3 Come è posizionato un piano: i vincoli di `FeatDefsDtm` + +La finestra "Piano di riferimento → Posizionamento" di Creo (riferimenti con il loro vincolo, +es. *Tangente* a una superficie, *Parallelo* a un piano) **si legge dal file**. Sta nella sezione +`FeatDefsDtm`, record `feat_defs_923` (un record per piano; `feat_defs_926` assi, `feat_defs_931` +punti, `feat_defs_979` sistemi di assi). Ogni record ha: + +``` +id id della feature (come in AllFeatur) +local_sys matrice 4x3 del piano risultante (§6.1) +place_instruction_ptrs una istruzione per ogni riferimento della finestra: + type codice del vincolo (intero a 2 byte) + offset double, offset del vincolo + dim_id, ref_id quota dell'offset e riferimento, se esistono + geometry1_id id della geometria a cui ci si riferisce + geometry2_id id della geometria che si sta creando (il piano stesso) +``` + +Gli `id` di geometria (`geom_id`) si risolvono nelle sezioni `ActDatums` (piani e assi di +riferimento), `VisibGeom` e `NovisGeom` (superfici del solido, visibili e no). Ogni voce di +`srf_array` ha `geom_id`, `geom_type` (`"`, 0x22 = piano; `$`, 0x24 = cilindro) e **`feat_id`**: è il +legame con la feature che l'ha generata. + +**Verifica sul caso che hai mostrato**: *DTM1* di `9252000507.prt` (feature 116), finestra di Creo +"Supfce:F5(RIVOLUZIONE_1) Tangente / FRONT:F3 Parallelo". Dal file: + +| Istruzione | `type` | `geometry1_id` | Si risolve in | Corrisponde a | +|---|---|---|---|---| +| 1 | `81 fb` (507) | 88 | `VisibGeom`: cilindro (`$`), `feat_id` 73 = Rivoluzione 1 | "Supfce:F5(RIVOLUZIONE_1)", **Tangente** | +| 2 | `81 f9` (505) | 6 | `ActDatums`: piano (`"`), `feat_id` 5 = FRONT | "FRONT:F3", **Parallelo** | + +`geometry2_id` è 117 in entrambe: `ActDatums` lo dà come piano con `feat_id` 116 = DTM1 (il piano +risultante). Nella sua matrice compare il valore `12.5` (`2f 29 00`): è il raggio del cilindro, +come deve essere per un piano tangente ad esso. Il campo `Traslazione` della finestra era vuoto. + +Quindi **quali sono i riferimenti** (quale feature/superficie e quale piano) si legge con certezza. +Resta da fissare: + +- **Il significato di `type`.** 507 ↔ Tangente e 505 ↔ Parallelo è dedotto da un solo esempio e + dall'ordine delle righe della finestra: non ho una tabella dei codici. Gli altri visti + (`82 01`, `82 02`, `82 03`, `81 fd`, `81 ff`) sono quelli dei piani di default e degli altri + piani del campione, non interpretati. +- **`Feature number` di Creo** (`F3`, `F5`): non è l'`id` ma la **posizione** nel tree + (RIGHT = F1, TOP = F2, FRONT = F3, PRT_CSYS_DEF = F4, Rivoluzione 1 = F5). I piani interni non + contano. Per tradurre un `id` in `F` si numerano le feature visibili in ordine + (`formato-prt-feature.md` §3). +- **L'offset.** Se un vincolo ha un offset (quota di tipo offset) il valore sta nel `dim_array` + della feature (§2) con il `dim_id` dell'istruzione; non ho un esempio con offset non nullo. + +### 6.4 Il foro: `feat_defs_911` + +Riferimento: *Foro 1* di `9252000507.prt.11` (feature 157), confrontato con le schermate di Creo. +Creo mostra: tipo **Standard**, profilo **Diritto** con **Maschiato**, filetto ISO **M8x1.25**, +**profondità 25**, **Ø6,8**, **profondità del filetto 20**, **angolo della punta 118°**, +"Includi la superficie del filetto" attivo, posizionamento **Coassiale** con riferimenti +`Supfce:F5(RIVOLUZIONE_1)` e `A_1(ASSE):F5(RIVOLUZIONE_1)`. + +La definizione del foro sta nella sezione `FeatDefs`, record `feat_defs_911`. Ha due parti. + +**a) I parametri del filetto, in chiaro** (`data(ddt_plinfo_hole_fstn_param)`): + +| Campo | Valore letto | In Creo | +|---|---|---| +| `name`, `series` | `ISO`, `ISO` | Tipo filetto: ISO | +| `scrsize` | `M8x1.25` | Dimensione vite: M8x1.25 | +| `scrsize_val` | `0x1d` (29) | indice di M8x1.25 nella tabella delle viti di Creo (nel segnaposto `M1x.25` vale 0) | +| `hole_class` | `H` | (classe del foro) | +| `drillnum` | `6.8` | Ø6,8 | + +**b) Le istruzioni** (`place_instruction_ptrs`): una per ogni parametro numerico, nella forma +`type`, `offset` (un `double`, §1), `dim_id`, `ref_id`, `geometry1_id`, `geometry2_id`. Quelle +del foro filettato, con il valore atteso da Creo: + +| `type` | `offset` letto | In Creo | Prova | +|---|---|---|---| +| 5104 (`0x13f0`) | 6,8 | Ø6,8 (anche nel foro semplice, vedi sotto) | **livello 1** | +| 5528 (`0x1598`) | 118 | angolo della punta | **livello 1** | +| 5538 (`0x15a2`) | 25 | profondità del foro | **livello 1** | +| 5536 (`0x15a0`) | 1,25 | passo del filetto (M8**x1.25**) | livello 2 | +| 6617 (`0x19d9`) | 11 | non corrisponde a nulla di mostrato | non interpretato | +| 5542, 10103, 5533, 5534 | 0 | non mostrati | non interpretati | + +Il codice `type` identifica il parametro; il valore è `offset`. La profondità del filetto (20) e il +diametro nominale (8) **non** sono istruzioni ma quote del `dim_array` (§2), con `dim_type` 9 e 4 +e `feat_id` 157. In tutto il `dim_array` ha per il foro cinque quote: 8 (`dim_type` 4), 20 (9), +Ø6,8 (2, scritto con il tag `2e`), 118 (10) e 25 (2). Tre di queste (6,8, 118, 25) compaiono +quindi due volte, come quota e come parametro di un'istruzione. + +**Foro semplice e foro standard.** `test.prt.1` ha un foro **semplice**: il suo `feat_defs_911` +è lungo 862 byte e ha solo due istruzioni (`5104` con `dim_id` 7, e `1853`); i parametri del +filetto ci sono comunque, ma con i valori segnaposto di Creo (`M1x.25`, `drillnum 0.75`, +`scrsize_val 0`): **quindi le stringhe `scrsize`/`drillnum` da sole non dicono se il foro è +filettato**. Quello di Fata ha 3212 byte e 12 istruzioni, valori diversi dal segnaposto. Il segno +affidabile oggi è: **foro standard = presenza delle istruzioni 5536 (passo) e 5528 (angolo punta)**, +e il foro è filettato quando anche i valori del filetto non sono quelli segnaposto. + +**Non individuato nel file** (per ognuno servono due salvataggi che differiscono solo per +quell'opzione): + +- *Maschiato / Trapanato / Gioco*, *Diritto / Rastremato*: non so quale istruzione o flag le + codifichi. `plin_info_hole_flag.flags` vale `2, 2` in entrambi i fori. +- *Includi la superficie del filetto*: idem. +- Il tipo *Standard*/*Semplice* come campo esplicito: oggi si deduce solo dal numero di istruzioni. + +**Posizionamento Coassiale.** Gli ingredienti ci sono: un blocco `data(plin_info_ref)` per ogni +riferimento, con gli id di geometria. Il piano del riferimento `Supfce:F5` dovrebbe essere la +faccia piana di *Rivoluzione 1* (feature 73, in `VisibGeom` con `feat_id` 73) e il secondo +riferimento l'asse `A_1`: non ho agganciato quegli id perché le coppie `id_type1`/`id_type2` non le +ho decifrate. La geometria generata dal foro (cilindro, cono, piani con `feat_id` 157) è invece +in `VisibGeom` e `NovisGeom`, e `geometry2_id` 175 delle istruzioni è un suo piano. + +### 6.5 Lo smusso: `feat_defs_914` + +Riferimento: *Smusso 1* di `9252000507.prt.11` (feature 252), in modifica in Creo: modalità +**Insiemi**, schema quote **D x D** con **D = 0.500**, un insieme ("Insieme 1") con **due +riferimenti**, entrambi `Spigolo:F5(RIVOLUZIONE_1)`, e l'opzione "Superfici con offset". + +| Cosa | Dove | Letto | Prova | +|---|---|---|---| +| Valore D | `dim_array`, `feat_id` 252, `dim_type` 9 | `0e` = **0,5** | **livello 1** | +| Valore in `test.prt.1` | `dim_array`, feat 188, `dim_type` 9 | `2f 18 00` = 6,0 | livello 2 | +| Superfici del bordo | `feat_defs_914`, istruzioni di tipo 4530 | `geometry1_id` = 88, 86, 106, 90 | vedi sotto | +| Superfici generate dallo smusso | `VisibGeom`, `feat_id` 252 | superfici coniche (`geom_id` 253, 258, 261, 266) | presenti | + +Il `dim_type` 9 è lo stesso del foro (profondità del filetto): dice la *classe* della quota, non +cosa misura. Per lo smusso vale D, ma la stessa classe in un foro vale 20. + +**I riferimenti.** Le istruzioni di tipo `4530` hanno nel campo `geometry1_id` gli id 88, 86, 106 e +90, ripetuti a coppie. Risolti con `VisibGeom`: **88** e **106** sono superfici cilindriche con +`feat_id` 73 (cioè *Rivoluzione 1*, F5), **86** è il piano di estremità della stessa rivoluzione +(visto in §3.1 e §6.3). Quindi i riferimenti `Spigolo:F5(RIVOLUZIONE_1)` sono spigoli ricavati dalle +superfici di Rivoluzione 1, come mostra Creo. Non so ancora quale coppia di id formi quale +spigolo, né a quale dei due "Spigolo" della lista corrisponda (le istruzioni non sono in un ordine +che io abbia decifrato), e **90** non l'ho risolto. + +**Non decodificato:** + +- lo schema quote (D x D, D1 x D2, angolo x D...): non ho trovato dove sta; compaiono vari tipi di + istruzione (`7350`, `7360`, `4549`, `4552`, `4557`, `4558`, `1125`, `7265`, `14741`) senza + corrispondenza con le voci mostrate; +- "Insieme 1" e la sua composizione: compare la struttura (`data(plin_info_chut_info)`, array di + riferimenti) ma non la ho letta; +- "Superfici con offset" e il tipo di transizione; +- l'istruzione `14741`, con un valore `11,476` in precisione piena: non corrisponde a niente di + mostrato. + +## 7. Cosa manca per determinare un `.prt` in modo univoco + +Tabella di verità: ogni informazione necessaria, se l'ho decodificata e quanto è provata. + +| Informazione | Stato | Dove si trova | +|---|---|---| +| Elenco e ordine delle feature | **fatto**, provato (`test.prt.1`, `9252000507.prt.11` contro Creo) | `AllFeatur` | +| Tipo di ogni feature | **fatto**; estrusione vs rivoluzione solo con lo storico | `AllFeatur`, storico | +| Nome di ogni feature | **fatto**, ma solo se esiste lo storico (10 file su 31 leggibili) | `MdlStatus` | +| Quote (valori numerici) | **fatto per i valori interi/semplici**, tag `2f`/`48` | `dim_array` | +| Significato di ogni quota | **parziale**: provato solo per Rivoluzione 1 | `dim_type` (§2.1) | +| Geometria dello schizzo (linee) | **fatto** per le linee, provato su Rivoluzione 1 | `p_saved_result` | +| Cerchi, archi, spline dello schizzo | non verificato (cerchio visto in `test.prt.1`, raggio 50) | `entity(circle)`, `entity(arc_z)`, `entity(spline)` | +| Valori non "tondi" | **non decodificato** (tag diversi da `2f`/`48`) | ovunque | +| Piano e orientamento dello schizzo | **non decodificato** | `gsec3d_ptr`, `sec_orient_data` | +| Posizione/rotazione di piani, assi, punti | **non decodificato** (§6.1) | `ActDatums`, `MdlRefInfo` | +| Vincoli e riferimenti di un piano (come DTM1) | **fatto per DTM1 di `9252000507`** (riferimenti sì, nome del vincolo da un esempio) | `FeatDefsDtm`, §6.3 | +| Offset di un piano da un altro | **non decodificato**: mai visto un offset non nullo | quota in `dim_array` (`dim_id`) | +| Direzione/lato e angolo di una rivoluzione, profondità e direzione di un'estrusione | **non decodificato** | `feat_defs_917`/`916` (`place_instruction_ptrs`, `plin_info_arr`) | +| Parametri del foro (misura, punta, passo, profondità, angolo) | **fatto**, provato contro Creo su `9252000507` | `feat_defs_911`, §6.4 | +| Opzioni del foro (maschiato, diritto, superficie del filetto) | **non individuato** | §6.4 | +| Posizione del foro (riferimenti e offset) | **non decodificato**: le istruzioni di posizionamento ci sono (`plin_info_arr`), come per DTM1 | `feat_defs_911` | +| Valore di raccordi e smussi | **fatto**, provato contro Creo su `9252000507` (D = 0,5) | `dim_array` | +| Spigoli a cui si applicano raccordi/smussi | **parziale**: si risolvono le superfici (feature di origine), non lo spigolo né l'insieme | `feat_defs_914`, §6.5 | +| Schema quote e insiemi dello smusso | **non decodificato** | `feat_defs_914` | +| Tolleranze (h7...) | **non decodificato** | blocco `tol_ptr` del `dim_array` | +| Unità di misura | **non letto** | `UnitSystemDef` (sezione compressa) | +| Feature nascoste / soppresse | **non decodificato** | non individuato nel file | +| Parametri e materiale | parziale, via `ND:0:Model_*` (XML) | sezione compressa `.Z` | +| File Wildfire (generazioni 1322/1375/1376) | **illeggibile** (sezioni di tipo `11`) | `formato-prt-feature.md` §1.3 | + +**Conclusione onesta:** oggi si ricava con affidabilità *quali* feature ci sono, *che tipo* sono, +*come si chiamano* (se c'è lo storico), *quanto misurano* le quote semplici e *che forma ha lo +schizzo* se fatto di linee con numeri semplici. Non si ricava ancora *dove* stanno nello spazio né +*come* sono orientate, né si può ricostruire il solido completo. + +## 8. Come finire il lavoro + +Per ogni riga "non decodificato" della §7 il metodo è lo stesso, ed è quello che ha dato Rivoluzione +1: + +1. Scegliere un `.prt` piccolo con **una sola feature** del tipo da decodificare, e annotare da + Creo i valori veri (quote, posizione dei piani, angolo, direzione). +2. Estrarre da `BasFullData`/`ActDatums` i record di quella feature e cercarvi quei numeri con il + decodificatore di §1: i valori noti ancorano i byte. +3. Variare **una cosa alla volta** nel modello (spostare il piano, cambiare l'angolo), risalvare e + confrontare i due file: i byte che cambiano sono il campo cercato. +4. Registrare in questo doc il campo, con il file di prova e il valore atteso, come in §5. + +Tre modelli di prova che chiuderebbero la maggior parte della §7: un piano `DTM1` a offset non nullo +dal piano `TOP` (e con un vincolo *Attraverso*, *Normale*, *Offset*...); una estrusione di profondità nota su un piano ruotato; una rivoluzione di 90°. + +Una volta chiusa la §7 il passo successivo è un `PrtModelReader` in C# accanto ad `AsmRecordReader`, +con le stesse regole: se un valore non si decodifica si solleva `InvalidDataException`, non si +restituisce un modello parziale in silenzio.