From 2ca9fd5bbc8f5a3b275d2067ef120996601a0174 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Thu, 13 Feb 2025 16:44:43 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 108 ++++++++---------------------- src/hooks/common/useRoofFn.js | 4 +- src/hooks/useMode.js | 4 ++ src/util/qpolygon-utils.js | 63 ++++++----------- 4 files changed, 56 insertions(+), 123 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 22ef408b..23e0de55 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -2,7 +2,7 @@ import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' import { QLine } from '@/components/fabric/QLine' import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util' -import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' +import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, toGeoJSON } from '@/util/qpolygon-utils' import * as turf from '@turf/turf' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import Big from 'big.js' @@ -188,8 +188,28 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }) }, - // 보조선 그리기 + /** + * 보조선 그리기 + * @param settingModalFirstOptions + */ drawHelpLine(settingModalFirstOptions) { + let textMode = 'plane' + + const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id + ? settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id + : 1 + switch (dimensionDisplay) { + case 1: + textMode = 'plane' + break + case 2: + textMode = 'actual' + break + case 3: + textMode = 'none' + break + } + const types = [] this.lines.forEach((line) => types.push(line.attributes.type)) @@ -206,7 +226,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { (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))) ) { - drawGabledRoof(this.id, this.canvas, settingModalFirstOptions) + drawGabledRoof(this.id, this.canvas, textMode) } else if (hasShed) { const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED) const areLinesParallel = function (line1, line2) { @@ -233,18 +253,18 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { const gables = this.lines.filter((line) => sheds.includes(line) === false && eaves.includes(line) === false) const isGable = gables.every((line) => gableType.includes(line.attributes.type)) if (isGable) { - drawShedRoof(this.id, this.canvas, settingModalFirstOptions) + drawShedRoof(this.id, this.canvas, textMode) } else { - drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions) + drawRidgeRoof(this.id, this.canvas, textMode) } } else { - drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions) + drawRidgeRoof(this.id, this.canvas, textMode) } } else { - drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions) + drawRidgeRoof(this.id, this.canvas, textMode) } } else { - drawRidgeRoof(this.id, this.canvas, settingModalFirstOptions) + drawRidgeRoof(this.id, this.canvas, textMode) } }, @@ -264,11 +284,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.texts = [] points.forEach((start, i) => { 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, - // actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10, const dx = Big(end.x).minus(Big(start.x)) 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 = dx.pow(2).plus(dy.pow(2)).sqrt().times(10).round().toNumber() let midPoint @@ -323,75 +340,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { setCanvas(canvas) { this.canvas = canvas }, - fillCell(cell = { width: 50, height: 100, padding: 10 }) { - const points = this.points - - const minX = Math.min(...points.map((p) => p.x)) - const maxX = Math.max(...points.map((p) => p.x)) - const minY = Math.min(...points.map((p) => p.y)) - const maxY = Math.max(...points.map((p) => p.y)) - - const boundingBoxWidth = maxX - minX - const boundingBoxHeight = maxY - minY - - const rectWidth = cell.width - const rectHeight = cell.height - - const cols = Math.floor((boundingBoxWidth + cell.padding) / (rectWidth + cell.padding)) - const rows = Math.floor((boundingBoxHeight + cell.padding) / (rectHeight + cell.padding)) - - //전체 높이에서 패딩을 포함하고 rows를 곱해서 여백길이를 계산 후에 2로 나누면 반높이를 넣어서 중간으로 정렬 - const tmpHeight = (boundingBoxHeight - (rectHeight + cell.padding) * rows) / 2 - //센터 정렬시에 쓴다 체크박스가 존재함 TODO: if문 추가해서 정렬해야함 - let tmpWidth = (boundingBoxWidth - (rectWidth + cell.padding) * cols) / 2 - - const drawCellsArray = [] //그려진 셀의 배열 - - let idx = 1 - - for (let i = 0; i < cols; i++) { - for (let j = 0; j < rows; j++) { - const rectLeft = minX + i * (rectWidth + cell.padding) - const rectTop = minY + j * (rectHeight + cell.padding) - - const rectPoints = [ - { x: rectLeft, y: rectTop }, - { x: rectLeft, y: rectTop + rectHeight }, - { x: rectLeft + rectWidth, y: rectTop + rectHeight }, - { x: rectLeft + rectWidth, y: rectTop }, - ] - - if (inPolygon(this.points, rectPoints)) { - const rect = new fabric.Rect({ - left: rectLeft, - top: rectTop, - width: rectWidth, - height: rectHeight, - fill: '#BFFD9F', - stroke: 'black', - selectable: true, // 선택 가능하게 설정 - lockMovementX: true, // X 축 이동 잠금 - lockMovementY: true, // Y 축 이동 잠금 - lockRotation: true, // 회전 잠금 - lockScalingX: true, // X 축 크기 조정 잠금 - lockScalingY: true, // Y 축 크기 조정 잠금 - opacity: 0.8, - name: 'cell', - idx: idx, - parentId: this.id, - parent: this, - }) - - idx++ - drawCellsArray.push(rect) //배열에 넣어서 반환한다 - this.canvas.add(rect) - } - } - } - this.canvas?.renderAll() - this.cells = drawCellsArray - return drawCellsArray - }, fillCellABType( cell = { width: 50, height: 100, padding: 5, wallDirection: 'left', referenceDirection: 'none', startIndex: -1, isCellCenter: false }, ) { diff --git a/src/hooks/common/useRoofFn.js b/src/hooks/common/useRoofFn.js index 35ec81df..d64f5df1 100644 --- a/src/hooks/common/useRoofFn.js +++ b/src/hooks/common/useRoofFn.js @@ -329,7 +329,9 @@ export function useRoofFn() { const allRoofObject = canvas .getObjects() - .filter((obj) => /*obj !== roof && obj !== wall &&*/ obj.attributes?.roofId === roof.id || obj.parentId === roof.id || obj.parentId === wall.id) + .filter( + (obj) => /*obj !== roof && obj !== wall &&*/ obj.attributes?.roofId === roof.id || obj.parentId === roof.id || obj.parentId === wall?.id, + ) allRoofObject.forEach((obj) => { canvas.remove(obj) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index cbc0e51d..06f1428a 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1797,6 +1797,10 @@ export function useMode() { roof.direction = wall.direction } if (wall.attributes?.roofId) { + canvas + .getObjects() + .filter((obj) => obj.parentId === roof.id) + .forEach((obj) => obj.set('parentId', wall.attributes.roofId)) roof.id = wall.attributes.roofId } roof.name = POLYGON_TYPE.ROOF diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 9fdd7275..0444c93d 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -312,8 +312,9 @@ export const isSamePoint = (a, b) => { * 박공지붕(templateA, templateB)을 그린다. * @param roofId * @param canvas + * @param textMode */ -export const drawGabledRoof = (roofId, canvas, settingModalFirstOptions) => { +export const drawGabledRoof = (roofId, canvas, textMode) => { const roof = canvas?.getObjects().find((object) => object.id === roofId) const roofLines = roof.lines const wallLines = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roof.id).lines @@ -323,15 +324,6 @@ export const drawGabledRoof = (roofId, canvas, settingModalFirstOptions) => { return } - // const roofPoints = roof.points - // const minX = Math.min(...roofPoints.map((point) => point.x)) - // const maxX = Math.max(...roofPoints.map((point) => point.x)) - // const minY = Math.min(...roofPoints.map((point) => point.y)) - // const maxY = Math.max(...roofPoints.map((point) => point.y)) - - // 맞은편 라인을 찾기 위해 현재 polygon 으로 만들수 있는 최대한의 길이를 구한다. - // const checkLength = Math.abs(Math.sqrt(Math.pow(maxX - minX, 2) + Math.pow(maxY - minY, 2))) - // 처마라인의 기본속성 입력 const eaves = [] roofLines.forEach((currentRoof, index) => { @@ -650,8 +642,9 @@ export const drawGabledRoof = (roofId, canvas, settingModalFirstOptions) => { * 한쪽흐름 지붕 * @param roofId * @param canvas + * @param textMode */ -export const drawShedRoof = (roofId, canvas, settingModalFirstOptions) => { +export const drawShedRoof = (roofId, canvas, textMode) => { const roof = canvas?.getObjects().find((object) => object.id === roofId) const hasNonParallelLines = roof.lines.filter((line) => Math.abs(line.x1 - line.x2) > 1 && Math.abs(line.y1 - line.y2) > 1) if (hasNonParallelLines.length > 0) { @@ -673,11 +666,9 @@ export const drawShedRoof = (roofId, canvas, settingModalFirstOptions) => { return Math.tan(degree * (Math.PI / 180)) * adjust } - gables.forEach((gable) => { - const adjust = gable.attributes.planeSize - const height = getHeight(adjust, shedDegree) - gable.attributes.actualSize = Math.round(Math.sqrt(Math.pow(adjust, 2) + Math.pow(height, 2))) - }) + gables.forEach( + (gable) => (gable.attributes.actualSize = calcLineActualSize({ x1: gable.x1, y1: gable.y1, x2: gable.x2, y2: gable.y2 }, shedDegree)), + ) const pitchSizeLines = [] @@ -707,8 +698,11 @@ export const drawShedRoof = (roofId, canvas, settingModalFirstOptions) => { x2 = eave.x1 } points.sort((a, b) => a - b) - const planeSize = Math.round(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) * 10) - const actualSize = Math.round(Math.sqrt(Math.pow(planeSize, 2) + Math.pow(getHeight(planeSize, shedDegree), 2)) * 10) + // const planeSize = Math.round(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) * 10) + const planeSize = calcLinePlaneSize({ x1, y1, x2, y2 }) + // const actualSize = Math.round(Math.sqrt (Math.pow(planeSize, 2) + Math.pow(getHeight(planeSize, shedDegree), 2)) * 10) + const actualSize = calcLineActualSize({ x1, y1, x2, y2 }, shedDegree) + const line = new QLine([x1, y1, x2, y2], { parentId: roof.id, stroke: '#000000', @@ -716,10 +710,11 @@ export const drawShedRoof = (roofId, canvas, settingModalFirstOptions) => { strokeDashArray: [5, 5], selectable: false, fontSize: roof.fontSize, + textMode: textMode, attributes: { roofId: roof.id, type: 'pitchSizeLine', - planeSize: planeSize, + planeSize: actualSize, actualSize: actualSize, }, }) @@ -730,33 +725,17 @@ export const drawShedRoof = (roofId, canvas, settingModalFirstOptions) => { const maxLine = pitchSizeLines.reduce((prev, current) => (prev.length > current.length ? prev : current), pitchSizeLines[0]) canvas.add(maxLine) canvas.renderAll() - - const adjust = Math.sqrt( - Math.pow(Math.round(Math.abs(maxLine.x1 - maxLine.x2) * 10), 2) + Math.pow(Math.round(Math.abs(maxLine.y1 - maxLine.y2) * 10), 2), - ) - const height = getHeight(adjust, shedDegree) - const lengthText = Math.round(Math.sqrt(Math.pow(adjust, 2) + Math.pow(height, 2))) - maxLine.setLengthText(lengthText) } -export const drawRidgeRoof = (roofId, canvas, settingModalFirstOptions) => { +/** + * 마루가 있는 지붕을 그린다. + * @param roofId + * @param canvas + * @param textMode + */ +export const drawRidgeRoof = (roofId, canvas, textMode) => { const roof = canvas?.getObjects().find((object) => object.id === roofId) - let textMode = 'plane' - const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id - ? settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id - : 1 - switch (dimensionDisplay) { - case 1: - textMode = 'plane' - break - case 2: - textMode = 'actual' - break - case 3: - textMode = 'none' - break - } //Math.abs(line.x1 - line.x2) > 1 && Math.abs(line.y1 - line.y2) > 1 const hasNonParallelLines = roof.lines.filter((line) => Big(line.x1).minus(Big(line.x2)).gt(1) && Big(line.y1).minus(Big(line.y2)).gt(1)) if (hasNonParallelLines.length > 0) {