삼각도머

This commit is contained in:
yjnoh 2025-03-05 17:14:03 +09:00
parent 652516146b
commit 8fb523cf3d
3 changed files with 242 additions and 132 deletions

View File

@ -5,7 +5,14 @@ import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { BATCH_TYPE, INPUT_TYPE, POLYGON_TYPE } from '@/common/common' import { BATCH_TYPE, INPUT_TYPE, POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { pointsToTurfPolygon, polygonToTurfPolygon, rectToPolygon, triangleToPolygon, getDegreeByChon } from '@/util/canvas-util' import {
pointsToTurfPolygon,
polygonToTurfPolygon,
rectToPolygon,
triangleToPolygon,
getDegreeByChon,
toFixedWithoutRounding,
} from '@/util/canvas-util'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
@ -13,6 +20,7 @@ import { QPolygon } from '@/components/fabric/QPolygon'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { fontSelector } from '@/store/fontAtom' import { fontSelector } from '@/store/fontAtom'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { roofDisplaySelector } from '@/store/settingAtom'
export function useObjectBatch({ isHidden, setIsHidden }) { export function useObjectBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -23,6 +31,9 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const { drawDirectionArrow } = usePolygon() const { drawDirectionArrow } = usePolygon()
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const lengthTextFont = useRecoilValue(fontSelector('lengthText')) const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const roofDisplay = useRecoilValue(roofDisplaySelector)
const { addPolygon } = usePolygon()
useEffect(() => { useEffect(() => {
if (canvas) { if (canvas) {
@ -293,6 +304,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (buttonAct === 3) { if (buttonAct === 3) {
let groupDormerPoints = [] //나중에 offset을 위한 포인트 저장용 let groupDormerPoints = [] //나중에 offset을 위한 포인트 저장용
let bottomLength = 0,
bottomOffsetLength = 0,
planeHypotenuse = 0,
planeOffsetHypotenuse = 0,
actualBottomLength = 0,
actualBottomOffsetLength = 0,
actualHypotenuse = 0,
actualOffsetHypotenuse = 0
addCanvasMouseEventListener('mouse:move', (e) => { addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true isDown = true
if (!isDown) return if (!isDown) return
@ -306,57 +326,51 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
} }
}) })
console.log('selectedSurface', selectedSurface) if (selectedSurface) {
const roofAngle = selectedSurface.roofMaterial.angle
const roofAngle = selectedSurface.roofMaterial.angle theta = Math.atan(Math.tan((roofAngle * Math.PI) / 180) / Math.tan((dormerAngle * Math.PI) / 180))
theta = Math.atan(Math.tan((roofAngle * Math.PI) / 180) / Math.tan((dormerAngle * Math.PI) / 180)) //센터 삼각형용
bottomLength = Number((Math.tan(theta) * height).toFixed())
const bottomLength = Number((Math.tan(theta) * height).toFixed()) //좌우 삼각형용
const bottomOffsetLength = Number((Math.tan(theta) * (height + offsetRef)).toFixed()) bottomOffsetLength = Number((Math.tan(theta) * (height + offsetRef)).toFixed())
let angle = 0 planeHypotenuse = Math.sqrt(Math.pow(height, 2) + Math.pow(bottomLength, 2))
if (directionRef === 'left') {
//서
angle = 90
} else if (directionRef === 'right') {
//동
angle = 270
} else if (directionRef === 'up') {
//북
angle = 180
}
dormer = new fabric.Triangle({ actualBottomLength = Math.sqrt(
fill: 'white', Math.pow(Math.tan(theta) * height, 2) + Math.pow(Math.tan(theta) * height * Math.tan((dormerAngle * Math.PI) / 180), 2),
stroke: 'red', )
strokeDashArray: [5, 5], actualHypotenuse = Math.sqrt(Math.pow(height, 2) + Math.pow(actualBottomLength, 2))
strokeWidth: 1,
width: bottomLength * 2,
height: height,
left: pointer.x,
top: pointer.y,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
})
canvas?.add(dormer)
if (offsetRef > 0) { actualBottomOffsetLength = Math.sqrt(
dormerOffset = new fabric.Triangle({ Math.pow(Math.tan(theta) * (height + offsetRef), 2) +
fill: 'gray', Math.pow(Math.tan(theta) * (height + offsetRef) * Math.tan((dormerAngle * Math.PI) / 180), 2),
)
planeOffsetHypotenuse = Math.sqrt(Math.pow(height + offsetRef, 2) + Math.pow(bottomOffsetLength, 2))
actualOffsetHypotenuse = Math.sqrt(Math.pow(height + offsetRef, 2) + Math.pow(actualBottomOffsetLength, 2))
let angle = 0
if (directionRef === 'left') {
//서
angle = 90
} else if (directionRef === 'right') {
//동
angle = 270
} else if (directionRef === 'up') {
//북
angle = 180
}
dormer = new fabric.Triangle({
fill: 'white',
stroke: 'red', stroke: 'red',
strokeDashArray: [5, 5], strokeDashArray: [5, 5],
strokeWidth: 1, strokeWidth: 1,
width: bottomOffsetLength * 2, width: bottomLength * 2,
height: height + offsetRef, height: height,
left: pointer.x, left: pointer.x,
top: pointer.y, top: pointer.y,
selectable: true, selectable: true,
@ -369,9 +383,33 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
originX: 'center', originX: 'center',
originY: 'top', originY: 'top',
angle: angle, angle: angle,
objectId: id,
}) })
canvas?.add(dormerOffset) canvas?.add(dormer)
if (offsetRef > 0) {
dormerOffset = new fabric.Triangle({
fill: 'gray',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
width: bottomOffsetLength * 2,
height: height + offsetRef,
left: pointer.x,
top: pointer.y,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
objectId: id,
})
canvas?.add(dormerOffset)
}
} }
}) })
@ -418,68 +456,120 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
strokeDashArray: [0], strokeDashArray: [0],
}) //오프셋이 있을땐 같이 도머로 만든다 }) //오프셋이 있을땐 같이 도머로 만든다
const leftTriangle = new QPolygon(leftPoints, { const leftTriangle = addPolygon(
fill: 'white', leftPoints,
stroke: 'black', {
strokeWidth: 1, fill: 'white',
selectable: true, stroke: 'black',
lockMovementX: true, // X 축 이동 잠금 strokeWidth: 1,
lockMovementY: true, // Y 축 이동 잠금 selectable: true,
lockRotation: true, // 회전 잠금 lockMovementX: true, // X 축 이동 잠금
viewLengthText: true, lockMovementY: true, // Y 축 이동 잠금
// direction: direction, lockRotation: true, // 회전 잠금
originX: 'center', viewLengthText: true,
originY: 'center', // direction: direction,
name: dormerName, originX: 'center',
pitch: pitch, originY: 'center',
fontSize: lengthTextFont.fontSize.value, name: dormerName,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch, pitch: pitch,
offsetRef: offsetRef, fontSize: lengthTextFont.fontSize.value,
offsetWidthRef: offsetWidthRef, fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
directionRef: directionRef, fontWeight: lengthTextFont.fontWeight.value,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
lines: [
{
attributes: {
planeSize: toFixedWithoutRounding(planeOffsetHypotenuse, 1) * 10,
actualSize: toFixedWithoutRounding(actualOffsetHypotenuse, 1) * 10,
},
},
{
attributes: {
planeSize: toFixedWithoutRounding(bottomOffsetLength, 1) * 10,
actualSize: toFixedWithoutRounding(actualBottomOffsetLength, 1) * 10,
},
},
{
attributes: {
planeSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
actualSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
},
},
],
}, },
false,
)
leftTriangle.texts.forEach((text) => {
text.bringToFront()
}) })
const rightTriangle = new QPolygon(rightPoints, { const rightTriangle = addPolygon(
fill: 'white', rightPoints,
stroke: 'black', {
strokeWidth: 1, fill: 'white',
selectable: true, stroke: 'black',
lockMovementX: true, // X 축 이동 잠금 strokeWidth: 1,
lockMovementY: true, // Y 축 이동 잠금 selectable: true,
lockRotation: true, // 회전 잠금 lockMovementX: true, // X 축 이동 잠금
viewLengthText: true, lockMovementY: true, // Y 축 이동 잠금
// direction: direction, lockRotation: true, // 회전 잠금
originX: 'center', viewLengthText: true,
originY: 'center', // direction: direction,
name: dormerName, originX: 'center',
pitch: pitch, originY: 'center',
fontSize: lengthTextFont.fontSize.value, name: dormerName,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch, pitch: pitch,
offsetRef: offsetRef, fontSize: lengthTextFont.fontSize.value,
offsetWidthRef: offsetWidthRef, fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
directionRef: directionRef, fontWeight: lengthTextFont.fontWeight.value,
groupPoints: groupPoints,
dormerAttributes: {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
lines: [
{
attributes: {
planeSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
actualSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
},
},
{
attributes: {
planeSize: toFixedWithoutRounding(bottomOffsetLength, 1) * 10,
actualSize: toFixedWithoutRounding(actualBottomOffsetLength, 1) * 10,
},
},
{
attributes: {
planeSize: toFixedWithoutRounding(planeOffsetHypotenuse, 1) * 10,
actualSize: toFixedWithoutRounding(actualOffsetHypotenuse, 1) * 10,
},
},
],
}, },
}) false,
)
// canvas?.add(leftTriangle) // canvas?.add(leftTriangle)
// canvas?.add(rightTriangle) // canvas?.add(rightTriangle)
//패턴 //패턴
setSurfaceShapePattern(leftTriangle) setSurfaceShapePattern(leftTriangle, roofDisplay.column, false, selectedSurface.roofMaterial, true)
setSurfaceShapePattern(rightTriangle) setSurfaceShapePattern(rightTriangle, roofDisplay.column, false, selectedSurface.roofMaterial, true)
//방향 //방향
// drawDirectionArrow(leftTriangle) // drawDirectionArrow(leftTriangle)
@ -492,33 +582,57 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (offsetRef > 0) { if (offsetRef > 0) {
canvas?.remove(dormer) canvas?.remove(dormer)
offsetPolygon = new QPolygon(triangleToPolygon(dormer), { offsetPolygon = addPolygon(
selectable: true, triangleToPolygon(dormer),
lockMovementX: true, // X 축 이동 잠금 {
lockMovementY: true, // Y 축 이동 잠금 selectable: true,
lockRotation: true, // 회전 잠금 lockMovementX: true, // X 축 이동 잠금
viewLengthText: true, lockMovementY: true, // Y 축 이동 잠금
name: 'triangleDormerOffset', lockRotation: true, // 회전 잠금
id: id, viewLengthText: true,
fill: 'rgba(255, 255, 255, 0.6)', name: 'triangleDormerOffset',
stroke: 'black', id: id,
strokeWidth: 1, fill: 'rgba(255, 255, 255, 0.6)',
originX: 'center', stroke: 'black',
originY: 'top', strokeWidth: 1,
fontSize: lengthTextFont.fontSize.value, originX: 'center',
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', originY: 'top',
fontWeight: lengthTextFont.fontWeight.value, fontSize: lengthTextFont.fontSize.value,
angle: originAngle, fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
pitch: pitch, fontWeight: lengthTextFont.fontWeight.value,
dormerAttributes: { angle: originAngle,
height: height,
width: width,
pitch: pitch, pitch: pitch,
offsetRef: offsetRef, dormerAttributes: {
offsetWidthRef: offsetWidthRef, height: height,
directionRef: directionRef, width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
},
lines: [
{
attributes: {
planeSize: toFixedWithoutRounding(planeHypotenuse, 1) * 10,
actualSize: toFixedWithoutRounding(actualHypotenuse, 1) * 10,
},
},
{
attributes: {
planeSize: toFixedWithoutRounding(bottomLength * 2, 1) * 10,
actualSize: toFixedWithoutRounding(bottomLength * 2, 1) * 10,
},
},
{
attributes: {
planeSize: toFixedWithoutRounding(planeHypotenuse, 1) * 10,
actualSize: toFixedWithoutRounding(actualHypotenuse, 1) * 10,
},
},
],
}, },
}) false,
)
} }
const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle] const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle]
@ -534,10 +648,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}) })
canvas?.add(objectGroup) canvas?.add(objectGroup)
objectGroup.getObjects().forEach((obj, index) => {
console.log(`최초 pathOffset ${index}`, obj.get('pathOffset'))
})
objectGroup._objects.forEach((obj) => { objectGroup._objects.forEach((obj) => {
if (obj.hasOwnProperty('texts')) { if (obj.hasOwnProperty('texts')) {
obj.texts.forEach((text) => { obj.texts.forEach((text) => {
@ -548,7 +658,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
isDown = false isDown = false
initEvent() initEvent()
dbClickEvent() // dbClickEvent()
if (setIsHidden) setIsHidden(false) if (setIsHidden) setIsHidden(false)
} }
}) })
@ -805,7 +915,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
isDown = false isDown = false
initEvent() initEvent()
dbClickEvent() // dbClickEvent()
} }
}) })
} }

View File

@ -26,7 +26,7 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
export function useSurfaceShapeBatch({ isHidden, setIsHidden }) { export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { drawDirectionArrow } = usePolygon() const { drawDirectionArrow, addPolygon } = usePolygon()
const lengthTextFont = useRecoilValue(fontSelector('lengthText')) const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const resetOuterLinePoints = useResetRecoilState(outerLinePointsState) const resetOuterLinePoints = useResetRecoilState(outerLinePointsState)
const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState) const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState)
@ -178,7 +178,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
} }
//회전, flip등이 먹은 기준으로 새로생성 //회전, flip등이 먹은 기준으로 새로생성
const batchSurface = new QPolygon(obj.getCurrentPoints(), { const batchSurface = addPolygon(obj.getCurrentPoints(), {
fill: 'transparent', fill: 'transparent',
stroke: 'red', stroke: 'red',
strokeWidth: 3, strokeWidth: 3,

View File

@ -17,16 +17,16 @@ export const usePolygon = () => {
const currentAngleType = useRecoilValue(currentAngleTypeSelector) const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const pitchText = useRecoilValue(pitchTextSelector) const pitchText = useRecoilValue(pitchTextSelector)
const addPolygon = (points, options) => { const addPolygon = (points, options, isAddCanvas = true) => {
const polygon = new QPolygon(points, { const polygon = new QPolygon(points, {
...options, ...options,
fontSize: lengthTextFontOptions.fontSize.value, fontSize: lengthTextFontOptions.fontSize.value,
fill: options.fill || 'transparent', fill: options.fill || 'transparent',
stroke: options.stroke || '#000000', stroke: options.stroke || '#000000',
selectable: true, // selectable: true,
}) })
canvas?.add(polygon) if (isAddCanvas) canvas?.add(polygon)
addLengthText(polygon) addLengthText(polygon)
return polygon return polygon