Merge pull request 'dev' (#692) from dev into dev-deploy
Reviewed-on: #692
This commit is contained in:
commit
7994f0ef16
@ -84,12 +84,12 @@ export default function AuxiliarySize(props) {
|
||||
|
||||
//1지점 선택일때는 2지점의 좌표, 2지점 선택일때는 1지점의 좌표를 조정한다.
|
||||
if (checkedRadio === 1) {
|
||||
const newX2 = Big(x1).plus(dx.times(scaleFactor))
|
||||
const newY2 = Big(y1).plus(dy.times(scaleFactor))
|
||||
const newX2 = Big(x1).plus(dx.times(scaleFactor)).toNumber()
|
||||
const newY2 = Big(y1).plus(dy.times(scaleFactor)).toNumber()
|
||||
currentObject.set({ x2: newX2, y2: newY2 })
|
||||
} else if (checkedRadio === 2) {
|
||||
const newX1 = Big(x2).minus(dx.times(scaleFactor))
|
||||
const newY1 = Big(y2).minus(dy.times(scaleFactor))
|
||||
const newX1 = Big(x2).minus(dx.times(scaleFactor)).toNumber()
|
||||
const newY1 = Big(y2).minus(dy.times(scaleFactor)).toNumber()
|
||||
currentObject.set({ x1: newX1, y1: newY1 })
|
||||
}
|
||||
//planeSize와 actualSize를 재계산한다.
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
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'
|
||||
@ -44,6 +45,42 @@ 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 추출
|
||||
@ -256,27 +293,10 @@ export function useModule() {
|
||||
|
||||
modules.forEach((module) => {
|
||||
const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength) * 10, false)
|
||||
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()
|
||||
})
|
||||
copyModule = createModuleCopy(module, left, top)
|
||||
canvas.add(copyModule)
|
||||
copyModules.push(copyModule)
|
||||
copyModule.setCoords()
|
||||
if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, surface)) {
|
||||
isWarning = true
|
||||
copyModule.set({ fill: 'red' })
|
||||
@ -318,27 +338,10 @@ export function useModule() {
|
||||
canvas.discardActiveObject() //선택해제
|
||||
modules.forEach((module) => {
|
||||
const { top, left } = getPosotion(module, direction, length, true)
|
||||
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()
|
||||
})
|
||||
copyModule = createModuleCopy(module, left, top)
|
||||
copyModules.push(copyModule)
|
||||
canvas.add(copyModule)
|
||||
canvas.renderAll()
|
||||
|
||||
if (
|
||||
isOverlapOtherModules(copyModule, otherModules) ||
|
||||
@ -412,29 +415,10 @@ export function useModule() {
|
||||
|
||||
modules.forEach((module) => {
|
||||
const { top, left } = getPosotion(module, direction, Number(length), true)
|
||||
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)
|
||||
})
|
||||
copyModule = createModuleCopy(module, left, top, { stroke: 'black' })
|
||||
canvas.add(copyModule)
|
||||
copyModules.push(copyModule)
|
||||
copyModule.setCoords()
|
||||
if (
|
||||
isOverlapOtherModules(copyModule, otherModules) ||
|
||||
isOverlapObjects(copyModule, objects) ||
|
||||
@ -770,28 +754,10 @@ export function useModule() {
|
||||
otherModules = getOtherModules(columnModules)
|
||||
columnModules.forEach((module) => {
|
||||
const { top, left } = getPosotion(module, type, moduleIntvlHor, true)
|
||||
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()
|
||||
})
|
||||
const copyModule = createModuleCopy(module, left, top)
|
||||
canvas.add(copyModule)
|
||||
copyModules.push(copyModule)
|
||||
copyModule.setCoords()
|
||||
canvas.renderAll()
|
||||
|
||||
if (
|
||||
@ -879,29 +845,10 @@ export function useModule() {
|
||||
otherModules = getOtherModules(rowModules)
|
||||
rowModules.forEach((module) => {
|
||||
const { top, left } = getPosotion(module, type, moduleIntvlVer, true)
|
||||
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()
|
||||
})
|
||||
const copyModule = createModuleCopy(module, left, top)
|
||||
canvas.add(copyModule)
|
||||
copyModules.push(copyModule)
|
||||
copyModule.setCoords()
|
||||
canvas.renderAll()
|
||||
|
||||
if (
|
||||
|
||||
@ -184,14 +184,14 @@ export function useModuleBasicSetting(tabNum) {
|
||||
|
||||
// 방향에 따른 좌표 설정
|
||||
const directionConfig = {
|
||||
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 },
|
||||
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 },
|
||||
}
|
||||
|
||||
const config = directionConfig[direction] || directionConfig.south
|
||||
const { coord1, coord2, findExtreme } = config
|
||||
const { coord1, coord2, offsetX, offsetY } = config
|
||||
|
||||
// 2. 직선만 필터링 (대각선 제외)
|
||||
// 남/북: y1 === y2 인 경우 수평 직선
|
||||
@ -200,22 +200,29 @@ export function useModuleBasicSetting(tabNum) {
|
||||
|
||||
if (straightLines.length === 0) return
|
||||
|
||||
// 3. 가장 끝에 있는 직선 찾기
|
||||
// 남쪽: 가장 하단 (y값이 가장 큰), 북쪽: 가장 상단 (y값이 가장 작은)
|
||||
// 동쪽: 가장 오른쪽 (x값이 가장 큰), 서쪽: 가장 왼쪽 (x값이 가장 작은)
|
||||
const extremeValue = findExtreme(...straightLines.map((line) => line[coord1]))
|
||||
const eavesLines = straightLines.filter((line) => line[coord1] === extremeValue)
|
||||
// 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])
|
||||
|
||||
// 4. 직선에 대해 타입 설정
|
||||
// 4. 각 직선에 대해 처마/용마루 판별
|
||||
// 라인 중점에서 처마 방향으로 약간 이동한 점이 폴리곤 외부이면 처마(eaves)
|
||||
// 폴리곤 내부이면 용마루(ridge)
|
||||
straightLines.forEach((line) => {
|
||||
if (eavesLines.includes(line)) {
|
||||
// 가장 끝에 있는 직선은 eaves
|
||||
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)) {
|
||||
// 테스트 포인트가 폴리곤 외부 → 처마 방향을 향함
|
||||
line.attributes = {
|
||||
...line.attributes,
|
||||
type: LINE_TYPE.WALLLINE.EAVES,
|
||||
}
|
||||
} else {
|
||||
// 나머지 직선은 ridge
|
||||
// 테스트 포인트가 폴리곤 내부 → 용마루 방향을 향함
|
||||
line.attributes = {
|
||||
...line.attributes,
|
||||
type: LINE_TYPE.SUBLINE.RIDGE,
|
||||
|
||||
@ -208,6 +208,13 @@ 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)
|
||||
@ -375,9 +382,9 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
||||
}
|
||||
|
||||
points = [
|
||||
{ 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 },
|
||||
{ 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 },
|
||||
]
|
||||
|
||||
break
|
||||
|
||||
@ -1023,6 +1023,9 @@ 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]
|
||||
@ -1042,25 +1045,43 @@ 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
|
||||
const maxLength = Math.max(length1, length2)
|
||||
const unifiedPlaneSize = line.attributes.planeSize ?? maxLength
|
||||
const unifiedActualSize = line.attributes.actualSize ?? maxLength
|
||||
|
||||
// 원본에 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
|
||||
}
|
||||
|
||||
newLine1.attributes = {
|
||||
...line.attributes,
|
||||
planeSize: unifiedPlaneSize,
|
||||
actualSize: unifiedActualSize,
|
||||
planeSize: planeSize1,
|
||||
actualSize: actualSize1,
|
||||
}
|
||||
newLine1.length = maxLength
|
||||
newLine1.length = length1
|
||||
newLine2.attributes = {
|
||||
...line.attributes,
|
||||
planeSize: unifiedPlaneSize,
|
||||
actualSize: unifiedActualSize,
|
||||
planeSize: planeSize2,
|
||||
actualSize: actualSize2,
|
||||
}
|
||||
newLine2.length = maxLength
|
||||
newLine2.length = length2
|
||||
|
||||
newLines.push(newLine1, newLine2)
|
||||
divideLines.splice(i, 1) // 기존 line 제거
|
||||
@ -1080,12 +1101,25 @@ 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: line.attributes.planeSize ?? calcLength,
|
||||
actualSize: line.attributes.actualSize ?? calcLength,
|
||||
planeSize: segPlaneSize,
|
||||
actualSize: segActualSize,
|
||||
}
|
||||
newLine.length = line.attributes.planeSize ?? calcLength
|
||||
newLine.length = calcLength
|
||||
|
||||
newLines.push(newLine)
|
||||
currentPoint = minDistancePoint
|
||||
@ -1100,12 +1134,25 @@ 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: line.attributes.planeSize ?? lastCalcLength,
|
||||
actualSize: line.attributes.actualSize ?? lastCalcLength,
|
||||
planeSize: lastPlaneSize,
|
||||
actualSize: lastActualSize,
|
||||
}
|
||||
newLine.length = line.attributes.planeSize ?? lastCalcLength
|
||||
newLine.length = lastCalcLength
|
||||
|
||||
newLines.push(newLine)
|
||||
divideLines.splice(i, 1) // 기존 line 제거
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user