Compare commits
5
Commits
1.0.0
..
1eac3ccaa7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1eac3ccaa7 | ||
|
|
5b11b3e8ca | ||
|
|
d5fb20a34e | ||
|
|
6d1e36a2ae | ||
|
|
ccfa00ff52 |
No files matched your search
@@ -0,0 +1,15 @@
|
||||
{
|
||||
// Regole base; disattivate quelle che non servono a prosa italiana con tabelle larghe
|
||||
"config": {
|
||||
"default": true,
|
||||
"MD013": false, // lunghezza riga
|
||||
"MD033": false, // HTML inline
|
||||
"MD024": { "siblings_only": true }, // CHANGELOG ripete "Aggiunto/Modificato"
|
||||
"MD036": false,
|
||||
"MD040": false, // dump esadecimali/testuali senza linguaggio
|
||||
"MD060": false, // stile colonne tabelle
|
||||
"MD041": false
|
||||
},
|
||||
"globs": ["**/*.md"],
|
||||
"ignores": ["node_modules", "raw", "step", "**/bin", "**/obj"]
|
||||
}
|
||||
@@ -5,6 +5,26 @@ Tutte le modifiche rilevanti di questo progetto sono documentate in questo file.
|
||||
Il formato segue [Keep a Changelog](https://keepachangelog.com/it/1.1.0/), e il progetto
|
||||
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
|
||||
|
||||
- Fase 2: modalità "Lista personalizzata" per inserire i codici a mano, uno alla volta, in alternativa al file del gestionale.
|
||||
- Docs-as-code: `scripts/CheckDocs.cs`, markdownlint, `docs/README.md` (indice Diátaxis e fonte unica).
|
||||
- Nuovi doc: `tutorial-primo-giro`, `risoluzione-problemi`, `sviluppo`, `rilascio`, `glossario` e registro delle decisioni `docs/decisioni/` (6 ADR).
|
||||
|
||||
### Modificato
|
||||
|
||||
- Il README rimanda a `docs/sviluppo.md` e `docs/rilascio.md` per build, test e setup, invece di duplicarli.
|
||||
- Fase 2: dopo "Verifica presenza" la riga selezionata mantiene il verde/rosso dell'esito invece di diventare blu.
|
||||
|
||||
## [1.0.0] - 2026-09-23
|
||||
|
||||
Prima versione distribuita agli utenti tramite setup di installazione.
|
||||
|
||||
@@ -63,8 +63,14 @@ Dove scrivere cosa:
|
||||
| [`docs/formato-asm.md`](docs/formato-asm.md) | euristica testuale di fallback |
|
||||
| [`docs/db-cad-index.md`](docs/db-cad-index.md) | schema e vista di `cad_index.db` |
|
||||
| [`docs/copia-raw-parallela.md`](docs/copia-raw-parallela.md) | parallelizzazione della copia in `raw/` |
|
||||
| [`docs/README.md`](docs/README.md) | indice Diátaxis di tutti i doc (tutorial, how-to, reference, decisioni) e regola di fonte unica |
|
||||
| [`CHANGELOG.md`](CHANGELOG.md) | storico delle versioni (formato Keep a Changelog); ogni release che cambia `<Version>` nel csproj aggiunge qui la sua voce |
|
||||
|
||||
I doc sono trattati come codice: stanno in git e si verificano con
|
||||
`dotnet run scripts/CheckDocs.cs` (link, versione/CHANGELOG, copertura di `architettura.md`) e
|
||||
`npx markdownlint-cli2` (config `.markdownlint-cli2.jsonc`) — da lanciare prima di ogni commit che
|
||||
tocca i doc. Organizzazione (Diátaxis) e regola di fonte unica: [`docs/README.md`](docs/README.md).
|
||||
|
||||
Quando il cambiamento nasce da un fallimento reale di Creo, scrivere anche **il sintomo**: i
|
||||
messaggi di Creo non nominano il file o la causa, e senza quel ponte la prossima volta si
|
||||
riparte da zero (i §7.3/§7.4/§7.5 di `formato-asm-record.md` sono l'esempio del formato
|
||||
|
||||
+125
-8
@@ -12,6 +12,11 @@ public partial class Form1 : Form
|
||||
private readonly Button _btnTrovaPrt = new();
|
||||
private readonly Button _btnVerifica = new();
|
||||
private readonly FlowLayoutPanel _rigaVerifica = new();
|
||||
private readonly FlowLayoutPanel _rigaFile = new();
|
||||
private readonly FlowLayoutPanel _rigaCustom = new();
|
||||
private readonly RadioButton _rbFile = new() { Text = "Da file del gestionale", Checked = true, AutoSize = true };
|
||||
private readonly RadioButton _rbCustom = new() { Text = "Lista personalizzata", AutoSize = true };
|
||||
private readonly TextBox _txtCodice = new() { Width = 220, Margin = new Padding(0, 3, 8, 0) };
|
||||
private readonly ListView _lstAnteprimaAsm = new();
|
||||
private readonly Label _lblStatus = new();
|
||||
private readonly Label _lblDb = new();
|
||||
@@ -50,7 +55,7 @@ public partial class Form1 : Form
|
||||
|
||||
private string? _dbPath;
|
||||
private string? _cartellaLavoro;
|
||||
private string? _percorsoInputCorrente;
|
||||
private bool _ripristinoModalita;
|
||||
private List<(string Componente, string Descrizione)>? _righeCorrenti;
|
||||
private Dictionary<string, List<string>>? _ultimaVerifica;
|
||||
private string? _ultimaCartellaRaw;
|
||||
@@ -266,7 +271,12 @@ public partial class Form1 : Form
|
||||
return;
|
||||
}
|
||||
|
||||
_percorsoInputCorrente = null;
|
||||
AzzeraDistinta();
|
||||
VaiAllaFase(1);
|
||||
}
|
||||
|
||||
private void AzzeraDistinta()
|
||||
{
|
||||
_righeCorrenti = null;
|
||||
_ultimaCartellaRaw = null;
|
||||
_ultimaVerifica = null;
|
||||
@@ -275,8 +285,68 @@ public partial class Form1 : Form
|
||||
_lstAnteprimaAsm.Items.Clear();
|
||||
ImpostaStatoImport("", Color.Black);
|
||||
_rigaVerifica.Visible = false;
|
||||
}
|
||||
|
||||
VaiAllaFase(1);
|
||||
private void CambiaModalitaDistinta()
|
||||
{
|
||||
if (_ripristinoModalita)
|
||||
return;
|
||||
if (_gridImport.Rows.Count > 0 && MessageBox.Show(this,
|
||||
"Cambiando modalità la distinta corrente viene azzerata. Continuare?", "Distinta",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
|
||||
{
|
||||
_ripristinoModalita = true;
|
||||
(_rbCustom.Checked ? _rbFile : _rbCustom).Checked = true;
|
||||
_ripristinoModalita = false;
|
||||
return;
|
||||
}
|
||||
AzzeraDistinta();
|
||||
_rigaFile.Visible = _rbFile.Checked;
|
||||
_rigaCustom.Visible = _rbCustom.Checked;
|
||||
AggiornaStatoAvanti();
|
||||
}
|
||||
|
||||
private void AggiungiCodice()
|
||||
{
|
||||
string codice = _txtCodice.Text.Trim();
|
||||
if (codice.Length == 0)
|
||||
return;
|
||||
_righeCorrenti ??= new();
|
||||
if (_righeCorrenti.Any(r => string.Equals(r.Componente, codice, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
_txtCodice.SelectAll();
|
||||
return;
|
||||
}
|
||||
_righeCorrenti.Add((codice, ""));
|
||||
_gridImport.Rows.Add(codice, "");
|
||||
InvalidaVerifica();
|
||||
_txtCodice.Clear();
|
||||
_txtCodice.Focus();
|
||||
}
|
||||
|
||||
private void RimuoviCodiceSelezionato()
|
||||
{
|
||||
if (_gridImport.CurrentRow is not { } riga || _righeCorrenti is null)
|
||||
return;
|
||||
_righeCorrenti.RemoveAt(riga.Index); // griglia e lista hanno lo stesso ordine
|
||||
_gridImport.Rows.Remove(riga);
|
||||
InvalidaVerifica();
|
||||
}
|
||||
|
||||
/// <summary>La lista è cambiata: la verifica presenza e il raw già creato non valgono più.</summary>
|
||||
private void InvalidaVerifica()
|
||||
{
|
||||
_ultimaVerifica = null;
|
||||
_ultimaCartellaRaw = null;
|
||||
_gridRaw.Rows.Clear();
|
||||
foreach (DataGridViewRow r in _gridImport.Rows)
|
||||
{
|
||||
r.DefaultCellStyle.BackColor = Color.Empty;
|
||||
r.DefaultCellStyle.SelectionBackColor = Color.Empty;
|
||||
r.DefaultCellStyle.SelectionForeColor = Color.Empty;
|
||||
}
|
||||
_rigaVerifica.Visible = _righeCorrenti is { Count: > 0 };
|
||||
AggiornaStatoAvanti();
|
||||
}
|
||||
|
||||
private Panel BuildFaseDatabase()
|
||||
@@ -400,12 +470,51 @@ public partial class Form1 : Form
|
||||
};
|
||||
contenuto.Controls.Add(lblIstruzioni);
|
||||
|
||||
var rigaImporta = new FlowLayoutPanel
|
||||
var rigaModalita = new FlowLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
Margin = new Padding(0, 0, 0, 8),
|
||||
};
|
||||
rigaModalita.Controls.Add(_rbFile);
|
||||
rigaModalita.Controls.Add(_rbCustom);
|
||||
_rbCustom.CheckedChanged += (_, _) => CambiaModalitaDistinta();
|
||||
contenuto.Controls.Add(rigaModalita);
|
||||
|
||||
_rigaCustom.AutoSize = true;
|
||||
_rigaCustom.FlowDirection = FlowDirection.LeftToRight;
|
||||
_rigaCustom.Margin = new Padding(0, 0, 0, 8);
|
||||
_rigaCustom.Visible = false;
|
||||
var btnAggiungi = new Button { Text = "Aggiungi", Margin = new Padding(0, 0, 8, 0) };
|
||||
UiStile.Secondario(btnAggiungi);
|
||||
btnAggiungi.Click += (_, _) => AggiungiCodice();
|
||||
_txtCodice.KeyDown += (_, e) =>
|
||||
{
|
||||
if (e.KeyCode != Keys.Enter)
|
||||
return;
|
||||
e.SuppressKeyPress = true;
|
||||
AggiungiCodice();
|
||||
};
|
||||
_rigaCustom.Controls.Add(_txtCodice);
|
||||
_rigaCustom.Controls.Add(btnAggiungi);
|
||||
_rigaCustom.Controls.Add(new Label
|
||||
{
|
||||
AutoSize = true,
|
||||
ForeColor = SystemColors.GrayText,
|
||||
Margin = new Padding(0, 9, 0, 0),
|
||||
Text = "Digita un codice e premi Invio (Canc sulla riga per toglierlo)",
|
||||
});
|
||||
contenuto.Controls.Add(_rigaCustom);
|
||||
_gridImport.KeyDown += (_, e) =>
|
||||
{
|
||||
if (e.KeyCode == Keys.Delete && _rbCustom.Checked)
|
||||
RimuoviCodiceSelezionato();
|
||||
};
|
||||
|
||||
var rigaImporta = _rigaFile;
|
||||
rigaImporta.AutoSize = true;
|
||||
rigaImporta.FlowDirection = FlowDirection.LeftToRight;
|
||||
rigaImporta.Margin = new Padding(0, 0, 0, 8);
|
||||
var btnSfoglia = new Button
|
||||
{
|
||||
Text = "Scegli file distinta...",
|
||||
@@ -646,10 +755,15 @@ public partial class Form1 : Form
|
||||
|
||||
private void ImportaDistinta(string percorso)
|
||||
{
|
||||
if (_rbCustom.Checked)
|
||||
{
|
||||
_rbFile.Checked = true; // chiede conferma se c'è una lista; se rifiuta resta in custom
|
||||
if (_rbCustom.Checked)
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var (_, righe) = DistintaBaseImporter.ConvertiInCsv(percorso, _cartellaLavoro!);
|
||||
_percorsoInputCorrente = percorso;
|
||||
_righeCorrenti = righe;
|
||||
|
||||
_gridImport.Rows.Clear();
|
||||
@@ -666,7 +780,6 @@ public partial class Form1 : Form
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_percorsoInputCorrente = null;
|
||||
_righeCorrenti = null;
|
||||
_gridImport.Rows.Clear();
|
||||
ImpostaStatoImport($"Errore durante la conversione: {ex.Message}", Color.DarkRed);
|
||||
@@ -694,16 +807,20 @@ public partial class Form1 : Form
|
||||
foreach (DataGridViewRow riga in _gridImport.Rows)
|
||||
{
|
||||
string componente = (string)riga.Cells["componente"].Value!;
|
||||
riga.DefaultCellStyle.BackColor = trovati.ContainsKey(componente)
|
||||
var colore = trovati.ContainsKey(componente)
|
||||
? Color.FromArgb(198, 239, 206)
|
||||
: Color.FromArgb(255, 199, 206);
|
||||
// la selezione mantiene il colore verde/rosso, altrimenti il blu nasconde l'esito
|
||||
riga.DefaultCellStyle.BackColor = colore;
|
||||
riga.DefaultCellStyle.SelectionBackColor = colore;
|
||||
riga.DefaultCellStyle.SelectionForeColor = Color.Black;
|
||||
}
|
||||
AggiornaStatoAvanti();
|
||||
}
|
||||
|
||||
private void CreaCartellaRaw()
|
||||
{
|
||||
if (_percorsoInputCorrente is null || _righeCorrenti is null)
|
||||
if (_righeCorrenti is null)
|
||||
return;
|
||||
|
||||
// L'assieme generale è già una riga di _righeCorrenti (aggiunta da
|
||||
|
||||
@@ -104,7 +104,10 @@ public class GuidaForm : Form
|
||||
[
|
||||
"Carica la distinta: trascina il file .xls nella finestra, oppure premi " +
|
||||
"\"Scegli file distinta...\". Le righe importate compaiono nella griglia " +
|
||||
"(Componente/Descrizione) e viene scritto un CSV nella cartella di lavoro.",
|
||||
"(Componente/Descrizione) e viene scritto un CSV nella cartella di lavoro. " +
|
||||
"In alternativa scegli \"Lista personalizzata\" e digita i codici uno alla " +
|
||||
"volta (Invio per aggiungere, Canc per togliere): nessun CSV, l'assieme " +
|
||||
"generale va inserito a mano.",
|
||||
"Verifica la presenza dei file sul server: compare solo dopo un import " +
|
||||
"riuscito. Cerca ogni componente nel database — le righe della griglia si " +
|
||||
"colorano di verde (trovato) o rosso (non trovato nell'indice).",
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<Product>PrepStep - Cevolani</Product>
|
||||
<Company>Cevolani</Company>
|
||||
<Copyright>Copyright (c) 2026 Davide Grilli</Copyright>
|
||||
<Version>1.0.0</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ passaggio, non lo sostituisce.
|
||||
manuale, fuori da quest'app): scrive in `step/`, dentro la cartella di
|
||||
lavoro.
|
||||
|
||||
Guida utente passo-passo completa in [`docs/guida-utente.md`](docs/guida-utente.md)
|
||||
Primo uso: [`docs/tutorial-primo-giro.md`](docs/tutorial-primo-giro.md). Guida utente completa in
|
||||
[`docs/guida-utente.md`](docs/guida-utente.md)
|
||||
(stessa sintesi anche in-app da **Aiuto → Guida**, F1).
|
||||
|
||||
## Requisiti
|
||||
@@ -50,83 +51,20 @@ Guida utente passo-passo completa in [`docs/guida-utente.md`](docs/guida-utente.
|
||||
- Accesso alla share di rete con i file CAD (`X:\` di default) per
|
||||
l'indicizzazione
|
||||
|
||||
## Build
|
||||
## Build, test e rilascio
|
||||
|
||||
```powershell
|
||||
cd PrepStep
|
||||
dotnet build -c Release
|
||||
```
|
||||
Build, avvio e test: [`docs/sviluppo.md`](docs/sviluppo.md). Pubblicazione dell'eseguibile e
|
||||
generazione del setup di installazione: [`docs/rilascio.md`](docs/rilascio.md).
|
||||
|
||||
## Avvio
|
||||
|
||||
Da sorgente:
|
||||
|
||||
```powershell
|
||||
cd PrepStep
|
||||
dotnet run -c Release
|
||||
```
|
||||
|
||||
Oppure l'eseguibile già compilato:
|
||||
|
||||
```powershell
|
||||
cd PrepStep\bin\Release\net10.0-windows
|
||||
.\PrepStep.exe
|
||||
```
|
||||
|
||||
## Pubblicazione (eseguibile standalone)
|
||||
|
||||
Genera un `.exe` self-contained per Windows x64, senza bisogno del runtime
|
||||
.NET installato sulla macchina di destinazione:
|
||||
|
||||
```powershell
|
||||
cd PrepStep
|
||||
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o publish
|
||||
```
|
||||
|
||||
L'eseguibile risultante è in `PrepStep\publish\PrepStep.exe` — un unico
|
||||
file, si copia e si lancia su un'altra macchina Windows senza bisogno di .NET
|
||||
installato.
|
||||
|
||||
## Setup di installazione
|
||||
|
||||
Per distribuire l'app agli utenti si genera un setup con
|
||||
[Inno Setup 6](https://jrsoftware.org/isinfo.php).
|
||||
|
||||
Una volta sola, per installare Inno Setup (per l'utente corrente, senza admin):
|
||||
|
||||
```powershell
|
||||
winget install --id JRSoftware.InnoSetup -e --scope user
|
||||
```
|
||||
|
||||
A ogni release, dalla root del repo:
|
||||
|
||||
```powershell
|
||||
# 1. aggiorna <Version> in PrepStep\PrepStep.csproj e la voce in CHANGELOG.md
|
||||
# 2. chiudi l'app se è aperta (l'exe in uso blocca la build)
|
||||
dotnet publish PrepStep -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o PrepStep\publish
|
||||
& "$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe" installer\PrepStep.iss
|
||||
```
|
||||
|
||||
Produce `installer\Output\PrepStep-Setup-<versione>.exe` (versione letta dall'exe, cioè
|
||||
`<Version>` del csproj): è l'unico file da distribuire. Per provarlo sul proprio PC basta
|
||||
lanciarlo (`.\installer\Output\PrepStep-Setup-<versione>.exe`). Il setup:
|
||||
|
||||
- installa **solo per l'utente corrente**, in `%LOCALAPPDATA%\Programs\PrepStep`, senza
|
||||
chiedere i diritti di amministratore;
|
||||
- crea nel menu Start i collegamenti al programma e al disinstallatore (quello sul desktop
|
||||
è facoltativo);
|
||||
- compare in "Impostazioni → App installate", da cui si disinstalla.
|
||||
|
||||
Se l'app è già installata, il setup chiede prima cosa fare: **Sì** aggiorna/reinstalla (DB e
|
||||
impostazioni restano), **No** disinstalla, **Annulla** esce. Installazione silenziosa (aggiorna
|
||||
senza chiedere) — es. per distribuirla da script:
|
||||
`PrepStep-Setup-<versione>.exe /VERYSILENT /SUPPRESSMSGBOXES`.
|
||||
Il setup installa **solo per l'utente corrente**, in `%LOCALAPPDATA%\Programs\PrepStep`, senza
|
||||
diritti di amministratore; si disinstalla da "Impostazioni → App installate".
|
||||
|
||||
## Struttura del progetto
|
||||
|
||||
Il codice dell'app è tutto in `PrepStep/` (GUI e indicizzazione integrate); accanto ci sono
|
||||
il progetto di test `PrepStep.Tests/`, gli script standalone `scripts/` e lo script del setup
|
||||
`installer/`. Mappa file-per-file completa in [`docs/architettura.md`](docs/architettura.md).
|
||||
`installer/`. Mappa file-per-file completa in [`docs/architettura.md`](docs/architettura.md); indice di tutti i doc in
|
||||
[`docs/README.md`](docs/README.md).
|
||||
|
||||
- `Program.cs` — entry point.
|
||||
- `Form1.cs` — finestra principale, wizard a 5 fasi e menu; UI costruita interamente in
|
||||
@@ -145,18 +83,7 @@ Il database generato (`cad_index.db`), i file Excel/CSV della distinta
|
||||
trascinati nella root e le cartelle `raw/`/`step/` sono rigenerabili e non
|
||||
sono tracciati in git (vedi `.gitignore`).
|
||||
|
||||
## Test
|
||||
|
||||
`PrepStep.Tests/` (xUnit) contiene unit test (lettore esatto e euristica di
|
||||
estrazione dei componenti dai `.asm`, parsing del nome file Pro-E, import della
|
||||
distinta) e integration test (scansione su disco, schema/vista SQL reale con focus
|
||||
sui bug di case-sensitivity/duplicati già risolti, pipeline end-to-end). Da
|
||||
eseguire:
|
||||
|
||||
```powershell
|
||||
cd PrepStep.Tests
|
||||
dotnet test
|
||||
```
|
||||
Per i test vedi [`docs/sviluppo.md`](docs/sviluppo.md#test).
|
||||
|
||||
## Licenza
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Documentazione di PrepStep
|
||||
|
||||
Indice dei doc, organizzati secondo [Diátaxis](https://diataxis.fr/): ogni file ha **uno** scopo,
|
||||
e cambia solo quando cambia il programma.
|
||||
|
||||
## Tutorial — imparare facendo
|
||||
|
||||
- [`tutorial-primo-giro.md`](tutorial-primo-giro.md) — il primo giro completo con una distinta vera.
|
||||
|
||||
## How-to — svolgere un compito
|
||||
|
||||
- [`guida-utente.md`](guida-utente.md) — i passi dell'utente fino a Creo Distributed Batch.
|
||||
- [`risoluzione-problemi.md`](risoluzione-problemi.md) — sintomo → causa → cosa fare.
|
||||
- [`sviluppo.md`](sviluppo.md) — build, test, script e regole per scrivere i doc.
|
||||
- [`rilascio.md`](rilascio.md) — pubblicare e generare il setup di una nuova versione.
|
||||
|
||||
## Reference — consultare
|
||||
|
||||
- [`architettura.md`](architettura.md) — il processo delle 5 fasi e la mappa file-per-file.
|
||||
- [`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.
|
||||
|
||||
## Explanation — capire il perché
|
||||
|
||||
- [`decisioni/`](decisioni/README.md) — registro delle scelte di progetto (ADR).
|
||||
- [`copia-raw-parallela.md`](copia-raw-parallela.md) — perché e come la copia in `raw/` è parallela.
|
||||
|
||||
## Fonte unica (SSOT)
|
||||
|
||||
Ogni informazione vive in **un** posto; altrove si mette un link, non una copia.
|
||||
|
||||
| Informazione | Fonte |
|
||||
|---|---|
|
||||
| Versione e nome prodotto | `PrepStep/PrepStep.csproj` (`<Version>`, `<Product>`) |
|
||||
| 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) |
|
||||
| Procedura di rilascio e setup | [`rilascio.md`](rilascio.md) |
|
||||
| Perché una scelta è fatta così | [`decisioni/`](decisioni/README.md) |
|
||||
| Storico release | [`../CHANGELOG.md`](../CHANGELOG.md) |
|
||||
|
||||
`CLAUDE.md` e `README.md` riassumono soltanto e rimandano a questi file.
|
||||
|
||||
## Verifica
|
||||
|
||||
```powershell
|
||||
dotnet run scripts/CheckDocs.cs
|
||||
npx markdownlint-cli2
|
||||
```
|
||||
@@ -3,7 +3,7 @@
|
||||
Panoramica di tutti i file sorgente e di come collaborano. `PrepStep` è il nome
|
||||
tecnico del progetto (cartella, namespace, csproj, eseguibile `PrepStep.exe`);
|
||||
**PrepStep - Cevolani** è il nome mostrato all'utente finale (titolo finestra, icona,
|
||||
versione — vedi `<Version>`/`<Product>` in `PrepStep.csproj`). Per il "come si usa" vedi il `README.md` in root; per il
|
||||
versione — vedi `<Version>`/`<Product>` in `PrepStep.csproj`). Per il "come si usa" vedi il `README.md` in root e la [`guida-utente.md`](guida-utente.md); per il
|
||||
formato binario `.asm` vedi `docs/formato-asm.md` (euristica testuale) e
|
||||
`docs/formato-asm-record.md` (parser esatto dei record); per la parallelizzazione della
|
||||
copia in `raw/` vedi `docs/copia-raw-parallela.md`.
|
||||
@@ -94,7 +94,7 @@ trascinano i `.asm` su Creo Distributed Batch, che scrive in `step/`.
|
||||
| # | Fase | Bottone → metodo | Cosa fa |
|
||||
|---|---|---|---|
|
||||
| 1 | Database | "Aggiorna indice" → `Indexer.ScanAsync` | Crea/aggiorna `cad_index.db` scansionando la share; un pallino verde/rosso accanto al titolo indica se un DB è caricato. La cartella di lavoro non è mostrata qui (cambiabile in qualunque momento da "File → Scegli cartella di lavoro...") |
|
||||
| 2 | Importa Distinta Base | selezione file/drag&drop → `ImportaDistinta` → `DistintaBaseImporter.ConvertiInCsv`, poi "Verifica presenza" → `VerificaCodiciNelDb` | Xls/Xml gestionale → CSV componente;descrizione, scritto nella cartella di lavoro; "Verifica presenza" (visibile solo dopo un import riuscito) cerca i componenti nell'indice e colora le righe della griglia — è quella che sblocca "Avanti", non il solo import |
|
||||
| 2 | Importa Distinta Base | selezione file/drag&drop → `ImportaDistinta` → `DistintaBaseImporter.ConvertiInCsv`, poi "Verifica presenza" → `VerificaCodiciNelDb` | Xls/Xml gestionale → CSV componente;descrizione, scritto nella cartella di lavoro (oppure "Lista personalizzata": codici digitati uno alla volta con `AggiungiCodice`, solo in memoria, senza CSV; tutto a valle legge solo `_righeCorrenti`); "Verifica presenza" (visibile solo dopo un import riuscito) cerca i componenti nell'indice e colora le righe della griglia — è quella che sblocca "Avanti", non il solo import |
|
||||
| 3 | Crea cartella raw | "Crea cartella raw" → `CreaCartellaRaw` | `TrovaPercorsiCad` + `CopiaFileTrovati` (parallela) → `raw/` dentro la cartella di lavoro |
|
||||
| 4 | Trova componenti referenziati | "Trova componenti referenziati" → `TrovaPrtReferenziati` → `RisolviAlberoComponenti` | Legge i `.asm` in `raw/`, risolve ricorsivamente sotto-assiemi/parti nell'indice e li copia anch'essi in `raw/`, insieme ai componenti soppressi e ai modelli citati per riferimento esterno che servono a Creo per aprire l'assieme |
|
||||
| 5 | Verifica completezza | (ingresso in fase) → `AggiornaAnteprimaAsm` | Mostra le icone trascinabili dei `.asm` della distinta già in `raw/`, da trascinare su Creo per l'esportazione STEP (Distributed Batch) |
|
||||
@@ -282,7 +282,7 @@ l'`UninstallString`), perché Inno da solo aggiornerebbe sempre; con `/VERYSILEN
|
||||
La disinstallazione rimuove solo
|
||||
i file installati: `cad_index.db`, `raw/`/`step/`/CSV creati accanto all'exe e
|
||||
`%AppData%/PrepStep/` restano.
|
||||
Comandi di build del setup nel `README.md`.
|
||||
Comandi di build del setup in [`rilascio.md`](rilascio.md).
|
||||
|
||||
## Script standalone (`scripts/`)
|
||||
|
||||
@@ -301,6 +301,9 @@ dipendenze extra con `#:package Nome@versione` in testa al file):
|
||||
investigare a mano nuovi falsi positivi prima di toccare la regex di
|
||||
`AssemblyComponentScanner`.
|
||||
- **Query.cs** — query SQL ad-hoc contro `cad_index.db` da riga di comando.
|
||||
- **CheckDocs.cs** — controllo dei doc (docs-as-code): link relativi e ancore, `<Version>` del csproj
|
||||
uguale all'ultima voce del `CHANGELOG.md`, ogni `.cs` di `PrepStep/` e `scripts/` descritto qui.
|
||||
Exit 1 se qualcosa non torna.
|
||||
|
||||
> ⚠️ Nota importante di sicurezza: se `dotnet run` viene lanciato dentro `PrepStep/`
|
||||
> (che contiene un `.csproj` di tipo `WinExe`), esegue l'app GUI vera invece dello script
|
||||
@@ -310,7 +313,7 @@ dipendenze extra con `#:package Nome@versione` in testa al file):
|
||||
## Test
|
||||
|
||||
- **PrepStep.Tests/** (xUnit) — riferimento al progetto principale via `ProjectReference`
|
||||
+ `InternalsVisibleTo` (in `PrepStep.csproj`), così i test chiamano direttamente
|
||||
e `InternalsVisibleTo` (in `PrepStep.csproj`), così i test chiamano direttamente
|
||||
`Indexer.ParseFilename` e `AssemblyComponentScanner.EstraiCodiciReferenziati` senza esporli
|
||||
come API pubblica. File: `IndexerParseFilenameTests.cs`, `IndexerScanTests.cs`,
|
||||
`AssemblyComponentScannerTests.cs`, `AsmRecordReaderTests.cs`,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# 0001 — Indice dei file in un DB SQLite locale
|
||||
|
||||
**Stato:** accettata
|
||||
|
||||
## Contesto
|
||||
|
||||
La share `X:\` contiene centinaia di migliaia di file (ordine di ~200k righe indicizzate).
|
||||
Cercare un codice direttamente sul disco di rete a ogni distinta è lento: il costo è dominato
|
||||
dalla latenza di rete.
|
||||
|
||||
## Decisione
|
||||
|
||||
Scansionare la share una volta in un DB SQLite locale (`cad_index.db`) e interrogare quello.
|
||||
L'aggiornamento è incrementale (confronto su percorso, dimensione e data), la vista
|
||||
`files_ultima_versione` usa `ROW_NUMBER()` e non un self-join con `GROUP BY`.
|
||||
|
||||
## Conseguenze
|
||||
|
||||
- Le ricerche sono istantanee e non richiedono la share (la copia sì).
|
||||
- L'indice può essere vecchio: per questo la fase 2 ha "Verifica presenza".
|
||||
- Il DB è rigenerabile, quindi non è tracciato in git.
|
||||
- Schema e criteri di pareggio: [`../db-cad-index.md`](../db-cad-index.md).
|
||||
@@ -0,0 +1,18 @@
|
||||
# 0002 — UI WinForms costruita interamente in codice
|
||||
|
||||
**Stato:** accettata
|
||||
|
||||
## Contesto
|
||||
|
||||
L'app è un wizard a 5 fasi con stile condiviso (bottoni, card, barre) e stato comune tra fasi.
|
||||
|
||||
## Decisione
|
||||
|
||||
Nessun designer visuale: `Form1.BuildUi` e i `BuildFase*` costruiscono i controlli, `UiStile`
|
||||
centralizza lo stile. `Form1.Designer.cs` resta lo scheletro del template.
|
||||
|
||||
## Conseguenze
|
||||
|
||||
- Layout e stile modificabili e rivedibili come codice normale (diff leggibili).
|
||||
- Dimensioni con `AutoSize`+`Padding` invece di pixel fissi, per non tagliare il testo.
|
||||
- `Form1.cs` è grande (~1400 righe) perché contiene wizard e logica delle fasi.
|
||||
@@ -0,0 +1,29 @@
|
||||
# 0003 — Parser esatto dei `.asm` con fallback euristico
|
||||
|
||||
**Stato:** accettata
|
||||
|
||||
## Contesto
|
||||
|
||||
Il `.asm` Creo è un binario proprietario non documentato. La prima soluzione, un'euristica
|
||||
testuale (`AssemblyComponentScanner`), contava le occorrenze di stringhe candidate e produceva
|
||||
falsi positivi (riferimenti fantasma, componenti soppressi con placement residuo).
|
||||
|
||||
Inoltre la lista dei componenti della distinta **non coincide** con i file necessari a Creo per
|
||||
aprire l'assieme: ne servono di più (soppressi, riferimenti esterni). Se ne manca uno Creo
|
||||
risponde solo `[-4] Dati di input non completi`.
|
||||
|
||||
## Decisione
|
||||
|
||||
Per reverse engineering si è decodificata la struttura a record (`AsmRecordReader`), validata
|
||||
contro BOM esportate da Creo. È il metodo preferito. L'euristica resta come **fallback** quando
|
||||
il parser lancia `InvalidDataException`, perché la validazione copre solo un campione di file.
|
||||
La fase 4 tiene tre liste separate (distinta, soppressi, riferimenti esterni) con regole di
|
||||
ricorsione diverse.
|
||||
|
||||
## Conseguenze
|
||||
|
||||
- Estrazione esatta sui file che rispettano il formato; nessun falso positivo da conteggio.
|
||||
- Due implementazioni da mantenere, per ora; l'euristica serve anche a due script.
|
||||
- Ogni caso strano diventa un test minimale costruito byte per byte.
|
||||
- Dettagli: [`../formato-asm-record.md`](../formato-asm-record.md),
|
||||
[`../formato-asm.md`](../formato-asm.md).
|
||||
@@ -0,0 +1,27 @@
|
||||
# 0004 — Setup per-utente con DB nella cartella di installazione
|
||||
|
||||
**Stato:** accettata
|
||||
|
||||
## Contesto
|
||||
|
||||
Gli utenti non hanno diritti di amministratore. L'app scrive `cad_index.db` e, di default, la
|
||||
cartella di lavoro accanto all'eseguibile. In `C:\Program Files` non sarebbe scrivibile.
|
||||
|
||||
Prima il DB era scelto dall'utente e ricordato in `ultimo_db.txt`: si finiva con DB diversi tra
|
||||
postazioni e ricerche incoerenti.
|
||||
|
||||
## Decisione
|
||||
|
||||
- Setup Inno Setup 6 con `PrivilegesRequired=lowest`: installa in
|
||||
`%LOCALAPPDATA%\Programs\PrepStep`.
|
||||
- Il DB è sempre `cad_index.db` nella cartella di installazione; "Apri DB..." vale solo per la
|
||||
sessione e nulla viene ricordato.
|
||||
- `AppId` fisso per riconoscere gli aggiornamenti; se l'app è già installata il setup chiede se
|
||||
aggiornare o disinstallare.
|
||||
|
||||
## Conseguenze
|
||||
|
||||
- Nessun admin necessario; aggiornare non tocca DB e impostazioni.
|
||||
- La disinstallazione lascia DB, `raw/`, `step/`, CSV e `%AppData%\PrepStep\`.
|
||||
- In sviluppo il DB è nella cartella di build ([`../db-cad-index.md`](../db-cad-index.md)).
|
||||
- Procedura: [`../rilascio.md`](../rilascio.md).
|
||||
@@ -0,0 +1,22 @@
|
||||
# 0005 — Scegliere la copia di un componente dalla cartella dell'assieme
|
||||
|
||||
**Stato:** accettata
|
||||
|
||||
## Contesto
|
||||
|
||||
Per il 13% dei codici esiste più di una copia sulla share, con contenuto diverso e stessa
|
||||
versione. Il `.asm` non registra quale copia usa. Scegliere a caso, o per data, può mettere in
|
||||
`raw/` un modello diverso da quello atteso: Creo lo carica, i vincoli non si risolvono e
|
||||
l'assieme non si apre, con il solito `[-4]`.
|
||||
|
||||
## Decisione
|
||||
|
||||
`ScegliPerCartella` preferisce la copia nella stessa cartella dell'assieme che la referenzia
|
||||
(replica la regola di Creo) e solo in mancanza ripiega su versione più alta e data più recente.
|
||||
Nella vista `files_ultima_versione` il pareggio è deterministico (`data_modifica` e percorso
|
||||
nell'`ORDER BY`), ma serve solo a non sbagliare a caso.
|
||||
|
||||
## Conseguenze
|
||||
|
||||
- La fase 4 legge `files` (tutte le copie) e non la vista.
|
||||
- Dettaglio e casi reali: [`../formato-asm-record.md`](../formato-asm-record.md) §7.4.
|
||||
@@ -0,0 +1,21 @@
|
||||
# 0006 — Script standalone che referenziano il progetto principale
|
||||
|
||||
**Stato:** accettata
|
||||
|
||||
## Contesto
|
||||
|
||||
Servono strumenti da riga di comando (BOM, query, analisi di binari) senza duplicare la logica di
|
||||
lettura dei `.asm`.
|
||||
|
||||
## Decisione
|
||||
|
||||
Gli script in `scripts/` sono C# file-based apps (.NET 10) che referenziano
|
||||
`PrepStep/PrepStep.csproj` con `#:project`. La logica vive **solo** nel progetto principale: una
|
||||
sola fonte di verità per GUI e script.
|
||||
|
||||
## Conseguenze
|
||||
|
||||
- Si lanciano dalla root del repo; da dentro `PrepStep/` partirebbe la GUI.
|
||||
- Due famiglie non intercambiabili: euristica + DB (`ExtractCreoStrings`, `BomViaDb`) e parser
|
||||
esatto + cartelle locali (`CreoBom`). Vedi [`../architettura.md`](../architettura.md).
|
||||
- `CheckDocs.cs` segue lo stesso schema per i doc.
|
||||
@@ -0,0 +1,14 @@
|
||||
# Registro delle decisioni
|
||||
|
||||
Perché il programma è fatto così. Ogni voce spiega il contesto, la scelta e le conseguenze, così
|
||||
chi ci rimette mano non rifà il ragionamento da zero. Se cambia una scelta non si riscrive la
|
||||
vecchia voce: se ne aggiunge una nuova che la sostituisce.
|
||||
|
||||
| N. | Decisione | Stato |
|
||||
|---|---|---|
|
||||
| [0001](0001-indice-sqlite-locale.md) | Indice dei file in un DB SQLite locale | accettata |
|
||||
| [0002](0002-ui-winforms-in-codice.md) | UI WinForms costruita interamente in codice | accettata |
|
||||
| [0003](0003-parser-esatto-con-fallback.md) | Parser esatto dei `.asm` con fallback euristico | accettata |
|
||||
| [0004](0004-installazione-per-utente.md) | Setup per-utente con DB nella cartella di installazione | accettata |
|
||||
| [0005](0005-copia-nella-cartella-dell-assieme.md) | Scegliere la copia di un componente dalla cartella dell'assieme | accettata |
|
||||
| [0006](0006-script-che-riusano-il-progetto.md) | Script standalone che referenziano il progetto principale | accettata |
|
||||
Binary file not shown.
@@ -0,0 +1,535 @@
|
||||
# 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 |
|
||||
| `e4`-`e7` | 0 | `K − 3` zeri di seguito, `K` = byte − `e0` (solo dentro le matrici, §6.1) | **livello 1** (matrici di `9239902104`) |
|
||||
| `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
|
||||
<dim_type> 1 byte: classe della quota (tabella sotto)
|
||||
<feat_id> intero (formato asm-record §2.1): la feature a cui appartiene
|
||||
<attributi> \xf8 \x02 ... flag
|
||||
\xe3 <valore> <valore_di_backup> \xe3 ... due numeri uguali: value e bck_value
|
||||
\xe3 \x09 \x01 ... <tolleranza> ... blocco della tolleranza (nominal_value, bound...)
|
||||
```
|
||||
|
||||
Per leggere solo valore e feature basta ancorarsi a `\xe1 \x08 <dim_type> <feat_id>` 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 |
|
||||
|
||||
`9239902104.prt.1` (piastra con tre fori, §6.4.1):
|
||||
|
||||
| Feature | `dim_type` | Valore | Interpretazione |
|
||||
|---|---|---|---|
|
||||
| Sketch 1 / Estrusione 1 (84) | 1 / 5 / 1 | 21 / 54 / 125 (+ 46) | quote del profilo a L (§3.2) |
|
||||
| Estrusione 1 (84) | 62 | 6 | profondità, coerente con y = 0 ... 6 delle facce |
|
||||
| Sketch 2 / Foro 1 (124 / 131) | 8 / 2 / 2 / 7 | 38 / 8 / 8 / 30 | quote dei 4 punti (§6.4.1) |
|
||||
| Foro 1 (131) | 4 | 5,5 | diametro |
|
||||
| Sketch 3 / Foro 2 (1095 / 1099) | 2 / 2 | 4 / 5 | distanze del punto dai bordi: l'origine `(67, 6, -5)` = 71 − 4 e 5 |
|
||||
| Foro 2 (1099) | 4 | 5 | diametro |
|
||||
| Foro 3 (1132) | 4 / 9 / 2 / 2 | 3 / 6 / 2,5 / 137,5 | diametro nominale M3, profondità filetto, punta, lunghezza (distanza fino all'estremo, §6.1) |
|
||||
| Sketch 4 / Estrusione 2 (1903 / 1911) | 1 / 62 | 3,5 / 3 | quota dello schizzo e profondità |
|
||||
| Arrotondamento 1 (2777) | 3 | 3 | raggio, confermato dallo storico |
|
||||
|
||||
**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.
|
||||
|
||||
### 3.2 Secondo esempio: il profilo a L di *Estrusione 1* (`9239902104.prt.1`)
|
||||
|
||||
Le linee del profilo (`entity(line)`, estremi `(x, y)` nel sistema dello schizzo, `z = 0`):
|
||||
|
||||
| Linea | Da | A |
|
||||
|---|---|---|
|
||||
| 1 | (71, 0) | (−54, 0) |
|
||||
| 2 | (−54, 0) | (−54, 46) |
|
||||
| 3 | (−54, 46) | (0, 46) |
|
||||
| 4 | (0, 46) | (0, 21) |
|
||||
| 5 | (0, 21) | (71, 21) |
|
||||
| 6 | (71, 21) | (71, 0) |
|
||||
|
||||
più una linea d'asse. Le quote 125 (= 54 + 71), 54, 46 e 21 sono tutte spiegate dal profilo. Qui le
|
||||
linee stanno in `FeatDefs` (record della feature, sezione `S2D0006`), non in `BasFullData` come in
|
||||
§3: la posizione del blocco `p_saved_result` dipende dal tipo di feature.
|
||||
|
||||
## 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, schizzi e feature hanno un `local_sys`: array
|
||||
`f9 04 03` = 4 righe per 3 colonne = 12 numeri: **tre versori e, per ultima, l'origine**. Si leggono
|
||||
con i numeri di §1 più un codice di ripetizione: un byte `e4`-`e7` vale **"altri `K − 3` zeri"**,
|
||||
con `K` = byte − `e0` (`e4` = 1 zero, `e5` = 2, `e6` = 3, `e7` = 4). L'identità è quindi
|
||||
`0f 18 e5 0f 18 e5 0f 18 e5` = `1,0,0,0, 1,0,0,0, 1,0,0,0`.
|
||||
|
||||
**Verificato su `9239902104.prt.1`** (livello 1: i valori coincidono con quelli mostrati da Creo,
|
||||
sotto), con le 4 righe `(e1, e2, e3, origine)`:
|
||||
|
||||
| Feature | Matrice letta | Significato |
|
||||
|---|---|---|
|
||||
| Foro 1 | `(1,0,0) (0,0,-1) (0,1,0)`, origine `(-46, 6, -38)` | uno dei 4 punti dello schizzo `(-46, 38)`: x = x dello schizzo, z = **−**y dello schizzo, y = 6 = faccia superiore (la piastra è spessa 6) |
|
||||
| Foro 2 | `(1,0,0) (0,0,-1) (0,1,0)`, origine `(67, 6, -5)` | 71 − 4 e 5 dal bordo: le due quote 4 e 5 della feature |
|
||||
| Foro 3 | `(0,1,0) (-1,0,0) (0,0,1)`, origine `(-66.5, 3, -5)` | y = 3: l'**offset 3,00** dalla faccia superiore (y = 6) che Creo mostra; z = −5: allineato all'asse di Foro 2 (**"Allinea" con `A_7`**); x = −66,5 = 71 − 137,5, cioè il foro parte 137,5 prima dell'estremo destro (71) |
|
||||
|
||||
Quindi **la posizione di un foro si legge dall'origine della sua matrice**: le quote di
|
||||
posizionamento (4, 5, 3,00) non servono, sono già il risultato. Nei tre fori l'`y` e la `z` tornano
|
||||
esattamente con le quote e con i riferimenti mostrati da Creo.
|
||||
|
||||
Dalla stessa matrice: nel modello di questa piastra lo schizzo di Estrusione 1 sta nel piano `x–z`
|
||||
(x dello schizzo = x, y dello schizzo = −z) e l'estrusione cresce lungo +y fino a 6.
|
||||
|
||||
**Resta incerta l'interpretazione dell'asse del foro.** Per Foro 1 e 2 il terzo versore è `(0,1,0)`
|
||||
(perpendicolare alla piastra, come deve essere). Per Foro 3 è `(0,0,1)`, ma il foro in Creo entra
|
||||
dalla faccia laterale: o la convenzione del versore dell'asse è diversa, o la direzione di foratura
|
||||
sta in un altro campo. Non risolto.
|
||||
|
||||
### 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_<tipo>`) |
|
||||
| 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<n>` 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.4.1 Foro a punti di schizzo e facce piane: `9239902104.prt.1`
|
||||
|
||||
*Foro 1* è definito da *Sketch 2* con **4 punti**. Cosa si legge, tutto da `local_sys` (§6.1):
|
||||
|
||||
**I punti.** Nello schizzo (`entity(point)`, campo `pnt`, un `[x, y, z]` per punto) sono
|
||||
`(-46, 8)`, `(-8, 8)`, `(-8, 38)`, `(-46, 38)`, con quote 8, 8, 30 e 38. Nel modello ogni punto
|
||||
diventa un'**istanza** del foro, e ogni istanza ha un piano proprio in `NovisGeom` (superficie
|
||||
piana con `feat_id` 131, §6.3) con la matrice del punto: l'**origine** è la posizione assoluta.
|
||||
|
||||
| Piano (`geom_id`) | Origine nel modello |
|
||||
|---|---|
|
||||
| 135 | `(-46, 6, -8)` |
|
||||
| 147 | `(-8, 6, -8)` |
|
||||
| 159 | `(-8, 6, -38)` |
|
||||
| 171 | `(-46, 6, -38)` |
|
||||
|
||||
Quindi `x` = `x` dello schizzo, `z` = **−**`y` dello schizzo (confermato dai quattro punti e da Foro
|
||||
2, §6.1) e `y` = 6.
|
||||
|
||||
**La faccia.** La superficie su cui stanno è la faccia piana superiore di *Estrusione 1*: ha
|
||||
`y = 6` e la stessa matrice del sistema di coordinate dello schizzo (origine `(0, 6, 0)`,
|
||||
versori `(1,0,0)`, `(0,0,1)`, `(0,-1,0)`). Le facce piane di *Estrusione 1* (`feat_id` 84, in
|
||||
`VisibGeom`) sono, con origine e normale (il terzo versore):
|
||||
|
||||
| `geom_id` | Origine | Normale | Faccia |
|
||||
|---|---|---|---|
|
||||
| 95 | `(0, 6, 0)` | `(0,-1,0)` | **superiore** (`y = 6`), dove sono i fori |
|
||||
| 107 | `(71, 0, 0)` | `(-1,0,0)` | estremo destro (`x = 71`) |
|
||||
| 113 | `(-54, 0, -46)` | `(1,0,0)` | estremo sinistro (`x = -54`) |
|
||||
| 115 | `(-54, 0, 0)` | `(0,0,1)` | lato `z = 0` |
|
||||
| 2999 | `(71, 0, -21)` | `(0,0,-1)` | lato del gradino (`z = -21`) |
|
||||
| 3001 | `(0, 0, -21)` | `(-1,0,0)` | alzata del gradino (`x = 0`) |
|
||||
| 3003 | `(0, 0, -46)` | `(0,0,-1)` | lato `z = -46` |
|
||||
|
||||
La piastra a L di Estrusione 1 (§3.2, profilo `x` da −54 a 71, `y` dello schizzo da 0 a 46, gradino
|
||||
a 21) torna in coordinate modello con `z = −y` dello schizzo, e spessore 6 lungo `y`. Gli altri
|
||||
tre fori cadono dentro il materiale (`x` −46 e −8, `z` −8 e −38).
|
||||
|
||||
**Non risolto:** quale `geom_id` il foro usi *formalmente* come faccia di riferimento (95, per
|
||||
coincidenza di piano e di origine) non è scritto in un campo che io abbia identificato: è
|
||||
un'identificazione per posizione, non una lettura.
|
||||
|
||||
### 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.
|
||||
|
||||
**Foro filettato con posizionamento lineare** (*Foro 3* di `9239902104.prt.1`). Creo mostra: tipo
|
||||
Standard, Diritto, Maschiato, ISO **M3x.5**, Ø2,50 (punta), campo profondità vuoto, posizionamento
|
||||
**Lineare** con riferimento primario `Supfce:F6(ESTRUSIONE_1)` e due riferimenti di offset
|
||||
(`Supfce:F6(ESTRUSIONE_1)` con offset 3,00 e `A_7(ASSE):F10(FORO 2)` allineato). Dal file:
|
||||
|
||||
| Informazione | Letto | Prova |
|
||||
|---|---|---|
|
||||
| Filetto | stringhe `ISO`, `M3x.5`, punta `2.5`; `scrsize_val` = 12 | concorda con Creo |
|
||||
| Ø della punta | istruzione 5104, offset 2,5 | concorda con Creo (Ø2,50) |
|
||||
| Quote del foro | 3 (`dim_type` 4), 6 (9), 2,5 (2), 137,5 (2) | numeri letti; 137,5 con campo "Profondità" vuoto in Creo: probabilmente un foro passante, valore non verificato |
|
||||
| Posizione risultante (offset 3,00 e allineamento a `A_7`) | **letta dalla matrice** `local_sys` (§6.1): origine `(-66.5, 3, -5)`, con y = 3 e z = −5 uguali a quelli di Foro 2 | concorda con Creo; la quota 3,00 non è una quota a sé nel `dim_array` |
|
||||
| Riferimenti `F6` e `A_7` | non risolti | gli id stanno in blocchi `plin_info_ref` come per DTM1 (§6.3) |
|
||||
|
||||
Correzione: il primo codice delle istruzioni è 5542 anche qui, come nel foro coassiale di
|
||||
`9252000507`; il `12266` che avevo letto nella prima versione di questo doc veniva da un'istruzione
|
||||
di un altro record. Il tipo di posizionamento (coassiale / lineare) **non** è quel codice. Quale sia
|
||||
non lo so: la posizione finale si legge comunque dalla matrice (§6.1).
|
||||
|
||||
## 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 fori e feature | **fatto**: matrice 4×3 (§6.1) | `local_sys` |
|
||||
| Posizione/rotazione di piani, assi, punti | stessa matrice, da verificare su un piano ruotato | `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 assoluta del foro (origine e versori) | **fatto**, provato contro i riferimenti di Creo su `9239902104` (§6.1) | `local_sys` del record |
|
||||
| Riferimenti del posizionamento (quale faccia/asse) | **non decodificato** | `plin_info_ref` in `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.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Glossario
|
||||
|
||||
| Termine | Significato |
|
||||
|---|---|
|
||||
| Assieme generale | l'assieme di primo livello di una distinta; il foglio del gestionale non lo elenca, l'app lo aggiunge come riga se il file è `DBP_<codice>_<timestamp>` |
|
||||
| `.asm` / `.prt` | file Creo/Pro-E di assieme e di parte; il nome è `<codice>.<tipo>.<versione>` |
|
||||
| Cartella di lavoro | dove finiscono CSV, `raw/` e `step/`; di default la cartella di installazione |
|
||||
| Codice | identificativo del componente, ricavato dal nome del file (può avere una lettera di revisione attaccata) |
|
||||
| Creo Distributed Batch | strumento PTC che esporta in batch (qui in STEP); usato a mano, fuori dall'app |
|
||||
| Distinta Base (DBP) | estrazione dal gestionale (Fata) dei componenti di un assieme |
|
||||
| Family table | tabella di varianti di un modello; il nome dell'istanza sta nel parametro `ConfigName` |
|
||||
| Indice | il DB `cad_index.db` con i metadati dei file della share |
|
||||
| `members` | sezione del `.asm` con i componenti diretti dell'assieme |
|
||||
| `raw/` | cartella con i file CAD da passare a Creo |
|
||||
| Riferimento esterno | modello citato da un assembly feature o datum copiato; non è un membro, ma Creo lo carica con il suo albero |
|
||||
| Share | disco di rete con i file CAD, `X:\` di default |
|
||||
| Soppresso | componente tolto dalla distinta ma il cui file serve comunque ad aprire l'assieme |
|
||||
| `step/` | cartella degli STEP esportati da Creo; non scritta dall'app |
|
||||
| `temp_*` | cartelle personali della share, escluse dall'indice |
|
||||
| Ultima versione | per ogni `(cartella_radice, codice, tipo_file)` la riga con versione più alta (vista `files_ultima_versione`) |
|
||||
@@ -76,7 +76,13 @@ Premi **Avanti** quando il database è caricato.
|
||||
oppure premi **Scegli file distinta...** e selezionalo da Esplora risorse. Le righe importate
|
||||
compaiono nella griglia (Componente/Descrizione) e viene scritto un CSV nella cartella
|
||||
di lavoro.
|
||||
- **2. Verifica la presenza dei file sul server**: compare solo dopo un import riuscito.
|
||||
In alternativa scegli **Lista personalizzata**: digita un codice e premi **Invio** (o
|
||||
**Aggiungi**) per inserirlo, ripeti per ogni codice; **Canc** sulla riga selezionata lo
|
||||
toglie. La lista non scrive nessun CSV e, passando da una modalità all'altra, viene azzerata
|
||||
(con conferma). Inserisci anche l'assieme generale, se serve: qui non viene aggiunto da solo.
|
||||
- **2. Verifica la presenza dei file sul server**: compare solo dopo un import riuscito
|
||||
(o dopo il primo codice aggiunto alla lista personalizzata; ogni modifica della lista
|
||||
richiede di rifare la verifica).
|
||||
Premila per cercare ogni componente nel database — le righe della griglia si colorano
|
||||
di verde (trovato) o rosso (non trovato nell'indice).
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Rilasciare una nuova versione
|
||||
|
||||
Procedura per produrre il setup `PrepStep-Setup-<versione>.exe`, l'unico file da distribuire.
|
||||
Il comportamento del setup (installazione per-utente, aggiornamento, `/VERYSILENT`) è descritto
|
||||
in [`architettura.md`](architettura.md#installazione); qui ci sono solo i passi da eseguire.
|
||||
|
||||
## Una volta sola
|
||||
|
||||
Installa Inno Setup 6 per l'utente corrente (niente admin):
|
||||
|
||||
```powershell
|
||||
winget install --id JRSoftware.InnoSetup -e --scope user
|
||||
```
|
||||
|
||||
## A ogni release
|
||||
|
||||
1. Aggiorna `<Version>` in `PrepStep/PrepStep.csproj` (SemVer).
|
||||
2. In [`CHANGELOG.md`](../CHANGELOG.md) trasforma "Non rilasciato" nella nuova versione con la
|
||||
data e riscrivi sotto le modifiche (Aggiunto/Modificato/Corretto/Rimosso).
|
||||
3. Controlla i doc: `dotnet run scripts/CheckDocs.cs` deve confermare che versione e CHANGELOG
|
||||
coincidono.
|
||||
4. Esegui i test: `dotnet test` in `PrepStep.Tests/`.
|
||||
5. Chiudi l'app se è aperta (l'exe in uso blocca la build), poi dalla root del repo:
|
||||
|
||||
```powershell
|
||||
dotnet publish PrepStep -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o PrepStep\publish
|
||||
& "$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe" installer\PrepStep.iss
|
||||
```
|
||||
|
||||
6. Il setup è in `installer\Output\PrepStep-Setup-<versione>.exe`; la versione è letta
|
||||
dall'exe, quindi coincide con `<Version>`. Provalo lanciandolo.
|
||||
7. Commit con codice, doc e CHANGELOG insieme (regola in [`README.md`](README.md)).
|
||||
|
||||
## Solo l'eseguibile, senza setup
|
||||
|
||||
```powershell
|
||||
cd PrepStep
|
||||
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o publish
|
||||
```
|
||||
|
||||
Produce `PrepStep\publish\PrepStep.exe`, un file unico che gira su un Windows x64 senza .NET
|
||||
installato.
|
||||
|
||||
## Da non toccare
|
||||
|
||||
`AppGuid` in `installer/PrepStep.iss`: è ciò che fa riconoscere a Windows le versioni nuove
|
||||
come aggiornamento della stessa app. Cambiarlo produce un'installazione doppia.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Risoluzione dei problemi
|
||||
|
||||
Sintomo → causa probabile → cosa fare. I messaggi di Creo non nominano il file né la causa, per
|
||||
questo il sintomo è il punto di partenza.
|
||||
|
||||
## Dentro l'app
|
||||
|
||||
| Sintomo | Causa probabile | Cosa fare |
|
||||
|---|---|---|
|
||||
| Pallino rosso in fase 1, "Database non trovato" | non c'è `cad_index.db` nella cartella di installazione | **Aggiorna indice** (lo crea lì), oppure **Apri DB...** per usarne un altro solo per la sessione |
|
||||
| "Disco non raggiungibile: X:\" | la share non è montata o non hai accesso | monta `X:\` e riprova; la radice è fissa in `Form1.RadiceDiscoDefault` |
|
||||
| Componente rosso in "Verifica presenza" | il codice non è nell'indice: indice vecchio, oppure il nome su disco ha una lettera di revisione in più o in meno | **Aggiorna indice**; poi cerca il codice con `LIKE` (vedi sotto) |
|
||||
| "Avanti" resta grigio in fase 2 | manca il passo **Verifica presenza** | premila: non basta l'import |
|
||||
| Alcuni file non compaiono in `raw/` dopo fase 3/4 | la copia salta in silenzio i file irraggiungibili (share offline, permessi) | controlla l'accesso alla share e ripeti la fase |
|
||||
| In fase 4 compaiono codici "non trovati" | disegni, componenti davvero assenti dalla share o falsi positivi della scansione | controllali a mano; non bloccano il lavoro |
|
||||
| Risultati incoerenti in sviluppo | l'app sta usando il DB della cartella di build, non quello che credi | guarda il percorso mostrato in fase 1; apri il DB giusto con **Apri DB...** |
|
||||
|
||||
Per capire se un codice è nell'indice:
|
||||
|
||||
```powershell
|
||||
dotnet run scripts/Query.cs -- cad_index.db "SELECT codice, tipo_file, percorso_completo FROM files_ultima_versione WHERE codice LIKE '925%' LIMIT 20"
|
||||
```
|
||||
|
||||
Nessuna riga nemmeno con `LIKE` → il file non è indicizzato. Una riga con codice leggermente
|
||||
diverso → revisione, maiuscole o spazi.
|
||||
|
||||
## In Creo Distributed Batch
|
||||
|
||||
| Sintomo | Causa probabile | Cosa fare |
|
||||
|---|---|---|
|
||||
| `[-4] Dati di input non completi` | nell'albero manca un file che Creo deve caricare, ma non dice quale | rifai la fase 4 e leggi l'elenco dei "non trovati"; poi vedi sotto |
|
||||
| L'assieme non si apre, nessun messaggio chiaro | in `raw/` c'è una copia sbagliata di un componente (lo stesso codice esiste in più cartelle, 13% dei casi) | l'app sceglie la copia nella cartella dell'assieme: [`formato-asm-record.md`](formato-asm-record.md) §7.4 |
|
||||
| Assieme con un componente soppresso che non si apre | il file del soppresso non era in `raw/` | §7.3; oggi la fase 4 lo copia |
|
||||
| Assieme con feature di assembly o datum copiati che non si apre | manca il modello citato per riferimento esterno | §7.5; oggi la fase 4 lo copia con il suo albero |
|
||||
|
||||
## Da sviluppatore
|
||||
|
||||
| Sintomo | Causa | Cosa fare |
|
||||
|---|---|---|
|
||||
| `dotnet run` apre la GUI e si blocca | lanciato dentro `PrepStep/` | lanciare gli script dalla root del repo |
|
||||
| `dotnet publish` fallisce con file in uso | l'app è aperta | chiudila e ripeti |
|
||||
| `CheckDocs.cs` segnala un file non descritto | nuovo `.cs` o doc non documentato | aggiungilo a `architettura.md` o a `docs/README.md` |
|
||||
|
||||
## Dopo la disinstallazione
|
||||
|
||||
Restano `cad_index.db`, `raw/`, `step/`, i CSV e `%AppData%\PrepStep\`: vanno cancellati a mano.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Guida per chi sviluppa
|
||||
|
||||
Come lavorare sul codice e sui doc. Per capire com'è fatto il programma parti da
|
||||
[`architettura.md`](architettura.md); per rilasciare vedi [`rilascio.md`](rilascio.md).
|
||||
|
||||
## Requisiti
|
||||
|
||||
- Windows e [.NET 10 SDK](https://dotnet.microsoft.com/download).
|
||||
- Accesso alla share `X:\` solo per indicizzare davvero; i test non ne hanno bisogno.
|
||||
- Node.js (per `npx markdownlint-cli2`, solo per i doc).
|
||||
|
||||
## Build e avvio
|
||||
|
||||
```powershell
|
||||
cd PrepStep
|
||||
dotnet build -c Release
|
||||
dotnet run -c Release
|
||||
```
|
||||
|
||||
In sviluppo `cad_index.db` si cerca nella cartella di build, non nella radice del repo: vedi
|
||||
[`db-cad-index.md`](db-cad-index.md#come-lapp-trova-il-db-allavvio).
|
||||
|
||||
## Test
|
||||
|
||||
```powershell
|
||||
cd PrepStep.Tests
|
||||
dotnet test
|
||||
```
|
||||
|
||||
I test xUnit chiamano gli `internal` del progetto principale grazie a `InternalsVisibleTo`. I
|
||||
`.asm` dei test si costruiscono byte per byte con piccoli helper invece di versionare file
|
||||
binari: ogni caso strano trovato sulla share diventa un test minimale. Elenco dei file di test in
|
||||
[`architettura.md`](architettura.md#test).
|
||||
|
||||
## Script standalone
|
||||
|
||||
Si lanciano dalla **root del repo**, mai da dentro `PrepStep/` (che è un `WinExe`: `dotnet run`
|
||||
avvierebbe la GUI e resterebbe bloccato). Elenco in
|
||||
[`architettura.md`](architettura.md#script-standalone-scripts).
|
||||
|
||||
```powershell
|
||||
dotnet run scripts/Query.cs -- cad_index.db "SELECT COUNT(*) FROM files"
|
||||
```
|
||||
|
||||
## Documentazione come codice
|
||||
|
||||
I doc stanno in git, si modificano nello stesso commit del codice e si verificano a mano:
|
||||
|
||||
```powershell
|
||||
dotnet run scripts/CheckDocs.cs # link, ancore, versione/CHANGELOG, copertura dei doc
|
||||
npx markdownlint-cli2 # stile Markdown (.markdownlint-cli2.jsonc)
|
||||
```
|
||||
|
||||
Regole di scrittura:
|
||||
|
||||
- **Una sola fonte per ogni informazione**, altrove un link (tabella in [`README.md`](README.md)).
|
||||
- **Ogni doc ha un solo scopo** (Diátaxis): non mescolare istruzioni, riferimento e motivazioni.
|
||||
- Un cambiamento strutturale (fasi, formato `.asm`, schema DB, criterio di scelta di un file)
|
||||
aggiorna i doc e il CHANGELOG **nello stesso commit**.
|
||||
- Se la modifica nasce da un fallimento reale di Creo scrivi **il sintomo**: i messaggi di Creo
|
||||
non nominano il file né la causa (esempio: §7.3-7.5 di
|
||||
[`formato-asm-record.md`](formato-asm-record.md)).
|
||||
- Una scelta con alternative reali non banali merita una voce in
|
||||
[`decisioni/`](decisioni/README.md).
|
||||
- Un nuovo `.cs` va descritto in `architettura.md` e un nuovo doc elencato in `docs/README.md`:
|
||||
`CheckDocs.cs` lo verifica.
|
||||
@@ -0,0 +1,64 @@
|
||||
# Tutorial: il tuo primo giro con PrepStep
|
||||
|
||||
Questo tutorial ti porta, con una distinta vera, dall'app appena installata ai file `raw/` pronti
|
||||
per Creo. Alla fine saprai cosa produce ogni fase e come capire se è andata bene. Per il
|
||||
dettaglio di ogni schermata e per l'esportazione in Creo vedi [`guida-utente.md`](guida-utente.md).
|
||||
|
||||
**Ti serve:** il programma installato (setup in [`rilascio.md`](rilascio.md)), la share `X:\`
|
||||
raggiungibile e un'estrazione "Distinta Base" `.xls` del gestionale, meglio se piccola (poche
|
||||
decine di righe) per il primo giro.
|
||||
|
||||
## 1. Avvia e carica l'indice
|
||||
|
||||
Apri **PrepStep - Cevolani**. Accanto a "Database" c'è un pallino.
|
||||
|
||||
- **Verde:** l'indice c'è già, vai al passo 2.
|
||||
- **Rosso:** premi **Aggiorna indice**. La prima volta scansiona tutta la share e richiede
|
||||
qualche minuto; vedi una barra di avanzamento con i conteggi.
|
||||
|
||||
Risultato atteso: pallino verde, percorso di `cad_index.db` e data dell'aggiornamento.
|
||||
Premi **Avanti**.
|
||||
|
||||
## 2. Importa la distinta
|
||||
|
||||
Trascina il `.xls` nella finestra. Risultato atteso: la griglia si riempie con
|
||||
Componente/Descrizione e nella cartella di lavoro compare un CSV con lo stesso nome base.
|
||||
Poi premi **Verifica presenza**: le righe diventano verdi (trovato nell'indice) o rosse (non
|
||||
trovato). Solo ora **Avanti** si sblocca.
|
||||
|
||||
Se vedi righe rosse non fermarti: nel primo giro è normale scoprire che l'indice è vecchio o
|
||||
che un componente non è sulla share. Vedi [`risoluzione-problemi.md`](risoluzione-problemi.md).
|
||||
|
||||
## 3. Crea la cartella raw
|
||||
|
||||
Premi **Crea cartella raw**. Risultato atteso: nella cartella di lavoro nasce `raw/` con i file
|
||||
`.prt`/`.asm` dei componenti trovati, e la griglia mostra il percorso CAD di ciascuno.
|
||||
|
||||
## 4. Trova i componenti referenziati
|
||||
|
||||
Premi **Trova componenti referenziati**. L'app legge i `.asm` in `raw/` e copia anche tutto
|
||||
quello che serve a Creo per aprirli (sotto-assiemi, componenti soppressi, riferimenti esterni).
|
||||
Risultato atteso: una finestra con l'elenco di quanto copiato e, in fondo, i codici "non
|
||||
trovati". `raw/` ora contiene più file di prima: è giusto così, perché la lista dei file
|
||||
necessari è più lunga di quella della distinta (il perché, in
|
||||
[`decisioni/0003-parser-esatto-con-fallback.md`](decisioni/0003-parser-esatto-con-fallback.md)).
|
||||
|
||||
## 5. Porta i `.asm` a Creo
|
||||
|
||||
La fase 5 mostra i `.asm` della distinta come icone trascinabili. Trascinali su **Creo
|
||||
Distributed Batch** (passi in
|
||||
[`guida-utente.md`](guida-utente.md#5-verifica-completezza-e-creo-distributed-batch)):
|
||||
i file STEP finiscono in `step/`.
|
||||
|
||||
## Cosa hai imparato
|
||||
|
||||
| Fase | Entra | Esce |
|
||||
|---|---|---|
|
||||
| 1 | share `X:\` | `cad_index.db` |
|
||||
| 2 | `.xls` del gestionale | CSV + verifica sull'indice |
|
||||
| 3 | CSV + indice | `raw/` con i componenti della distinta |
|
||||
| 4 | `.asm` in `raw/` | `raw/` completa dell'albero |
|
||||
| 5 | `raw/` | `.asm` da trascinare su Creo |
|
||||
|
||||
Per un secondo giro con un'altra distinta usa **File → Nuovo** (Ctrl+N), e prima ripulisci
|
||||
`raw/`/`step/` da **File → Pulisci raw e step...**.
|
||||
@@ -0,0 +1,59 @@
|
||||
// dotnet run scripts/CheckDocs.cs (dalla root del repo; exit 1 se i doc sono fuori allineamento)
|
||||
// Controlla anche che ogni doc di docs/ e docs/decisioni/ sia nell'indice.
|
||||
// Controlla: link relativi (file e #ancora), <Version> del csproj == ultima voce del CHANGELOG,
|
||||
// ogni .cs di PrepStep/ e scripts/ citato in docs/architettura.md.
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
var errori = new List<string>();
|
||||
var mdFiles = Directory.EnumerateFiles(".", "*.md", SearchOption.AllDirectories)
|
||||
.Where(f => !f.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}")
|
||||
&& !f.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}")
|
||||
&& !f.Contains($"{Path.DirectorySeparatorChar}raw{Path.DirectorySeparatorChar}")
|
||||
&& !f.Contains($"{Path.DirectorySeparatorChar}step{Path.DirectorySeparatorChar}")).ToList();
|
||||
|
||||
// slug delle intestazioni come lo calcola GitHub/Gitea
|
||||
static HashSet<string> Ancore(string path) =>
|
||||
File.ReadLines(path).Where(l => l.StartsWith('#'))
|
||||
.Select(l => Regex.Replace(Regex.Replace(l.TrimStart('#').Trim().ToLowerInvariant(), @"[`*]", ""), @"[^\p{L}\p{N}\- _]", "").Replace(' ', '-'))
|
||||
.ToHashSet();
|
||||
|
||||
// 1. link relativi
|
||||
foreach (var f in mdFiles)
|
||||
{
|
||||
var testo = Regex.Replace(File.ReadAllText(f), @"```.*?```", "", RegexOptions.Singleline);
|
||||
foreach (Match m in Regex.Matches(testo, @"\]\(([^)\s]+)\)"))
|
||||
{
|
||||
var url = m.Groups[1].Value;
|
||||
if (Regex.IsMatch(url, @"^[a-z]+:")) continue; // http:, mailto:, ...
|
||||
var parti = url.Split('#', 2);
|
||||
var target = parti[0] == "" ? f : Path.GetFullPath(Path.Combine(Path.GetDirectoryName(f)!, parti[0]));
|
||||
if (!File.Exists(target) && !Directory.Exists(target)) { errori.Add($"{f}: link rotto -> {url}"); continue; }
|
||||
if (parti.Length == 2 && target.EndsWith(".md") && !Ancore(target).Contains(parti[1].ToLowerInvariant()))
|
||||
errori.Add($"{f}: ancora inesistente -> {url}");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. versione
|
||||
var version = Regex.Match(File.ReadAllText("PrepStep/PrepStep.csproj"), @"<Version>(.+?)</Version>").Groups[1].Value;
|
||||
var ultima = Regex.Match(File.ReadAllText("CHANGELOG.md"), @"^## \[(\d[^\]]*)\]", RegexOptions.Multiline).Groups[1].Value;
|
||||
if (version != ultima) errori.Add($"CHANGELOG.md: ultima voce {ultima} != <Version> {version} del csproj");
|
||||
|
||||
// 3. ogni sorgente citato nella mappa file-per-file
|
||||
var arch = File.ReadAllText("docs/architettura.md");
|
||||
foreach (var cs in Directory.EnumerateFiles("PrepStep", "*.cs").Concat(Directory.EnumerateFiles("scripts", "*.cs")))
|
||||
{
|
||||
var nome = Path.GetFileName(cs);
|
||||
if (!arch.Contains(nome) && !nome.EndsWith(".Designer.cs")) errori.Add($"docs/architettura.md: {cs} non è descritto");
|
||||
}
|
||||
|
||||
// 4. ogni doc in docs/ è raggiungibile dall'indice della sua cartella
|
||||
foreach (var dir in new[] { "docs", Path.Combine("docs", "decisioni") })
|
||||
{
|
||||
var indice = File.ReadAllText(Path.Combine(dir, "README.md")) + (dir == "docs" ? File.ReadAllText(Path.Combine(dir, "decisioni", "README.md")) : "");
|
||||
foreach (var md in Directory.EnumerateFiles(dir, "*.md").Where(f => Path.GetFileName(f) != "README.md"))
|
||||
if (!indice.Contains(Path.GetFileName(md))) errori.Add($"{dir}/README.md: {Path.GetFileName(md)} non è nell'indice");
|
||||
}
|
||||
|
||||
errori.ForEach(Console.Error.WriteLine);
|
||||
Console.WriteLine(errori.Count == 0 ? $"Doc OK ({mdFiles.Count} file md)" : $"{errori.Count} problemi");
|
||||
return errori.Count == 0 ? 0 : 1;
|
||||
Reference in new issue
Block a user