diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx
index 20883410..68303710 100644
--- a/src/components/Roof2.jsx
+++ b/src/components/Roof2.jsx
@@ -4,13 +4,20 @@ import { Mode, useMode } from '@/hooks/useMode'
import { Button } from '@nextui-org/react'
import RangeSlider from './ui/RangeSlider'
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 { getCanvasState, insertCanvasState } from '@/lib/canvas'
import { calculateIntersection } from '@/util/canvas-util'
import { QPolygon } from '@/components/fabric/QPolygon'
-import * as turf from '@turf/turf'
-import { toGeoJSON } from '@/util/qpolygon-utils'
export default function Roof2() {
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
@@ -38,6 +45,10 @@ export default function Roof2() {
const [compass, setCompass] = useRecoilState(compassState)
+ const roof = useRecoilValue(roofState)
+
+ const wall = useRecoilValue(wallState)
+
const {
mode,
setMode,
@@ -55,6 +66,8 @@ export default function Roof2() {
createRoofRack,
drawRoofPolygon,
drawCellInTrestle,
+ setDirectionTrestles,
+ cutHelpLines,
} = useMode()
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
@@ -553,12 +566,19 @@ export default function Roof2() {
- {/*
clear
@@ -614,6 +634,9 @@ export default function Roof2() {
캔버스 추가
*/}
+
+ 보조선 절삭
+
{templateType === 1 && (
<>
@@ -622,6 +645,9 @@ export default function Roof2() {
지붕가대설치
+
+ 가대 방향 설정
+
선택한 가대 셀채우기
diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js
index 968f3676..27c80187 100644
--- a/src/hooks/useCanvas.js
+++ b/src/hooks/useCanvas.js
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react'
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 { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
@@ -9,6 +9,8 @@ import { QPolygon } from '@/components/fabric/QPolygon'
import { defineQLine } from '@/util/qline-utils'
import { defineQPloygon } from '@/util/qpolygon-utils'
+import * as turf from '@turf/turf'
+
export function useCanvas(id) {
const [canvas, setCanvas] = useState()
const [isLocked, setIsLocked] = useState(false)
@@ -65,6 +67,7 @@ export function useCanvas(id) {
initialize()
canvas?.on('object:added', onChange)
canvas?.on('object:added', addEventOnObject)
+
canvas?.on('object:modified', onChange)
canvas?.on('object:removed', onChange)
canvas?.on('mouse:move', drawMouseLines)
diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js
index 9edd121c..968c76ca 100644
--- a/src/hooks/useMode.js
+++ b/src/hooks/useMode.js
@@ -1,5 +1,13 @@
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 {
@@ -18,6 +26,8 @@ import { QLine } from '@/components/fabric/QLine'
import { fabric } from 'fabric'
import { QPolygon } from '@/components/fabric/QPolygon'
import offsetPolygon from '@/util/qpolygon-utils'
+import { isObjectNotEmpty } from '@/util/common-utils'
+import * as turf from '@turf/turf'
export const Mode = {
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
@@ -31,6 +41,7 @@ export const Mode = {
ROOF_TRESTLE: 'roofTrestle', //지붕가대 모드
FILL_CELLS: 'fillCells', //태양광셀 모드
CELL_POWERCON: 'cellPowercon', //파워콘
+ DRAW_HELP_LINE: 'drawHelpLine', // 보조선 그리기 모드 지붕 존재해야함
DEFAULT: 'default',
}
@@ -254,6 +265,14 @@ export function useMode() {
case 'cellPowercon':
makeCellPowercon()
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':
canvas?.off('mouse:down')
break
@@ -340,6 +359,81 @@ export function useMode() {
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) => {
switch (e.key) {
case 'ArrowDown': {
@@ -531,7 +625,7 @@ export function useMode() {
// handleOuterlines()
const wall = makePolygon(null, sort)
wall.set({ name: 'wall' })
- setWall(wall)
+ console.log('wall', wall)
return wall
}
@@ -695,6 +789,7 @@ export function useMode() {
viewLengthText: true,
fontSize: fontSize,
sort: sort,
+ selectable: false,
},
canvas,
)
@@ -738,296 +833,6 @@ export function useMode() {
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)
setRoof(roof)
+ setWall(polygon)
- roof.drawHelpLine()
- roof.divideLine()
+ // roof.drawHelpLine()
+ // roof.divideLine()
}
const drawRoofPolygon = (wall, offset = 50) => {
@@ -4465,6 +4271,7 @@ export function useMode() {
}
const createRoofRack = () => {
+ roof.divideLine()
const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle')
// 이미 만들어진 가대가 있을 경우 return
if (trestlePolygons.length !== 0) {
@@ -4475,7 +4282,6 @@ export function useMode() {
canvas?.off('mouse:out')
document.removeEventListener('keydown', handleKeyDown)
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
- let roofCells = [] // roof에 적재된 cell들
roofs.forEach((roof, index) => {
const offsetPolygonPoint = offsetPolygon(roof.points, -20)
@@ -4498,8 +4304,6 @@ export function useMode() {
canvas?.add(trestlePoly)
})
-
- setDrewRoofCells(roofCells)
}
//배터리 셀 넣기
@@ -4531,19 +4335,24 @@ export function useMode() {
let drawRoofCells
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'
} else {
- drawRoofCells = trestle.fillCell({ width: 100, height: 50, padding: 0 })
+ drawRoofCells = trestle.fillCell({ width: 100, height: 50, padding: 10 })
trestle.direction = 'east'
}
drawRoofCells.forEach((cell) => {
- roofCells.push(cell)
+ drawCellsArray.push(cell)
})
})
- setDrewRoofCells(roofCells)
+ setDrewRoofCells(drawCellsArray)
+ }
+
+ // 가대 방위 설정
+ const setDirectionTrestles = () => {
+ console.log('roof', roof)
}
const makeCellPowercon = () => {
@@ -4610,6 +4419,143 @@ export function useMode() {
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 {
mode,
setMode,
@@ -4627,5 +4573,7 @@ export function useMode() {
createRoofRack,
drawRoofPolygon,
drawCellInTrestle,
+ setDirectionTrestles,
+ cutHelpLines,
}
}
diff --git a/src/util/common-utils.js b/src/util/common-utils.js
new file mode 100644
index 00000000..9f53fede
--- /dev/null
+++ b/src/util/common-utils.js
@@ -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
+}
diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js
index 5a216524..77af0df5 100644
--- a/src/util/qpolygon-utils.js
+++ b/src/util/qpolygon-utils.js
@@ -1127,7 +1127,7 @@ export const splitPolygonWithLines = (polygon) => {
})
})
- roofs.forEach((roofPoint) => {
+ roofs.forEach((roofPoint, index) => {
const roof = new QPolygon(roofPoint, {
fontSize: polygon.fontSize,
stroke: 'black',
@@ -1135,6 +1135,7 @@ export const splitPolygonWithLines = (polygon) => {
strokeWidth: 3,
name: 'roof',
selectable: false,
+ startDirection: polygon.lines[index].direction,
})
polygon.canvas.add(roof)