diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 97e1d394..3aac6cdf 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1569,6 +1569,7 @@ export const drawGableRoof = (roofId, canvas, textMode) => { //각 포인트들을 직교하도록 정렬 const sortedPoints = getSortedOrthogonalPoints(roofPlanePoint) + // logger.log(`[GABLE-H8-PLANE] planeDir ridges=${ridgeLines.length}`) sortedPoints.forEach((currPoint, index) => { const nextPoint = sortedPoints[(index + 1) % sortedPoints.length] const points = [currPoint.x, currPoint.y, nextPoint.x, nextPoint.y] @@ -1617,6 +1618,7 @@ export const drawGableRoof = (roofId, canvas, textMode) => { if (Math.abs(rg.y1 - points[1]) >= 1) return false return Math.min(rg.x1, rg.x2) - 1 <= sMin && sMax <= Math.max(rg.x1, rg.x2) + 1 }) + // logger.log(`[GABLE-H8-CHK] seg covered=${coveredByRidge ? 'YES' : 'NO'}`) if (coveredByRidge) { return true } @@ -1651,6 +1653,52 @@ export const drawGableRoof = (roofId, canvas, textMode) => { drawRoofPlane(backward) }) roof.innerLines.push(...ridgeLines, ...innerLines) + + // [VALLEY-BOX-FILL 2026-06-24] 골짜기에서 평행한 두 마루가 수직축으로 겹치면(出幅 겹침=박스), + // 짧은 마루 쪽 위치에 겹침구간을 잇는 세로 박스라인(라벨 B)을 채운다. + // 마루는 건드리지 않고(박스라인+마루) 박스 경계만 보강 → 마루 삭제해도 경계 유지. + { + const VB_EPS = 1 + for (let i = 0; i < ridgeLines.length; i++) { + for (let j = i + 1; j < ridgeLines.length; j++) { + const a = ridgeLines[i] + const b = ridgeLines[j] + const aV = Math.abs(a.x1 - a.x2) < VB_EPS + const bV = Math.abs(b.x1 - b.x2) < VB_EPS + const aH = Math.abs(a.y1 - a.y2) < VB_EPS + const bH = Math.abs(b.y1 - b.y2) < VB_EPS + let pts = null + if (aV && bV && Math.abs(a.x1 - b.x1) > VB_EPS) { + const aMin = Math.min(a.y1, a.y2) + const aMax = Math.max(a.y1, a.y2) + const bMin = Math.min(b.y1, b.y2) + const bMax = Math.max(b.y1, b.y2) + const o0 = Math.max(aMin, bMin) + const o1 = Math.min(aMax, bMax) + if (o1 - o0 > VB_EPS) { + const fillX = aMax - aMin <= bMax - bMin ? a.x1 : b.x1 + pts = [fillX, o0, fillX, o1] + } + } else if (aH && bH && Math.abs(a.y1 - b.y1) > VB_EPS) { + const aMin = Math.min(a.x1, a.x2) + const aMax = Math.max(a.x1, a.x2) + const bMin = Math.min(b.x1, b.x2) + const bMax = Math.max(b.x1, b.x2) + const o0 = Math.max(aMin, bMin) + const o1 = Math.min(aMax, bMax) + if (o1 - o0 > VB_EPS) { + const fillY = aMax - aMin <= bMax - bMin ? a.y1 : b.y1 + pts = [o0, fillY, o1, fillY] + } + } + if (pts) { + // logger.log(`[VALLEY-BOX-FILL] box`) + roof.innerLines.push(drawValleyBoxLine(pts, canvas, roof, roof.textMode)) + } + } + } + } + // 처마선 innerLine 이 외곽선/치수를 전담하므로 roof 원본 외곽(stroke) 숨김 + 지붕선 치수(roof lengthText) 제거. // 외벽선(wall) 치수는 유지. (박공은 split 공용 함수를 안 거치므로 여기서 직접 처리) roof.set({ stroke: 'transparent' }) @@ -5934,6 +5982,27 @@ const drawRidgeLine = (points, canvas, roof, textMode) => { return ridge } +// [VALLEY-BOX-FILL 2026-06-24] 골짜기 박스(出幅 겹침)의 세로변을 마루와 별개의 박스라인으로 채운다. +// kerabValleyOverlapLine(라벨 B) 으로 만들어 마루를 지워도 박스 경계가 남도록 한다(박스라인+마루). +const drawValleyBoxLine = (points, canvas, roof, textMode) => { + const lsz = calcLinePlaneSize({ x1: points[0], y1: points[1], x2: points[2], y2: points[3] }) + const box = new QLine(points, { + parentId: roof.id, + fontSize: roof.fontSize, + stroke: '#1083E3', + strokeWidth: 3, + name: LINE_TYPE.SUBLINE.VALLEY, + textMode: textMode, + attributes: { roofId: roof.id, type: 'kerabValleyOverlapLine', isStart: true, pitch: roof.pitch, planeSize: lsz, actualSize: lsz }, + }) + box.lineName = 'kerabValleyOverlapLine' + box.roofId = roof.id + canvas.add(box) + box.bringToFront() + canvas.renderAll() + return box +} + /** * 지붕선을 그린다. * @param points