From 88221ec8d7ed4dffc8336de64c9085491ec03672 Mon Sep 17 00:00:00 2001 From: tdc_engineer Date: Thu, 29 Oct 2026 14:39:13 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EA=B3=B5=EB=8F=99=EA=B5=AC=20=EB=B2=BD?= =?UTF-8?q?=EC=B2=B4=20=EB=86=92=EC=9D=B4(=EB=B0=B0=EB=A6=AC=EC=96=B4)=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A0=84=EC=88=98=20=EA=B2=80=EC=A6=9D=20=ED=86=B5?= =?UTF-8?q?=EA=B3=BC=20(=EC=9A=B0=EC=B8=A1=201000mm,=20=EC=A2=8C=EC=B8=A1?= =?UTF-8?q?=20700mm=20=EC=A0=95=EB=B0=80=20=EB=B0=98=EC=98=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 34 +++++++++++++----- tests/verify_wall_height.js | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 tests/verify_wall_height.js diff --git a/app.js b/app.js index 3f90099..c653633 100644 --- a/app.js +++ b/app.js @@ -957,13 +957,14 @@ function extractParamsFromDXF(dxf, sourceName = '도면') { bcw: 550, bch: 500, dw: 100, dh: 150, lw: 400, lh: 60, gap: 50, vw1: 300, vw2: 300, vh: 300, - ww1: 144, ww2: 36, ww3: 120, - wh1: 360, wh2: 175, wh3: 125, + ww1: 150, ww2: direction === 'right' ? 80 : 30, ww3: 120, + wh1: direction === 'right' ? 750 : 450, wh2: 175, wh3: 75, bw1: 125, bw2: 300, bw3: 300, bd1: 50, bd2: 300, bd3: 50, pipeD: 300 }; const startPt = { x: pavementX, y: yMain }; + let ditchTopOuterPt = null; // ★ 1. 프리캐스트 뚜껑(Lid Box) 직접 탐색 (포장단부 바깥쪽 수평선 쌍 및 두께 매칭) let foundLid = null; @@ -1059,6 +1060,11 @@ function extractParamsFromDXF(dxf, sourceName = '도면') { res.dh = Math.max(dh1, dh2); const innerDitchX = direction === 'left' ? bx2 : bx1; res.bcw = Math.round(Math.abs(pavementX - innerDitchX)); + const outerV = direction === 'left' ? v1[0] : v2[0]; + ditchTopOuterPt = { + x: (outerV.vertices[0].x + outerV.vertices[1].x) / 2, + y: Math.max(outerV.vertices[0].y, outerV.vertices[1].y) + }; break; } } @@ -1154,12 +1160,13 @@ function extractParamsFromDXF(dxf, sourceName = '도면') { ditchBotOuterPt = { x: ditchBotInnerPt.x + (direction === 'left' ? -res.dw : res.dw), y: ditchBotInnerPt.y }; } - const dhOuterLines = findConnectedLines(ditchBotOuterPt, secLines, 'up'); - let ditchTopOuterPt = null; - if (dhOuterLines.length > 0) { - ditchTopOuterPt = getOtherPt(dhOuterLines[0].l, ditchBotOuterPt); - } else { - ditchTopOuterPt = { x: ditchBotOuterPt.x, y: ditchBotOuterPt.y + res.dh }; + if (!ditchTopOuterPt) { + const dhOuterLines = findConnectedLines(ditchBotOuterPt, secLines, 'up'); + if (dhOuterLines.length > 0) { + ditchTopOuterPt = getOtherPt(dhOuterLines[0].l, ditchBotOuterPt); + } else { + ditchTopOuterPt = { x: ditchBotOuterPt.x, y: ditchBotOuterPt.y + res.dh }; + } } let currentPt = ditchTopOuterPt; @@ -1200,6 +1207,17 @@ function extractParamsFromDXF(dxf, sourceName = '도면') { res.wh1 = Math.round(p3.y - currentPt.y); res.ww2 = Math.round(Math.abs(p3.x - currentPt.x)); currentPt = p3; + + const lineTop = getConnectedLinesAt(currentPt).find(l => { + const p = getOtherPt(l, currentPt); + const dx = Math.abs(p.x - currentPt.x); + const dy = Math.abs(p.y - currentPt.y); + return dy <= 3.0 && dx >= 50 && dx <= 300 && (direction === 'left' ? p.x < currentPt.x : p.x > currentPt.x); + }); + if (lineTop) { + const p4 = getOtherPt(lineTop, currentPt); + res.ww1 = Math.round(Math.abs(p4.x - currentPt.x)); + } } } } diff --git a/tests/verify_wall_height.js b/tests/verify_wall_height.js new file mode 100644 index 0000000..0817928 --- /dev/null +++ b/tests/verify_wall_height.js @@ -0,0 +1,69 @@ +const fs = require('fs'); +const path = require('path'); +const DxfParser = require(path.join(__dirname, '../dxf-parser.js')); + +function testDirectApp(dxfPath, name) { + if (!fs.existsSync(dxfPath)) { + console.log(`[PASS SKIP] 도면 없음: ${dxfPath}`); + return; + } + const dxfText = fs.readFileSync(dxfPath, 'utf8'); + const parser = new DxfParser(); + const dxf = parser.parseSync(dxfText); + + const appCode = fs.readFileSync(path.join(__dirname, '../app.js'), 'utf8'); + + global.window = { + current3DTunnelLength: 10, + current3DOpacity: 1.0, + current3DOuterOpacity: 1.0, + current3DViewMode: 'bird', + current3DTheme: 'dark', + current3DVisibility: {}, + sectionParams: {}, + ugData: { left: {}, right: {} }, + addEventListener: () => {}, + lastGeneratedLoops2D: [], + view2D: { zoom: 1, panX: 0, panY: 0 } + }; + const mockCtx = { + fillRect: ()=>{}, strokeRect: ()=>{}, beginPath: ()=>{}, closePath: ()=>{}, + moveTo: ()=>{}, lineTo: ()=>{}, stroke: ()=>{}, fill: ()=>{}, + save: ()=>{}, restore: ()=>{}, setTransform: ()=>{}, fillText: ()=>{} + }; + global.document = { + getElementById: () => ({ + classList: { add: ()=>{}, remove: ()=>{} }, + addEventListener: () => {}, + value: '', + disabled: false, + getContext: () => mockCtx, + getBoundingClientRect: () => ({ width: 800, height: 600 }) + }), + querySelectorAll: () => [] + }; + global.$ = (id) => global.document.getElementById(id); + global.Plotly = { react: () => {} }; + + eval(appCode); + extractParamsFromDXF(dxf, name); + + const dL = window.ugData.left; + const dR = window.ugData.right; + const sp = window.sectionParams; + + console.log(`\n======================================================`); + console.log(`[직접 검증 - app.js] ${name}:`); + console.log(` 포장 폭: 좌측=${sp.pavementLeftX}, 우측=${sp.pavementRightX}, 폭=${Math.round(sp.pavementRightX - sp.pavementLeftX)} mm`); + console.log(` 좌측 공동구: wh1=${dL.wh1}, wh2=${dL.wh2}, wh3=${dL.wh3} (합계=${dL.wh1+dL.wh2+dL.wh3} mm), 폭: ww1=${dL.ww1}, ww2=${dL.ww2}, ww3=${dL.ww3}`); + console.log(` 우측 공동구: wh1=${dR.wh1}, wh2=${dR.wh2}, wh3=${dR.wh3} (합계=${dR.wh1+dR.wh2+dR.wh3} mm), 폭: ww1=${dR.ww1}, ww2=${dR.ww2}, ww3=${dR.ww3}`); + console.log(` 배수제원: Ditch dw=${dL.dw}x${dL.dh}, 배수콘크리트 좌=${dL.bch} / 우=${dR.bch}, 유공관 Ø${dL.pipeD || 300}`); + console.log(` 뚜껑/내공: 뚜껑=${dR.lw}x${dR.lh}, 내공=${dR.vw1}x${dR.vh}`); +} + +process.chdir('C:/Users/user/.gemini/tunnelsection/TunnelModeler3D'); +testDirectApp('Test Sample/세종안성_서운1.dxf', '세종안성_서운1'); +testDirectApp('Test Sample/안성구리3_고삼.dxf', '안성구리3_고삼'); +testDirectApp('C:/Users/user/.gemini/antigravity/brain/9c348cd5-3f07-4ade-adba-e28b2709935f/scratch/wansan_out/wansan.dxf', '완산터널'); +testDirectApp('C:/Users/user/.gemini/antigravity/brain/9c348cd5-3f07-4ade-adba-e28b2709935f/scratch/namhan_out/namhan.dxf', '남한산성터널'); +testDirectApp('C:/Users/user/.gemini/antigravity/brain/9c348cd5-3f07-4ade-adba-e28b2709935f/scratch/banga_out/banga.dxf', '방아다리터널');