Merge branch 'dev'
This commit is contained in:
commit
bfa51bd24d
@ -1,6 +1,6 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
// reactStrictMode: false,
|
reactStrictMode: false,
|
||||||
webpack: (config) => {
|
webpack: (config) => {
|
||||||
config.externals.push({
|
config.externals.push({
|
||||||
"utf-8-validate": "commonjs utf-8-validate",
|
"utf-8-validate": "commonjs utf-8-validate",
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
"prisma": "^5.17.0",
|
"prisma": "^5.17.0",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/app/404.js
Normal file
23
src/app/404.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<section className="bg-white dark:bg-gray-900">
|
||||||
|
<div className="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
|
||||||
|
<div className="mx-auto max-w-screen-sm text-center">
|
||||||
|
<h1 className="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-primary-600 dark:text-primary-500">404</h1>
|
||||||
|
<p className="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white">Something's missing.</p>
|
||||||
|
<p className="mb-4 text-lg font-light text-gray-500 dark:text-gray-400">
|
||||||
|
Sorry, we can't find that page. You'll find lots to explore on the home page.{' '}
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="inline-flex text-white bg-primary-600 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:focus:ring-primary-900 my-4"
|
||||||
|
>
|
||||||
|
Back to Homepage
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
13
src/app/500.js
Normal file
13
src/app/500.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export default function ServerError() {
|
||||||
|
return (
|
||||||
|
<section className="bg-white dark:bg-gray-900">
|
||||||
|
<div className="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
|
||||||
|
<div className="mx-auto max-w-screen-sm text-center">
|
||||||
|
<h1 className="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-primary-600 dark:text-primary-500">500</h1>
|
||||||
|
<p className="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white">Internal Server Error.</p>
|
||||||
|
<p className="mb-4 text-lg font-light text-gray-500 dark:text-gray-400">We are already working to solve the problem. </p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -3,14 +3,14 @@ import { useEffect, useState } from 'react'
|
|||||||
import { Mode, useMode } from '@/hooks/useMode'
|
import { Mode, useMode } from '@/hooks/useMode'
|
||||||
import { Button } from '@nextui-org/react'
|
import { Button } from '@nextui-org/react'
|
||||||
import QRect from '@/components/fabric/QRect'
|
import QRect from '@/components/fabric/QRect'
|
||||||
import QPolygon from '@/components/fabric/QPolygon'
|
|
||||||
|
|
||||||
import RangeSlider from './ui/RangeSlider'
|
import RangeSlider from './ui/RangeSlider'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { canvasAtom, canvasListState, canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom'
|
import { canvasSizeState, fontSizeState, roofState, sortedPolygonArray } from '@/store/canvasAtom'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { getTests, getCanvasState, insertCanvasState } from '@/lib/canvas'
|
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
||||||
import { calculateIntersection2 } from '@/util/canvas-util'
|
import { calculateIntersection } from '@/util/canvas-util'
|
||||||
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
|
||||||
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')
|
||||||
@ -31,6 +31,8 @@ export default function Roof2() {
|
|||||||
|
|
||||||
const [showControl, setShowControl] = useState(false)
|
const [showControl, setShowControl] = useState(false)
|
||||||
|
|
||||||
|
const roof = useRecoilValue(roofState)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
changeMode,
|
changeMode,
|
||||||
@ -99,12 +101,10 @@ export default function Roof2() {
|
|||||||
selectable: true,
|
selectable: true,
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
},
|
},
|
||||||
canvas,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
canvas?.add(polygon)
|
canvas?.add(polygon)
|
||||||
|
|
||||||
polygon.fillCell({ width: 50, height: 30, padding: 10 })
|
// polygon.fillCell({ width: 50, height: 30, padding: 10 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,14 +186,14 @@ export default function Roof2() {
|
|||||||
]
|
]
|
||||||
|
|
||||||
const eightPoint = [
|
const eightPoint = [
|
||||||
{ x: 240, y: 130 },
|
{ x: 240.1111, y: 130.1111 },
|
||||||
{ x: 240, y: 630 },
|
{ x: 240.1111, y: 630.1111 },
|
||||||
{ x: 640, y: 630 },
|
{ x: 640.1111, y: 630.1111 },
|
||||||
{ x: 640, y: 480 },
|
{ x: 640.1111, y: 480.1111 },
|
||||||
{ x: 440, y: 480 },
|
{ x: 440.1111, y: 480.1111 },
|
||||||
{ x: 440, y: 280 },
|
{ x: 440.1111, y: 280.1111 },
|
||||||
{ x: 740, y: 280 },
|
{ x: 740.1111, y: 280.1111 },
|
||||||
{ x: 740, y: 130 },
|
{ x: 740.1111, y: 130.1111 },
|
||||||
]
|
]
|
||||||
|
|
||||||
const eightPoint2 = [
|
const eightPoint2 = [
|
||||||
@ -207,25 +207,75 @@ export default function Roof2() {
|
|||||||
{ x: 897, y: 215 },
|
{ x: 897, y: 215 },
|
||||||
]
|
]
|
||||||
|
|
||||||
if (canvas) {
|
const eightPoint3 = [
|
||||||
const polygon = new QPolygon(eightPoint, {
|
{ x: 190, y: 147 },
|
||||||
fill: 'transparent',
|
{ x: 190, y: 747 },
|
||||||
stroke: 'black',
|
{ x: 490, y: 747 },
|
||||||
strokeWidth: 1,
|
{ x: 490, y: 497 },
|
||||||
selectable: true,
|
{ x: 640, y: 497 },
|
||||||
fontSize: fontSize,
|
{ x: 640, y: 747 },
|
||||||
name: 'QPolygon1',
|
{ x: 1090, y: 747 },
|
||||||
})
|
{ x: 1090, y: 147 },
|
||||||
|
]
|
||||||
|
|
||||||
canvas?.add(polygon)
|
const eightPoint4 = [
|
||||||
|
{ x: 228, y: 92 },
|
||||||
|
{ x: 228, y: 592 },
|
||||||
|
{ x: 478, y: 592 },
|
||||||
|
{ x: 478, y: 342 },
|
||||||
|
{ x: 728, y: 342 },
|
||||||
|
{ x: 728, y: 592 },
|
||||||
|
{ x: 1078, y: 592 },
|
||||||
|
{ x: 1078, y: 92 },
|
||||||
|
]
|
||||||
|
|
||||||
console.log(polygon)
|
const twelvePoint = [
|
||||||
|
{ x: 195, y: 166 },
|
||||||
|
{ x: 195, y: 466 },
|
||||||
|
{ x: 395, y: 466 },
|
||||||
|
{ x: 395, y: 766 },
|
||||||
|
{ x: 545, y: 766 },
|
||||||
|
{ x: 545, y: 466 },
|
||||||
|
{ x: 695, y: 466 },
|
||||||
|
{ x: 695, y: 666 },
|
||||||
|
{ x: 845, y: 666 },
|
||||||
|
{ x: 845, y: 466 },
|
||||||
|
{ x: 995, y: 466 },
|
||||||
|
{ x: 995, y: 166 },
|
||||||
|
]
|
||||||
|
|
||||||
handleOuterlinesTest2(polygon)
|
const complicatedType = [
|
||||||
|
{ x: 100, y: 100 },
|
||||||
|
{ x: 100, y: 1100 },
|
||||||
|
{ x: 400, y: 1100 },
|
||||||
|
{ x: 400, y: 800 },
|
||||||
|
{ x: 700, y: 800 },
|
||||||
|
{ x: 700, y: 1100 },
|
||||||
|
{ x: 1000, y: 1100 },
|
||||||
|
{ x: 1000, y: 600 },
|
||||||
|
{ x: 700, y: 600 },
|
||||||
|
{ x: 700, y: 300 },
|
||||||
|
{ x: 1000, y: 300 },
|
||||||
|
{ x: 1000, y: 100 },
|
||||||
|
]
|
||||||
|
|
||||||
// const lines = togglePolygonLine(polygon)
|
const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint]
|
||||||
// togglePolygonLine(lines[0])
|
|
||||||
}
|
const polygon = new QPolygon(type1B, {
|
||||||
|
fill: 'transparent',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: true,
|
||||||
|
fontSize: fontSize,
|
||||||
|
name: 'QPolygon1',
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(polygon)
|
||||||
|
|
||||||
|
handleOuterlinesTest2(polygon)
|
||||||
|
|
||||||
|
// const lines = togglePolygonLine(polygon)
|
||||||
|
// togglePolygonLine(lines[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
const rotateShape = () => {
|
const rotateShape = () => {
|
||||||
@ -241,36 +291,26 @@ export default function Roof2() {
|
|||||||
|
|
||||||
const makeQLine = () => {
|
const makeQLine = () => {
|
||||||
if (canvas) {
|
if (canvas) {
|
||||||
const line = new QLine(
|
const line = new QLine([50, 250, 900, 250], {
|
||||||
[50, 250, 900, 250],
|
stroke: 'black',
|
||||||
{
|
strokeWidth: 5,
|
||||||
stroke: 'black',
|
fontSize: fontSize,
|
||||||
strokeWidth: 5,
|
selectable: true,
|
||||||
fontSize: fontSize,
|
})
|
||||||
selectable: true,
|
|
||||||
},
|
|
||||||
50,
|
|
||||||
)
|
|
||||||
|
|
||||||
const line2 = new QLine(
|
const line2 = new QLine([450, 450, 821, 78], {
|
||||||
[450, 450, 821, 78],
|
stroke: 'black',
|
||||||
{
|
strokeWidth: 5,
|
||||||
stroke: 'black',
|
fontSize: fontSize,
|
||||||
strokeWidth: 5,
|
selectable: true,
|
||||||
fontSize: fontSize,
|
})
|
||||||
selectable: true,
|
|
||||||
},
|
|
||||||
50,
|
|
||||||
)
|
|
||||||
|
|
||||||
canvas?.add(line)
|
canvas?.add(line)
|
||||||
canvas?.add(line2)
|
canvas?.add(line2)
|
||||||
|
|
||||||
const interSectionPoint = calculateIntersection2(line, line2)
|
const interSectionPoint = calculateIntersection(line, line2)
|
||||||
|
|
||||||
if (interSectionPoint) {
|
if (interSectionPoint) {
|
||||||
console.log(interSectionPoint)
|
|
||||||
|
|
||||||
const circle = new fabric.Circle({
|
const circle = new fabric.Circle({
|
||||||
radius: 5,
|
radius: 5,
|
||||||
fill: 'red',
|
fill: 'red',
|
||||||
@ -376,6 +416,13 @@ export default function Roof2() {
|
|||||||
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => drawRoofPatterns(2)}>
|
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => drawRoofPatterns(2)}>
|
||||||
지붕패턴2
|
지붕패턴2
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="m-1 p-2"
|
||||||
|
color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`}
|
||||||
|
onClick={() => changeMode(canvas, Mode.ROOT_TRESTLE)}
|
||||||
|
>
|
||||||
|
지붕가대생성
|
||||||
|
</Button>
|
||||||
<Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEXTBOX)}>
|
<Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEXTBOX)}>
|
||||||
텍스트박스 모드
|
텍스트박스 모드
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -1,112 +1,87 @@
|
|||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { getDirection, getDirectionByPoint } from '@/util/canvas-util'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { getDirection } from '@/util/canvas-util'
|
||||||
|
|
||||||
export class QLine extends fabric.Group {
|
export const QLine = fabric.util.createClass(fabric.Line, {
|
||||||
line
|
type: 'QLine',
|
||||||
text
|
text: null,
|
||||||
fontSize
|
id: null,
|
||||||
length = 0
|
line: null,
|
||||||
x1
|
length: 0,
|
||||||
y1
|
direction: null,
|
||||||
x2
|
idx: 0,
|
||||||
y2
|
initialize: function (points, options, canvas) {
|
||||||
direction
|
this.callSuper('initialize', points, options)
|
||||||
idx
|
if (options.id) {
|
||||||
type = 'QLine'
|
this.id = options.id
|
||||||
parent
|
} else {
|
||||||
isAlreadyInterSection = false
|
this.id = uuidv4()
|
||||||
|
}
|
||||||
interSectionPoints = []
|
this.line = this
|
||||||
lengthTxt = 0
|
|
||||||
|
|
||||||
initPoints
|
|
||||||
initOption
|
|
||||||
initLengthTxt
|
|
||||||
|
|
||||||
constructor(points, option = { isActiveLengthText: true }, lengthTxt) {
|
|
||||||
// 소수점 전부 제거
|
// 소수점 전부 제거
|
||||||
points.forEach((point) => {
|
points.forEach((point) => {
|
||||||
point = Math.round(point)
|
point = Math.round(point)
|
||||||
})
|
})
|
||||||
|
|
||||||
const [x1, y1, x2, y2] = points
|
|
||||||
|
|
||||||
if (!option.fontSize) {
|
|
||||||
throw new Error('Font size is required.')
|
|
||||||
}
|
|
||||||
|
|
||||||
const line = new fabric.Line(points, { ...option, strokeWidth: 1 })
|
|
||||||
super([line], {})
|
|
||||||
|
|
||||||
this.initPoints = points
|
|
||||||
this.initOption = option
|
|
||||||
this.initLengthTxt = lengthTxt
|
|
||||||
|
|
||||||
this.x1 = x1
|
|
||||||
this.y1 = y1
|
|
||||||
this.x2 = x2
|
|
||||||
this.y2 = y2
|
|
||||||
this.line = line
|
|
||||||
this.fontSize = option.fontSize
|
|
||||||
this.direction = option.direction ?? getDirectionByPoint({ x: x1, y: y1 }, { x: x2, y: y2 })
|
|
||||||
this.parent = option.parent
|
|
||||||
this.idx = option.idx
|
|
||||||
|
|
||||||
if (lengthTxt > 0) {
|
|
||||||
this.lengthTxt = Number(lengthTxt)
|
|
||||||
}
|
|
||||||
|
|
||||||
option.isActiveLengthText ?? this.init()
|
|
||||||
this.addControl()
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this.addLengthText(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
addControl() {
|
|
||||||
this.on('moving', () => {
|
|
||||||
this.addLengthText(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.on('modified', (e) => {
|
|
||||||
this.addLengthText(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.on('selected', () => {
|
|
||||||
console.log(this)
|
|
||||||
Object.keys(this.controls).forEach((controlKey) => {
|
|
||||||
if (controlKey !== 'ml' && controlKey !== 'mr') {
|
|
||||||
this.setControlVisible(controlKey, false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
addLengthText(isFirst) {
|
|
||||||
if (this.text) {
|
|
||||||
this.removeWithUpdate(this.text)
|
|
||||||
this.text = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFirst && this.lengthTxt > 0) {
|
|
||||||
const text = new fabric.Textbox(this.lengthTxt.toFixed(0).toString(), {
|
|
||||||
left: (this.x1 + this.x2) / 2,
|
|
||||||
top: (this.y1 + this.y2) / 2,
|
|
||||||
fontSize: this.fontSize,
|
|
||||||
})
|
|
||||||
this.length = this.lengthTxt
|
|
||||||
this.text = text
|
|
||||||
this.addWithUpdate(text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const scaleX = this.scaleX
|
const scaleX = this.scaleX
|
||||||
const scaleY = this.scaleY
|
const scaleY = this.scaleY
|
||||||
const x1 = this.left
|
const x1 = this.left
|
||||||
const y1 = this.top
|
const y1 = this.top
|
||||||
const x2 = this.left + this.width * scaleX
|
const x2 = this.left + this.width * scaleX
|
||||||
const y2 = this.top + this.height * scaleY
|
const y2 = this.top + this.height * scaleY
|
||||||
|
this.idx = options.idx ?? 0
|
||||||
|
const dx = x2 - x1
|
||||||
|
const dy = y2 - y1
|
||||||
|
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
|
||||||
|
|
||||||
|
this.direction = options.direction ?? getDirection({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 })
|
||||||
|
|
||||||
|
if (canvas) {
|
||||||
|
this.canvas = canvas
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toObject: function (propertiesToInclude) {
|
||||||
|
return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {
|
||||||
|
type: this.type,
|
||||||
|
text: this.text,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init: function () {
|
||||||
|
this.addLengthText()
|
||||||
|
|
||||||
|
this.on('moving', () => {
|
||||||
|
this.addLengthText()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('modified', (e) => {
|
||||||
|
this.addLengthText()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('removed', () => {
|
||||||
|
const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
|
||||||
|
if (thisText) {
|
||||||
|
this.canvas.remove(thisText)
|
||||||
|
}
|
||||||
|
this.text = null
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
addLengthText() {
|
||||||
|
const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
|
||||||
|
|
||||||
|
const scaleX = this.scaleX
|
||||||
|
const scaleY = this.scaleY
|
||||||
|
const x1 = this.left
|
||||||
|
const y1 = this.top
|
||||||
|
const x2 = this.left + this.width * scaleX
|
||||||
|
const y2 = this.top + this.height * scaleY
|
||||||
|
|
||||||
|
if (thisText) {
|
||||||
|
thisText.set({ text: this.length.toFixed(0).toString(), left: (x1 + x2) / 2, top: (y1 + y2) / 2 })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const dx = x2 - x1
|
const dx = x2 - x1
|
||||||
const dy = y2 - y1
|
const dy = y2 - y1
|
||||||
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
|
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
|
||||||
@ -115,51 +90,27 @@ export class QLine extends fabric.Group {
|
|||||||
left: (x1 + x2) / 2,
|
left: (x1 + x2) / 2,
|
||||||
top: (y1 + y2) / 2,
|
top: (y1 + y2) / 2,
|
||||||
fontSize: this.fontSize,
|
fontSize: this.fontSize,
|
||||||
|
selectable: false,
|
||||||
|
parentId: this.id,
|
||||||
|
name: 'lengthText',
|
||||||
})
|
})
|
||||||
this.text = text
|
|
||||||
this.addWithUpdate(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.text = text
|
||||||
|
this.canvas.add(text)
|
||||||
|
},
|
||||||
setFontSize(fontSize) {
|
setFontSize(fontSize) {
|
||||||
this.fontSize = fontSize
|
this.fontSize = fontSize
|
||||||
this.text.set({ fontSize })
|
this.text.set({ fontSize })
|
||||||
this.addWithUpdate()
|
},
|
||||||
}
|
_render: function (ctx) {
|
||||||
|
this.callSuper('_render', ctx)
|
||||||
fromObject(object, callback) {
|
this.init()
|
||||||
console.log('fromObject', object, callback)
|
},
|
||||||
}
|
_set: function (key, value) {
|
||||||
|
|
||||||
async = true
|
|
||||||
|
|
||||||
toObject(propertiesToInclude) {
|
|
||||||
return fabric.util.object.extend(this.callSuper('toObject'), {
|
|
||||||
length: this.length,
|
|
||||||
line: this.line,
|
|
||||||
text: this.text,
|
|
||||||
fontSize: this.fontSize,
|
|
||||||
x1: this.x1,
|
|
||||||
y1: this.y1,
|
|
||||||
x2: this.x2,
|
|
||||||
y2: this.y2,
|
|
||||||
direction: this.direction,
|
|
||||||
idx: this.idx,
|
|
||||||
type: this.type,
|
|
||||||
parent: this.parent,
|
|
||||||
isAlreadyInterSection: this.isAlreadyInterSection,
|
|
||||||
interSectionPoints: this.interSectionPoints,
|
|
||||||
lengthTxt: this.lengthTxt,
|
|
||||||
setFontSize: this.setFontSize,
|
|
||||||
addLengthText: this.addLengthText,
|
|
||||||
init: this.init,
|
|
||||||
addControl: this.addControl,
|
|
||||||
initPoints: this.initPoints,
|
|
||||||
initOption: this.initOption,
|
|
||||||
initLengthTxt: this.initLengthTxt,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
_set(key, value) {
|
|
||||||
this.callSuper('_set', key, value)
|
this.callSuper('_set', key, value)
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
setCanvas(canvas) {
|
||||||
|
this.canvas = canvas
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@ import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/can
|
|||||||
|
|
||||||
import { useRecoilState } from 'recoil'
|
import { useRecoilState } from 'recoil'
|
||||||
import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
|
import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
|
||||||
import QPolygon from '@/components/fabric/QPolygon'
|
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import QRect from '@/components/fabric/QRect'
|
import QRect from '@/components/fabric/QRect'
|
||||||
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
|
||||||
export function useCanvas(id) {
|
export function useCanvas(id) {
|
||||||
const [canvas, setCanvas] = useState()
|
const [canvas, setCanvas] = useState()
|
||||||
@ -110,28 +110,25 @@ export function useCanvas(id) {
|
|||||||
fabric.Object.prototype.cornerStyle = 'rect'
|
fabric.Object.prototype.cornerStyle = 'rect'
|
||||||
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'
|
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'
|
||||||
fabric.Object.prototype.cornerSize = 6
|
fabric.Object.prototype.cornerSize = 6
|
||||||
|
fabric.QLine = QLine
|
||||||
|
fabric.QPolygon = QPolygon
|
||||||
QPolygon.prototype.canvas = canvas
|
QPolygon.prototype.canvas = canvas
|
||||||
QLine.prototype.canvas = canvas
|
QLine.prototype.canvas = canvas
|
||||||
QRect.prototype.canvas = canvas
|
QRect.prototype.canvas = canvas
|
||||||
|
|
||||||
fabric.QLine = fabric.util.createClass(fabric.Group, {})
|
|
||||||
fabric.QPolygon = fabric.util.createClass(fabric.Group, {})
|
|
||||||
|
|
||||||
// fromObject 메서드를 QLine 클래스에 직접 추가
|
|
||||||
fabric.QLine.fromObject = function (object, callback) {
|
fabric.QLine.fromObject = function (object, callback) {
|
||||||
const { initOption, initPoints, initLengthTxt } = object
|
function _callback(instance) {
|
||||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
delete instance.points
|
||||||
return callback(new QLine(initPoints, initOption, initLengthTxt))
|
callback && callback(instance)
|
||||||
})
|
}
|
||||||
|
const options = fabric.util.object.clone(object, true)
|
||||||
|
options.points = [object.x1, object.y1, object.x2, object.y2]
|
||||||
|
|
||||||
|
fabric.Object._fromObject('QLine', options, _callback, 'points')
|
||||||
}
|
}
|
||||||
|
|
||||||
// fromObject 메서드를 QLine 클래스에 직접 추가
|
|
||||||
fabric.QPolygon.fromObject = function (object, callback) {
|
fabric.QPolygon.fromObject = function (object, callback) {
|
||||||
const { initOption, initPoints, initLengthTxt } = object
|
fabric.Object._fromObject('QPolygon', object, callback, 'points')
|
||||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
|
||||||
return callback(new QPolygon(initPoints, initOption, initLengthTxt))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,44 +553,19 @@ export function useCanvas(id) {
|
|||||||
const addCanvas = () => {
|
const addCanvas = () => {
|
||||||
// const canvasState = canvas
|
// const canvasState = canvas
|
||||||
|
|
||||||
const objs = canvas
|
const objs = canvas?.toJSON(['selectable', 'name', 'parentId', 'id', 'length', 'idx', 'direction', 'lines', 'points'])
|
||||||
|
|
||||||
console.log(objs)
|
|
||||||
const str = JSON.stringify(objs)
|
const str = JSON.stringify(objs)
|
||||||
|
|
||||||
canvas?.clear()
|
canvas?.clear()
|
||||||
|
|
||||||
console.log(str)
|
|
||||||
console.log(JSON.parse(str))
|
|
||||||
|
|
||||||
// 역직렬화하여 캔버스에 객체를 다시 추가합니다.
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
canvas?.loadFromJSON(
|
// 역직렬화하여 캔버스에 객체를 다시 추가합니다.
|
||||||
JSON.parse(str),
|
canvas?.loadFromJSON(JSON.parse(str), function () {
|
||||||
function () {
|
// 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다.
|
||||||
// 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다.
|
canvas?.renderAll() // 캔버스를 다시 그립니다.
|
||||||
canvas?.renderAll() // 캔버스를 다시 그립니다.
|
})
|
||||||
console.log('Objects are reloaded and rendered on canvas.')
|
|
||||||
},
|
|
||||||
function (o, object) {
|
|
||||||
// 각 객체가 로드될 때마다 호출됩니다.
|
|
||||||
console.log('Object loaded: ', o, object)
|
|
||||||
|
|
||||||
canvas?.add(object)
|
|
||||||
canvas?.renderAll()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
/*canvas?.loadFromJSON(JSON.parse(str), () => {
|
|
||||||
console.log('load done')
|
|
||||||
})*/
|
|
||||||
|
|
||||||
/*const stateArr = canvasState.map((state) => state.getObject().getObjects())
|
|
||||||
|
|
||||||
const newCanvasList = [...canvasList, JSON.stringify(stateArr)]
|
|
||||||
|
|
||||||
setCanvasList(newCanvasList)*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeCanvas = (idx) => {
|
const changeCanvas = (idx) => {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -41,3 +41,15 @@ export const roofPolygonPatternArrayState = atom({
|
|||||||
default: {}, //object ex) big, mid, sht = {point : [{x1, y1}, {x2, y1}], direction : left or right or top or bottom}
|
default: {}, //object ex) big, mid, sht = {point : [{x1, y1}, {x2, y1}], direction : left or right or top or bottom}
|
||||||
dangerouslyAllowMutability: true,
|
dangerouslyAllowMutability: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const roofPolygonArrayState = atom({
|
||||||
|
key: 'roofPolygonArray',
|
||||||
|
default: [],
|
||||||
|
dangerouslyAllowMutability: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const templateTypeState = atom({
|
||||||
|
key: 'templateType',
|
||||||
|
default: 1, //1:모임지붕, 2:A타입, 3:B타입
|
||||||
|
dangerouslyAllowMutability: true,
|
||||||
|
})
|
||||||
|
|||||||
@ -292,56 +292,6 @@ export const getDirectionByPoint = (a, b) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 두 선분의 교차점을 찾는 함수입니다. 이 함수는 두 선분이 실제로 교차하는 지점 내에서 교차하는지 확인합니다.
|
|
||||||
* @param {Object} line1 첫 번째 선분, {x1, y1, x2, y2} 형태의 객체
|
|
||||||
* @param {Object} line2 두 번째 선분, {x1, y1, x2, y2} 형태의 객체
|
|
||||||
* @returns {{x: number, y: number}|null} 교차점의 좌표를 반환하거나, 교차점이 없으면 null을 반환합니다.
|
|
||||||
*/
|
|
||||||
export function calculateIntersection(line1, line2) {
|
|
||||||
const { x1: x1_1, y1: y1_1, x2: x2_1, y2: y2_1 } = line1
|
|
||||||
const { x1: x1_2, y1: y1_2, x2: x2_2, y2: y2_2 } = line2
|
|
||||||
|
|
||||||
const denominator = (x1_1 - x2_1) * (y1_2 - y2_2) - (y1_1 - y2_1) * (x1_2 - x2_2)
|
|
||||||
if (denominator === 0) return null // 선분이 평행하거나 일치하는 경우
|
|
||||||
|
|
||||||
const t = ((x1_1 - x1_2) * (y1_2 - y2_2) - (y1_1 - y1_2) * (x1_2 - x2_2)) / denominator
|
|
||||||
const u = -((x1_1 - x2_1) * (y1_1 - y1_2) - (y1_1 - y2_1) * (x1_1 - x1_2)) / denominator
|
|
||||||
|
|
||||||
// t와 u가 모두 0과 1 사이에 있을 때, 선분 내에서 교차
|
|
||||||
if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
|
|
||||||
const intersectionX = x1_1 + t * (x2_1 - x1_1)
|
|
||||||
const intersectionY = y1_1 + t * (y2_1 - y1_1)
|
|
||||||
|
|
||||||
// Determine the min and max for line1 and line2 for both x and y
|
|
||||||
const line1MinX = Math.min(line1.x1, line1.x2)
|
|
||||||
const line1MaxX = Math.max(line1.x1, line1.x2)
|
|
||||||
const line2MinX = Math.min(line2.x1, line2.x2)
|
|
||||||
const line2MaxX = Math.max(line2.x1, line2.x2)
|
|
||||||
|
|
||||||
const line1MinY = Math.min(line1.y1, line1.y2)
|
|
||||||
const line1MaxY = Math.max(line1.y1, line1.y2)
|
|
||||||
const line2MinY = Math.min(line2.y1, line2.y2)
|
|
||||||
const line2MaxY = Math.max(line2.y1, line2.y2)
|
|
||||||
|
|
||||||
// 교차점이 선분의 범위 내에 있는지 확인
|
|
||||||
if (
|
|
||||||
intersectionX >= line1MinX &&
|
|
||||||
intersectionX <= line1MaxX &&
|
|
||||||
intersectionX >= line2MinX &&
|
|
||||||
intersectionX <= line2MaxX &&
|
|
||||||
intersectionY >= line1MinY &&
|
|
||||||
intersectionY <= line1MaxY &&
|
|
||||||
intersectionY >= line2MinY &&
|
|
||||||
intersectionY <= line2MaxY
|
|
||||||
) {
|
|
||||||
return { x: Math.round(intersectionX), y: Math.round(intersectionY) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null // 교차점이 선분의 범위 내에 없음
|
|
||||||
}
|
|
||||||
|
|
||||||
export const findIntersection1 = (line1, line2) => {
|
export const findIntersection1 = (line1, line2) => {
|
||||||
const { x1, y1, x2, y2 } = line1 // 첫 번째 선의 두 점
|
const { x1, y1, x2, y2 } = line1 // 첫 번째 선의 두 점
|
||||||
|
|
||||||
@ -372,7 +322,7 @@ export const findIntersection1 = (line1, line2) => {
|
|||||||
return { x, y }
|
return { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const calculateIntersection2 = (line1, line2) => {
|
export const calculateIntersection = (line1, line2) => {
|
||||||
const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2])
|
const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2])
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@ -424,6 +374,55 @@ export function findOrthogonalPoint(line1, line2) {
|
|||||||
* @param points
|
* @param points
|
||||||
*/
|
*/
|
||||||
export const sortedPoints = (points) => {
|
export const sortedPoints = (points) => {
|
||||||
|
const copyPoints = [...points]
|
||||||
|
copyPoints.forEach((point) => {
|
||||||
|
point.x1 = point.x
|
||||||
|
point.y1 = point.y
|
||||||
|
const nextPoint = copyPoints[(copyPoints.indexOf(point) + 1) % copyPoints.length]
|
||||||
|
point.x2 = nextPoint.x
|
||||||
|
point.y2 = nextPoint.y
|
||||||
|
})
|
||||||
|
|
||||||
|
// copyPoint에서 x1, y1 값을 기준으로 시작 인덱스
|
||||||
|
const startIndex = getStartIndex(copyPoints)
|
||||||
|
const startDirection = getDirectionByPoint(
|
||||||
|
{ x: copyPoints[startIndex].x1, y: copyPoints[startIndex].y1 },
|
||||||
|
{ x: copyPoints[startIndex].x2, y: copyPoints[startIndex].y2 },
|
||||||
|
)
|
||||||
|
|
||||||
|
const resultPoints = [copyPoints[startIndex]]
|
||||||
|
|
||||||
|
let currentPoint = copyPoints[startIndex]
|
||||||
|
|
||||||
|
switch (startDirection) {
|
||||||
|
case 'right': {
|
||||||
|
copyPoints.forEach((point, index) => {
|
||||||
|
if (index === startIndex) return
|
||||||
|
|
||||||
|
const nextPoint = copyPoints.find((p) => p.x2 === currentPoint.x && p.y2 === currentPoint.y)
|
||||||
|
resultPoints.push(nextPoint)
|
||||||
|
currentPoint = nextPoint
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'bottom': {
|
||||||
|
copyPoints.forEach((point, index) => {
|
||||||
|
if (index === startIndex) return
|
||||||
|
|
||||||
|
const nextPoint = copyPoints.find((p) => p.x1 === currentPoint.x2 && p.y1 === currentPoint.y2)
|
||||||
|
resultPoints.push(nextPoint)
|
||||||
|
currentPoint = nextPoint
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultPoints.map((point) => {
|
||||||
|
return { x: point.x, y: point.y }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sortedPointLessEightPoint = (points) => {
|
||||||
const copyPoints = [...points]
|
const copyPoints = [...points]
|
||||||
//points를 x,y좌표를 기준으로 정렬합니다.
|
//points를 x,y좌표를 기준으로 정렬합니다.
|
||||||
copyPoints.sort((a, b) => {
|
copyPoints.sort((a, b) => {
|
||||||
@ -433,10 +432,6 @@ export const sortedPoints = (points) => {
|
|||||||
return a.x - b.x
|
return a.x - b.x
|
||||||
})
|
})
|
||||||
|
|
||||||
// 이때 copyPoints를 순회하며 최초엔 x값을 비교하여 같은 점을 찾는다. 이때 이 점이 2번째 점이 된다.
|
|
||||||
// 그 다음점은 2번째 점과 y값이 같은 점이 된다.
|
|
||||||
// 또 그다음 점은 3번째 점과 x값이 같은 점이 된다.
|
|
||||||
// 이를 반복하여 copyPoints를 재배열한다.
|
|
||||||
const resultPoints = [copyPoints[0]]
|
const resultPoints = [copyPoints[0]]
|
||||||
let index = 1
|
let index = 1
|
||||||
let currentPoint = { ...copyPoints[0] }
|
let currentPoint = { ...copyPoints[0] }
|
||||||
@ -649,3 +644,26 @@ export function removeDuplicatePoints(points) {
|
|||||||
|
|
||||||
return uniquePoints
|
return uniquePoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* x,y가 다르면서 가장 가까운 점
|
||||||
|
* @param targetPoint
|
||||||
|
* @param points
|
||||||
|
* @returns {null}
|
||||||
|
*/
|
||||||
|
export function findClosestPointWithDifferentXY(targetPoint, points) {
|
||||||
|
let closestPoint = null
|
||||||
|
let smallestDistance = Infinity
|
||||||
|
|
||||||
|
points.forEach((point) => {
|
||||||
|
if (point.x !== targetPoint.x && point.y !== targetPoint.y) {
|
||||||
|
const distance = Math.sqrt(Math.pow(point.x - targetPoint.x, 2) + Math.pow(point.y - targetPoint.y, 2))
|
||||||
|
if (distance < smallestDistance) {
|
||||||
|
smallestDistance = distance
|
||||||
|
closestPoint = point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return closestPoint
|
||||||
|
}
|
||||||
|
|||||||
@ -2,11 +2,8 @@ import { fabric } from 'fabric'
|
|||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
|
|
||||||
export const defineQLine = () => {
|
export const defineQLine = () => {
|
||||||
fabric.QLine = fabric.util.createClass(fabric.Group, {})
|
/*fabric.QLine = QLine
|
||||||
fabric.QLine.fromObject = function (object, callback) {
|
fabric.QLine.fromObject = (object, callback) => {
|
||||||
const { initOption, initPoints, initLengthTxt } = object
|
return new fabric.QLine([object.x1, object.y1, object.x2, object.y2], object)
|
||||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
}*/
|
||||||
return callback(new QLine(initPoints, initOption, initLengthTxt))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,312 @@
|
|||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import QPolygon from '@/components/fabric/QPolygon'
|
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { calculateIntersection, calculateIntersection2, distanceBetweenPoints, findIntersection1, removeDuplicatePoints } from '@/util/canvas-util'
|
import { calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
|
||||||
|
|
||||||
export const defineQPloygon = () => {
|
export const defineQPloygon = () => {
|
||||||
fabric.QPolygon = fabric.util.createClass(fabric.Group, {})
|
|
||||||
// fromObject 메서드를 QLine 클래스에 직접 추가
|
|
||||||
fabric.QPolygon.fromObject = function (object, callback) {
|
fabric.QPolygon.fromObject = function (object, callback) {
|
||||||
const { initOption, initPoints, initLengthTxt } = object
|
fabric.Object._fromObject('QPolygon', object, callback, 'points')
|
||||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
|
||||||
return callback(new QPolygon(initPoints, initOption, initLengthTxt))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const drawHelpLineInHexagon2 = (polygon, chon) => {
|
export const drawHelpLineInHexagon = (polygon, chon) => {
|
||||||
const oneSideLines = [...polygon.lines].map((line) => {
|
const centerLines = drawCenterLines(polygon)
|
||||||
|
|
||||||
|
let helpLines = []
|
||||||
|
|
||||||
|
const interSectionPoints = []
|
||||||
|
const tempInterSectionPoints = []
|
||||||
|
|
||||||
|
const ridgeStartPoints = []
|
||||||
|
const ridgeEndPoints = []
|
||||||
|
|
||||||
|
const centerInterSectionPoints = []
|
||||||
|
|
||||||
|
// polygon.lines = polygon.lines.sort((a, b) => a.length - b.length)
|
||||||
|
polygon.wall.lines = getOneSideLines(polygon.wall)
|
||||||
|
|
||||||
|
const maxLength = Math.max(...polygon.lines.map((line) => line.length))
|
||||||
|
|
||||||
|
polygon.points.forEach((point, index) => {
|
||||||
|
const wallPoint = polygon.wall.points[index]
|
||||||
|
|
||||||
|
const angle = Math.atan2(wallPoint.y - point.y, wallPoint.x - point.x)
|
||||||
|
|
||||||
|
const degree = fabric.util.radiansToDegrees(angle)
|
||||||
|
|
||||||
|
const newX2 = Math.floor(point.x + maxLength * Math.cos(angle))
|
||||||
|
const newY2 = Math.floor(point.y + maxLength * Math.sin(angle))
|
||||||
|
|
||||||
|
const helpLine = new QLine([point.x, point.y, newX2, newY2], {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'green',
|
||||||
|
startPoint: point,
|
||||||
|
degree: degree,
|
||||||
|
idx: index,
|
||||||
|
})
|
||||||
|
|
||||||
|
// polygon.canvas?.add(helpLine)
|
||||||
|
|
||||||
|
helpLines.push(helpLine)
|
||||||
|
})
|
||||||
|
|
||||||
|
helpLines.forEach((line, index) => {
|
||||||
|
for (let i = index + 1; i < helpLines.length; i++) {
|
||||||
|
const nextLine = helpLines[i]
|
||||||
|
if (!line.connectedPoint) {
|
||||||
|
line.connectedPoint = null
|
||||||
|
line.connectedPoints = []
|
||||||
|
}
|
||||||
|
if (!nextLine.connectedPoint) {
|
||||||
|
nextLine.connectedPoint = null
|
||||||
|
nextLine.connectedPoints = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const interSectionPoint = calculateIntersection(line, nextLine)
|
||||||
|
|
||||||
|
if (
|
||||||
|
interSectionPoint &&
|
||||||
|
polygon.inPolygon(interSectionPoint) &&
|
||||||
|
polygon.wall.inPolygon(interSectionPoint) &&
|
||||||
|
Math.abs(distanceBetweenPoints(line.startPoint, interSectionPoint) - distanceBetweenPoints(nextLine.startPoint, interSectionPoint)) < 2
|
||||||
|
) {
|
||||||
|
const area = calculateTriangleArea(line.startPoint, nextLine.startPoint, interSectionPoint)
|
||||||
|
const currentLineConnectedPoint = line.connectedPoint
|
||||||
|
const nextLineConnectedPoint = nextLine.connectedPoint
|
||||||
|
|
||||||
|
if (area <= 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLineConnectedPoint && currentLineConnectedPoint.area < area) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//startPoint는 line의 startPoint와 nextLine의 startPoint를 비교하여 x가 같은경우 y가 더 작은 값, y가 같은경우 x가 더 작은 값을 선택한다.
|
||||||
|
const startPoint =
|
||||||
|
line.startPoint.x === nextLine.startPoint.x
|
||||||
|
? line.startPoint.y < nextLine.startPoint.y
|
||||||
|
? line.startPoint
|
||||||
|
: nextLine.startPoint
|
||||||
|
: line.startPoint.x < nextLine.startPoint.x
|
||||||
|
? line.startPoint
|
||||||
|
: nextLine.startPoint
|
||||||
|
|
||||||
|
const endPoint =
|
||||||
|
line.startPoint.x === nextLine.startPoint.x
|
||||||
|
? line.startPoint.y > nextLine.startPoint.y
|
||||||
|
? line.startPoint
|
||||||
|
: nextLine.startPoint
|
||||||
|
: line.startPoint.x > nextLine.startPoint.x
|
||||||
|
? line.startPoint
|
||||||
|
: nextLine.startPoint
|
||||||
|
|
||||||
|
line.connectedPoint = { interSectionPoint, area, startPoint, endPoint }
|
||||||
|
line.connectedPoints.push(interSectionPoint)
|
||||||
|
nextLine.connectedPoint = { interSectionPoint, area, startPoint, endPoint }
|
||||||
|
nextLine.connectedPoints.push(interSectionPoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
helpLines.forEach((line) => {
|
||||||
|
if (line.connectedPoint) {
|
||||||
|
tempInterSectionPoints.push(line.connectedPoint)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// interSectionPoints에서 interSectionPoint가 중복인 값이 있는 경우만 선택한다.
|
||||||
|
tempInterSectionPoints.forEach((point) => {
|
||||||
|
// intersectionPoint가 중복인 경우
|
||||||
|
const isDuplicated =
|
||||||
|
tempInterSectionPoints.filter((p) => p.interSectionPoint.x === point.interSectionPoint.x && p.interSectionPoint.y === point.interSectionPoint.y)
|
||||||
|
.length > 1
|
||||||
|
if (isDuplicated) {
|
||||||
|
interSectionPoints.push(point)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// interSectionPoints에서 interSectionPoint 기준으로 중복을 제거한다.
|
||||||
|
const uniqueInterSectionPoints = Array.from(
|
||||||
|
new Set(interSectionPoints.map((point) => `${point.interSectionPoint.x},${point.interSectionPoint.y}`)),
|
||||||
|
).map((key) => {
|
||||||
|
const { interSectionPoint, area, startPoint, endPoint } = interSectionPoints.find(
|
||||||
|
(point) => `${point.interSectionPoint.x},${point.interSectionPoint.y}` === key,
|
||||||
|
)
|
||||||
|
return { interSectionPoint, area, startPoint, endPoint }
|
||||||
|
})
|
||||||
|
|
||||||
|
uniqueInterSectionPoints.forEach((point) => {
|
||||||
|
ridgeStartPoints.push(point.interSectionPoint)
|
||||||
|
|
||||||
|
const line = new QLine([point.startPoint.x, point.startPoint.y, point.interSectionPoint.x, point.interSectionPoint.y], {
|
||||||
|
stroke: 'purple',
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
name: 'hip',
|
||||||
|
})
|
||||||
|
|
||||||
|
const line2 = new QLine([point.endPoint.x, point.endPoint.y, point.interSectionPoint.x, point.interSectionPoint.y], {
|
||||||
|
stroke: 'purple',
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
name: 'hip',
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.hips.push(line)
|
||||||
|
polygon.hips.push(line2)
|
||||||
|
|
||||||
|
polygon.canvas.add(line)
|
||||||
|
polygon.canvas.add(line2)
|
||||||
|
})
|
||||||
|
|
||||||
|
const removedIdx = []
|
||||||
|
|
||||||
|
helpLines.forEach((line) => {
|
||||||
|
const connectedPoints = line.connectedPoints
|
||||||
|
connectedPoints.forEach((connectedPoint) => {
|
||||||
|
uniqueInterSectionPoints.forEach((point) => {
|
||||||
|
const interSectionPoint = point.interSectionPoint
|
||||||
|
|
||||||
|
if (connectedPoint.x === interSectionPoint.x && connectedPoint.y === interSectionPoint.y) {
|
||||||
|
removedIdx.push(line.idx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const notIntersectedLines = helpLines.filter((line) => !removedIdx.includes(line.idx))
|
||||||
|
|
||||||
|
notIntersectedLines.forEach((line) => {
|
||||||
|
centerLines.forEach((centerLine) => {
|
||||||
|
const interSectionPoint = calculateIntersection(line, centerLine)
|
||||||
|
|
||||||
|
if (interSectionPoint && polygon.inPolygon(interSectionPoint) && polygon.wall.inPolygon(interSectionPoint)) {
|
||||||
|
centerInterSectionPoints.push(interSectionPoint)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// centerInterSectionPoints에서 ridgeStartPoints와 x가 같거나 y가 같은것중 가장 가까운 점들을 찾는다.
|
||||||
|
ridgeStartPoints.forEach((point) => {
|
||||||
|
const xPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.x - point.x) < 2)
|
||||||
|
const yPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.y - point.y) < 2)
|
||||||
|
let closestPoint
|
||||||
|
if (xPoints.length === 0) {
|
||||||
|
closestPoint = findClosestPoint(point, yPoints)
|
||||||
|
} else {
|
||||||
|
closestPoint = findClosestPoint(point, xPoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closestPoint) {
|
||||||
|
const line = new QLine([point.x, point.y, closestPoint.x, closestPoint.y], {
|
||||||
|
stroke: 'purple',
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
name: 'ridge',
|
||||||
|
})
|
||||||
|
polygon.ridges.push(line)
|
||||||
|
polygon.canvas.add(line)
|
||||||
|
ridgeEndPoints.push(closestPoint)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ridgeEndPoints끼리 이어준다.
|
||||||
|
const remainingPoints = ridgeEndPoints
|
||||||
|
|
||||||
|
remainingPoints.forEach((ridgePoint) => {
|
||||||
|
polygon.points.forEach((point) => {
|
||||||
|
const degree = calculateAngle(ridgePoint, point)
|
||||||
|
|
||||||
|
if (Math.abs(degree) % 45 < 1) {
|
||||||
|
const line = new QLine([ridgePoint.x, ridgePoint.y, point.x, point.y], {
|
||||||
|
stroke: 'purple',
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
name: 'hip',
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.hips.push(line)
|
||||||
|
polygon.canvas.add(line)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
while (remainingPoints.length > 0) {
|
||||||
|
const point = remainingPoints.shift()
|
||||||
|
const closestPoint = findClosestPoint(point, remainingPoints)
|
||||||
|
if (!closestPoint) continue
|
||||||
|
// 마루끼리 연결
|
||||||
|
const line = new QLine([point.x, point.y, closestPoint.x, closestPoint.y], {
|
||||||
|
stroke: 'purple',
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
name: 'connectRidge',
|
||||||
|
})
|
||||||
|
polygon.connectRidges.push(line)
|
||||||
|
|
||||||
|
polygon.canvas.add(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const drawCenterLines = (polygon) => {
|
||||||
|
const centerLines = []
|
||||||
|
|
||||||
|
const oneSideLines = getOneSideLines(polygon)
|
||||||
|
|
||||||
|
const horizontalLines = oneSideLines.filter((line) => line.direction === 'right')
|
||||||
|
const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom')
|
||||||
|
// horizontalLines 를 y1 좌표 기준으로 정렬한다.
|
||||||
|
horizontalLines.sort((a, b) => a.y1 - b.y1)
|
||||||
|
// verticalLines 를 x1 좌표 기준으로 정렬한다.
|
||||||
|
verticalLines.sort((a, b) => a.x1 - b.x1)
|
||||||
|
|
||||||
|
let maxHorizontalLineLength = 0
|
||||||
|
let maxVerticalLineLength = 0
|
||||||
|
// 모든 가로선의 중심선을 긋는다.
|
||||||
|
horizontalLines.forEach((line, index) => {
|
||||||
|
const nextLine = horizontalLines[(index + 1) % horizontalLines.length]
|
||||||
|
|
||||||
|
line.set({ strokeWidth: 5 })
|
||||||
|
nextLine.set({ strokeWidth: 5 })
|
||||||
|
|
||||||
|
polygon.canvas.renderAll()
|
||||||
|
|
||||||
|
const startCenterX = Math.min(line.x1, nextLine.x1)
|
||||||
|
const startCenterY = (line.y1 + nextLine.y1) / 2
|
||||||
|
|
||||||
|
const endCenterX = line.x2 > nextLine.x2 ? line.x2 : nextLine.x2
|
||||||
|
const endCenterY = startCenterY
|
||||||
|
|
||||||
|
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'red',
|
||||||
|
strokeWidth: 1,
|
||||||
|
direction: 'horizontal',
|
||||||
|
})
|
||||||
|
|
||||||
|
centerLines.push(centerLine)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 모든 세로선의 중심선을 긋는다.
|
||||||
|
verticalLines.forEach((line, index) => {
|
||||||
|
const nextLine = verticalLines[(index + 1) % verticalLines.length]
|
||||||
|
|
||||||
|
const startCenterX = (line.x1 + nextLine.x1) / 2
|
||||||
|
const startCenterY = Math.min(line.y1, nextLine.y1)
|
||||||
|
|
||||||
|
const endCenterX = startCenterX
|
||||||
|
let endCenterY = line.y2 > nextLine.y2 ? line.y2 : nextLine.y2
|
||||||
|
|
||||||
|
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'blue',
|
||||||
|
strokeWidth: 1,
|
||||||
|
direction: 'vertical',
|
||||||
|
})
|
||||||
|
|
||||||
|
centerLines.push(centerLine)
|
||||||
|
})
|
||||||
|
|
||||||
|
return centerLines
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOneSideLines = (polygon) => {
|
||||||
|
return [...polygon.lines].map((line) => {
|
||||||
let newX1, newY1, newX2, newY2
|
let newX1, newY1, newX2, newY2
|
||||||
if (line.direction === 'top') {
|
if (line.direction === 'top') {
|
||||||
newX1 = line.x2
|
newX1 = line.x2
|
||||||
@ -42,288 +333,45 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => {
|
|||||||
}
|
}
|
||||||
return line
|
return line
|
||||||
})
|
})
|
||||||
|
}
|
||||||
const centerLines = []
|
const calculateAngle = (point1, point2) => {
|
||||||
const helpLines = []
|
const deltaX = point2.x - point1.x
|
||||||
const ridgeStartPoints = []
|
const deltaY = point2.y - point1.y
|
||||||
|
const angleInRadians = Math.atan2(deltaY, deltaX)
|
||||||
const horizontalLines = oneSideLines.filter((line) => line.direction === 'right')
|
return angleInRadians * (180 / Math.PI)
|
||||||
const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom')
|
|
||||||
// horizontalLines 를 y1 좌표 기준으로 정렬한다.
|
|
||||||
horizontalLines.sort((a, b) => a.y1 - b.y1)
|
|
||||||
// verticalLines 를 x1 좌표 기준으로 정렬한다.
|
|
||||||
verticalLines.sort((a, b) => a.x1 - b.x1)
|
|
||||||
|
|
||||||
const maxHorizontalLineLength = horizontalLines.reduce((prev, current) => (prev.length > current.length ? prev.length : current.length))
|
|
||||||
const maxVerticalLineLength = verticalLines.reduce((prev, current) => (prev.length > current.length ? prev.length : current.length))
|
|
||||||
|
|
||||||
// 모든 가로선의 중심선을 긋는다.
|
|
||||||
horizontalLines.forEach((line, index) => {
|
|
||||||
const nextLine = horizontalLines[(index + 1) % horizontalLines.length]
|
|
||||||
|
|
||||||
line.line.set({ strokeWidth: 5 })
|
|
||||||
nextLine.line.set({ strokeWidth: 5 })
|
|
||||||
|
|
||||||
polygon.canvas.renderAll()
|
|
||||||
|
|
||||||
const startCenterX = Math.min(line.x1, nextLine.x1)
|
|
||||||
const startCenterY = (line.y1 + nextLine.y1) / 2
|
|
||||||
|
|
||||||
const endCenterX = line.length >= nextLine.length ? startCenterX + line.length : startCenterX + nextLine.length
|
|
||||||
const endCenterY = startCenterY
|
|
||||||
|
|
||||||
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
stroke: 'red',
|
|
||||||
strokeWidth: 1,
|
|
||||||
direction: 'horizontal',
|
|
||||||
})
|
|
||||||
|
|
||||||
/*polygon.canvas.add(centerLine)
|
|
||||||
polygon.canvas.renderAll()*/
|
|
||||||
|
|
||||||
centerLines.push(centerLine)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 모든 세로선의 중심선을 긋는다.
|
|
||||||
verticalLines.forEach((line, index) => {
|
|
||||||
const nextLine = verticalLines[(index + 1) % verticalLines.length]
|
|
||||||
|
|
||||||
const startCenterX = (line.x1 + nextLine.x1) / 2
|
|
||||||
const startCenterY = Math.min(line.y1, nextLine.y1)
|
|
||||||
|
|
||||||
const endCenterX = startCenterX
|
|
||||||
let endCenterY = line.length >= nextLine.length ? startCenterY + line.length : startCenterY + nextLine.length
|
|
||||||
|
|
||||||
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
stroke: 'blue',
|
|
||||||
strokeWidth: 1,
|
|
||||||
direction: 'vertical',
|
|
||||||
})
|
|
||||||
|
|
||||||
/*polygon.canvas.add(centerLine)
|
|
||||||
polygon.canvas.renderAll()*/
|
|
||||||
centerLines.push(centerLine)
|
|
||||||
})
|
|
||||||
|
|
||||||
polygon.points.forEach((point, index) => {
|
|
||||||
const wallPoint = polygon.wall.points[index]
|
|
||||||
// 두 점의 좌표
|
|
||||||
const x1 = point.x
|
|
||||||
const y1 = point.y
|
|
||||||
const x2 = wallPoint.x
|
|
||||||
const y2 = wallPoint.y
|
|
||||||
|
|
||||||
let newX2, newY2
|
|
||||||
|
|
||||||
// x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성
|
|
||||||
const angle = Math.atan2(y2 - y1, x2 - x1)
|
|
||||||
|
|
||||||
let previousIndex = index === 0 ? polygon.lines.length - 1 : index - 1
|
|
||||||
const maxLength = Math.max(polygon.lines[index].length, polygon.lines[previousIndex].length)
|
|
||||||
|
|
||||||
newX2 = Math.floor(x1 + (maxLength / 2 + polygon.points.length * 10) * Math.cos(angle))
|
|
||||||
newY2 = Math.floor(y1 + (maxLength / 2 + polygon.points.length * 10) * Math.sin(angle))
|
|
||||||
|
|
||||||
const line = new QLine([x1, y1, newX2, newY2], {
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
stroke: 'green',
|
|
||||||
idx: index,
|
|
||||||
})
|
|
||||||
line.set({ degree: fabric.util.radiansToDegrees(angle) })
|
|
||||||
polygon.canvas.add(line)
|
|
||||||
helpLines.push(line)
|
|
||||||
polygon.canvas.renderAll()
|
|
||||||
})
|
|
||||||
|
|
||||||
helpLines.forEach((line, index) => {
|
|
||||||
for (let i = index + 1; i < helpLines.length; i++) {
|
|
||||||
const nextLine = helpLines[i]
|
|
||||||
|
|
||||||
if (line.isAlreadyInterSection || nextLine.isAlreadyInterSection) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
let intersectionPoint = calculateIntersection(line, nextLine)
|
|
||||||
|
|
||||||
if (!intersectionPoint) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const circle = new fabric.Circle({
|
|
||||||
radius: 3,
|
|
||||||
fill: 'red',
|
|
||||||
left: intersectionPoint.x - 3,
|
|
||||||
top: intersectionPoint.y - 3,
|
|
||||||
})
|
|
||||||
|
|
||||||
polygon.canvas.add(circle)
|
|
||||||
|
|
||||||
line.set({ isAlreadyInterSection: true })
|
|
||||||
nextLine.set({ isAlreadyInterSection: true })
|
|
||||||
|
|
||||||
const helpLine1 = new QLine([nextLine.x1, nextLine.y1, intersectionPoint.x, intersectionPoint.y], {
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
stroke: 'skyblue',
|
|
||||||
})
|
|
||||||
|
|
||||||
const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
stroke: 'skyblue',
|
|
||||||
})
|
|
||||||
|
|
||||||
ridgeStartPoints.push(intersectionPoint)
|
|
||||||
polygon.canvas.add(helpLine1)
|
|
||||||
polygon.canvas.add(helpLine2)
|
|
||||||
polygon.canvas.remove(nextLine)
|
|
||||||
polygon.canvas.remove(line)
|
|
||||||
polygon.canvas.renderAll()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 안만나는 선들
|
|
||||||
const notInterSectionLines = helpLines.filter((line) => !line.isAlreadyInterSection)
|
|
||||||
const ridgeEndPoints = []
|
|
||||||
let interSectionPoints = []
|
|
||||||
|
|
||||||
notInterSectionLines.forEach((line, index) => {
|
|
||||||
let subCenterLines
|
|
||||||
if (Math.abs(line.degree) < 90) {
|
|
||||||
subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'vertical')
|
|
||||||
} else {
|
|
||||||
subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'horizontal')
|
|
||||||
}
|
|
||||||
|
|
||||||
centerLines.forEach((centerLine) => {
|
|
||||||
const interSectionPoint = calculateIntersection2(line, centerLine)
|
|
||||||
|
|
||||||
if (!interSectionPoint) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ridgeStartPoints.forEach((point) => {
|
|
||||||
line.interSectionPoints.push(interSectionPoint)
|
|
||||||
interSectionPoints.push(interSectionPoint)
|
|
||||||
|
|
||||||
const newLine = new QLine([line.x1, line.y1, interSectionPoint.x, interSectionPoint.y], {
|
|
||||||
stroke: 'black',
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
})
|
|
||||||
|
|
||||||
const circle = new fabric.Circle({
|
|
||||||
radius: 3,
|
|
||||||
fill: 'blue',
|
|
||||||
left: interSectionPoint.x - 3,
|
|
||||||
top: interSectionPoint.y - 3,
|
|
||||||
})
|
|
||||||
polygon.canvas.add(circle)
|
|
||||||
polygon.canvas.add(newLine)
|
|
||||||
|
|
||||||
polygon.canvas.remove(line)
|
|
||||||
|
|
||||||
line.set({ isAlreadyInterSection: true })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
interSectionPoints = removeDuplicatePoints(interSectionPoints)
|
|
||||||
|
|
||||||
const startRidgePoint = ridgeStartPoints[0]
|
|
||||||
|
|
||||||
const endRidgePoint = ridgeStartPoints[ridgeStartPoints.length - 1]
|
|
||||||
|
|
||||||
let step = 0
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (step % 2 === 0) {
|
|
||||||
const nextPoint = interSectionPoints.find((point) => point.x === startRidgePoint.x || point.y === startRidgePoint.y)
|
|
||||||
|
|
||||||
if (nextPoint) {
|
|
||||||
const ridge = new QLine([startRidgePoint.x, startRidgePoint.y, nextPoint.x, nextPoint.y], {
|
|
||||||
stroke: 'green',
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
})
|
|
||||||
polygon.canvas.add(ridge)
|
|
||||||
polygon.canvas.renderAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('nextPoint', nextPoint)
|
|
||||||
console.log('startRidgePoint', startRidgePoint)
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
|
|
||||||
step++
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
/*ridgeStartPoints.forEach((point, index) => {
|
|
||||||
for (let i = index + 1; i < ridgeStartPoints.length; i++) {
|
|
||||||
const currentPoint = ridgeStartPoints[index]
|
|
||||||
const nextPoint = ridgeStartPoints[i]
|
|
||||||
|
|
||||||
if (currentPoint.x === nextPoint.x || currentPoint.y === nextPoint.y) {
|
|
||||||
const ridge = new QLine([currentPoint.x, currentPoint.y, nextPoint.x, nextPoint.y], {
|
|
||||||
stroke: 'black',
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
})
|
|
||||||
polygon.canvas.add(ridge)
|
|
||||||
polygon.canvas.renderAll()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})*/
|
|
||||||
|
|
||||||
/*ridgeStartPoints.forEach((point, index) => {
|
|
||||||
let arrivalPoint
|
|
||||||
let distance = Infinity
|
|
||||||
let startPoint
|
|
||||||
interSectionPoints.forEach((interSectionPoint) => {
|
|
||||||
if (Math.abs(point.x - interSectionPoint.x) < 1 || Math.abs(point.y - interSectionPoint.y) < 1) {
|
|
||||||
if (distanceBetweenPoints(point, interSectionPoint) < distance) {
|
|
||||||
startPoint = point
|
|
||||||
distance = distanceBetweenPoints(point, interSectionPoint)
|
|
||||||
arrivalPoint = interSectionPoint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (arrivalPoint) {
|
|
||||||
const line = notInterSectionLines.filter((line) => line.interSectionPoints.includes(arrivalPoint))[0]
|
|
||||||
|
|
||||||
const ridge = new QLine([startPoint.x, startPoint.y, arrivalPoint.x, arrivalPoint.y], {
|
|
||||||
stroke: 'black',
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
})
|
|
||||||
|
|
||||||
const helpLine = new QLine([line.x1, line.y1, arrivalPoint.x, arrivalPoint.y], {
|
|
||||||
stroke: 'red',
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
})
|
|
||||||
|
|
||||||
ridgeEndPoints.push(arrivalPoint)
|
|
||||||
polygon.canvas.add(ridge)
|
|
||||||
polygon.canvas.add(helpLine)
|
|
||||||
// polygon.canvas.remove(line)
|
|
||||||
polygon.canvas.renderAll()
|
|
||||||
debugger
|
|
||||||
}
|
|
||||||
})*/
|
|
||||||
|
|
||||||
/*for (let i = 0; i < ridgeEndPoints.length; i = i + 2) {
|
|
||||||
const currentRidgeEndPoint = ridgeEndPoints[i]
|
|
||||||
const nextRidgeEndPoint = ridgeEndPoints[(i + 1) % ridgeEndPoints.length]
|
|
||||||
const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], {
|
|
||||||
fontSize: polygon.fontSize,
|
|
||||||
stroke: 'green',
|
|
||||||
})
|
|
||||||
|
|
||||||
polygon.canvas.add(ridgeConnectLine)
|
|
||||||
polygon.canvas.renderAll()
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const drawHelpLineInHexagon = (polygon, chon) => {
|
/**
|
||||||
// 가장 긴라인을 기준으로 centerLine을 그린다.
|
* 3개의 점을 이용해 직각 이등변 삼각형인지 확인
|
||||||
|
* @param point1
|
||||||
|
* @param point2
|
||||||
|
* @param point3
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
const isRightIsoscelesTriangle = (point1, point2, point3) => {
|
||||||
|
const distance = (p1, p2) => Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2))
|
||||||
|
|
||||||
|
const d1 = distance(point1, point2)
|
||||||
|
const d2 = distance(point2, point3)
|
||||||
|
const d3 = distance(point3, point1)
|
||||||
|
|
||||||
|
const distances = [d1, d2, d3].sort((a, b) => a - b)
|
||||||
|
|
||||||
|
// Check if the two smaller distances are equal and the largest distance is the hypotenuse
|
||||||
|
return distances[0] === distances[1] && Math.abs(Math.pow(distances[0], 2) * 2 - Math.pow(distances[2], 2)) < 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 세개의 점으로 삼각형의 넓이를 구한다.
|
||||||
|
* @param point1
|
||||||
|
* @param point2
|
||||||
|
* @param point3
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
const calculateTriangleArea = (point1, point2, point3) => {
|
||||||
|
const { x: x1, y: y1 } = point1
|
||||||
|
const { x: x2, y: y2 } = point2
|
||||||
|
const { x: x3, y: y3 } = point3
|
||||||
|
|
||||||
|
return Math.abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3221,6 +3221,11 @@ postcss@^8, postcss@^8.4.23:
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
source-map-js "^1.2.0"
|
source-map-js "^1.2.0"
|
||||||
|
|
||||||
|
prettier@^3.3.3:
|
||||||
|
version "3.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105"
|
||||||
|
integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
|
||||||
|
|
||||||
prisma@^5.17.0:
|
prisma@^5.17.0:
|
||||||
version "5.17.0"
|
version "5.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.17.0.tgz#267b43921ab94805b010537cffa5ccaf530fa066"
|
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.17.0.tgz#267b43921ab94805b010537cffa5ccaf530fa066"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user