보조선 연결모드 추가
This commit is contained in:
parent
225cf3a566
commit
3d266b21d7
@ -4,13 +4,20 @@ import { Mode, useMode } from '@/hooks/useMode'
|
|||||||
import { Button } from '@nextui-org/react'
|
import { Button } from '@nextui-org/react'
|
||||||
import RangeSlider from './ui/RangeSlider'
|
import RangeSlider from './ui/RangeSlider'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { canvasSizeState, fontSizeState, roofMaterialState, sortedPolygonArray, templateTypeState, compassState } from '@/store/canvasAtom'
|
import {
|
||||||
|
canvasSizeState,
|
||||||
|
compassState,
|
||||||
|
fontSizeState,
|
||||||
|
roofMaterialState,
|
||||||
|
roofState,
|
||||||
|
sortedPolygonArray,
|
||||||
|
templateTypeState,
|
||||||
|
wallState,
|
||||||
|
} from '@/store/canvasAtom'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
||||||
import { calculateIntersection } from '@/util/canvas-util'
|
import { calculateIntersection } from '@/util/canvas-util'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import * as turf from '@turf/turf'
|
|
||||||
import { toGeoJSON } from '@/util/qpolygon-utils'
|
|
||||||
|
|
||||||
export default function Roof2() {
|
export default function Roof2() {
|
||||||
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
|
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
|
||||||
@ -38,6 +45,10 @@ export default function Roof2() {
|
|||||||
|
|
||||||
const [compass, setCompass] = useRecoilState(compassState)
|
const [compass, setCompass] = useRecoilState(compassState)
|
||||||
|
|
||||||
|
const roof = useRecoilValue(roofState)
|
||||||
|
|
||||||
|
const wall = useRecoilValue(wallState)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
setMode,
|
setMode,
|
||||||
@ -55,6 +66,8 @@ export default function Roof2() {
|
|||||||
createRoofRack,
|
createRoofRack,
|
||||||
drawRoofPolygon,
|
drawRoofPolygon,
|
||||||
drawCellInTrestle,
|
drawCellInTrestle,
|
||||||
|
setDirectionTrestles,
|
||||||
|
cutHelpLines,
|
||||||
} = useMode()
|
} = useMode()
|
||||||
|
|
||||||
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
|
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
|
||||||
@ -553,12 +566,19 @@ export default function Roof2() {
|
|||||||
<Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => setMode(Mode.TEXTBOX)}>
|
<Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => setMode(Mode.TEXTBOX)}>
|
||||||
텍스트박스 모드
|
텍스트박스 모드
|
||||||
</Button>
|
</Button>
|
||||||
{/*<Button className="m-1 p-2" onClick={handleUndo}>
|
<Button
|
||||||
|
className="m-1 p-2"
|
||||||
|
color={`${mode === Mode.DRAW_HELP_LINE ? 'primary' : 'default'}`}
|
||||||
|
onClick={() => setMode(Mode.DRAW_HELP_LINE)}
|
||||||
|
>
|
||||||
|
보조선 연결 모드
|
||||||
|
</Button>
|
||||||
|
<Button className="m-1 p-2" onClick={handleUndo}>
|
||||||
Undo
|
Undo
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="m-1 p-2" onClick={handleRedo}>
|
<Button className="m-1 p-2" onClick={handleRedo}>
|
||||||
Redo
|
Redo
|
||||||
</Button>*/}
|
</Button>
|
||||||
<Button className="m-1 p-2" onClick={handleClear}>
|
<Button className="m-1 p-2" onClick={handleClear}>
|
||||||
clear
|
clear
|
||||||
</Button>
|
</Button>
|
||||||
@ -614,6 +634,9 @@ export default function Roof2() {
|
|||||||
<Button className="m-1 p-2" onClick={addCanvas}>
|
<Button className="m-1 p-2" onClick={addCanvas}>
|
||||||
캔버스 추가
|
캔버스 추가
|
||||||
</Button>*/}
|
</Button>*/}
|
||||||
|
<Button className="m-1 p-2" onClick={cutHelpLines}>
|
||||||
|
보조선 절삭
|
||||||
|
</Button>
|
||||||
{templateType === 1 && (
|
{templateType === 1 && (
|
||||||
<>
|
<>
|
||||||
<Button className="m-1 p-2" onClick={drawRoofMaterial}>
|
<Button className="m-1 p-2" onClick={drawRoofMaterial}>
|
||||||
@ -622,6 +645,9 @@ export default function Roof2() {
|
|||||||
<Button className="m-1 p-2" onClick={createRoofRack}>
|
<Button className="m-1 p-2" onClick={createRoofRack}>
|
||||||
지붕가대설치
|
지붕가대설치
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button className="m-1 p-2" onClick={setDirectionTrestles}>
|
||||||
|
가대 방향 설정
|
||||||
|
</Button>
|
||||||
<Button className="m-1 p-2" onClick={drawCellInTrestle}>
|
<Button className="m-1 p-2" onClick={drawCellInTrestle}>
|
||||||
선택한 가대 셀채우기
|
선택한 가대 셀채우기
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util'
|
import { actionHandler, anchorWrapper, calculateIntersection, distanceBetweenPoints, polygonPositionHandler } from '@/util/canvas-util'
|
||||||
|
|
||||||
import { useRecoilState } from 'recoil'
|
import { useRecoilState } from 'recoil'
|
||||||
import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
|
import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
|
||||||
@ -9,6 +9,8 @@ import { QPolygon } from '@/components/fabric/QPolygon'
|
|||||||
import { defineQLine } from '@/util/qline-utils'
|
import { defineQLine } from '@/util/qline-utils'
|
||||||
import { defineQPloygon } from '@/util/qpolygon-utils'
|
import { defineQPloygon } from '@/util/qpolygon-utils'
|
||||||
|
|
||||||
|
import * as turf from '@turf/turf'
|
||||||
|
|
||||||
export function useCanvas(id) {
|
export function useCanvas(id) {
|
||||||
const [canvas, setCanvas] = useState()
|
const [canvas, setCanvas] = useState()
|
||||||
const [isLocked, setIsLocked] = useState(false)
|
const [isLocked, setIsLocked] = useState(false)
|
||||||
@ -65,6 +67,7 @@ export function useCanvas(id) {
|
|||||||
initialize()
|
initialize()
|
||||||
canvas?.on('object:added', onChange)
|
canvas?.on('object:added', onChange)
|
||||||
canvas?.on('object:added', addEventOnObject)
|
canvas?.on('object:added', addEventOnObject)
|
||||||
|
|
||||||
canvas?.on('object:modified', onChange)
|
canvas?.on('object:modified', onChange)
|
||||||
canvas?.on('object:removed', onChange)
|
canvas?.on('object:removed', onChange)
|
||||||
canvas?.on('mouse:move', drawMouseLines)
|
canvas?.on('mouse:move', drawMouseLines)
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { findTopTwoIndexesByDistance, getCenterPoint, getDirection, getStartIndex, rearrangeArray } from '@/util/canvas-util'
|
import {
|
||||||
|
calculateIntersection,
|
||||||
|
distanceBetweenPoints,
|
||||||
|
findTopTwoIndexesByDistance,
|
||||||
|
getCenterPoint,
|
||||||
|
getDirection,
|
||||||
|
getStartIndex,
|
||||||
|
rearrangeArray,
|
||||||
|
} from '@/util/canvas-util'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -18,6 +26,8 @@ import { QLine } from '@/components/fabric/QLine'
|
|||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import offsetPolygon from '@/util/qpolygon-utils'
|
import offsetPolygon from '@/util/qpolygon-utils'
|
||||||
|
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||||
|
import * as turf from '@turf/turf'
|
||||||
|
|
||||||
export const Mode = {
|
export const Mode = {
|
||||||
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
|
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
|
||||||
@ -31,6 +41,7 @@ export const Mode = {
|
|||||||
ROOF_TRESTLE: 'roofTrestle', //지붕가대 모드
|
ROOF_TRESTLE: 'roofTrestle', //지붕가대 모드
|
||||||
FILL_CELLS: 'fillCells', //태양광셀 모드
|
FILL_CELLS: 'fillCells', //태양광셀 모드
|
||||||
CELL_POWERCON: 'cellPowercon', //파워콘
|
CELL_POWERCON: 'cellPowercon', //파워콘
|
||||||
|
DRAW_HELP_LINE: 'drawHelpLine', // 보조선 그리기 모드 지붕 존재해야함
|
||||||
DEFAULT: 'default',
|
DEFAULT: 'default',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,6 +265,14 @@ export function useMode() {
|
|||||||
case 'cellPowercon':
|
case 'cellPowercon':
|
||||||
makeCellPowercon()
|
makeCellPowercon()
|
||||||
break
|
break
|
||||||
|
case 'drawHelpLine':
|
||||||
|
canvas?.off('selection:created', addSelectCreatedEvent)
|
||||||
|
canvas?.off('selection:cleared', addSelectClearedEvent)
|
||||||
|
canvas?.on('selection:created', addSelectCreatedEvent)
|
||||||
|
canvas?.on('selection:cleared', addSelectClearedEvent)
|
||||||
|
drawHelpLineMode()
|
||||||
|
break
|
||||||
|
|
||||||
case 'default':
|
case 'default':
|
||||||
canvas?.off('mouse:down')
|
canvas?.off('mouse:down')
|
||||||
break
|
break
|
||||||
@ -340,6 +359,81 @@ export function useMode() {
|
|||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const addSelectCreatedEvent = (e) => {
|
||||||
|
const target = e.selected[0]
|
||||||
|
|
||||||
|
if (target.name === 'helpPoint') {
|
||||||
|
canvas?.on('mouse:move', helpPointEvent.mouseMove)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const helpPointEvent = {
|
||||||
|
mouseMove: (e) => {
|
||||||
|
const target = canvas?.getActiveObject()
|
||||||
|
const pointer = canvas?.getPointer(e.e)
|
||||||
|
const point = { x: target.left + target.radius, y: target.top + target.radius }
|
||||||
|
const angle = Math.atan2(pointer.y - point.y, pointer.x - point.x)
|
||||||
|
const degree = fabric.util.radiansToDegrees(angle)
|
||||||
|
|
||||||
|
const min = [0, 45, 90, -0, -90, -45, 135, -135, 180, -180].reduce((prev, curr) => {
|
||||||
|
return Math.abs(curr - degree) < Math.abs(prev - degree) ? curr : prev
|
||||||
|
})
|
||||||
|
|
||||||
|
// Calculate the center point of the target object
|
||||||
|
const centerX = target.left + target.width / 2
|
||||||
|
const centerY = target.top + target.height / 2
|
||||||
|
|
||||||
|
const length = distanceBetweenPoints(point, { x: pointer.x, y: pointer.y })
|
||||||
|
|
||||||
|
// min의 각도와 pointer의 위치를 이용하여 새로운 점을 구한다.
|
||||||
|
const newPoint = {
|
||||||
|
x: centerX + length * Math.cos(fabric.util.degreesToRadians(min)),
|
||||||
|
y: centerY + length * Math.sin(fabric.util.degreesToRadians(min)),
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = new fabric.Line([point.x, point.y, newPoint.x, newPoint.y], {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'beforeHelpLine',
|
||||||
|
helpPoint: target,
|
||||||
|
})
|
||||||
|
|
||||||
|
const helpLines = canvas?._objects.filter((obj) => obj.name === 'beforeHelpLine')
|
||||||
|
helpLines.forEach((item) => canvas?.remove(item))
|
||||||
|
|
||||||
|
canvas?.add(line)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const addSelectClearedEvent = (e) => {
|
||||||
|
const target = e.deselected[0]
|
||||||
|
|
||||||
|
if (target.name === 'helpPoint') {
|
||||||
|
const beforeHelpLines = canvas?._objects.filter((obj) => obj.name === 'beforeHelpLine' && obj.helpPoint === target)
|
||||||
|
|
||||||
|
const helpLines = canvas?._objects.filter((obj) => obj.name === 'helpLine' && obj.helpPoint === target)
|
||||||
|
|
||||||
|
beforeHelpLines.forEach((item) => canvas?.remove(item))
|
||||||
|
helpLines.forEach((item) => canvas?.remove(item))
|
||||||
|
|
||||||
|
const newPoint = { x: beforeHelpLines[0].x2, y: beforeHelpLines[0].y2 }
|
||||||
|
|
||||||
|
const helpLine = new fabric.Line([target.left + target.radius, target.top + target.radius, newPoint.x, newPoint.y], {
|
||||||
|
stroke: 'red',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'helpLine',
|
||||||
|
helpPoint: target,
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(helpLine)
|
||||||
|
canvas?.renderAll()
|
||||||
|
|
||||||
|
canvas?.off('mouse:move', helpPointEvent.mouseMove)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleKeyDown = (e) => {
|
const handleKeyDown = (e) => {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'ArrowDown': {
|
case 'ArrowDown': {
|
||||||
@ -531,7 +625,7 @@ export function useMode() {
|
|||||||
// handleOuterlines()
|
// handleOuterlines()
|
||||||
const wall = makePolygon(null, sort)
|
const wall = makePolygon(null, sort)
|
||||||
wall.set({ name: 'wall' })
|
wall.set({ name: 'wall' })
|
||||||
setWall(wall)
|
console.log('wall', wall)
|
||||||
|
|
||||||
return wall
|
return wall
|
||||||
}
|
}
|
||||||
@ -695,6 +789,7 @@ export function useMode() {
|
|||||||
viewLengthText: true,
|
viewLengthText: true,
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
sort: sort,
|
sort: sort,
|
||||||
|
selectable: false,
|
||||||
},
|
},
|
||||||
canvas,
|
canvas,
|
||||||
)
|
)
|
||||||
@ -738,296 +833,6 @@ export function useMode() {
|
|||||||
setZoom(Math.ceil(zoom - 10))
|
setZoom(Math.ceil(zoom - 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOuterlines = () => {
|
|
||||||
const newOuterlines = []
|
|
||||||
for (let i = 0; i < historyLines.current.length; i++) {
|
|
||||||
const next = historyLines.current[i + 1]
|
|
||||||
const prev = historyLines.current[i - 1] ?? historyLines.current[historyLines.current.length - 1]
|
|
||||||
if (next) {
|
|
||||||
if (next.direction === 'right') {
|
|
||||||
// 다름 라인이 오른쪽으로 이동
|
|
||||||
if (historyLines.current[i].direction === 'top') {
|
|
||||||
if (prev.direction !== 'right') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// bottom
|
|
||||||
if (prev?.direction !== 'right') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (next.direction === 'left') {
|
|
||||||
if (historyLines.current[i].direction === 'top') {
|
|
||||||
if (prev?.direction !== 'left') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// bottom
|
|
||||||
if (prev?.direction !== 'left') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (next.direction === 'top') {
|
|
||||||
if (historyLines.current[i].direction === 'right') {
|
|
||||||
if (prev?.direction !== 'top') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// left
|
|
||||||
if (prev?.direction !== 'top') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (next.direction === 'bottom') {
|
|
||||||
if (historyLines.current[i].direction === 'right') {
|
|
||||||
if (prev?.direction !== 'bottom') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// left
|
|
||||||
if (prev.direction !== 'bottom') {
|
|
||||||
if (historyLines.current.length === 4) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 6) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 + 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 - 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
} else if (historyLines.current.length === 8) {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 + 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 + 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: historyLines.current[i].x1 - 50,
|
|
||||||
y1: historyLines.current[i].y1 - 50,
|
|
||||||
x2: historyLines.current[i].x2 + 50,
|
|
||||||
y2: historyLines.current[i].y2 - 50,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const tmp = newOuterlines[newOuterlines.length - 1]
|
|
||||||
newOuterlines.push({
|
|
||||||
x1: tmp.x2,
|
|
||||||
y1: tmp.y2,
|
|
||||||
x2: newOuterlines[0].x1,
|
|
||||||
y2: newOuterlines[0].y1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
makePolygon(newOuterlines)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*벽 지붕 외곽선 생성
|
*벽 지붕 외곽선 생성
|
||||||
*/
|
*/
|
||||||
@ -1115,9 +920,10 @@ export function useMode() {
|
|||||||
)
|
)
|
||||||
roof.setWall(polygon)
|
roof.setWall(polygon)
|
||||||
setRoof(roof)
|
setRoof(roof)
|
||||||
|
setWall(polygon)
|
||||||
|
|
||||||
roof.drawHelpLine()
|
// roof.drawHelpLine()
|
||||||
roof.divideLine()
|
// roof.divideLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
const drawRoofPolygon = (wall, offset = 50) => {
|
const drawRoofPolygon = (wall, offset = 50) => {
|
||||||
@ -4465,6 +4271,7 @@ export function useMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const createRoofRack = () => {
|
const createRoofRack = () => {
|
||||||
|
roof.divideLine()
|
||||||
const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle')
|
const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle')
|
||||||
// 이미 만들어진 가대가 있을 경우 return
|
// 이미 만들어진 가대가 있을 경우 return
|
||||||
if (trestlePolygons.length !== 0) {
|
if (trestlePolygons.length !== 0) {
|
||||||
@ -4475,7 +4282,6 @@ export function useMode() {
|
|||||||
canvas?.off('mouse:out')
|
canvas?.off('mouse:out')
|
||||||
document.removeEventListener('keydown', handleKeyDown)
|
document.removeEventListener('keydown', handleKeyDown)
|
||||||
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
||||||
let roofCells = [] // roof에 적재된 cell들
|
|
||||||
roofs.forEach((roof, index) => {
|
roofs.forEach((roof, index) => {
|
||||||
const offsetPolygonPoint = offsetPolygon(roof.points, -20)
|
const offsetPolygonPoint = offsetPolygon(roof.points, -20)
|
||||||
|
|
||||||
@ -4498,8 +4304,6 @@ export function useMode() {
|
|||||||
|
|
||||||
canvas?.add(trestlePoly)
|
canvas?.add(trestlePoly)
|
||||||
})
|
})
|
||||||
|
|
||||||
setDrewRoofCells(roofCells)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//배터리 셀 넣기
|
//배터리 셀 넣기
|
||||||
@ -4531,19 +4335,24 @@ export function useMode() {
|
|||||||
|
|
||||||
let drawRoofCells
|
let drawRoofCells
|
||||||
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
||||||
drawRoofCells = trestle.fillCell({ width: 50, height: 100, padding: 0 })
|
drawRoofCells = trestle.fillCell({ width: 50, height: 100, padding: 10 })
|
||||||
trestle.direction = 'south'
|
trestle.direction = 'south'
|
||||||
} else {
|
} else {
|
||||||
drawRoofCells = trestle.fillCell({ width: 100, height: 50, padding: 0 })
|
drawRoofCells = trestle.fillCell({ width: 100, height: 50, padding: 10 })
|
||||||
trestle.direction = 'east'
|
trestle.direction = 'east'
|
||||||
}
|
}
|
||||||
|
|
||||||
drawRoofCells.forEach((cell) => {
|
drawRoofCells.forEach((cell) => {
|
||||||
roofCells.push(cell)
|
drawCellsArray.push(cell)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
setDrewRoofCells(roofCells)
|
setDrewRoofCells(drawCellsArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 가대 방위 설정
|
||||||
|
const setDirectionTrestles = () => {
|
||||||
|
console.log('roof', roof)
|
||||||
}
|
}
|
||||||
|
|
||||||
const makeCellPowercon = () => {
|
const makeCellPowercon = () => {
|
||||||
@ -4610,6 +4419,143 @@ export function useMode() {
|
|||||||
return { concaveIndices: concaveIndices, concavePointIndices: concavePointIndices }
|
return { concaveIndices: concaveIndices, concavePointIndices: concavePointIndices }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const drawHelpLineMode = () => {
|
||||||
|
if (!isObjectNotEmpty(roof)) {
|
||||||
|
alert('지붕을 먼저 그려주세요.')
|
||||||
|
setMode(Mode.DEFAULT)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const roofPoints = roof.points
|
||||||
|
const wallPoints = wall.points
|
||||||
|
|
||||||
|
roofPoints.forEach((roofPoint, index) => {
|
||||||
|
const circle = new fabric.Circle({
|
||||||
|
radius: 5,
|
||||||
|
fill: 'red',
|
||||||
|
left: roofPoint.x - 5,
|
||||||
|
top: roofPoint.y - 5,
|
||||||
|
selectable: true, // 선택 가능하게 설정
|
||||||
|
lockMovementX: true, // X 축 이동 잠금
|
||||||
|
lockMovementY: true, // Y 축 이동 잠금
|
||||||
|
lockRotation: true, // 회전 잠금
|
||||||
|
lockScalingX: true, // X 축 크기 조정 잠금
|
||||||
|
lockScalingY: true, // Y 축 크기 조정 잠금
|
||||||
|
name: 'helpPoint',
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(circle)
|
||||||
|
canvas?.renderAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const cutHelpLines = () => {
|
||||||
|
// 먼저 hip을 자른다.
|
||||||
|
canvas
|
||||||
|
?.getObjects()
|
||||||
|
.filter((obj) => obj.name === 'helpLine')
|
||||||
|
.forEach((line, index1) => {
|
||||||
|
canvas
|
||||||
|
?.getObjects()
|
||||||
|
.filter((obj) => obj.name === 'helpLine')
|
||||||
|
.forEach((line2, index2) => {
|
||||||
|
if (line === line2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const intersectionPoint = calculateIntersection(line, line2)
|
||||||
|
if (!intersectionPoint) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas?.remove(line)
|
||||||
|
canvas?.remove(line2)
|
||||||
|
|
||||||
|
const hip1 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'hip',
|
||||||
|
})
|
||||||
|
|
||||||
|
const hip2 = new QLine([line2.x1, line2.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'hip',
|
||||||
|
})
|
||||||
|
|
||||||
|
const interSectionCircle = new fabric.Circle({
|
||||||
|
radius: 5,
|
||||||
|
fill: 'red',
|
||||||
|
left: intersectionPoint.x - 5,
|
||||||
|
top: intersectionPoint.y - 5,
|
||||||
|
selectable: true, // 선택 가능하게 설정
|
||||||
|
lockMovementX: true, // X 축 이동 잠금
|
||||||
|
lockMovementY: true, // Y 축 이동 잠금
|
||||||
|
lockRotation: true, // 회전 잠금
|
||||||
|
lockScalingX: true, // X 축 크기 조정 잠금
|
||||||
|
lockScalingY: true, // Y 축 크기 조정 잠금
|
||||||
|
name: 'helpPoint',
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(hip1)
|
||||||
|
canvas?.add(hip2)
|
||||||
|
roof.innerLines.push(hip1)
|
||||||
|
roof.innerLines.push(hip2)
|
||||||
|
canvas?.add(interSectionCircle)
|
||||||
|
canvas?.renderAll()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas
|
||||||
|
?.getObjects()
|
||||||
|
.filter((obj) => obj.name === 'helpLine')
|
||||||
|
.forEach((line) => {
|
||||||
|
const helpPoints = canvas?.getObjects().filter((obj) => obj.name === 'helpPoint')
|
||||||
|
let cnt = 0
|
||||||
|
let intersectionPoints = []
|
||||||
|
helpPoints.forEach((point) => {
|
||||||
|
if (cnt === 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
turf.booleanPointOnLine(
|
||||||
|
turf.point([point.left + point.radius, point.top + point.radius]),
|
||||||
|
turf.lineString([
|
||||||
|
[line.x1, line.y1],
|
||||||
|
[line.x2, line.y2],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
intersectionPoints.push(point)
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (intersectionPoints.length === 2) {
|
||||||
|
const ridge = new QLine(
|
||||||
|
[
|
||||||
|
intersectionPoints[0].left + intersectionPoints[0].radius,
|
||||||
|
intersectionPoints[0].top + intersectionPoints[0].radius,
|
||||||
|
intersectionPoints[1].left + intersectionPoints[1].radius,
|
||||||
|
intersectionPoints[1].top + intersectionPoints[1].radius,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'ridge',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
roof.innerLines.push(ridge)
|
||||||
|
canvas?.add(ridge)
|
||||||
|
canvas?.remove(line)
|
||||||
|
canvas?.renderAll()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mode,
|
mode,
|
||||||
setMode,
|
setMode,
|
||||||
@ -4627,5 +4573,7 @@ export function useMode() {
|
|||||||
createRoofRack,
|
createRoofRack,
|
||||||
drawRoofPolygon,
|
drawRoofPolygon,
|
||||||
drawCellInTrestle,
|
drawCellInTrestle,
|
||||||
|
setDirectionTrestles,
|
||||||
|
cutHelpLines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/util/common-utils.js
Normal file
11
src/util/common-utils.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Check if an object is not empty.
|
||||||
|
* @param {Object} obj - The object to check.
|
||||||
|
* @returns {boolean} - Returns true if the object is not empty, false otherwise.
|
||||||
|
*/
|
||||||
|
export const isObjectNotEmpty = (obj) => {
|
||||||
|
if (!obj) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return Object.keys(obj).length > 0
|
||||||
|
}
|
||||||
@ -1127,7 +1127,7 @@ export const splitPolygonWithLines = (polygon) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
roofs.forEach((roofPoint) => {
|
roofs.forEach((roofPoint, index) => {
|
||||||
const roof = new QPolygon(roofPoint, {
|
const roof = new QPolygon(roofPoint, {
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
@ -1135,6 +1135,7 @@ export const splitPolygonWithLines = (polygon) => {
|
|||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
name: 'roof',
|
name: 'roof',
|
||||||
selectable: false,
|
selectable: false,
|
||||||
|
startDirection: polygon.lines[index].direction,
|
||||||
})
|
})
|
||||||
|
|
||||||
polygon.canvas.add(roof)
|
polygon.canvas.add(roof)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user