Compare commits

..

No commits in common. "d30d92df0b80f0376895730d0a70a17ffc007767" and "abc61b2a0cba8fe7aadecb4bbadd2f3abe14c23b" have entirely different histories.

5 changed files with 147 additions and 155 deletions

View File

@ -84,12 +84,12 @@ export default function AuxiliarySize(props) {
//1 2 , 2 1 .
if (checkedRadio === 1) {
const newX2 = Big(x1).plus(dx.times(scaleFactor)).toNumber()
const newY2 = Big(y1).plus(dy.times(scaleFactor)).toNumber()
const newX2 = Big(x1).plus(dx.times(scaleFactor))
const newY2 = Big(y1).plus(dy.times(scaleFactor))
currentObject.set({ x2: newX2, y2: newY2 })
} else if (checkedRadio === 2) {
const newX1 = Big(x2).minus(dx.times(scaleFactor)).toNumber()
const newY1 = Big(y2).minus(dy.times(scaleFactor)).toNumber()
const newX1 = Big(x2).minus(dx.times(scaleFactor))
const newY1 = Big(y2).minus(dy.times(scaleFactor))
currentObject.set({ x1: newX1, y1: newY1 })
}
//planeSize actualSize .

View File

@ -1,5 +1,4 @@
import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common'
import { QPolygon } from '@/components/fabric/QPolygon'
import { canvasState } from '@/store/canvasAtom'
import { polygonToTurfPolygon } from '@/util/canvas-util'
import { useRecoilValue } from 'recoil'
@ -45,42 +44,6 @@ export function useModule() {
const { clear: removeTrestleMaterials } = useTrestle()
const { checkModuleDisjointSurface } = useTurf()
// clone() 대신 직접 새 QPolygon을 생성하여 Maximum call stack 방지
const createModuleCopy = (module, newLeft, newTop, overrides = {}) => {
const deltaX = newLeft - module.left
const deltaY = newTop - module.top
const newPoints = module.points.map((p) => ({
x: p.x + deltaX,
y: p.y + deltaY,
}))
return new QPolygon(newPoints, {
fill: module.fill,
stroke: module.stroke,
strokeWidth: module.strokeWidth,
opacity: module.opacity,
selectable: module.selectable,
lockMovementX: module.lockMovementX,
lockMovementY: module.lockMovementY,
lockRotation: module.lockRotation,
lockScalingX: module.lockScalingX,
lockScalingY: module.lockScalingY,
parentId: module.parentId,
initOptions: module.initOptions,
direction: module.direction,
arrow: module.arrow,
name: module.name,
surfaceId: module.surfaceId,
moduleInfo: module.moduleInfo,
left: newLeft,
top: newTop,
width: module.width,
height: module.height,
toFixed: 2,
sort: false,
...overrides,
})
}
const moduleMove = (length, direction) => {
const selectedObj = canvas.getActiveObjects() //선택된 객체들을 가져옴
const selectedIds = selectedObj.map((obj) => obj.id) // selectedObj의 ID 추출
@ -293,10 +256,27 @@ export function useModule() {
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength) * 10, false)
copyModule = createModuleCopy(module, left, top)
canvas.add(copyModule)
copyModules.push(copyModule)
copyModule.setCoords()
module.clone((obj) => {
obj.set({
parentId: module.parentId,
initOptions: module.initOptions,
direction: module.direction,
arrow: module.arrow,
name: module.name,
type: module.type,
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
moduleInfo: module.moduleInfo,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
})
if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, surface)) {
isWarning = true
copyModule.set({ fill: 'red' })
@ -338,10 +318,27 @@ export function useModule() {
canvas.discardActiveObject() //선택해제
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, true)
copyModule = createModuleCopy(module, left, top)
copyModules.push(copyModule)
canvas.add(copyModule)
canvas.renderAll()
module.clone((obj) => {
obj.set({
parentId: module.parentId,
initOptions: module.initOptions,
direction: module.direction,
arrow: module.arrow,
name: module.name,
type: module.type,
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
moduleInfo: module.moduleInfo,
left,
top,
id: uuidv4(),
})
copyModules.push(obj)
copyModule = obj
canvas.add(obj)
canvas.renderAll()
})
if (
isOverlapOtherModules(copyModule, otherModules) ||
@ -415,10 +412,29 @@ export function useModule() {
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, Number(length), true)
copyModule = createModuleCopy(module, left, top, { stroke: 'black' })
canvas.add(copyModule)
copyModules.push(copyModule)
copyModule.setCoords()
module.clone((obj) => {
obj.set({
parentId: module.parentId,
initOptions: module.initOptions,
stroke: 'black',
direction: module.direction,
arrow: module.arrow,
name: module.name,
type: module.type,
length: module.length,
points: module.points,
moduleInfo: module.moduleInfo,
surfaceId: module.surfaceId,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
console.log(obj)
})
if (
isOverlapOtherModules(copyModule, otherModules) ||
isOverlapObjects(copyModule, objects) ||
@ -754,10 +770,28 @@ export function useModule() {
otherModules = getOtherModules(columnModules)
columnModules.forEach((module) => {
const { top, left } = getPosotion(module, type, moduleIntvlHor, true)
const copyModule = createModuleCopy(module, left, top)
canvas.add(copyModule)
copyModules.push(copyModule)
copyModule.setCoords()
let copyModule = null
module.clone((obj) => {
obj.set({
parentId: module.parentId,
initOptions: module.initOptions,
direction: module.direction,
arrow: module.arrow,
name: module.name,
type: module.type,
length: module.length,
points: module.points,
moduleInfo: module.moduleInfo,
surfaceId: module.surfaceId,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
})
canvas.renderAll()
if (
@ -845,10 +879,29 @@ export function useModule() {
otherModules = getOtherModules(rowModules)
rowModules.forEach((module) => {
const { top, left } = getPosotion(module, type, moduleIntvlVer, true)
const copyModule = createModuleCopy(module, left, top)
canvas.add(copyModule)
copyModules.push(copyModule)
copyModule.setCoords()
let copyModule = null
module.clone((obj) => {
obj.set({
parentId: module.parentId,
initOptions: module.initOptions,
direction: module.direction,
arrow: module.arrow,
name: module.name,
type: module.type,
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
moduleInfo: module.moduleInfo,
fill: module.fill,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
})
canvas.renderAll()
if (

View File

@ -184,14 +184,14 @@ export function useModuleBasicSetting(tabNum) {
// 방향에 따른 좌표 설정
const directionConfig = {
south: { coord1: 'y1', coord2: 'y2', findExtreme: Math.max, offsetX: 0, offsetY: 1 },
north: { coord1: 'y1', coord2: 'y2', findExtreme: Math.min, offsetX: 0, offsetY: -1 },
east: { coord1: 'x1', coord2: 'x2', findExtreme: Math.max, offsetX: 1, offsetY: 0 },
west: { coord1: 'x1', coord2: 'x2', findExtreme: Math.min, offsetX: -1, offsetY: 0 },
south: { coord1: 'y1', coord2: 'y2', findExtreme: Math.max },
north: { coord1: 'y1', coord2: 'y2', findExtreme: Math.min },
east: { coord1: 'x1', coord2: 'x2', findExtreme: Math.max },
west: { coord1: 'x1', coord2: 'x2', findExtreme: Math.min },
}
const config = directionConfig[direction] || directionConfig.south
const { coord1, coord2, offsetX, offsetY } = config
const { coord1, coord2, findExtreme } = config
// 2. 직선만 필터링 (대각선 제외)
// 남/북: y1 === y2 인 경우 수평 직선
@ -200,29 +200,22 @@ export function useModuleBasicSetting(tabNum) {
if (straightLines.length === 0) return
// 3. 폴리곤의 turf polygon 생성 (처마 방향 판별용)
const points = polygon.getCurrentPoints()
const turfCoords = points.map((p) => [p.x, p.y])
turfCoords.push(turfCoords[0]) // 폴리곤 닫기
const turfPolygon = turf.polygon([turfCoords])
// 3. 가장 끝에 있는 직선 찾기
// 남쪽: 가장 하단 (y값이 가장 큰), 북쪽: 가장 상단 (y값이 가장 작은)
// 동쪽: 가장 오른쪽 (x값이 가장 큰), 서쪽: 가장 왼쪽 (x값이 가장 작은)
const extremeValue = findExtreme(...straightLines.map((line) => line[coord1]))
const eavesLines = straightLines.filter((line) => line[coord1] === extremeValue)
// 4. 각 직선에 대해 처마/용마루 판별
// 라인 중점에서 처마 방향으로 약간 이동한 점이 폴리곤 외부이면 처마(eaves)
// 폴리곤 내부이면 용마루(ridge)
// 4. 직선에 대해 타입 설정
straightLines.forEach((line) => {
const midX = (line.x1 + line.x2) / 2
const midY = (line.y1 + line.y2) / 2
// 처마 방향으로 약간 이동한 테스트 포인트
const testPoint = turf.point([midX + offsetX * 0.5, midY + offsetY * 0.5])
if (!turf.booleanPointInPolygon(testPoint, turfPolygon)) {
// 테스트 포인트가 폴리곤 외부 → 처마 방향을 향함
if (eavesLines.includes(line)) {
// 가장 끝에 있는 직선은 eaves
line.attributes = {
...line.attributes,
type: LINE_TYPE.WALLLINE.EAVES,
}
} else {
// 테스트 포인트가 폴리곤 내부 → 용마루 방향을 향함
// 나머지 직선은 ridge
line.attributes = {
...line.attributes,
type: LINE_TYPE.SUBLINE.RIDGE,

View File

@ -208,13 +208,6 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
isXInversion: xInversion,
isYInversion: yInversion,
})
// 최초 생성 시 planeSize를 계산된 길이로 저장 (회전 후 좌표 반올림에 의한 오차 방지)
batchSurface.lines.forEach((line) => {
if (!line.attributes.planeSize || line.attributes.planeSize === 0) {
line.attributes.planeSize = line.getLength()
}
})
canvas.setActiveObject(batchSurface)
setSurfaceShapePattern(batchSurface, roofDisplay.column)
drawDirectionArrow(batchSurface)
@ -382,9 +375,9 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
}
points = [
{ x: pointer.x, y: pointer.y - newLength2 / 2 },
{ x: pointer.x - length1 / 2, y: pointer.y + newLength2 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y + newLength2 / 2 },
{ x: pointer.x, y: pointer.y - parseInt(newLength2) / 2 },
{ x: pointer.x - parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 },
{ x: pointer.x + parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 },
]
break

View File

@ -1023,9 +1023,6 @@ export const usePolygon = () => {
const line = divideLines[i]
const { intersections, startPoint, endPoint } = line
// 원본 라인의 기하학적 길이 (비율 계산용)
const originalGeomLength = Math.round(Math.hypot(line.x2 - line.x1, line.y2 - line.y1)) * 10
if (intersections.length === 1) {
const newLinePoint1 = [line.x1, line.y1, intersections[0].x, intersections[0].y]
const newLinePoint2 = [intersections[0].x, intersections[0].y, line.x2, line.y2]
@ -1045,43 +1042,25 @@ export const usePolygon = () => {
name: 'newLine',
})
// 분할된 각 세그먼트의 기하학적 길이
// 두 라인 중 큰 길이로 통일
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
// 원본에 planeSize/actualSize가 있으면 비율로 분배, 없으면 기하학적 길이 사용
let planeSize1, planeSize2, actualSize1, actualSize2
if (line.attributes.planeSize && originalGeomLength > 0) {
const ratio1 = length1 / originalGeomLength
const ratio2 = length2 / originalGeomLength
planeSize1 = Math.round(line.attributes.planeSize * ratio1)
planeSize2 = Math.round(line.attributes.planeSize * ratio2)
} else {
planeSize1 = length1
planeSize2 = length2
}
if (line.attributes.actualSize && originalGeomLength > 0) {
const ratio1 = length1 / originalGeomLength
const ratio2 = length2 / originalGeomLength
actualSize1 = Math.round(line.attributes.actualSize * ratio1)
actualSize2 = Math.round(line.attributes.actualSize * ratio2)
} else {
actualSize1 = length1
actualSize2 = length2
}
const maxLength = Math.max(length1, length2)
const unifiedPlaneSize = line.attributes.planeSize ?? maxLength
const unifiedActualSize = line.attributes.actualSize ?? maxLength
newLine1.attributes = {
...line.attributes,
planeSize: planeSize1,
actualSize: actualSize1,
planeSize: unifiedPlaneSize,
actualSize: unifiedActualSize,
}
newLine1.length = length1
newLine1.length = maxLength
newLine2.attributes = {
...line.attributes,
planeSize: planeSize2,
actualSize: actualSize2,
planeSize: unifiedPlaneSize,
actualSize: unifiedActualSize,
}
newLine2.length = length2
newLine2.length = maxLength
newLines.push(newLine1, newLine2)
divideLines.splice(i, 1) // 기존 line 제거
@ -1101,25 +1080,12 @@ export const usePolygon = () => {
})
const calcLength = Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10
let segPlaneSize, segActualSize
if (line.attributes.planeSize && originalGeomLength > 0) {
segPlaneSize = Math.round(line.attributes.planeSize * (calcLength / originalGeomLength))
} else {
segPlaneSize = calcLength
}
if (line.attributes.actualSize && originalGeomLength > 0) {
segActualSize = Math.round(line.attributes.actualSize * (calcLength / originalGeomLength))
} else {
segActualSize = calcLength
}
newLine.attributes = {
...line.attributes,
planeSize: segPlaneSize,
actualSize: segActualSize,
planeSize: line.attributes.planeSize ?? calcLength,
actualSize: line.attributes.actualSize ?? calcLength,
}
newLine.length = calcLength
newLine.length = line.attributes.planeSize ?? calcLength
newLines.push(newLine)
currentPoint = minDistancePoint
@ -1134,25 +1100,12 @@ export const usePolygon = () => {
name: 'newLine',
})
const lastCalcLength = Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10
let lastPlaneSize, lastActualSize
if (line.attributes.planeSize && originalGeomLength > 0) {
lastPlaneSize = Math.round(line.attributes.planeSize * (lastCalcLength / originalGeomLength))
} else {
lastPlaneSize = lastCalcLength
}
if (line.attributes.actualSize && originalGeomLength > 0) {
lastActualSize = Math.round(line.attributes.actualSize * (lastCalcLength / originalGeomLength))
} else {
lastActualSize = lastCalcLength
}
newLine.attributes = {
...line.attributes,
planeSize: lastPlaneSize,
actualSize: lastActualSize,
planeSize: line.attributes.planeSize ?? lastCalcLength,
actualSize: line.attributes.actualSize ?? lastCalcLength,
}
newLine.length = lastCalcLength
newLine.length = line.attributes.planeSize ?? lastCalcLength
newLines.push(newLine)
divideLines.splice(i, 1) // 기존 line 제거