Merge branch 'dev'

This commit is contained in:
yoosangwook 2024-07-31 14:42:43 +09:00
commit bfa51bd24d
14 changed files with 1752 additions and 1608 deletions

View File

@ -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",

View File

@ -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
View 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
View 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>
)
}

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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,
})

View File

@ -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
}

View File

@ -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))
})
}
} }

View File

@ -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
} }

View File

@ -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"