1525 면형상배치 치수 표기 이상 #716

Merged
ysCha merged 1 commits from dev into prd-deploy 2026-03-18 13:24:14 +09:00

View File

@ -9,14 +9,14 @@ import {
globalPitchState,
} from '@/store/canvasAtom'
import { LINE_TYPE, MENU, POLYGON_TYPE } from '@/common/common'
import { getIntersectionPoint } from '@/util/canvas-util'
import { getIntersectionPoint, getDegreeByChon } from '@/util/canvas-util'
import { degreesToRadians } from '@turf/turf'
import { QPolygon } from '@/components/fabric/QPolygon'
import { useSwal } from '@/hooks/useSwal'
import { useMessage } from '@/hooks/useMessage'
import { useEvent } from '@/hooks/useEvent'
import { usePopup } from '@/hooks/usePopup'
import { roofDisplaySelector } from '@/store/settingAtom'
import { roofDisplaySelector, basicSettingState } from '@/store/settingAtom'
import { usePolygon } from '@/hooks/usePolygon'
import { fontSelector } from '@/store/fontAtom'
import { slopeSelector } from '@/store/commonAtom'
@ -30,10 +30,12 @@ import { useText } from '@/hooks/useText'
import SizeSetting from '@/components/floor-plan/modal/object/SizeSetting'
import { v4 as uuidv4 } from 'uuid'
import { useState } from 'react'
import { fabric } from 'fabric'
export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage()
const { drawDirectionArrow, addPolygon, addLengthText, setPolygonLinesActualSize } = usePolygon()
const roofSizeSet = useRecoilValue(basicSettingState).roofSizeSet
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const resetOuterLinePoints = useResetRecoilState(outerLinePointsState)
const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState)
@ -92,9 +94,76 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
let obj = null
let points = []
// azimuth로부터 direction 결정
let direction = 'south'
if (azimuth === 'left') direction = 'west'
else if (azimuth === 'right') direction = 'east'
else if (azimuth === 'up') direction = 'north'
// after:render 콜백 - 매 렌더링 후 temp 수치 텍스트를 ctx에 직접 그림
let tempLengthData = null // { transformedPoints, direction }
const afterRenderHandler = () => {
if (!tempLengthData) return
const ctx = canvas?.getContext('2d')
if (!ctx) return
const { tPoints, dir } = tempLengthData
const vpt = canvas.viewportTransform
const zoom = vpt[0]
const oX = vpt[4]
const oY = vpt[5]
ctx.save()
ctx.font = `bold ${(lengthTextFont.fontSize.value || 14) * zoom}px sans-serif`
ctx.fillStyle = 'black'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
tPoints.forEach((start, i) => {
const end = tPoints[(i + 1) % tPoints.length]
const dx = end.x - start.x
const dy = end.y - start.y
const planeSize = Math.round(Math.sqrt(dx * dx + dy * dy) * 10)
let actualSize = planeSize
const lineDir = Math.abs(dx) > Math.abs(dy) ? (dx > 0 ? 'right' : 'left') : (dy > 0 ? 'bottom' : 'top')
if (+roofSizeSet === 1 && globalPitch > 0) {
const pitchDeg = getDegreeByChon(globalPitch)
const isV = Math.abs(start.x - end.x) < 1
const isH = Math.abs(start.y - end.y) < 1
const isD = !isH && !isV
if (dir === 'south' || dir === 'north') {
if (isV) actualSize = Math.round(planeSize / Math.cos(pitchDeg * Math.PI / 180))
else if (isD) {
const h = Math.abs(dy) * 10 * Math.tan(pitchDeg * Math.PI / 180)
actualSize = Math.round(Math.sqrt(h * h + planeSize * planeSize))
}
} else if (dir === 'west' || dir === 'east') {
if (isH) actualSize = Math.round(planeSize / Math.cos(pitchDeg * Math.PI / 180))
else if (isD) {
const h = Math.abs(dx) * 10 * Math.tan(pitchDeg * Math.PI / 180)
actualSize = Math.round(Math.sqrt(h * h + planeSize * planeSize))
}
}
}
const displayValue = (+roofSizeSet === 1 ? actualSize : planeSize).toString()
let tx = (start.x + end.x) / 2
let ty = (start.y + end.y) / 2
if (lineDir === 'right') ty += 15
else if (lineDir === 'left') ty -= 15
else if (lineDir === 'top') tx += 15
else tx -= 25
ctx.fillText(displayValue, tx * zoom + oX, ty * zoom + oY)
})
ctx.restore()
}
//일단 팝업을 가린다
if (checkSurfaceShape(surfaceId, { length1, length2, length3, length4, length5 })) {
canvas?.on('after:render', afterRenderHandler)
addCanvasMouseEventListener('mouse:move', (e) => {
if (!isDrawing) {
return
@ -125,7 +194,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
pitch: globalPitch,
}
obj = new QPolygon(points, options)
obj = new fabric.Polygon(points, options)
let imageRotate = 0
if (xInversion && !yInversion) {
@ -159,12 +228,25 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
obj.setCoords() //좌표 변경 적용
canvas?.add(obj)
// 회전/반전이 적용된 실제 좌표를 계산하여 after:render에서 그릴 데이터 설정
const matrix = obj.calcTransformMatrix()
const tPoints = obj.get('points').map((p) => {
const pt = new fabric.Point(p.x - obj.pathOffset.x, p.y - obj.pathOffset.y)
return fabric.util.transformPoint(pt, matrix)
})
tempLengthData = { tPoints, dir: direction }
canvas?.renderAll()
})
addCanvasMouseEventListener('mouse:down', (e) => {
isDrawing = false
// after:render 핸들러 해제 및 temp 수치 데이터 초기화
tempLengthData = null
canvas?.off('after:render', afterRenderHandler)
const { xInversion, yInversion } = surfaceRefs
canvas?.remove(obj)
@ -186,8 +268,12 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
}
//회전, flip등이 먹은 기준으로 새로생성
// const batchSurface = addPolygon(reorderedPoints, {
const batchSurface = addPolygon(obj.getCurrentPoints(), {
const objMatrix = obj.calcTransformMatrix()
const finalPoints = obj.get('points').map((p) => {
const pt = new fabric.Point(p.x - obj.pathOffset.x, p.y - obj.pathOffset.y)
return fabric.util.transformPoint(pt, objMatrix)
})
const batchSurface = addPolygon(finalPoints, {
fill: 'transparent',
stroke: 'red',
strokeWidth: 3,