[1961] split 길이 계산 Math.round(hypot)*10 → calcLinePlaneSize 통일 — 좌우대칭 hip 라벨 1mm 갈림 차단 #843

Merged
ysCha merged 1 commits from dev into prd-deploy 2026-05-14 10:42:27 +09:00
2 changed files with 12 additions and 51 deletions

View File

@ -670,28 +670,6 @@ export function useRoofAllocationSetting(id) {
(obj.lineName === 'eaveHelpLine' || obj.lineName === 'extensionLine') &&
obj.roofId === roofBase.id
)
// [ALLOC-DEBUG] canvas 픽업 스냅샷 (삭제 직전 상태)
const snapByLineName = {}
const snapByName = {}
roofEaveHelpLines.forEach((o) => {
snapByLineName[o.lineName] = (snapByLineName[o.lineName] || 0) + 1
snapByName[o.name || '?'] = (snapByName[o.name || '?'] || 0) + 1
})
logger.log(
`[ALLOC-DEBUG] roofBase.id=${roofBase.id} ` +
`roofBase.lines=${roofBase.lines?.length || 0} ` +
`roofBase.innerLines=${roofBase.innerLines?.length || 0} ` +
`canvas픽업=${roofEaveHelpLines.length} ` +
`byLineName=${JSON.stringify(snapByLineName)} ` +
`byName=${JSON.stringify(snapByName)}`
)
roofEaveHelpLines.forEach((o, i) => {
logger.log(
` [ALLOC-DEBUG] picked[${i}] name=${o.name} lineName=${o.lineName} ` +
`(${o.x1?.toFixed(1)},${o.y1?.toFixed(1)})→(${o.x2?.toFixed(1)},${o.y2?.toFixed(1)}) ` +
`len=${Math.hypot((o.x2 || 0) - (o.x1 || 0), (o.y2 || 0) - (o.y1 || 0)).toFixed(1)}`
)
})
// logger.log('roofBase.id:', roofBase.id)
// logger.log('roofEaveHelpLines:', roofEaveHelpLines)
// logger.log('extensionLines found:', roofEaveHelpLines.filter(l => l.lineName === 'extensionLine'))
@ -760,20 +738,6 @@ export function useRoofAllocationSetting(id) {
});
// Combine remaining lines with newEaveLines
roofBase.lines = [...linesToKeep, ...normalEaveLines, ...extensionLines];
// [ALLOC-DEBUG] 병합 결과 breakdown
logger.log(
`[ALLOC-DEBUG] 병합완료 roofBase.id=${roofBase.id} ` +
`linesToKeep=${linesToKeep.length} ` +
`normalEave=${normalEaveLines.length} ` +
`extension=${extensionLines.length} ` +
`total=${roofBase.lines.length}`
)
roofBase.lines.forEach((ln, i) => {
logger.log(
` [ALLOC-DEBUG] merged[${i}] name=${ln.name || '?'} lineName=${ln.lineName || '?'} ` +
`(${ln.x1?.toFixed(1)},${ln.y1?.toFixed(1)})→(${ln.x2?.toFixed(1)},${ln.y2?.toFixed(1)})`
)
})
} else {
roofBase.lines = [...roofEaveHelpLines]
}
@ -813,15 +777,6 @@ export function useRoofAllocationSetting(id) {
// extensionLine + 동일직선 SK 1:1 통합 (대각선 단일길이/각도 면적 산출)
integrateExtensionLines(roofBase)
// [ALLOC-DEBUG] split 직전 최종 입력
logger.log(
`[ALLOC-DEBUG] split 직전 roofBase.id=${roofBase.id} ` +
`separatePolygon=${roofBase.separatePolygon?.length || 0} ` +
`lines=${roofBase.lines?.length || 0} ` +
`innerLines=${roofBase.innerLines?.length || 0} ` +
`points=${roofBase.points?.length || 0} ` +
`${roofBase.separatePolygon?.length > 0 ? 'splitPolygonWithSeparate' : 'splitPolygonWithLines'}`
)
if (roofBase.separatePolygon.length > 0) {
splitPolygonWithSeparate(roofBase.separatePolygon)
} else {

View File

@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil'
import { fabric } from 'fabric'
import { calculateIntersection, findAndRemoveClosestPoint, getDegreeByChon, isPointOnLine } from '@/util/canvas-util'
import { QPolygon } from '@/components/fabric/QPolygon'
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
import { calcLinePlaneSize, isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
import { basicSettingState, flowDisplaySelector } from '@/store/settingAtom'
import { fontSelector } from '@/store/fontAtom'
import { QLine } from '@/components/fabric/QLine'
@ -1028,7 +1028,10 @@ export const usePolygon = () => {
const { intersections, startPoint, endPoint } = line
// 원본 라인의 기하학적 길이 (비율 계산용)
const originalGeomLength = Math.round(Math.hypot(line.x2 - line.x1, line.y2 - line.y1)) * 10
// [ROUND-PRECISION 2026-05-14] Math.round(hypot)*10 → calcLinePlaneSize (Big.js, ×10 후 round).
// 기존: 45.6 → Math.round(45.6)*10 = 460. 伏せ図入力 의 Big.js 경로는 456.
// 배치면 split 결과와 伏せ図入力 SK 빌더의 0.5mm boundary 가 갈리는 근본 원인.
const originalGeomLength = calcLinePlaneSize({ x1: line.x1, y1: line.y1, x2: line.x2, y2: line.y2 })
if (intersections.length === 1) {
const newLinePoint1 = [line.x1, line.y1, intersections[0].x, intersections[0].y]
@ -1050,8 +1053,9 @@ export const usePolygon = () => {
})
// 분할된 각 세그먼트의 기하학적 길이
const length1 = Math.round(Math.hypot(newLine1.x1 - newLine1.x2, newLine1.y1 - newLine1.y2)) * 10
const length2 = Math.round(Math.hypot(newLine2.x1 - newLine2.x2, newLine2.y1 - newLine2.y2)) * 10
// [ROUND-PRECISION 2026-05-14] calcLinePlaneSize 사용 — 위 originalGeomLength 와 동일 이유.
const length1 = calcLinePlaneSize({ x1: newLine1.x1, y1: newLine1.y1, x2: newLine1.x2, y2: newLine1.y2 })
const length2 = calcLinePlaneSize({ x1: newLine2.x1, y1: newLine2.y1, x2: newLine2.x2, y2: newLine2.y2 })
// 분할 시 새 sub-segment 의 planeSize/actualSize 는 새 기하학으로 직접 계산.
// 부모 비율을 쓰면 부모 좌표 drift 가 그대로 전파되어 사용자 기대 round 값과 어긋남.
@ -1131,7 +1135,8 @@ export const usePolygon = () => {
name: 'newLine',
})
const calcLength = Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10
// [ROUND-PRECISION 2026-05-14] calcLinePlaneSize 사용 — Big.js ×10 후 round.
const calcLength = calcLinePlaneSize({ x1: newLine.x1, y1: newLine.y1, x2: newLine.x2, y2: newLine.y2 })
let segPlaneSize, segActualSize
if (line.attributes.planeSize && originalGeomLength > 0) {
@ -1164,7 +1169,8 @@ export const usePolygon = () => {
attributes: line.attributes,
name: 'newLine',
})
const lastCalcLength = Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10
// [ROUND-PRECISION 2026-05-14] calcLinePlaneSize 사용 — Big.js ×10 후 round.
const lastCalcLength = calcLinePlaneSize({ x1: newLine.x1, y1: newLine.y1, x2: newLine.x2, y2: newLine.y2 })
let lastPlaneSize, lastActualSize
if (line.attributes.planeSize && originalGeomLength > 0) {