# 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.