Merge Q-CAST-III-MR-2: feature/Q-CAST-III-T-4
This commit is contained in:
commit
eba2ea0516
3
.env.development
Normal file
3
.env.development
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
NEXT_PUBLIC_TEST="테스트변수입니다. development"
|
||||||
|
|
||||||
|
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
||||||
3
.env.production
Normal file
3
.env.production
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
NEXT_PUBLIC_TEST="테스트변수입니다. production"
|
||||||
|
|
||||||
|
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
||||||
@ -1,15 +1,15 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: false,
|
reactStrictMode: true,
|
||||||
webpack: (config) => {
|
webpack: (config) => {
|
||||||
config.externals.push({
|
config.externals.push({
|
||||||
"utf-8-validate": "commonjs utf-8-validate",
|
'utf-8-validate': 'commonjs utf-8-validate',
|
||||||
bufferutil: "commonjs bufferutil",
|
bufferutil: 'commonjs bufferutil',
|
||||||
canvas: "commonjs canvas",
|
canvas: 'commonjs canvas',
|
||||||
});
|
})
|
||||||
// config.infrastructureLogging = { debug: /PackFileCache/ };
|
// config.infrastructureLogging = { debug: /PackFileCache/ };
|
||||||
return config;
|
return config
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nextui-org/react": "^2.4.2",
|
"@nextui-org/react": "^2.4.2",
|
||||||
"@prisma/client": "^5.17.0",
|
"@prisma/client": "^5.17.0",
|
||||||
|
"axios": "^1.7.3",
|
||||||
"fabric": "^5.3.0",
|
"fabric": "^5.3.0",
|
||||||
"framer-motion": "^11.2.13",
|
"framer-motion": "^11.2.13",
|
||||||
"mathjs": "^13.0.2",
|
"mathjs": "^13.0.2",
|
||||||
|
|||||||
@ -3,6 +3,6 @@ const config = {
|
|||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export default config;
|
export default config
|
||||||
|
|||||||
4
src/app/changelog/changelog.module.css
Normal file
4
src/app/changelog/changelog.module.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.test {
|
||||||
|
@apply bg-red-500;
|
||||||
|
@apply text-2xl;
|
||||||
|
}
|
||||||
@ -1,19 +1,22 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import { Button, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from '@nextui-org/react'
|
||||||
import Hero from '@/components/Hero'
|
import Hero from '@/components/Hero'
|
||||||
import {
|
import QSelect from '@/components/ui/QSelect'
|
||||||
Table,
|
import styles from './changelog.module.css'
|
||||||
TableBody,
|
import { get } from '@/lib/Axios'
|
||||||
TableCell,
|
|
||||||
TableColumn,
|
|
||||||
TableHeader,
|
|
||||||
TableRow,
|
|
||||||
} from '@nextui-org/react'
|
|
||||||
|
|
||||||
export default function changelogPage() {
|
export default function changelogPage() {
|
||||||
|
const testVar = process.env.NEXT_PUBLIC_TEST
|
||||||
|
|
||||||
|
const handleUsers = async () => {
|
||||||
|
const users = await get('/api/user/find-all')
|
||||||
|
console.log(users)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hero title="Change log" />
|
<Hero title="Change log" />
|
||||||
|
<div className={styles.test}>이 영역은 테스트입니다.</div>
|
||||||
<div>
|
<div>
|
||||||
<Table isStriped>
|
<Table isStriped>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
@ -35,6 +38,15 @@ export default function changelogPage() {
|
|||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="m-2">
|
||||||
|
<QSelect />
|
||||||
|
</div>
|
||||||
|
<div className="w-full bg-orange-300 m-2">{testVar}</div>
|
||||||
|
<div>
|
||||||
|
<div className="m-2">
|
||||||
|
<Button onClick={handleUsers}>Button</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,10 +30,11 @@ body {
|
|||||||
.text-balance {
|
.text-balance {
|
||||||
text-wrap: balance;
|
text-wrap: balance;
|
||||||
}
|
}
|
||||||
} */
|
}
|
||||||
|
|
||||||
.archivo-black-regular {
|
.archivo-black-regular {
|
||||||
font-family: 'Archivo Black', sans-serif;
|
font-family: 'Archivo Black', sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import QRect from '@/components/fabric/QRect'
|
|||||||
|
|
||||||
import RangeSlider from './ui/RangeSlider'
|
import RangeSlider from './ui/RangeSlider'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { canvasSizeState, fontSizeState, roofState, sortedPolygonArray } from '@/store/canvasAtom'
|
import { canvasSizeState, fontSizeState, roofMaterialState, roofState, sortedPolygonArray } from '@/store/canvasAtom'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
||||||
import { calculateIntersection } from '@/util/canvas-util'
|
import { calculateIntersection } from '@/util/canvas-util'
|
||||||
@ -31,7 +31,8 @@ export default function Roof2() {
|
|||||||
|
|
||||||
const [showControl, setShowControl] = useState(false)
|
const [showControl, setShowControl] = useState(false)
|
||||||
|
|
||||||
const roof = useRecoilValue(roofState)
|
//지붕재
|
||||||
|
const roofMaterial = useRecoilValue(roofMaterialState)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
@ -138,12 +139,12 @@ export default function Roof2() {
|
|||||||
{ x: 100, y: 400 },
|
{ x: 100, y: 400 },
|
||||||
]
|
]
|
||||||
const type2 = [
|
const type2 = [
|
||||||
{ x: 100, y: 100 },
|
{ x: 200, y: 100 },
|
||||||
{ x: 100, y: 1000 },
|
{ x: 200, y: 1000 },
|
||||||
{ x: 1000, y: 1000 },
|
{ x: 1100, y: 1000 },
|
||||||
{ x: 1000, y: 600 },
|
{ x: 1100, y: 600 },
|
||||||
{ x: 550, y: 600 },
|
{ x: 650, y: 600 },
|
||||||
{ x: 550, y: 100 },
|
{ x: 650, y: 100 },
|
||||||
]
|
]
|
||||||
|
|
||||||
const type3 = [
|
const type3 = [
|
||||||
@ -257,20 +258,23 @@ export default function Roof2() {
|
|||||||
]
|
]
|
||||||
|
|
||||||
const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint]
|
const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint]
|
||||||
|
const newP = [
|
||||||
const polygon = new QPolygon(type1B, {
|
{ x: 450, y: 450 },
|
||||||
|
{ x: 650, y: 250 },
|
||||||
|
{ x: 675, y: 275 },
|
||||||
|
{ x: 450, y: 850 },
|
||||||
|
]
|
||||||
|
const polygon = new QPolygon(type2, {
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
selectable: true,
|
selectable: false,
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
name: 'QPolygon1',
|
name: 'wall',
|
||||||
})
|
})
|
||||||
|
|
||||||
canvas?.add(polygon)
|
canvas?.add(polygon)
|
||||||
|
|
||||||
handleOuterlinesTest2(polygon)
|
handleOuterlinesTest2(polygon)
|
||||||
|
|
||||||
// const lines = togglePolygonLine(polygon)
|
// const lines = togglePolygonLine(polygon)
|
||||||
// togglePolygonLine(lines[0])
|
// togglePolygonLine(lines[0])
|
||||||
}
|
}
|
||||||
@ -360,6 +364,70 @@ export default function Roof2() {
|
|||||||
handleClear()
|
handleClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const drawRoofMaterial = () => {
|
||||||
|
const { width, height, roofStyle } = roofMaterial
|
||||||
|
|
||||||
|
const wallPolygon = canvas?.getObjects().find((obj) => obj.name === 'wall')
|
||||||
|
|
||||||
|
wallPolygon.set('strokeDashArray', [10, 5, 2, 5])
|
||||||
|
wallPolygon.set('stroke', 'blue')
|
||||||
|
wallPolygon.set('strokeWidth', 1)
|
||||||
|
|
||||||
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
||||||
|
|
||||||
|
roofs.forEach((roof) => {
|
||||||
|
let maxLengthLine = roof.lines.reduce((acc, cur) => {
|
||||||
|
return acc.length > cur.length ? acc : cur
|
||||||
|
})
|
||||||
|
|
||||||
|
const roofRatio = window.devicePixelRatio || 1
|
||||||
|
|
||||||
|
// 패턴 소스를 위한 임시 캔버스 생성
|
||||||
|
const patternSourceCanvas = document.createElement('canvas')
|
||||||
|
if (roofStyle === 1) {
|
||||||
|
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
||||||
|
patternSourceCanvas.width = width * roofRatio
|
||||||
|
patternSourceCanvas.height = height * roofRatio
|
||||||
|
} else {
|
||||||
|
patternSourceCanvas.width = height * roofRatio
|
||||||
|
patternSourceCanvas.height = width * roofRatio
|
||||||
|
}
|
||||||
|
} else if (roofStyle === 2) {
|
||||||
|
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
||||||
|
patternSourceCanvas.width = width * 2
|
||||||
|
patternSourceCanvas.height = height * 2
|
||||||
|
} else {
|
||||||
|
patternSourceCanvas.width = height * 2
|
||||||
|
patternSourceCanvas.height = width * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = patternSourceCanvas.getContext('2d')
|
||||||
|
|
||||||
|
ctx.scale(roofRatio, roofRatio)
|
||||||
|
ctx.strokeStyle = 'green'
|
||||||
|
ctx.lineWidth = 0.4
|
||||||
|
// 벽돌 패턴 그리기
|
||||||
|
if (roofStyle === 1) {
|
||||||
|
ctx.strokeRect(0, 0, 50, 30)
|
||||||
|
} else if (roofStyle === 2) {
|
||||||
|
// 지그재그
|
||||||
|
ctx.strokeRect(0, 0, 200, 100)
|
||||||
|
ctx.strokeRect(100, 100, 200, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 생성
|
||||||
|
const pattern = new fabric.Pattern({
|
||||||
|
source: patternSourceCanvas,
|
||||||
|
repeat: 'repeat',
|
||||||
|
})
|
||||||
|
roof.set('fill', null)
|
||||||
|
|
||||||
|
roof.set('fill', pattern)
|
||||||
|
canvas?.renderAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* canvas 내용 불러오기
|
* canvas 내용 불러오기
|
||||||
*/
|
*/
|
||||||
@ -380,6 +448,21 @@ export default function Roof2() {
|
|||||||
makeRoofPatternPolygon(roofStyle)
|
makeRoofPatternPolygon(roofStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createRoofRack = () => {
|
||||||
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
||||||
|
roofs.forEach((roof) => {
|
||||||
|
let maxLengthLine = roof.lines.reduce((acc, cur) => {
|
||||||
|
return acc.length > cur.length ? acc : cur
|
||||||
|
})
|
||||||
|
|
||||||
|
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
||||||
|
roof.fillCell({ width: 50, height: 100, padding: 0 })
|
||||||
|
} else {
|
||||||
|
roof.fillCell({ width: 100, height: 50, padding: 0 })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{canvas && (
|
{canvas && (
|
||||||
@ -486,6 +569,12 @@ export default function Roof2() {
|
|||||||
<Button className="m-1 p-2" onClick={addCanvas}>
|
<Button className="m-1 p-2" onClick={addCanvas}>
|
||||||
캔버스 추가
|
캔버스 추가
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button className="m-1 p-2" onClick={drawRoofMaterial}>
|
||||||
|
지붕타입 지붕재
|
||||||
|
</Button>
|
||||||
|
<Button className="m-1 p-2" onClick={createRoofRack}>
|
||||||
|
지붕가대
|
||||||
|
</Button>
|
||||||
<Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
|
<Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
|
||||||
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
|
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -10,8 +10,9 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
length: 0,
|
length: 0,
|
||||||
direction: null,
|
direction: null,
|
||||||
idx: 0,
|
idx: 0,
|
||||||
|
area: 0,
|
||||||
initialize: function (points, options, canvas) {
|
initialize: function (points, options, canvas) {
|
||||||
this.callSuper('initialize', points, options)
|
this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? false })
|
||||||
if (options.id) {
|
if (options.id) {
|
||||||
this.id = options.id
|
this.id = options.id
|
||||||
} else {
|
} else {
|
||||||
@ -23,16 +24,9 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
point = Math.round(point)
|
point = Math.round(point)
|
||||||
})
|
})
|
||||||
|
|
||||||
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
|
|
||||||
this.idx = options.idx ?? 0
|
this.idx = options.idx ?? 0
|
||||||
const dx = x2 - x1
|
|
||||||
const dy = y2 - y1
|
this.setLength()
|
||||||
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 })
|
this.direction = options.direction ?? getDirection({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 })
|
||||||
|
|
||||||
@ -67,9 +61,22 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLength() {
|
||||||
|
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
|
||||||
|
const dx = x2 - x1
|
||||||
|
const dy = y2 - y1
|
||||||
|
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
|
||||||
|
},
|
||||||
|
|
||||||
addLengthText() {
|
addLengthText() {
|
||||||
const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
|
const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
|
||||||
|
|
||||||
|
this.setLength()
|
||||||
const scaleX = this.scaleX
|
const scaleX = this.scaleX
|
||||||
const scaleY = this.scaleY
|
const scaleY = this.scaleY
|
||||||
const x1 = this.left
|
const x1 = this.left
|
||||||
@ -79,13 +86,10 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
|
|
||||||
if (thisText) {
|
if (thisText) {
|
||||||
thisText.set({ text: this.length.toFixed(0).toString(), left: (x1 + x2) / 2, top: (y1 + y2) / 2 })
|
thisText.set({ text: this.length.toFixed(0).toString(), left: (x1 + x2) / 2, top: (y1 + y2) / 2 })
|
||||||
|
this.text = thisText
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const dx = x2 - x1
|
|
||||||
const dy = y2 - y1
|
|
||||||
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
|
|
||||||
|
|
||||||
const text = new fabric.Textbox(this.length.toFixed(0).toString(), {
|
const text = new fabric.Textbox(this.length.toFixed(0).toString(), {
|
||||||
left: (x1 + x2) / 2,
|
left: (x1 + x2) / 2,
|
||||||
top: (y1 + y2) / 2,
|
top: (y1 + y2) / 2,
|
||||||
@ -113,4 +117,12 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
setCanvas(canvas) {
|
setCanvas(canvas) {
|
||||||
this.canvas = canvas
|
this.canvas = canvas
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setViewLengthText(bool) {
|
||||||
|
const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
|
||||||
|
if (thisText) {
|
||||||
|
thisText.set({ visible: bool })
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { fabric } from 'fabric'
|
|||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
|
import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
|
||||||
import { drawHelpLineInHexagon } from '@/util/qpolygon-utils'
|
import { calculateAngle, dividePolygon, drawHelpLineInHexagon } from '@/util/qpolygon-utils'
|
||||||
|
|
||||||
export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
||||||
type: 'QPolygon',
|
type: 'QPolygon',
|
||||||
@ -19,10 +19,25 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
point.x = Math.round(point.x)
|
point.x = Math.round(point.x)
|
||||||
point.y = Math.round(point.y)
|
point.y = Math.round(point.y)
|
||||||
})
|
})
|
||||||
if (points.length <= 8) {
|
options.sort = options.sort ?? true
|
||||||
|
if (!options.sort && points.length <= 8) {
|
||||||
points = sortedPointLessEightPoint(points)
|
points = sortedPointLessEightPoint(points)
|
||||||
} else {
|
} else {
|
||||||
points = sortedPoints(points)
|
let isDiagonal = false
|
||||||
|
points.forEach((point, i) => {
|
||||||
|
if (isDiagonal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const nextPoint = points[(i + 1) % points.length]
|
||||||
|
const angle = calculateAngle(point, nextPoint)
|
||||||
|
if (!(Math.abs(angle) === 0 || Math.abs(angle) === 180)) {
|
||||||
|
isDiagonal = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!isDiagonal) {
|
||||||
|
points = sortedPoints(points)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.callSuper('initialize', points, options)
|
this.callSuper('initialize', points, options)
|
||||||
@ -77,6 +92,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {
|
return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {
|
||||||
type: this.type,
|
type: this.type,
|
||||||
text: this.text,
|
text: this.text,
|
||||||
|
hips: this.hips,
|
||||||
|
ridges: this.ridges,
|
||||||
|
connectRidges: this.connectRidges,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
init: function () {
|
init: function () {
|
||||||
@ -119,6 +137,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
direction: getDirectionByPoint(point, nextPoint),
|
direction: getDirectionByPoint(point, nextPoint),
|
||||||
idx: i,
|
idx: i,
|
||||||
})
|
})
|
||||||
|
line.startPoint = point
|
||||||
|
line.endPoint = nextPoint
|
||||||
this.lines.push(line)
|
this.lines.push(line)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -201,6 +221,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
//센터 정렬시에 쓴다 체크박스가 존재함 TODO: if문 추가해서 정렬해야함
|
//센터 정렬시에 쓴다 체크박스가 존재함 TODO: if문 추가해서 정렬해야함
|
||||||
let tmpWidth = (boundingBoxWidth - (rectWidth + cell.padding) * cols) / 2
|
let tmpWidth = (boundingBoxWidth - (rectWidth + cell.padding) * cols) / 2
|
||||||
|
|
||||||
|
const drawCellsArray = [] //그려진 셀의 배열
|
||||||
|
|
||||||
for (let i = 0; i < cols; i++) {
|
for (let i = 0; i < cols; i++) {
|
||||||
for (let j = 0; j < rows; j++) {
|
for (let j = 0; j < rows; j++) {
|
||||||
const rectLeft = minX + i * (rectWidth + cell.padding) + tmpWidth
|
const rectLeft = minX + i * (rectWidth + cell.padding) + tmpWidth
|
||||||
@ -212,7 +234,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
{ x: rectLeft, y: rectTop + rectHeight },
|
{ x: rectLeft, y: rectTop + rectHeight },
|
||||||
{ x: rectLeft + rectWidth, y: rectTop + rectHeight },
|
{ x: rectLeft + rectWidth, y: rectTop + rectHeight },
|
||||||
]
|
]
|
||||||
|
|
||||||
const allPointsInside = rectPoints.every((point) => this.inPolygon(point))
|
const allPointsInside = rectPoints.every((point) => this.inPolygon(point))
|
||||||
|
|
||||||
if (allPointsInside) {
|
if (allPointsInside) {
|
||||||
@ -222,23 +243,25 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
width: rectWidth,
|
width: rectWidth,
|
||||||
height: rectHeight,
|
height: rectHeight,
|
||||||
fill: '#BFFD9F',
|
fill: '#BFFD9F',
|
||||||
|
stroke: 'black',
|
||||||
selectable: true, // 선택 가능하게 설정
|
selectable: true, // 선택 가능하게 설정
|
||||||
lockMovementX: true, // X 축 이동 잠금
|
lockMovementX: true, // X 축 이동 잠금
|
||||||
lockMovementY: true, // Y 축 이동 잠금
|
lockMovementY: true, // Y 축 이동 잠금
|
||||||
lockRotation: true, // 회전 잠금
|
lockRotation: true, // 회전 잠금
|
||||||
lockScalingX: true, // X 축 크기 조정 잠금
|
lockScalingX: true, // X 축 크기 조정 잠금
|
||||||
lockScalingY: true, // Y 축 크기 조정 잠금
|
lockScalingY: true, // Y 축 크기 조정 잠금
|
||||||
opacity: 0.6,
|
opacity: 0.8,
|
||||||
})
|
})
|
||||||
|
drawCellsArray.push(rect) //배열에 넣어서 반환한다
|
||||||
this.canvas.add(rect)
|
this.canvas.add(rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.canvas?.renderAll()
|
this.canvas?.renderAll()
|
||||||
|
return drawCellsArray
|
||||||
},
|
},
|
||||||
inPolygon(point) {
|
inPolygon(point) {
|
||||||
const vertices = this.getCurrentPoints()
|
const vertices = this.points
|
||||||
let intersects = 0
|
let intersects = 0
|
||||||
|
|
||||||
for (let i = 0; i < vertices.length; i++) {
|
for (let i = 0; i < vertices.length; i++) {
|
||||||
@ -326,5 +349,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
text.set({ visible: isView })
|
text.set({ visible: isView })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
divideLine() {},
|
divideLine() {
|
||||||
|
dividePolygon(this)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
33
src/components/ui/QSelect.jsx
Normal file
33
src/components/ui/QSelect.jsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Select, SelectItem } from '@nextui-org/react'
|
||||||
|
import styles from './QSelect.module.css'
|
||||||
|
|
||||||
|
const animals = [
|
||||||
|
{ key: 'cat', label: 'Cat' },
|
||||||
|
{ key: 'dog', label: 'Dog' },
|
||||||
|
{ key: 'elephant', label: 'Elephant' },
|
||||||
|
{ key: 'lion', label: 'Lion' },
|
||||||
|
{ key: 'tiger', label: 'Tiger' },
|
||||||
|
{ key: 'giraffe', label: 'Giraffe' },
|
||||||
|
{ key: 'dolphin', label: 'Dolphin' },
|
||||||
|
{ key: 'penguin', label: 'Penguin' },
|
||||||
|
{ key: 'zebra', label: 'Zebra' },
|
||||||
|
{ key: 'shark', label: 'Shark' },
|
||||||
|
{ key: 'whale', label: 'Whale' },
|
||||||
|
{ key: 'otter', label: 'Otter' },
|
||||||
|
{ key: 'crocodile', label: 'Crocodile' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export default function QSelect() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||||
|
<Select label="Select an animal" className="max-w-xs">
|
||||||
|
{animals.map((animal) => (
|
||||||
|
<SelectItem key={animal.key}>{animal.label}</SelectItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className={styles.test}>test</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
3
src/components/ui/QSelect.module.css
Normal file
3
src/components/ui/QSelect.module.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.test {
|
||||||
|
@apply bg-blue-500;
|
||||||
|
}
|
||||||
@ -7,6 +7,8 @@ import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
|
|||||||
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'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
import { defineQLine } from '@/util/qline-utils'
|
||||||
|
import { defineQPloygon } from '@/util/qpolygon-utils'
|
||||||
|
|
||||||
export function useCanvas(id) {
|
export function useCanvas(id) {
|
||||||
const [canvas, setCanvas] = useState()
|
const [canvas, setCanvas] = useState()
|
||||||
@ -115,22 +117,8 @@ export function useCanvas(id) {
|
|||||||
QPolygon.prototype.canvas = canvas
|
QPolygon.prototype.canvas = canvas
|
||||||
QLine.prototype.canvas = canvas
|
QLine.prototype.canvas = canvas
|
||||||
QRect.prototype.canvas = canvas
|
QRect.prototype.canvas = canvas
|
||||||
|
defineQLine()
|
||||||
fabric.QLine.fromObject = function (object, callback) {
|
defineQPloygon()
|
||||||
function _callback(instance) {
|
|
||||||
delete instance.points
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
|
|
||||||
fabric.QPolygon.fromObject = function (object, callback) {
|
|
||||||
fabric.Object._fromObject('QPolygon', object, callback, 'points')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { useRecoilState } from 'recoil'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
canvasSizeState,
|
canvasSizeState,
|
||||||
|
drewRoofCellsState,
|
||||||
fontSizeState,
|
fontSizeState,
|
||||||
roofPolygonArrayState,
|
roofPolygonArrayState,
|
||||||
roofPolygonPatternArrayState,
|
roofPolygonPatternArrayState,
|
||||||
@ -18,17 +19,16 @@ import { fabric } from 'fabric'
|
|||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
|
||||||
export const Mode = {
|
export const Mode = {
|
||||||
DRAW_LINE: 'drawLine', // 기준선 긋기모드
|
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
|
||||||
EDIT: 'edit',
|
EDIT: 'edit',
|
||||||
TEMPLATE: 'template',
|
TEMPLATE: 'template',
|
||||||
PATTERNA: 'patterna',
|
PATTERNA: 'patterna',
|
||||||
PATTERNB: 'patternb',
|
PATTERNB: 'patternb',
|
||||||
TEXTBOX: 'textbox',
|
TEXTBOX: 'textbox',
|
||||||
DRAW_RECT: 'drawRect',
|
DRAW_RECT: 'drawRect',
|
||||||
ROOF_PATTERN: 'roofPattern',
|
ROOF_PATTERN: 'roofPattern', //지붕패턴 모드
|
||||||
MODULE: 'module',
|
ROOF_TRESTLE: 'roofTrestle', //지붕가대 모드
|
||||||
ROOF_TRESTLE: 'roofTrestle',
|
FILL_CELLS: 'fillCells', //태양광셀 모드
|
||||||
FILL_CELLS: 'fillCells',
|
|
||||||
DEFAULT: 'default',
|
DEFAULT: 'default',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +57,7 @@ export function useMode() {
|
|||||||
const [canvasSize] = useRecoilState(canvasSizeState)
|
const [canvasSize] = useRecoilState(canvasSizeState)
|
||||||
|
|
||||||
const [selectedCellRoofArray, setSelectedCellRoofArray] = useState([])
|
const [selectedCellRoofArray, setSelectedCellRoofArray] = useState([])
|
||||||
|
const [drewRoofCells, setDrewRoofCells] = useRecoilState(drewRoofCellsState)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 이벤트 리스너 추가
|
// 이벤트 리스너 추가
|
||||||
@ -641,6 +642,9 @@ export function useMode() {
|
|||||||
* a : 시작점, b : 끝점
|
* a : 시작점, b : 끝점
|
||||||
*/
|
*/
|
||||||
const drawLineWithLength = (a, b) => {
|
const drawLineWithLength = (a, b) => {
|
||||||
|
if (!a || !b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const line = new QLine([a.left, a.top, b.left, b.top], {
|
const line = new QLine([a.left, a.top, b.left, b.top], {
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
@ -700,7 +704,6 @@ export function useMode() {
|
|||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
viewLengthText: true,
|
viewLengthText: true,
|
||||||
selectable: true,
|
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
},
|
},
|
||||||
canvas,
|
canvas,
|
||||||
@ -1174,6 +1177,7 @@ export function useMode() {
|
|||||||
setRoof(roof)
|
setRoof(roof)
|
||||||
|
|
||||||
roof.drawHelpLine()
|
roof.drawHelpLine()
|
||||||
|
roof.divideLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
const togglePolygonLine = (obj) => {
|
const togglePolygonLine = (obj) => {
|
||||||
@ -3175,23 +3179,27 @@ export function useMode() {
|
|||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 지붕 패턴 생성 로직
|
||||||
|
* @param roofStyle
|
||||||
|
*/
|
||||||
const makeRoofPatternPolygon = (roofStyle) => {
|
const makeRoofPatternPolygon = (roofStyle) => {
|
||||||
if (Object.keys(roofPolygonPattern).length === 0 && roofPolygonPattern.constructor === Object) {
|
if (Object.keys(roofPolygonPattern).length === 0 && roofPolygonPattern.constructor === Object) {
|
||||||
alert('객체가 비어있습니다.')
|
alert('객체가 비어있습니다.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//내부 선 점선으로 변경
|
//내부 선 점선으로 변경 추후에 다시 되돌리는 로직 필요
|
||||||
roofPolygonPattern.lines.forEach((line, index) => {
|
roofPolygonPattern.lines.forEach((line, index) => {
|
||||||
line.line.set('strokeDashArray', [10, 5, 2, 5])
|
line.line.set('strokeDashArray', [10, 5, 2, 5])
|
||||||
line.line.set('stroke', 'blue')
|
line.line.set('stroke', 'blue')
|
||||||
line.line.set('strokeWidth', 1)
|
line.line.set('strokeWidth', 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
var ratio = window.devicePixelRatio || 1
|
const ratio = window.devicePixelRatio || 1
|
||||||
|
|
||||||
let inputPatternSize = { width: 30, height: 20 } //임시 사이즈
|
const inputPatternSize = { width: 30, height: 20 } //임시 사이즈
|
||||||
let patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
||||||
|
|
||||||
if (templateType === 2) {
|
if (templateType === 2) {
|
||||||
//세로형이면 width height를 바꿈
|
//세로형이면 width height를 바꿈
|
||||||
@ -3237,6 +3245,7 @@ export function useMode() {
|
|||||||
fill: pattern,
|
fill: pattern,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
fontSize: 15, // fontSize는 필요에 따라 조정
|
fontSize: 15, // fontSize는 필요에 따라 조정
|
||||||
|
sort: false,
|
||||||
lockMovementX: true,
|
lockMovementX: true,
|
||||||
lockMovementY: true,
|
lockMovementY: true,
|
||||||
lockRotation: true,
|
lockRotation: true,
|
||||||
@ -3246,6 +3255,7 @@ export function useMode() {
|
|||||||
|
|
||||||
let polygonArray = []
|
let polygonArray = []
|
||||||
|
|
||||||
|
//패턴 폴리곤을 생성 후 배열에 담음
|
||||||
roofPolygonPattern.roofPatternPolygonArray.forEach((patternPolygon, index) => {
|
roofPolygonPattern.roofPatternPolygonArray.forEach((patternPolygon, index) => {
|
||||||
const drawPolygon = new QPolygon(patternPolygon, commonOption)
|
const drawPolygon = new QPolygon(patternPolygon, commonOption)
|
||||||
canvas.add(drawPolygon)
|
canvas.add(drawPolygon)
|
||||||
@ -3255,9 +3265,13 @@ export function useMode() {
|
|||||||
})
|
})
|
||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
|
|
||||||
|
//지붕 폴리곤 recoil에 담음
|
||||||
setRoofPolygonArray(polygonArray)
|
setRoofPolygonArray(polygonArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 가대 생성 로직
|
||||||
|
*/
|
||||||
const makeRoofTrestle = () => {
|
const makeRoofTrestle = () => {
|
||||||
if (Object.keys(roofPolygonPattern).length === 0 && roofPolygonPattern.constructor === Object) {
|
if (Object.keys(roofPolygonPattern).length === 0 && roofPolygonPattern.constructor === Object) {
|
||||||
alert('객체가 비어있습니다.')
|
alert('객체가 비어있습니다.')
|
||||||
@ -3278,8 +3292,13 @@ export function useMode() {
|
|||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 지붕가대 생성 후 가대 선택 이벤트를 추가하는 로직
|
||||||
|
* @param polygon
|
||||||
|
*/
|
||||||
function toggleSelection(polygon) {
|
function toggleSelection(polygon) {
|
||||||
if (polygon.strokeWidth === defualtStrokeStyle.strokeWidth) {
|
if (polygon.strokeWidth === defualtStrokeStyle.strokeWidth) {
|
||||||
|
//기본 선택이랑 스트로크 굵기가 같으면 선택 안됨으로 봄
|
||||||
polygon.set({
|
polygon.set({
|
||||||
stroke: selectedStrokeStyle.stroke,
|
stroke: selectedStrokeStyle.stroke,
|
||||||
strokeWidth: selectedStrokeStyle.strokeWidth,
|
strokeWidth: selectedStrokeStyle.strokeWidth,
|
||||||
@ -3288,6 +3307,7 @@ export function useMode() {
|
|||||||
canvas.discardActiveObject() // 객체의 활성 상태 해제
|
canvas.discardActiveObject() // 객체의 활성 상태 해제
|
||||||
selectedAreaArray.push(polygon)
|
selectedAreaArray.push(polygon)
|
||||||
} else {
|
} else {
|
||||||
|
//선택후 재선택하면 선택안됨으로 변경
|
||||||
polygon.set({
|
polygon.set({
|
||||||
stroke: defualtStrokeStyle.stroke,
|
stroke: defualtStrokeStyle.stroke,
|
||||||
strokeWidth: defualtStrokeStyle.strokeWidth,
|
strokeWidth: defualtStrokeStyle.strokeWidth,
|
||||||
@ -3295,6 +3315,7 @@ export function useMode() {
|
|||||||
})
|
})
|
||||||
canvas.discardActiveObject() // 객체의 활성 상태 해제
|
canvas.discardActiveObject() // 객체의 활성 상태 해제
|
||||||
|
|
||||||
|
//폴리곤에 커스텀 인덱스를 가지고 해당 배열 인덱스를 찾아 삭제함
|
||||||
const removeIndex = polygon.customIndex
|
const removeIndex = polygon.customIndex
|
||||||
const removeArrayIndex = selectedAreaArray.findIndex((x) => x.customIndex === removeIndex)
|
const removeArrayIndex = selectedAreaArray.findIndex((x) => x.customIndex === removeIndex)
|
||||||
selectedAreaArray.splice(removeArrayIndex, 1)
|
selectedAreaArray.splice(removeArrayIndex, 1)
|
||||||
@ -3302,6 +3323,7 @@ export function useMode() {
|
|||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//외각선을 안쪽으로 그려 가대선을 그린다.
|
||||||
polygons.forEach((polygon, index) => {
|
polygons.forEach((polygon, index) => {
|
||||||
const trestlePolygon = handleOuterlinesTest(polygon, -12)
|
const trestlePolygon = handleOuterlinesTest(polygon, -12)
|
||||||
trestlePolygon.setViewLengthText(false) //얘는 set으로 안먹는다...
|
trestlePolygon.setViewLengthText(false) //얘는 set으로 안먹는다...
|
||||||
@ -3315,25 +3337,45 @@ export function useMode() {
|
|||||||
lockScalingX: true,
|
lockScalingX: true,
|
||||||
lockScalingY: true,
|
lockScalingY: true,
|
||||||
bringToFront: true,
|
bringToFront: true,
|
||||||
customIndex: polygon.customIndex,
|
customIndex: polygon.customIndex, //가대 폴리곤의 임시 인덱스를 넣어줌
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 가대 선택 이벤트
|
||||||
|
*/
|
||||||
trestlePolygon.on('mousedown', function () {
|
trestlePolygon.on('mousedown', function () {
|
||||||
const customIndex = polygon.get('customIndex')
|
|
||||||
toggleSelection(trestlePolygon)
|
toggleSelection(trestlePolygon)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
setSelectedCellRoofArray(selectedAreaArray)
|
setSelectedCellRoofArray(selectedAreaArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 가대 선택 후 셀 채우기
|
||||||
|
*/
|
||||||
const makeRoofFillCells = () => {
|
const makeRoofFillCells = () => {
|
||||||
// const selectedCellRoofs = selectedCellRoofArray
|
const drawCellsArray = []
|
||||||
|
|
||||||
if (selectedCellRoofArray.length === 0) {
|
if (selectedCellRoofArray.length === 0) {
|
||||||
|
//배열에 선택된 가대 셀이 없으면 리턴
|
||||||
alert('선택된 영역이 없습니다.')
|
alert('선택된 영역이 없습니다.')
|
||||||
setMode(Mode.DEFAULT) //default 모드로 변경
|
setMode(Mode.DEFAULT) //default 모드로 변경
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (drewRoofCells.length > 0) {
|
||||||
|
//리코일에
|
||||||
|
if (confirm('패널이 초기화 됩니다.')) {
|
||||||
|
drewRoofCells.forEach((cells, index) => {
|
||||||
|
cells.drawCells.forEach((cell) => {
|
||||||
|
canvas?.remove(cell)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setDrewRoofCells([])
|
||||||
|
canvas?.renderAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const inputCellSize = { width: 172, height: 113 }
|
const inputCellSize = { width: 172, height: 113 }
|
||||||
const cellSize = { ...inputCellSize } //기본으로 가로형으로 넣고
|
const cellSize = { ...inputCellSize } //기본으로 가로형으로 넣고
|
||||||
|
|
||||||
@ -3342,8 +3384,11 @@ export function useMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectedCellRoofArray.forEach((polygon, index) => {
|
selectedCellRoofArray.forEach((polygon, index) => {
|
||||||
polygon.fillCell({ width: cellSize.width, height: cellSize.height, padding: 10 })
|
const drawCells = polygon.fillCell({ width: cellSize.width, height: cellSize.height, padding: 10 })
|
||||||
|
drawCellsArray.push({ roofIndex: polygon.customIndex, drawCells: drawCells })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setDrewRoofCells(drawCellsArray)
|
||||||
setMode(Mode.DEFAULT) //default 모드로 변경
|
setMode(Mode.DEFAULT) //default 모드로 변경
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
56
src/lib/Axios.js
Normal file
56
src/lib/Axios.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
axios.defaults.baseURL = process.env.NEXT_PUBLIC_API_SERVER_PATH
|
||||||
|
|
||||||
|
const axiosInstance = axios.create({
|
||||||
|
// baseURL: process.env.API_SERVER_URL,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
axiosInstance.interceptors.request.use((config) => {
|
||||||
|
// config['Authorization'] = localStorage.getItem('token')
|
||||||
|
//TODO: 인터셉터에서 추가 로직 구현
|
||||||
|
return config
|
||||||
|
})
|
||||||
|
|
||||||
|
axiosInstance.interceptors.request.use(undefined, (error) => {
|
||||||
|
//TODO: 인터셉터에서 에러 처리 로직 구현
|
||||||
|
// if (error.isAxiosError && e.response?.status === 401) {
|
||||||
|
// localStorage.removeItem('token')
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
export const get = (url) =>
|
||||||
|
axiosInstance
|
||||||
|
.get(url)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const post = (url, data) =>
|
||||||
|
axiosInstance
|
||||||
|
.post(url, data)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const put = (url, data) =>
|
||||||
|
axiosInstance
|
||||||
|
.put(url, data)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const patch = (url, data) =>
|
||||||
|
axiosInstance
|
||||||
|
.patch(url, data)
|
||||||
|
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const del = (url) =>
|
||||||
|
axiosInstance
|
||||||
|
.delete(url)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
@ -53,3 +53,17 @@ export const templateTypeState = atom({
|
|||||||
default: 1, //1:모임지붕, 2:A타입, 3:B타입
|
default: 1, //1:모임지붕, 2:A타입, 3:B타입
|
||||||
dangerouslyAllowMutability: true,
|
dangerouslyAllowMutability: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//셀 그린 이후에 생성하는 state
|
||||||
|
export const drewRoofCellsState = atom({
|
||||||
|
key: 'drewRoofCells',
|
||||||
|
default: [],
|
||||||
|
dangerouslyAllowMutability: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 지붕재 width, height, rafter(서까래), roofStyle을 갖고있고 roofStyle 1은 정방향, 2는 지그재그
|
||||||
|
export const roofMaterialState = atom({
|
||||||
|
key: 'roofMaterial',
|
||||||
|
default: { width: 20, height: 10, rafter: 0, roofStyle: 2 },
|
||||||
|
dangerouslyAllowMutability: true,
|
||||||
|
})
|
||||||
|
|||||||
@ -2,8 +2,14 @@ import { fabric } from 'fabric'
|
|||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
|
|
||||||
export const defineQLine = () => {
|
export const defineQLine = () => {
|
||||||
/*fabric.QLine = QLine
|
fabric.QLine.fromObject = function (object, callback) {
|
||||||
fabric.QLine.fromObject = (object, callback) => {
|
function _callback(instance) {
|
||||||
return new fabric.QLine([object.x1, object.y1, object.x2, object.y2], object)
|
delete instance.points
|
||||||
}*/
|
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')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
|
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDirectionByPoint } from '@/util/canvas-util'
|
||||||
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
|
||||||
export const defineQPloygon = () => {
|
export const defineQPloygon = () => {
|
||||||
fabric.QPolygon.fromObject = function (object, callback) {
|
fabric.QPolygon.fromObject = function (object, callback) {
|
||||||
@ -19,7 +20,7 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
|
|||||||
const ridgeStartPoints = []
|
const ridgeStartPoints = []
|
||||||
const ridgeEndPoints = []
|
const ridgeEndPoints = []
|
||||||
|
|
||||||
const centerInterSectionPoints = []
|
let centerInterSectionPoints = []
|
||||||
|
|
||||||
// polygon.lines = polygon.lines.sort((a, b) => a.length - b.length)
|
// polygon.lines = polygon.lines.sort((a, b) => a.length - b.length)
|
||||||
polygon.wall.lines = getOneSideLines(polygon.wall)
|
polygon.wall.lines = getOneSideLines(polygon.wall)
|
||||||
@ -101,9 +102,9 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
|
|||||||
: nextLine.startPoint
|
: nextLine.startPoint
|
||||||
|
|
||||||
line.connectedPoint = { interSectionPoint, area, startPoint, endPoint }
|
line.connectedPoint = { interSectionPoint, area, startPoint, endPoint }
|
||||||
line.connectedPoints.push(interSectionPoint)
|
line.connectedPoints.push({ interSectionPoint, area, startPoint, endPoint })
|
||||||
nextLine.connectedPoint = { interSectionPoint, area, startPoint, endPoint }
|
nextLine.connectedPoint = { interSectionPoint, area, startPoint, endPoint }
|
||||||
nextLine.connectedPoints.push(interSectionPoint)
|
nextLine.connectedPoints.push({ interSectionPoint, area, startPoint, endPoint })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -150,6 +151,12 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
|
|||||||
name: 'hip',
|
name: 'hip',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
line.startPoint = point.startPoint
|
||||||
|
line.endPoint = point.interSectionPoint
|
||||||
|
|
||||||
|
line2.startPoint = point.endPoint
|
||||||
|
line2.endPoint = point.interSectionPoint
|
||||||
|
|
||||||
polygon.hips.push(line)
|
polygon.hips.push(line)
|
||||||
polygon.hips.push(line2)
|
polygon.hips.push(line2)
|
||||||
|
|
||||||
@ -165,20 +172,26 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
|
|||||||
uniqueInterSectionPoints.forEach((point) => {
|
uniqueInterSectionPoints.forEach((point) => {
|
||||||
const interSectionPoint = point.interSectionPoint
|
const interSectionPoint = point.interSectionPoint
|
||||||
|
|
||||||
if (connectedPoint.x === interSectionPoint.x && connectedPoint.y === interSectionPoint.y) {
|
if (connectedPoint.interSectionPoint.x === interSectionPoint.x && connectedPoint.interSectionPoint.y === interSectionPoint.y) {
|
||||||
removedIdx.push(line.idx)
|
removedIdx.push(line.idx)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const notIntersectedLines = helpLines.filter((line) => !removedIdx.includes(line.idx))
|
let notIntersectedLines = helpLines.filter((line) => !removedIdx.includes(line.idx))
|
||||||
|
|
||||||
|
notIntersectedLines = notIntersectedLines.map((line) => {
|
||||||
|
return { ...line, centerInterSectionPoints: [] }
|
||||||
|
})
|
||||||
|
|
||||||
notIntersectedLines.forEach((line) => {
|
notIntersectedLines.forEach((line) => {
|
||||||
centerLines.forEach((centerLine) => {
|
centerLines.forEach((centerLine) => {
|
||||||
const interSectionPoint = calculateIntersection(line, centerLine)
|
const interSectionPoint = calculateIntersection(line, centerLine)
|
||||||
|
|
||||||
if (interSectionPoint && polygon.inPolygon(interSectionPoint) && polygon.wall.inPolygon(interSectionPoint)) {
|
if (interSectionPoint && polygon.inPolygon(interSectionPoint) && polygon.wall.inPolygon(interSectionPoint)) {
|
||||||
|
line.centerInterSectionPoints.push(interSectionPoint)
|
||||||
|
interSectionPoint.lineIdx = line.idx
|
||||||
centerInterSectionPoints.push(interSectionPoint)
|
centerInterSectionPoints.push(interSectionPoint)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -187,11 +200,12 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
|
|||||||
// centerInterSectionPoints에서 ridgeStartPoints와 x가 같거나 y가 같은것중 가장 가까운 점들을 찾는다.
|
// centerInterSectionPoints에서 ridgeStartPoints와 x가 같거나 y가 같은것중 가장 가까운 점들을 찾는다.
|
||||||
ridgeStartPoints.forEach((point) => {
|
ridgeStartPoints.forEach((point) => {
|
||||||
const xPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.x - point.x) < 2)
|
const xPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.x - point.x) < 2)
|
||||||
|
|
||||||
const yPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.y - point.y) < 2)
|
const yPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.y - point.y) < 2)
|
||||||
let closestPoint
|
let closestPoint
|
||||||
if (xPoints.length === 0) {
|
if (xPoints.length === 0) {
|
||||||
closestPoint = findClosestPoint(point, yPoints)
|
closestPoint = findClosestPoint(point, yPoints)
|
||||||
} else {
|
} else if (yPoints.length === 0) {
|
||||||
closestPoint = findClosestPoint(point, xPoints)
|
closestPoint = findClosestPoint(point, xPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,44 +214,119 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
|
|||||||
stroke: 'purple',
|
stroke: 'purple',
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
name: 'ridge',
|
name: 'ridge',
|
||||||
|
direction: getDirectionByPoint(point, closestPoint),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
line.startPoint = point
|
||||||
|
line.endPoint = closestPoint
|
||||||
|
|
||||||
polygon.ridges.push(line)
|
polygon.ridges.push(line)
|
||||||
polygon.canvas.add(line)
|
polygon.canvas.add(line)
|
||||||
ridgeEndPoints.push(closestPoint)
|
ridgeEndPoints.push(closestPoint)
|
||||||
|
|
||||||
|
notIntersectedLines = notIntersectedLines.filter((line) => line.idx !== closestPoint.lineIdx)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
centerInterSectionPoints = []
|
||||||
|
notIntersectedLines.forEach((line) => {
|
||||||
|
centerInterSectionPoints.push(...line.centerInterSectionPoints)
|
||||||
|
})
|
||||||
|
|
||||||
// ridgeEndPoints끼리 이어준다.
|
// ridgeEndPoints끼리 이어준다.
|
||||||
const remainingPoints = ridgeEndPoints
|
const remainingPoints = [...ridgeEndPoints]
|
||||||
|
|
||||||
|
// ridgeEndPoint에서 centerInterSectionPoints와 45도인 점을 찾아 이어준다.
|
||||||
|
|
||||||
|
ridgeEndPoints.forEach((ridgePoint) => {
|
||||||
|
const filteredCenterInterSectionPoints = centerInterSectionPoints.filter((centerPoint) => {
|
||||||
|
const degree = calculateAngle(ridgePoint, centerPoint)
|
||||||
|
return Math.abs(degree) === 45 || Math.abs(degree) === 135
|
||||||
|
})[0]
|
||||||
|
|
||||||
|
if (filteredCenterInterSectionPoints) {
|
||||||
|
const line = new QLine([ridgePoint.x, ridgePoint.y, filteredCenterInterSectionPoints.x, filteredCenterInterSectionPoints.y], {
|
||||||
|
stroke: 'purple',
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
name: 'hip',
|
||||||
|
})
|
||||||
|
|
||||||
|
line.startPoint = ridgePoint
|
||||||
|
line.endPoint = filteredCenterInterSectionPoints
|
||||||
|
|
||||||
|
polygon.hips.push(line)
|
||||||
|
polygon.canvas.add(line)
|
||||||
|
|
||||||
|
ridgeStartPoints.push(filteredCenterInterSectionPoints)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ridgeEndPoint끼리 연결한다.
|
||||||
|
while (remainingPoints.length > 1) {
|
||||||
|
const startPoint = remainingPoints.shift()
|
||||||
|
const endPoint = remainingPoints.shift()
|
||||||
|
|
||||||
|
const line = new QLine([startPoint.x, startPoint.y, endPoint.x, endPoint.y], {
|
||||||
|
stroke: 'purple',
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
name: 'connectRidge',
|
||||||
|
})
|
||||||
|
|
||||||
|
line.startPoint = startPoint
|
||||||
|
line.endPoint = endPoint
|
||||||
|
|
||||||
|
polygon.connectRidges.push(line)
|
||||||
|
|
||||||
remainingPoints.forEach((ridgePoint) => {
|
|
||||||
polygon.points.forEach((point) => {
|
polygon.points.forEach((point) => {
|
||||||
const degree = calculateAngle(ridgePoint, point)
|
const degree = calculateAngle(startPoint, point)
|
||||||
|
|
||||||
if (Math.abs(degree) % 45 < 1) {
|
if (Math.abs(degree) === 45 || Math.abs(degree) === 135) {
|
||||||
const line = new QLine([ridgePoint.x, ridgePoint.y, point.x, point.y], {
|
const line = new QLine([startPoint.x, startPoint.y, point.x, point.y], {
|
||||||
stroke: 'purple',
|
stroke: 'purple',
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
name: 'hip',
|
name: 'hip',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
line.startPoint = startPoint
|
||||||
|
line.endPoint = point
|
||||||
|
|
||||||
polygon.hips.push(line)
|
polygon.hips.push(line)
|
||||||
polygon.canvas.add(line)
|
polygon.canvas.add(line)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
while (remainingPoints.length > 0) {
|
polygon.points.forEach((point) => {
|
||||||
const point = remainingPoints.shift()
|
const degree = calculateAngle(endPoint, point)
|
||||||
const closestPoint = findClosestPoint(point, remainingPoints)
|
|
||||||
if (!closestPoint) continue
|
if (Math.abs(degree) === 45 || Math.abs(degree) === 135) {
|
||||||
// 마루끼리 연결
|
const line = new QLine([endPoint.x, endPoint.y, point.x, point.y], {
|
||||||
const line = new QLine([point.x, point.y, closestPoint.x, closestPoint.y], {
|
stroke: 'purple',
|
||||||
stroke: 'purple',
|
fontSize: polygon.fontSize,
|
||||||
fontSize: polygon.fontSize,
|
name: 'hip',
|
||||||
name: 'connectRidge',
|
})
|
||||||
|
|
||||||
|
line.startPoint = endPoint
|
||||||
|
line.endPoint = point
|
||||||
|
|
||||||
|
polygon.hips.push(line)
|
||||||
|
polygon.canvas.add(line)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
polygon.connectRidges.push(line)
|
|
||||||
|
|
||||||
polygon.canvas.add(line)
|
polygon.canvas.add(line)
|
||||||
}
|
}
|
||||||
@ -246,7 +335,7 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
|
|||||||
export const drawCenterLines = (polygon) => {
|
export const drawCenterLines = (polygon) => {
|
||||||
const centerLines = []
|
const centerLines = []
|
||||||
|
|
||||||
const oneSideLines = getOneSideLines(polygon)
|
const oneSideLines = polygon.lines.map((line) => getOneSideLine(line))
|
||||||
|
|
||||||
const horizontalLines = oneSideLines.filter((line) => line.direction === 'right')
|
const horizontalLines = oneSideLines.filter((line) => line.direction === 'right')
|
||||||
const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom')
|
const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom')
|
||||||
@ -261,9 +350,6 @@ export const drawCenterLines = (polygon) => {
|
|||||||
horizontalLines.forEach((line, index) => {
|
horizontalLines.forEach((line, index) => {
|
||||||
const nextLine = horizontalLines[(index + 1) % horizontalLines.length]
|
const nextLine = horizontalLines[(index + 1) % horizontalLines.length]
|
||||||
|
|
||||||
line.set({ strokeWidth: 5 })
|
|
||||||
nextLine.set({ strokeWidth: 5 })
|
|
||||||
|
|
||||||
polygon.canvas.renderAll()
|
polygon.canvas.renderAll()
|
||||||
|
|
||||||
const startCenterX = Math.min(line.x1, nextLine.x1)
|
const startCenterX = Math.min(line.x1, nextLine.x1)
|
||||||
@ -319,6 +405,8 @@ const getOneSideLines = (polygon) => {
|
|||||||
line.x2 = newX2
|
line.x2 = newX2
|
||||||
line.y2 = newY2
|
line.y2 = newY2
|
||||||
line.direction = 'bottom'
|
line.direction = 'bottom'
|
||||||
|
line.startPoint = { x: newX1, y: newY1 }
|
||||||
|
line.endPoint = { x: newX2, y: newY2 }
|
||||||
} else if (line.direction === 'left') {
|
} else if (line.direction === 'left') {
|
||||||
newX1 = line.x2
|
newX1 = line.x2
|
||||||
newY1 = line.y2
|
newY1 = line.y2
|
||||||
@ -330,11 +418,13 @@ const getOneSideLines = (polygon) => {
|
|||||||
line.x2 = newX2
|
line.x2 = newX2
|
||||||
line.y2 = newY2
|
line.y2 = newY2
|
||||||
line.direction = 'right'
|
line.direction = 'right'
|
||||||
|
line.startPoint = { x: newX1, y: newY1 }
|
||||||
|
line.endPoint = { x: newX2, y: newY2 }
|
||||||
}
|
}
|
||||||
return line
|
return line
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const calculateAngle = (point1, point2) => {
|
export const calculateAngle = (point1, point2) => {
|
||||||
const deltaX = point2.x - point1.x
|
const deltaX = point2.x - point1.x
|
||||||
const deltaY = point2.y - point1.y
|
const deltaY = point2.y - point1.y
|
||||||
const angleInRadians = Math.atan2(deltaY, deltaX)
|
const angleInRadians = Math.atan2(deltaY, deltaX)
|
||||||
@ -375,3 +465,214 @@ const calculateTriangleArea = (point1, point2, point3) => {
|
|||||||
|
|
||||||
return Math.abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2
|
return Math.abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// polygon을 나눈다.
|
||||||
|
export const dividePolygon = (polygon) => {
|
||||||
|
let hips = polygon.hips
|
||||||
|
const ridges = polygon.ridges.map((ridge) => getOneSideLine(ridge))
|
||||||
|
const connectRidges = polygon.connectRidges
|
||||||
|
const polygonLines = polygon.lines
|
||||||
|
|
||||||
|
hips.forEach((hip) => {
|
||||||
|
// hips의 startPoint와 endPoint를 polygon의 points와 비교하여 같은 점이 endPoint일 경우 startPoint로 변경한다.
|
||||||
|
const startPoint = polygon.points.find((point) => point.x === hip.endPoint.x && point.y === hip.endPoint.y)
|
||||||
|
if (startPoint) {
|
||||||
|
const temp = hip.startPoint
|
||||||
|
hip.startPoint = hip.endPoint
|
||||||
|
hip.endPoint = temp
|
||||||
|
}
|
||||||
|
})
|
||||||
|
hips = [...hips, ...connectRidges]
|
||||||
|
polygon.setViewLengthText(false)
|
||||||
|
|
||||||
|
polygonLines.forEach((line) => {
|
||||||
|
let ridge
|
||||||
|
|
||||||
|
const startPoint = line.startPoint
|
||||||
|
const endPoint = line.endPoint
|
||||||
|
let polygonPoints = []
|
||||||
|
|
||||||
|
polygonPoints.push(startPoint)
|
||||||
|
|
||||||
|
polygonPoints.push(endPoint)
|
||||||
|
|
||||||
|
const startHip = hips.find((hip) => hip.startPoint.x === startPoint.x && hip.startPoint.y === startPoint.y)
|
||||||
|
const endHip = hips.find((hip) => hip.startPoint.x === endPoint.x && hip.startPoint.y === endPoint.y)
|
||||||
|
|
||||||
|
if (!startHip || !endHip) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startHip && endHip && startHip.endPoint.x === endHip.endPoint.x && startHip.endPoint.y === endHip.endPoint.y) {
|
||||||
|
polygonPoints.push(startHip.endPoint)
|
||||||
|
|
||||||
|
const newPolygon = new QPolygon(polygonPoints, {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
id: polygon.id,
|
||||||
|
name: 'roof',
|
||||||
|
selectable: false,
|
||||||
|
stroke: 'black',
|
||||||
|
fill: 'transparent',
|
||||||
|
strokeWidth: 3,
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.canvas.add(newPolygon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let connectedRidge = ridges.find(
|
||||||
|
(ridge) =>
|
||||||
|
(ridge.startPoint.x === startHip.endPoint.x && ridge.startPoint.y === startHip.endPoint.y) ||
|
||||||
|
(ridge.endPoint.x === startHip.endPoint.x && ridge.endPoint.y === startHip.endPoint.y),
|
||||||
|
)
|
||||||
|
|
||||||
|
const hipStartPoint = startHip.endPoint
|
||||||
|
const hipEndPoint = endHip.endPoint
|
||||||
|
const restRidgeConnection = connectRidges[0]
|
||||||
|
|
||||||
|
if (connectedRidge.startPoint.x === hipStartPoint.x && connectedRidge.startPoint.y === hipStartPoint.y) {
|
||||||
|
if (connectedRidge.endPoint.x === hipEndPoint.x && connectedRidge.endPoint.y === hipEndPoint.y) {
|
||||||
|
polygonPoints.push(connectedRidge.endPoint)
|
||||||
|
polygonPoints.push(connectedRidge.startPoint)
|
||||||
|
|
||||||
|
const newPolygon = new QPolygon(polygonPoints, {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
id: polygon.id,
|
||||||
|
name: 'roof',
|
||||||
|
selectable: false,
|
||||||
|
stroke: 'black',
|
||||||
|
fill: 'transparent',
|
||||||
|
strokeWidth: 3,
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.canvas.add(newPolygon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if (connectedRidge.endPoint.x === hipStartPoint.x && connectedRidge.endPoint.y === hipStartPoint.y) {
|
||||||
|
if (connectedRidge.startPoint.x === hipEndPoint.x && connectedRidge.startPoint.y === hipEndPoint.y) {
|
||||||
|
polygonPoints.push(connectedRidge.startPoint)
|
||||||
|
polygonPoints.push(connectedRidge.endPoint)
|
||||||
|
|
||||||
|
const newPolygon = new QPolygon(polygonPoints, {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
id: polygon.id,
|
||||||
|
name: 'roof',
|
||||||
|
selectable: false,
|
||||||
|
stroke: 'black',
|
||||||
|
fill: 'transparent',
|
||||||
|
strokeWidth: 3,
|
||||||
|
sort: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.canvas.add(newPolygon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 지붕이 꺾여있는 경우
|
||||||
|
|
||||||
|
if (
|
||||||
|
(restRidgeConnection.startPoint.x === startHip.endPoint.x && restRidgeConnection.startPoint.y === startHip.endPoint.y) ||
|
||||||
|
(restRidgeConnection.endPoint.x === startHip.endPoint.x && restRidgeConnection.endPoint.y === startHip.endPoint.y)
|
||||||
|
) {
|
||||||
|
polygonPoints = [startPoint, startHip.endPoint]
|
||||||
|
let lastPoint
|
||||||
|
|
||||||
|
if (restRidgeConnection.startPoint.x === startHip.endPoint.x && restRidgeConnection.startPoint.y === startHip.endPoint.y) {
|
||||||
|
lastPoint = restRidgeConnection.endPoint
|
||||||
|
polygonPoints.push(restRidgeConnection.endPoint)
|
||||||
|
} else {
|
||||||
|
lastPoint = restRidgeConnection.startPoint
|
||||||
|
polygonPoints.push(restRidgeConnection.startPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedRidge = ridges.find(
|
||||||
|
(ridge) =>
|
||||||
|
(ridge.startPoint.x === lastPoint.x && ridge.startPoint.y === lastPoint.y) ||
|
||||||
|
(ridge.endPoint.x === lastPoint.x && ridge.endPoint.y === lastPoint.y),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (connectedRidge.startPoint.x === lastPoint.x && connectedRidge.startPoint.y === lastPoint.y) {
|
||||||
|
polygonPoints.push(connectedRidge.endPoint)
|
||||||
|
} else {
|
||||||
|
polygonPoints.push(connectedRidge.startPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
polygonPoints.push(endPoint)
|
||||||
|
} else {
|
||||||
|
polygonPoints = [endPoint, endHip.endPoint]
|
||||||
|
let lastPoint
|
||||||
|
|
||||||
|
if (restRidgeConnection.startPoint.x === endHip.endPoint.x && restRidgeConnection.startPoint.y === endHip.endPoint.y) {
|
||||||
|
lastPoint = restRidgeConnection.endPoint
|
||||||
|
polygonPoints.push(restRidgeConnection.endPoint)
|
||||||
|
} else {
|
||||||
|
lastPoint = restRidgeConnection.startPoint
|
||||||
|
polygonPoints.push(restRidgeConnection.startPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedRidge = ridges.find(
|
||||||
|
(ridge) =>
|
||||||
|
(ridge.startPoint.x === lastPoint.x && ridge.startPoint.y === lastPoint.y) ||
|
||||||
|
(ridge.endPoint.x === lastPoint.x && ridge.endPoint.y === lastPoint.y),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (connectedRidge.startPoint.x === startHip.endPoint.x && connectedRidge.startPoint.y === startHip.endPoint.y) {
|
||||||
|
lastPoint = connectedRidge.startPoint
|
||||||
|
polygonPoints.push(connectedRidge.startPoint)
|
||||||
|
} else {
|
||||||
|
lastPoint = connectedRidge.endPoint
|
||||||
|
polygonPoints.push(connectedRidge.endPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
polygonPoints.push(startPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPolygon = new QPolygon(polygonPoints, {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
id: polygon.id,
|
||||||
|
name: 'roof',
|
||||||
|
selectable: false,
|
||||||
|
stroke: 'black',
|
||||||
|
fill: 'transparent',
|
||||||
|
strokeWidth: 3,
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.canvas.add(newPolygon)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOneSideLine = (line) => {
|
||||||
|
// left, top 방향의 line은 right, bottom 방향의 line으로 변경한다.
|
||||||
|
const newLine = { ...line }
|
||||||
|
let newX1, newY1, newX2, newY2
|
||||||
|
if (newLine.direction === 'top') {
|
||||||
|
newX1 = newLine.x2
|
||||||
|
newY1 = newLine.y2
|
||||||
|
newX2 = newLine.x1
|
||||||
|
newY2 = newLine.y1
|
||||||
|
|
||||||
|
newLine.x1 = newX1
|
||||||
|
newLine.y1 = newY1
|
||||||
|
newLine.x2 = newX2
|
||||||
|
newLine.y2 = newY2
|
||||||
|
newLine.direction = 'bottom'
|
||||||
|
newLine.startPoint = { x: newX1, y: newY1 }
|
||||||
|
newLine.endPoint = { x: newX2, y: newY2 }
|
||||||
|
} else if (line.direction === 'left') {
|
||||||
|
newX1 = newLine.x2
|
||||||
|
newY1 = newLine.y2
|
||||||
|
newX2 = newLine.x1
|
||||||
|
newY2 = newLine.y1
|
||||||
|
|
||||||
|
newLine.x1 = newX1
|
||||||
|
newLine.y1 = newY1
|
||||||
|
newLine.x2 = newX2
|
||||||
|
newLine.y2 = newY2
|
||||||
|
newLine.direction = 'right'
|
||||||
|
newLine.startPoint = { x: newX1, y: newY1 }
|
||||||
|
newLine.endPoint = { x: newX2, y: newY2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
return newLine
|
||||||
|
}
|
||||||
|
|||||||
19
yarn.lock
19
yarn.lock
@ -2181,6 +2181,15 @@ asynckit@^0.4.0:
|
|||||||
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
||||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||||
|
|
||||||
|
axios@^1.7.3:
|
||||||
|
version "1.7.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.3.tgz#a1125f2faf702bc8e8f2104ec3a76fab40257d85"
|
||||||
|
integrity sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.15.6"
|
||||||
|
form-data "^4.0.0"
|
||||||
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||||
@ -2539,6 +2548,11 @@ flat@^5.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
|
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
|
||||||
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
|
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
|
||||||
|
|
||||||
|
follow-redirects@^1.15.6:
|
||||||
|
version "1.15.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
|
||||||
|
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
|
||||||
|
|
||||||
foreground-child@^3.1.0:
|
foreground-child@^3.1.0:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz"
|
resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz"
|
||||||
@ -3233,6 +3247,11 @@ prisma@^5.17.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/engines" "5.17.0"
|
"@prisma/engines" "5.17.0"
|
||||||
|
|
||||||
|
proxy-from-env@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
psl@^1.1.33:
|
psl@^1.1.33:
|
||||||
version "1.9.0"
|
version "1.9.0"
|
||||||
resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
|
resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user