도머 카피 로직 변경

This commit is contained in:
yjnoh 2025-03-05 12:46:09 +09:00
parent 304d0840e3
commit 4ca23c1827
7 changed files with 217 additions and 84 deletions

View File

@ -198,6 +198,10 @@ export const SAVE_KEY = [
'isChidory',
'textVisible',
'groupPoints',
'fontSize',
'fontStyle',
'fontWeight',
'dormerAttributes',
]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]

View File

@ -24,7 +24,6 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
const { closePopup } = usePopup()
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
//
useEffect(() => {
canvas.discardActiveObject()
@ -54,15 +53,41 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
const applyObject = () => {
if (surfaceShapePolygons.length === 0) {
swalFire({ text: '지붕이 없어요 지붕부터 그리세요', icon: 'error' })
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
return
}
//,
if (buttonAct === 1 || buttonAct === 2) {
applyOpeningAndShadow(objectPlacement, buttonAct, surfaceShapePolygons)
applyOpeningAndShadow(objectPlacement, buttonAct)
} else {
applyDormers(dormerPlacement, buttonAct, surfaceShapePolygons)
const height = dormerPlacement.heightRef.current !== null ? dormerPlacement.heightRef.current.value / 10 : 0
const width = dormerPlacement.widthRef.current !== null ? dormerPlacement.widthRef.current.value / 10 : 0 //triangle
const pitch = dormerPlacement.pitchRef.current !== null ? Number(dormerPlacement.pitchRef.current.value) : 0
const offsetRef =
dormerPlacement.offsetRef.current !== null
? dormerPlacement.offsetRef.current.value === ''
? 0
: parseInt(dormerPlacement.offsetRef.current.value) / 10
: 0
const offsetWidthRef =
dormerPlacement.offsetWidthRef.current !== null
? dormerPlacement.offsetWidthRef.current.value === ''
? 0
: parseInt(dormerPlacement.offsetWidthRef.current.value) / 10
: 0
const directionRef = dormerPlacement.directionRef.current
const dormerParams = {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
}
applyDormers(dormerParams, buttonAct)
}
setIsHidden(true)
}

View File

@ -23,7 +23,7 @@ export function useCanvasConfigInitialize() {
const {} = useFont()
const {} = useGrid()
const {} = useRoof()
const { drawDirectionArrow } = usePolygon()
const { drawDirectionArrow, addLengthText } = usePolygon()
useEffect(() => {
if (!canvas) return
@ -160,11 +160,15 @@ export function useCanvasConfigInitialize() {
const objectsParentId = canvas.getObjects().filter((obj) => obj.groupId === id || obj.id === id)[0].parentId
let objectArray = []
let groupPoints = []
//그룹객체가 있으면 배열에 추가함
if (groupObjects) {
groupObjects.forEach((obj) => {
objectArray.push(obj)
if (obj.groupPoints) {
groupPoints = obj.groupPoints
}
})
}
@ -187,9 +191,21 @@ export function useCanvasConfigInitialize() {
})
canvas.add(group)
//도머등 그룹에 포인트가 있는애들한테 다시 넣어준다
if (groupPoints.length > 0) {
group.set({
groupPoints: groupPoints,
})
}
//그룹 객체 재그룹 완료
group.getObjects().forEach((obj) => {
obj.fire('modified')
if (obj.texts) {
obj.texts.forEach((text) => {
text.bringToFront()
})
}
})
})
}

View File

@ -10,6 +10,7 @@ import { v4 as uuidv4 } from 'uuid'
import { usePopup } from '@/hooks/usePopup'
import Distance from '@/components/floor-plan/modal/distance/Distance'
import { usePolygon } from '@/hooks/usePolygon'
import { useObjectBatch } from '@/hooks/object/useObjectBatch'
export function useCommonUtils() {
const canvas = useRecoilValue(canvasState)
@ -21,6 +22,7 @@ export function useCommonUtils() {
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
const { addPopup } = usePopup()
const { drawDirectionArrow, addLengthText } = usePolygon()
const { applyDormers } = useObjectBatch({})
useEffect(() => {
if (commonUtils.text) {
@ -557,58 +559,76 @@ export function useCommonUtils() {
const commonCopyObject = (obj) => {
if (obj) {
let clonedObj = null
if (obj.name.indexOf('triangleDormer') || obj.name.indexOf('pentagonDormer')) {
const dormerAttributes = obj._objects[0].dormerAttributes
const dormerName = obj._objects[0].name
obj.clone((cloned) => {
clonedObj = cloned
})
addCanvasMouseEventListener('mouse:move', (e) => {
const pointer = canvas?.getPointer(e.e)
if (!clonedObj) return
canvas
.getObjects()
.filter((obj) => obj.name === 'clonedObj')
.forEach((obj) => canvas?.remove(obj))
clonedObj.set({
left: pointer.x,
top: pointer.y,
name: 'clonedObj',
})
canvas.add(clonedObj)
})
addCanvasMouseEventListener('mouse:down', (e) => {
clonedObj.set({
lockMovementX: true,
lockMovementY: true,
name: obj.name,
editable: false,
id: uuidv4(), //복사된 객체라 새로 따준다
})
//객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다
if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() })
//배치면일 경우
if (obj.name === 'roof') {
clonedObj.setCoords()
clonedObj.fire('polygonMoved')
clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial })
obj.lines.forEach((line, index) => {
clonedObj.lines[index].set({ attributes: line.attributes })
})
canvas.renderAll()
addLengthText(clonedObj) //수치 추가
drawDirectionArrow(clonedObj) //방향 화살표 추가
const dormerParams = {
height: dormerAttributes.height,
width: dormerAttributes.width,
pitch: dormerAttributes.pitch,
offsetRef: dormerAttributes.offsetRef,
offsetWidthRef: dormerAttributes.offsetWidthRef,
directionRef: dormerAttributes.directionRef,
}
initEvent()
})
const buttonAct = dormerName == 'triangleDormer' ? 3 : 4
applyDormers(dormerParams, buttonAct)
} else {
let clonedObj = null
obj.clone((cloned) => {
clonedObj = cloned
})
addCanvasMouseEventListener('mouse:move', (e) => {
const pointer = canvas?.getPointer(e.e)
if (!clonedObj) return
canvas
.getObjects()
.filter((obj) => obj.name === 'clonedObj')
.forEach((obj) => canvas?.remove(obj))
clonedObj.set({
left: pointer.x,
top: pointer.y,
name: 'clonedObj',
})
canvas.add(clonedObj)
})
addCanvasMouseEventListener('mouse:down', (e) => {
clonedObj.set({
lockMovementX: true,
lockMovementY: true,
name: obj.name,
editable: false,
id: uuidv4(), //복사된 객체라 새로 따준다
})
//객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다
if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() })
//배치면일 경우
if (obj.name === 'roof') {
clonedObj.setCoords()
clonedObj.fire('polygonMoved')
clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial })
obj.lines.forEach((line, index) => {
clonedObj.lines[index].set({ attributes: line.attributes })
})
canvas.renderAll()
addLengthText(clonedObj) //수치 추가
drawDirectionArrow(clonedObj) //방향 화살표 추가
}
initEvent()
})
}
}
}

View File

@ -391,11 +391,11 @@ export function useModuleBasicSetting(tabNum) {
//모듈,회로에서 다른메뉴 -> 배치면으로 갈 경수 초기화
const restoreModuleInstArea = () => {
//설치면 삭제
const setupArea = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
const setupArea = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE || obj.name === POLYGON_TYPE.OBJECT_SURFACE)
//모듈 삭제 및 초기화
setupArea.forEach((obj) => {
if (obj.modules.length > 0) {
if (isObjectNotEmpty(obj.modules) && obj.modules.length > 0) {
obj.modules.forEach((module) => {
canvas.remove(module)
})

View File

@ -1,11 +1,11 @@
'use client'
import { useEffect } from 'react'
import { useEffect, useRef } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { BATCH_TYPE, INPUT_TYPE, POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent'
import { pointsToTurfPolygon, polygonToTurfPolygon, rectToPolygon, triangleToPolygon } from '@/util/canvas-util'
import { pointsToTurfPolygon, polygonToTurfPolygon, rectToPolygon, triangleToPolygon, toFixedWithoutRounding } from '@/util/canvas-util'
import { useSwal } from '@/hooks/useSwal'
import * as turf from '@turf/turf'
import { usePolygon } from '@/hooks/usePolygon'
@ -71,13 +71,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
}
const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => {
const applyOpeningAndShadow = (objectPlacement, buttonAct) => {
const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value
const isCrossChecked = buttonAct === 1 ? objectPlacement.isCrossRef.current.checked : false
const objName = buttonAct === 1 ? BATCH_TYPE.OPENING : BATCH_TYPE.SHADOW
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const objTempName = buttonAct === 1 ? BATCH_TYPE.OPENING_TEMP : BATCH_TYPE.SHADOW_TEMP
let rect, isDown, origX, origY
let selectedSurface
//프리입력
@ -267,26 +269,14 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
* @param {*} surfaceShapePolygons
* @returns
*/
const applyDormers = (dormerPlacement, buttonAct, surfaceShapePolygons) => {
const applyDormers = ({ height, width, pitch, offsetRef, offsetWidthRef, directionRef }, buttonAct) => {
const dormerName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER : BATCH_TYPE.PENTAGON_DORMER
const dormerTempName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER_TEMP : BATCH_TYPE.PENTAGON_DORMER_TEMP
const height = dormerPlacement.heightRef.current !== null ? dormerPlacement.heightRef.current.value / 10 : 0
const width = dormerPlacement.widthRef.current !== null ? dormerPlacement.widthRef.current.value / 10 : 0 //triangle일때는 없음
const pitch = dormerPlacement.pitchRef.current !== null ? dormerPlacement.pitchRef.current.value : 0
const offsetRef =
dormerPlacement.offsetRef.current !== null
? dormerPlacement.offsetRef.current.value === ''
? 0
: parseInt(dormerPlacement.offsetRef.current.value) / 10
: 0
const offsetWidthRef =
dormerPlacement.offsetWidthRef.current !== null
? dormerPlacement.offsetWidthRef.current.value === ''
? 0
: parseInt(dormerPlacement.offsetWidthRef.current.value) / 10
: 0
const directionRef = dormerPlacement.directionRef.current
let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const id = uuidv4()
if (height === '' || pitch === '' || height <= 0 || pitch <= 0) {
@ -296,8 +286,9 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//삼각형 도머
if (buttonAct === 3) {
const bottomLength = height / (pitch * 0.25)
const bottomOffsetLength = (height + offsetRef) / (pitch * 0.25)
const bottomLength = Math.floor((height / Math.cos(Math.atan(pitch / 10))) * 10) / 10
const bottomOffsetLength = Math.floor(((height + offsetRef) / Math.cos(Math.atan(pitch / 10))) * 10) / 10
let groupDormerPoints = [] //나중에 offset을 위한 포인트 저장용
addCanvasMouseEventListener('mouse:move', (e) => {
@ -313,6 +304,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
})
console.log('selectedSurface', selectedSurface)
let angle = 0
if (directionRef === 'left') {
//서
@ -433,6 +426,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
})
const rightTriangle = new QPolygon(rightPoints, {
@ -452,6 +454,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
})
// canvas?.add(leftTriangle)
@ -489,6 +500,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
angle: originAngle,
pitch: pitch,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
})
}
@ -528,8 +548,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//(동의길이 깊이)+출폭(깊이)-[(입력한 폭값)/2+출폭(폭)]*(0.25*입력한 寸)
const heightOffsetLength = height + offsetRef - (width / 2 + offsetWidthRef) * (pitch * 0.25)
let groupDormerPoints = []
addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true
if (!isDown) return
@ -672,6 +690,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
originY: 'center',
name: dormerName,
pitch: pitch,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
})
const rightPentagon = new QPolygon(rightPoints, {
@ -689,6 +716,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
originY: 'center',
name: dormerName,
pitch: pitch,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
})
// canvas?.add(leftPentagon)
@ -703,8 +739,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
let offsetPolygon
groupDormerPoints = groupPoints
if (offsetRef > 0) {
canvas?.remove(dormer)
@ -725,6 +759,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
angle: originAngle,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
})
}
@ -738,7 +781,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
groupYn: true,
originX: 'center',
originY: 'center',
groupPoints: groupDormerPoints,
groupPoints: groupPoints,
})
canvas?.add(objectGroup)
@ -1191,6 +1234,26 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
}
const dormerPlacement = {
widthRef: useRef(null),
heightRef: useRef(null),
pitchRef: useRef(null),
offsetRef: useRef(null),
offsetWidthRef: useRef(null),
directionRef: useRef(null),
}
const copyOjbectDormer = () => {
const obj = canvas.getActiveObject()
if (obj) {
if (obj.name === 'triangleDormer') {
const offset = obj._objects.filter((item) => item.name === 'triangleDormerOffset')
} else {
//오각도머
}
}
}
const dormerOffsetKeyEvent = (setArrow1, setArrow2) => {
addDocumentEventListener('keydown', document, (e) => {
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {

View File

@ -1035,3 +1035,8 @@ export function calculateVisibleModuleHeight(sourceWidth, sourceHeight, angle, d
height: Number(visibleHeight.toFixed(1)), // 소수점 두 자리로 고정
}
}
//숫자, 몇자리수
export function toFixedWithoutRounding(number, decimals) {
return Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals)
}