From 042cdc4b83fb6af42a44244b7417724356360188 Mon Sep 17 00:00:00 2001 From: ysCha Date: Thu, 14 May 2026 17:04:43 +0900 Subject: [PATCH] =?UTF-8?q?1=EC=B0=A8=20=EB=A1=9C=EA=B7=B8=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/skeleton-utils.js | 374 ++++++++++++++++++------------------- 1 file changed, 187 insertions(+), 187 deletions(-) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index ce02181c..5d31367b 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -96,7 +96,7 @@ const movingLineFromSkeleton = (roofId, canvas) => { const _lp = canvas?.skeleton?.lastPoints const _src = _lp ? 'lastPoints' : 'orgRoofPoints' const _p7 = oldPoints?.[7] - logger.log(`[LP-TRACE] movingLineFromSkeleton.in src=${_src} oldPoints[7]=(${_p7?.x?.toFixed(1)},${_p7?.y?.toFixed(1)}) pos=${movePosition} dir=${moveDirection}`) + // logger.log(`[LP-TRACE] movingLineFromSkeleton.in src=${_src} oldPoints[7]=(${_p7?.x?.toFixed(1)},${_p7?.y?.toFixed(1)}) pos=${movePosition} dir=${moveDirection}`) } catch (_e) {} const oppositeLine = findOppositeLine(canvas.skeleton.Edges, startPoint, endPoint, oldPoints); @@ -108,18 +108,18 @@ const movingLineFromSkeleton = (roofId, canvas) => { const skeletonLines = canvas.getObjects().filter((object) => object.skeletonType === 'line' && object.parentId === roofId) if (oppositeLine) { - logger.log('Opposite line found:', oppositeLine); + // logger.log('Opposite line found:', oppositeLine); } else { - logger.log('No opposite line found'); + // logger.log('No opposite line found'); } if(moveFlowLine !== 0) { return oldPoints.map((point, index) => { - logger.log('Point:', point); + // logger.log('Point:', point); const newPoint = { ...point }; const absMove = Big(moveFlowLine).times(2).div(10); - logger.log('skeletonBuilder moveDirection:', moveDirection); + // logger.log('skeletonBuilder moveDirection:', moveDirection); switch (moveDirection) { case 'left': @@ -180,7 +180,7 @@ const movingLineFromSkeleton = (roofId, canvas) => { if (line.position === 'bottom') { - logger.log('oldPoint:', point); + // logger.log('oldPoint:', point); if (isSamePoint(newPoint, line.start)) { newPoint.y = Big(line.start.y).minus(absMove).toNumber(); @@ -199,7 +199,7 @@ const movingLineFromSkeleton = (roofId, canvas) => { // 사용 예시 } - logger.log('newPoint:', newPoint); + // logger.log('newPoint:', newPoint); //baseline 변경 return newPoint; }) @@ -256,10 +256,10 @@ const movingLineFromSkeleton = (roofId, canvas) => { affected.add(k); affected.add((k + 1) % nPts); }); - logger.log('absMove::', moveUpDownLength); + // logger.log('absMove::', moveUpDownLength); // [BR-TRACE local] movingLineFromSkeleton position/direction 분기 const __isLocalMS = process.env.NEXT_PUBLIC_RUN_MODE === 'local' - if (__isLocalMS) logger.log(`[BR-TRACE] movingLineFromSkeleton position=${position} dir=${moveDirection} affected=${[...affected].join(',')}`) + // if (__isLocalMS) logger.log(`[BR-TRACE] movingLineFromSkeleton position=${position} dir=${moveDirection} affected=${[...affected].join(',')}`) affected.forEach((i) => { const point = newPoints[i]; if (!point) return; @@ -267,21 +267,21 @@ const movingLineFromSkeleton = (roofId, canvas) => { if (position === 'bottom') { if (moveDirection === 'in') point.y = Big(point.y).minus(moveUpDownLength).toNumber(); else if (moveDirection === 'out') point.y = Big(point.y).plus(moveUpDownLength).toNumber(); - if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} bottom/${moveDirection} y ${__by}→${point.y}`) + // if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} bottom/${moveDirection} y ${__by}→${point.y}`) } else if (position === 'top') { if (moveDirection === 'in') point.y = Big(point.y).plus(moveUpDownLength).toNumber(); else if (moveDirection === 'out') point.y = Big(point.y).minus(moveUpDownLength).toNumber(); - if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} top/${moveDirection} y ${__by}→${point.y}`) + // if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} top/${moveDirection} y ${__by}→${point.y}`) } else if (position === 'left') { if (moveDirection === 'in') point.x = Big(point.x).plus(moveUpDownLength).toNumber(); else if (moveDirection === 'out') point.x = Big(point.x).minus(moveUpDownLength).toNumber(); - if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} left/${moveDirection} x ${__bx}→${point.x}`) + // if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} left/${moveDirection} x ${__bx}→${point.x}`) } else if (position === 'right') { if (moveDirection === 'in') point.x = Big(point.x).minus(moveUpDownLength).toNumber(); else if (moveDirection === 'out') point.x = Big(point.x).plus(moveUpDownLength).toNumber(); - if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} right/${moveDirection} x ${__bx}→${point.x}`) + // if (__isLocalMS) logger.log(`[BR-TRACE] i=${i} right/${moveDirection} x ${__bx}→${point.x}`) } else if (__isLocalMS) { - logger.warn(`[BR-TRACE] i=${i} position=${position} 매칭 분기 없음 (이동 안 됨)`) + // logger.warn(`[BR-TRACE] i=${i} position=${position} 매칭 분기 없음 (이동 안 됨)`) } }); @@ -409,7 +409,7 @@ const buildRawMovedPoints = (roofId, canvas) => { // [LP-TRACE] buildRawMovedPoints 진입 — prevLast 유무 및 [7] 현재 값 try { const _pl7 = prevLast?.[7] - logger.log(`[LP-TRACE] buildRaw.in prevLast=${prevLast ? 'Y' : 'N'} prevLast[7]=(${_pl7?.x?.toFixed(1)},${_pl7?.y?.toFixed(1)}) oldPoints[7]=(${oldPoints[7]?.x?.toFixed(1)},${oldPoints[7]?.y?.toFixed(1)})`) + // logger.log(`[LP-TRACE] buildRaw.in prevLast=${prevLast ? 'Y' : 'N'} prevLast[7]=(${_pl7?.x?.toFixed(1)},${_pl7?.y?.toFixed(1)}) oldPoints[7]=(${oldPoints[7]?.x?.toFixed(1)},${oldPoints[7]?.y?.toFixed(1)})`) } catch (_e) {} const selectLine = roof.moveSelectLine @@ -447,7 +447,7 @@ const buildRawMovedPoints = (roofId, canvas) => { }) // [BR-TRACE local] buildRawMovedPoints position/direction 분기 const __isLocalBR = process.env.NEXT_PUBLIC_RUN_MODE === 'local' - if (__isLocalBR) logger.log(`[BR-TRACE] buildRawMovedPoints position=${position} dir=${moveDirection} affected=${[...affected].join(',')}`) + // if (__isLocalBR) logger.log(`[BR-TRACE] buildRawMovedPoints position=${position} dir=${moveDirection} affected=${[...affected].join(',')}`) affected.forEach((i) => { const point = newPoints[i] if (!point) return @@ -455,21 +455,21 @@ const buildRawMovedPoints = (roofId, canvas) => { if (position === 'bottom') { if (moveDirection === 'out') point.y = Big(point.y).plus(moveUpDownLength).toNumber() else if (moveDirection === 'in') point.y = Big(point.y).minus(moveUpDownLength).toNumber() - if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} bottom/${moveDirection} y ${__by}→${point.y}`) + // if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} bottom/${moveDirection} y ${__by}→${point.y}`) } else if (position === 'top') { if (moveDirection === 'out') point.y = Big(point.y).minus(moveUpDownLength).toNumber() else if (moveDirection === 'in') point.y = Big(point.y).plus(moveUpDownLength).toNumber() - if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} top/${moveDirection} y ${__by}→${point.y}`) + // if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} top/${moveDirection} y ${__by}→${point.y}`) } else if (position === 'left') { if (moveDirection === 'out') point.x = Big(point.x).minus(moveUpDownLength).toNumber() else if (moveDirection === 'in') point.x = Big(point.x).plus(moveUpDownLength).toNumber() - if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} left/${moveDirection} x ${__bx}→${point.x}`) + // if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} left/${moveDirection} x ${__bx}→${point.x}`) } else if (position === 'right') { if (moveDirection === 'out') point.x = Big(point.x).plus(moveUpDownLength).toNumber() else if (moveDirection === 'in') point.x = Big(point.x).minus(moveUpDownLength).toNumber() - if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} right/${moveDirection} x ${__bx}→${point.x}`) + // if (__isLocalBR) logger.log(`[BR-TRACE] i=${i} right/${moveDirection} x ${__bx}→${point.x}`) } else if (__isLocalBR) { - logger.warn(`[BR-TRACE] i=${i} position=${position} 매칭 분기 없음 (이동 안 됨)`) + // logger.warn(`[BR-TRACE] i=${i} position=${position} 매칭 분기 없음 (이동 안 됨)`) } }) @@ -478,12 +478,12 @@ const buildRawMovedPoints = (roofId, canvas) => { const _sel = selectLine const _sp = _sel?.startPoint const _ep = _sel?.endPoint - logger.log(`[LP-TRACE] buildRaw.out matchingLines=${matchingLines.length} selSP=(${_sp?.x?.toFixed(1)},${_sp?.y?.toFixed(1)}) selEP=(${_ep?.x?.toFixed(1)},${_ep?.y?.toFixed(1)}) bp7=(${basePoints[7]?.x?.toFixed(1)},${basePoints[7]?.y?.toFixed(1)}) newPoints[7]=(${newPoints[7]?.x?.toFixed(1)},${newPoints[7]?.y?.toFixed(1)})`) + // logger.log(`[LP-TRACE] buildRaw.out matchingLines=${matchingLines.length} selSP=(${_sp?.x?.toFixed(1)},${_sp?.y?.toFixed(1)}) selEP=(${_ep?.x?.toFixed(1)},${_ep?.y?.toFixed(1)}) bp7=(${basePoints[7]?.x?.toFixed(1)},${basePoints[7]?.y?.toFixed(1)}) newPoints[7]=(${newPoints[7]?.x?.toFixed(1)},${newPoints[7]?.y?.toFixed(1)})`) } catch (_e) {} return newPoints } catch (e) { - logger.warn('[buildRawMovedPoints] 실패 → null fallback:', e) + // logger.warn('[buildRawMovedPoints] 실패 → null fallback:', e) return null } } @@ -512,7 +512,7 @@ export const verifyMoveBoundary = (roofId, canvas) => { try { const roof = canvas?.getObjects().find((o) => o.id === roofId) if (!roof || !Array.isArray(roof.points)) { - logger.log('[verifyMoveBoundary] roof/points 없음 → unknown') + // logger.log('[verifyMoveBoundary] roof/points 없음 → unknown') return 'unknown' } @@ -520,20 +520,20 @@ export const verifyMoveBoundary = (roofId, canvas) => { const moveUpDown = roof.moveUpDown ?? 0 const position = roof.movePosition const direction = roof.moveDirect - logger.log( - `[verifyMoveBoundary] 진입 position=${position} direction=${direction} moveUpDown=${moveUpDown} moveFlowLine=${moveFlowLine}` - ) + // logger.log( + // `[verifyMoveBoundary] 진입 position=${position} direction=${direction} moveUpDown=${moveUpDown} moveFlowLine=${moveFlowLine}` + // ) if (moveFlowLine === 0 && moveUpDown === 0) { - logger.log('[verifyMoveBoundary] 이동 없음 → ok') + // logger.log('[verifyMoveBoundary] 이동 없음 → ok') return 'ok' } const proposed = buildRawMovedPoints(roofId, canvas) const orig = roof.points if (!Array.isArray(proposed) || proposed.length !== orig.length) { - logger.log( - `[verifyMoveBoundary] proposed 비정상 (len=${proposed?.length}, orig.len=${orig.length}) → unknown` - ) + // logger.log( + // `[verifyMoveBoundary] proposed 비정상 (len=${proposed?.length}, orig.len=${orig.length}) → unknown` + // ) return 'unknown' } @@ -556,9 +556,9 @@ export const verifyMoveBoundary = (roofId, canvas) => { const crossOrig = getTurnDirection(orig[prev], orig[i], orig[next]) const crossNew = getTurnDirection(proposed[prev], proposed[i], proposed[next]) - logger.log( - `[verifyMoveBoundary] [${i}] orig=(${Math.round(orig[i].x)},${Math.round(orig[i].y)}) → proposed=(${Math.round(proposed[i].x)},${Math.round(proposed[i].y)}) crossOrig=${crossOrig.toFixed(1)} crossNew=${crossNew.toFixed(1)}` - ) + // logger.log( + // `[verifyMoveBoundary] [${i}] orig=(${Math.round(orig[i].x)},${Math.round(orig[i].y)}) → proposed=(${Math.round(proposed[i].x)},${Math.round(proposed[i].y)}) crossOrig=${crossOrig.toFixed(1)} crossNew=${crossNew.toFixed(1)}` + // ) // 원래 골짜기(>0) 였던 꼭짓점만 경계 판정 대상 if (crossOrig > 0) { @@ -566,27 +566,27 @@ export const verifyMoveBoundary = (roofId, canvas) => { const boundaryTol = Math.max(1.0, Math.abs(crossOrig) * 0.05) if (crossNew < -boundaryTol) { - logger.warn( - `[verifyMoveBoundary] 꼭짓점[${i}] 골짜기 → 볼록 뒤집힘 (CROSSED): ${crossOrig.toFixed(1)} → ${crossNew.toFixed(1)}` - ) + // logger.warn( + // `[verifyMoveBoundary] 꼭짓점[${i}] 골짜기 → 볼록 뒤집힘 (CROSSED): ${crossOrig.toFixed(1)} → ${crossNew.toFixed(1)}` + // ) return 'crossed' } if (Math.abs(crossNew) <= boundaryTol) { - logger.log( - `[verifyMoveBoundary] 꼭짓점[${i}] 경계 도달 (on-boundary): cross ≈ 0 (${crossNew.toFixed(1)})` - ) + // logger.log( + // `[verifyMoveBoundary] 꼭짓점[${i}] 경계 도달 (on-boundary): cross ≈ 0 (${crossNew.toFixed(1)})` + // ) if (worst === 'ok') worst = 'on-boundary' } } } if (movedIdx.length === 0) { - logger.log('[verifyMoveBoundary] 이동된 꼭짓점 0개 (buildRawMovedPoints 매칭 실패 가능성)') + // logger.log('[verifyMoveBoundary] 이동된 꼭짓점 0개 (buildRawMovedPoints 매칭 실패 가능성)') } - logger.log(`[verifyMoveBoundary] 최종 판정: ${worst} (moved indices=[${movedIdx.join(',')}])`) + // logger.log(`[verifyMoveBoundary] 최종 판정: ${worst} (moved indices=[${movedIdx.join(',')}])`) return worst } catch (e) { - logger.warn('[verifyMoveBoundary] 판정 실패 → unknown:', e) + // logger.warn('[verifyMoveBoundary] 판정 실패 → unknown:', e) return 'unknown' } } @@ -601,7 +601,7 @@ const safeMovedPointsWithFallback = (roofId, canvas) => { const movedPoints = movingLineFromSkeleton(roofId, canvas) if (!Array.isArray(movedPoints) || movedPoints.length === 0) { - logger.warn('[safeMovedPointsWithFallback] movedPoints 비정상 → bail out') + // logger.warn('[safeMovedPointsWithFallback] movedPoints 비정상 → bail out') return null } @@ -651,13 +651,13 @@ const safeMovedPointsWithFallback = (roofId, canvas) => { } if (zeroLenEdges > 0 || severeReduction || selfIntersect) { - logger.warn('[safeMovedPointsWithFallback] 붕괴/교차 감지 (로그만)', { - movedLen: movedPoints.length, - oldLen: oldPoints.length, - zeroLenEdges, - severeReduction, - selfIntersect, - }) + // logger.warn('[safeMovedPointsWithFallback] 붕괴/교차 감지 (로그만)', { + // movedLen: movedPoints.length, + // oldLen: oldPoints.length, + // zeroLenEdges, + // severeReduction, + // selfIntersect, + // }) } return movedPoints @@ -735,7 +735,7 @@ const drawBaselineToRooflineHelpers = (roof, canvas, baseLinePoints, roofLinePoi if (!il || !isFinite(il.x1) || !isFinite(il.y1) || !isFinite(il.x2) || !isFinite(il.y2)) return false return il.lineName === 'hip' || il.name === 'hip' }) - logger.log(`[v1 ext] HIP 추출 ${hipLines.length}개 / 전체 innerLines ${roof.innerLines.length}`) + // logger.log(`[v1 ext] HIP 추출 ${hipLines.length}개 / 전체 innerLines ${roof.innerLines.length}`) // 절삭 대상: roofLine seg + canvas 의 다른 보조라인 (eaveHelpLine 등). // 기존 helper 자체(BASELINE_TO_ROOFLINE_HELPER_TYPE) / wall/roof 본체 / 텍스트 등은 제외. @@ -765,7 +765,7 @@ const drawBaselineToRooflineHelpers = (roof, canvas, baseLinePoints, roofLinePoi const s = segs[k] auxList.push(`${s.__name || '?'}=(${Math.round(s.A.x)},${Math.round(s.A.y)})→(${Math.round(s.B.x)},${Math.round(s.B.y)}) len=${Math.round(Math.hypot(s.B.x - s.A.x, s.B.y - s.A.y))}`) } - logger.log(`[BR-SEGS] roofLine=${m} aux=${segs.length - m}`, auxList) + // logger.log(`[BR-SEGS] roofLine=${m} aux=${segs.length - m}`, auxList) } // [v1 ext 정정] ext 는 wallbaseLine 의 꼭지점(corner) 에 outer 끝점이 일치하는 hip 만 대상. @@ -784,16 +784,16 @@ const drawBaselineToRooflineHelpers = (roof, canvas, baseLinePoints, roofLinePoi // outer 끝이 wallbaseLine corner 에 일치하지 않으면 ext 대상 아님. if (outerCornerDist > CORNER_EPS) { - logger.log( - `[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) ` + - `corner 거리=${outerCornerDist.toFixed(2)} > ${CORNER_EPS} → 내부 hip skip` - ) + // logger.log( + // `[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) ` + + // `corner 거리=${outerCornerDist.toFixed(2)} > ${CORNER_EPS} → 내부 hip skip` + // ) continue } // 이미 처마(roofLine) 위에 있으면 ext 불필요. if (isPointOnRoofLine(outerEnd, 1.0)) { - logger.log(`[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) 이미 roofLine 위 → skip`) + // logger.log(`[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) 이미 roofLine 위 → skip`) continue } @@ -815,7 +815,7 @@ const drawBaselineToRooflineHelpers = (roof, canvas, baseLinePoints, roofLinePoi // [BR-RAY] local only — finite t 인 모든 후보 hit 찍기 (어떤 seg 가 가장 빠른지 비교용) if (__isLocalRayLog && isFinite(t)) { const __label = (k < m) ? `roofLine#${k}` : (segs[k].__name || `aux#${k - m}`) - logger.log(`[BR-RAY] hip outer=(${Math.round(outerEnd.x)},${Math.round(outerEnd.y)}) ${__label} t=${t.toFixed(2)} seg=(${Math.round(A.x)},${Math.round(A.y)})→(${Math.round(B.x)},${Math.round(B.y)})`) + // logger.log(`[BR-RAY] hip outer=(${Math.round(outerEnd.x)},${Math.round(outerEnd.y)}) ${__label} t=${t.toFixed(2)} seg=(${Math.round(A.x)},${Math.round(A.y)})→(${Math.round(B.x)},${Math.round(B.y)})`) } if (t < bestT) { bestT = t @@ -824,7 +824,7 @@ const drawBaselineToRooflineHelpers = (roof, canvas, baseLinePoints, roofLinePoi } } if (!isFinite(bestT) || bestT < 0.5) { - logger.log(`[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) NO_HIT or 너무 가까움`) + // logger.log(`[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) NO_HIT or 너무 가까움`) continue } @@ -833,18 +833,18 @@ const drawBaselineToRooflineHelpers = (roof, canvas, baseLinePoints, roofLinePoi // eaveHelpLine 이 ray 경로를 가로막으면 이미 eave/aux 영역에 도달한 것이므로 더 그릴 필요 없음. // roofLine 승자만 진짜 "처마 도달" 로 인정 → ext 그림. if (bestSegName === 'eaveHelpLine') { - logger.log(`[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) 승자=eaveHelpLine bestT=${bestT.toFixed(2)} → skip`) + // logger.log(`[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) 승자=eaveHelpLine bestT=${bestT.toFixed(2)} → skip`) continue } const hitX = outerEnd.x + ux * bestT const hitY = outerEnd.y + uy * bestT - logger.log( - `[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) ` + - `dir=(${ux.toFixed(3)},${uy.toFixed(3)}) bestT=${bestT.toFixed(2)} src=${bestSrc} ` + - `→ ext=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)})→(${hitX.toFixed(1)},${hitY.toFixed(1)})` - ) + // logger.log( + // `[v1 ext] hip outer=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)}) ` + + // `dir=(${ux.toFixed(3)},${uy.toFixed(3)}) bestT=${bestT.toFixed(2)} src=${bestSrc} ` + + // `→ ext=(${outerEnd.x.toFixed(1)},${outerEnd.y.toFixed(1)})→(${hitX.toFixed(1)},${hitY.toFixed(1)})` + // ) // ───────────────────────────────────────────────────────────────────────── // [hip 좌표 연장 2026-04-30] @@ -884,10 +884,10 @@ const drawBaselineToRooflineHelpers = (roof, canvas, baseLinePoints, roofLinePoi if (typeof hip.setLength === 'function') hip.setLength() if (typeof hip.addLengthText === 'function') hip.addLengthText() - logger.log( - `[v1 ext] hip 연장 oldLen=${oldLen.toFixed(1)} +extLen=${extLen.toFixed(1)} ratio=${ratio.toFixed(3)} ` + - `(plane ${oldPlane}→${hip.attributes.planeSize}, actual ${oldActual}→${hip.attributes.actualSize})` - ) + // logger.log( + // `[v1 ext] hip 연장 oldLen=${oldLen.toFixed(1)} +extLen=${extLen.toFixed(1)} ratio=${ratio.toFixed(3)} ` + + // `(plane ${oldPlane}→${hip.attributes.planeSize}, actual ${oldActual}→${hip.attributes.actualSize})` + // ) // ───────────────────────────────────────────────────────────────────────── // [확장선 스타일] local: 빨강 점선(디버그 가시화), dev/prd: innerLine 동일색·실선(연결된 것처럼). @@ -975,7 +975,7 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { // 1. 지붕 폴리곤 유효성 검사 const coordinates = preprocessPolygonCoordinates(roof.points) if (coordinates.length < 3) { - logger.warn('Polygon has less than 3 unique points. Cannot generate skeleton.') + // logger.warn('Polygon has less than 3 unique points. Cannot generate skeleton.') return } @@ -983,10 +983,10 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { const moveUpDown = roof.moveUpDown || 0 // 디버그: offset 변경 + moveLine 상태 확인 - logger.log('[DEBUG] moveFlowLine:', moveFlowLine, 'moveUpDown:', moveUpDown) - logger.log('[DEBUG] wall.lines:', wall.lines.map((l, i) => `[${i}] (${Math.round(l.x1)},${Math.round(l.y1)})→(${Math.round(l.x2)},${Math.round(l.y2)})`)) - logger.log('[DEBUG] wall.baseLines:', wall.baseLines.map((l, i) => `[${i}] (${Math.round(l.x1)},${Math.round(l.y1)})→(${Math.round(l.x2)},${Math.round(l.y2)})`)) - logger.log('[DEBUG] roof.points:', roof.points.map((p, i) => `[${i}] (${Math.round(p.x)},${Math.round(p.y)})`)) + // logger.log('[DEBUG] moveFlowLine:', moveFlowLine, 'moveUpDown:', moveUpDown) + // logger.log('[DEBUG] wall.lines:', wall.lines.map((l, i) => `[${i}] (${Math.round(l.x1)},${Math.round(l.y1)})→(${Math.round(l.x2)},${Math.round(l.y2)})`)) + // logger.log('[DEBUG] wall.baseLines:', wall.baseLines.map((l, i) => `[${i}] (${Math.round(l.x1)},${Math.round(l.y1)})→(${Math.round(l.x2)},${Math.round(l.y2)})`)) + // logger.log('[DEBUG] roof.points:', roof.points.map((p, i) => `[${i}] (${Math.round(p.x)},${Math.round(p.y)})`)) // 닫힌 폴리곤(첫점 = 끝점)인 경우 마지막 중복 점 제거 const isClosedPolygon = (points) => @@ -1076,10 +1076,10 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { try { const __moveVerdict = verifyMoveBoundary(roofId, canvas) if (__moveVerdict === 'crossed') { - logger.warn('[skeleton] 경계 넘음(crossed) → 오버된 wall.baseLine 좌표 기반 재빌드 진행') + // logger.warn('[skeleton] 경계 넘음(crossed) → 오버된 wall.baseLine 좌표 기반 재빌드 진행') } } catch (e) { - logger.warn('[skeleton] verifyMoveBoundary 예외 → 기존 흐름 진행:', e) + // logger.warn('[skeleton] verifyMoveBoundary 예외 → 기존 흐름 진행:', e) } const movedPoints = safeMovedPointsWithFallback(roofId, canvas) @@ -1128,8 +1128,8 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { if (SK_INPUT_USE_WALL_BASELINE_DIRECT) { changRoofLinePoints = orderedBaseLinePoints.map((p) => ({ x: p.x, y: p.y })) roofLineContactPoints = orderedBaseLinePoints.map((p) => ({ x: p.x, y: p.y })) - logger.log('[v1 SK_INPUT] wall.baseLines 직접 사용 (45° 확장/movedPoints 무시):', - changRoofLinePoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`).join(' ')) + // logger.log('[v1 SK_INPUT] wall.baseLines 직접 사용 (45° 확장/movedPoints 무시):', + // changRoofLinePoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`).join(' ')) // [v1 평행오버 corner 흡수 2026-04-29] // 평행오버 시 OVER_GUARD 가 인접 baseLine 길이를 OVER_EPS(0.5) 만큼만 남김. @@ -1162,15 +1162,15 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { kept = next } if (absorbedAll.length > 0 && kept.length >= 3) { - logger.log(`[v1 SK_INPUT 평행흡수] ${absorbedAll.length}개 corner 제거:\n ${absorbedAll.join('\n ')}`) - logger.log(`[v1 SK_INPUT 평행흡수] 최종 ${kept.length}개 corner:`, - kept.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`).join(' ')) + // logger.log(`[v1 SK_INPUT 평행흡수] ${absorbedAll.length}개 corner 제거:\n ${absorbedAll.join('\n ')}`) + // logger.log(`[v1 SK_INPUT 평행흡수] 최종 ${kept.length}개 corner:`, + // kept.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`).join(' ')) changRoofLinePoints = kept roofLineContactPoints = kept.map((p) => ({ x: p.x, y: p.y })) } } - logger.log('[DEBUG] changRoofLinePoints(최종 SK입력):', changRoofLinePoints.map((p, i) => `[${i}] (${Math.round(p.x)},${Math.round(p.y)})`)) + // logger.log('[DEBUG] changRoofLinePoints(최종 SK입력):', changRoofLinePoints.map((p, i) => `[${i}] (${Math.round(p.x)},${Math.round(p.y)})`)) // 좌표 유효성 검증 const invalidPoints = changRoofLinePoints.filter((p, i) => @@ -1187,7 +1187,7 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { const next = changRoofLinePoints[(i + 1) % changRoofLinePoints.length] const dist = Math.hypot(next.x - curr.x, next.y - curr.y) if (dist < 0.5) { - logger.warn(`[SK_WARN] 인접 중복점: [${i}](${Math.round(curr.x)},${Math.round(curr.y)}) ↔ [${(i + 1) % changRoofLinePoints.length}](${Math.round(next.x)},${Math.round(next.y)}) dist=${dist.toFixed(3)}`) + // logger.warn(`[SK_WARN] 인접 중복점: [${i}](${Math.round(curr.x)},${Math.round(curr.y)}) ↔ [${(i + 1) % changRoofLinePoints.length}](${Math.round(next.x)},${Math.round(next.y)}) dist=${dist.toFixed(3)}`) } } @@ -1198,7 +1198,7 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { const next = changRoofLinePoints[(i + 1) % changRoofLinePoints.length] const cross = (curr.x - prev.x) * (next.y - prev.y) - (curr.y - prev.y) * (next.x - prev.x) if (Math.abs(cross) < 1.0) { - logger.warn(`[SK_WARN] 일직선 점: [${i}](${Math.round(curr.x)},${Math.round(curr.y)}) cross=${cross.toFixed(3)}`) + // logger.warn(`[SK_WARN] 일직선 점: [${i}](${Math.round(curr.x)},${Math.round(curr.y)}) cross=${cross.toFixed(3)}`) } } @@ -1206,14 +1206,14 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { let isOverDetected = false const origPoints = roof.points || [] const n = changRoofLinePoints.length - logger.log('[SK_OVER_DEBUG] origPoints:', origPoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) - logger.log('[SK_OVER_DEBUG] changRoofLinePoints:', changRoofLinePoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) - logger.log('[SK_OVER_DEBUG] 변경된 점:', changRoofLinePoints.map((p, i) => { - const o = origPoints[i] - if (!o) return null - const dist = Math.hypot(p.x - o.x, p.y - o.y) - return dist > 1 ? `[${i}] dx=${Math.round(p.x - o.x)} dy=${Math.round(p.y - o.y)}` : null - }).filter(Boolean)) + // logger.log('[SK_OVER_DEBUG] origPoints:', origPoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) + // logger.log('[SK_OVER_DEBUG] changRoofLinePoints:', changRoofLinePoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) + // logger.log('[SK_OVER_DEBUG] 변경된 점:', changRoofLinePoints.map((p, i) => { + // const o = origPoints[i] + // if (!o) return null + // const dist = Math.hypot(p.x - o.x, p.y - o.y) + // return dist > 1 ? `[${i}] dx=${Math.round(p.x - o.x)} dy=${Math.round(p.y - o.y)}` : null + // }).filter(Boolean)) if (origPoints.length === n && n >= 3) { for (let i = 0; i < n; i++) { const prevOrig = origPoints[(i - 1 + n) % n] @@ -1257,7 +1257,7 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { ) if (corrected && corrected.length >= 3) { skeletonInputPoints = corrected - logger.log('[SK_OVER] 보정 포인트 적용:', skeletonInputPoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) + // logger.log('[SK_OVER] 보정 포인트 적용:', skeletonInputPoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) } } catch (e) { logger.error('[SK_OVER] 보정 실패 → fallback:', e) @@ -1270,8 +1270,8 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { try { // SkeletonBuilder는 닫히지 않은 폴리곤을 기대하므로 마지막 점 제거 geoJSONPolygon.pop() - logger.log('[SkeletonBuilder] geoJSONPolygon:', JSON.stringify(geoJSONPolygon, null, 2)) - logger.log('[SkeletonBuilder] 꼭짓점 수:', geoJSONPolygon.length) + // logger.log('[SkeletonBuilder] geoJSONPolygon:', JSON.stringify(geoJSONPolygon, null, 2)) + // logger.log('[SkeletonBuilder] 꼭짓점 수:', geoJSONPolygon.length) const skeleton = SkeletonBuilder.BuildFromGeoJSON([[geoJSONPolygon]]) // 스켈레톤 데이터를 기반으로 내부선 생성 @@ -1324,9 +1324,9 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { // [LP-TRACE] 실제 저장되는 lastPoints[7] — 이 값이 다음 이동의 prevLast[7] try { const _p7 = rawMovedFull[7] - logger.log(`[LP-TRACE] lastPoints.save [7]=(${_p7?.x?.toFixed(1)},${_p7?.y?.toFixed(1)}) len=${rawMovedFull.length}`) + // logger.log(`[LP-TRACE] lastPoints.save [7]=(${_p7?.x?.toFixed(1)},${_p7?.y?.toFixed(1)}) len=${rawMovedFull.length}`) } catch (_e) {} - logger.log('[skeleton] lastPoints 저장: raw 풀 길이', rawMovedFull.length, '점') + // logger.log('[skeleton] lastPoints 저장: raw 풀 길이', rawMovedFull.length, '점') } else { canvas.skeleton.lastPoints = roofLineContactPoints } @@ -1363,12 +1363,12 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { export const drawSkeletonRidgeRoofFromBaseLines = (roofId, canvas, textMode) => { const roof = canvas?.getObjects().find((o) => o.id === roofId) if (!roof) { - logger.warn('[SK_OVER_FN] roof 없음 → 중단') + // logger.warn('[SK_OVER_FN] roof 없음 → 중단') return } const wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes?.roofId === roofId) if (!wall || !wall.baseLines?.length) { - logger.warn('[SK_OVER_FN] wall/baseLines 없음 → 중단') + // logger.warn('[SK_OVER_FN] wall/baseLines 없음 → 중단') return } @@ -1378,22 +1378,22 @@ export const drawSkeletonRidgeRoofFromBaseLines = (roofId, canvas, textMode) => const bl = wall.baseLines[i] const planeSize = bl?.attributes?.planeSize ?? Infinity if (planeSize < 1) { - logger.log(`[SK_OVER_FN] baseLines[${i}] SHOULDER_ABSORBED skip (planeSize=${planeSize})`) + // logger.log(`[SK_OVER_FN] baseLines[${i}] SHOULDER_ABSORBED skip (planeSize=${planeSize})`) continue } if (bl == null || !isFinite(bl.x1) || !isFinite(bl.y1)) { - logger.warn(`[SK_OVER_FN] baseLines[${i}] invalid coord → skip`) + // logger.warn(`[SK_OVER_FN] baseLines[${i}] invalid coord → skip`) continue } rawPoints.push({ x: bl.x1, y: bl.y1 }) } if (rawPoints.length < 3) { - logger.warn(`[SK_OVER_FN] 유효 baseLines 끝점 ${rawPoints.length} < 3 → 중단`) + // logger.warn(`[SK_OVER_FN] 유효 baseLines 끝점 ${rawPoints.length} < 3 → 중단`) return } - logger.log('[SK_OVER_FN] wall.baseLines polygon:', rawPoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) + // logger.log('[SK_OVER_FN] wall.baseLines polygon:', rawPoints.map((p, i) => `[${i}](${Math.round(p.x)},${Math.round(p.y)})`)) // skeletonPoints 마킹 (오버 좌표 그대로) roof.skeletonPoints = rawPoints.map((p) => ({ x: p.x, y: p.y })) @@ -1403,8 +1403,8 @@ export const drawSkeletonRidgeRoofFromBaseLines = (roofId, canvas, textMode) => try { geoJSONPolygon.pop() - logger.log('[SK_OVER_FN] geoJSONPolygon:', JSON.stringify(geoJSONPolygon, null, 2)) - logger.log('[SK_OVER_FN] 꼭짓점 수:', geoJSONPolygon.length) + // logger.log('[SK_OVER_FN] geoJSONPolygon:', JSON.stringify(geoJSONPolygon, null, 2)) + // logger.log('[SK_OVER_FN] 꼭짓점 수:', geoJSONPolygon.length) const skeleton = SkeletonBuilder.BuildFromGeoJSON([[geoJSONPolygon]]) roof.innerLines = roof.innerLines || [] @@ -1577,7 +1577,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver if (rotIdx > 0) { wallLines = [...wallLines.slice(rotIdx), ...wallLines.slice(0, rotIdx)] if (process.env.NEXT_PUBLIC_RUN_MODE === 'local') { - logger.log('[WL-ROT-FIX] wall.lines rotated by', -rotIdx, 'to align with wall.baseLines[0].startPoint') + // logger.log('[WL-ROT-FIX] wall.lines rotated by', -rotIdx, 'to align with wall.baseLines[0].startPoint') } } } @@ -1723,24 +1723,24 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver // [PAIR-DIAG] local only — top in 시 페어 인덱스 어긋남 진단 (2026-04-30) // 1) 길이 미스매치 / 2) _keyOfEdge 충돌 / 3) raw 단계 1:1 무너짐 가려내기 위함 if (process.env.NEXT_PUBLIC_RUN_MODE === 'local') { - logger.log('[PAIR-DIAG] lengths', { - roofLines: roofLines.length, - wallLines: wallLines.length, - wallBaseLines: wall.baseLines.length, - }) + // logger.log('[PAIR-DIAG] lengths', { + // roofLines: roofLines.length, + // wallLines: wallLines.length, + // wallBaseLines: wall.baseLines.length, + // }) const _seen = new Map() roofLines.forEach((l, i) => { const k = _keyOfEdge(l) - if (_seen.has(k)) logger.warn(`[PAIR-DIAG] key collision: idx ${_seen.get(k)} vs ${i} key=${k}`) - else _seen.set(k, i) + // if (_seen.has(k)) logger.warn(`[PAIR-DIAG] key collision: idx ${_seen.get(k)} vs ${i} key=${k}`) + // else _seen.set(k, i) }) roofLines.forEach((rl, i) => { const wl = wallLines[i] const wb = wall.baseLines[i] - logger.log(`[PAIR-DIAG] raw#${i}`, - `roof=(${Math.round(rl.x1)},${Math.round(rl.y1)})→(${Math.round(rl.x2)},${Math.round(rl.y2)})`, - wl ? `wall=(${Math.round(wl.x1)},${Math.round(wl.y1)})→(${Math.round(wl.x2)},${Math.round(wl.y2)})` : 'wall=∅', - wb ? `base=(${Math.round(wb.x1)},${Math.round(wb.y1)})→(${Math.round(wb.x2)},${Math.round(wb.y2)})` : 'base=∅') + // logger.log(`[PAIR-DIAG] raw#${i}`, + // `roof=(${Math.round(rl.x1)},${Math.round(rl.y1)})→(${Math.round(rl.x2)},${Math.round(rl.y2)})`, + // wl ? `wall=(${Math.round(wl.x1)},${Math.round(wl.y1)})→(${Math.round(wl.x2)},${Math.round(wl.y2)})` : 'wall=∅', + // wb ? `base=(${Math.round(wb.x1)},${Math.round(wb.y1)})→(${Math.round(wb.x2)},${Math.round(wb.y2)})` : 'base=∅') }) } @@ -1774,7 +1774,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const l = `${lineAxis}${k}` // y1 or x1 const otherL = `${lineAxis}${otherK}` // y2 or x2 - logger.log(`${condition}::::isStartEnd:::::`) + // logger.log(`${condition}::::isStartEnd:::::`) // [MOVE-TRACE] index 0 전용 (필요 시 주석 해제) // if (index === 0) { @@ -1826,7 +1826,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const wbL = wallBaseLine[l] const wL = wallLine[l] if (Math.abs(wbL - wL) < 0.1) { - logger.warn(`⚠️ [${condition.toUpperCase()}_${isStart ? 'START' : 'END'}] Line crossing detected! newPoint:`, newPointM, 'pLine:', pLineM) + // logger.warn(`⚠️ [${condition.toUpperCase()}_${isStart ? 'START' : 'END'}] Line crossing detected! newPoint:`, newPointM, 'pLine:', pLineM) if (moveAxis === 'x') { getAddLine({ x: pLineM, y: pLineL }, { x: newPointM, y: pLineL }, 'green') getAddLine({ x: newPointM, y: pLineL }, ePoint, 'pink') @@ -1858,12 +1858,12 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const prevAbsorbed = (prevBL?.attributes?.planeSize ?? Infinity) < 10 const nextAbsorbed = (nextBL?.attributes?.planeSize ?? Infinity) < 10 if (prevAbsorbed || nextAbsorbed) { - logger.log(`⏭️ [pair#${index}] ${condition} HIP_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) + // logger.log(`⏭️ [pair#${index}] ${condition} HIP_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) return } } - logger.log(`${condition}::::isStartEnd (both):::::`) + // logger.log(`${condition}::::isStartEnd (both):::::`) // 원본 기준: moveDistY = abs(roofLine.y - wallBaseLine.y), moveDistX = abs(roofLine.x - wallBaseLine.x) const moveDistY1 = Math.abs(Big(roofLine.y1).minus(wallBaseLine.y1).toNumber()) @@ -1889,7 +1889,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const createHipLine = (fromPoint, toPoint) => { const createdLine = getAddLine(fromPoint, toPoint, 'orange', 'extensionLine') - logger.log('extensionLine created - length:', createdLine.length, 'coords:', { x1: createdLine.x1, y1: createdLine.y1, x2: createdLine.x2, y2: createdLine.y2 }) + // logger.log('extensionLine created - length:', createdLine.length, 'coords:', { x1: createdLine.x1, y1: createdLine.y1, x2: createdLine.x2, y2: createdLine.y2 }) createdLine.set({ name: LINE_TYPE.SUBLINE.HIP, lineName: LINE_TYPE.SUBLINE.HIP, stroke: '#FF0000', strokeWidth: 2 }) createdLine.attributes = { ...createdLine.attributes, type: LINE_TYPE.SUBLINE.HIP } innerLines.push(createdLine) @@ -1915,7 +1915,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver target = { x: roofLine.x1 + xSignStart * dist, y: roofLine.y1 } } if (!__isNearSkVertex(target)) { - logger.log(`⏭️ [pair#${index}] ${condition} HIP_SKIP_VERTEX_MISS start target=(${target.x.toFixed(1)},${target.y.toFixed(1)})`) + // logger.log(`⏭️ [pair#${index}] ${condition} HIP_SKIP_VERTEX_MISS start target=(${target.x.toFixed(1)},${target.y.toFixed(1)})`) } else { createHipLine(sPoint, target) } @@ -1931,7 +1931,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver target = { x: roofLine.x2 + xSignEnd * dist, y: roofLine.y2 } } if (!__isNearSkVertex(target)) { - logger.log(`⏭️ [pair#${index}] ${condition} HIP_SKIP_VERTEX_MISS end target=(${target.x.toFixed(1)},${target.y.toFixed(1)})`) + // logger.log(`⏭️ [pair#${index}] ${condition} HIP_SKIP_VERTEX_MISS end target=(${target.x.toFixed(1)},${target.y.toFixed(1)})`) } else { createHipLine(ePoint, target) } @@ -1988,7 +1988,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver // }) // } - logger.log('wallBaseLines', wall.baseLines) + // logger.log('wallBaseLines', wall.baseLines) //wall.baseLine은 움직인라인 let movedLines = [] @@ -1996,7 +1996,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver // 조건에 맞는 라인들만 필터링 const validWallLines = [...wallLines].sort((a, b) => a.idx - b.idx).filter((wallLine, index) => wallLine.idx - 1 === index) - logger.log('', sortRoofLines, sortWallLines, sortWallBaseLines); + // logger.log('', sortRoofLines, sortWallLines, sortWallBaseLines); (sortWallLines.length === sortWallBaseLines.length && sortWallBaseLines.length > 3) && sortWallLines.forEach((wallLine, index) => { @@ -2009,7 +2009,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver // 임계 = 10: useMovementSetting OVER_EPS=0.5 (canvas unit) 시 잔여 길이=0.5 → planeSize=5 (calcLinePlaneSize × 10). // 안전마진 두고 < 10 으로 차단. 정상 baseLine 은 보통 50+ 이므로 false positive 없음. if (!wallBaseLine || (wallBaseLine.attributes?.planeSize ?? Infinity) < 10) { - logger.log(`⏭️ [pair#${index}] SHOULDER_ABSORBED skip: wb=(${Math.round(wallBaseLine?.x1)},${Math.round(wallBaseLine?.y1)})→(${Math.round(wallBaseLine?.x2)},${Math.round(wallBaseLine?.y2)}) planeSize=${wallBaseLine?.attributes?.planeSize}`) + // logger.log(`⏭️ [pair#${index}] SHOULDER_ABSORBED skip: wb=(${Math.round(wallBaseLine?.x1)},${Math.round(wallBaseLine?.y1)})→(${Math.round(wallBaseLine?.x2)},${Math.round(wallBaseLine?.y2)}) planeSize=${wallBaseLine?.attributes?.planeSize}`) return } @@ -2022,7 +2022,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const wallIdWl = wallLine.attributes?.wallId ?? wallLine.attributes?.idx ?? '?' const wallIdWb = wallBaseLine.attributes?.wallId ?? wallBaseLine.attributes?.idx ?? '?' const dirMatch = wlDir === wbDir - logger.log(`🔗 [pair#${index}] wallId wl=${wallIdWl} wb=${wallIdWb} ${dirMatch ? '' : '⚠️DIR_MISMATCH '}wlDir=${wlDir} wbDir=${wbDir} wl=(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)}) wb=(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`) + // logger.log(`🔗 [pair#${index}] wallId wl=${wallIdWl} wb=${wallIdWb} ${dirMatch ? '' : '⚠️DIR_MISMATCH '}wlDir=${wlDir} wbDir=${wbDir} wl=(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)}) wb=(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`) } //roofline 외곽선 설정 @@ -2066,7 +2066,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver } for (const [p1, p2] of __cgPairs) { if (Math.hypot(p2.x - p1.x, p2.y - p1.y) < 0.5) continue - logger.log(`🎯 [corner-gap eaveHelpLine] index=${index} p1=(${Math.round(p1.x)},${Math.round(p1.y)})→p2=(${Math.round(p2.x)},${Math.round(p2.y)}) wallLine=(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)}) wallBaseLine=(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`) + // logger.log(`🎯 [corner-gap eaveHelpLine] index=${index} p1=(${Math.round(p1.x)},${Math.round(p1.y)})→p2=(${Math.round(p2.x)},${Math.round(p2.y)}) wallLine=(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)}) wallBaseLine=(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`) const __cgLine = new QLine([p1.x, p1.y, p2.x, p2.y], { parentId: roof.id, fontSize: roof.fontSize, @@ -2112,15 +2112,15 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver movedLines.push({ index, p1, p2 }) // [진단] eaveHelpLine 생성 추적: 어느 index/어느 wallBaseLine-wallLine 쌍에서 만들어지는지 - logger.log('🎯 [getAddLine]', { - index, - lineType, - p1: { x: Math.round(p1.x), y: Math.round(p1.y) }, - p2: { x: Math.round(p2.x), y: Math.round(p2.y) }, - wallLine: `(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)})`, - wallBaseLine: `(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`, - wallBaseLen: Math.round(Math.hypot(wallBaseLine.x2 - wallBaseLine.x1, wallBaseLine.y2 - wallBaseLine.y1)), - }) + // logger.log('🎯 [getAddLine]', { + // index, + // lineType, + // p1: { x: Math.round(p1.x), y: Math.round(p1.y) }, + // p2: { x: Math.round(p2.x), y: Math.round(p2.y) }, + // wallLine: `(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)})`, + // wallBaseLine: `(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`, + // wallBaseLen: Math.round(Math.hypot(wallBaseLine.x2 - wallBaseLine.x1, wallBaseLine.y2 - wallBaseLine.y1)), + // }) const dx = Math.abs(p2.x - p1.x); const dy = Math.abs(p2.y - p1.y); @@ -2190,7 +2190,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const midY = (wallBaseLine.y1 + wallBaseLine.y2) / 2 const isH = Math.abs(wallBaseLine.y1 - wallBaseLine.y2) < 0.5 const isV = Math.abs(wallBaseLine.x1 - wallBaseLine.x2) < 0.5 - logger.log(`🧭 [getSelectLinePosition 결과] idx=${index} position=${mLine.position} orient=${mLine.orientation} mid=(${Math.round(midX)},${Math.round(midY)}) isH=${isH} isV=${isV} wallLine=(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)}) wallBaseLine=(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`) + // logger.log(`🧭 [getSelectLinePosition 결과] idx=${index} position=${mLine.position} orient=${mLine.orientation} mid=(${Math.round(midX)},${Math.round(midY)}) isH=${isH} isV=${isV} wallLine=(${Math.round(wallLine.x1)},${Math.round(wallLine.y1)})→(${Math.round(wallLine.x2)},${Math.round(wallLine.y2)}) wallBaseLine=(${Math.round(wallBaseLine.x1)},${Math.round(wallBaseLine.y1)})→(${Math.round(wallBaseLine.x2)},${Math.round(wallBaseLine.y2)})`) } if (getOrientation(roofLine) === 'vertical') { @@ -2247,7 +2247,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const prevAbsorbed = (prevBL?.attributes?.planeSize ?? Infinity) < 10 const nextAbsorbed = (nextBL?.attributes?.planeSize ?? Infinity) < 10 if (prevAbsorbed || nextAbsorbed) { - logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) + // logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) return } } @@ -2306,7 +2306,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver } if (isStartEnd.end) { - logger.log('left_out::::isStartEnd:::::', isStartEnd) + // logger.log('left_out::::isStartEnd:::::', isStartEnd) const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber() const aStartY = Big(roofLine.y2).plus(moveDist).toNumber() const bStartY = Big(wallLine.y2).plus(moveDist).toNumber() @@ -2371,13 +2371,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const prevAbsorbed = (prevBL?.attributes?.planeSize ?? Infinity) < 10 const nextAbsorbed = (nextBL?.attributes?.planeSize ?? Infinity) < 10 if (prevAbsorbed || nextAbsorbed) { - logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) + // logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) return } } if (isStartEnd.start) { - logger.log('right_out::::isStartEnd:::::', isStartEnd) + // logger.log('right_out::::isStartEnd:::::', isStartEnd) const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber() const aStartY = Big(roofLine.y1).plus(moveDist).toNumber() const bStartY = Big(wallLine.y1).plus(moveDist).toNumber() @@ -2532,13 +2532,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const prevAbsorbed = (prevBL?.attributes?.planeSize ?? Infinity) < 10 const nextAbsorbed = (nextBL?.attributes?.planeSize ?? Infinity) < 10 if (prevAbsorbed || nextAbsorbed) { - logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) + // logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) return } } if (isStartEnd.start) { - logger.log('top_out isStartEnd:::::::', isStartEnd) + // logger.log('top_out isStartEnd:::::::', isStartEnd) const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() const aStartX = Big(roofLine.x1).plus(moveDist).toNumber() const bStartX = Big(wallLine.x1).plus(moveDist).toNumber() @@ -2591,7 +2591,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver getAddLine(newPStart, newPEnd, 'red') } if (isStartEnd.end) { - logger.log('isStartEnd:::::', isStartEnd) + // logger.log('isStartEnd:::::', isStartEnd) const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() const aStartX = Big(roofLine.x2).minus(moveDist).toNumber() const bStartX = Big(wallLine.x2).minus(moveDist).toNumber() @@ -2643,7 +2643,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver getAddLine(newPStart, newPEnd, 'red') } } else if (condition === 'bottom_out') { - logger.log('bottom_out isStartEnd:::::::', isStartEnd) + // logger.log('bottom_out isStartEnd:::::::', isStartEnd) // [SHOULDER-ADJACENT _out] 인접 pair 흡수 시 현재 pair 의 끝점은 새 SK 토폴로지에서 dissolve 됨. // roof.points 옛 코너 참조 → updateAndAddLine NOT FOUND + phantom eaveHelpLine 외부 출현. @@ -2655,13 +2655,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver const prevAbsorbed = (prevBL?.attributes?.planeSize ?? Infinity) < 10 const nextAbsorbed = (nextBL?.attributes?.planeSize ?? Infinity) < 10 if (prevAbsorbed || nextAbsorbed) { - logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) + // logger.log(`⏭️ [pair#${index}] ${condition} OUT_SKIP adj_absorbed prev=${prevAbsorbed} next=${nextAbsorbed}`) return } } if (isStartEnd.start) { - logger.log('isStartEnd:::::::', isStartEnd) + // logger.log('isStartEnd:::::::', isStartEnd) const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() const aStartX = Big(roofLine.x1).minus(moveDist).toNumber() const bStartX = Big(wallLine.x1).minus(moveDist).toNumber() @@ -2714,7 +2714,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver } if (isStartEnd.end) { - logger.log('isStartEnd:::::', isStartEnd) + // logger.log('isStartEnd:::::', isStartEnd) const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() const aStartX = Big(roofLine.x2).plus(moveDist).toNumber() const bStartX = Big(wallLine.x2).plus(moveDist).toNumber() @@ -2851,12 +2851,12 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver if (toRemove.length > 0) { if (process.env.NEXT_PUBLIC_RUN_MODE === 'local') { - logger.log( - `[B안 cull] dead-end ridge 제거 ${toRemove.length}개`, - toRemove.map( - (l) => `(${Math.round(l.x1)},${Math.round(l.y1)})→(${Math.round(l.x2)},${Math.round(l.y2)})` - ) - ) + // logger.log( + // `[B안 cull] dead-end ridge 제거 ${toRemove.length}개`, + // toRemove.map( + // (l) => `(${Math.round(l.x1)},${Math.round(l.y1)})→(${Math.round(l.x2)},${Math.round(l.y2)})` + // ) + // ) } toRemove.forEach((line) => { canvas.remove(line) @@ -2915,7 +2915,7 @@ function processEavesEdge(roofId, canvas, skeleton, edgeResult, skeletonLines) { if(!outerLine) { outerLine = findMatchingLine(edgeResult.Polygon, roof, roof.points); - logger.log('Has matching line:', outerLine); + // logger.log('Has matching line:', outerLine); //if(outerLine === null) return } // [hip pitch fallback 2026-04-30] @@ -3084,12 +3084,12 @@ function logDeadEndLines(skeletonLines, roof) { const p2Dead = deadEndVertices.has(k2); if (p1Dead || p2Dead) { - logger.log('⚠️ [logDeadEndLines] 삭제 후보:', { - idx, - p1: { x: Math.round(line.p1.x), y: Math.round(line.p1.y), deadEnd: p1Dead, isRoof: isRoofVertex(line.p1) }, - p2: { x: Math.round(line.p2.x), y: Math.round(line.p2.y), deadEnd: p2Dead, isRoof: isRoofVertex(line.p2) }, - dx: Math.round(dx), dy: Math.round(dy), - }); + // logger.log('⚠️ [logDeadEndLines] 삭제 후보:', { + // idx, + // p1: { x: Math.round(line.p1.x), y: Math.round(line.p1.y), deadEnd: p1Dead, isRoof: isRoofVertex(line.p1) }, + // p2: { x: Math.round(line.p2.x), y: Math.round(line.p2.y), deadEnd: p2Dead, isRoof: isRoofVertex(line.p2) }, + // dx: Math.round(dx), dy: Math.round(dy), + // }); } }); @@ -3248,8 +3248,8 @@ const calcOverCorrectedPointsSafe = (points, origPoints, lastPoints) => { changedNow[i] ? op : (lastPoints[i] ?? op) ) - logger.log('[calcOverCorrectedPointsSafe] changedNow:', - changedNow.map((v, i) => v ? i : null).filter(v => v !== null)) + // logger.log('[calcOverCorrectedPointsSafe] changedNow:', + // changedNow.map((v, i) => v ? i : null).filter(v => v !== null)) return calcOverCorrectedPoints(points, virtualOrig) } @@ -3271,7 +3271,7 @@ const calcOverCorrectedPoints = (points, origPoints) => { const origDir = origPoints[movedIdx].x - origPoints[fixedIdx].x const newDir = skPoints[movedIdx].x - skPoints[fixedIdx].x if (origDir * newDir < 0) { - logger.log(`[SK_OVER] 클램핑: [${movedIdx}].x ${Math.round(skPoints[movedIdx].x)} → ${Math.round(skPoints[fixedIdx].x)}`) + // logger.log(`[SK_OVER] 클램핑: [${movedIdx}].x ${Math.round(skPoints[movedIdx].x)} → ${Math.round(skPoints[fixedIdx].x)}`) skPoints[movedIdx].x = skPoints[fixedIdx].x didClamp = true } @@ -3281,7 +3281,7 @@ const calcOverCorrectedPoints = (points, origPoints) => { const origDir = origPoints[movedIdx].y - origPoints[fixedIdx].y const newDir = skPoints[movedIdx].y - skPoints[fixedIdx].y if (origDir * newDir < 0) { - logger.log(`[SK_OVER] 클램핑: [${movedIdx}].y ${Math.round(skPoints[movedIdx].y)} → ${Math.round(skPoints[fixedIdx].y)}`) + // logger.log(`[SK_OVER] 클램핑: [${movedIdx}].y ${Math.round(skPoints[movedIdx].y)} → ${Math.round(skPoints[fixedIdx].y)}`) skPoints[movedIdx].y = skPoints[fixedIdx].y didClamp = true } @@ -3342,7 +3342,7 @@ const calcOverCorrectedPoints = (points, origPoints) => { // 보정 실패 시(꼭짓점 부족) 원본 반환 → 기존 동작 보장 if (cleaned.length >= 3) return cleaned if (deduped.length >= 3) return deduped - logger.warn('[SK_OVER] calcOverCorrectedPoints: 보정 실패 → 원본 반환') + // logger.warn('[SK_OVER] calcOverCorrectedPoints: 보정 실패 → 원본 반환') return points } @@ -4534,14 +4534,14 @@ export const getSelectLinePosition = (wall, selectLine, options = {}) => { const { testDistance = 10, epsilon = 0.5, debug = false } = options; if (!wall || !selectLine) { - if (debug) logger.log('ERROR: wall 또는 selectLine이 없음'); + // if (debug) logger.log('ERROR: wall 또는 selectLine이 없음'); return { position: 'unknown', orientation: 'unknown', error: 'invalid_input' }; } // selectLine의 좌표 추출 const lineCoords = extractLineCoords(selectLine); if (!lineCoords.valid) { - if (debug) logger.log('ERROR: selectLine 좌표가 유효하지 않음'); + // if (debug) logger.log('ERROR: selectLine 좌표가 유효하지 않음'); return { position: 'unknown', orientation: 'unknown', error: 'invalid_coords' }; } @@ -4633,7 +4633,7 @@ export const getSelectLinePosition = (wall, selectLine, options = {}) => { } else { // 대각선 - if (debug) logger.log('대각선은 지원하지 않음'); + // if (debug) logger.log('대각선은 지원하지 않음'); return { position: 'unknown', orientation: 'diagonal', error: 'not_supported' }; } @@ -4664,7 +4664,7 @@ const checkPointInPolygon = (point, wall) => { // 2. wall.baseLines를 이용한 Ray Casting Algorithm if (!wall.baseLines || !Array.isArray(wall.baseLines)) { - logger.warn('wall.baseLines가 없습니다'); + // logger.warn('wall.baseLines가 없습니다'); return false; } @@ -4848,9 +4848,9 @@ export const processEaveHelpLines = (lines) => { const mergedHorizontal = mergeLines(horizontalLines, 'horizontal'); // 결과 확인용 로그 - logger.log('Original lines:', lines.length); - logger.log('Merged vertical:', mergedVertical.length); - logger.log('Merged horizontal:', mergedHorizontal.length); + // logger.log('Original lines:', lines.length); + // logger.log('Merged vertical:', mergedVertical.length); + // logger.log('Merged horizontal:', mergedHorizontal.length); return [...mergedVertical, ...mergedHorizontal]; }; @@ -4893,7 +4893,7 @@ const mergeLines = (lines, direction) => { merged.push(current); // 병합 결과 로그 - logger.log(`Merged ${direction} lines:`, merged); + // logger.log(`Merged ${direction} lines:`, merged); return merged; }; @@ -4959,11 +4959,11 @@ function updateAndAddLine(innerLines, targetPoint) { if (!foundLine) { foundLine = findLineContainingPoint(innerLines, targetPoint); if (foundLine) { - logger.log(`[MOVE-TRACE] HIP fallback matched: position=${targetPoint.position} target=(${targetPoint.x.toFixed(2)},${targetPoint.y.toFixed(2)}) → (${foundLine.x1.toFixed(1)},${foundLine.y1.toFixed(1)})→(${foundLine.x2.toFixed(1)},${foundLine.y2.toFixed(1)}) type=${foundLine.attributes?.type||'?'}`) + // logger.log(`[MOVE-TRACE] HIP fallback matched: position=${targetPoint.position} target=(${targetPoint.x.toFixed(2)},${targetPoint.y.toFixed(2)}) → (${foundLine.x1.toFixed(1)},${foundLine.y1.toFixed(1)})→(${foundLine.x2.toFixed(1)},${foundLine.y2.toFixed(1)}) type=${foundLine.attributes?.type||'?'}`) } } if (!foundLine) { - logger.warn(`[updateAndAddLine] NOT FOUND position=${targetPoint.position} point=(${targetPoint.x.toFixed(2)},${targetPoint.y.toFixed(2)})`); + // logger.warn(`[updateAndAddLine] NOT FOUND position=${targetPoint.position} point=(${targetPoint.x.toFixed(2)},${targetPoint.y.toFixed(2)})`); return [...innerLines]; } @@ -5116,7 +5116,7 @@ function isPointOnLineSegment2(point, lineStart, lineEnd, tolerance = 0.1) { const isOnSegment = Math.abs((dist1 + dist2) - lineLength) <= tolerance; if (isOnSegment) { - logger.log(`점 (${px}, ${py})은 선분 [(${x1}, ${y1}), (${x2}, ${y2})] 위에 있습니다.`); + // logger.log(`점 (${px}, ${py})은 선분 [(${x1}, ${y1}), (${x2}, ${y2})] 위에 있습니다.`); } return isOnSegment; @@ -5223,13 +5223,13 @@ function isValleyVertex(targetPoint, connectedLine, allLines, isStartVertex) { const fmt = (p) => `(${Math.round(p.x)},${Math.round(p.y)})`; const cLen = Math.hypot(clx2 - clx1, cly2 - cly1); const nLen = Math.hypot(nlx2 - nlx1, nly2 - nly1); - logger.log( - `[VALLEY] ${isStartVertex ? 'START' : 'END'} target=${fmt(targetPoint)} ` + - `conn=${fmt({x:clx1,y:cly1})}→${fmt({x:clx2,y:cly2})}[len=${cLen.toFixed(2)}] ` + - `neigh=${fmt({x:nlx1,y:nly1})}→${fmt({x:nlx2,y:nly2})}[len=${nLen.toFixed(2)}] ` + - `p1=${fmt(p1)} p2=${fmt(p2)} p3=${fmt(p3)} cross=${crossProduct.toFixed(2)} ` + - `valley=${collinearSkip ? false : (crossProduct > 0)}${collinearSkip ? ' (collinear-skip)' : ''}` - ); + // logger.log( + // `[VALLEY] ${isStartVertex ? 'START' : 'END'} target=${fmt(targetPoint)} ` + + // `conn=${fmt({x:clx1,y:cly1})}→${fmt({x:clx2,y:cly2})}[len=${cLen.toFixed(2)}] ` + + // `neigh=${fmt({x:nlx1,y:nly1})}→${fmt({x:nlx2,y:nly2})}[len=${nLen.toFixed(2)}] ` + + // `p1=${fmt(p1)} p2=${fmt(p2)} p3=${fmt(p3)} cross=${crossProduct.toFixed(2)} ` + + // `valley=${collinearSkip ? false : (crossProduct > 0)}${collinearSkip ? ' (collinear-skip)' : ''}` + // ); if (collinearSkip) return false; return crossProduct > 0; } -- 2.47.2