From 03b54e0f88697f6ee3ca5d1c6df1ade197bfbe52 Mon Sep 17 00:00:00 2001 From: simone castellan Date: Fri, 13 Nov 2026 23:43:37 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20import=20organico,=20le=20formule=20di?= =?UTF-8?q?=20archi=20non=20danno=20pi=C3=B9=20un=20falso=20=C2=ABsovrappo?= =?UTF-8?q?sizioni=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Causa: (1) layoutStrings metteva i leggii ruotati con passo fisso (corda 112 cm) e file a 150 cm: viola/violoncello (110×160) si toccavano davvero; (2) assessOut contava cerchi di raggio 0,48×lato maggiore invece dei rettangoli ruotati. Ora passo e distanza delle file si allargano a scatti solo finché le postazioni non si toccano; il conteggio usa i rettangoli (SAT, 2 cm). Se non c'è combinazione libera resta il disegno di prima e l'avviso è giusto. Test con mutazione: rosso sul codice vecchio. Co-Authored-By: Claude Sonnet 5.5 --- app.js | 101 ++++++++++++++++++++++++++---------------- index.template.html | 101 ++++++++++++++++++++++++++---------------- test/engines.test.mjs | 22 +++++++++ 3 files changed, 148 insertions(+), 76 deletions(-) diff --git a/app.js b/app.js index 6633585..a646bcf 100644 --- a/app.js +++ b/app.js @@ -24611,38 +24611,71 @@ function layoutStrings(counts, out){ for(var r=0;r=proj(a,ax[0],ax[1])+proj(b,ax[0],ax[1])) sep=true; }); + if(!sep){ n++; if(stopAt1) return n; } + } + return n; +} +function strHaClash(seats){ return strContaClash(seats, 0, true)>0; } function buildOrchestraOut(counts){ var out=[]; @@ -24780,17 +24813,9 @@ function assessOut(out, stageW, stageD, fp){ var m=measureOrchestraOut(out), C={x:stageW/2, y:stageD-fp}; var tooSmall = (C.y+m.minY<0 || C.y+m.maxY>stageD || C.x-m.maxX<0 || C.x+m.maxX>stageW); /* gli elementi di sfondo (pedane, tappeti) possono stare sotto altri: non contano come sovrapposizione */ - var boxes = out.map(function(o){ - var z=odim(o); - return {x:C.x+o.x, y:C.y+o.y, r:Math.max(24, Math.max(z.w,z.d)*0.48), bg:(TYPES[o.type].z||2)<=1}; - }); - var overlaps=0; - for(var bi=0; bi1; }); + /* sovrapposizione VERA: rettangoli ruotati (prima cerchi di raggio 0,48 × il lato maggiore: un violoncello 110×160 «toccava» il vicino senza toccarlo) */ + var overlaps=strContaClash(fg, 1); return {tooSmall:tooSmall, overlaps:overlaps, relevantOverlaps:overlaps, measure:m}; } diff --git a/index.template.html b/index.template.html index 5df3316..32083b1 100644 --- a/index.template.html +++ b/index.template.html @@ -26867,38 +26867,71 @@

Esporta PDF in scala

for(var r=0;r=proj(a,ax[0],ax[1])+proj(b,ax[0],ax[1])) sep=true; }); + if(!sep){ n++; if(stopAt1) return n; } + } + return n; +} +function strHaClash(seats){ return strContaClash(seats, 0, true)>0; } function buildOrchestraOut(counts){ var out=[]; @@ -27036,17 +27069,9 @@

Esporta PDF in scala

var m=measureOrchestraOut(out), C={x:stageW/2, y:stageD-fp}; var tooSmall = (C.y+m.minY<0 || C.y+m.maxY>stageD || C.x-m.maxX<0 || C.x+m.maxX>stageW); /* gli elementi di sfondo (pedane, tappeti) possono stare sotto altri: non contano come sovrapposizione */ - var boxes = out.map(function(o){ - var z=odim(o); - return {x:C.x+o.x, y:C.y+o.y, r:Math.max(24, Math.max(z.w,z.d)*0.48), bg:(TYPES[o.type].z||2)<=1}; - }); - var overlaps=0; - for(var bi=0; bi1; }); + /* sovrapposizione VERA: rettangoli ruotati (prima cerchi di raggio 0,48 × il lato maggiore: un violoncello 110×160 «toccava» il vicino senza toccarlo) */ + var overlaps=strContaClash(fg, 1); return {tooSmall:tooSmall, overlaps:overlaps, relevantOverlaps:overlaps, measure:m}; } diff --git a/test/engines.test.mjs b/test/engines.test.mjs index 24bef4e..71a7175 100644 --- a/test/engines.test.mjs +++ b/test/engines.test.mjs @@ -32378,6 +32378,28 @@ t("Import organico: si trova dalla ricerca («importa organico»), il menu File ok(!/fetch\(|supabase|localStorage|sessionStorage/.test(src), "niente rete, niente archivio: il testo incollato resta sulla pagina"); }); +t("Import organico (fix 13/11): le formule di archi non creano sovrapposizioni vere né l'avviso; il conteggio usa i rettangoli, non i cerchi", () => { + const salvaDoc = A.document, el = { textContent: "", hidden: true }; + A.document = { body: { classList: { contains: () => false } }, getElementById: (id) => (id === "orchWarnText" || id === "orchWarnModal" || id === "orgImpModal" ? el : null) }; + const warn = () => el.textContent; + for (const f of ["1-1-1-1", "2-2-1-1", "4-3-2-2-1", "8-6-4-4-2", "12-12-6-6-4", "7-6-4-4-2", "fl2-o2-cl2-fg2"]) { + const out = A.buildOrchestraOut(impC(f)), m = A.measureOrchestraOut(out); + eq(A.assessOut(out, 4000, 3000, A.frontPad(m)).overlaps, 0, f + ": nessuna sovrapposizione"); + eq(A.strContaClash(out.filter((o) => o.type !== "pedana"), 0), 0, f + ": nemmeno a filo (geometria vera)"); + } + A.loadDoc({ titolo: "Prova", stage: { w: 4000, d: 3000, blocks: [{ x: 0, y: 0, w: 4000, d: 3000 }] }, inputs: [], outputs: [], items: [] }); + A.orgImportApplica(impC("2-2-1-1"), { clear: true, fit: true }); + eq(!!A.pendingOut, false, "2-2-1-1: nessun avviso, i posti si creano subito"); + eq(A.state.items.length > 0, true, "e i posti ci sono"); + /* avviso vero, plurale giusto */ + A.loadDoc({ titolo: "Prova", stage: { w: 4000, d: 3000, blocks: [{ x: 0, y: 0, w: 4000, d: 3000 }] }, inputs: [], outputs: [], items: [] }); + A.placeOut([{ type: "flauto", x: 0, y: 0 }, { type: "flauto", x: 10, y: 0 }], false, false, false); + ok(/crea 1 sovrapposizione tra/.test(warn()), "una sola: «1 sovrapposizione» — " + warn()); + A.placeOut([{ type: "flauto", x: 0, y: 0 }, { type: "flauto", x: 10, y: 0 }, { type: "flauto", x: 20, y: 0 }], false, false, false); + ok(/crea 3 sovrapposizioni tra/.test(warn()), "più d'una: «3 sovrapposizioni» — " + warn()); + A.document = salvaDoc; +}); + console.log("\n" + (fail === 0 ? "✓ TUTTI VERDI" : "✗ " + fail + " FALLITI") + " — " + pass + " passati, " + fail + " falliti."); process.exit(fail === 0 ? 0 : 1);