작업중 dev와 merge 금지

This commit is contained in:
Jaeyoung Lee 2025-02-07 21:37:34 +09:00
parent 2159046e8f
commit 4101a3ede9
11 changed files with 960 additions and 498 deletions

View File

@ -13,6 +13,7 @@
"@nextui-org/react": "^2.4.2", "@nextui-org/react": "^2.4.2",
"ag-grid-react": "^32.0.2", "ag-grid-react": "^32.0.2",
"axios": "^1.7.8", "axios": "^1.7.8",
"big.js": "^6.2.2",
"chart.js": "^4.4.6", "chart.js": "^4.4.6",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"fabric": "^5.3.0", "fabric": "^5.3.0",

View File

@ -28,6 +28,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
this.idx = options.idx ?? 0 this.idx = options.idx ?? 0
this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }) this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 })
this.textMode = options.textMode ?? 'plane' // plane:복시도, actual:실측, none:표시안함
if (length !== 0) { if (length !== 0) {
this.length = length this.length = length
} else { } else {
@ -60,70 +61,84 @@ export const QLine = fabric.util.createClass(fabric.Line, {
}, },
setLength() { setLength() {
const scaleX = this.scaleX if (this.attributes?.actualSize !== undefined && this.attributes?.planeSize !== undefined) {
const scaleY = this.scaleY if (this.textMode === 'plane') {
const x1 = this.left this.length = this.attributes.planeSize / 10
const y1 = this.top } else if (this.textMode === 'actual') {
const x2 = this.left + this.width * scaleX this.length = this.attributes.actualSize / 10
const y2 = this.top + this.height * scaleY }
const dx = x2 - x1 } else {
const dy = y2 - y1 const scaleX = this.scaleX
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) 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(1))
}
}, },
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() if (this.textMode === 'none') {
const scaleX = this.scaleX if (thisText) {
const scaleY = this.scaleY this.canvas.remove(thisText)
const x1 = this.left }
const y1 = this.top } else {
const x2 = this.left + this.width * scaleX this.setLength()
const y2 = this.top + this.height * scaleY 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) { if (thisText) {
thisText.set({ text: this.getLength().toString(), left: (x1 + x2) / 2, top: (y1 + y2) / 2 }) thisText.set({ text: this.getLength().toString(), left: (x1 + x2) / 2, top: (y1 + y2) / 2 })
this.text = thisText this.text = thisText
return return
}
let left, top
if (this.direction === 'left' || this.direction === 'right') {
left = (x1 + x2) / 2
top = (y1 + y2) / 2 + 10
} else if (this.direction === 'top' || this.direction === 'bottom') {
left = (x1 + x2) / 2 + 10
top = (y1 + y2) / 2
}
const minX = this.left
const maxX = this.left + this.width
const minY = this.top
const maxY = this.top + this.length
const degree = (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI
const text = new fabric.Textbox(this.getLength().toString(), {
left: left,
top: top,
fontSize: this.fontSize,
minX,
maxX,
minY,
maxY,
parentDirection: this.direction,
parentDegree: degree,
parentId: this.id,
editable: false,
selectable: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
parent: this,
name: 'lengthText',
})
this.text = text
this.canvas.add(text)
} }
let left, top
if (this.direction === 'left' || this.direction === 'right') {
left = (x1 + x2) / 2
top = (y1 + y2) / 2 + 10
} else if (this.direction === 'top' || this.direction === 'bottom') {
left = (x1 + x2) / 2 + 10
top = (y1 + y2) / 2
}
const minX = this.left
const maxX = this.left + this.width
const minY = this.top
const maxY = this.top + this.length
const degree = (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI
const text = new fabric.Textbox(this.getLength().toString(), {
left: left,
top: top,
fontSize: this.fontSize,
minX,
maxX,
minY,
maxY,
parentDirection: this.direction,
parentDegree: degree,
parentId: this.id,
editable: false,
selectable: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
parent: this,
name: 'lengthText',
})
this.text = text
this.canvas.add(text)
}, },
setFontSize(fontSize) { setFontSize(fontSize) {
this.fontSize = fontSize this.fontSize = fontSize

View File

@ -5,6 +5,7 @@ import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint
import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import Big from 'big.js'
export const QPolygon = fabric.util.createClass(fabric.Polygon, { export const QPolygon = fabric.util.createClass(fabric.Polygon, {
type: 'QPolygon', type: 'QPolygon',
@ -188,7 +189,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
}, },
// 보조선 그리기 // 보조선 그리기
drawHelpLine() { drawHelpLine(settingModalFirstOptions) {
const types = [] const types = []
this.lines.forEach((line) => types.push(line.attributes.type)) this.lines.forEach((line) => types.push(line.attributes.type))
@ -205,7 +206,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
(gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) || (gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) ||
(gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type))) (gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type)))
) { ) {
drawGabledRoof(this.id, this.canvas) drawGabledRoof(this.id, this.canvas, settingModalFirstOptions)
} else if (hasShed) { } else if (hasShed) {
const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED) const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED)
const areLinesParallel = function (line1, line2) { const areLinesParallel = function (line1, line2) {
@ -232,18 +233,18 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const gables = this.lines.filter((line) => sheds.includes(line) === false && eaves.includes(line) === false) const gables = this.lines.filter((line) => sheds.includes(line) === false && eaves.includes(line) === false)
const isGable = gables.every((line) => gableType.includes(line.attributes.type)) const isGable = gables.every((line) => gableType.includes(line.attributes.type))
if (isGable) { if (isGable) {
drawShedRoof(this.id, this.canvas) drawShedRoof(this.id, this.canvas, settingModalFirstOptions)
} else { } else {
drawRidgeRoof(this.id, this.canvas) drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions)
} }
} else { } else {
drawRidgeRoof(this.id, this.canvas) drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions)
} }
} else { } else {
drawRidgeRoof(this.id, this.canvas) drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions)
} }
} else { } else {
drawRidgeRoof(this.id, this.canvas) drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions)
} }
}, },
@ -262,15 +263,16 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const end = points[(i + 1) % points.length] const end = points[(i + 1) % points.length]
// planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10, // planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
// actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10, // actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
const dx = end.x - start.x const dx = Big(end.x).minus(Big(start.x))
const dy = end.y - start.y const dy = Big(end.y).minus(Big(start.y))
const length = Math.round(Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2))) * 10 // const length = Math.round(Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2))) * 10
const length = dx.pow(2).plus(dy.pow(2)).sqrt().times(10).round().toNumber()
let midPoint let midPoint
midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2) midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2)
const degree = (Math.atan2(dy, dx) * 180) / Math.PI const degree = Big(Math.atan2(dy.toNumber(), dx.toNumber())).times(180).div(Math.PI).toNumber()
// Create new text object if it doesn't exist // Create new text object if it doesn't exist
const text = new fabric.Text(length.toString(), { const text = new fabric.Text(length.toString(), {

View File

@ -10,6 +10,7 @@ import { outerLineFixState } from '@/store/outerLineAtom'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { getChonByDegree } from '@/util/canvas-util' import { getChonByDegree } from '@/util/canvas-util'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
// 처마.케라바 변경 // 처마.케라바 변경
export function useEavesGableEdit(id) { export function useEavesGableEdit(id) {
@ -46,6 +47,8 @@ export function useEavesGableEdit(id) {
{ id: 4, name: getMessage('shed'), type: TYPES.SHED }, { id: 4, name: getMessage('shed'), type: TYPES.SHED },
] ]
const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState)
useEffect(() => { useEffect(() => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
if (!outerLineFix || outerLines.length === 0) { if (!outerLineFix || outerLines.length === 0) {
@ -180,7 +183,7 @@ export function useEavesGableEdit(id) {
const roof = drawRoofPolygon(wallLine) const roof = drawRoofPolygon(wallLine)
canvas?.renderAll() canvas?.renderAll()
roof.drawHelpLine() roof.drawHelpLine(settingModalFirstOptions)
}) })
wallLines.forEach((wallLine) => { wallLines.forEach((wallLine) => {

View File

@ -31,6 +31,7 @@ import { fabric } from 'fabric'
import { outlineDisplaySelector } from '@/store/settingAtom' import { outlineDisplaySelector } from '@/store/settingAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting' import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting'
import Big from 'big.js'
//외벽선 그리기 //외벽선 그리기
export function useOuterLineWall(id, propertiesId) { export function useOuterLineWall(id, propertiesId) {
@ -141,6 +142,8 @@ export function useOuterLineWall(id, propertiesId) {
const mouseDown = (e) => { const mouseDown = (e) => {
let pointer = getIntersectMousePoint(e) let pointer = getIntersectMousePoint(e)
pointer = { x: Big(pointer.x).round(1).toNumber(), y: Big(pointer.y).round(1).toNumber() }
console.log('mouseDown', pointer, points)
if (points.length === 0) { if (points.length === 0) {
setPoints((prev) => [...prev, pointer]) setPoints((prev) => [...prev, pointer])
@ -148,24 +151,30 @@ export function useOuterLineWall(id, propertiesId) {
const lastPoint = points[points.length - 1] const lastPoint = points[points.length - 1]
let newPoint = { x: pointer.x, y: pointer.y } let newPoint = { x: pointer.x, y: pointer.y }
const length = distanceBetweenPoints(lastPoint, newPoint) const length = distanceBetweenPoints(lastPoint, newPoint)
console.log('length', length)
if (verticalHorizontalMode) { if (verticalHorizontalMode) {
const vector = { const vector = {
x: pointer.x - points[points.length - 1].x, x: Big(pointer.x).minus(Big(points[points.length - 1].x)),
y: pointer.y - points[points.length - 1].y, y: Big(pointer.y).minus(Big(points[points.length - 1].y)),
} }
const slope = Math.abs(vector.y / vector.x) // 기울기 계산 // const slope = Math.abs(vector.y / vector.x) // 기울기 계산
console.log('vector', vector.x.toNumber(), vector.y.toNumber(), Math.abs(vector.y.toNumber() / vector.x.toNumber()) >= 1)
const slope = vector.x.eq(0) ? Big(1) : vector.y.div(vector.x).abs() // 기울기 계산
let scaledVector let scaledVector
if (slope >= 1) { // if (slope >= 1) {
if (slope.gte(1)) {
// 기울기가 1 이상이면 x축 방향으로 그림 // 기울기가 1 이상이면 x축 방향으로 그림
scaledVector = { scaledVector = {
x: 0, x: 0,
y: vector.y >= 0 ? Number(length) : -Number(length), // y: vector.y >= 0 ? Number(length) : -Number(length),
y: vector.y.gte(0) ? Big(length).toNumber() : Big(length).neg().toNumber(),
} }
} else { } else {
// 기울기가 1 미만이면 y축 방향으로 그림 // 기울기가 1 미만이면 y축 방향으로 그림
scaledVector = { scaledVector = {
x: vector.x >= 0 ? Number(length) : -Number(length), // x: vector.x >= 0 ? Number(length) : -Number(length),
x: vector.x.gte(0) ? Big(length).toNumber() : Big(length).neg().toNumber(),
y: 0, y: 0,
} }
} }
@ -173,9 +182,11 @@ export function useOuterLineWall(id, propertiesId) {
const verticalLength = scaledVector.y const verticalLength = scaledVector.y
const horizontalLength = scaledVector.x const horizontalLength = scaledVector.x
console.log('verticalLength', verticalLength, 'horizontalLength', horizontalLength)
newPoint = { newPoint = {
x: lastPoint.x + horizontalLength, x: Big(lastPoint.x).plus(horizontalLength).toNumber(),
y: lastPoint.y + verticalLength, y: Big(lastPoint.y).plus(verticalLength).toNumber(),
} }
} }
setPoints((prev) => [...prev, newPoint]) setPoints((prev) => [...prev, newPoint])
@ -865,6 +876,8 @@ export function useOuterLineWall(id, propertiesId) {
const firstPoint = points[0] const firstPoint = points[0]
console.log('points 좌표 : ', points)
points.forEach((point, idx) => { points.forEach((point, idx) => {
if (idx === 0 || !isAllRightAngle) { if (idx === 0 || !isAllRightAngle) {
return return

View File

@ -1,12 +1,13 @@
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useMode } from '@/hooks/useMode' import { useMode } from '@/hooks/useMode'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
import { useLine } from '@/hooks/useLine' import { useLine } from '@/hooks/useLine'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
// 외벽선 속성 설정 // 외벽선 속성 설정
export function usePropertiesSetting(id) { export function usePropertiesSetting(id) {
@ -16,6 +17,7 @@ export function usePropertiesSetting(id) {
const { drawRoofPolygon } = useMode() const { drawRoofPolygon } = useMode()
const setPoints = useResetRecoilState(outerLinePointsState) const setPoints = useResetRecoilState(outerLinePointsState)
const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState)
const { addPolygonByLines } = usePolygon() const { addPolygonByLines } = usePolygon()
const { removeLine, hideLine } = useLine() const { removeLine, hideLine } = useLine()
@ -156,7 +158,7 @@ export function usePropertiesSetting(id) {
setPoints([]) setPoints([])
canvas.renderAll() canvas.renderAll()
roof.drawHelpLine() roof.drawHelpLine(settingModalFirstOptions)
closePopup(id) closePopup(id)
return return

View File

@ -10,6 +10,7 @@ import { outerLineFixState } from '@/store/outerLineAtom'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { getChonByDegree } from '@/util/canvas-util' import { getChonByDegree } from '@/util/canvas-util'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
// 지붕형상 설정 // 지붕형상 설정
export function useRoofShapeSetting(id) { export function useRoofShapeSetting(id) {
@ -48,6 +49,8 @@ export function useRoofShapeSetting(id) {
const history = useRef([]) const history = useRef([])
const { closePopup } = usePopup() const { closePopup } = usePopup()
const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState)
useEffect(() => { useEffect(() => {
pitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch) pitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch)
}, [pitch]) }, [pitch])
@ -423,7 +426,7 @@ export function useRoofShapeSetting(id) {
const roof = drawRoofPolygon(polygon) const roof = drawRoofPolygon(polygon)
canvas?.renderAll() canvas?.renderAll()
roof.drawHelpLine() roof.drawHelpLine(settingModalFirstOptions)
isFixRef.current = true isFixRef.current = true
closePopup(id) closePopup(id)
} }

View File

@ -37,6 +37,8 @@ import offsetPolygon from '@/util/qpolygon-utils'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { INPUT_TYPE, LINE_TYPE, Mode, POLYGON_TYPE } from '@/common/common' import { INPUT_TYPE, LINE_TYPE, Mode, POLYGON_TYPE } from '@/common/common'
import Big from 'big.js'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
export function useMode() { export function useMode() {
const [mode, setMode] = useRecoilState(modeState) const [mode, setMode] = useRecoilState(modeState)
@ -78,6 +80,8 @@ export function useMode() {
const [objectPlacementMode, setObjectPlacementModeState] = useRecoilState(objectPlacementModeState) const [objectPlacementMode, setObjectPlacementModeState] = useRecoilState(objectPlacementModeState)
const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState)
useEffect(() => { useEffect(() => {
// if (!canvas) { // if (!canvas) {
// canvas?.setZoom(0.8) // canvas?.setZoom(0.8)
@ -1554,7 +1558,7 @@ export function useMode() {
}) })
const roof = drawRoofPolygon(polygon) //지붕 그리기 const roof = drawRoofPolygon(polygon) //지붕 그리기
roof.drawHelpLine() roof.drawHelpLine(settingModalFirstOptions)
// roof.divideLine() // roof.divideLine()
} }
@ -1664,11 +1668,18 @@ export function useMode() {
} }
} }
/**
* polygon 기준으로 margin polygon 작성한다.
* @param polygon
* @param lines
* @param arcSegments
* @returns {{vertices, edges: *[], minX: *, minY: *, maxX: *, maxY: *}}
*/
function createMarginPolygon(polygon, lines, arcSegments = 0) { function createMarginPolygon(polygon, lines, arcSegments = 0) {
const offsetEdges = [] const offsetEdges = []
polygon.edges.forEach((edge, i) => { polygon.edges.forEach((edge, i) => {
const offset = lines[i % lines.length].attributes.offset === 0 ? 1 : lines[i % lines.length].attributes.offset const offset = lines[i % lines.length].attributes.offset === 0 ? 0.1 : lines[i % lines.length].attributes.offset
const dx = edge.outwardNormal.x * offset const dx = edge.outwardNormal.x * offset
const dy = edge.outwardNormal.y * offset const dy = edge.outwardNormal.y * offset
offsetEdges.push(createOffsetEdge(edge, dx, dy)) offsetEdges.push(createOffsetEdge(edge, dx, dy))
@ -1692,6 +1703,13 @@ export function useMode() {
return marginPolygon return marginPolygon
} }
/**
* polygon 기준으로 padding polygon 작성한다.
* @param polygon
* @param lines
* @param arcSegments
* @returns {{vertices, edges: *[], minX: *, minY: *, maxX: *, maxY: *}}
*/
function createPaddingPolygon(polygon, lines, arcSegments = 0) { function createPaddingPolygon(polygon, lines, arcSegments = 0) {
const offsetEdges = [] const offsetEdges = []
@ -1720,7 +1738,13 @@ export function useMode() {
return paddingPolygon return paddingPolygon
} }
/**
* 외벽선을 기준으로 지붕을 그린다.
* @param wall
* @returns {*}
*/
const drawRoofPolygon = (wall) => { const drawRoofPolygon = (wall) => {
//외벽선의 순서를 최좌측 선을 기준으로 반시계방향으로 정리한다. 지붕선과 순서를 맞추기 위함.
const startLine = wall.lines const startLine = wall.lines
.filter((line) => line.x1 === Math.min(...wall.lines.map((line) => line.x1))) .filter((line) => line.x1 === Math.min(...wall.lines.map((line) => line.x1)))
.reduce((prev, current) => { .reduce((prev, current) => {
@ -1740,12 +1764,15 @@ export function useMode() {
wall.lines = afterLine.concat(beforeLine) wall.lines = afterLine.concat(beforeLine)
//외벽선을 기준으로 polygon을 생성한다. 지붕선의 기준이 됨.
const polygon = createRoofPolygon(wall.points) const polygon = createRoofPolygon(wall.points)
const originPolygon = new QPolygon(wall.points, { fontSize: 0 }) const originPolygon = new QPolygon(wall.points, { fontSize: 0 })
originPolygon.setViewLengthText(false) originPolygon.setViewLengthText(false)
let offsetPolygon let offsetPolygon
let result = createMarginPolygon(polygon, wall.lines).vertices let result = createMarginPolygon(polygon, wall.lines).vertices
//margin polygon 의 point가 기준 polygon의 밖에 있는지 판단한다.
const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point)) const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
if (allPointsOutside) { if (allPointsOutside) {
@ -1759,6 +1786,7 @@ export function useMode() {
return { x1: point.x, y1: point.y } return { x1: point.x, y1: point.y }
}), }),
) )
if (wall.direction) { if (wall.direction) {
roof.direction = wall.direction roof.direction = wall.direction
} }
@ -1769,9 +1797,11 @@ export function useMode() {
roof.setWall(wall) roof.setWall(wall)
roof.lines.forEach((line, index) => { roof.lines.forEach((line, index) => {
const lineLength = Math.sqrt( const x1 = Big(line.x1)
Math.pow(Math.round(Math.abs(line.x1 - line.x2) * 10), 2) + Math.pow(Math.round(Math.abs(line.y1 - line.y2) * 10), 2), const x2 = Big(line.x2)
) const y1 = Big(line.y1)
const y2 = Big(line.y2)
const lineLength = x1.minus(x2).abs().pow(2).plus(y1.minus(y2).abs().pow(2)).sqrt().times(10).round().toNumber()
line.attributes = { line.attributes = {
roofId: roof.id, roofId: roof.id,
planeSize: lineLength, planeSize: lineLength,
@ -1789,14 +1819,18 @@ export function useMode() {
roofId: roof.id, roofId: roof.id,
} }
//외벽선 삭제
canvas canvas
.getObjects() .getObjects()
.filter((line) => line.attributes?.wallId === wall.id) .filter((line) => line.attributes?.wallId === wall.id)
.forEach((line) => canvas.remove(line)) .forEach((line) => canvas.remove(line))
wall.lines.forEach((line, index) => { wall.lines.forEach((line, index) => {
const lineLength = Math.sqrt( const x1 = Big(line.x1)
Math.pow(Math.round(Math.abs(line.x1 - line.x2) * 10), 2) + Math.pow(Math.round(Math.abs(line.y1 - line.y2) * 10), 2), const x2 = Big(line.x2)
) const y1 = Big(line.y1)
const y2 = Big(line.y2)
const lineLength = x1.minus(x2).abs().pow(2).plus(y1.minus(y2).abs().pow(2)).sqrt().times(10).round().toNumber()
line.attributes.roofId = roof.id line.attributes.roofId = roof.id
line.attributes.currentRoofId = roof.lines[index].id line.attributes.currentRoofId = roof.lines[index].id
line.attributes.planeSize = lineLength line.attributes.planeSize = lineLength
@ -1829,6 +1863,8 @@ export function useMode() {
wallStrokeWidth = 4 wallStrokeWidth = 4
break break
} }
//외벽선의 색깔 표시를 위해 라인을 추가한다.
const wallLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], { const wallLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
parentId: wall.id, parentId: wall.id,
name: 'wallLine', name: 'wallLine',

View File

@ -1,12 +1,12 @@
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { calculateIntersection, getInterSectionLineNotOverCoordinate } from '@/util/canvas-util' import { getInterSectionLineNotOverCoordinate } from '@/util/canvas-util'
export function useMouse() { export function useMouse() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
//가로선, 세로선의 교차점을 return //가로선, 세로선의 교차점을 return
const getIntersectMousePoint = (e) => { /*const getIntersectMousePoint = (e) => {
let pointer = canvas.getPointer(e.e) let pointer = canvas.getPointer(e.e)
const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine') const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine')
@ -15,6 +15,17 @@ export function useMouse() {
} }
return getInterSectionLineNotOverCoordinate(mouseLines[0], mouseLines[1]) || pointer return getInterSectionLineNotOverCoordinate(mouseLines[0], mouseLines[1]) || pointer
}*/
//가로선, 세로선의 교차점을 return
const getIntersectMousePoint = (e) => {
let pointer = canvas.getPointer(e.e)
const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine')
if (mouseLines.length < 2) {
return { x: Math.round(pointer.x), y: Math.round(pointer.y) }
}
return getInterSectionLineNotOverCoordinate(mouseLines[0], mouseLines[1]) || { x: Math.round(pointer.x), y: Math.round(pointer.y) }
} }
return { return {

View File

@ -1,5 +1,6 @@
import { intersect } from 'mathjs' import { intersect } from 'mathjs'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import Big from 'big.js'
/** /**
* Collection of function to use on canvas * Collection of function to use on canvas
@ -128,9 +129,9 @@ export const formattedWithComma = (value, unit = 'mm') => {
} }
export const distanceBetweenPoints = (point1, point2) => { export const distanceBetweenPoints = (point1, point2) => {
const dx = point2.x - point1.x const dx = Big(point2.x).minus(Big(point1.x))
const dy = point2.y - point1.y const dy = Big(point2.y).minus(Big(point1.y))
return Math.sqrt(dx * dx + dy * dy) return dx.pow(2).plus(dy.pow(2)).sqrt().round(1).toNumber()
} }
/** /**

File diff suppressed because it is too large Load Diff