템플릿A,B 중간 저장

This commit is contained in:
Jaeyoung Lee 2024-11-21 18:28:39 +09:00
parent eb5bb77f1f
commit d7bdfa4892
4 changed files with 397 additions and 67 deletions

View File

@ -5,7 +5,7 @@ import { useEffect, useRef, useState } from 'react'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { useMode } from '@/hooks/useMode' import { useMode } from '@/hooks/useMode'
import { LINE_TYPE, Mode } from '@/common/common' import { LINE_TYPE, Mode } from '@/common/common'
import { Button, Input } 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 { import {
@ -410,10 +410,10 @@ export default function Roof2(props) {
] ]
const rectangleType1 = [ const rectangleType1 = [
{ x: 100, y: 100 }, { x: 500, y: 100 },
{ x: 100, y: 600 }, { x: 500, y: 800 },
{ x: 300, y: 600 }, { x: 900, y: 800 },
{ x: 300, y: 100 }, { x: 900, y: 100 },
] ]
const rectangleType2 = [ const rectangleType2 = [
@ -460,6 +460,15 @@ export default function Roof2(props) {
{ x: 200, y: 100 }, { x: 200, y: 100 },
] ]
const test4 = [
{ x: 100, y: 100 },
{ x: 100, y: 1000 },
{ x: 1100, y: 1000 },
{ x: 1100, y: 550 },
{ x: 500, y: 550 },
{ x: 500, y: 100 },
]
const polygon = new QPolygon(eightPoint4, { const polygon = new QPolygon(eightPoint4, {
fill: 'transparent', fill: 'transparent',
stroke: 'green', stroke: 'green',
@ -1021,7 +1030,7 @@ export default function Roof2(props) {
</> </>
)} )}
<ThumbnailList {...thumbnailProps} /> <ThumbnailList {...thumbnailProps} />
<div className={'flex'}> {/* <div className={'flex'}>
<p className={'m-1 p-3'}>각도 입력(0~360) 방향설정 클릭</p> <p className={'m-1 p-3'}>각도 입력(0~360) 방향설정 클릭</p>
<Input <Input
className="m-1 p-3" className="m-1 p-3"
@ -1039,14 +1048,14 @@ export default function Roof2(props) {
<Button className="m-1 p-3" onClick={setDirectionStringToArrow}> <Button className="m-1 p-3" onClick={setDirectionStringToArrow}>
방향 설정 방향 설정
</Button> </Button>
</div> </div>*/}
<div className="relative w-48 h-48 flex justify-center items-center border-2 border-gray-300 rounded-full"> {/* <div className="relative w-48 h-48 flex justify-center items-center border-2 border-gray-300 rounded-full">
{/* Compass Circle */} Compass Circle
<div <div
className="absolute w-full h-full border-2 border-gray-300 rounded-full flex justify-center items-center" className="absolute w-full h-full border-2 border-gray-300 rounded-full flex justify-center items-center"
style={{ rotate: `${globalCampass}deg` }} style={{ rotate: `${globalCampass}deg` }}
> >
{/* N, S, E, W Labels */} N, S, E, W Labels
<div className="absolute top-2 text-lg font-bold">N</div> <div className="absolute top-2 text-lg font-bold">N</div>
<div className="absolute bottom-2 text-lg font-bold">S</div> <div className="absolute bottom-2 text-lg font-bold">S</div>
<div className="absolute right-2 text-lg font-bold" style={{ rotate: '90deg' }}> <div className="absolute right-2 text-lg font-bold" style={{ rotate: '90deg' }}>
@ -1057,9 +1066,9 @@ export default function Roof2(props) {
</div> </div>
</div> </div>
{/* Compass Pointer */} Compass Pointer
<div className="relative w-10 h-10"> <div className="relative w-10 h-10">
{/* Red Upper Triangle */} Red Upper Triangle
<div <div
className="absolute top-0" className="absolute top-0"
style={{ style={{
@ -1072,7 +1081,7 @@ export default function Roof2(props) {
}} }}
/> />
</div> </div>
</div> </div>*/}
<div className="flex justify-start my-8 mx-2 w-full"> <div className="flex justify-start my-8 mx-2 w-full">
<canvas ref={canvasRef} id="canvas" style={{ border: '1px solid black' }} /> <canvas ref={canvasRef} id="canvas" style={{ border: '1px solid black' }} />
{!canvas ? null : mode === Mode.DRAW_LINE ? ( {!canvas ? null : mode === Mode.DRAW_LINE ? (

View File

@ -1,15 +1,8 @@
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
distanceBetweenPoints, import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils'
findTopTwoIndexesByDistance,
getAllRelatedObjects,
getDirectionByPoint,
sortedPointLessEightPoint,
sortedPoints,
} from '@/util/canvas-util'
import { calculateAngle, drawRidgeRoof, drawShedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { LINE_TYPE } from '@/common/common' import { LINE_TYPE } from '@/common/common'
@ -217,7 +210,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
(gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) || (gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) ||
(gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type))) (gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type)))
) { ) {
console.log('박공 지붕') drawGabledRoof(this.id, this.canvas)
} else if (hasShed) { } else if (hasShed) {
const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED) const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED)
const areLinesParallel = function (line1, line2) { const areLinesParallel = function (line1, line2) {

View File

@ -1508,55 +1508,14 @@ export function useMode() {
const handleOuterlinesTest2 = (polygon, offset = 50) => { const handleOuterlinesTest2 = (polygon, offset = 50) => {
// TODO [ljyoung] : offset 입력 처리 후 제거 해야함. // TODO [ljyoung] : offset 입력 처리 후 제거 해야함.
polygon.lines.forEach((line, index) => { polygon.lines.forEach((line, index) => {
line.attributes = { /*line.attributes = {
type: LINE_TYPE.WALLLINE.EAVES, type: LINE_TYPE.WALLLINE.EAVES,
offset: 50, offset: 50,
width: 50, width: 50,
pitch: 4, pitch: 4,
sleeve: true, sleeve: true,
}
/*if (index === 1) {
line.attributes = {
type: LINE_TYPE.WALLLINE.SHED,
offset: 30, //출폭
width: 30, //폭
pitch: 4, //구배
sleeve: true, //소매
}
} else if (index === 5 || index === 3) {
line.attributes = {
type: LINE_TYPE.WALLLINE.EAVES,
offset: 50, //출폭
width: 30, //폭
pitch: 4, //구배
sleeve: true, //소매
}
} else {
line.attributes = {
type: LINE_TYPE.WALLLINE.GABLE,
offset: 20,
width: 50,
pitch: 4,
sleeve: true,
}
}*/ }*/
/* if (index === 1) { if (index % 2 !== 0) {
line.attributes = {
type: LINE_TYPE.WALLLINE.SHED,
offset: 20, //출폭
width: 30, //폭
pitch: 4, //구배
sleeve: true, //소매
}
} else if (index === 3) {
line.attributes = {
type: LINE_TYPE.WALLLINE.EAVES,
offset: 50, //출폭
width: 30, //폭
pitch: 4, //구배
sleeve: true, //소매
}
} else {
line.attributes = { line.attributes = {
type: LINE_TYPE.WALLLINE.GABLE, type: LINE_TYPE.WALLLINE.GABLE,
offset: 30, offset: 30,
@ -1564,7 +1523,15 @@ export function useMode() {
pitch: 4, pitch: 4,
sleeve: true, sleeve: true,
} }
}*/ } else {
line.attributes = {
type: LINE_TYPE.WALLLINE.EAVES,
offset: 50,
width: 50,
pitch: 4,
sleeve: true,
}
}
}) })
const roof = drawRoofPolygon(polygon) //지붕 그리기 const roof = drawRoofPolygon(polygon) //지붕 그리기

View File

@ -1232,6 +1232,367 @@ function calculateAngleBetweenLines(line1, line2) {
return (angleInRadians * 180) / Math.PI return (angleInRadians * 180) / Math.PI
} }
/**
* 박공지붕(templateA, templateB) 그린다.
* @param roofId
* @param canvas
*/
export const drawGabledRoof = (roofId, canvas) => {
const roof = canvas?.getObjects().find((object) => object.id === roofId)
const roofLines = roof.lines
const wallLines = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roof.id).lines
const hasNonParallelLines = roofLines.filter((line) => line.x1 !== line.x2 && line.y1 !== line.y2)
if (hasNonParallelLines.length > 0) {
alert('대각선이 존재합니다.')
return
}
const roofPoints = roof.points
const minX = Math.min(...roofPoints.map((point) => point.x))
const maxX = Math.max(...roofPoints.map((point) => point.x))
const minY = Math.min(...roofPoints.map((point) => point.y))
const maxY = Math.max(...roofPoints.map((point) => point.y))
const checkLength = Math.abs(Math.sqrt(Math.pow(maxX - minX, 2) + Math.pow(maxY - minY, 2)))
wallLines
.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.GABLE)
.forEach((gable) => {
const gableLine = new QLine([gable.x1, gable.y1, gable.x2, gable.y2], {
fontSize: roof.fontSize,
stroke: 'cyan',
strokeWidth: 2,
})
canvas.add(gableLine)
canvas.renderAll()
})
const eaves = []
roofLines.forEach((currentRoof, index) => {
if (currentRoof.attributes !== undefined && currentRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES) {
eaves.push({ index: index, roof: currentRoof, length: currentRoof.attributes.planeSize })
}
})
const ridgeCount = eaves.length - 1
const ridges = []
eaves.sort((a, b) => a.length - b.length)
eaves.forEach((eave, index) => {
if (ridges.length < ridgeCount) {
const index = eave.index,
currentRoof = eave.roof
const currentWall = wallLines[index]
const prevRoof = index === 0 ? roofLines[wallLines.length - 1] : roofLines[index - 1]
const nextRoof = index === roofLines.length - 1 ? roofLines[0] : index === roofLines.length ? roofLines[1] : roofLines[index + 1]
const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10
const midY = Math.round(((currentRoof.y1 + currentRoof.y2) / 2) * 10) / 10
const deltaX = currentWall.x2 - currentWall.x1
const deltaY = currentWall.y2 - currentWall.y1
const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
// currentWall과 직각인 기울기 계산
const perpendicularDeltaX = deltaY / length
const perpendicularDeltaY = -deltaX / length
// midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산
const midWallX = midX + perpendicularDeltaX * length
const midWallY = midY + perpendicularDeltaY * length
const signX = Math.sign(midX - midWallX)
const signY = Math.sign(midY - midWallY)
const checkX = Math.round((midX - signX * checkLength) * 10) / 10
const checkY = Math.round((midY - signY * checkLength) * 10) / 10
const intersectLines = []
roofLines
.filter((line) => line !== currentRoof)
.forEach((line) => {
const intersect = edgesIntersection(
{ vertex1: { x: midX, y: midY }, vertex2: { x: checkX, y: checkY } },
{ vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
)
if (intersect && !intersect.isIntersectionOutside) {
intersectLines.push({ x: intersect.x, y: intersect.y, line: line })
}
})
const intersect = intersectLines.reduce((prev, current) => {
if (prev !== undefined) {
const prevDistance = Math.sqrt(Math.pow(prev.x - midX, 2) + Math.pow(prev.y - midY, 2))
const currentDistance = Math.sqrt(Math.pow(current.x - midX, 2) + Math.pow(current.y - midY, 2))
return prevDistance >= currentDistance ? current : prev
} else {
return current
}
}, undefined)
const linesCenterX = Math.round(((midX + intersect.x) / 2) * 10) / 10
const linesCenterY = Math.round(((midY + intersect.y) / 2) * 10) / 10
let addLength = currentRoof.attributes.planeSize / 2 / 10
let centerLineX1 = Math.sign(currentRoof.x1 - currentRoof.x2) * addLength + linesCenterX
let centerLineY1 = Math.sign(currentRoof.y1 - currentRoof.y2) * addLength + linesCenterY
let centerLineX2 = Math.sign(currentRoof.x2 - currentRoof.x1) * addLength + linesCenterX
let centerLineY2 = Math.sign(currentRoof.y2 - currentRoof.y1) * addLength + linesCenterY
const point1Intersect = []
const point2Intersect = []
roofLines.forEach((line) => {
const point1 = edgesIntersection(
{ vertex1: { x: linesCenterX, y: linesCenterY }, vertex2: { x: centerLineX1, y: centerLineY1 } },
{ vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
)
if (point1 && !point1.isIntersectionOutside) {
point1Intersect.push({ x: point1.x, y: point1.y })
}
const point2 = edgesIntersection(
{ vertex1: { x: linesCenterX, y: linesCenterY }, vertex2: { x: centerLineX2, y: centerLineY2 } },
{ vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
)
if (point2 && !point2.isIntersectionOutside) {
point2Intersect.push({ x: point2.x, y: point2.y })
}
})
point1Intersect.reduce((prev, current) => {
if (prev !== undefined) {
const prevDistance = Math.sqrt(Math.pow(prev.x - linesCenterX, 2) + Math.pow(prev.y - linesCenterY, 2))
const currentDistance = Math.sqrt(Math.pow(current.x - linesCenterX, 2) + Math.pow(current.y - linesCenterY, 2))
return prevDistance >= currentDistance ? current : prev
} else {
return current
}
}, undefined)
point2Intersect.reduce((prev, current) => {
if (prev !== undefined) {
const prevDistance = Math.sqrt(Math.pow(prev.x - linesCenterX, 2) + Math.pow(prev.y - linesCenterY, 2))
const currentDistance = Math.sqrt(Math.pow(current.x - linesCenterX, 2) + Math.pow(current.y - linesCenterY, 2))
return prevDistance >= currentDistance ? current : prev
} else {
return current
}
}, undefined)
if (point1Intersect.length > 0) {
centerLineX1 = point1Intersect[0].x
centerLineY1 = point1Intersect[0].y
}
if (point2Intersect.length > 0) {
centerLineX2 = point2Intersect[0].x
centerLineY2 = point2Intersect[0].y
}
const ridge = new QLine([centerLineX1, centerLineY1, centerLineX2, centerLineY2], {
fontSize: roof.fontSize,
stroke: 'blue',
strokeWidth: 1,
name: LINE_TYPE.SUBLINE.RIDGE,
attributes: { roofId: roof.id, currentRoof: currentRoof.id },
})
canvas.add(ridge)
canvas.renderAll()
ridges.push(ridge)
}
})
eaves.forEach((eave) => {
const index = eave.index,
currentRoof = eave.roof
const currentWall = wallLines[index]
const prevRoof = index === 0 ? roofLines[wallLines.length - 1] : roofLines[index - 1]
const nextRoof = index === roofLines.length - 1 ? roofLines[0] : index === roofLines.length ? roofLines[1] : roofLines[index + 1]
/*const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10
const midY = Math.round(((currentRoof.y1 + currentRoof.y2) / 2) * 10) / 10
const midWallX = Math.round(((currentWall.x1 + currentWall.x2) / 2) * 10) / 10
const midWallY = Math.round(((currentWall.y1 + currentWall.y2) / 2) * 10) / 10
const signX = Math.sign(midX - midWallX)
const signY = Math.sign(midY - midWallY)
*/
const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10
const midY = Math.round(((currentRoof.y1 + currentRoof.y2) / 2) * 10) / 10
const deltaX = currentWall.x2 - currentWall.x1
const deltaY = currentWall.y2 - currentWall.y1
const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
// currentWall과 직각인 기울기 계산
const perpendicularDeltaX = deltaY / length
const perpendicularDeltaY = -deltaX / length
// midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산
const midWallX = midX + perpendicularDeltaX * length
const midWallY = midY + perpendicularDeltaY * length
const signX = Math.sign(midX - midWallX)
const signY = Math.sign(midY - midWallY)
let points = []
const intersectRidge = []
// 현재 roof가 wall보다 작을때 이전, 다음 지붕의 offset만큼 포인트를 조정한다.
if (currentRoof.attributes.planeSize >= currentWall.attributes.planeSize) {
points.push({ x: currentRoof.x1, y: currentRoof.y1 }, { x: currentRoof.x2, y: currentRoof.y2 })
} else {
const deltaX = currentRoof.x2 - currentRoof.x1
const deltaY = currentRoof.y2 - currentRoof.y1
points.push(
{ x: currentRoof.x1 - Math.sign(deltaX) * prevRoof.attributes.offset, y: currentRoof.y1 - Math.sign(deltaY) * prevRoof.attributes.offset },
{ x: currentRoof.x2 + Math.sign(deltaX) * nextRoof.attributes.offset, y: currentRoof.y2 + Math.sign(deltaY) * nextRoof.attributes.offset },
)
}
ridges.forEach((ridge) => {
const ridgeMidX = (ridge.x1 + ridge.x2) / 2
const ridgeMidY = (ridge.y1 + ridge.y2) / 2
if (midX === ridgeMidX || midY === ridgeMidY) {
const intersection = edgesIntersection(
{ vertex1: { x: midX, y: midY }, vertex2: { x: ridgeMidX, y: ridgeMidY } },
{ vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
)
if (intersection && !intersection.isIntersectionOutside) {
intersectRidge.push({ line: ridge, name: 'mid' })
}
}
console.log('signX : ', signX, 'signY : ', signY)
if (Math.sign(midX - ridgeMidX) === signX || Math.sign(midY - ridgeMidY) === signY) {
const prevIntersect = edgesIntersection(
{ vertex1: { x: prevRoof.x1, y: prevRoof.y1 }, vertex2: { x: prevRoof.x2, y: prevRoof.y2 } },
{ vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
)
const nextIntersect = edgesIntersection(
{ vertex1: { x: nextRoof.x1, y: nextRoof.y1 }, vertex2: { x: nextRoof.x2, y: nextRoof.y2 } },
{ vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
)
if (prevIntersect && !prevIntersect.isIntersectionOutside) {
intersectRidge.push({ line: ridge, name: 'prev' })
}
if (nextIntersect && !nextIntersect.isIntersectionOutside) {
intersectRidge.push({ line: ridge, name: 'next' })
}
}
})
intersectRidge.forEach((intersect) => {
const line = intersect.line
if (currentRoof.attributes.planeSize >= currentWall.attributes.planeSize) {
points.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 })
} else {
if (intersect.name === 'mid') {
let lineX1 = line.x1,
lineY1 = line.y1,
lineX2 = line.x2,
lineY2 = line.y2
const prevCheck1 = Math.sqrt(Math.pow(Math.round(lineX1 - currentRoof.x1), 2) + Math.pow(Math.round(lineY1 - currentRoof.y1), 2))
const prevCheck2 = Math.sqrt(Math.pow(Math.round(lineX2 - currentRoof.x1), 2) + Math.pow(Math.round(lineY2 - currentRoof.y1), 2))
const deltaX = currentRoof.x2 - currentRoof.x1
const deltaY = currentRoof.y2 - currentRoof.y1
console.log('deltaX : ', deltaX, 'deltaY : ', deltaY)
if (prevCheck1 < prevCheck2) {
lineX1 = lineX1 - Math.sign(deltaX) * prevRoof.attributes.offset
lineY1 = lineY1 - Math.sign(deltaY) * prevRoof.attributes.offset
lineX2 = lineX2 + Math.sign(deltaX) * nextRoof.attributes.offset
lineY2 = lineY2 + Math.sign(deltaY) * nextRoof.attributes.offset
} else {
lineX1 = lineX1 + Math.sign(deltaX) * prevRoof.attributes.offset
lineY1 = lineY1 + Math.sign(deltaY) * prevRoof.attributes.offset
lineX2 = lineX2 - Math.sign(deltaX) * nextRoof.attributes.offset
lineY2 = lineY2 - Math.sign(deltaY) * nextRoof.attributes.offset
}
points.push({ x: lineX1, y: lineY1 }, { x: lineX2, y: lineY2 })
}
}
})
points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
const startPoint = points
.filter((point) => point.x === Math.min(...points.map((point) => point.x)))
.reduce((prev, current) => {
return prev.y < current.y ? prev : current
})
const sortedPoints = [startPoint]
points.forEach((p, index) => {
const lastPoint = sortedPoints[sortedPoints.length - 1]
if (index === 0) {
const underStartPoint = points.filter((point) => point.y > startPoint.y)
const nextPoint = underStartPoint
.filter((point) => point.x === startPoint.x)
.reduce((prev, current) => {
return Math.abs(prev.y - startPoint.y) < Math.abs(current.y - startPoint.y) ? prev : current
})
if (nextPoint) {
sortedPoints.push(nextPoint)
} else {
const nextPoint = underStartPoint.reduce((prev, current) => {
const prevHypos = Math.sqrt(Math.abs(Math.pow(prev.x - startPoint.x, 2)) + Math.abs(Math.pow(prev.y - startPoint.y, 2)))
const currentHypos = Math.sqrt(Math.abs(Math.pow(current.x - startPoint.x, 2)) + Math.abs(Math.pow(current.y - startPoint.y, 2)))
return prevHypos < currentHypos ? prev : current
})
sortedPoints.push(nextPoint)
}
} else {
const prevPoint = sortedPoints[sortedPoints.length - 2]
const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
const nextPoint = otherPoints.reduce((prev, current) => {
if (prev === undefined) {
const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
const adjacent = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuse = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
const angle = Math.round(
Math.acos((Math.pow(adjacent, 2) + Math.pow(height, 2) - Math.pow(hypotenuse, 2)) / (2 * adjacent * height)) * (180 / Math.PI),
)
if (angle === 90) {
return current
}
} else {
return prev
}
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
} else {
const nextPoint = otherPoints.reduce((prev, current) => {
if (prev !== undefined) {
const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuseC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
const angleC = Math.round(
Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
)
const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
const angleP = Math.round(
Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
)
if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
return current
} else {
return prev
}
} else {
return current
}
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
}
}
}
})
console.log('sortedPoints : ', sortedPoints)
if (sortedPoints.length > 0) {
const roofPolygon = new QPolygon(sortedPoints, {
fill: 'transparent',
stroke: 'blue',
strokeWidth: 1,
selectable: false,
fontSize: roof.fontSize,
name: 'roofPolygon',
attributes: { roofId: roof.id, currentRoof: currentRoof.id },
})
canvas.add(roofPolygon)
canvas.renderAll()
}
})
}
/** /**
* 한쪽흐름 지붕 * 한쪽흐름 지붕
* @param roofId * @param roofId