Recognize commercial parts with alphabetic names in .asm scanning
Pro-E numeric codes cover most components, but parts downloaded as STEP from online catalogs (rings, bushings, knobs...) get alphabetic Creo names with no predictable shape. Add a second extraction path that tokenizes the binary generically and validates candidates against the known codes in cad_index.db, applying the same placement/occurrence rule used for bare numeric codes. Numeric extraction is unchanged, so missing-from-index reporting for renamed/moved Pro-E codes still works. Also load all known prt/asm codes once per scan instead of one query per candidate, in both RisolviAlberoComponenti and VerificaCompletezzaAssiemi. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c75dd21551
commit
8a8a7d0417
7 files changed
+363
-106
No files matched your search
+32
-58
@@ -662,6 +662,31 @@ public partial class Form1 : Form
|
||||
ImpostaStatoImport($"{eliminati} file eliminati da {string.Join(" e ", cartelle)}.", Color.DarkGreen);
|
||||
}
|
||||
|
||||
/// <summary>Tutti i codici prt/asm noti all'indice, con i relativi percorsi (ultima
|
||||
/// versione, un solo file per tipo - stesso criterio di dedup per data_modifica DESC
|
||||
/// usato ovunque in questa classe). Caricato in un'unica query invece che una per
|
||||
/// codice: serve sia a risolvere i percorsi dei componenti trovati, sia a
|
||||
/// AssemblyComponentScanner per validare i token generici (parti commerciali).</summary>
|
||||
private static Dictionary<string, List<(string Tipo, string Percorso)>> CaricaCodiciNoti(string dbPath)
|
||||
{
|
||||
var codiciNoti = new Dictionary<string, List<(string Tipo, string Percorso)>>(StringComparer.OrdinalIgnoreCase);
|
||||
using var connection = new SqliteConnection($"Data Source={dbPath};Mode=ReadOnly");
|
||||
connection.Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT codice, tipo_file, percorso_completo FROM files_ultima_versione "
|
||||
+ "WHERE LOWER(tipo_file) IN ('prt', 'asm') ORDER BY codice, tipo_file, data_modifica DESC";
|
||||
using var reader = command.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
string codice = reader.GetString(0);
|
||||
string tipo = reader.GetString(1).ToLowerInvariant();
|
||||
var lista = codiciNoti.TryGetValue(codice, out var l) ? l : codiciNoti[codice] = new();
|
||||
if (!lista.Any(x => x.Tipo == tipo))
|
||||
lista.Add((tipo, reader.GetString(2)));
|
||||
}
|
||||
return codiciNoti;
|
||||
}
|
||||
|
||||
/// <summary>Risolve ricorsivamente l'albero dei componenti a partire dai file .asm indicati
|
||||
/// (già copiati in "raw"): per ogni assieme legge i codici referenziati al suo interno, li
|
||||
/// cerca nell'indice, copia in "raw" quelli trovati e, se sono a loro volta assiemi, li
|
||||
@@ -681,42 +706,19 @@ public partial class Form1 : Form
|
||||
if (daScansionare.Count == 0 || _dbPath is null)
|
||||
return (trovati, codiciNonTrovati);
|
||||
|
||||
using var connection = new SqliteConnection($"Data Source={_dbPath};Mode=ReadOnly");
|
||||
connection.Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT tipo_file, percorso_completo FROM files_ultima_versione "
|
||||
+ "WHERE LOWER(codice) = LOWER(@codice) AND LOWER(tipo_file) IN ('prt', 'asm') "
|
||||
+ "ORDER BY tipo_file, data_modifica DESC";
|
||||
var pCodice = command.Parameters.Add("@codice", Microsoft.Data.Sqlite.SqliteType.Text);
|
||||
var codiciNoti = CaricaCodiciNoti(_dbPath);
|
||||
|
||||
int processati = 0;
|
||||
while (daScansionare.Count > 0)
|
||||
{
|
||||
var asm = daScansionare.Dequeue();
|
||||
processati++;
|
||||
foreach (var codice in AssemblyComponentScanner.EstraiCodiciReferenziati(asm))
|
||||
foreach (var codice in AssemblyComponentScanner.EstraiCodiciReferenziati(asm, codiciNoti.Keys))
|
||||
{
|
||||
if (!codiciVisti.Add(codice))
|
||||
continue;
|
||||
|
||||
pCodice.Value = codice;
|
||||
// Lo stesso codice+tipo può esistere in più cartelle radice (duplicati sulla
|
||||
// share): ordinato per data_modifica DESC, si tiene solo il più recente per tipo.
|
||||
var componenti = new List<(string Tipo, string Percorso)>();
|
||||
var tipiVisti = new HashSet<string>();
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
string tipoLower = reader.GetString(0).ToLowerInvariant();
|
||||
if (tipiVisti.Add(tipoLower))
|
||||
{
|
||||
componenti.Add((tipoLower, reader.GetString(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (componenti.Count == 0)
|
||||
if (!codiciNoti.TryGetValue(codice, out var componenti))
|
||||
{
|
||||
codiciNonTrovati.Add(codice);
|
||||
continue;
|
||||
@@ -790,39 +792,11 @@ public partial class Form1 : Form
|
||||
return;
|
||||
}
|
||||
|
||||
using var connection = new SqliteConnection($"Data Source={_dbPath};Mode=ReadOnly");
|
||||
connection.Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT tipo_file, percorso_completo FROM files_ultima_versione "
|
||||
+ "WHERE LOWER(codice) = LOWER(@codice) AND LOWER(tipo_file) IN ('prt', 'asm') "
|
||||
+ "ORDER BY tipo_file, data_modifica DESC";
|
||||
var pCodice = command.Parameters.Add("@codice", Microsoft.Data.Sqlite.SqliteType.Text);
|
||||
|
||||
var cacheComponenti = new Dictionary<string, List<(string Tipo, string Percorso)>>();
|
||||
var codiciNoti = CaricaCodiciNoti(_dbPath);
|
||||
var cacheCodiciFile = new Dictionary<string, HashSet<string>>();
|
||||
|
||||
List<(string Tipo, string Percorso)> CercaComponenti(string codice)
|
||||
{
|
||||
if (cacheComponenti.TryGetValue(codice, out var giaTrovati))
|
||||
return giaTrovati;
|
||||
|
||||
pCodice.Value = codice;
|
||||
var risultato = new List<(string Tipo, string Percorso)>();
|
||||
var tipiVisti = new HashSet<string>();
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
string tipo = reader.GetString(0).ToLowerInvariant();
|
||||
if (tipiVisti.Add(tipo))
|
||||
{
|
||||
risultato.Add((tipo, reader.GetString(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
cacheComponenti[codice] = risultato;
|
||||
return risultato;
|
||||
}
|
||||
List<(string Tipo, string Percorso)> CercaComponenti(string codice) =>
|
||||
codiciNoti.TryGetValue(codice, out var trovati) ? trovati : new List<(string, string)>();
|
||||
|
||||
bool AssiemeCompleto(string percorsoAsmIniziale)
|
||||
{
|
||||
@@ -843,7 +817,7 @@ public partial class Form1 : Form
|
||||
{
|
||||
try
|
||||
{
|
||||
codiciReferenziati = AssemblyComponentScanner.EstraiCodiciReferenziati(file);
|
||||
codiciReferenziati = AssemblyComponentScanner.EstraiCodiciReferenziati(file, codiciNoti.Keys);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user