fix: 좌/우 공동구 벽체 높이 660mm 고정 오류 해결 및 전수 검증 (좌 700mm, 우 1000mm 표준 동기화)
This commit is contained in:
1 parent
88221ec8d7
commit
599696883f
4 files changed
+147
-8
No files matched your search
@@ -52,9 +52,9 @@ window.ugData = {
|
||||
type: 'T1',
|
||||
vw1: 300, vw2: 300, vh: 300,
|
||||
lw: 400, lh: 60, gap: 50,
|
||||
ww1: 144, ww2: 36, ww3: 120,
|
||||
wh1: 360, wh2: 175, wh3: 125,
|
||||
bcw: 650, bch: 500, dw: 100, dh: 150,
|
||||
ww1: 150, ww2: 30, ww3: 120,
|
||||
wh1: 450, wh2: 175, wh3: 75,
|
||||
bcw: 550, bch: 530, dw: 100, dh: 150,
|
||||
bw1: 125, bw2: 300, bw3: 300,
|
||||
bd1: 50, bd2: 300, bd3: 50,
|
||||
pipeD: 300
|
||||
@@ -63,9 +63,9 @@ window.ugData = {
|
||||
type: 'T1',
|
||||
vw1: 300, vw2: 300, vh: 300,
|
||||
lw: 400, lh: 60, gap: 50,
|
||||
ww1: 144, ww2: 36, ww3: 120,
|
||||
wh1: 360, wh2: 175, wh3: 125,
|
||||
bcw: 650, bch: 500, dw: 100, dh: 150,
|
||||
ww1: 150, ww2: 80, ww3: 120,
|
||||
wh1: 750, wh2: 175, wh3: 75,
|
||||
bcw: 550, bch: 500, dw: 100, dh: 150,
|
||||
bw1: 125, bw2: 300, bw3: 300,
|
||||
bd1: 50, bd2: 300, bd3: 50,
|
||||
pipeD: 300
|
||||
@@ -1628,6 +1628,10 @@ function syncParamsToInputs() {
|
||||
setIf('p_pave_t1', p.pave_t1);
|
||||
setIf('p_pave_t2', p.pave_t2);
|
||||
setIf('p_pave_t3', p.pave_t3);
|
||||
const dL = window.ugData.left || {};
|
||||
const dR = window.ugData.right || {};
|
||||
setIf('p_ug_wh_l', (dL.wh1 || 450) + (dL.wh2 || 175) + (dL.wh3 || 75));
|
||||
setIf('p_ug_wh_r', (dR.wh1 || 750) + (dR.wh2 || 175) + (dR.wh3 || 75));
|
||||
}
|
||||
|
||||
function readParamsFromInputs() {
|
||||
@@ -1650,6 +1654,19 @@ function readParamsFromInputs() {
|
||||
p.pave_t1 = getNum('p_pave_t1', p.pave_t1);
|
||||
p.pave_t2 = getNum('p_pave_t2', p.pave_t2);
|
||||
p.pave_t3 = getNum('p_pave_t3', p.pave_t3);
|
||||
|
||||
const whTotL = getNum('p_ug_wh_l', 700);
|
||||
const whTotR = getNum('p_ug_wh_r', 1000);
|
||||
if (window.ugData.left) {
|
||||
window.ugData.left.wh3 = 75;
|
||||
window.ugData.left.wh2 = 175;
|
||||
window.ugData.left.wh1 = Math.max(100, Math.round(whTotL - 250));
|
||||
}
|
||||
if (window.ugData.right) {
|
||||
window.ugData.right.wh3 = 75;
|
||||
window.ugData.right.wh2 = 175;
|
||||
window.ugData.right.wh1 = Math.max(100, Math.round(whTotR - 250));
|
||||
}
|
||||
}
|
||||
|
||||
function renderDetectionList(sourceName, entityCount) {
|
||||
@@ -1674,8 +1691,8 @@ function renderDetectionList(sourceName, entityCount) {
|
||||
},
|
||||
{
|
||||
color: '#cbd5e1',
|
||||
title: '공동구 및 프리캐스트 뚜껑',
|
||||
detail: `좌 ${dL.type || 'T2'} (${dL.lw}×${dL.lh}mm, 내공 ${dL.vw1}×${dL.vh}mm) · 우 ${dR.type || 'T2'} (${dR.lw}×${dR.lh}mm, 내공 ${dR.vw1}×${dR.vh}mm)`,
|
||||
title: '공동구 벽체 및 프리캐스트 뚜껑',
|
||||
detail: `좌 벽체 ${dL.wh1 + dL.wh2 + dL.wh3}mm(뚜껑 ${dL.lw}×${dL.lh}) · 우 벽체 ${dR.wh1 + dR.wh2 + dR.wh3}mm(뚜껑 ${dR.lw}×${dR.lh}) · 내공 ${dR.vw1}×${dR.vh}mm`,
|
||||
badge: '100%'
|
||||
},
|
||||
{
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
<label><span>포장 표층 t1(mm)</span><input type="number" id="p_pave_t1" value="20"></label>
|
||||
<label><span>포장 콘크리트 t2</span><input type="number" id="p_pave_t2" value="260"></label>
|
||||
<label><span>포장 필터층 t3</span><input type="number" id="p_pave_t3" value="150"></label>
|
||||
<label><span>좌측 벽체 높이(mm)</span><input type="number" id="p_ug_wh_l" value="700"></label>
|
||||
<label><span>우측 벽체 높이(mm)</span><input type="number" id="p_ug_wh_r" value="1000"></label>
|
||||
</div>
|
||||
<button type="button" id="applyParamsBtn" class="secondary-button">변경 제원으로 3D 갱신</button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
const fs = require('fs');
|
||||
const DxfParser = require('c:/Users/user/.gemini/tunnelsection/TunnelModeler3D/dxf-parser.js');
|
||||
|
||||
function analyzeWallGeometry(dxfPath, label) {
|
||||
if (!fs.existsSync(dxfPath)) return;
|
||||
console.log(`\n======================================================`);
|
||||
console.log(`[${label}] 공동구 선분 기하 정밀 실측: ${dxfPath}`);
|
||||
const dxf = new DxfParser().parseSync(fs.readFileSync(dxfPath, 'utf8'));
|
||||
|
||||
// app.js와 동일한 방식으로 targetCenterX, targetCenterY, pavement 선분 찾기
|
||||
let appCode = fs.readFileSync('c:/Users/user/.gemini/tunnelsection/TunnelModeler3D/app.js', 'utf8');
|
||||
|
||||
// mock 환경
|
||||
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, label);
|
||||
|
||||
const sp = window.sectionParams;
|
||||
const pL_X = sp.pavementLeftX;
|
||||
const pR_X = sp.pavementRightX;
|
||||
|
||||
// 단면 선분들 중 좌측 공동구 영역(X: pL_X - 1500 ~ pL_X)과 우측 공동구 영역(X: pR_X ~ pR_X + 1500)
|
||||
const allLines = dxf.entities.filter(e => e.type === 'LINE');
|
||||
|
||||
// 좌측 공동구 상단선(수평선) 탐색
|
||||
const leftHLines = allLines.filter(l => {
|
||||
const minX = Math.min(l.vertices[0].x, l.vertices[1].x);
|
||||
const maxX = Math.max(l.vertices[0].x, l.vertices[1].x);
|
||||
const dy = Math.abs(l.vertices[0].y - l.vertices[1].y);
|
||||
const dx = Math.abs(l.vertices[0].x - l.vertices[1].x);
|
||||
return minX >= pL_X - 2500 && maxX <= pL_X + 100 && dy <= 3.0 && dx >= 40;
|
||||
});
|
||||
|
||||
// 우측 공동구 상단선(수평선) 탐색
|
||||
const rightHLines = allLines.filter(l => {
|
||||
const minX = Math.min(l.vertices[0].x, l.vertices[1].x);
|
||||
const maxX = Math.max(l.vertices[0].x, l.vertices[1].x);
|
||||
const dy = Math.abs(l.vertices[0].y - l.vertices[1].y);
|
||||
const dx = Math.abs(l.vertices[0].x - l.vertices[1].x);
|
||||
return minX >= pR_X - 100 && maxX <= pR_X + 2500 && dy <= 3.0 && dx >= 40;
|
||||
});
|
||||
|
||||
// 도로 표면 기준 높이(포장 끝단 Y)
|
||||
// roadOriginY는 대략 포장 끝점 Y
|
||||
const pL_Y = sp.roadOriginY || 0; // sp에는 없음, app.js 내 pL_Y 찾기
|
||||
console.log(` 포장 좌측단 X=${Math.round(pL_X)}, 우측단 X=${Math.round(pR_X)}`);
|
||||
console.log(` [좌측 수평선들 (X, Y, 길이 dx)]:`);
|
||||
leftHLines.sort((a,b) => b.vertices[0].y - a.vertices[0].y).slice(0, 10).forEach(l => {
|
||||
const x1 = Math.round(l.vertices[0].x), x2 = Math.round(l.vertices[1].x);
|
||||
const y = Math.round((l.vertices[0].y + l.vertices[1].y)/2);
|
||||
const len = Math.round(Math.abs(x1 - x2));
|
||||
console.log(` Y=${y}, X=[${Math.min(x1,x2)} ~ ${Math.max(x1,x2)}], dx=${len}, layer=${l.layer}`);
|
||||
});
|
||||
|
||||
console.log(` [우측 수평선들 (X, Y, 길이 dx)]:`);
|
||||
rightHLines.sort((a,b) => b.vertices[0].y - a.vertices[0].y).slice(0, 10).forEach(l => {
|
||||
const x1 = Math.round(l.vertices[0].x), x2 = Math.round(l.vertices[1].x);
|
||||
const y = Math.round((l.vertices[0].y + l.vertices[1].y)/2);
|
||||
const len = Math.round(Math.abs(x1 - x2));
|
||||
console.log(` Y=${y}, X=[${Math.min(x1,x2)} ~ ${Math.max(x1,x2)}], dx=${len}, layer=${l.layer}`);
|
||||
});
|
||||
}
|
||||
|
||||
analyzeWallGeometry('c:/Users/user/.gemini/tunnelsection/TunnelModeler3D/Test Sample/세종안성_서운1.dxf', '서운1');
|
||||
analyzeWallGeometry('c:/Users/user/.gemini/tunnelsection/TunnelModeler3D/Test Sample/안성구리3_고삼.dxf', '고삼');
|
||||
analyzeWallGeometry('c:/Users/user/.gemini/antigravity/brain/9c348cd5-3f07-4ade-adba-e28b2709935f/scratch/wansan_out/wansan.dxf', '완산');
|
||||
analyzeWallGeometry('c:/Users/user/.gemini/antigravity/brain/9c348cd5-3f07-4ade-adba-e28b2709935f/scratch/namhan_out/namhan.dxf', '남한산성');
|
||||
@@ -0,0 +1,32 @@
|
||||
const fs = require('fs');
|
||||
const DxfParser = require('c:/Users/user/.gemini/tunnelsection/TunnelModeler3D/dxf-parser.js');
|
||||
|
||||
function searchDimensionTexts(dxfPath, label) {
|
||||
if (!fs.existsSync(dxfPath)) return;
|
||||
console.log(`\n========================================`);
|
||||
console.log(`[${label}] 치수 텍스트 정밀 탐색: ${dxfPath}`);
|
||||
const dxf = new DxfParser().parseSync(fs.readFileSync(dxfPath, 'utf8'));
|
||||
const texts = dxf.entities.filter(e => e.type === 'TEXT' || e.type === 'MTEXT');
|
||||
|
||||
// 공동구 벽체 높이 관련 숫자 검색: 660, 700, 750, 800, 900, 950, 1000, 1050, 1100, 450, 360, 175, 125, 75 등
|
||||
const targetNums = ['660', '700', '750', '800', '900', '950', '1000', '1050', '1100', '450', '360', '175', '125', '75', '144', '150', '160'];
|
||||
|
||||
const found = texts.filter(t => {
|
||||
const text = t.text || '';
|
||||
return targetNums.some(num => new RegExp(`(^|[^0-9])${num}([^0-9]|$)`).test(text));
|
||||
});
|
||||
|
||||
console.log(`발견된 관련 텍스트 수: ${found.length}`);
|
||||
// X좌표 기준으로 좌측 공동구 영역, 우측 공동구 영역 텍스트만 필터링해보기
|
||||
found.forEach(t => {
|
||||
const txt = (t.text || '').replace(/\\P/g, ' ').trim();
|
||||
const px = Math.round(t.x || (t.position && t.position.x) || 0);
|
||||
const py = Math.round(t.y || (t.position && t.position.y) || 0);
|
||||
console.log(` [${t.layer}] (${px}, ${py}): "${txt}"`);
|
||||
});
|
||||
}
|
||||
|
||||
searchDimensionTexts('c:/Users/user/.gemini/tunnelsection/TunnelModeler3D/Test Sample/세종안성_서운1.dxf', '서운1');
|
||||
searchDimensionTexts('c:/Users/user/.gemini/tunnelsection/TunnelModeler3D/Test Sample/안성구리3_고삼.dxf', '고삼');
|
||||
searchDimensionTexts('c:/Users/user/.gemini/antigravity/brain/9c348cd5-3f07-4ade-adba-e28b2709935f/scratch/wansan_out/wansan.dxf', '완산');
|
||||
searchDimensionTexts('c:/Users/user/.gemini/antigravity/brain/9c348cd5-3f07-4ade-adba-e28b2709935f/scratch/namhan_out/namhan.dxf', '남한산성');
|
||||
Reference in new issue
Block a user