script-volume-auto/src/config.ts
Nicolas Fryder 86a75bd47b Mode comparaison a 2 nuages + remplissage de trous + fix critique de parsing
- Nouveau mode "cloud_compare" (en plus de "const_height") : comparaison entre une surface
  superieure et une limite inferieure, avec appariement de densite avant le niveau 0 puis
  decimation synchronisee x2 sur 5 etapes. UI : selecteur de mode + upload double avec labels
  explicites (surface superieure / limite inferieure).
- Remplissage des trous de scan (interpolation Delaunay bornee par max-edge-length) avant chaque
  calcul de volume, dans les deux modes. -VOLUME n'ayant aucune option native pour ca (verifie dans
  les sources CloudCompare), on rasterize+comble+exporte en nuage avant de le passer a -VOLUME.
  Override utilisateur possible pour la distance max, afin de ne pas combler les parties concaves
  du contour de l'objet mesure.
- Fix critique : CloudCompare formate les grands nombres avec une virgule comme separateur de
  milliers ("Volume: 14,244.46") ; le parsing tronquait silencieusement a la premiere virgule
  (14 244 devenait 14). Trouve en testant avec un vrai nuage industriel.
- Validation avec 2 vrais nuages utilisateur : le mode Z constant donnait ~50m3 (plan de reference
  sans rapport avec la base reelle de l'amas, nuage contenant du contexte environnant) ; le nouveau
  mode comparaison donne ~14 244m3, stable a +/-4% meme a 16x de decimation.
- CLAUDE.md mis a jour avec tous ces findings (limitation -VOLUME/LEAVE_EMPTY, technique de
  contournement, piege du separateur de milliers, architecture du mode 2 nuages).
2026-07-10 15:21:37 +02:00

45 lines
2.3 KiB
TypeScript

import * as path from 'path';
function envInt(name: string, fallback: number): number {
const v = process.env[name];
if (!v) return fallback;
const n = Number(v);
return Number.isFinite(n) ? n : fallback;
}
export const config = {
port: envInt('PORT', 3000),
dataDir: process.env.DATA_DIR ?? path.resolve(process.cwd(), 'data'),
cloudCompareBin: process.env.CLOUDCOMPARE_BIN ?? 'CloudCompare',
pythonBin: process.env.PYTHON_BIN ?? 'python3',
// Pipeline constants (voir plan: facteur 2, 5 etapes)
decimationFactor: 2,
decimationSteps: 5,
// Nombre max de points echantillonnes pour estimer la distance moyenne au plus proche voisin
statsSampleCap: envInt('STATS_SAMPLE_CAP', 50000),
// Grille de calcul du volume = pas spatial DE CHAQUE NIVEAU x ce multiplicateur (adaptee
// dynamiquement a chaque niveau, pas figee sur la resolution du niveau 0 - voir CLAUDE.md).
gridStepMultiplier: 2,
// Remplissage des trous (occlusions de scan) avant -VOLUME : distance max d'interpolation
// Delaunay = gridStep du niveau x ce multiplicateur. Empeche de combler les parties concaves
// du contour de l'amas (qui doivent rester "vides") tout en bouchant les petits trous de scan.
// Voir CLAUDE.md : -VOLUME n'a PAS d'option de remplissage native, on passe par -RASTERIZE.
maxEdgeLengthMultiplier: 3,
// En dessous de ce nombre de points, on arrete la decimation progressive (cloud devenu inexploitable)
minPointsToContinue: 25,
// Seuil d'alerte robustesse : si "matching cells %" du rapport CloudCompare passe sous ce seuil,
// le resultat est signale comme peu fiable dans l'UI.
matchingCellsWarnThreshold: 90,
// Taille max d'upload (octets)
maxUploadBytes: envInt('MAX_UPLOAD_MB', 2048) * 1024 * 1024,
// Timeout par appel CloudCompare CLI (ms)
ccTimeoutMs: envInt('CC_TIMEOUT_MS', 10 * 60 * 1000),
// Auth HTTP Basic (UI + API). Si l'une des deux variables est absente, l'auth est desactivee
// (pratique en dev local) - un warning est logge au demarrage dans ce cas, voir main.ts.
authUsername: process.env.AUTH_USERNAME ?? null,
authPasswordHash: process.env.AUTH_PASSWORD_HASH ?? null,
};
export const uploadsDir = () => path.join(config.dataDir, 'uploads');
export const resultsDir = () => path.join(config.dataDir, 'results');
export const dbPath = () => path.join(config.dataDir, 'app.db');