diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 7b817f8f..def5f45e 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -244,21 +244,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { const types = [] this.lines.forEach((line) => types.push(line.attributes.type)) - const eavesType = [LINE_TYPE.WALLLINE.EAVES, LINE_TYPE.WALLLINE.HIPANDGABLE] const gableType = [LINE_TYPE.WALLLINE.GABLE, LINE_TYPE.WALLLINE.JERKINHEAD] - // const isEaves = types.every((type) => eavesType.includes(type)) - const gableOdd = types.filter((type, i) => i % 2 === 0) - const gableEven = types.filter((type, i) => i % 2 === 1) const hasShed = types.includes(LINE_TYPE.WALLLINE.SHED) - // A형, B형 박공 지붕 - /* if ( - (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, 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) { diff --git a/src/components/floor-plan/modal/eavesGable/type/WallMerge.jsx b/src/components/floor-plan/modal/eavesGable/type/WallMerge.jsx index 0f80f9ec..31cf3909 100644 --- a/src/components/floor-plan/modal/eavesGable/type/WallMerge.jsx +++ b/src/components/floor-plan/modal/eavesGable/type/WallMerge.jsx @@ -18,7 +18,7 @@ export default function WallMerge({ offsetRef, radioTypeRef }) {
onChange(e)} /> - +
@@ -31,7 +31,7 @@ export default function WallMerge({ offsetRef, radioTypeRef }) {
onChange(e)} /> - +
diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index 11ac5684..b6fcb8cf 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -61,8 +61,7 @@ export function useEavesGableEdit(id) { const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') wallLines.forEach((wallLine) => { - const id = wallLine.id - wallLine.lines = outerLines.filter((line) => line.attributes?.wallId === id) + wallLine.lines = outerLines.filter((line) => line.attributes?.wallId === wallLine.id).sort((a, b) => a.idx - b.idx) }) wallLines.forEach((wallLine) => { convertPolygonToLines(wallLine) @@ -77,6 +76,38 @@ export function useEavesGableEdit(id) { convertLinesToPolygon(wallLine) }) initEvent() + + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + + outerLines.forEach((line) => { + let stroke, strokeWidth + if (line.attributes) { + if (line.attributes.type === LINE_TYPE.WALLLINE.EAVES || line.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + stroke = '#45CD7D' + strokeWidth = 4 + } else if (line.attributes.type === LINE_TYPE.WALLLINE.GABLE || line.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + stroke = '#3FBAE6' + strokeWidth = 4 + } else { + stroke = '#000000' + strokeWidth = 4 + } + + line.set({ + visible: true, + stroke, + strokeWidth, + selectable: false, + }) + + line.bringToFront() + } + }) + const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) + roofs.forEach((roof) => { + roof.innerLines.forEach((line) => line.set({ selectable: true })) + }) + canvas.renderAll() } }, []) @@ -106,6 +137,7 @@ export function useEavesGableEdit(id) { } const mouseDownEvent = (e) => { + canvas.discardActiveObject() if (!e.target || (e.target && e.target.name !== 'outerLine')) { return } diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index f1451bd1..4945fdd7 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -3,18 +3,16 @@ import { fabric } from 'fabric' import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util' -import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil' +import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { canvasSizeState, canvasState, canvasZoomState, fontSizeState } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { QPolygon } from '@/components/fabric/QPolygon' import { defineQLine } from '@/util/qline-utils' -import { defineQPloygon } from '@/util/qpolygon-utils' +import { defineQPolygon } from '@/util/qpolygon-utils' import { writeImage } from '@/lib/canvas' import { useCanvasEvent } from '@/hooks/useCanvasEvent' -import { useAxios } from '@/hooks/useAxios' import { useFont } from '@/hooks/common/useFont' -import { OBJECT_PROTOTYPE, POLYGON_TYPE, RELOAD_TYPE_PROTOTYPE, SAVE_KEY } from '@/common/common' -import { usePlan } from './usePlan' +import { OBJECT_PROTOTYPE, SAVE_KEY } from '@/common/common' import { imageDisplaySelector } from '@/store/settingAtom' export function useCanvas(id) { @@ -140,7 +138,7 @@ export function useCanvas(id) { QPolygon.prototype.canvas = canvas QLine.prototype.canvas = canvas defineQLine() - defineQPloygon() + defineQPolygon() } /** @@ -376,6 +374,8 @@ export function useCanvas(id) { /** * 이미지로 저장하는 함수 * @param {string} title - 저장할 이미지 이름 + * @param userId + * @param setThumbnails */ const saveImage = async (title = 'canvas', userId, setThumbnails) => { removeMouseLines() diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 7b99948b..8f1a72ce 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1,16 +1,15 @@ import { fabric } from 'fabric' import { QLine } from '@/components/fabric/QLine' -import { getDegreeByChon, isPointOnLine } from '@/util/canvas-util' +import { getAdjacent, getDegreeByChon, isPointOnLine } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import * as turf from '@turf/turf' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' -import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' import Big from 'big.js' const TWO_PI = Math.PI * 2 -export const defineQPloygon = () => { +export const defineQPolygon = () => { fabric.QPolygon.fromObject = function (object, callback) { fabric.Object._fromObject('QPolygon', object, callback, 'points') } @@ -378,15 +377,7 @@ export const drawShedRoof = (roofId, canvas, textMode) => { const gables = roof.lines.filter((line) => line.attributes?.type === LINE_TYPE.WALLLINE.GABLE) const eaves = roof.lines.filter((line) => line.attributes?.type === LINE_TYPE.WALLLINE.EAVES) - let shedDegree = sheds[0].attributes.degree || 0 - const shedChon = sheds[0].attributes.pitch || 0 - - if (shedDegree === 0) { - shedDegree = getDegreeByChon(shedChon) - } - const getHeight = function (adjust, degree) { - return Math.tan(degree * (Math.PI / 180)) * adjust - } + const shedDegree = getDegreeByChon(sheds[0].attributes.pitch) gables.forEach( (gable) => @@ -429,9 +420,6 @@ export const drawShedRoof = (roofId, canvas, textMode) => { 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 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], { @@ -465,12 +453,9 @@ export const drawShedRoof = (roofId, canvas, textMode) => { * @param textMode */ export const drawRidgeRoof = (roofId, canvas, textMode) => { - const roof = canvas?.getObjects().find((object) => object.id === roofId) + let roof = canvas?.getObjects().find((object) => object.id === roofId) const wall = canvas.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roofId) - console.log('wall.lines : ', wall.lines) - console.log('wall.baseLines : ', wall.baseLines) - 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) { return @@ -483,6 +468,231 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const baseLines = wall.baseLines.filter((line) => line.attributes.planeSize > 0) const baseLinePoints = baseLines.map((line) => ({ x: line.x1, y: line.y1 })) + /** 벽취합이 있는 경우 소매가 있다면 지붕 형상을 변경해야 한다. */ + console.log('baseLines :', baseLines) + console.log('roof : ', roof) + baseLines + .filter((line) => line.attributes.type === LINE_TYPE.WALLLINE.WALL && line.attributes.offset > 0) + .forEach((currentLine) => { + const prevLine = baseLines.find((line) => line.x2 === currentLine.x1 && line.y2 === currentLine.y1) + const nextLine = baseLines.find((line) => line.x1 === currentLine.x2 && line.y1 === currentLine.y2) + + const currentMidX = Big(currentLine.x1).plus(Big(currentLine.x2)).div(2).toNumber() + const currentMidY = Big(currentLine.y1).plus(Big(currentLine.y2)).div(2).toNumber() + const currentVectorX = Math.sign(currentLine.x2 - currentLine.x1) + const currentVectorY = Math.sign(currentLine.y2 - currentLine.y1) + + /** 현재 라인의 지붕 라인을 찾는다. */ + const intersectionRoofs = [] + let currentRoof + if (currentVectorX === 0) { + const checkEdge = { + vertex1: { x: prevLine.x1, y: currentMidY }, + vertex2: { x: currentMidX, y: currentMidY }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } else { + const checkEdge = { + vertex1: { x: currentMidX, y: prevLine.y1 }, + vertex2: { x: currentMidX, y: currentMidY }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } + if (intersectionRoofs.length > 0) { + currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line + } + if (currentRoof) { + const prevRoof = roof.lines.find((line) => line.x2 === currentRoof.x1 && line.y2 === currentRoof.y1) + const nextRoof = roof.lines.find((line) => line.x1 === currentRoof.x2 && line.y1 === currentRoof.y2) + + const prevOffset = prevLine.attributes.offset + const nextOffset = nextLine.attributes.offset + + currentRoof.set({ x1: currentLine.x1, y1: currentLine.y1, x2: currentLine.x2, y2: currentLine.y2 }) + + if (prevLine.attributes.type !== LINE_TYPE.WALLLINE.WALL && prevOffset > 0) { + const addPoint1 = [] + const addPoint2 = [] + if (Math.sign(prevLine.y2 - prevLine.y1) === 0) { + addPoint1.push(prevRoof.x2, prevRoof.y2, prevRoof.x2, currentRoof.y1) + addPoint2.push(addPoint1[2], addPoint1[3], currentRoof.x1, currentRoof.y1) + } else { + addPoint1.push(prevRoof.x2, prevRoof.y2, currentRoof.x1, prevRoof.y2) + addPoint2.push(addPoint1[2], addPoint1[3], currentRoof.x1, currentRoof.y1) + } + const addRoofLine1 = new QLine(addPoint1, { + name: 'addRoofLine', + parentId: roof.id, + fontSize: roof.fontSize, + stroke: '#1083E3', + strokeWidth: 2, + textMode: textMode, + attributes: { + roofId: roofId, + type: LINE_TYPE.WALLLINE.ETC, + planeSize: calcLinePlaneSize({ + x1: addPoint1[0], + y1: addPoint1[1], + x2: addPoint1[2], + y2: addPoint1[3], + }), + actualSize: calcLinePlaneSize({ + x1: addPoint1[0], + y1: addPoint1[1], + x2: addPoint1[2], + y2: addPoint1[3], + }), + }, + }) + + const addRoofLine2 = new QLine(addPoint2, { + name: 'addRoofLine', + parentId: roof.id, + fontSize: roof.fontSize, + stroke: '#1083E3', + strokeWidth: 2, + textMode: textMode, + attributes: { + roofId: roofId, + type: LINE_TYPE.WALLLINE.ETC, + planeSize: calcLinePlaneSize({ + x1: addPoint2[0], + y1: addPoint2[1], + x2: addPoint2[2], + y2: addPoint2[3], + }), + actualSize: calcLinePlaneSize({ + x1: addPoint2[0], + y1: addPoint2[1], + x2: addPoint2[2], + y2: addPoint2[3], + }), + }, + }) + canvas.add(addRoofLine1, addRoofLine2) + canvas.renderAll() + + const prevIndex = roof.lines.indexOf(prevRoof) + if (prevIndex === roof.lines.length - 1) { + roof.lines.unshift(addRoofLine1, addRoofLine2) + } else { + roof.lines.splice(prevIndex + 1, 0, addRoofLine1, addRoofLine2) + } + } else if (prevLine.attributes.type === LINE_TYPE.WALLLINE.WALL || prevOffset === 0) { + prevRoof.set({ x2: currentLine.x1, y2: currentLine.y1 }) + } + if (nextLine.attributes.type !== LINE_TYPE.WALLLINE.WALL && nextOffset > 0) { + const addPoint1 = [] + const addPoint2 = [] + if (Math.sign(nextLine.y2 - nextLine.y1) === 0) { + addPoint1.push(currentRoof.x2, currentRoof.y2, nextRoof.x1, currentRoof.y2) + addPoint2.push(addPoint1[2], addPoint1[3], nextRoof.x1, nextRoof.y1) + } else { + addPoint1.push(currentRoof.x2, currentRoof.y2, currentRoof.x2, nextRoof.y1) + addPoint2.push(addPoint1[2], addPoint1[3], nextRoof.x1, nextRoof.y1) + } + + const addRoofLine1 = new QLine(addPoint1, { + name: 'addRoofLine', + parentId: roof.id, + fontSize: roof.fontSize, + stroke: '#1083E3', + strokeWidth: 2, + textMode: textMode, + attributes: { + roofId: roofId, + type: LINE_TYPE.WALLLINE.ETC, + planeSize: calcLinePlaneSize({ + x1: addPoint1[0], + y1: addPoint1[1], + x2: addPoint1[2], + y2: addPoint1[3], + }), + actualSize: calcLinePlaneSize({ + x1: addPoint1[0], + y1: addPoint1[1], + x2: addPoint1[2], + y2: addPoint1[3], + }), + }, + }) + + const addRoofLine2 = new QLine(addPoint2, { + name: 'addRoofLine', + parentId: roof.id, + fontSize: roof.fontSize, + stroke: '#1083E3', + strokeWidth: 2, + textMode: textMode, + attributes: { + roofId: roofId, + type: LINE_TYPE.WALLLINE.ETC, + planeSize: calcLinePlaneSize({ + x1: addPoint2[0], + y1: addPoint2[1], + x2: addPoint2[2], + y2: addPoint2[3], + }), + actualSize: calcLinePlaneSize({ + x1: addPoint2[0], + y1: addPoint2[1], + x2: addPoint2[2], + y2: addPoint2[3], + }), + }, + }) + canvas.add(addRoofLine1, addRoofLine2) + canvas.renderAll() + + const nextIndex = roof.lines.indexOf(nextRoof) + if (nextIndex === 0) { + roof.lines.push(addRoofLine1, addRoofLine2) + } else { + roof.lines.splice(nextIndex, 0, addRoofLine1, addRoofLine2) + } + } else if (nextLine.attributes.type === LINE_TYPE.WALLLINE.WALL) { + if (Math.sign(nextLine.y2 - nextLine.y1) === 0) { + nextRoof.set({ x1: currentLine.x2, y1: nextRoof.y1 }) + } else { + nextRoof.set({ x1: nextRoof.x1, y1: currentLine.y2 }) + } + currentRoof.set({ x2: nextRoof.x1, y2: nextRoof.y1 }) + } else if (nextOffset === 0) { + nextRoof.set({ x1: currentLine.x2, y1: currentLine.y2 }) + } + + roof = reDrawPolygon(roof, canvas) + } + }) + /** 모양 판단을 위한 라인 처리. * 평행한 라인이 나누어져 있는 경우 하나의 선으로 판단 한다. */ @@ -541,6 +751,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const drawGablePolygonFirst = [] const drawGablePolygonSecond = [] const drawHipAndGableFirst = [] + const drawWallRidgeLine = [] /** 모양을 판단한다. */ drawBaseLines.forEach((currentBaseLine, index) => { @@ -584,22 +795,17 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } else { drawEavesSecondLines.push({ currentBaseLine, prevBaseLine, nextBaseLine }) } + } else if (eavesType.includes(nextLine.attributes?.type)) { + drawEavesSecondLines.push({ currentBaseLine, prevBaseLine, nextBaseLine }) } } else if (gableType.includes(nextLine.attributes?.type) && gableType.includes(prevLine.attributes?.type)) { if (Big(prevAngle).minus(Big(nextAngle)).abs().eq(180)) { - const checkPoints = { - x: currentMidX.plus(checkScale.times(Math.sign(xVector.toNumber()))).toNumber(), - y: currentMidY.plus(checkScale.times(Math.sign(yVector.toNumber()))).toNumber(), - } - if (checkWallPolygon.inPolygon(checkPoints)) { drawGablePolygonFirst.push({ currentBaseLine, prevBaseLine, nextBaseLine }) } else { drawGablePolygonSecond.push({ currentBaseLine, prevBaseLine, nextBaseLine }) } - // if (!checkWallPolygon.inPolygon(checkPoints)) { drawGableRidgeSecond.push({ currentBaseLine, prevBaseLine, nextBaseLine }) - // } } else { if (currentAngle !== prevAngle && currentAngle !== nextAngle) { drawGablePolygonSecond.push({ currentBaseLine, prevBaseLine, nextBaseLine }) @@ -609,29 +815,42 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } if (gableType.includes(currentLine.attributes?.type)) { - if (eavesType.includes(nextLine.attributes?.type)) { - if ( - eavesType.includes(prevLine.attributes?.type) && - eavesType.includes(nextLine.attributes?.type) && - Big(prevAngle).minus(Big(nextAngle)).abs().eq(180) - ) { - if (checkWallPolygon.inPolygon(checkPoints)) { - drawGableRidgeFirst.push({ currentBaseLine, prevBaseLine, nextBaseLine }) - } else { - drawGableRidgeSecond.push({ currentBaseLine, prevBaseLine, nextBaseLine }) - } + if ( + eavesType.includes(prevLine.attributes?.type) && + eavesType.includes(nextLine.attributes?.type) && + Big(prevAngle).minus(Big(nextAngle)).abs().eq(180) + ) { + if (checkWallPolygon.inPolygon(checkPoints)) { + drawGableRidgeFirst.push({ currentBaseLine, prevBaseLine, nextBaseLine }) + } else { + drawGableRidgeSecond.push({ currentBaseLine, prevBaseLine, nextBaseLine }) } } } - if (LINE_TYPE.WALLLINE.HIPANDGABLE === currentLine.attributes?.type) { + if ( + LINE_TYPE.WALLLINE.HIPANDGABLE === currentLine.attributes?.type && + eavesType.includes(nextLine.attributes?.type) && + eavesType.includes(prevLine.attributes?.type) + ) { drawHipAndGableFirst.push({ currentBaseLine, prevBaseLine, nextBaseLine }) } + + if ( + LINE_TYPE.WALLLINE.WALL === currentLine.attributes?.type && + eavesType.includes(nextLine.attributes?.type) && + eavesType.includes(prevLine.attributes?.type) + ) { + if (Big(prevAngle).minus(Big(nextAngle)).abs().eq(180) && checkWallPolygon.inPolygon(checkPoints)) { + drawWallRidgeLine.push({ currentBaseLine, prevBaseLine, nextBaseLine }) + } + } }) drawEavesFirstLines.sort((a, b) => a.currentBaseLine.size - b.currentBaseLine.size) drawGableRidgeFirst.sort((a, b) => a.currentBaseLine.size - b.currentBaseLine.size) drawGableRidgeSecond.sort((a, b) => a.currentBaseLine.size - b.currentBaseLine.size) + drawWallRidgeLine.sort((a, b) => a.currentBaseLine.size - b.currentBaseLine.size) /** 추녀마루 */ let baseHipLines = [] @@ -651,6 +870,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { console.log('drawGableRidgeSecond:', drawGableRidgeSecond) console.log('drawGablePolygonFirst :', drawGablePolygonFirst) console.log('drawGablePolygonSecond :', drawGablePolygonSecond) + console.log('drawHipAndGableFirst :', drawHipAndGableFirst) + console.log('drawWallLines :', drawWallRidgeLine) /** 박공지붕에서 파생되는 마루를 그린다. ㄷ 형태*/ drawGableRidgeFirst.forEach((current) => { @@ -663,11 +884,9 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { let beforePrevBaseLine, afterNextBaseLine /** 이전 라인의 경사 */ - const prevDegree = prevLine.attributes.pitch > 0 ? getDegreeByChon(prevLine.attributes.pitch) : prevLine.attributes.degree + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) /** 다음 라인의 경사 */ - const nextDegree = nextLine.attributes.pitch > 0 ? getDegreeByChon(nextLine.attributes.pitch) : nextLine.attributes.degree - /** 현재 라인의 경사 */ - const currentDegree = currentLine.attributes.pitch > 0 ? getDegreeByChon(currentLine.attributes.pitch) : currentLine.attributes.degree + const nextDegree = getDegreeByChon(nextLine.attributes.pitch) /** 이전 라인의 전라인, 다음 라인의 다음라인을 찾는다 */ drawBaseLines.forEach((line, index) => { @@ -709,6 +928,60 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { let oppositeMidX = currentMidX, oppositeMidY = currentMidY + /** 현재 라인의 지붕 라인을 찾는다. */ + const intersectionRoofs = [] + let currentRoof + if (currentVectorX === 0) { + const checkEdge = { + vertex1: { x: prevLine.x1, y: currentMidY.toNumber() }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } else { + const checkEdge = { + vertex1: { x: currentMidX.toNumber(), y: prevLine.y1 }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } + if (intersectionRoofs.length > 0) { + currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line + } + + /** 현재 라인의 지붕선에서 이전 지붕선, 다음 지붕선으로 향하는 vector*/ + const prevRoofVectorX = Math.sign(currentRoof.x2 - currentRoof.x1) + const prevRoofVectorY = Math.sign(currentRoof.y2 - currentRoof.y1) + const nextRoofVectorX = Math.sign(currentRoof.x1 - currentRoof.x2) + const nextRoofVectorY = Math.sign(currentRoof.y1 - currentRoof.y2) + /** 한개의 지붕선을 둘로 나누어서 처리 하는 경우 */ if (prevAngle === beforePrevAngle || nextAngle === afterNextAngle) { if (currentVectorX === 0) { @@ -861,6 +1134,73 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { line: nextHipLine, }) } + const vectorOppositeX = Math.sign(currentMidX.minus(oppositeMidX)) + const vectorOppositeY = Math.sign(currentMidY.minus(oppositeMidY)) + + /** 반철처 인 경우 처리 */ + if (currentLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const width = Big(currentLine.attributes.width).div(2) + const degree = getDegreeByChon(currentLine.attributes.pitch) + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) + const nextDegree = getDegreeByChon(nextLine.attributes.pitch) + if (vectorOppositeY === 0) { + currentMidX = currentMidX.minus(Big(width).times(vectorOppositeX)) + } else { + currentMidY = currentMidY.minus(Big(width).times(vectorOppositeY)) + } + + /** 현재 라인에서 반철처 부분을 그린다.*/ + let firstHipPoint, secondHipPoint, connectHipPoint, firstRoofPoint, secondRoofPoint + if (vectorOppositeY === 0) { + firstHipPoint = [ + currentMidX.plus(Big(width).times(vectorOppositeX)).toNumber(), + currentMidY.minus(Big(width).times(prevRoofVectorY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + + secondHipPoint = [ + currentMidX.plus(Big(width).times(vectorOppositeX)).toNumber(), + currentMidY.minus(Big(width).times(nextRoofVectorY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + } else { + firstHipPoint = [ + currentMidX.plus(Big(width).times(prevRoofVectorX)).toNumber(), + currentMidY.plus(Big(width).times(vectorOppositeY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + + secondHipPoint = [ + currentMidX.plus(Big(width).times(nextRoofVectorX)).toNumber(), + currentMidY.plus(Big(width).times(vectorOppositeY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + } + connectHipPoint = [firstHipPoint[0], firstHipPoint[1], secondHipPoint[0], secondHipPoint[1]] + firstRoofPoint = [currentRoof.x1, currentRoof.y1, firstHipPoint[0], firstHipPoint[1]] + secondRoofPoint = [currentRoof.x2, currentRoof.y2, secondHipPoint[0], secondHipPoint[1]] + const firstHipLine = drawHipLine(firstHipPoint, canvas, roof, textMode, null, degree, degree) + const firstRoofLine = drawHipLine(firstRoofPoint, canvas, roof, textMode, null, prevDegree, prevDegree) + const secondHipLine = drawHipLine(secondHipPoint, canvas, roof, textMode, null, degree, degree) + const secondRoofLine = drawHipLine(secondRoofPoint, canvas, roof, textMode, null, nextDegree, nextDegree) + const connectHipLine = drawRoofLine(connectHipPoint, canvas, roof, textMode) + baseHipLines.push({ x1: firstHipLine.x1, y1: firstHipLine.y1, x2: firstHipLine.x2, y2: firstHipLine.y2, line: firstHipLine }) + baseHipLines.push({ x1: firstRoofLine.x1, y1: firstRoofLine.y1, x2: firstRoofLine.x2, y2: firstRoofLine.y2, line: firstRoofLine }) + baseHipLines.push({ x1: secondHipLine.x1, y1: secondHipLine.y1, x2: secondHipLine.x2, y2: secondHipLine.y2, line: secondHipLine }) + baseHipLines.push({ x1: secondRoofLine.x1, y1: secondRoofLine.y1, x2: secondRoofLine.x2, y2: secondRoofLine.y2, line: secondRoofLine }) + baseHipLines.push({ x1: connectHipLine.x1, y1: connectHipLine.y1, x2: connectHipLine.x2, y2: connectHipLine.y2, line: connectHipLine }) + } else { + const firstHipPoint = [currentRoof.x1, currentRoof.y1, currentMidX.toNumber(), currentMidY.toNumber()] + const secondHipPoint = [currentRoof.x2, currentRoof.y2, currentMidX.toNumber(), currentMidY.toNumber()] + const firstHipLine = drawHipLine(firstHipPoint, canvas, roof, textMode, null, prevDegree, prevDegree) + const secondHipLine = drawHipLine(secondHipPoint, canvas, roof, textMode, null, nextDegree, nextDegree) + baseHipLines.push({ x1: firstHipLine.x1, y1: firstHipLine.y1, x2: firstHipLine.x2, y2: firstHipLine.y2, line: firstHipLine }) + baseHipLines.push({ x1: secondHipLine.x1, y1: secondHipLine.y1, x2: secondHipLine.x2, y2: secondHipLine.y2, line: secondHipLine }) + } if (baseRidgeCount < getMaxRidge(baseLines.length)) { const ridgeLine = drawRidgeLine( @@ -880,7 +1220,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const vectorMidY = Math.sign(currentMidY.minus(afterNextMidY)) let oppositeMidX, oppositeMidY - if (eavesType.includes(afterNextLine.attributes?.type)) { + if (afterNextLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { const checkSize = currentMidX .minus(afterNextMidX) .pow(2) @@ -937,8 +1277,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: oppositeMidY.plus(addOppositeY2), }) - const afterNextDegree = - afterNextLine.attributes.pitch > 0 ? getDegreeByChon(afterNextLine.attributes.pitch) : afterNextLine.attributes.degree + const afterNextDegree = getDegreeByChon(afterNextLine.attributes.pitch) if (intersection1) { const hipLine = drawHipLine( @@ -984,7 +1323,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const vectorOppositeX = Math.sign(currentMidX.minus(oppositeMidX)) const vectorOppositeY = Math.sign(currentMidY.minus(oppositeMidY)) - if (vectorMidX === vectorOppositeX && vectorMidY === vectorOppositeY && baseRidgeCount < getMaxRidge(baseLines.length)) { + if (vectorMidX === vectorOppositeX && vectorMidY === vectorOppositeY) { if (!roof.inPolygon({ x: currentMidX.toNumber(), y: currentMidY.toNumber() })) { const checkEdge = { vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, @@ -1055,14 +1394,99 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } } - const ridge = drawRidgeLine( - [currentMidX.toNumber(), currentMidY.toNumber(), oppositeMidX.toNumber(), oppositeMidY.toNumber()], - canvas, - roof, - textMode, - ) - baseGableRidgeLines.push(ridge) - baseRidgeCount++ + if (afterNextLine.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + const width = afterNextLine.attributes.width + if (vectorOppositeY === 0) { + oppositeMidX = oppositeMidX.plus(Big(width).times(vectorOppositeX)) + } else { + oppositeMidY = oppositeMidY.plus(Big(width).times(vectorOppositeY)) + } + } + + if (afterNextLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const width = Big(afterNextLine.attributes.width).div(2).toNumber() + if (vectorOppositeY === 0) { + oppositeMidX = oppositeMidX.plus(Big(width).times(vectorOppositeX)) + } else { + oppositeMidY = oppositeMidY.plus(Big(width).times(vectorOppositeY)) + } + } + + /** 반철처 인 경우 처리 */ + if (currentLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const width = Big(currentLine.attributes.width).div(2) + const degree = getDegreeByChon(currentLine.attributes.pitch) + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) + const nextDegree = getDegreeByChon(nextLine.attributes.pitch) + if (vectorMidY === 0) { + currentMidX = currentMidX.minus(Big(width).times(vectorOppositeX)) + } else { + currentMidY = currentMidY.minus(Big(width).times(vectorOppositeY)) + } + + /** 현재 라인에서 반철처 부분을 그린다.*/ + let firstHipPoint, secondHipPoint, connectHipPoint, firstRoofPoint, secondRoofPoint + if (vectorMidY === 0) { + firstHipPoint = [ + currentMidX.plus(Big(width).times(vectorOppositeX)).toNumber(), + currentMidY.minus(Big(width).times(prevRoofVectorY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + + secondHipPoint = [ + currentMidX.plus(Big(width).times(vectorOppositeX)).toNumber(), + currentMidY.minus(Big(width).times(nextRoofVectorY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + } else { + firstHipPoint = [ + currentMidX.minus(Big(width).times(prevRoofVectorX)).toNumber(), + currentMidY.plus(Big(width).times(vectorOppositeY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + + secondHipPoint = [ + currentMidX.minus(Big(width).times(nextRoofVectorX)).toNumber(), + currentMidY.plus(Big(width).times(vectorOppositeY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + } + connectHipPoint = [firstHipPoint[0], firstHipPoint[1], secondHipPoint[0], secondHipPoint[1]] + firstRoofPoint = [currentRoof.x1, currentRoof.y1, firstHipPoint[0], firstHipPoint[1]] + secondRoofPoint = [currentRoof.x2, currentRoof.y2, secondHipPoint[0], secondHipPoint[1]] + const firstHipLine = drawHipLine(firstHipPoint, canvas, roof, textMode, null, degree, degree) + const firstRoofLine = drawHipLine(firstRoofPoint, canvas, roof, textMode, null, prevDegree, prevDegree) + const secondHipLine = drawHipLine(secondHipPoint, canvas, roof, textMode, null, degree, degree) + const secondRoofLine = drawHipLine(secondRoofPoint, canvas, roof, textMode, null, nextDegree, nextDegree) + const connectHipLine = drawRoofLine(connectHipPoint, canvas, roof, textMode) + baseHipLines.push({ x1: firstHipLine.x1, y1: firstHipLine.y1, x2: firstHipLine.x2, y2: firstHipLine.y2, line: firstHipLine }) + baseHipLines.push({ x1: firstRoofLine.x1, y1: firstRoofLine.y1, x2: firstRoofLine.x2, y2: firstRoofLine.y2, line: firstRoofLine }) + baseHipLines.push({ x1: secondHipLine.x1, y1: secondHipLine.y1, x2: secondHipLine.x2, y2: secondHipLine.y2, line: secondHipLine }) + baseHipLines.push({ x1: secondRoofLine.x1, y1: secondRoofLine.y1, x2: secondRoofLine.x2, y2: secondRoofLine.y2, line: secondRoofLine }) + baseHipLines.push({ x1: connectHipLine.x1, y1: connectHipLine.y1, x2: connectHipLine.x2, y2: connectHipLine.y2, line: connectHipLine }) + } else { + const firstHipPoint = [currentRoof.x1, currentRoof.y1, currentMidX.toNumber(), currentMidY.toNumber()] + const secondHipPoint = [currentRoof.x2, currentRoof.y2, currentMidX.toNumber(), currentMidY.toNumber()] + const firstHipLine = drawHipLine(firstHipPoint, canvas, roof, textMode, null, prevDegree, prevDegree) + const secondHipLine = drawHipLine(secondHipPoint, canvas, roof, textMode, null, nextDegree, nextDegree) + baseHipLines.push({ x1: firstHipLine.x1, y1: firstHipLine.y1, x2: firstHipLine.x2, y2: firstHipLine.y2, line: firstHipLine }) + baseHipLines.push({ x1: secondHipLine.x1, y1: secondHipLine.y1, x2: secondHipLine.x2, y2: secondHipLine.y2, line: secondHipLine }) + } + + if (baseRidgeCount < getMaxRidge(baseLines.length)) { + const ridge = drawRidgeLine( + [currentMidX.toNumber(), currentMidY.toNumber(), oppositeMidX.toNumber(), oppositeMidY.toNumber()], + canvas, + roof, + textMode, + ) + baseGableRidgeLines.push(ridge) + baseRidgeCount++ + } } } else { const vectorMidX = Math.sign(Big(nextLine.x2).minus(nextLine.x1)) @@ -1357,8 +1781,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { }) const intersect = intersectPoints.sort((a, b) => a.size - b.size)[0] if (intersect) { - const degree = - intersect.line.attributes.pitch > 0 ? getDegreeByChon(intersect.line.attributes.pitch) : intersect.line.attributes.degree + const degree = getDegreeByChon(intersect.line.attributes.pitch) const hipLine = drawHipLine( [intersect.intersection.x, intersect.intersection.y, nextOppositeMidX.toNumber(), nextOppositeMidY.toNumber()], canvas, @@ -1421,8 +1844,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const intersect = intersectPoints.sort((a, b) => a.size - b.size)[0] if (intersect) { - const degree = - intersect.line.attributes.pitch > 0 ? getDegreeByChon(intersect.line.attributes.pitch) : intersect.line.attributes.degree + const degree = getDegreeByChon(intersect.line.attributes.pitch) const hipLine = drawHipLine( [intersect.intersection.x, intersect.intersection.y, prevOppositeMidX.toNumber(), prevOppositeMidY.toNumber()], canvas, @@ -1445,8 +1867,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { oppositeMidX = prevOppositeMidX } } - } - if (baseRidgeCount < getMaxRidge(baseLines.length)) { + /** 포인트가 지붕 밖에 있는 경우 조정 */ if (!roof.inPolygon({ x: currentMidX.toNumber(), y: currentMidY.toNumber() })) { const checkEdge = { @@ -1518,6 +1939,74 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } } + const vectorOppositeX = Math.sign(currentMidX.minus(oppositeMidX)) + const vectorOppositeY = Math.sign(currentMidY.minus(oppositeMidY)) + + /** 반철처 인 경우 처리 */ + if (currentLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const width = Big(currentLine.attributes.width).div(2) + const degree = getDegreeByChon(currentLine.attributes.pitch) + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) + const nextDegree = getDegreeByChon(nextLine.attributes.pitch) + if (vectorOppositeY === 0) { + currentMidX = currentMidX.minus(Big(width).times(vectorOppositeX)) + } else { + currentMidY = currentMidY.minus(Big(width).times(vectorOppositeY)) + } + + /** 현재 라인에서 반철처 부분을 그린다.*/ + let firstHipPoint, secondHipPoint, connectHipPoint, firstRoofPoint, secondRoofPoint + if (vectorOppositeY === 0) { + firstHipPoint = [ + currentMidX.plus(Big(width).times(vectorOppositeX)).toNumber(), + currentMidY.minus(Big(width).times(prevRoofVectorY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + + secondHipPoint = [ + currentMidX.plus(Big(width).times(vectorOppositeX)).toNumber(), + currentMidY.minus(Big(width).times(nextRoofVectorY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + } else { + firstHipPoint = [ + currentMidX.minus(Big(width).times(prevRoofVectorX)).toNumber(), + currentMidY.plus(Big(width).times(vectorOppositeY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + + secondHipPoint = [ + currentMidX.minus(Big(width).times(nextRoofVectorX)).toNumber(), + currentMidY.plus(Big(width).times(vectorOppositeY)).toNumber(), + currentMidX.toNumber(), + currentMidY.toNumber(), + ] + } + connectHipPoint = [firstHipPoint[0], firstHipPoint[1], secondHipPoint[0], secondHipPoint[1]] + firstRoofPoint = [currentRoof.x1, currentRoof.y1, firstHipPoint[0], firstHipPoint[1]] + secondRoofPoint = [currentRoof.x2, currentRoof.y2, secondHipPoint[0], secondHipPoint[1]] + const firstHipLine = drawHipLine(firstHipPoint, canvas, roof, textMode, null, degree, degree) + const firstRoofLine = drawHipLine(firstRoofPoint, canvas, roof, textMode, null, prevDegree, prevDegree) + const secondHipLine = drawHipLine(secondHipPoint, canvas, roof, textMode, null, degree, degree) + const secondRoofLine = drawHipLine(secondRoofPoint, canvas, roof, textMode, null, nextDegree, nextDegree) + const connectHipLine = drawRoofLine(connectHipPoint, canvas, roof, textMode) + baseHipLines.push({ x1: firstHipLine.x1, y1: firstHipLine.y1, x2: firstHipLine.x2, y2: firstHipLine.y2, line: firstHipLine }) + baseHipLines.push({ x1: firstRoofLine.x1, y1: firstRoofLine.y1, x2: firstRoofLine.x2, y2: firstRoofLine.y2, line: firstRoofLine }) + baseHipLines.push({ x1: secondHipLine.x1, y1: secondHipLine.y1, x2: secondHipLine.x2, y2: secondHipLine.y2, line: secondHipLine }) + baseHipLines.push({ x1: secondRoofLine.x1, y1: secondRoofLine.y1, x2: secondRoofLine.x2, y2: secondRoofLine.y2, line: secondRoofLine }) + baseHipLines.push({ x1: connectHipLine.x1, y1: connectHipLine.y1, x2: connectHipLine.x2, y2: connectHipLine.y2, line: connectHipLine }) + } else { + const firstHipPoint = [currentRoof.x1, currentRoof.y1, currentMidX.toNumber(), currentMidY.toNumber()] + const secondHipPoint = [currentRoof.x2, currentRoof.y2, currentMidX.toNumber(), currentMidY.toNumber()] + const firstHipLine = drawHipLine(firstHipPoint, canvas, roof, textMode, null, prevDegree, prevDegree) + const secondHipLine = drawHipLine(secondHipPoint, canvas, roof, textMode, null, nextDegree, nextDegree) + baseHipLines.push({ x1: firstHipLine.x1, y1: firstHipLine.y1, x2: firstHipLine.x2, y2: firstHipLine.y2, line: firstHipLine }) + baseHipLines.push({ x1: secondHipLine.x1, y1: secondHipLine.y1, x2: secondHipLine.x2, y2: secondHipLine.y2, line: secondHipLine }) + } + /** 마루가 맞은편 외벽선에 닿는 경우 해당 부분까지로 한정한다. */ const ridgeEdge = { vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, @@ -1546,14 +2035,16 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } } }) - const ridgeLine = drawRidgeLine( - [currentMidX.toNumber(), currentMidY.toNumber(), oppositeMidX.toNumber(), oppositeMidY.toNumber()], - canvas, - roof, - textMode, - ) - baseGableRidgeLines.push(ridgeLine) - baseRidgeCount++ + if (baseRidgeCount < getMaxRidge(baseLines.length)) { + const ridgeLine = drawRidgeLine( + [currentMidX.toNumber(), currentMidY.toNumber(), oppositeMidX.toNumber(), oppositeMidY.toNumber()], + canvas, + roof, + textMode, + ) + baseGableRidgeLines.push(ridgeLine) + baseRidgeCount++ + } } } }) @@ -1565,12 +2056,19 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const prevLine = prevBaseLine.line const nextLine = nextBaseLine.line + const checkLine = new fabric.Line([currentLine.x1, currentLine.y1, currentLine.x2, currentLine.y2], { + stroke: 'red', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + canvas.add(checkLine) + canvas.renderAll() + /** 이전 라인의 경사 */ - const prevDegree = prevLine.attributes.pitch > 0 ? getDegreeByChon(prevLine.attributes.pitch) : prevLine.attributes.degree + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) /** 다음 라인의 경사 */ - const nextDegree = nextLine.attributes.pitch > 0 ? getDegreeByChon(nextLine.attributes.pitch) : nextLine.attributes.degree - /** 현재 라인의 경사 */ - const currentDegree = currentLine.attributes.pitch > 0 ? getDegreeByChon(currentLine.attributes.pitch) : currentLine.attributes.degree + const nextDegree = getDegreeByChon(nextLine.attributes.pitch) const currentAngle = calculateAngle(currentLine.startPoint, currentLine.endPoint) const currentVectorX = Big(currentLine.x2).minus(currentLine.x1) @@ -1581,11 +2079,63 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const currentMidY = Big(currentLine.y1).plus(Big(currentLine.y2)).div(2) const checkSize = Big(10) - const checkPoints = { - x: currentMidX.plus(checkSize.times(Math.sign(checkVectorX.toNumber()))).toNumber(), - y: currentMidY.plus(checkSize.times(Math.sign(checkVectorY.toNumber()))).toNumber(), + /** 현재 라인의 지붕선을 찾는다. */ + const intersectionRoofs = [] + if (currentVectorX.eq(0)) { + const checkEdge = { + vertex1: { x: prevLine.x1, y: currentMidY.toNumber() }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter( + (line) => + Math.sign(line.x2 - line.x1) === Math.sign(currentVectorX.toNumber()) && + Math.sign(line.y2 - line.y1) === Math.sign(currentVectorY.toNumber()), + ) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber(), + }) + } + } + }) + } else { + const checkEdge = { + vertex1: { x: currentMidX.toNumber(), y: prevLine.y1 }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter( + (line) => + Math.sign(line.x2 - line.x1) === Math.sign(currentVectorX.toNumber()) && + Math.sign(line.y2 - line.y1) === Math.sign(currentVectorY.toNumber()), + ) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber(), + }) + } + } + }) } - if (!checkWallPolygon.inPolygon(checkPoints)) { + let currentRoof + if (intersectionRoofs.length > 0) { + currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line + } + + if (currentLine.attributes.type === LINE_TYPE.WALLLINE.EAVES || currentLine.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { const currentMidEdge = { vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, vertex2: { @@ -1593,16 +2143,10 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: currentMidY.plus(checkSize.times(Math.sign(checkVectorY.neg().toNumber()))).toNumber(), }, } - let oppositeLines = [] baseLines - .filter((line, index) => { - let nextLine = baseLines[(index + 1) % baseLines.length] - let prevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length] - if ( - (gableType.includes(nextLine.attributes.type) && gableType.includes(prevLine.attributes.type)) || - (eavesType.includes(nextLine.attributes.type) && eavesType.includes(prevLine.attributes.type)) - ) { + .filter((line) => { + if (eavesType.includes(line.attributes.type)) { const angle = calculateAngle(line.startPoint, line.endPoint) switch (currentAngle) { case 90: @@ -1613,9 +2157,12 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { return angle === 180 case 180: return angle === 0 + default: + return false } + } else { + return false } - return false }) .forEach((line) => { const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } @@ -1632,207 +2179,297 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { if (oppositeLines.length === 0) { return } - const oppositeLine = oppositeLines.sort((a, b) => a.size - b.size)[0] + const oppositeLine = oppositeLines.sort((a, b) => b.size - a.size)[0].line - let points = [] - if (eavesType.includes(oppositeLine.line.attributes.type)) { - const oppositeCurrentLine = oppositeLine.line - let oppositePrevLine, oppositeNextLine - baseLines.forEach((line, index) => { - if (line === oppositeCurrentLine) { - oppositePrevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length] - oppositeNextLine = baseLines[(index + 1) % baseLines.length] - } - }) - if (gableType.includes(oppositeNextLine.attributes.type) && gableType.includes(oppositePrevLine.attributes.type)) { - if (currentVectorX.eq(0)) { - const centerX = currentMidX.plus(oppositeLine.intersection.x).div(2).toNumber() - points = [centerX, currentLine.y1, centerX, currentLine.y2] - } else { - const centerY = currentMidY.plus(oppositeLine.intersection.y).div(2).toNumber() - points = [currentLine.x1, centerY, currentLine.x2, centerY] - } - } - if (eavesType.includes(oppositeNextLine.attributes.type) && eavesType.includes(oppositePrevLine.attributes.type)) { - /** 이전, 다음라인의 사잇각의 vector를 구한다. */ - let prevVector = getHalfAngleVector(oppositePrevLine, oppositeCurrentLine) - let nextVector = getHalfAngleVector(oppositeCurrentLine, oppositeNextLine) - - let prevHipVector = { x: Big(prevVector.x), y: Big(prevVector.y) } - let nextHipVector = { x: Big(nextVector.x), y: Big(nextVector.y) } - - /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ - const prevCheckPoint = { - x: Big(oppositeCurrentLine.x1).plus(Big(prevHipVector.x).times(10)), - y: Big(oppositeCurrentLine.y1).plus(Big(prevHipVector.y).times(10)), - } - if (!checkWallPolygon.inPolygon(prevCheckPoint)) { - prevHipVector = { x: Big(prevHipVector.x).neg(), y: Big(prevHipVector.y).neg() } - } - - /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ - const nextCheckPoint = { - x: Big(oppositeCurrentLine.x2).plus(Big(nextHipVector.x).times(10)), - y: Big(oppositeCurrentLine.y2).plus(Big(nextHipVector.y).times(10)), - } - if (!checkWallPolygon.inPolygon(nextCheckPoint)) { - nextHipVector = { x: Big(nextHipVector.x).neg(), y: Big(nextHipVector.y).neg() } - } - - /** 현재 라인의 길이를 기준으로 추녀 마루의 길이를 삼각함수를 사용하여 판단한다.*/ - let hipLength = Big(oppositeCurrentLine.attributes.planeSize) - .div(2) - .pow(2) - .plus(Big(oppositeCurrentLine.attributes.planeSize).div(2).pow(2)) - .sqrt() - .div(10) - .round(2) - - const ridgeEndPoint = { - x: Big(oppositeCurrentLine.x1).plus(hipLength.times(prevHipVector.x)).round(1), - y: Big(oppositeCurrentLine.y1).plus(hipLength.times(prevHipVector.y)).round(1), - } - - const prevHypotenuse = Big(oppositePrevLine.attributes.offset).pow(2).plus(Big(oppositeCurrentLine.attributes.offset).pow(2)).sqrt() - const prevHipPoints = { - x1: Big(oppositeCurrentLine.x1).plus(prevHypotenuse.times(prevHipVector.x.neg())).round(1).toNumber(), - y1: Big(oppositeCurrentLine.y1).plus(prevHypotenuse.times(prevHipVector.y.neg())).round(1).toNumber(), - x2: ridgeEndPoint.x.toNumber(), - y2: ridgeEndPoint.y.toNumber(), - } - - const nextHypotenuse = Big(oppositeNextLine.attributes.offset).pow(2).plus(Big(oppositeCurrentLine.attributes.offset).pow(2)).sqrt() - const nextHipPoints = { - x1: Big(oppositeCurrentLine.x2).plus(nextHypotenuse.times(nextHipVector.x.neg())).round(1).toNumber(), - y1: Big(oppositeCurrentLine.y2).plus(nextHypotenuse.times(nextHipVector.y.neg())).round(1).toNumber(), - x2: ridgeEndPoint.x.toNumber(), - y2: ridgeEndPoint.y.toNumber(), - } - - const prevIntersection = findRoofIntersection(roof, prevHipPoints, ridgeEndPoint) - const nextIntersection = findRoofIntersection(roof, nextHipPoints, ridgeEndPoint) - - if (prevIntersection) { - const prevHip = drawHipLine( - [prevIntersection.intersection.x, prevIntersection.intersection.y, ridgeEndPoint.x.toNumber(), ridgeEndPoint.y.toNumber()], - canvas, - roof, - textMode, - null, - prevDegree, - prevDegree, - ) - baseHipLines.push({ - x1: oppositeCurrentLine.x1, - y1: oppositeCurrentLine.y1, - x2: ridgeEndPoint.x, - y2: ridgeEndPoint.y, - line: prevHip, - }) - } - if (nextIntersection) { - const nextHip = drawHipLine( - [nextIntersection.intersection.x, nextIntersection.intersection.y, ridgeEndPoint.x.toNumber(), ridgeEndPoint.y.toNumber()], - canvas, - roof, - textMode, - null, - nextDegree, - nextDegree, - ) - baseHipLines.push({ - x1: ridgeEndPoint.x, - y1: ridgeEndPoint.y, - x2: oppositeCurrentLine.x2, - y2: oppositeCurrentLine.y2, - line: nextHip, - }) - } - - const ridgeVectorX = Math.sign(currentMidX.minus(ridgeEndPoint.x).toNumber()) - const ridgeVectorY = Math.sign(currentMidY.minus(ridgeEndPoint.y).toNumber()) - const ridgePoints = { - x1: currentMidX.plus(Big(currentLine.attributes.offset).times(ridgeVectorX)).toNumber(), - y1: currentMidY.plus(Big(currentLine.attributes.offset).times(ridgeVectorY)).toNumber(), - x2: ridgeEndPoint.x.toNumber(), - y2: ridgeEndPoint.y.toNumber(), - } - const ridgeIntersection = findRoofIntersection(roof, ridgePoints, { - x: Big(ridgePoints.x2), - y: Big(ridgePoints.y2), - }) - if (ridgeIntersection) { - points = [ridgeIntersection.intersection.x, ridgeIntersection.intersection.y, ridgeEndPoint.x, ridgeEndPoint.y] - } - } + let ridgePoint + if (currentVectorY.eq(0)) { + const ridgeY = Big(currentLine.y1).plus(Big(oppositeLine.y1)).div(2).round() + ridgePoint = [currentRoof.x1, ridgeY.toNumber(), currentRoof.x2, ridgeY.toNumber()] } else { - if (currentVectorX.eq(0)) { - points = [oppositeLine.intersection.x, currentLine.y1, oppositeLine.intersection.x, currentLine.y2] - } else { - points = [currentLine.x1, oppositeLine.intersection.y, currentLine.x2, oppositeLine.intersection.y] - } + const ridgeX = Big(currentLine.x1).plus(Big(oppositeLine.x1)).div(2).round() + ridgePoint = [ridgeX.toNumber(), currentRoof.y1, ridgeX.toNumber(), currentRoof.y2] } - - if (baseRidgeCount < getMaxRidge(baseLines.length)) { - const ridgeLine = drawRidgeLine(points, canvas, roof, textMode) + const isAlreadyRidge = baseGableRidgeLines.find( + (line) => + (line.x1 === ridgePoint[0] && line.y1 === ridgePoint[1] && line.x2 === ridgePoint[2] && line.y2 === ridgePoint[3]) || + (line.x1 === ridgePoint[2] && line.y1 === ridgePoint[3] && line.x2 === ridgePoint[0] && line.y2 === ridgePoint[1]), + ) + if (baseRidgeCount < getMaxRidge(baseLines.length) && !isAlreadyRidge) { + const ridgeLine = drawRidgeLine(ridgePoint, canvas, roof, textMode) baseGableRidgeLines.push(ridgeLine) baseRidgeCount++ } } else { - const oppositeLines = baseLines.filter((line) => { - const lineAngle = calculateAngle(line.startPoint, line.endPoint) - switch (currentAngle) { - case 90: - return lineAngle === -90 - case -90: - return lineAngle === 90 - case 0: - return lineAngle === 180 - case 180: - return lineAngle === 0 + const checkPoints = { + x: currentMidX.plus(checkSize.times(Math.sign(checkVectorX.toNumber()))).toNumber(), + y: currentMidY.plus(checkSize.times(Math.sign(checkVectorY.toNumber()))).toNumber(), + } + if (!checkWallPolygon.inPolygon(checkPoints)) { + const currentMidEdge = { + vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + vertex2: { + x: currentMidX.plus(checkSize.times(Math.sign(checkVectorX.neg().toNumber()))).toNumber(), + y: currentMidY.plus(checkSize.times(Math.sign(checkVectorY.neg().toNumber()))).toNumber(), + }, } - }) - if (oppositeLines.length > 0 && baseRidgeCount < getMaxRidge(baseLines.length)) { - let ridgePoints = [] - const oppositeLine = oppositeLines.sort((a, b) => { - let diffCurrentA, diffCurrentB - if (Math.sign(currentVectorX) === 0) { - diffCurrentA = currentMidY.minus(a.y1).abs() - diffCurrentB = currentMidY.minus(b.y1).abs() - } else { - diffCurrentA = currentMidX.minus(a.x1).abs() - diffCurrentB = currentMidX.minus(b.x1).abs() + let oppositeLines = [] + baseLines + .filter((line, index) => { + let nextLine = baseLines[(index + 1) % baseLines.length] + let prevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length] + if ( + (gableType.includes(nextLine.attributes.type) && gableType.includes(prevLine.attributes.type)) || + (eavesType.includes(nextLine.attributes.type) && eavesType.includes(prevLine.attributes.type)) + ) { + const angle = calculateAngle(line.startPoint, line.endPoint) + switch (currentAngle) { + case 90: + return angle === -90 + case -90: + return angle === 90 + case 0: + return angle === 180 + case 180: + return angle === 0 + } + } + return false + }) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(currentMidEdge, lineEdge) + if (intersection) { + oppositeLines.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + }) + + if (oppositeLines.length === 0) { + return + } + const oppositeLine = oppositeLines.sort((a, b) => a.size - b.size)[0] + + let points = [] + if (eavesType.includes(oppositeLine.line.attributes.type)) { + const oppositeCurrentLine = oppositeLine.line + let oppositePrevLine, oppositeNextLine + baseLines.forEach((line, index) => { + if (line === oppositeCurrentLine) { + oppositePrevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length] + oppositeNextLine = baseLines[(index + 1) % baseLines.length] + } + }) + if (gableType.includes(oppositeNextLine.attributes.type) && gableType.includes(oppositePrevLine.attributes.type)) { + if (currentVectorX.eq(0)) { + const centerX = currentMidX.plus(oppositeLine.intersection.x).div(2).toNumber() + points = [centerX, currentLine.y1, centerX, currentLine.y2] + } else { + const centerY = currentMidY.plus(oppositeLine.intersection.y).div(2).toNumber() + points = [currentLine.x1, centerY, currentLine.x2, centerY] + } } - return diffCurrentA.minus(diffCurrentB).toNumber() - })[0] + if (eavesType.includes(oppositeNextLine.attributes.type) && eavesType.includes(oppositePrevLine.attributes.type)) { + /** 이전, 다음라인의 사잇각의 vector를 구한다. */ + let prevVector = getHalfAngleVector(oppositePrevLine, oppositeCurrentLine) + let nextVector = getHalfAngleVector(oppositeCurrentLine, oppositeNextLine) - const prevOffset = prevLine.attributes.offset - const nextOffset = nextLine.attributes.offset - if (Math.sign(currentVectorX) === 0) { - const prevY = Big(currentLine.y1) - .plus(Big(Math.sign(currentVectorY)).neg().times(prevOffset)) - .toNumber() - const nextY = Big(currentLine.y2) - .plus(Big(Math.sign(currentVectorY)).times(nextOffset)) - .toNumber() - const midX = Big(currentLine.x1).plus(oppositeLine.x1).div(2).toNumber() - ridgePoints = [midX, prevY, midX, nextY] + let prevHipVector = { x: Big(prevVector.x), y: Big(prevVector.y) } + let nextHipVector = { x: Big(nextVector.x), y: Big(nextVector.y) } + + /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const prevCheckPoint = { + x: Big(oppositeCurrentLine.x1).plus(Big(prevHipVector.x).times(10)), + y: Big(oppositeCurrentLine.y1).plus(Big(prevHipVector.y).times(10)), + } + if (!checkWallPolygon.inPolygon(prevCheckPoint)) { + prevHipVector = { x: Big(prevHipVector.x).neg(), y: Big(prevHipVector.y).neg() } + } + + /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const nextCheckPoint = { + x: Big(oppositeCurrentLine.x2).plus(Big(nextHipVector.x).times(10)), + y: Big(oppositeCurrentLine.y2).plus(Big(nextHipVector.y).times(10)), + } + if (!checkWallPolygon.inPolygon(nextCheckPoint)) { + nextHipVector = { x: Big(nextHipVector.x).neg(), y: Big(nextHipVector.y).neg() } + } + + /** 현재 라인의 길이를 기준으로 추녀 마루의 길이를 삼각함수를 사용하여 판단한다.*/ + let hipLength = Big(oppositeCurrentLine.attributes.planeSize) + .div(2) + .pow(2) + .plus(Big(oppositeCurrentLine.attributes.planeSize).div(2).pow(2)) + .sqrt() + .div(10) + .round(2) + + const ridgeEndPoint = { + x: Big(oppositeCurrentLine.x1).plus(hipLength.times(prevHipVector.x)).round(1), + y: Big(oppositeCurrentLine.y1).plus(hipLength.times(prevHipVector.y)).round(1), + } + + const prevHypotenuse = Big(oppositePrevLine.attributes.offset).pow(2).plus(Big(oppositeCurrentLine.attributes.offset).pow(2)).sqrt() + const prevHipPoints = { + x1: Big(oppositeCurrentLine.x1).plus(prevHypotenuse.times(prevHipVector.x.neg())).round(1).toNumber(), + y1: Big(oppositeCurrentLine.y1).plus(prevHypotenuse.times(prevHipVector.y.neg())).round(1).toNumber(), + x2: ridgeEndPoint.x.toNumber(), + y2: ridgeEndPoint.y.toNumber(), + } + + const nextHypotenuse = Big(oppositeNextLine.attributes.offset).pow(2).plus(Big(oppositeCurrentLine.attributes.offset).pow(2)).sqrt() + const nextHipPoints = { + x1: Big(oppositeCurrentLine.x2).plus(nextHypotenuse.times(nextHipVector.x.neg())).round(1).toNumber(), + y1: Big(oppositeCurrentLine.y2).plus(nextHypotenuse.times(nextHipVector.y.neg())).round(1).toNumber(), + x2: ridgeEndPoint.x.toNumber(), + y2: ridgeEndPoint.y.toNumber(), + } + + const prevIntersection = findRoofIntersection(roof, prevHipPoints, ridgeEndPoint) + const nextIntersection = findRoofIntersection(roof, nextHipPoints, ridgeEndPoint) + + if (prevIntersection) { + const prevHip = drawHipLine( + [prevIntersection.intersection.x, prevIntersection.intersection.y, ridgeEndPoint.x.toNumber(), ridgeEndPoint.y.toNumber()], + canvas, + roof, + textMode, + null, + prevDegree, + prevDegree, + ) + baseHipLines.push({ + x1: oppositeCurrentLine.x1, + y1: oppositeCurrentLine.y1, + x2: ridgeEndPoint.x, + y2: ridgeEndPoint.y, + line: prevHip, + }) + } + if (nextIntersection) { + const nextHip = drawHipLine( + [nextIntersection.intersection.x, nextIntersection.intersection.y, ridgeEndPoint.x.toNumber(), ridgeEndPoint.y.toNumber()], + canvas, + roof, + textMode, + null, + nextDegree, + nextDegree, + ) + baseHipLines.push({ + x1: ridgeEndPoint.x, + y1: ridgeEndPoint.y, + x2: oppositeCurrentLine.x2, + y2: oppositeCurrentLine.y2, + line: nextHip, + }) + } + + const ridgeVectorX = Math.sign(currentMidX.minus(ridgeEndPoint.x).toNumber()) + const ridgeVectorY = Math.sign(currentMidY.minus(ridgeEndPoint.y).toNumber()) + const ridgePoints = { + x1: currentMidX.plus(Big(currentLine.attributes.offset).times(ridgeVectorX)).toNumber(), + y1: currentMidY.plus(Big(currentLine.attributes.offset).times(ridgeVectorY)).toNumber(), + x2: ridgeEndPoint.x.toNumber(), + y2: ridgeEndPoint.y.toNumber(), + } + const ridgeIntersection = findRoofIntersection(roof, ridgePoints, { + x: Big(ridgePoints.x2), + y: Big(ridgePoints.y2), + }) + if (ridgeIntersection) { + points = [ridgeIntersection.intersection.x, ridgeIntersection.intersection.y, ridgeEndPoint.x, ridgeEndPoint.y] + } + } } else { - const prevX = Big(currentLine.x1) - .plus(Big(Math.sign(currentVectorX)).neg().times(prevOffset)) - .toNumber() - const nextX = Big(currentLine.x2) - .plus(Big(Math.sign(currentVectorX)).times(nextOffset)) - .toNumber() - const midY = Big(currentLine.y1).plus(oppositeLine.y1).div(2).toNumber() - ridgePoints = [prevX, midY, nextX, midY] + if (currentVectorX.eq(0)) { + points = [oppositeLine.intersection.x, currentLine.y1, oppositeLine.intersection.x, currentLine.y2] + } else { + points = [currentLine.x1, oppositeLine.intersection.y, currentLine.x2, oppositeLine.intersection.y] + } + } + + const isAlreadyRidge = baseGableRidgeLines.find( + (line) => + (line.x1 === points[0] && line.y1 === points[1] && line.x2 === points[2] && line.y2 === points[3]) || + (line.x1 === points[2] && line.y1 === points[3] && line.x2 === points[0] && line.y2 === points[1]), + ) + if (baseRidgeCount < getMaxRidge(baseLines.length) && !isAlreadyRidge) { + const ridgeLine = drawRidgeLine(points, canvas, roof, textMode) + baseGableRidgeLines.push(ridgeLine) + baseRidgeCount++ + } + } else { + const oppositeLines = baseLines.filter((line) => { + const lineAngle = calculateAngle(line.startPoint, line.endPoint) + switch (currentAngle) { + case 90: + return lineAngle === -90 + case -90: + return lineAngle === 90 + case 0: + return lineAngle === 180 + case 180: + return lineAngle === 0 + } + }) + + if (oppositeLines.length > 0 && baseRidgeCount < getMaxRidge(baseLines.length)) { + let ridgePoints = [] + const oppositeLine = oppositeLines.sort((a, b) => { + let diffCurrentA, diffCurrentB + if (Math.sign(currentVectorX) === 0) { + diffCurrentA = currentMidY.minus(a.y1).abs() + diffCurrentB = currentMidY.minus(b.y1).abs() + } else { + diffCurrentA = currentMidX.minus(a.x1).abs() + diffCurrentB = currentMidX.minus(b.x1).abs() + } + return diffCurrentA.minus(diffCurrentB).toNumber() + })[0] + + const prevOffset = prevLine.attributes.offset + const nextOffset = nextLine.attributes.offset + if (Math.sign(currentVectorX) === 0) { + const prevY = Big(currentLine.y1) + .plus(Big(Math.sign(currentVectorY)).neg().times(prevOffset)) + .toNumber() + const nextY = Big(currentLine.y2) + .plus(Big(Math.sign(currentVectorY)).times(nextOffset)) + .toNumber() + const midX = Big(currentLine.x1).plus(oppositeLine.x1).div(2).toNumber() + ridgePoints = [midX, prevY, midX, nextY] + } else { + const prevX = Big(currentLine.x1) + .plus(Big(Math.sign(currentVectorX)).neg().times(prevOffset)) + .toNumber() + const nextX = Big(currentLine.x2) + .plus(Big(Math.sign(currentVectorX)).times(nextOffset)) + .toNumber() + const midY = Big(currentLine.y1).plus(oppositeLine.y1).div(2).toNumber() + ridgePoints = [prevX, midY, nextX, midY] + } + const isAlreadyRidge = baseGableRidgeLines.find( + (line) => + (line.x1 === ridgePoints[0] && line.y1 === ridgePoints[1] && line.x2 === ridgePoints[2] && line.y2 === ridgePoints[3]) || + (line.x1 === ridgePoints[2] && line.y1 === ridgePoints[3] && line.x2 === ridgePoints[0] && line.y2 === ridgePoints[1]), + ) + if (!isAlreadyRidge) { + const ridge = drawRidgeLine(ridgePoints, canvas, roof, textMode) + baseGableRidgeLines.push(ridge) + baseRidgeCount++ + } } - const ridge = drawRidgeLine(ridgePoints, canvas, roof, textMode) - baseGableRidgeLines.push(ridge) - baseRidgeCount++ } } + canvas + .getObjects() + .filter((obj) => obj.name === 'checkLine' || obj.name === 'checkCircle') + .forEach((obj) => canvas.remove(obj)) + canvas.renderAll() }) const uniqueRidgeLines = [] @@ -1854,23 +2491,21 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { baseGableRidgeLines = uniqueRidgeLines + console.log('baseGableRidgeLines : ', baseGableRidgeLines) + /** 박공지붕 polygon 생성 */ drawGablePolygonFirst.forEach((current) => { const { currentBaseLine, prevBaseLine, nextBaseLine } = current const currentLine = currentBaseLine.line const prevLine = prevBaseLine.line const nextLine = nextBaseLine.line - let { x1, x2, y1, y2 } = currentBaseLine - let prevLineRidges = [], - nextLineRidges = [] const currentVectorX = Math.sign(currentLine.x2 - currentLine.x1) const currentVectorY = Math.sign(currentLine.y2 - currentLine.y1) const nextVectorX = Math.sign(nextLine.x1 - nextLine.x2) const nextVectorY = Math.sign(nextLine.y1 - nextLine.y2) - const currentDegree = currentLine.attributes.pitch > 0 ? getDegreeByChon(currentLine.attributes.pitch) : currentLine.attributes.degree + const currentDegree = getDegreeByChon(currentLine.attributes.pitch) - let roofX1, roofY1, roofX2, roofY2 const currentMidX = Big(currentLine.x1).plus(Big(currentLine.x2)).div(2) const currentMidY = Big(currentLine.y1).plus(Big(currentLine.y2)).div(2) const intersectionRoofs = [] @@ -1915,258 +2550,215 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } }) } + let currentRoof, prevRoof, nextRoof if (intersectionRoofs.length > 0) { - const currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line - roofX1 = Big(currentRoof.x1) - roofY1 = Big(currentRoof.y1) - roofX2 = Big(currentRoof.x2) - roofY2 = Big(currentRoof.y2) + currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line } - let prevRoofLine, nextRoofLine + if (currentRoof) { + prevRoof = roof.lines.find((line) => line.x2 === currentRoof.x1 && line.y2 === currentRoof.y1) + nextRoof = roof.lines.find((line) => line.x1 === currentRoof.x2 && line.y1 === currentRoof.y2) - roof.lines - .filter((line) => (currentVectorX === 0 ? line.y1 === line.y2 : line.x1 === line.x2)) - .forEach((line) => { - if ( - (roofX1.minus(line.x1).abs().lte(1) && roofY1.minus(line.y1).abs().lte(1)) || - (roofX1.minus(line.x2).abs().lte(1) && roofY1.minus(line.y2).abs().lte(1)) - ) { - prevRoofLine = line - } - if ( - (roofX2.minus(line.x1).abs().lte(1) && roofY2.minus(line.y1).abs().lte(1)) || - (roofX2.minus(line.x2).abs().lte(1) && roofY2.minus(line.y2).abs().lte(1)) - ) { - nextRoofLine = line - } - }) - const prevRoofEdge = { - vertex1: { x: prevRoofLine.x2, y: prevRoofLine.y2 }, - vertex2: { x: prevRoofLine.x1, y: prevRoofLine.y1 }, - } - const nextRoofEdge = { - vertex1: { x: nextRoofLine.x1, y: nextRoofLine.y1 }, - vertex2: { x: nextRoofLine.x2, y: nextRoofLine.y2 }, - } - - baseGableRidgeLines.forEach((ridge) => { - const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } - const prevIs = edgesIntersection(prevRoofEdge, ridgeEdge) - const nextIs = edgesIntersection(nextRoofEdge, ridgeEdge) - if ( - prevIs && - ((Math.abs(ridgeEdge.vertex1.x - prevIs.x) < 1 && Math.abs(ridgeEdge.vertex1.y - prevIs.y) < 1) || - (Math.abs(ridgeEdge.vertex2.x - prevIs.x) < 1 && Math.abs(ridgeEdge.vertex2.y - prevIs.y) < 1)) - ) { - prevLineRidges.push({ - ridge, - size: calcLinePlaneSize({ x1: roofX1, y1: roofY1, x2: prevIs.x, y2: prevIs.y }), - }) + const prevRoofEdge = { + vertex1: { x: prevRoof.x2, y: prevRoof.y2 }, + vertex2: { x: prevRoof.x1, y: prevRoof.y1 }, + } + const nextRoofEdge = { + vertex1: { x: nextRoof.x1, y: nextRoof.y1 }, + vertex2: { x: nextRoof.x2, y: nextRoof.y2 }, } - if ( - nextIs && - ((Math.abs(ridgeEdge.vertex1.x - nextIs.x) < 1 && Math.abs(ridgeEdge.vertex1.y - nextIs.y) < 1) || - (Math.abs(ridgeEdge.vertex2.x - nextIs.x) < 1 && Math.abs(ridgeEdge.vertex2.y - nextIs.y) < 1)) - ) { - nextLineRidges.push({ - ridge, - size: calcLinePlaneSize({ x1: roofX2, y1: roofY2, x2: nextIs.x, y2: nextIs.y }), - }) - } - }) - - const polygonPoints = [] - - let prevLineRidge, nextLineRidge - if (prevLineRidges.length > 0) { - prevLineRidges = prevLineRidges - .filter((line) => { - const ridge = line.ridge - if (currentVectorX === 0) { - return ridge.y1 === roofY1.toNumber() || ridge.y2 === roofY1.toNumber() - } else { - return ridge.x1 === roofX1.toNumber() || ridge.x2 === roofX1.toNumber() - } - }) - .sort((a, b) => a.size - b.size) - prevLineRidge = prevLineRidges[0].ridge - } - if (nextLineRidges.length > 0) { - nextLineRidges = nextLineRidges - .filter((line) => { - const ridge = line.ridge - if (currentVectorX === 0) { - return ridge.y1 === roofY2.toNumber() || ridge.y2 === roofY2.toNumber() - } else { - return ridge.x1 === roofX2.toNumber() || ridge.x2 === roofX2.toNumber() - } - }) - .sort((a, b) => a.size - b.size) - nextLineRidge = nextLineRidges[0].ridge - } - const ridgeLine = prevLineRidge === undefined ? nextLineRidge : prevLineRidge - - /** 마루선이 한쪽만 존재 연결될 경우 다각형을 그린다.*/ - if (prevLineRidge === undefined || nextLineRidge === undefined) { - const points = [ - { x: roofX1.toNumber(), y: roofY1.toNumber() }, - { x: roofX2.toNumber(), y: roofY2.toNumber() }, - { x: ridgeLine.x1, y: ridgeLine.y1 }, - { x: ridgeLine.x2, y: ridgeLine.y2 }, + let polygonPoints = [ + { x: currentRoof.x1, y: currentRoof.y1 }, + { x: currentRoof.x2, y: currentRoof.y2 }, ] - const minX = Math.min(ridgeLine.x1, ridgeLine.x2, roofX1.toNumber(), roofX2.toNumber()) - const minY = Math.min(ridgeLine.y1, ridgeLine.y2, roofY1.toNumber(), roofY2.toNumber()) + const prevHipLines = [] + const nextHipLine = [] + let prevLineRidge, nextLineRidge - let polygonPoints = [] - - polygonPoints.push(points.find((point) => point.x === minX && point.y === minY)) - - let i = 0 - let length = points.length - while (i < length - 1) { - const currentPoint = polygonPoints[i] - if (i === 0) { - polygonPoints.push(points.find((point) => point.x === currentPoint.x && point.y > currentPoint.y)) - i++ - } else { - const prevPoint = polygonPoints[(i - 1 + polygonPoints.length) % polygonPoints.length] - const vectorX = Math.sign(prevPoint.x - currentPoint.x) - const vectorY = Math.sign(prevPoint.y - currentPoint.y) - if (i % 2 === 1) { - /** 가로선 찾기 */ - const nextPoint = points.find((point) => point.y === currentPoint.y && point.x !== currentPoint.x) - if (nextPoint === undefined) { - const connectLine = roof.lines.find((line) => line.y1 === line.y2 && line.x1 === currentPoint.x && line.y1 === currentPoint.y) - if (connectLine) { - polygonPoints.push( - connectLine.x1 === currentPoint.x && connectLine.y1 === currentPoint.y - ? { x: connectLine.x2, y: connectLine.y2 } - : { x: connectLine.x1, y: connectLine.y1 }, - ) - } else { - const intersectLine = roof.lines.find( - (line) => - line.y1 === currentPoint.y && - line.y2 === currentPoint.y && - ((line.x1 <= currentPoint.x && line.x2 >= currentPoint.x) || (line.x2 <= currentPoint.x && line.x1 >= currentPoint.x)), - ) - /** 이전 라인이 위에서 아래로 항하면 오른쪽 포인트 찾기*/ - if (vectorY === 1) { - polygonPoints.push({ x: intersectLine.x1, y: intersectLine.y1 }) - } - /** 이전 라인이 아래에서 위로 항하면 왼쪽 포인트 찾기*/ - if (vectorY === -1) { - polygonPoints.push({ x: intersectLine.x2, y: intersectLine.y2 }) - } - } - length = length + 1 - } else { - polygonPoints.push(nextPoint) - } - i++ - } else { - /** 세로선 찾기*/ - const nextPoint = points.find((point) => point.x === currentPoint.x && point.y !== currentPoint.y) - if (nextPoint === undefined) { - const connectLine = roof.lines.find((line) => line.x1 === line.x2 && line.x1 === currentPoint.x && line.y1 === currentPoint.y) - if (connectLine) { - polygonPoints.push( - connectLine.x1 === currentPoint.x && connectLine.y1 === currentPoint.y - ? { x: connectLine.x2, y: connectLine.y2 } - : { x: connectLine.x1, y: connectLine.y1 }, - ) - } else { - const intersectLine = roof.lines.find( - (line) => - line.x1 === currentPoint.x && - line.x2 === currentPoint.x && - ((line.y1 <= currentPoint.y && line.y2 >= currentPoint.y) || (line.y2 <= currentPoint.y && line.y1 >= currentPoint.y)), - ) - /** 이전 라인이 왼쪽에서 오른쪽로 항하면 위쪽 포인트 찾기*/ - if (vectorX === -1) { - polygonPoints.push({ x: intersectLine.x1, y: intersectLine.y1 }) - } - /** 이전 라인이 오른에서 왼쪽으로 항하면 아래쪽 포인트 찾기*/ - if (vectorX === 1) { - polygonPoints.push({ x: intersectLine.x2, y: intersectLine.y2 }) - } - } - length = length + 1 - } else { - polygonPoints.push(nextPoint) - } - i++ - } + baseHipLines.forEach((current) => { + const { line } = current + if ( + (Math.abs(line.x1 - currentRoof.x1) <= 1 && + Math.abs(line.y1 - currentRoof.y1) <= 1 && + isPointOnLine(prevRoof, { x: line.x2, y: line.y2 })) || + (Math.abs(line.x2 - currentRoof.x1) <= 1 && + Math.abs(line.y2 - currentRoof.y1) <= 1 && + isPointOnLine(prevRoof, { + x: line.x1, + y: line.y1, + })) + ) { + prevHipLines.push(current) } - } - polygonPoints = getSortedPoint(polygonPoints) - polygonPoints.forEach((currentPoint, index) => { - const nextPoint = polygonPoints[(index + 1) % polygonPoints.length] - const points = [currentPoint.x, currentPoint.y, nextPoint.x, nextPoint.y] - const isParallel = ridgeLine.x1 === ridgeLine.x2 ? currentPoint.x === nextPoint.x : currentPoint.y === nextPoint.y - - let line - if (isParallel) { - line = drawRoofLine(points, canvas, roof, textMode) - baseGableLines.push(line) - } else { - line = drawHipLine(points, canvas, roof, textMode, null, currentDegree, currentDegree) - baseHipLines.push({ x1: line.x1, y1: line.y1, x2: line.x2, y2: line.y2, line }) + if ( + (Math.abs(line.x1 - currentRoof.x2) <= 1 && + Math.abs(line.y1 - currentRoof.y2) <= 1 && + isPointOnLine(nextRoof, { x: line.x2, y: line.y2 })) || + (Math.abs(line.x2 - currentRoof.x2) <= 1 && + Math.abs(line.y2 - currentRoof.y2) <= 1 && + isPointOnLine(nextRoof, { + x: line.x1, + y: line.y1, + })) + ) { + nextHipLine.push(current) } }) - } else { - /** 마루에서 현재라인으로 향하는 외벽선까지의 포인트를 확인 하여 처리*/ - let checkEdge - if (currentVectorX === 0) { - checkEdge = { - vertex1: { x: ridgeLine.x1, y: roofY1.toNumber() }, - vertex2: { x: roofX1.toNumber(), y: roofY1.toNumber() }, - } - } else { - checkEdge = { - vertex1: { x: roofX1.toNumber(), y: ridgeLine.y1 }, - vertex2: { x: roofX1.toNumber(), y: roofY1.toNumber() }, - } - } - const checkVectorX = Math.sign(checkEdge.vertex1.x - checkEdge.vertex2.x) - const checkVectorY = Math.sign(checkEdge.vertex1.y - checkEdge.vertex2.y) - const intersectPoints = [] - roof.lines - .filter((line) => (currentVectorX === 0 ? line.x1 === line.x2 : line.y1 === line.y2)) - .forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const is = edgesIntersection(checkEdge, lineEdge) - if (is) { - const isVectorX = Math.sign(checkEdge.vertex1.x - is.x) - const isVectorY = Math.sign(checkEdge.vertex1.y - is.y) - const isLineOtherPoint = - is.x === line.x1 && is.y === line.y1 - ? { x: line.x2, y: line.y2 } - : { - x: line.x1, - y: line.y1, - } - const lineVectorX = Math.sign(isLineOtherPoint.x - is.x) - const lineVectorY = Math.sign(isLineOtherPoint.y - is.y) - if (checkVectorX === isVectorX && checkVectorY === isVectorY && lineVectorX === currentVectorX && lineVectorY === currentVectorY) { - intersectPoints.push(is) - } + prevHipLines.forEach((current) => { + if (prevLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + let findPoint + if (Math.abs(current.x1 - currentRoof.x1) <= 1 && Math.abs(current.y1 - currentRoof.y1) <= 1) { + findPoint = { x: current.x2, y: current.y2 } + } else { + findPoint = { x: current.x1, y: current.y1 } + } + baseHipLines + .filter( + (line) => + ((Math.abs(line.x1 - findPoint.x) <= 1 && Math.abs(line.y1 - findPoint.y) <= 1) || + (Math.abs(line.x2 - findPoint.x) <= 1 && Math.abs(line.y2 - findPoint.y) <= 1)) && + line.x1 !== line.x2 && + line.y1 !== line.y2, + ) + .forEach((line) => { + polygonPoints.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 }) + let ridgePoint + if (Math.abs(line.x1 - findPoint.x) <= 1 && Math.abs(line.y1 - findPoint.y) <= 1) { + ridgePoint = { x: line.x2, y: line.y2 } + } else { + ridgePoint = { x: line.x1, y: line.y1 } + } + prevLineRidge = baseGableRidgeLines.find( + (ridge) => + (Math.abs(ridge.x1 - ridgePoint.x) <= 1 && Math.abs(ridge.y1 - ridgePoint.y) <= 1) || + (Math.abs(ridge.x2 - ridgePoint.x) <= 1 && Math.abs(ridge.y2 - ridgePoint.y) <= 1), + ) + }) + } else { + let ridgePoint + if (Math.abs(current.x1 - currentRoof.x1) <= 1 && Math.abs(current.y1 - currentRoof.y1) <= 1) { + ridgePoint = { x: current.x2, y: current.y2 } + } else { + ridgePoint = { x: current.x1, y: current.y1 } } - }) - let intersect = intersectPoints[0] - if (currentVectorX === 0) { - polygonPoints.push({ x: intersect.x, y: roofY1.toNumber() }, { x: intersect.x, y: roofY2.toNumber() }) - } else { - polygonPoints.push({ x: roofX1.toNumber(), y: intersect.y }, { x: roofX2.toNumber(), y: intersect.y }) + prevLineRidge = baseGableRidgeLines.find((ridge) => { + return ( + (Math.abs(ridge.x1 - ridgePoint.x) <= 1 && Math.abs(ridge.y1 - ridgePoint.y) <= 1) || + (Math.abs(ridge.x2 - ridgePoint.x) <= 1 && Math.abs(ridge.y2 - ridgePoint.y) <= 1) + ) + }) + } + }) + nextHipLine.forEach((current) => { + if (nextLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + let findPoint + if (Math.abs(current.x1 - currentRoof.x2) <= 1 && Math.abs(current.y1 - currentRoof.y2) <= 1) { + findPoint = { x: current.x2, y: current.y2 } + } else { + findPoint = { x: current.x1, y: current.y1 } + } + + baseHipLines + .filter( + (line) => + ((Math.abs(line.x1 - findPoint.x) <= 1 && Math.abs(line.y1 - findPoint.y) <= 1) || + (Math.abs(line.x2 - findPoint.x) <= 1 && Math.abs(line.y2 - findPoint.y) <= 1)) && + line.x1 !== line.x2 && + line.y1 !== line.y2, + ) + .forEach((line) => { + polygonPoints.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 }) + let ridgePoint + if (Math.abs(line.x1 - findPoint.x) <= 1 && Math.abs(line.y1 - findPoint.y) <= 1) { + ridgePoint = { x: line.x2, y: line.y2 } + } else { + ridgePoint = { x: line.x1, y: line.y1 } + } + nextLineRidge = baseGableRidgeLines.find( + (ridge) => + (Math.abs(ridge.x1 - ridgePoint.x) <= 1 && Math.abs(ridge.y1 - ridgePoint.y) <= 1) || + (Math.abs(ridge.x2 - ridgePoint.x) <= 1 && Math.abs(ridge.y2 - ridgePoint.y) <= 1), + ) + }) + } else { + let ridgePoint + if (Math.abs(current.x1 - currentRoof.x2) <= 1 && Math.abs(current.y1 - currentRoof.y2) <= 1) { + ridgePoint = { x: current.x2, y: current.y2 } + } else { + ridgePoint = { x: current.x1, y: current.y1 } + } + + nextLineRidge = baseGableRidgeLines.find( + (ridge) => + (Math.abs(ridge.x1 - ridgePoint.x) <= 1 && Math.abs(ridge.y1 - ridgePoint.y) <= 1) || + (Math.abs(ridge.x2 - ridgePoint.x) <= 1 && Math.abs(ridge.y2 - ridgePoint.y) <= 1), + ) + } + }) + + if (!prevLineRidge) { + if (prevLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + } else { + const isRidgePoints = [] + baseGableRidgeLines.forEach((ridge) => { + const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } + const intersection = edgesIntersection(prevRoofEdge, ridgeEdge) + if ( + intersection && + ((ridge.x1 <= intersection.x && intersection.x <= ridge.x2 && ridge.y1 <= intersection.y && intersection.y <= ridge.y2) || + (ridge.x2 <= intersection.x && intersection.x <= ridge.x1 && ridge.y2 <= intersection.y && intersection.y <= ridge.y1)) + ) { + const size = Big(intersection.x) + .minus(Big(currentRoof.x1)) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(Big(currentRoof.y1)).abs().pow(2)) + .sqrt() + isRidgePoints.push({ intersection, ridge, size }) + } + }) + if (isRidgePoints.length > 0) { + const sortedRidgePoints = isRidgePoints.sort((a, b) => a.size - b.size) + prevLineRidge = sortedRidgePoints[0].ridge + } + } } + if (!nextLineRidge) { + if (nextLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + } else { + const isRidgePoints = [] + baseGableRidgeLines.forEach((ridge) => { + const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } + const intersection = edgesIntersection(nextRoofEdge, ridgeEdge) + if ( + intersection && + ((ridge.x1 <= intersection.x && intersection.x <= ridge.x2 && ridge.y1 <= intersection.y && intersection.y <= ridge.y2) || + (ridge.x2 <= intersection.x && intersection.x <= ridge.x1 && ridge.y2 <= intersection.y && intersection.y <= ridge.y1)) + ) { + const size = Big(intersection.x) + .minus(Big(currentRoof.x2)) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(Big(currentRoof.y2)).abs().pow(2)) + .sqrt() + isRidgePoints.push({ intersection, ridge, size }) + } + }) + if (isRidgePoints.length > 0) { + const sortedRidgePoints = isRidgePoints.sort((a, b) => a.size - b.size) + nextLineRidge = sortedRidgePoints[0].ridge + } + } + } + const ridgeLine = prevLineRidge === undefined ? nextLineRidge : prevLineRidge - if (prevLineRidge === nextLineRidge) { + if (prevLineRidge !== undefined && nextLineRidge !== undefined) { /** 4각*/ - polygonPoints.push({ x: prevLineRidge.x1, y: prevLineRidge.y1 }, { x: prevLineRidge.x2, y: prevLineRidge.y2 }) - } else { + if (prevLineRidge === nextLineRidge) { + polygonPoints.push({ x: ridgeLine.x1, y: ridgeLine.y1 }, { x: ridgeLine.x2, y: ridgeLine.y2 }) + } /** 6각이상*/ let isOverLap = currentVectorX === 0 @@ -2179,83 +2771,102 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { (prevLineRidge.x1 <= nextLineRidge.x2 && prevLineRidge.x2 >= nextLineRidge.x2) || (prevLineRidge.x1 >= nextLineRidge.x2 && prevLineRidge.x2 <= nextLineRidge.x2) if (isOverLap) { - const prevDistance = currentVectorX === 0 ? Math.abs(prevLineRidge.x1 - roofX1.toNumber()) : Math.abs(prevLineRidge.y1 - roofY1.toNumber()) - const nextDistance = currentVectorX === 0 ? Math.abs(nextLineRidge.x1 - roofX1.toNumber()) : Math.abs(nextLineRidge.y1 - roofY1.toNumber()) - /** 현재 지붕 라인과 먼 라인의 포인트를 온전히 사용한다. */ - if (prevDistance <= nextDistance) { - polygonPoints.push( - { x: nextLineRidge.x1, y: nextLineRidge.y1 }, - { - x: nextLineRidge.x2, - y: nextLineRidge.y2, - }, - ) - /** 이전라인과 교차한 마루의 포인트*/ - const prevRidgePoint1 = - currentVectorX === 0 - ? roofY1.toNumber() === prevLineRidge.y1 - ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } - : { x: prevLineRidge.x2, y: prevLineRidge.y2 } - : roofX1.toNumber() === prevLineRidge.x1 - ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } - : { x: prevLineRidge.x2, y: prevLineRidge.y2 } + const prevDistance = currentVectorX === 0 ? Math.abs(prevLineRidge.x1 - currentRoof.x1) : Math.abs(prevLineRidge.y1 - currentRoof.y1) + const nextDistance = currentVectorX === 0 ? Math.abs(nextLineRidge.x1 - currentRoof.x1) : Math.abs(nextLineRidge.y1 - currentRoof.y1) - polygonPoints.push(prevRidgePoint1) + /** 현재 지붕 라인과 먼 라인의 포인트를 온전히 사용한다. */ + if (Math.abs(prevDistance - nextDistance) < 1) { + const minX = Math.min(currentRoof.x1, currentRoof.x2, currentLine.x1, currentLine.x2) + const maxX = Math.max(currentRoof.x1, currentRoof.x2, currentLine.x1, currentLine.x2) + const minY = Math.min(currentRoof.y1, currentRoof.y2, currentLine.y1, currentLine.y2) + const maxY = Math.max(currentRoof.y1, currentRoof.y2, currentLine.y1, currentLine.y2) + if (currentVectorX === 0) { + polygonPoints.push({ x: prevLineRidge.x1, y: minY }, { x: prevLineRidge.x1, y: maxY }) + } else { + polygonPoints.push({ x: minX, y: prevLineRidge.y1 }, { x: maxX, y: prevLineRidge.y1 }) + } + } else if (prevDistance < nextDistance) { + polygonPoints.push({ x: nextLineRidge.x1, y: nextLineRidge.y1 }, { x: nextLineRidge.x2, y: nextLineRidge.y2 }) + + /** 이전라인과 교차한 마루의 포인트*/ + let prevRidgePoint1 + if (prevLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + prevRidgePoint1 = polygonPoints.find( + (point) => + (point.x === prevLineRidge.x1 && point.y === prevLineRidge.y1) || (point.x === prevLineRidge.x2 && point.y === prevLineRidge.y2), + ) + } else { + prevRidgePoint1 = + currentVectorX === 0 + ? currentRoof.y1 === prevLineRidge.y1 + ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } + : { x: prevLineRidge.x2, y: prevLineRidge.y2 } + : currentRoof.x1 === prevLineRidge.x1 + ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } + : { x: prevLineRidge.x2, y: prevLineRidge.y2 } + + polygonPoints.push(prevRidgePoint1) + } /** 다음 라인과 교차한 마루의 포인트 중 라인과 접하지 않은 포인트*/ - const checkRidgePoint = - currentVectorX === 0 - ? roofY2.toNumber() !== nextLineRidge.y1 - ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } - : { x: nextLineRidge.x2, y: nextLineRidge.y2 } - : roofX2.toNumber() !== nextLineRidge.x1 - ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } - : { x: nextLineRidge.x2, y: nextLineRidge.y2 } + let checkRidgePoint + if (nextLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const ridgePoint1 = polygonPoints.filter((point) => point.x === nextLineRidge.x1 && point.y === nextLineRidge.y1) + checkRidgePoint = ridgePoint1.length > 0 ? { x: nextLineRidge.x2, y: nextLineRidge.y2 } : { x: nextLineRidge.x1, y: nextLineRidge.y1 } + } else { + checkRidgePoint = + currentVectorX === 0 + ? currentRoof.y2 !== nextLineRidge.y1 + ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } + : { x: nextLineRidge.x2, y: nextLineRidge.y2 } + : currentRoof.x2 !== nextLineRidge.x1 + ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } + : { x: nextLineRidge.x2, y: nextLineRidge.y2 } + } const prevRidgePoint2 = - currentVectorX === 0 - ? { x: prevRidgePoint1.x, y: checkRidgePoint.y } - : { - x: checkRidgePoint.x, - y: prevRidgePoint1.y, - } + currentVectorX === 0 ? { x: prevRidgePoint1.x, y: checkRidgePoint.y } : { x: checkRidgePoint.x, y: prevRidgePoint1.y } polygonPoints.push(prevRidgePoint2) } else { - polygonPoints.push( - { x: prevLineRidge.x1, y: prevLineRidge.y1 }, - { - x: prevLineRidge.x2, - y: prevLineRidge.y2, - }, - ) + polygonPoints.push({ x: prevLineRidge.x1, y: prevLineRidge.y1 }, { x: prevLineRidge.x2, y: prevLineRidge.y2 }) /** 다음라인과 교차한 마루의 포인트*/ - const nextRidgePoint1 = - currentVectorX === 0 - ? roofY2.toNumber() === nextLineRidge.y1 - ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } - : { x: nextLineRidge.x2, y: nextLineRidge.y2 } - : roofX2.toNumber() === nextLineRidge.x1 - ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } - : { x: nextLineRidge.x2, y: nextLineRidge.y2 } - polygonPoints.push(nextRidgePoint1) + let nextRidgePoint1 + if (nextLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + nextRidgePoint1 = polygonPoints.find( + (point) => + (point.x === nextLineRidge.x1 && point.y === nextLineRidge.y1) || (point.x === nextLineRidge.x2 && point.y === nextLineRidge.y2), + ) + } else { + nextRidgePoint1 = + currentVectorX === 0 + ? currentRoof.y2 === nextLineRidge.y1 + ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } + : { x: nextLineRidge.x2, y: nextLineRidge.y2 } + : currentRoof.x2 === nextLineRidge.x1 + ? { x: nextLineRidge.x1, y: nextLineRidge.y1 } + : { x: nextLineRidge.x2, y: nextLineRidge.y2 } + polygonPoints.push(nextRidgePoint1) + } /** 이전 라인과 교차한 마루의 포인트 중 라인과 접하지 않은 포인트*/ - const checkRidgePoint = - currentVectorX === 0 - ? roofY1.toNumber() !== prevLineRidge.y1 - ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } - : { x: prevLineRidge.x2, y: prevLineRidge.y2 } - : roofX1.toNumber() !== prevLineRidge.x1 - ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } - : { x: prevLineRidge.x2, y: prevLineRidge.y2 } + let checkRidgePoint + if (prevLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const ridgePoint1 = polygonPoints.filter((point) => point.x === prevLineRidge.x1 && point.y === prevLineRidge.y1) + checkRidgePoint = ridgePoint1.length > 0 ? { x: prevLineRidge.x2, y: prevLineRidge.y2 } : { x: prevLineRidge.x1, y: prevLineRidge.y1 } + } else { + checkRidgePoint = + currentVectorX === 0 + ? currentRoof.y1 !== prevLineRidge.y1 + ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } + : { x: prevLineRidge.x2, y: prevLineRidge.y2 } + : currentRoof.x1 !== prevLineRidge.x1 + ? { x: prevLineRidge.x1, y: prevLineRidge.y1 } + : { x: prevLineRidge.x2, y: prevLineRidge.y2 } + } + const nextRidgePoint2 = - currentVectorX === 0 - ? { x: nextRidgePoint1.x, y: checkRidgePoint.y } - : { - x: checkRidgePoint.x, - y: nextRidgePoint1.y, - } + currentVectorX === 0 ? { x: nextRidgePoint1.x, y: checkRidgePoint.y } : { x: checkRidgePoint.x, y: nextRidgePoint1.y } polygonPoints.push(nextRidgePoint2) } } else { @@ -2381,89 +2992,43 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } } } - const sortedPolygonPoints = getSortedPoint(polygonPoints) - - /** 외벽선 밖으로 나가있는 포인트*/ - const outsidePoints = polygonPoints.filter((point) => { - let isOutside = true - roof.lines.forEach((line) => { - if ( - (line.x1 <= point.x && line.x2 >= point.x && line.y1 <= point.y && line.y2 >= point.y) || - (line.x1 >= point.x && line.x2 <= point.x && line.y1 >= point.y && line.y2 <= point.y) - ) { - isOutside = false - } - }) - baseGableRidgeLines.forEach((line) => { - if ( - (line.x1 <= point.x && line.x2 >= point.x && line.y1 <= point.y && line.y2 >= point.y) || - (line.x1 >= point.x && line.x2 <= point.x && line.y1 >= point.y && line.y2 <= point.y) - ) { - isOutside = false - } - }) - return isOutside + /** 중복되는 포인트 제거 */ + const uniquePoints = [] + polygonPoints.forEach((point) => { + const isAlready = uniquePoints.find((uniquePoint) => uniquePoint.x === point.x && uniquePoint.y === point.y) + if (!isAlready) { + uniquePoints.push(point) + } }) + polygonPoints = getSortedPoint(uniquePoints, baseHipLines) - if (outsidePoints.length > 0) { - sortedPolygonPoints.forEach((currentPoint, index) => { - if (outsidePoints.includes(currentPoint)) { - const prevPoint = sortedPolygonPoints[(index - 1 + sortedPolygonPoints.length) % sortedPolygonPoints.length] - const nextPoint = sortedPolygonPoints[(index + 1) % sortedPolygonPoints.length] - const vectorX = Math.sign(currentPoint.x - prevPoint.x) - const vectorY = Math.sign(currentPoint.y - prevPoint.y) - - const checkEdge = { - vertex1: { x: prevPoint.x, y: prevPoint.y }, - vertex2: { x: currentPoint.x, y: currentPoint.y }, - } - const intersectPoints = [] - roof.lines - .filter((line) => (vectorX === 0 ? line.x1 !== line.x2 : line.y1 !== line.y2)) - .forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const is = edgesIntersection(checkEdge, lineEdge) - if (is && !is.isIntersectionOutside) { - const isVectorX = Math.sign(is.x - prevPoint.x) - const isVectorY = Math.sign(is.y - prevPoint.y) - if ((vectorX === 0 && vectorY === isVectorY) || (vectorY === 0 && vectorX === isVectorX)) { - intersectPoints.push(is) - } - } - }) - if (intersectPoints.length > 0) { - const intersection = intersectPoints[0] - if (vectorX === 0) { - currentPoint.y = intersection.y - nextPoint.y = intersection.y - } else { - currentPoint.x = intersection.x - nextPoint.x = intersection.x - } - } - } - }) - } - - sortedPolygonPoints.forEach((startPoint, index) => { - let endPoint - if (index === sortedPolygonPoints.length - 1) { - endPoint = sortedPolygonPoints[0] - } else { - endPoint = sortedPolygonPoints[index + 1] + polygonPoints.forEach((currentPoint, index) => { + const nextPoint = polygonPoints[(index + 1) % polygonPoints.length] + const points = [currentPoint.x, currentPoint.y, nextPoint.x, nextPoint.y] + const isParallel = ridgeLine.x1 === ridgeLine.x2 ? currentPoint.x === nextPoint.x : currentPoint.y === nextPoint.y + const ridgeLines = baseGableRidgeLines.filter( + (line) => + (line.x1 === points[0] && line.y1 === points[1] && line.x2 === points[2] && line.y2 === points[3]) || + (line.x1 === points[2] && line.y1 === points[3] && line.x2 === points[0] && line.y2 === points[1]), + ) + const hipLine = baseHipLines.filter( + (line) => + (line.x1 === points[0] && line.y1 === points[1] && line.x2 === points[2] && line.y2 === points[3]) || + (line.x1 === points[2] && line.y1 === points[3] && line.x2 === points[0] && line.y2 === points[1]), + ) + /** 이미 존재하는 라인이면 넘긴다.*/ + if (ridgeLines.length > 0 || hipLine.length > 0) { + return } - const hipLine = drawHipLine([startPoint.x, startPoint.y, endPoint.x, endPoint.y], canvas, roof, textMode, null, currentDegree, currentDegree) - if (currentVectorX === 0) { - if (Math.sign(startPoint.x - endPoint.x) === 0) { - hipLine.attributes.actualSize = hipLine.attributes.planeSize - } + let line + if (isParallel) { + line = drawRoofLine(points, canvas, roof, textMode) + baseGableLines.push(line) } else { - if (Math.sign(startPoint.y - endPoint.y) === 0) { - hipLine.attributes.actualSize = hipLine.attributes.planeSize - } + line = drawHipLine(points, canvas, roof, textMode, null, currentDegree, currentDegree) + baseHipLines.push({ x1: line.x1, y1: line.y1, x2: line.x2, y2: line.y2, line }) } - baseHipLines.push({ x1: hipLine.x1, y1: hipLine.y1, x2: hipLine.x2, y2: hipLine.y2, line: hipLine }) }) } }) @@ -2477,190 +3042,462 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const currentVectorX = Math.sign(currentLine.x2 - currentLine.x1) const currentVectorY = Math.sign(currentLine.y2 - currentLine.y1) - const currentDegree = currentLine.attributes.pitch > 0 ? getDegreeByChon(currentLine.attributes.pitch) : currentLine.attributes.degree + const currentDegree = getDegreeByChon(currentLine.attributes.pitch) const prevAngle = calculateAngle(prevLine.startPoint, prevLine.endPoint) const nextAngle = calculateAngle(nextLine.startPoint, nextLine.endPoint) - const polygonPoints = [] - if (Big(prevAngle).minus(Big(nextAngle)).abs().eq(180)) { - const currentRidge = baseGableRidgeLines.find((line) => - currentVectorX === 0 - ? (line.y1 === y1 && line.y2 === y2) || (line.y1 === y2 && line.y2 === y1) - : (line.x1 === x1 && line.x2 === x2) || (line.x1 === x2 && line.x2 === x1), - ) - if (currentRidge) { - const ridgeVectorX = Math.sign(currentRidge.x1 - currentRidge.x2) - const ridgeVectorY = Math.sign(currentRidge.y1 - currentRidge.y2) - - let checkEdge - if (currentVectorX === 0) { - checkEdge = { - vertex1: { x: currentRidge.x1, y: currentRidge.y1 }, - vertex2: { x: currentLine.x1, y: currentRidge.y1 }, + const currentMidX = Big(currentLine.x1).plus(Big(currentLine.x2)).div(2) + const currentMidY = Big(currentLine.y1).plus(Big(currentLine.y2)).div(2) + const intersectionRoofs = [] + if (currentVectorX === 0) { + const checkEdge = { + vertex1: { x: prevLine.x1, y: currentMidY.toNumber() }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } } - } else { - checkEdge = { - vertex1: { x: currentRidge.x1, y: currentRidge.y1 }, - vertex2: { x: currentRidge.x1, y: currentLine.y1 }, + }) + } else { + const checkEdge = { + vertex1: { x: currentMidX.toNumber(), y: prevLine.y1 }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } + let currentRoof, prevRoof, nextRoof + if (intersectionRoofs.length > 0) { + currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line + prevRoof = roof.lines.find((line) => line.x2 === currentRoof.x1 && line.y2 === currentRoof.y1) + nextRoof = roof.lines.find((line) => line.x1 === currentRoof.x2 && line.y1 === currentRoof.y2) + } + + let polygonPoints = [] + if (Big(prevAngle).minus(Big(nextAngle)).abs().eq(180)) { + const xVector = Big(nextLine.x2).minus(Big(nextLine.x1)) + const yVector = Big(nextLine.y2).minus(Big(nextLine.y1)) + const currentMidX = Big(currentLine.x1).plus(Big(currentLine.x2)).div(2) + const currentMidY = Big(currentLine.y1).plus(Big(currentLine.y2)).div(2) + + const checkPoints = { + x: currentMidX.plus(Big(10).times(Math.sign(xVector.toNumber()))).toNumber(), + y: currentMidY.plus(Big(10).times(Math.sign(yVector.toNumber()))).toNumber(), + } + console.log('checkWallPolygon.inPolygon(checkPoints)', checkWallPolygon.inPolygon(checkPoints)) + + if (checkWallPolygon.inPolygon(checkPoints)) { + const currentRidge = baseGableRidgeLines.find((line) => + currentVectorX === 0 + ? (line.y1 === y1 && line.y2 === y2) || (line.y1 === y2 && line.y2 === y1) + : (line.x1 === x1 && line.x2 === x2) || (line.x1 === x2 && line.x2 === x1), + ) + if (currentRidge) { + const ridgeVectorX = Math.sign(currentRidge.x1 - currentRidge.x2) + const ridgeVectorY = Math.sign(currentRidge.y1 - currentRidge.y2) + + let checkEdge + if (currentVectorX === 0) { + checkEdge = { + vertex1: { x: currentRidge.x1, y: currentRidge.y1 }, + vertex2: { x: currentLine.x1, y: currentRidge.y1 }, + } + } else { + checkEdge = { + vertex1: { x: currentRidge.x1, y: currentRidge.y1 }, + vertex2: { x: currentRidge.x1, y: currentLine.y1 }, + } + } + const isRoofLines = [] + roof.lines + .filter((line) => (currentVectorX === 0 ? line.x1 === line.x2 : line.y1 === line.y2)) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const is = edgesIntersection(checkEdge, lineEdge) + if (is) { + const checkVectorX = Math.sign(checkEdge.vertex1.x - checkEdge.vertex2.x) + const checkVectorY = Math.sign(checkEdge.vertex1.y - checkEdge.vertex2.y) + const isVectorX = Math.sign(checkEdge.vertex1.x - is.x) + const isVectorY = Math.sign(checkEdge.vertex1.y - is.y) + if ((ridgeVectorX === 0 && checkVectorX === isVectorX) || (ridgeVectorY === 0 && checkVectorY === isVectorY)) { + const size = ridgeVectorX === 0 ? Math.abs(checkEdge.vertex1.x - is.x) : Math.abs(checkEdge.vertex1.y - is.y) + isRoofLines.push({ line, size }) + } + } + }) + isRoofLines.sort((a, b) => a.size - b.size) + const roofLine = isRoofLines[0].line + polygonPoints.push({ x: currentRidge.x1, y: currentRidge.y1 }, { x: currentRidge.x2, y: currentRidge.y2 }) + if (ridgeVectorX === 0) { + polygonPoints.push({ x: roofLine.x1, y: currentRidge.y1 }, { x: roofLine.x1, y: currentRidge.y2 }) + } else { + polygonPoints.push({ x: currentRidge.x1, y: roofLine.y1 }, { x: currentRidge.x2, y: roofLine.y1 }) } } - const isRoofLines = [] - roof.lines - .filter((line) => (currentVectorX === 0 ? line.x1 === line.x2 : line.y1 === line.y2)) - .forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const is = edgesIntersection(checkEdge, lineEdge) - if (is) { - const checkVectorX = Math.sign(checkEdge.vertex1.x - checkEdge.vertex2.x) - const checkVectorY = Math.sign(checkEdge.vertex1.y - checkEdge.vertex2.y) - const isVectorX = Math.sign(checkEdge.vertex1.x - is.x) - const isVectorY = Math.sign(checkEdge.vertex1.y - is.y) - if ((ridgeVectorX === 0 && checkVectorX === isVectorX) || (ridgeVectorY === 0 && checkVectorY === isVectorY)) { - const size = ridgeVectorX === 0 ? Math.abs(checkEdge.vertex1.x - is.x) : Math.abs(checkEdge.vertex1.y - is.y) - isRoofLines.push({ line, size }) - } - } - }) - isRoofLines.sort((a, b) => a.size - b.size) - const roofLine = isRoofLines[0].line - polygonPoints.push({ x: currentRidge.x1, y: currentRidge.y1 }, { x: currentRidge.x2, y: currentRidge.y2 }) - if (ridgeVectorX === 0) { - polygonPoints.push({ x: roofLine.x1, y: currentRidge.y1 }, { x: roofLine.x1, y: currentRidge.y2 }) - } else { - polygonPoints.push({ x: currentRidge.x1, y: roofLine.y1 }, { x: currentRidge.x2, y: roofLine.y1 }) + } else { + const currentRidge = baseGableRidgeLines.find((line) => + currentVectorX === 0 + ? (Math.abs(line.y1 - currentRoof.y1) < 1 && Math.abs(line.y2 - currentRoof.y2) < 1) || + (Math.abs(line.y1 - currentRoof.y2) < 1 && Math.abs(line.y2 - currentRoof.y1) < 1) + : (Math.abs(line.x1 - currentRoof.x1) < 1 && Math.abs(line.x2 - currentRoof.x2) < 1) || + (Math.abs(line.x1 - currentRoof.x2) < 1 && Math.abs(line.x2 - currentRoof.x1) < 1), + ) + if (currentRidge) { + if (currentVectorX === 0) { + polygonPoints.push({ x: currentRoof.x1, y: currentLine.y1 }, { x: currentRoof.x2, y: currentLine.y2 }) + polygonPoints.push({ x: currentRidge.x1, y: currentLine.y1 }, { x: currentRidge.x1, y: currentLine.y2 }) + } else { + polygonPoints.push({ x: currentLine.x1, y: currentRoof.y1 }, { x: currentLine.x2, y: currentRoof.y2 }) + polygonPoints.push({ x: currentLine.x1, y: currentRidge.y1 }, { x: currentLine.x2, y: currentRidge.y1 }) + } } } } else { - const prevEdge = { vertex1: { x: prevLine.x1, y: prevLine.y1 }, vertex2: { x: prevLine.x2, y: prevLine.y2 } } - const prevRidge = baseGableRidgeLines.find((ridge) => { - const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } - const is = edgesIntersection(prevEdge, ridgeEdge) - if (is && !is.isIntersectionOutside) { - return ridge - } - }) + const prevEdge = { vertex1: { x: prevRoof.x2, y: prevRoof.y2 }, vertex2: { x: prevRoof.x1, y: prevRoof.y1 } } + const prevVectorX = Math.sign(prevRoof.x1 - prevRoof.x2) + const prevVectorY = Math.sign(prevRoof.y1 - prevRoof.y2) - const nextEdge = { vertex1: { x: nextLine.x1, y: nextLine.y1 }, vertex2: { x: nextLine.x2, y: nextLine.y2 } } - const nextRidge = baseGableRidgeLines.find((ridge) => { - const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } - const is = edgesIntersection(nextEdge, ridgeEdge) - if (is && !is.isIntersectionOutside) { - return ridge + let prevRidge, nextRidge + if (prevLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const hipLines = [] + baseHipLines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const is = edgesIntersection(prevEdge, lineEdge) + if (is) { + const size = Big(is.x).minus(prevRoof.x2).abs().pow(2).plus(Big(is.y).minus(prevRoof.y2).abs().pow(2)).sqrt().toNumber() + hipLines.push({ line, is, size }) + } + }) + if (hipLines.length > 0) { + hipLines.sort((a, b) => a.size - b.size) + const hipLine = hipLines[0] + polygonPoints.push({ x: hipLine.is.x, y: hipLine.is.y }) + const ridgePoint = + hipLine.is.x === hipLine.line.x1 && hipLine.is.y === hipLine.line.y1 + ? { x: hipLine.line.x2, y: hipLine.line.y2 } + : { x: hipLine.line.x1, y: hipLine.line.y1 } + prevRidge = baseGableRidgeLines.find( + (line) => (line.x1 === ridgePoint.x && line.y1 === ridgePoint.y) || (line.x2 === ridgePoint.x && line.y2 === ridgePoint.y), + ) } - }) + } else { + const prevRidges = [] + baseGableRidgeLines.forEach((ridge) => { + const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } + const is = edgesIntersection(prevEdge, ridgeEdge) + if (is) { + const isVectorX = Math.sign(prevRoof.x1 - is.x) + const isVectorY = Math.sign(prevRoof.y1 - is.y) + if ( + isVectorX === prevVectorX && + isVectorY === prevVectorY && + ((Math.abs(ridge.x1 - is.x) < 1 && Math.abs(ridge.y1 - is.y) < 1) || (Math.abs(ridge.x2 - is.x) < 1 && Math.abs(ridge.y2 - is.y) < 1)) + ) { + const size = Big(prevRoof.x1).minus(is.x).abs().pow(2).plus(Big(prevRoof.y1).minus(is.y).abs().pow(2)).sqrt().toNumber() + prevRidges.push({ ridge, size }) + } + } + }) + if (prevRidges.length > 0) { + prevRidges.sort((a, b) => a.size - b.size) + prevRidge = prevRidges[0].ridge + } + } + + const nextEdge = { vertex1: { x: nextRoof.x1, y: nextRoof.y1 }, vertex2: { x: nextRoof.x2, y: nextRoof.y2 } } + const nextVectorX = Math.sign(nextLine.x1 - nextLine.x2) + const nextVectorY = Math.sign(nextLine.y1 - nextLine.y2) + if (nextLine.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + const hipLines = [] + baseHipLines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const is = edgesIntersection(nextEdge, lineEdge) + if (is) { + const size = Big(is.x).minus(nextRoof.x1).abs().pow(2).plus(Big(is.y).minus(nextRoof.y1).abs().pow(2)).sqrt().toNumber() + hipLines.push({ line, is, size }) + } + }) + if (hipLines.length > 0) { + hipLines.sort((a, b) => a.size - b.size) + const hipLine = hipLines[0] + polygonPoints.push({ x: hipLine.is.x, y: hipLine.is.y }) + const ridgePoint = + hipLine.is.x === hipLine.line.x1 && hipLine.is.y === hipLine.line.y1 + ? { x: hipLine.line.x2, y: hipLine.line.y2 } + : { x: hipLine.line.x1, y: hipLine.line.y1 } + nextRidge = baseGableRidgeLines.find( + (line) => (line.x1 === ridgePoint.x && line.y1 === ridgePoint.y) || (line.x2 === ridgePoint.x && line.y2 === ridgePoint.y), + ) + } + } else { + const nextRidges = [] + baseGableRidgeLines.forEach((ridge) => { + const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } + const is = edgesIntersection(nextEdge, ridgeEdge) + if (is) { + const isVectorX = Math.sign(nextRoof.x1 - is.x) + const isVectorY = Math.sign(nextRoof.y1 - is.y) + if ( + isVectorX === nextVectorX && + isVectorY === nextVectorY && + ((Math.abs(ridge.x1 - is.x) < 1 && Math.abs(ridge.y1 - is.y) < 1) || (Math.abs(ridge.x2 - is.x) < 1 && Math.abs(ridge.y2 - is.y) < 1)) + ) { + const size = Big(nextLine.x1).minus(is.x).abs().pow(2).plus(Big(nextLine.y1).minus(is.y).abs().pow(2)).sqrt().toNumber() + nextRidges.push({ ridge, size }) + } + } + }) + if (nextRidges.length > 0) { + nextRidges.sort((a, b) => a.size - b.size) + nextRidge = nextRidges[0].ridge + } + } + + if (prevRidge) { + const checkLine = new fabric.Line([prevRidge.x1, prevRidge.y1, prevRidge.x2, prevRidge.y2], { + stroke: 'red', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + canvas.add(checkLine) + canvas.renderAll() + } + if (nextRidge) { + const checkLine = new fabric.Line([nextRidge.x1, nextRidge.y1, nextRidge.x2, nextRidge.y2], { + stroke: 'yellow', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + canvas.add(checkLine) + canvas.renderAll() + } let currentRidge if (prevRidge) { - if ( - currentVectorX === 0 && - ((prevRidge.y1 <= currentLine.y1 && prevRidge.y2 >= currentLine.y1 && prevRidge.y1 <= currentLine.y2 && prevRidge.y2 >= currentLine.y2) || - (prevRidge.y1 >= currentLine.y1 && prevRidge.y2 <= currentLine.y1 && prevRidge.y1 >= currentLine.y2 && prevRidge.y2 <= currentLine.y2)) - ) { - currentRidge = prevRidge + if (currentVectorX === 0) { + const minY = Math.min(currentLine.y1, currentLine.y2, currentRoof.y1, currentRoof.y2) + const maxY = Math.max(currentLine.y1, currentLine.y2, currentRoof.y1, currentRoof.y2) + if (minY <= prevRidge.y1 && maxY >= prevRidge.y1 && minY <= prevRidge.y2 && maxY >= prevRidge.y2) { + currentRidge = prevRidge + } } - if ( - currentVectorY === 0 && - ((prevRidge.x1 <= currentLine.x1 && prevRidge.x2 >= currentLine.x1 && prevRidge.x1 <= currentLine.x2 && prevRidge.x2 >= currentLine.x2) || - (prevRidge.x1 >= currentLine.x1 && prevRidge.x2 <= currentLine.x1 && prevRidge.x1 >= currentLine.x2 && prevRidge.x2 <= currentLine.x2)) - ) { - currentRidge = prevRidge + if (currentVectorY === 0) { + const minX = Math.min(currentLine.x1, currentLine.x2, currentRoof.x1, currentRoof.x2) + const maxX = Math.max(currentLine.x1, currentLine.x2, currentRoof.x1, currentRoof.x2) + const checkCircle = new fabric.Circle({ + left: minX, + top: prevRidge.y1, + radius: 5, + fill: 'blue', + parentId: roofId, + name: 'checkCircle', + }) + const checkCircle1 = new fabric.Circle({ + left: maxX, + top: prevRidge.y1, + radius: 5, + fill: 'green', + parentId: roofId, + name: 'checkCircle', + }) + canvas.add(checkCircle, checkCircle1) + canvas.renderAll() + + if (minX <= prevRidge.x1 && maxX >= prevRidge.x1 && minX <= prevRidge.x2 && maxX >= prevRidge.x2) { + currentRidge = prevRidge + } } } if (nextRidge) { - if ( - currentVectorX === 0 && - ((nextRidge.y1 <= currentLine.y1 && nextRidge.y2 >= currentLine.y1 && nextRidge.y1 <= currentLine.y2 && nextRidge.y2 >= currentLine.y2) || - (nextRidge.y1 >= currentLine.y1 && nextRidge.y2 <= currentLine.y1 && nextRidge.y1 >= currentLine.y2 && nextRidge.y2 <= currentLine.y2)) - ) { - currentRidge = nextRidge + if (currentVectorX === 0) { + const minY = Math.min(currentLine.y1, currentLine.y2, currentRoof.y1, currentRoof.y2) + const maxY = Math.max(currentLine.y1, currentLine.y2, currentRoof.y1, currentRoof.y2) + if (minY <= nextRidge.y1 && maxY >= nextRidge.y1 && minY <= nextRidge.y2 && maxY >= nextRidge.y2) { + currentRidge = nextRidge + } } - if ( - currentVectorY === 0 && - ((nextRidge.x1 <= currentLine.x1 && nextRidge.x2 >= currentLine.x1 && nextRidge.x1 <= currentLine.x2 && nextRidge.x2 >= currentLine.x2) || - (nextRidge.x1 >= currentLine.x1 && nextRidge.x2 <= currentLine.x1 && nextRidge.x1 >= currentLine.x2 && nextRidge.x2 <= currentLine.x2)) - ) { - currentRidge = nextRidge + if (currentVectorY === 0) { + const minX = Math.min(currentLine.x1, currentLine.x2, currentRoof.x1, currentRoof.x2) + const maxX = Math.max(currentLine.x1, currentLine.x2, currentRoof.x1, currentRoof.x2) + + const checkCircle = new fabric.Circle({ + left: minX, + top: nextRidge.y1, + radius: 5, + fill: 'blue', + parentId: roofId, + name: 'checkCircle', + }) + const checkCircle1 = new fabric.Circle({ + left: maxX, + top: nextRidge.y1, + radius: 5, + fill: 'green', + parentId: roofId, + name: 'checkCircle', + }) + canvas.add(checkCircle, checkCircle1) + canvas.renderAll() + if (minX <= nextRidge.x1 && maxX >= nextRidge.x1 && minX <= nextRidge.x2 && maxX >= nextRidge.x2) { + currentRidge = nextRidge + } } } + if (currentRidge) { + const checkLine = new fabric.Line([currentRidge.x1, currentRidge.y1, currentRidge.x2, currentRidge.y2], { + stroke: 'green', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + canvas.add(checkLine) + canvas.renderAll() + polygonPoints.push({ x: currentRidge.x1, y: currentRidge.y1 }, { x: currentRidge.x2, y: currentRidge.y2 }) + /** 기준점이 될 포인트를 찾는다. 기준점 = 지붕선이나 hip 등에 붙지 않은 포인트 */ + const checkRidgePoints = [ + { x: currentRidge.x1, y: currentRidge.y1, checkPoint: true }, + { x: currentRidge.x2, y: currentRidge.y2, checkPoint: true }, + ] + const ridgeEdge = { vertex1: { x: currentRidge.x1, y: currentRidge.y1 }, vertex2: { x: currentRidge.x2, y: currentRidge.y2 } } + /** 포인트가 지붕선과 붙은 경우 */ + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const is = edgesIntersection(ridgeEdge, lineEdge) + if (is) { + if (Math.abs(is.x - currentRidge.x1) < 1 && Math.abs(is.y - currentRidge.y1) < 1) { + checkRidgePoints[0].checkPoint = false + } + if (Math.abs(is.x - currentRidge.x2) < 1 && Math.abs(is.y - currentRidge.y2) < 1) { + checkRidgePoints[1].checkPoint = false + } + } + }) + /** 포인트가 hip과 붙은 경우 */ + baseHipLines + .filter((line) => line.x1 !== line.x2 && line.y1 !== line.y2) + .forEach((line) => { + if ( + (Math.abs(line.x1 - currentRidge.x1) < 1 && Math.abs(line.y1 - currentRidge.y1) < 1) || + (Math.abs(line.x2 - currentRidge.x1) < 1 && Math.abs(line.y2 - currentRidge.y1) < 1) + ) { + checkRidgePoints[0].checkPoint = false + } + if ( + (Math.abs(line.x1 - currentRidge.x2) < 1 && Math.abs(line.y1 - currentRidge.y2) < 1) || + (Math.abs(line.x2 - currentRidge.x2) < 1 && Math.abs(line.y2 - currentRidge.y2) < 1) + ) { + checkRidgePoints[1].checkPoint = false + } + }) + + const checkRidgePoint = checkRidgePoints.find((point) => point.checkPoint) + /** 마루에서 현재라인으로 향하는 외벽선까지의 포인트를 확인 하여 처리*/ let checkEdge if (currentVectorX === 0) { checkEdge = { - vertex1: { x: currentRidge.x1, y: currentRidge.y1 }, - vertex2: { x: currentLine.x1, y: currentRidge.y1 }, + vertex1: { x: checkRidgePoint.x, y: checkRidgePoint.y }, + vertex2: { x: currentRoof.x1, y: checkRidgePoint.y }, } } else { checkEdge = { - vertex1: { x: currentRidge.x1, y: currentRidge.y1 }, - vertex2: { x: currentRidge.x1, y: currentLine.y1 }, + vertex1: { x: checkRidgePoint.x, y: checkRidgePoint.y }, + vertex2: { x: checkRidgePoint.x, y: currentRoof.y1 }, } } + const currentRoofEdge = { vertex1: { x: currentRoof.x1, y: currentRoof.y1 }, vertex2: { x: currentRoof.x2, y: currentRoof.y2 } } - const checkVectorX = Math.sign(checkEdge.vertex1.x - checkEdge.vertex2.x) - const checkVectorY = Math.sign(checkEdge.vertex1.y - checkEdge.vertex2.y) - const intersectPoints = [] - roof.lines - .filter((line) => (currentVectorX === 0 ? line.x1 === line.x2 : line.y1 === line.y2)) - .forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const is = edgesIntersection(checkEdge, lineEdge) - if (is) { - const isVectorX = Math.sign(checkEdge.vertex1.x - is.x) - const isVectorY = Math.sign(checkEdge.vertex1.y - is.y) - const isLineOtherPoint = - is.x === line.x1 && is.y === line.y1 - ? { x: line.x2, y: line.y2 } - : { - x: line.x1, - y: line.y1, - } - const isInPoint = - checkVectorX === 0 - ? (currentRidge.x1 <= isLineOtherPoint.x && isLineOtherPoint.x <= currentRidge.x2) || - (currentRidge.x1 >= isLineOtherPoint.x && isLineOtherPoint.x >= currentRidge.x2) - : (currentRidge.y1 <= isLineOtherPoint.y && isLineOtherPoint.y <= currentRidge.y2) || - (currentRidge.y1 >= isLineOtherPoint.y && isLineOtherPoint.y >= currentRidge.y2) - if (checkVectorX === isVectorX && checkVectorY === isVectorY && isInPoint) { - const size = Big(checkEdge.vertex1.x).minus(is.x).abs().pow(2).plus(Big(checkEdge.vertex1.y).minus(is.y).abs().pow(2)).sqrt() - intersectPoints.push({ is, size }) - } - } - }) - intersectPoints.sort((a, b) => a.size - b.size) - let intersect = intersectPoints[0].is - if (currentVectorX === 0) { - polygonPoints.push({ x: intersect.x, y: currentRidge.y1 }, { x: intersect.x, y: currentRidge.y2 }) - } else { - polygonPoints.push({ x: currentRidge.x1, y: intersect.y }, { x: currentRidge.x2, y: intersect.y }) + const isRoofPoint = edgesIntersection(checkEdge, currentRoofEdge) + if (isRoofPoint) { + if (currentVectorX === 0) { + const minY = Math.min(currentRoof.y1, currentRoof.y2, isRoofPoint.y) + const maxY = Math.max(currentRoof.y1, currentRoof.y2, isRoofPoint.y) + polygonPoints.push({ x: isRoofPoint.x, y: minY }, { x: isRoofPoint.x, y: maxY }) + } else { + const minX = Math.min(currentRoof.x1, currentRoof.x2, isRoofPoint.x) + const maxX = Math.max(currentRoof.x1, currentRoof.x2, isRoofPoint.x) + polygonPoints.push({ x: minX, y: isRoofPoint.y }, { x: maxX, y: isRoofPoint.y }) + } } } } - const sortedPolygonPoints = getSortedPoint(polygonPoints) - sortedPolygonPoints.forEach((startPoint, index) => { - let endPoint - if (index === sortedPolygonPoints.length - 1) { - endPoint = sortedPolygonPoints[0] - } else { - endPoint = sortedPolygonPoints[index + 1] + const uniquePoints = [] + polygonPoints.forEach((point) => { + const isAlready = uniquePoints.find((uniquePoint) => uniquePoint.x === point.x && uniquePoint.y === point.y) + if (!isAlready) { + uniquePoints.push(point) } - const hipLine = drawHipLine([startPoint.x, startPoint.y, endPoint.x, endPoint.y], canvas, roof, textMode, null, currentDegree, currentDegree) + }) + + polygonPoints = getSortedPoint(uniquePoints, baseHipLines) + polygonPoints.forEach((currentPoint, index) => { + const nextPoint = polygonPoints[(index + 1) % polygonPoints.length] + const points = [currentPoint.x, currentPoint.y, nextPoint.x, nextPoint.y] + + const ridgeLines = baseGableRidgeLines.filter( + (line) => + (line.x1 === points[0] && line.y1 === points[1] && line.x2 === points[2] && line.y2 === points[3]) || + (line.x1 === points[2] && line.y1 === points[3] && line.x2 === points[0] && line.y2 === points[1]), + ) + const hipLines = baseHipLines.filter( + (line) => + (line.x1 === points[0] && line.y1 === points[1] && line.x2 === points[2] && line.y2 === points[3]) || + (line.x1 === points[2] && line.y1 === points[3] && line.x2 === points[0] && line.y2 === points[1]), + ) + /** 이미 존재하는 라인이면 넘긴다.*/ + if (ridgeLines.length > 0 || hipLines.length > 0) { + return + } + + const hipLine = drawHipLine(points, canvas, roof, textMode, null, currentDegree, currentDegree) if (currentVectorX === 0) { - if (Math.sign(startPoint.x - endPoint.x) === 0) { + if (Math.sign(currentPoint.x - nextPoint.x) === 0) { hipLine.attributes.actualSize = hipLine.attributes.planeSize } } else { - if (Math.sign(startPoint.y - endPoint.y) === 0) { + if (Math.sign(currentPoint.y - nextPoint.y) === 0) { hipLine.attributes.actualSize = hipLine.attributes.planeSize } } baseHipLines.push({ x1: hipLine.x1, y1: hipLine.y1, x2: hipLine.x2, y2: hipLine.y2, line: hipLine }) }) + canvas + .getObjects() + .filter((obj) => obj.name === 'checkLine' || obj.name === 'checkCircle') + .forEach((obj) => canvas.remove(obj)) + canvas.renderAll() }) /** 케라바 지붕에 연결된 마루 중 처마라인이 그려지지 않은 경우 확*/ @@ -2711,8 +3548,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { currentLine.x1 !== currentLine.x2 && ((currentLine.x1 <= ridge.x1 && ridge.x1 <= currentLine.x2) || (currentLine.x2 <= ridge.x1 && ridge.x1 <= currentLine.x1)) ) { - degree1 = prevLine.attributes.pitch > 0 ? getDegreeByChon(prevLine.attributes.pitch) : prevLine.attributes.degree - degree2 = nextLine.attributes.pitch > 0 ? getDegreeByChon(nextLine.attributes.pitch) : nextLine.attributes.degree + degree1 = getDegreeByChon(prevLine.attributes.pitch) + degree2 = getDegreeByChon(nextLine.attributes.pitch) } if ( @@ -2720,8 +3557,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { currentLine.y1 !== currentLine.y2 && ((currentLine.y1 <= ridge.y1 && ridge.y1 <= currentLine.y2) || (currentLine.y2 <= ridge.y1 && ridge.y1 <= currentLine.y1)) ) { - degree1 = prevLine.attributes.pitch > 0 ? getDegreeByChon(prevLine.attributes.pitch) : prevLine.attributes.degree - degree2 = nextLine.attributes.pitch > 0 ? getDegreeByChon(nextLine.attributes.pitch) : nextLine.attributes.degree + degree1 = getDegreeByChon(prevLine.attributes.pitch) + degree2 = getDegreeByChon(nextLine.attributes.pitch) } } }) @@ -2775,52 +3612,35 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } if (hipPoint1) { - let alreadyHip = false - baseHipLines - .filter( - (line) => - (line.line.x1 === hipPoint1[0] && line.line.y1 === hipPoint1[1] && line.line.x2 === hipPoint1[2] && line.line.y2 === hipPoint1[3]) || - (line.line.x2 === hipPoint1[0] && line.line.y2 === hipPoint1[1] && line.line.x1 === hipPoint1[2] && line.line.y1 === hipPoint1[3]), - ) - .forEach((line) => { - alreadyHip = true - }) - baseGableLines - .filter( - (line) => - (line.x1 === hipPoint1[0] && line.y1 === hipPoint1[1] && line.x2 === hipPoint1[2] && line.y2 === hipPoint1[3]) || - (line.x2 === hipPoint1[0] && line.y2 === hipPoint1[1] && line.x1 === hipPoint1[2] && line.y1 === hipPoint1[3]), - ) - .forEach((line) => { - alreadyHip = true - }) + const hipLines = baseHipLines.filter( + (line) => + (line.line.x1 === hipPoint1[0] && line.line.y1 === hipPoint1[1] && line.line.x2 === hipPoint1[2] && line.line.y2 === hipPoint1[3]) || + (line.line.x2 === hipPoint1[0] && line.line.y2 === hipPoint1[1] && line.line.x1 === hipPoint1[2] && line.line.y1 === hipPoint1[3]), + ) - if (!alreadyHip) { + const gableLines = baseGableLines.filter( + (line) => + (line.x1 === hipPoint1[0] && line.y1 === hipPoint1[1] && line.x2 === hipPoint1[2] && line.y2 === hipPoint1[3]) || + (line.x2 === hipPoint1[0] && line.y2 === hipPoint1[1] && line.x1 === hipPoint1[2] && line.y1 === hipPoint1[3]), + ) + + if (gableLines.length === 0 && hipLines.length === 0) { const hipLine1 = drawHipLine(hipPoint1, canvas, roof, textMode, null, degree1, degree1) baseHipLines.push({ x1: hipLine1.x1, y1: hipLine1.y1, x2: hipLine1.x2, y2: hipLine1.y2, line: hipLine1 }) } } if (hipPoint2) { - let alreadyHip = false - baseHipLines - .filter( - (line) => - (line.line.x1 === hipPoint2[0] && line.line.y1 === hipPoint2[1] && line.line.x2 === hipPoint2[2] && line.line.y2 === hipPoint2[3]) || - (line.line.x2 === hipPoint2[0] && line.line.y2 === hipPoint2[1] && line.line.x1 === hipPoint2[2] && line.line.y1 === hipPoint2[3]), - ) - .forEach((line) => { - alreadyHip = true - }) - baseGableLines - .filter( - (line) => - (line.x1 === hipPoint2[0] && line.y1 === hipPoint2[1] && line.x2 === hipPoint2[2] && line.y2 === hipPoint2[3]) || - (line.x2 === hipPoint2[0] && line.y2 === hipPoint2[1] && line.x1 === hipPoint2[2] && line.y1 === hipPoint2[3]), - ) - .forEach((line) => { - alreadyHip = true - }) - if (!alreadyHip) { + const hipLines = baseHipLines.filter( + (line) => + (line.line.x1 === hipPoint2[0] && line.line.y1 === hipPoint2[1] && line.line.x2 === hipPoint2[2] && line.line.y2 === hipPoint2[3]) || + (line.line.x2 === hipPoint2[0] && line.line.y2 === hipPoint2[1] && line.line.x1 === hipPoint2[2] && line.line.y1 === hipPoint2[3]), + ) + const gableLines = baseGableLines.filter( + (line) => + (line.x1 === hipPoint2[0] && line.y1 === hipPoint2[1] && line.x2 === hipPoint2[2] && line.y2 === hipPoint2[3]) || + (line.x2 === hipPoint2[0] && line.y2 === hipPoint2[1] && line.x1 === hipPoint2[2] && line.y1 === hipPoint2[3]), + ) + if (hipLines.length === 0 && gableLines.length === 0) { const hipLine2 = drawHipLine(hipPoint2, canvas, roof, textMode, null, degree2, degree2) baseHipLines.push({ x1: hipLine2.x1, y1: hipLine2.y1, x2: hipLine2.x2, y2: hipLine2.y2, line: hipLine2 }) } @@ -2877,52 +3697,34 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } if (hipPoint1) { - let alreadyHip = false - baseHipLines - .filter( - (line) => - (line.line.x1 === hipPoint1[0] && line.line.y1 === hipPoint1[1] && line.line.x2 === hipPoint1[2] && line.line.y2 === hipPoint1[3]) || - (line.line.x2 === hipPoint1[0] && line.line.y2 === hipPoint1[1] && line.line.x1 === hipPoint1[2] && line.line.y1 === hipPoint1[3]), - ) - .forEach((line) => { - alreadyHip = true - }) - baseGableLines - .filter( - (line) => - (line.x1 === hipPoint1[0] && line.y1 === hipPoint1[1] && line.x2 === hipPoint1[2] && line.y2 === hipPoint1[3]) || - (line.x2 === hipPoint1[0] && line.y2 === hipPoint1[1] && line.x1 === hipPoint1[2] && line.y1 === hipPoint1[3]), - ) - .forEach((line) => { - alreadyHip = true - }) + const hipLines = baseHipLines.filter( + (line) => + (line.line.x1 === hipPoint1[0] && line.line.y1 === hipPoint1[1] && line.line.x2 === hipPoint1[2] && line.line.y2 === hipPoint1[3]) || + (line.line.x2 === hipPoint1[0] && line.line.y2 === hipPoint1[1] && line.line.x1 === hipPoint1[2] && line.line.y1 === hipPoint1[3]), + ) + const gableLines = baseGableLines.filter( + (line) => + (line.x1 === hipPoint1[0] && line.y1 === hipPoint1[1] && line.x2 === hipPoint1[2] && line.y2 === hipPoint1[3]) || + (line.x2 === hipPoint1[0] && line.y2 === hipPoint1[1] && line.x1 === hipPoint1[2] && line.y1 === hipPoint1[3]), + ) - if (!alreadyHip) { + if (hipLines.length === 0 && gableLines.length === 0) { const hipLine1 = drawHipLine(hipPoint1, canvas, roof, textMode, null, degree1, degree1) baseHipLines.push({ x1: hipLine1.x1, y1: hipLine1.y1, x2: hipLine1.x2, y2: hipLine1.y2, line: hipLine1 }) } } if (hipPoint2) { - let alreadyHip = false - baseHipLines - .filter( - (line) => - (line.line.x1 === hipPoint2[0] && line.line.y1 === hipPoint2[1] && line.line.x2 === hipPoint2[2] && line.line.y2 === hipPoint2[3]) || - (line.line.x2 === hipPoint2[0] && line.line.y2 === hipPoint2[1] && line.line.x1 === hipPoint2[2] && line.line.y1 === hipPoint2[3]), - ) - .forEach((line) => { - alreadyHip = true - }) - baseGableLines - .filter( - (line) => - (line.x1 === hipPoint2[0] && line.y1 === hipPoint2[1] && line.x2 === hipPoint2[2] && line.y2 === hipPoint2[3]) || - (line.x2 === hipPoint2[0] && line.y2 === hipPoint2[1] && line.x1 === hipPoint2[2] && line.y1 === hipPoint2[3]), - ) - .forEach((line) => { - alreadyHip = true - }) - if (!alreadyHip) { + const hipLines = baseHipLines.filter( + (line) => + (line.line.x1 === hipPoint2[0] && line.line.y1 === hipPoint2[1] && line.line.x2 === hipPoint2[2] && line.line.y2 === hipPoint2[3]) || + (line.line.x2 === hipPoint2[0] && line.line.y2 === hipPoint2[1] && line.line.x1 === hipPoint2[2] && line.line.y1 === hipPoint2[3]), + ) + const gableLines = baseGableLines.filter( + (line) => + (line.x1 === hipPoint2[0] && line.y1 === hipPoint2[1] && line.x2 === hipPoint2[2] && line.y2 === hipPoint2[3]) || + (line.x2 === hipPoint2[0] && line.y2 === hipPoint2[1] && line.x1 === hipPoint2[2] && line.y1 === hipPoint2[3]), + ) + if (hipLines.length === 0 && gableLines.length === 0) { const hipLine2 = drawHipLine(hipPoint2, canvas, roof, textMode, null, degree2, degree2) baseHipLines.push({ x1: hipLine2.x1, y1: hipLine2.y1, x2: hipLine2.x2, y2: hipLine2.y2, line: hipLine2 }) } @@ -2931,6 +3733,928 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } }) + /** 팔작지붕 */ + drawHipAndGableFirst.forEach((current) => { + const { currentBaseLine, prevBaseLine, nextBaseLine } = current + const currentLine = currentBaseLine.line + const prevLine = prevBaseLine.line + const nextLine = nextBaseLine.line + let { x1, x2, y1, y2 } = currentBaseLine + const currentDegree = getDegreeByChon(currentLine.attributes.pitch) + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) + const nextDegree = getDegreeByChon(nextLine.attributes.pitch) + + let beforePrevLine, afterNextLine + drawBaseLines.forEach((line, index) => { + if (line === prevBaseLine) { + beforePrevLine = drawBaseLines[(index - 1 + drawBaseLines.length) % drawBaseLines.length] + } + if (line === nextBaseLine) { + afterNextLine = drawBaseLines[(index + 1) % drawBaseLines.length] + } + }) + /** 팔작지붕 두께*/ + const lineWidth = + currentLine.attributes.width < Big(currentLine.attributes.planeSize).div(20).toNumber() + ? currentLine.attributes.width + : Big(currentLine.attributes.planeSize).div(20).toNumber() + + const currentVectorX = Math.sign(currentLine.x2 - currentLine.x1) + const currentVectorY = Math.sign(currentLine.y2 - currentLine.y1) + + const currentMidX = Big(currentLine.x1).plus(Big(currentLine.x2)).div(2) + const currentMidY = Big(currentLine.y1).plus(Big(currentLine.y2)).div(2) + const intersectionRoofs = [] + if (currentVectorX === 0) { + const checkEdge = { + vertex1: { x: prevLine.x1, y: currentMidY.toNumber() }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } else { + const checkEdge = { + vertex1: { x: currentMidX.toNumber(), y: prevLine.y1 }, + vertex2: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } + + let currentRoof, prevRoof, nextRoof + if (intersectionRoofs.length > 0) { + currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line + } + + roof.lines.forEach((line, index) => { + if (line === currentRoof) { + prevRoof = roof.lines[(index - 1 + roof.lines.length) % roof.lines.length] + nextRoof = roof.lines[(index + 1) % roof.lines.length] + } + }) + + // /** 이전, 다음라인의 사잇각의 vector를 구한다. */ + let prevVector = getHalfAngleVector(prevRoof, currentRoof) + let nextVector = getHalfAngleVector(currentRoof, nextRoof) + + let prevHipVector = { x: Math.sign(prevVector.x), y: Math.sign(prevVector.y) } + let nextHipVector = { x: Math.sign(nextVector.x), y: Math.sign(nextVector.y) } + + /** 현재 라인의 길이 추녀마루 길이의 기준이 된다. */ + let hipSize = Big(lineWidth).pow(2).plus(Big(lineWidth).pow(2)).sqrt() + console.log('hipSize', hipSize.toNumber()) + + /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const prevCheckPoint = { + x: Big(currentRoof.x1).plus(Big(prevHipVector.x).times(lineWidth)), + y: Big(currentRoof.y1).plus(Big(prevHipVector.y).times(lineWidth)), + } + if (!roof.inPolygon(prevCheckPoint)) { + prevHipVector = { x: Math.sign(prevHipVector.x * -1), y: Math.sign(prevHipVector.y * -1) } + } + + /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const nextCheckPoint = { + x: Big(currentRoof.x2).plus(Big(nextHipVector.x).times(lineWidth)), + y: Big(currentRoof.y2).plus(Big(nextHipVector.y).times(lineWidth)), + } + if (!roof.inPolygon(nextCheckPoint)) { + nextHipVector = { x: Math.sign(nextHipVector.x * -1), y: Math.sign(nextHipVector.y * -1) } + } + + /** 처마끝에서 올라오는 라인*/ + const prevPoint = [ + currentRoof.x1, + currentRoof.y1, + Big(currentRoof.x1).plus(Big(prevHipVector.x).times(lineWidth)).toNumber(), + Big(currentRoof.y1).plus(Big(prevHipVector.y).times(lineWidth)).toNumber(), + ] + const nextPoint = [ + currentRoof.x2, + currentRoof.y2, + Big(currentRoof.x2).plus(Big(nextHipVector.x).times(lineWidth)).toNumber(), + Big(currentRoof.y2).plus(Big(nextHipVector.y).times(lineWidth)).toNumber(), + ] + const prevHipLine = drawHipLine(prevPoint, canvas, roof, textMode, null, prevDegree, currentDegree) + const nextHipLine = drawHipLine(nextPoint, canvas, roof, textMode, null, currentDegree, nextDegree) + baseHipLines.push({ x1, y1, x2: prevHipLine.x1, y2: prevHipLine.y1, line: prevHipLine }) + baseHipLines.push({ x1: x2, y1: y2, x2: nextHipLine.x1, y2: nextHipLine.y1, line: nextHipLine }) + + /** 처마끝에서 올라오는 라인에서 가운데로 모이는 라인*/ + let midX, midY + if (currentVectorX === 0) { + midX = prevHipLine.x2 + midY = currentMidY.toNumber() + } else { + midX = currentMidX.toNumber() + midY = prevHipLine.y2 + } + const prevGablePoint = [prevHipLine.x2, prevHipLine.y2, midX, midY] + const nextGablePoint = [nextHipLine.x2, nextHipLine.y2, midX, midY] + + const prevGableLine = drawHipLine(prevGablePoint, canvas, roof, textMode, null, prevDegree, currentDegree) + const nextGableLine = drawHipLine(nextGablePoint, canvas, roof, textMode, null, currentDegree, nextDegree) + baseHipLines.push({ x1: prevGableLine.x1, y1: prevGableLine.y1, x2: prevGableLine.x2, y2: prevGableLine.y2, line: prevGableLine }) + baseHipLines.push({ x1: nextGableLine.x1, y1: nextGableLine.y1, x2: nextGableLine.x2, y2: nextGableLine.y2, line: nextGableLine }) + + let oppositeLine + baseLines + .filter((line) => line !== currentLine) + .filter((line) => (currentVectorX === 0 ? line.x1 === line.x2 : line.y1 === line.y2)) + .forEach((oppCurrLine) => { + let checkEdge + if (currentVectorX === 0) { + checkEdge = { + vertex1: { x: midX, y: midY }, + vertex2: { x: oppCurrLine.x1, y: midY }, + } + } else { + checkEdge = { + vertex1: { x: midX, y: midY }, + vertex2: { x: midX, y: oppCurrLine.y1 }, + } + } + const lineEdge = { vertex1: { x: oppCurrLine.x1, y: oppCurrLine.y1 }, vertex2: { x: oppCurrLine.x2, y: oppCurrLine.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection && isPointOnLine(oppCurrLine, intersection)) { + const size = + calcLinePlaneSize({ + x1: checkEdge.vertex1.x, + y1: checkEdge.vertex1.y, + x2: intersection.x, + y2: intersection.y, + }) / 10 + oppositeLine = { intersection, size, oppCurrLine } + } + }) + + if (oppositeLine) { + const { intersection, size, oppCurrLine } = oppositeLine + let oppPrevLine, oppNextLine + let oppRoofLine + + let ridgePoints = [] + let ridgeSize + + const ridgeEdge = { + vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + vertex2: { x: intersection.x, y: intersection.y }, + } + + if (prevLine.attributes.type === LINE_TYPE.WALLLINE.EAVES && beforePrevLine.line.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let beforePrevVector = getHalfAngleVector(prevLine, beforePrevLine) + /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const beforePrevCheckPoint = { + x: Big(prevLine.x1).plus(Big(beforePrevVector.x).times(10)), + y: Big(prevLine.y1).plus(Big(beforePrevVector.y).times(10)), + } + if (!checkWallPolygon.inPolygon(beforePrevCheckPoint)) { + beforePrevVector = { x: -beforePrevVector.x, y: -beforePrevVector.y } + } + + const checkBeforeEdge = { + vertex1: { x: prevLine.x1, y: prevLine.y1 }, + vertex2: { + x: Big(prevLine.x1).plus(Big(beforePrevVector.x).times(10)).toNumber(), + y: Big(prevLine.y1).plus(Big(beforePrevVector.y).times(10)).toNumber(), + }, + } + + const isBefore = edgesIntersection(checkBeforeEdge, ridgeEdge) + if (isBefore) { + const size = Big(isBefore.x).minus(currentMidX).abs().pow(2).plus(Big(isBefore.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber() + ridgePoints.push({ x: isBefore.x, y: isBefore.y, size }) + } + } + + if (nextLine.attributes.type === LINE_TYPE.WALLLINE.EAVES && afterNextLine.line.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let afterNextVector = getHalfAngleVector(nextLine, afterNextLine) + + /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const afterNextCheckPoint = { + x: Big(nextLine.x2).plus(Big(afterNextVector.x).times(10)), + y: Big(nextLine.y2).plus(Big(afterNextVector.y).times(10)), + } + if (!checkWallPolygon.inPolygon(afterNextCheckPoint)) { + afterNextVector = { x: -afterNextVector.x, y: -afterNextVector.y } + } + + const checkAfterEdge = { + vertex1: { x: nextLine.x2, y: nextLine.y2 }, + vertex2: { + x: Big(nextLine.x2).plus(Big(afterNextVector.x).times(10)).toNumber(), + y: Big(nextLine.y2).plus(Big(afterNextVector.y).times(10)).toNumber(), + }, + } + const isAfter = edgesIntersection(checkAfterEdge, ridgeEdge) + if (isAfter) { + const size = Big(isAfter.x).minus(currentMidX).abs().pow(2).plus(Big(isAfter.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber() + ridgePoints.push({ x: isAfter.x, y: isAfter.y, size }) + } + } + + baseLines.forEach((line, index) => { + if (line === oppCurrLine) { + oppPrevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length] + oppNextLine = baseLines[(index + 1) % baseLines.length] + } + }) + + const oppositeRoofs = [] + const oppositeMidX = Big(oppCurrLine.x1).plus(Big(oppCurrLine.x2)).div(2) + const oppositeMidY = Big(oppCurrLine.y1).plus(Big(oppCurrLine.y2)).div(2) + const oppositeVectorX = Math.sign(oppCurrLine.x2 - oppCurrLine.x1) + const oppositeVectorY = Math.sign(oppCurrLine.y2 - oppCurrLine.y1) + + if (Math.sign(oppCurrLine.x1 - oppCurrLine.x2) === 0) { + const checkEdge = { + vertex1: { x: oppPrevLine.x1, y: oppositeMidY.toNumber() }, + vertex2: { x: oppositeMidX.toNumber(), y: oppositeMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === oppositeVectorX && Math.sign(line.y2 - line.y1) === oppositeVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + oppositeRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(oppositeMidX).abs().pow(2).plus(Big(intersection.y).minus(oppositeMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } else { + const checkEdge = { + vertex1: { x: oppositeMidX.toNumber(), y: oppPrevLine.y1 }, + vertex2: { x: oppositeMidX.toNumber(), y: oppositeMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === oppositeVectorX && Math.sign(line.y2 - line.y1) === oppositeVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + oppositeRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(oppositeMidX).abs().pow(2).plus(Big(intersection.y).minus(oppositeMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } + if (oppositeRoofs.length > 0) { + oppRoofLine = oppositeRoofs.sort((a, b) => a.size - b.size)[0].line + } + + console.log('oppositeRoofs', oppositeRoofs) + console.log('oppositeRoofLine', oppRoofLine) + if (oppCurrLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + if (oppRoofLine) { + const oppRoofSize = Big(oppRoofLine.attributes.planeSize).div(20) + const ridgeEdge = { + vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + vertex2: { x: intersection.x, y: intersection.y }, + } + + if (oppPrevLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let oppPrevVector = getHalfAngleVector(oppCurrLine, oppPrevLine) + oppPrevVector = { x: oppPrevVector.x, y: oppPrevVector.y } + + /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const prevCheckPoint = { + x: Big(oppCurrLine.x1).plus(Big(oppPrevVector.x).times(10)), + y: Big(oppCurrLine.y1).plus(Big(oppPrevVector.y).times(10)), + } + + if (!checkWallPolygon.inPolygon(prevCheckPoint)) { + oppPrevVector = { x: -oppPrevVector.x, y: -oppPrevVector.y } + } + + const oppPrevHipEdge = { + vertex1: { + x: oppRoofLine.x1, + y: oppRoofLine.y1, + }, + vertex2: { + x: Big(oppRoofLine.x1).plus(Big(oppPrevVector.x).times(oppRoofSize)).toNumber(), + y: Big(oppRoofLine.y1).plus(Big(oppPrevVector.y).times(oppRoofSize)).toNumber(), + }, + } + + const isOppPrev = edgesIntersection(oppPrevHipEdge, ridgeEdge) + + if ( + isOppPrev && + isPointOnLine( + { + x1: oppPrevHipEdge.vertex1.x, + y1: oppPrevHipEdge.vertex1.y, + x2: oppPrevHipEdge.vertex2.x, + y2: oppPrevHipEdge.vertex2.y, + }, + isOppPrev, + ) + ) { + const size = Big(isOppPrev.x).minus(currentMidX).abs().pow(2).plus(Big(isOppPrev.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber() + ridgePoints.push({ x: isOppPrev.x, y: isOppPrev.y, size }) + } + } + if (oppNextLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let oppNextVector = getHalfAngleVector(oppCurrLine, oppNextLine) + oppNextVector = { x: oppNextVector.x, y: oppNextVector.y } + + /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const nextCheckPoint = { + x: Big(oppCurrLine.x2).plus(Big(oppNextVector.x).times(10)), + y: Big(oppCurrLine.y2).plus(Big(oppNextVector.y).times(10)), + } + + if (!checkWallPolygon.inPolygon(nextCheckPoint)) { + oppNextVector = { x: -oppNextVector.x, y: -oppNextVector.y } + } + + const oppNextHipEdge = { + vertex1: { + x: oppRoofLine.x2, + y: oppRoofLine.y2, + }, + vertex2: { + x: Big(oppRoofLine.x2).plus(Big(oppNextVector.x).times(oppRoofSize)).toNumber(), + y: Big(oppRoofLine.y2).plus(Big(oppNextVector.y).times(oppRoofSize)).toNumber(), + }, + } + const isOppNext = edgesIntersection(oppNextHipEdge, ridgeEdge) + if ( + isOppNext && + isPointOnLine( + { + x1: oppNextHipEdge.vertex1.x, + y1: oppNextHipEdge.vertex1.y, + x2: oppNextHipEdge.vertex2.x, + y2: oppNextHipEdge.vertex2.y, + }, + isOppNext, + ) + ) { + const size = Big(isOppNext.x).minus(currentMidX).abs().pow(2).plus(Big(isOppNext.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber() + ridgePoints.push({ x: isOppNext.x, y: isOppNext.y, size }) + } + } + } + } else if (oppCurrLine.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + ridgeSize = Big(size).minus(Big(oppCurrLine.attributes.width)).plus(Big(oppCurrLine.attributes.offset)).toNumber() + } + + if (ridgePoints.length > 0) { + ridgeSize = ridgePoints.sort((a, b) => a.size - b.size)[0].size + } + + if (ridgeSize > 0 && baseRidgeCount < getMaxRidge(baseLines.length)) { + const ridgeVectorX = Math.sign(midX - intersection.x) + const ridgeVectorY = Math.sign(midY - intersection.y) + const ridgePoint = [ + midX, + midY, + Big(midX).minus(Big(ridgeSize).times(ridgeVectorX)).toNumber(), + Big(midY).minus(Big(ridgeSize).times(ridgeVectorY)).toNumber(), + ] + const ridgeLine = drawRidgeLine(ridgePoint, canvas, roof, textMode) + baseRidgeLines.push(ridgeLine) + baseRidgeCount++ + } else { + let ridges = [] + baseGableRidgeLines + .filter( + (ridge) => + (Math.abs(ridge.x1 - midX) < 1 && Math.abs(ridge.y1 - midY) < 1) || (Math.abs(ridge.x2 - midX) < 1 && Math.abs(ridge.y2 - midY) < 1), + ) + .forEach((ridge) => ridges.push(ridge)) + baseRidgeLines + .filter( + (ridge) => + (Math.abs(ridge.x1 - midX) < 1 && Math.abs(ridge.y1 - midY) < 1) || (Math.abs(ridge.x2 - midX) < 1 && Math.abs(ridge.y2 - midY) < 1), + ) + .forEach((ridge) => ridges.push(ridge)) + if (ridges.length > 0) { + return + } + + canvas.remove(prevGableLine) + canvas.remove(nextGableLine) + baseHipLines = baseHipLines.filter((base) => base.line !== prevGableLine && base.line !== nextGableLine) + + const points = [prevGableLine.x1, prevGableLine.y1, nextGableLine.x1, nextGableLine.y1] + const gableLine = drawRoofLine(points, canvas, roof, textMode) + baseHipLines.push({ x1: gableLine.x1, y1: gableLine.y1, x2: gableLine.x2, y2: gableLine.y2, line: gableLine }) + } + } + }) + + /** 벽과 이어진 마루를 그린다. */ + drawWallRidgeLine.forEach((current) => { + const { currentBaseLine, prevBaseLine, nextBaseLine } = current + const currentLine = currentBaseLine.line + const prevLine = prevBaseLine.line + const nextLine = nextBaseLine.line + let beforePrevLine, afterNextLine + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) + const nextDegree = getDegreeByChon(nextLine.attributes.pitch) + const currentMidX = Big(currentLine.x1).plus(Big(currentLine.x2)).div(2).toNumber() + const currentMidY = Big(currentLine.y1).plus(Big(currentLine.y2)).div(2).toNumber() + const currentVectorX = Math.sign(currentLine.x2 - currentLine.x1) + const currentVectorY = Math.sign(currentLine.y2 - currentLine.y1) + + /** 이전 라인의 전라인, 다음 라인의 다음라인을 찾는다 */ + drawBaseLines.forEach((line, index) => { + if (line === prevBaseLine) { + beforePrevLine = drawBaseLines[(index - 1 + drawBaseLines.length) % drawBaseLines.length] + } + if (line === nextBaseLine) { + afterNextLine = drawBaseLines[(index + 1) % drawBaseLines.length] + } + }) + + let oppositeLine + baseLines + .filter((line) => line !== currentLine) + .filter((line) => (currentVectorX === 0 ? line.x1 === line.x2 : line.y1 === line.y2)) + .forEach((oppCurrLine) => { + let checkEdge + if (currentVectorX === 0) { + checkEdge = { + vertex1: { x: currentMidX, y: currentMidY }, + vertex2: { x: oppCurrLine.x1, y: currentMidY }, + } + } else { + checkEdge = { + vertex1: { x: currentMidX, y: currentMidY }, + vertex2: { x: currentMidX, y: oppCurrLine.y1 }, + } + } + const lineEdge = { vertex1: { x: oppCurrLine.x1, y: oppCurrLine.y1 }, vertex2: { x: oppCurrLine.x2, y: oppCurrLine.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection && isPointOnLine(oppCurrLine, intersection)) { + const size = + calcLinePlaneSize({ + x1: checkEdge.vertex1.x, + y1: checkEdge.vertex1.y, + x2: intersection.x, + y2: intersection.y, + }) / 10 + oppositeLine = { intersection, size, oppCurrLine } + } + }) + + const ridgePoints = [] + if (oppositeLine) { + const { intersection, size, oppCurrLine } = oppositeLine + ridgePoints.push({ x: intersection.x, y: intersection.y, size }) + const oppPrevLine = baseLines.find((line) => line.x2 === oppCurrLine.x1 && line.y2 === oppCurrLine.y1) + const oppNextLine = baseLines.find((line) => line.x1 === oppCurrLine.x2 && line.y1 === oppCurrLine.y2) + + const oppositeRoofs = [] + const oppositeMidX = Big(oppCurrLine.x1).plus(Big(oppCurrLine.x2)).div(2) + const oppositeMidY = Big(oppCurrLine.y1).plus(Big(oppCurrLine.y2)).div(2) + const oppositeVectorX = Math.sign(oppCurrLine.x2 - oppCurrLine.x1) + const oppositeVectorY = Math.sign(oppCurrLine.y2 - oppCurrLine.y1) + + let oppRoofLine + + if (Math.sign(oppCurrLine.x1 - oppCurrLine.x2) === 0) { + const checkEdge = { + vertex1: { x: oppPrevLine.x1, y: oppositeMidY.toNumber() }, + vertex2: { x: oppositeMidX.toNumber(), y: oppositeMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === oppositeVectorX && Math.sign(line.y2 - line.y1) === oppositeVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + oppositeRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(oppositeMidX).abs().pow(2).plus(Big(intersection.y).minus(oppositeMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } else { + const checkEdge = { + vertex1: { x: oppositeMidX.toNumber(), y: oppPrevLine.y1 }, + vertex2: { x: oppositeMidX.toNumber(), y: oppositeMidY.toNumber() }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === oppositeVectorX && Math.sign(line.y2 - line.y1) === oppositeVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + oppositeRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(oppositeMidX).abs().pow(2).plus(Big(intersection.y).minus(oppositeMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } + if (oppositeRoofs.length > 0) { + oppRoofLine = oppositeRoofs.sort((a, b) => a.size - b.size)[0].line + } + + if (oppRoofLine) { + const ridgeEdge = { vertex1: { x: currentMidX, y: currentMidY }, vertex2: { x: intersection.x, y: intersection.y } } + + if (oppCurrLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + const oppRoofSize = Big(oppRoofLine.attributes.planeSize).div(20) + + if (oppPrevLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let oppPrevVector = getHalfAngleVector(oppCurrLine, oppPrevLine) + oppPrevVector = { x: oppPrevVector.x, y: oppPrevVector.y } + + /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const prevCheckPoint = { + x: Big(oppCurrLine.x1).plus(Big(oppPrevVector.x).times(10)), + y: Big(oppCurrLine.y1).plus(Big(oppPrevVector.y).times(10)), + } + + if (!checkWallPolygon.inPolygon(prevCheckPoint)) { + oppPrevVector = { x: -oppPrevVector.x, y: -oppPrevVector.y } + } + + const oppPrevHipEdge = { + vertex1: { + x: oppRoofLine.x1, + y: oppRoofLine.y1, + }, + vertex2: { + x: Big(oppRoofLine.x1).plus(Big(oppPrevVector.x).times(oppRoofSize)).toNumber(), + y: Big(oppRoofLine.y1).plus(Big(oppPrevVector.y).times(oppRoofSize)).toNumber(), + }, + } + + const isOppPrev = edgesIntersection(oppPrevHipEdge, ridgeEdge) + + if ( + isOppPrev && + isPointOnLine( + { + x1: oppPrevHipEdge.vertex1.x, + y1: oppPrevHipEdge.vertex1.y, + x2: oppPrevHipEdge.vertex2.x, + y2: oppPrevHipEdge.vertex2.y, + }, + isOppPrev, + ) + ) { + const size = Big(isOppPrev.x).minus(currentMidX).abs().pow(2).plus(Big(isOppPrev.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber() + ridgePoints.push({ x: isOppPrev.x, y: isOppPrev.y, size }) + } + } + if (oppNextLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let oppNextVector = getHalfAngleVector(oppCurrLine, oppNextLine) + oppNextVector = { x: oppNextVector.x, y: oppNextVector.y } + + /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const nextCheckPoint = { + x: Big(oppCurrLine.x2).plus(Big(oppNextVector.x).times(10)), + y: Big(oppCurrLine.y2).plus(Big(oppNextVector.y).times(10)), + } + + if (!checkWallPolygon.inPolygon(nextCheckPoint)) { + oppNextVector = { x: -oppNextVector.x, y: -oppNextVector.y } + } + + const oppNextHipEdge = { + vertex1: { + x: oppRoofLine.x2, + y: oppRoofLine.y2, + }, + vertex2: { + x: Big(oppRoofLine.x2).plus(Big(oppNextVector.x).times(oppRoofSize)).toNumber(), + y: Big(oppRoofLine.y2).plus(Big(oppNextVector.y).times(oppRoofSize)).toNumber(), + }, + } + + const isOppNext = edgesIntersection(oppNextHipEdge, ridgeEdge) + if ( + isOppNext && + isPointOnLine( + { + x1: oppNextHipEdge.vertex1.x, + y1: oppNextHipEdge.vertex1.y, + x2: oppNextHipEdge.vertex2.x, + y2: oppNextHipEdge.vertex2.y, + }, + isOppNext, + ) + ) { + const size = Big(isOppNext.x).minus(currentMidX).abs().pow(2).plus(Big(isOppNext.y).minus(currentMidY).abs().pow(2)).sqrt().toNumber() + ridgePoints.push({ x: isOppNext.x, y: isOppNext.y, size }) + } + } + } else { + baseHipLines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(ridgeEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + const size = Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt() + ridgePoints.push({ x: intersection.x, y: intersection.y, size }) + } + } + }) + } + + if (prevLine.attributes.type === LINE_TYPE.WALLLINE.EAVES && beforePrevLine.line.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let beforePrevVector = getHalfAngleVector(prevLine, beforePrevLine) + const checkPoint = { + x: Big(prevLine.x1).plus(Big(beforePrevVector.x).times(10)), + y: Big(prevLine.y1).plus(Big(beforePrevVector.y).times(10)), + } + if (!checkWallPolygon.inPolygon(checkPoint)) { + beforePrevVector = { x: -beforePrevVector.x, y: -beforePrevVector.y } + } + + const hipEdge = { + vertex1: { x: prevLine.x1, y: prevLine.y1 }, + vertex2: { + x: Big(prevLine.x1).plus(Big(beforePrevVector.x).times(prevLine.attributes.planeSize)).toNumber(), + y: Big(prevLine.y1).plus(Big(beforePrevVector.y).times(prevLine.attributes.planeSize)).toNumber(), + }, + } + + const isLines = [] + drawBaseLines + .filter((base) => base !== currentBaseLine && base !== prevBaseLine && base !== beforePrevLine) + .forEach((base) => { + const lineEdge = { vertex1: { x: base.line.x1, y: base.line.y1 }, vertex2: { x: base.line.x2, y: base.line.y2 } } + const intersection = edgesIntersection(hipEdge, lineEdge) + if (intersection && isPointOnLine(base.line, intersection)) { + const size = Big(intersection.x) + .minus(prevLine.x1) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(prevLine.y1).abs().pow(2)) + .sqrt() + .toNumber() + isLines.push({ intersection, size }) + } + }) + + if (isLines.length > 0) { + const hipSize = getAdjacent(isLines.sort((a, b) => a.size - b.size)[0].size / 2) + const hipPoint = [ + prevLine.x1, + prevLine.y1, + Big(prevLine.x1).plus(Big(beforePrevVector.x).times(hipSize)).toNumber(), + Big(prevLine.y1).plus(Big(beforePrevVector.y).times(hipSize)).toNumber(), + ] + + const hipEdge = { vertex1: { x: hipPoint[0], y: hipPoint[1] }, vertex2: { x: hipPoint[2], y: hipPoint[3] } } + const intersection = edgesIntersection(ridgeEdge, hipEdge) + if ( + intersection && + (isPointOnLine({ x1: hipPoint[0], y1: hipPoint[1], x2: hipPoint[2], y2: hipPoint[3] }, intersection) || + (Math.abs(hipPoint[0] - intersection.x) < 1 && Math.abs(hipPoint[1] - intersection.y) < 1) || + (Math.abs(hipPoint[2] - intersection.x) < 1 && Math.abs(hipPoint[3] - intersection.y) < 1)) + ) { + const size = Big(intersection.x) + .minus(currentMidX) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(currentMidY).abs().pow(2)) + .sqrt() + .toNumber() + ridgePoints.push({ x: intersection.x, y: intersection.y, size }) + } + } + } + if (nextLine.attributes.type === LINE_TYPE.WALLLINE.EAVES && afterNextLine.line.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let afterNextVector = getHalfAngleVector(nextLine, afterNextLine) + const checkPoint = { + x: Big(nextLine.x1).plus(Big(afterNextVector.x).times(10)), + y: Big(nextLine.y1).plus(Big(afterNextVector.y).times(10)), + } + if (!checkWallPolygon.inPolygon(checkPoint)) { + afterNextVector = { x: -afterNextVector.x, y: -afterNextVector.y } + } + + const hipEdge = { + vertex1: { x: nextLine.x2, y: nextLine.y2 }, + vertex2: { + x: Big(nextLine.x2).plus(Big(afterNextVector.x).times(nextLine.attributes.planeSize)).toNumber(), + y: Big(nextLine.y2).plus(Big(afterNextVector.y).times(nextLine.attributes.planeSize)).toNumber(), + }, + } + + const isLines = [] + drawBaseLines + .filter((base) => base !== currentBaseLine && base !== nextBaseLine && base !== afterNextLine) + .forEach((base) => { + const lineEdge = { vertex1: { x: base.line.x1, y: base.line.y1 }, vertex2: { x: base.line.x2, y: base.line.y2 } } + const intersection = edgesIntersection(hipEdge, lineEdge) + if (intersection && isPointOnLine(base.line, intersection)) { + const size = Big(intersection.x) + .minus(nextLine.x2) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(nextLine.y2).abs().pow(2)) + .sqrt() + .toNumber() + isLines.push({ intersection, size }) + } + }) + if (isLines.length > 0) { + const hipSize = getAdjacent(isLines.sort((a, b) => a.size - b.size)[0].size / 2) + const hipPoint = [ + nextLine.x2, + nextLine.y2, + Big(nextLine.x2).plus(Big(afterNextVector.x).times(hipSize)).toNumber(), + Big(nextLine.y2).plus(Big(afterNextVector.y).times(hipSize)).toNumber(), + ] + const hipEdge = { vertex1: { x: hipPoint[0], y: hipPoint[1] }, vertex2: { x: hipPoint[2], y: hipPoint[3] } } + const intersection = edgesIntersection(ridgeEdge, hipEdge) + + if ( + intersection && + (isPointOnLine({ x1: hipPoint[0], y1: hipPoint[1], x2: hipPoint[2], y2: hipPoint[3] }, intersection) || + (Math.abs(hipPoint[0] - intersection.x) < 1 && Math.abs(hipPoint[1] - intersection.y) < 1) || + (Math.abs(hipPoint[2] - intersection.x) < 1 && Math.abs(hipPoint[3] - intersection.y) < 1)) + ) { + const size = Big(intersection.x) + .minus(currentMidX) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(currentMidY).abs().pow(2)) + .sqrt() + .toNumber() + ridgePoints.push({ x: intersection.x, y: intersection.y, size }) + } + } + } + } + } + + if (ridgePoints.length === 0 || baseRidgeCount >= getMaxRidge(baseLines.length)) return + const ridgeEndPoint = ridgePoints.sort((a, b) => a.size - b.size)[0] + const ridgePoint = { x1: currentMidX, y1: currentMidY, x2: ridgeEndPoint.x, y2: ridgeEndPoint.y } + + /** 포인트가 지붕밖에 있는 경우 조정*/ + if (!roof.inPolygon({ x: ridgePoint.x1, y: ridgePoint.y1 })) { + const checkEdge = { vertex1: { x: ridgePoint.x2, y: ridgePoint.y2 }, vertex2: { x: ridgePoint.x1, y: ridgePoint.y1 } } + const isPoints = [] + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection && isPointOnLine(line, intersection)) { + if ( + Math.sign(checkEdge.vertex1.x - checkEdge.vertex2.x) === Math.sign(checkEdge.vertex1.x - intersection.x) && + Math.sign(checkEdge.vertex1.y - checkEdge.vertex2.y) === Math.sign(checkEdge.vertex1.y - intersection.y) + ) { + const size = Big(intersection.x) + .minus(ridgePoint.x2) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(ridgePoint.y2).abs().pow(2)) + .sqrt() + .toNumber() + isPoints.push({ x: intersection.x, y: intersection.y, size }) + } + } + }) + if (isPoints.length > 0) { + const newPoint = isPoints.sort((a, b) => a.size - b.size)[0] + ridgePoint.x1 = newPoint.x + ridgePoint.y1 = newPoint.y + } + } + + if (!roof.inPolygon({ x: ridgePoint.x2, y: ridgePoint.y2 })) { + const checkEdge = { vertex1: { x: ridgePoint.x1, y: ridgePoint.y1 }, vertex2: { x: ridgePoint.x2, y: ridgePoint.y2 } } + const isPoints = [] + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection && isPointOnLine(line, intersection)) { + if ( + Math.sign(checkEdge.vertex1.x - checkEdge.vertex2.x) === Math.sign(checkEdge.vertex1.x - intersection.x) && + Math.sign(checkEdge.vertex1.y - checkEdge.vertex2.y) === Math.sign(checkEdge.vertex1.y - intersection.y) + ) { + const size = Big(intersection.x) + .minus(ridgePoint.x1) + .abs() + .pow(2) + .plus(Big(intersection.y).minus(ridgePoint.y1).abs().pow(2)) + .sqrt() + .toNumber() + isPoints.push({ x: intersection.x, y: intersection.y, size }) + } + } + }) + if (isPoints.length > 0) { + const newPoint = isPoints.sort((a, b) => a.size - b.size)[0] + ridgePoint.x2 = newPoint.x + ridgePoint.y2 = newPoint.y + } + } + + const ridge = drawRidgeLine([ridgePoint.x1, ridgePoint.y1, ridgePoint.x2, ridgePoint.y2], canvas, roof, textMode) + baseRidgeLines.push(ridge) + baseRidgeCount++ + + /** 현재 라인의 지붕 라인을 찾는다. */ + const intersectionRoofs = [] + let currentRoof + if (currentVectorX === 0) { + const checkEdge = { + vertex1: { x: prevLine.x1, y: currentMidY }, + vertex2: { x: currentMidX, y: currentMidY }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } else { + const checkEdge = { + vertex1: { x: currentMidX, y: prevLine.y1 }, + vertex2: { x: currentMidX, y: currentMidY }, + } + roof.lines + .filter((line) => Math.sign(line.x2 - line.x1) === currentVectorX && Math.sign(line.y2 - line.y1) === currentVectorY) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection) { + if (isPointOnLine(line, intersection)) { + intersectionRoofs.push({ + line, + intersection, + size: Big(intersection.x).minus(currentMidX).abs().pow(2).plus(Big(intersection.y).minus(currentMidY).abs().pow(2)).sqrt(), + }) + } + } + }) + } + if (intersectionRoofs.length > 0) { + currentRoof = intersectionRoofs.sort((a, b) => a.size - b.size)[0].line + } + if (currentRoof) { + const prevHipPoint = [currentRoof.x1, currentRoof.y1, currentMidX, currentMidY] + const nextHipPoint = [currentRoof.x2, currentRoof.y2, currentMidX, currentMidY] + + const prevHipLine = drawHipLine(prevHipPoint, canvas, roof, textMode, null, prevDegree, prevDegree) + const nextHipLine = drawHipLine(nextHipPoint, canvas, roof, textMode, null, nextDegree, nextDegree) + baseHipLines.push({ x1: prevHipLine.x1, y1: prevHipLine.y1, x2: prevHipLine.x2, y2: prevHipLine.y2, line: prevHipLine }) + baseHipLines.push({ x1: nextHipLine.x1, y1: nextHipLine.y1, x2: nextHipLine.x2, y2: nextHipLine.y2, line: nextHipLine }) + } + }) + /** ⨆ 모양 처마에 추녀마루를 그린다. */ drawEavesFirstLines.forEach((current) => { // 확인용 라인, 포인트 제거 @@ -2942,9 +4666,9 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { let beforePrevLine, afterNextLine /** 이전 라인의 경사 */ - const prevDegree = prevLine.attributes.pitch > 0 ? getDegreeByChon(prevLine.attributes.pitch) : prevLine.attributes.degree + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) /** 다음 라인의 경사 */ - const currentDegree = currentLine.attributes.pitch > 0 ? getDegreeByChon(currentLine.attributes.pitch) : currentLine.attributes.degree + const currentDegree = getDegreeByChon(currentLine.attributes.pitch) /** 이전 라인의 전라인, 다음 라인의 다음라인을 찾는다 */ drawBaseLines.forEach((line, index) => { @@ -2960,8 +4684,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { let prevVector = getHalfAngleVector(prevLine, currentLine) let nextVector = getHalfAngleVector(currentLine, nextLine) - let prevHipVector = { x: Big(prevVector.x), y: Big(prevVector.y) } - let nextHipVector = { x: Big(nextVector.x), y: Big(nextVector.y) } + let prevHipVector = { x: prevVector.x, y: prevVector.y } + let nextHipVector = { x: nextVector.x, y: nextVector.y } /** 각 라인의 흐름 방향을 확인한다. */ const currentAngle = calculateAngle(currentLine.startPoint, currentLine.endPoint) @@ -2979,7 +4703,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: Big(y1).plus(Big(prevHipVector.y).times(10)), } if (!checkWallPolygon.inPolygon(prevCheckPoint)) { - prevHipVector = { x: Big(prevHipVector.x).neg().toNumber(), y: Big(prevHipVector.y).neg().toNumber() } + prevHipVector = { x: -prevHipVector.x, y: -prevHipVector.y } } /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ @@ -2988,12 +4712,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: Big(y2).plus(Big(nextHipVector.y).times(10)), } if (!checkWallPolygon.inPolygon(nextCheckPoint)) { - nextHipVector = { x: Big(nextHipVector.x).neg().toNumber(), y: Big(nextHipVector.y).neg().toNumber() } + nextHipVector = { x: -nextHipVector.x, y: -nextHipVector.y } } /** 현재 라인의 길이를 기준으로 추녀 마루의 길이를 삼각함수를 사용하여 판단한다.*/ let hipLength = currentSize.div(2).pow(2).plus(currentSize.div(2).pow(2)).sqrt() + console.log('hipLength 1 :', hipLength.toNumber()) /** * 현재 라인에서 2번째 전 라인과 2번째 후 라인의 각도가 같을때 -_- 와 같은 형태로 판단하고 * 맞은 편 외벽선까지의 거리를 확인후 currentSize 를 조정한다. @@ -3023,6 +4748,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const intersectionSize = Big(intersection.x) .minus(Big(currentMidX)) .plus(Big(intersection.y).minus(Big(currentMidY))) + .abs() if (intersectionSize.lt(currentSize)) { currentSize = intersectionSize } @@ -3033,12 +4759,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } else { if (currentAngle !== beforePrevAngle && currentAngle !== afterNextAngle && beforePrevLine !== afterNextLine) { const beforePrevX1 = beforePrevLine.x1, - beforePrevY1 = beforePrevLine.y1, - beforePrevX2 = beforePrevLine.x2, - beforePrevY2 = beforePrevLine.y2 - const afterNextX1 = afterNextLine.x1, - afterNextY1 = afterNextLine.y1, - afterNextX2 = afterNextLine.x2, + beforePrevY1 = beforePrevLine.y1 + const afterNextX2 = afterNextLine.x2, afterNextY2 = afterNextLine.y2 /** beforePrevLine 과 afterNextLine 을 연결하는 사각형의 경우 6각으로 판단 */ @@ -3050,7 +4772,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { ).length > 0 /** 6각 */ - // console.log('isConnect :', isConnect) + console.log('isConnect :', isConnect) if (isConnect) { const checkScale = currentSize.pow(2).plus(currentSize.pow(2)).sqrt() const intersectBaseLine = [] @@ -3110,6 +4832,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const rightAngleLine = baseLines .filter( (line) => + line !== currentLine && line !== prevLine && line !== nextLine && (prevAngle === calculateAngle(line.startPoint, line.endPoint) || nextAngle === calculateAngle(line.startPoint, line.endPoint)), @@ -3169,8 +4892,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { checkHipPoints = [ x1, y1, - Big(x1).plus(Big(prevHipVector.x).times(hipLength)).round(2), - Big(y1).plus(Big(prevHipVector.y).times(hipLength)).round(2), + Big(x1).plus(Big(prevHipVector.x).times(hipLength)).round(2).toNumber(), + Big(y1).plus(Big(prevHipVector.y).times(hipLength)).round(2).toNumber(), ] } @@ -3178,8 +4901,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { checkHipPoints = [ x2, y2, - Big(x2).plus(Big(nextHipVector.x).times(hipLength)).round(2), - Big(y2).plus(Big(nextHipVector.y).times(hipLength)).round(2), + Big(x2).plus(Big(nextHipVector.x).times(hipLength)).round(2).toNumber(), + Big(y2).plus(Big(nextHipVector.y).times(hipLength)).round(2).toNumber(), ] } @@ -3200,7 +4923,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { .minus(Big(checkHipPoints[0])) .pow(2) .plus(Big(intersection.y).minus(Big(checkHipPoints[1])).pow(2)) - .sqrt(), + .sqrt() + .toNumber(), }) } }) @@ -3220,20 +4944,20 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { .minus(Big(checkHipPoints[0])) .pow(2) .plus(Big(intersection.y).minus(Big(checkHipPoints[1])).pow(2)) - .sqrt(), + .sqrt() + .toNumber(), }) } }) - const intersection = intersectPoints.reduce((prev, current) => (prev.distance.lt(current.distance) ? prev : current), intersectPoints[0]) - if (intersection) { - hipLength = intersection.distance.div(2) + if (intersectPoints.length > 0) { + const intersection = intersectPoints.sort((a, b) => a.distance - b.distance)[0] + hipLength = getAdjacent(intersection.distance) / 2 } } } } } - let prevHipLine, nextHipLine /** 이전라인과의 연결지점에 추녀마루를 그린다. */ if (baseHipLines.filter((line) => line.x1 === x1 && line.y1 === y1).length === 0) { @@ -3242,6 +4966,44 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: Big(y1).plus(Big(prevHipVector.y).times(hipLength)).round(1), } + if (!roof.inPolygon({ x: prevEndPoint.x.toNumber(), y: prevEndPoint.y.toNumber() })) { + const checkEdge = { vertex1: { x: prevEndPoint.x.toNumber(), y: prevEndPoint.y.toNumber() }, vertex2: { x: x1, y: y1 } } + const intersectionPoints = [] + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection && !intersection.isIntersectionOutside) { + const size = Big(intersection.x) + .minus(Big(prevEndPoint.x)) + .pow(2) + .plus(Big(intersection.y).minus(Big(prevEndPoint.y)).pow(2)) + .sqrt() + .toNumber() + intersectionPoints.push({ intersection, size }) + } + }) + if (intersectionPoints.length > 0) { + const intersection = intersectionPoints.sort((a, b) => a.size - b.size)[0].intersection + prevEndPoint.x = Big(intersection.x) + prevEndPoint.y = Big(intersection.y) + } + } + const overlapLine = baseHipLines.find((line) => isPointOnLine(line, { x: prevEndPoint.x.toNumber(), y: prevEndPoint.y.toNumber() })) + + if (overlapLine) { + if ( + isPointOnLine({ x1: x1, y1: y1, x2: prevEndPoint.x.toNumber(), y2: prevEndPoint.y.toNumber() }, { x: overlapLine.x1, y: overlapLine.y1 }) + ) { + prevEndPoint.x = Big(overlapLine.x1) + prevEndPoint.y = Big(overlapLine.y1) + } + if ( + isPointOnLine({ x1: x1, y1: y1, x2: prevEndPoint.x.toNumber(), y2: prevEndPoint.y.toNumber() }, { x: overlapLine.x2, y: overlapLine.y2 }) + ) { + prevEndPoint.x = Big(overlapLine.x2) + prevEndPoint.y = Big(overlapLine.y2) + } + } const intersectRidgeLine = [] baseRidgeLines.forEach((line) => { const intersection = edgesIntersection( @@ -3328,6 +5090,46 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: Big(y2).plus(Big(nextHipVector.y).times(hipLength)).round(1), } + if (!roof.inPolygon({ x: nextEndPoint.x.toNumber(), y: nextEndPoint.y.toNumber() })) { + const checkEdge = { vertex1: { x: nextEndPoint.x.toNumber(), y: nextEndPoint.y.toNumber() }, vertex2: { x: x2, y: y2 } } + const intersectionPoints = [] + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection && !intersection.isIntersectionOutside) { + const size = Big(intersection.x) + .minus(Big(nextEndPoint.x)) + .pow(2) + .plus(Big(intersection.y).minus(Big(nextEndPoint.y)).pow(2)) + .sqrt() + .toNumber() + intersectionPoints.push({ intersection, size }) + } + }) + if (intersectionPoints.length > 0) { + const intersection = intersectionPoints.sort((a, b) => a.size - b.size)[0].intersection + nextEndPoint.x = Big(intersection.x) + nextEndPoint.y = Big(intersection.y) + } + } + + const overlapLine = baseHipLines.find((line) => isPointOnLine(line, { x: nextEndPoint.x.toNumber(), y: nextEndPoint.y.toNumber() })) + + if (overlapLine) { + if ( + isPointOnLine({ x1: x2, y1: y2, x2: nextEndPoint.x.toNumber(), y2: nextEndPoint.y.toNumber() }, { x: overlapLine.x1, y: overlapLine.y1 }) + ) { + nextEndPoint.x = Big(overlapLine.x1) + nextEndPoint.y = Big(overlapLine.y1) + } + if ( + isPointOnLine({ x1: x2, y1: y2, x2: nextEndPoint.x.toNumber(), y2: nextEndPoint.y.toNumber() }, { x: overlapLine.x2, y: overlapLine.y2 }) + ) { + nextEndPoint.x = Big(overlapLine.x2) + nextEndPoint.y = Big(overlapLine.y2) + } + } + const intersectRidgeLine = [] baseRidgeLines.forEach((line) => { const intersection = edgesIntersection( @@ -3466,181 +5268,234 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const xVector = Big(currentMidX).minus(Big(startPoint.x)).round(0, Big.roundDown) const yVector = Big(currentMidY).minus(Big(startPoint.y)).round(0, Big.roundDown) - - if (gableType.includes(beforePrevLine.line.attributes.type) || gableType.includes(afterNextLine.line.attributes.type)) { - const oppositeLine = gableType.includes(beforePrevLine.line.attributes.type) ? beforePrevLine.line : afterNextLine.line - const oppositeAngle = calculateAngle(oppositeLine.startPoint, oppositeLine.endPoint) - let checkEdge - if (Math.sign(oppositeLine.x1 - oppositeLine.x2) === 0) { - checkEdge = { vertex1: startPoint, vertex2: { x: oppositeLine.x1, y: startPoint.y } } + if (beforePrevLine === afterNextLine) { + console.log('4각 :::::::: ') + const oppositeMidX = Big(beforePrevLine.x2).plus(Big(beforePrevLine.x1)).div(2) + const oppositeMidY = Big(beforePrevLine.y2).plus(Big(beforePrevLine.y1)).div(2) + if (beforePrevLine.line.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + ridgeSize = oppositeMidX + .minus(Big(startPoint.x)) + .abs() + .pow(2) + .plus(oppositeMidY.minus(Big(startPoint.y)).abs().pow(2)) + .sqrt() + .minus(Big(beforePrevLine.line.attributes.planeSize).div(20)) } else { - checkEdge = { vertex1: startPoint, vertex2: { x: startPoint.x, y: oppositeLine.y1 } } - } - if (currentAngle === oppositeAngle) { - const oppositeEdge = { - vertex1: { x: oppositeLine.x1, y: oppositeLine.y1 }, - vertex2: { x: oppositeLine.x2, y: oppositeLine.y2 }, + let width = 0 + if (beforePrevLine.line.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + width = beforePrevLine.line.attributes.width / 2 + } else if (beforePrevLine.line.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + width = beforePrevLine.line.attributes.width } - const intersection = edgesIntersection(oppositeEdge, checkEdge) - if (intersection) { - ridgeSize = Big(intersection.x) + const checkEdge = { vertex1: { x: startPoint.x, y: startPoint.y }, vertex2: { x: oppositeMidX.toNumber(), y: oppositeMidY.toNumber() } } + const vectorX = Math.sign(startPoint.x - oppositeMidX.toNumber()) + const vectorY = Math.sign(startPoint.y - oppositeMidY.toNumber()) + const oppositeRoofPoints = [] + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdge, lineEdge) + if (intersection && Math.sign(startPoint.x - intersection.x) === vectorX && Math.sign(startPoint.y - intersection.y) === vectorY) { + const size = Big(intersection.x) + .minus(Big(startPoint.x)) + .pow(2) + .plus(Big(intersection.y).minus(Big(startPoint.y)).pow(2)) + .sqrt() + .toNumber() + oppositeRoofPoints.push({ intersection, size }) + } + }) + if (oppositeRoofPoints.length > 0) { + const oppositeRoofPoint = oppositeRoofPoints.sort((a, b) => a.size - b.size)[0].intersection + ridgeSize = Big(oppositeRoofPoint.x) .minus(Big(startPoint.x)) + .abs() .pow(2) - .plus(Big(intersection.y).minus(Big(startPoint.y)).pow(2)) + .plus(Big(oppositeRoofPoint.y).minus(Big(startPoint.y)).abs().pow(2)) + .minus(width) .sqrt() } - } else { - const intersectPoints = [] - roof.lines - .filter( - (line) => - Math.sign(oppositeLine.x1 - oppositeLine.x2) === Math.sign(line.x1 - line.x2) && - Math.sign(oppositeLine.y1 - oppositeLine.y2) === Math.sign(line.y1 - line.y2), - ) - .forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const intersection = edgesIntersection(lineEdge, checkEdge) - if (intersection) { - const size = Big(startPoint.x) - .minus(Big(intersection.x)) - .pow(2) - .plus(Big(startPoint.y).minus(Big(intersection.y)).pow(2)) - .sqrt() - .toNumber() - intersectPoints.push({ intersection, size }) - } - }) - intersectPoints.sort((a, b) => a.size - b.size) - if (intersectPoints.length > 0) { - ridgeSize = Big(intersectPoints[0].size) - } } } else { - /** baseLines 에서 가장 작은 x1과 가장 큰 x1, 가장 작은 y1과 가장 큰 y1을 계산*/ - let minX = Infinity - let maxX = -Infinity - let minY = Infinity - let maxY = -Infinity - - baseLines.forEach((line) => { - if (line.x1 < minX) { - minX = line.x1 + if (gableType.includes(beforePrevLine.line.attributes.type) || gableType.includes(afterNextLine.line.attributes.type)) { + const oppositeLine = gableType.includes(beforePrevLine.line.attributes.type) ? beforePrevLine.line : afterNextLine.line + const oppositeAngle = calculateAngle(oppositeLine.startPoint, oppositeLine.endPoint) + let checkEdge + if (Math.sign(oppositeLine.x1 - oppositeLine.x2) === 0) { + checkEdge = { vertex1: startPoint, vertex2: { x: oppositeLine.x1, y: startPoint.y } } + } else { + checkEdge = { vertex1: startPoint, vertex2: { x: startPoint.x, y: oppositeLine.y1 } } } - if (line.x1 > maxX) { - maxX = line.x1 - } - if (line.y1 < minY) { - minY = line.y1 - } - if (line.y1 > maxY) { - maxY = line.y1 - } - }) - const checkLength = Big(maxX) - .minus(Big(minX)) - .pow(2) - .plus(Big(maxY).minus(Big(minY)).pow(2)) - .sqrt() - - const checkEdges = { - vertex1: { x: startPoint.x, y: startPoint.y }, - vertex2: { - x: Big(startPoint.x).minus(checkLength.times(Math.sign(xVector))), - y: Big(startPoint.y).minus(checkLength.times(Math.sign(yVector))), - }, - } - - /** 맞은편 벽 까지의 길이 판단을 위한 교차되는 line*/ - const intersectBaseLine = [] - baseLines - .filter((line) => { - /** currentAngle 의 반대 각도인 라인 */ - const angle = calculateAngle(line.startPoint, line.endPoint) - switch (currentAngle) { - case 90: - return angle === -90 - case -90: - return angle === 90 - case 0: - return angle === 180 - case 180: - return angle === 0 + if (currentAngle === oppositeAngle) { + const oppositeEdge = { + vertex1: { x: oppositeLine.x1, y: oppositeLine.y1 }, + vertex2: { x: oppositeLine.x2, y: oppositeLine.y2 }, } - }) - .filter((line) => { - const currentMinX = Math.min(x1, x2) - const currentMaxX = Math.max(x1, x2) - const currentMinY = Math.min(y1, y2) - const currentMaxY = Math.max(y1, y2) - const lineMinX = Math.min(line.x1, line.x2) - const lineMaxX = Math.max(line.x1, line.x2) - const lineMinY = Math.min(line.y1, line.y2) - const lineMaxY = Math.max(line.y1, line.y2) - - /** currentLine 의 안쪽에 있거나 currentLine이 line의 안쪽에 있는 라인 */ - if (Big(currentLine.y1).minus(Big(currentLine.y2)).abs().lte(1)) { - return ( - (currentMinX <= lineMinX && lineMinX <= currentMaxX) || - (currentMinX <= lineMaxX && lineMaxX <= currentMaxX) || - (lineMinX <= currentMinX && currentMinX <= lineMaxX) || - (lineMinX <= currentMaxX && currentMaxX <= lineMaxX) - ) - } else { - return ( - (currentMinY <= lineMinY && lineMinY <= currentMaxY) || - (currentMinY <= lineMaxY && lineMaxY <= currentMaxY) || - (lineMinY <= currentMinY && currentMinY <= lineMaxY) || - (lineMinY <= currentMaxY && currentMaxY <= lineMaxY) - ) - } - }) - .forEach((line, index) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const intersection = edgesIntersection(checkEdges, lineEdge) + const intersection = edgesIntersection(oppositeEdge, checkEdge) if (intersection) { - intersectBaseLine.push({ intersection, line }) + ridgeSize = Big(intersection.x) + .minus(Big(startPoint.x)) + .pow(2) + .plus(Big(intersection.y).minus(Big(startPoint.y)).pow(2)) + .sqrt() + } + } else { + const intersectPoints = [] + roof.lines + .filter( + (line) => + Math.sign(oppositeLine.x1 - oppositeLine.x2) === Math.sign(line.x1 - line.x2) && + Math.sign(oppositeLine.y1 - oppositeLine.y2) === Math.sign(line.y1 - line.y2), + ) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(lineEdge, checkEdge) + if (intersection) { + const size = Big(startPoint.x) + .minus(Big(intersection.x)) + .pow(2) + .plus(Big(startPoint.y).minus(Big(intersection.y)).pow(2)) + .sqrt() + .toNumber() + intersectPoints.push({ intersection, size }) + } + }) + intersectPoints.sort((a, b) => a.size - b.size) + if (intersectPoints.length > 0) { + ridgeSize = Big(intersectPoints[0].size) + } + } + } else { + /** baseLines 에서 가장 작은 x1과 가장 큰 x1, 가장 작은 y1과 가장 큰 y1을 계산*/ + let minX = Infinity + let maxX = -Infinity + let minY = Infinity + let maxY = -Infinity + + baseLines.forEach((line) => { + if (line.x1 < minX) { + minX = line.x1 + } + if (line.x1 > maxX) { + maxX = line.x1 + } + if (line.y1 < minY) { + minY = line.y1 + } + if (line.y1 > maxY) { + maxY = line.y1 } }) - - /** 맞은편 라인 */ - const oppositeLine = intersectBaseLine.reduce((prev, current) => { - const prevDistance = Big(prev.intersection.x) - .minus(Big(startPoint.x)) + const checkLength = Big(maxX) + .minus(Big(minX)) .pow(2) - .plus(Big(prev.intersection.y).minus(Big(startPoint.y)).pow(2)) + .plus(Big(maxY).minus(Big(minY)).pow(2)) .sqrt() - const currentDistance = Big(current.intersection.x) - .minus(Big(startPoint.x)) - .pow(2) - .plus(Big(current.intersection.y).minus(Big(startPoint.y)).pow(2)) - .sqrt() - return prevDistance < currentDistance ? prev : current - }, intersectBaseLine[0]) - /** 맞은편 라인까지의 길이 = 전체 길이 - 현재라인의 길이 */ - const oppositeSize = oppositeLine - ? Big(oppositeLine.intersection.x) + const checkEdges = { + vertex1: { x: startPoint.x, y: startPoint.y }, + vertex2: { + x: Big(startPoint.x).minus(checkLength.times(Math.sign(xVector))), + y: Big(startPoint.y).minus(checkLength.times(Math.sign(yVector))), + }, + } + + /** 맞은편 벽 까지의 길이 판단을 위한 교차되는 line*/ + const intersectBaseLine = [] + baseLines + .filter((line) => { + /** currentAngle 의 반대 각도인 라인 */ + const angle = calculateAngle(line.startPoint, line.endPoint) + switch (currentAngle) { + case 90: + return angle === -90 + case -90: + return angle === 90 + case 0: + return angle === 180 + case 180: + return angle === 0 + } + }) + .filter((line) => { + const currentMinX = Math.min(x1, x2) + const currentMaxX = Math.max(x1, x2) + const currentMinY = Math.min(y1, y2) + const currentMaxY = Math.max(y1, y2) + const lineMinX = Math.min(line.x1, line.x2) + const lineMaxX = Math.max(line.x1, line.x2) + const lineMinY = Math.min(line.y1, line.y2) + const lineMaxY = Math.max(line.y1, line.y2) + + /** currentLine 의 안쪽에 있거나 currentLine이 line의 안쪽에 있는 라인 */ + if (Big(currentLine.y1).minus(Big(currentLine.y2)).abs().lte(1)) { + return ( + (currentMinX <= lineMinX && lineMinX <= currentMaxX) || + (currentMinX <= lineMaxX && lineMaxX <= currentMaxX) || + (lineMinX <= currentMinX && currentMinX <= lineMaxX) || + (lineMinX <= currentMaxX && currentMaxX <= lineMaxX) + ) + } else { + return ( + (currentMinY <= lineMinY && lineMinY <= currentMaxY) || + (currentMinY <= lineMaxY && lineMaxY <= currentMaxY) || + (lineMinY <= currentMinY && currentMinY <= lineMaxY) || + (lineMinY <= currentMaxY && currentMaxY <= lineMaxY) + ) + } + }) + .forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(checkEdges, lineEdge) + if (intersection) { + intersectBaseLine.push({ intersection, line }) + } + }) + + /** 맞은편 라인 */ + const oppositeLine = intersectBaseLine.reduce((prev, current) => { + const prevDistance = Big(prev.intersection.x) .minus(Big(startPoint.x)) .pow(2) - .plus(Big(oppositeLine.intersection.y).minus(Big(startPoint.y)).pow(2)) + .plus(Big(prev.intersection.y).minus(Big(startPoint.y)).pow(2)) .sqrt() - .minus(currentSize.div(2)) - .round(1) - : Infinity + const currentDistance = Big(current.intersection.x) + .minus(Big(startPoint.x)) + .pow(2) + .plus(Big(current.intersection.y).minus(Big(startPoint.y)).pow(2)) + .sqrt() + return prevDistance < currentDistance ? prev : current + }, intersectBaseLine[0]) - /** 이전, 다음 라인중 길이가 짧은 길이*/ - const lineMinSize = prevBaseLine.size < nextBaseLine.size ? Big(prevBaseLine.size).div(10) : Big(nextBaseLine.size).div(10) + /** 맞은편 라인까지의 길이 = 전체 길이 - 현재라인의 길이 */ + const oppositeSize = oppositeLine + ? Big(oppositeLine.intersection.x) + .minus(Big(startPoint.x)) + .pow(2) + .plus(Big(oppositeLine.intersection.y).minus(Big(startPoint.y)).pow(2)) + .sqrt() + .minus(currentSize.div(2)) + .round(1) + .toNumber() + : Infinity - /** 마루의 길이는 이전 다음 라인중 짧은것의 길이와 현재라인부터 맞은편 라인까지의 길이에서 현재 라인의 길이를 뺀 것중 짧은 길이 */ - ridgeSize = Big(Math.min(oppositeSize, lineMinSize)) + /** 이전, 다음 라인중 길이가 짧은 길이*/ + const lineMinSize = + prevBaseLine.size < nextBaseLine.size ? Big(prevBaseLine.size).div(10).toNumber() : Big(nextBaseLine.size).div(10).toNumber() + /** 마루의 길이는 이전 다음 라인중 짧은것의 길이와 현재라인부터 맞은편 라인까지의 길이에서 현재 라인의 길이를 뺀 것중 짧은 길이 */ + ridgeSize = Big(Math.min(oppositeSize, lineMinSize)) + } } if (ridgeSize.gt(0) && baseRidgeCount < getMaxRidge(baseLines.length)) { const points = [ startPoint.x, startPoint.y, - Big(startPoint.x).minus(ridgeSize.times(Math.sign(xVector))), - Big(startPoint.y).minus(ridgeSize.times(Math.sign(yVector))), + Big(startPoint.x) + .minus(ridgeSize.times(Math.sign(xVector))) + .toNumber(), + Big(startPoint.y) + .minus(ridgeSize.times(Math.sign(yVector))) + .toNumber(), ] /** 동일 라인이 있는지 확인. */ @@ -3694,21 +5549,15 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { if (gableType.includes(beforePrevLine.line.attributes.type) || gableType.includes(afterNextLine.line.attributes.type)) { const oppositeLine = gableType.includes(beforePrevLine.line.attributes.type) ? beforePrevLine.line : afterNextLine.line - const oppositeAngle = calculateAngle(oppositeLine.startPoint, oppositeLine.endPoint) if (Math.sign(ridgeLine.x1 - ridgeLine.x2) === 0) { const gableVector = Math.sign(ridgeLine.x1 - oppositeLine.x1) const prevVector = ridgeLine.x1 === prevHipLine.x1 ? Math.sign(ridgeLine.x1 - prevHipLine.x2) : Math.sign(ridgeLine.x2 - prevHipLine.x1) - const nextVector = ridgeLine.x1 === nextHipLine.x1 ? Math.sign(ridgeLine.x1 - nextHipLine.x2) : Math.sign(ridgeLine.x2 - nextHipLine.x1) const firstHipLine = gableVector === prevVector ? prevHipLine : nextHipLine const firstDegree = gableVector === Math.sign(ridgeLine.x1 - prevLine.x1) - ? prevLine.attributes.pitch > 0 - ? getDegreeByChon(prevLine.attributes.pitch) - : prevLine.attributes.degree - : nextLine.attributes.pitch > 0 - ? getDegreeByChon(nextLine.attributes.pitch) - : nextLine.attributes.degree + ? getDegreeByChon(prevLine.attributes.pitch) + : getDegreeByChon(nextLine.attributes.pitch) const oppositeRoofPoints = [ ridgeLine.x2, @@ -3744,12 +5593,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const secondHipLine = gableVector === prevVector ? nextHipLine : prevHipLine const secondDegree = gableVector === Math.sign(ridgeLine.x1 - prevLine.x1) - ? nextLine.attributes.pitch > 0 - ? getDegreeByChon(nextLine.attributes.pitch) - : nextLine.attributes.degree - : prevLine.attributes.pitch > 0 - ? getDegreeByChon(prevLine.attributes.pitch) - : prevLine.attributes.degree + ? getDegreeByChon(nextLine.attributes.pitch) + : getDegreeByChon(prevLine.attributes.pitch) const intersections = [] const checkEdge = { @@ -3807,18 +5652,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } else { const gableVector = Math.sign(ridgeLine.y1 - oppositeLine.y1) const prevVector = ridgeLine.y1 === prevHipLine.y1 ? Math.sign(ridgeLine.y1 - prevHipLine.y2) : Math.sign(ridgeLine.y1 - prevHipLine.y1) - const nextVector = ridgeLine.y1 === nextHipLine.y1 ? Math.sign(ridgeLine.y1 - nextHipLine.y2) : Math.sign(ridgeLine.y1 - nextHipLine.y1) /** 마루와 박공지붕을 연결하기위한 추녀마루 라인 */ const firstHipLine = gableVector === prevVector ? prevHipLine : nextHipLine const firstDegree = gableVector === Math.sign(ridgeLine.y1 - prevLine.y1) - ? prevLine.attributes.pitch > 0 - ? getDegreeByChon(prevLine.attributes.pitch) - : prevLine.attributes.degree - : nextLine.attributes.pitch > 0 - ? getDegreeByChon(nextLine.attributes.pitch) - : nextLine.attributes.degree + ? getDegreeByChon(prevLine.attributes.pitch) + : getDegreeByChon(nextLine.attributes.pitch) const oppositeRoofPoints = [ ridgeLine.x2, @@ -3855,12 +5695,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const secondHipLine = gableVector === prevVector ? nextHipLine : prevHipLine const secondDegree = gableVector === Math.sign(ridgeLine.y1 - prevLine.y1) - ? nextLine.attributes.pitch > 0 - ? getDegreeByChon(nextLine.attributes.pitch) - : nextLine.attributes.degree - : prevLine.attributes.pitch > 0 - ? getDegreeByChon(prevLine.attributes.pitch) - : prevLine.attributes.degree + ? getDegreeByChon(nextLine.attributes.pitch) + : getDegreeByChon(prevLine.attributes.pitch) const intersections = [] const checkEdge = { @@ -3917,6 +5753,11 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } } } + canvas + .getObjects() + .filter((obj) => obj.name === 'checkLine' || obj.name === 'checkCircle') + .forEach((obj) => canvas.remove(obj)) + canvas.renderAll() }) /** 중복제거 */ @@ -3950,19 +5791,19 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const currentLine = currentBaseLine.line const prevLine = prevBaseLine.line const nextLine = nextBaseLine.line - let { x1, x2, y1, y2, size } = currentBaseLine + let { x1, x2, y1, y2 } = currentBaseLine /** 이전 라인의 경사 */ - const prevDegree = prevLine.attributes.pitch > 0 ? getDegreeByChon(prevLine.attributes.pitch) : prevLine.attributes.degree + const prevDegree = getDegreeByChon(prevLine.attributes.pitch) /** 다음 라인의 경사 */ - const currentDegree = currentLine.attributes.pitch > 0 ? getDegreeByChon(currentLine.attributes.pitch) : currentLine.attributes.degree + const currentDegree = getDegreeByChon(currentLine.attributes.pitch) /** 이전, 다음라인의 사잇각의 vector를 구한다. */ let prevVector = getHalfAngleVector(prevLine, currentLine) let nextVector = getHalfAngleVector(currentLine, nextLine) - let prevHipVector = { x: Big(prevVector.x), y: Big(prevVector.y) } - let nextHipVector = { x: Big(nextVector.x), y: Big(nextVector.y) } + let prevHipVector = { x: prevVector.x, y: prevVector.y } + let nextHipVector = { x: nextVector.x, y: nextVector.y } /** 각 라인의 흐름 방향을 확인한다. */ const currentAngle = calculateAngle(currentLine.startPoint, currentLine.endPoint) @@ -3979,7 +5820,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: Big(y1).plus(Big(prevHipVector.y).times(10)), } if (!checkWallPolygon.inPolygon(prevCheckPoint)) { - prevHipVector = { x: Big(prevHipVector.x).neg(), y: Big(prevHipVector.y).neg() } + prevHipVector = { x: -prevHipVector.x, y: -prevHipVector.y } } /** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ @@ -3988,12 +5829,12 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { y: Big(y2).plus(Big(nextHipVector.y).times(10)), } if (!checkWallPolygon.inPolygon(nextCheckPoint)) { - nextHipVector = { x: Big(nextHipVector.x).neg(), y: Big(nextHipVector.y).neg() } + nextHipVector = { x: -nextHipVector.x, y: -nextHipVector.y } } let prevHipLine, nextHipLine /** 이전라인과의 연결지점에 추녀마루를 그린다. */ - if (baseHipLines.filter((line) => line.x1 === x1 && line.y1 === y1).length === 0 && eavesType.includes(prevLine.attributes.type)) { + if (baseHipLines.filter((line) => line.x1 === x1 && line.y1 === y1).length === 0 && prevLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { let prevEndPoint = { x: Big(x1).plus(Big(prevHipVector.x).times(hipLength)).round(2), y: Big(y1).plus(Big(prevHipVector.y).times(hipLength)).round(2), @@ -4006,16 +5847,16 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { .filter((line) => line !== currentLine && line !== prevLine && line !== nextLine) .filter((line) => { if (currentAngle === 0 || currentAngle === 180) { - return Big(line.y1).minus(Big(y1)).s === nextHipVector.y.s || Big(line.y2).minus(Big(y1)).s === nextHipVector.y.s + return Math.sign(line.y1 - y1) === nextHipVector.y || Math.sign(line.y2 - y1) === nextHipVector.y } else { - return Big(line.x1).minus(Big(x1)).s === nextHipVector.x.s || Big(line.x2).minus(Big(x1)).s === nextHipVector.x.s + return Math.sign(line.x1 - x1) === nextHipVector.x || Math.sign(line.x2 - x1) === nextHipVector.x } }) .forEach((line) => { const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } const intersection = edgesIntersection(prevEndEdge, lineEdge) - if (intersection && Big(intersection.x - x1).s === nextHipVector.x.s && Big(intersection.y - y1).s === nextHipVector.y.s) { + if (intersection && Math.sign(intersection.x - x1) === nextHipVector.x && Math.sign(intersection.y - y1) === nextHipVector.y) { const size = Big(intersection.x - x1) .abs() .pow(2) @@ -4132,7 +5973,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } } /** 다음라인과의 연결지점에 추녀마루를 그린다. */ - if (baseHipLines.filter((line) => line.x1 === x2 && line.y1 === y2).length === 0 && eavesType.includes(nextLine.attributes.type)) { + if (baseHipLines.filter((line) => line.x1 === x2 && line.y1 === y2).length === 0 && nextLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) { let nextEndPoint = { x: Big(x2).plus(Big(nextHipVector.x).times(hipLength)).round(2), y: Big(y2).plus(Big(nextHipVector.y).times(hipLength)).round(2), @@ -4148,16 +5989,16 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { .filter((line) => line !== currentLine && line !== prevLine && line !== nextLine) .filter((line) => { if (currentAngle === 0 || currentAngle === 180) { - return Big(line.y1).minus(Big(y1)).s === nextHipVector.y.s || Big(line.y2).minus(Big(y1)).s === nextHipVector.y.s + return Math.sign(line.y1 - y1) === nextHipVector.y || Math.sign(line.y2 - y1) === nextHipVector.y } else { - return Big(line.x1).minus(Big(x1)).s === nextHipVector.x.s || Big(line.x2).minus(Big(x1)).s === nextHipVector.x.s + return Math.sign(line.x1 - x1) === nextHipVector.x || Math.sign(line.x2 - x1) === nextHipVector.x } }) .forEach((line) => { const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } const intersection = edgesIntersection(nextEndEdge, lineEdge) - if (intersection && Big(intersection.x - x2).s === nextHipVector.x.s && Big(intersection.y - y2).s === nextHipVector.y.s) { + if (intersection && Math.sign(intersection.x - x2) === nextHipVector.x && Math.sign(intersection.y - y2) === nextHipVector.y) { const size = Big(intersection.x - x2) .abs() .pow(2) @@ -4181,15 +6022,24 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { }, intersectBaseLine[0]) if (intersectBase) { + const size = Big(getAdjacent(intersectBase.size)) nextEndPoint = { x: Big(x2) - .plus(Big(nextHipVector.x).times(intersectBase.size.div(2))) + .plus(Big(nextHipVector.x).times(size.div(2))) .round(2), y: Big(y2) - .plus(Big(nextHipVector.y).times(intersectBase.size.div(2))) + .plus(Big(nextHipVector.y).times(size.div(2))) .round(2), } } + const checkLine = new fabric.Line([x2, y2, nextEndPoint.x, nextEndPoint.y], { + stroke: 'red', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + canvas.add(checkLine) + canvas.renderAll() const intersectRidgeLine = [] baseRidgeLines.forEach((line) => { @@ -4198,7 +6048,31 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } }, ) - if (intersection && !intersection.isIntersectionOutside) { + console.log('intersection : ', intersection) + console.log('isPointOnLine(line, intersection)', isPointOnLine(line, intersection)) + console.log( + 'line : ', + (line.x1 <= intersection.x && line.x2 >= intersection.x && line.y1 <= intersection.y && line.y2 >= intersection.y) || + (line.x2 <= intersection.x && line.x1 >= intersection.x && line.y2 <= intersection.y && line.y1 >= intersection.y), + ) + + if (intersection) { + const checkCircle = new fabric.Circle({ + left: intersection.x, + top: intersection.y, + radius: 5, + fill: 'blue', + parentId: roofId, + name: 'checkCircle', + }) + canvas.add(checkCircle) + canvas.renderAll() + } + if ( + intersection && + ((line.x1 <= intersection.x && line.x2 >= intersection.x && line.y1 <= intersection.y && line.y2 >= intersection.y) || + (line.x2 <= intersection.x && line.x1 >= intersection.x && line.y2 <= intersection.y && line.y1 >= intersection.y)) + ) { intersectRidgeLine.push({ intersection, distance: Big(intersection.x) @@ -4209,6 +6083,10 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { }) } }) + + canvas.remove(checkLine) + canvas.renderAll() + const intersectRidge = intersectRidgeLine.reduce((prev, current) => (prev.distance < current.distance ? prev : current), intersectRidgeLine[0]) if (intersectRidge) { @@ -4449,8 +6327,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { .filter((line) => eavesType.includes(line.attributes.type)) .forEach((line) => { const pitch = line.attributes.pitch - const degree = line.attributes.degree - degreeAllLine.push(pitch > 0 ? getDegreeByChon(pitch) : degree) + degreeAllLine.push(getDegreeByChon(pitch)) }) let currentDegree, prevDegree @@ -4519,6 +6396,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { }, ) + const checkPointCnt = checkPoints.filter((point) => point.point.x === checkPoint.point.x && point.point.y === checkPoint.point.y).length const isConnectLine = ((line.line.x1 === point[0] && line.line.y1 === point[1]) || (line.line.x2 === point[0] && line.line.y2 === point[1])) && checkAngel1 === checkAngel2 @@ -4527,7 +6405,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { (point[0] === line.x2 && point[1] === line.y2 && point[2] === line.x1 && point[3] === line.y1) || (point[0] === line.x1 && point[1] === line.y1 && point[2] === line.x2 && point[3] === line.y2) - if (isConnectLine || isOverlap || isSameLine) { + if (checkPointCnt === 1 && (isConnectLine || isOverlap || isSameLine)) { /** 겹치는 추녀마루와 하나의 선으로 변경*/ const mergePoint = [ { x: point[0], y: point[1] }, @@ -4796,18 +6674,16 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { /** 직교 하는 포인트가 없는 경우 남은 포인트 처리 */ const checkEdgeLines = [] noRidgeHipPoints.forEach((current) => { - noRidgeHipPoints.forEach((current) => { - noRidgeHipPoints - .filter((point) => point !== current) - .forEach((point) => { - checkEdgeLines.push( - { vertex1: { x: current.x2, y: current.y2 }, vertex2: { x: current.x2, y: point.y2 } }, - { vertex1: { x: current.x2, y: point.y2 }, vertex2: { x: point.x2, y: point.y2 } }, - { vertex1: { x: point.x2, y: point.y2 }, vertex2: { x: point.x2, y: current.y2 } }, - { vertex1: { x: point.x2, y: current.y2 }, vertex2: { x: current.x2, y: current.y2 } }, - ) - }) - }) + noRidgeHipPoints + .filter((point) => point !== current) + .forEach((point) => { + checkEdgeLines.push( + { vertex1: { x: current.x2, y: current.y2 }, vertex2: { x: current.x2, y: point.y2 } }, + { vertex1: { x: current.x2, y: point.y2 }, vertex2: { x: point.x2, y: point.y2 } }, + { vertex1: { x: point.x2, y: point.y2 }, vertex2: { x: point.x2, y: current.y2 } }, + { vertex1: { x: point.x2, y: current.y2 }, vertex2: { x: current.x2, y: current.y2 } }, + ) + }) }) /** 연결되지 않은 포인트를 찾아서 해당 포인트를 가지고 있는 라인을 찾는다. */ @@ -5084,6 +6960,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const ridgeAllPoints = [] baseRidgeLines.forEach((line) => ridgeAllPoints.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 })) + baseGableRidgeLines.forEach((line) => ridgeAllPoints.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 })) /** hip 중에 지붕의 라인과 만나지 않은 선을 확인.*/ baseHipLines @@ -5451,11 +7328,6 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { }) }) - /** 중복 제거 */ - baseHipLines.forEach((hipLine) => { - baseHipLines.filter((hipLine2) => hipLine !== hipLine2).forEach((hipLine2) => {}) - }) - const innerLines = [...baseRidgeLines, ...baseGableRidgeLines, ...baseGableLines, ...baseHipLines.map((line) => line.line)] const uniqueInnerLines = [] @@ -5480,7 +7352,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { canvas.renderAll() roof.innerLines = uniqueInnerLines - // modifyRidge(roof, canvas, textMode) + /** 확인용 라인 제거 */ + canvas + .getObjects() + .filter((obj) => obj.name === 'checkCircle' || obj.name === 'checkLine') + .forEach((obj) => canvas.remove(obj)) + canvas.renderAll() + /* drawCenterLine(roof, canvas, textMode) */ @@ -5497,6 +7375,21 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { * @param currentDegree */ const drawHipLine = (points, canvas, roof, textMode, currentRoof, prevDegree, currentDegree) => { + /** 대각선인 경우 경사를 조정해서 계산*/ + const baseX = Big(points[0]).minus(Big(points[2])).abs() + const baseY = Big(points[1]).minus(Big(points[3])).abs() + if (baseX.gt(1) && baseY.gt(1)) { + const base = calcLinePlaneSize({ x1: points[0], y1: points[1], x2: points[2], y2: points[3] }) / 10 + const heightX = baseX.times(Math.tan((currentDegree * Math.PI) / 180)).round() + const heightY = baseY.times(Math.tan((prevDegree * Math.PI) / 180)).round() + const degreeX = Math.atan(heightX.div(base).toNumber()) / (Math.PI / 180) + const degreeY = Math.atan(heightY.div(base).toNumber()) / (Math.PI / 180) + if (Math.abs(degreeX - degreeY) < 1) { + currentDegree = degreeX + prevDegree = degreeY + } + } + const hip = new QLine(points, { parentId: roof.id, fontSize: roof.fontSize, @@ -5667,7 +7560,7 @@ const normalizeVector = (v) => { /** 벡터의 크기(길이)*/ const magnitude = Big(v.x).pow(2).plus(Big(v.y).pow(2)).sqrt() if (magnitude.eq(0)) return { x: 0, y: 0 } // 크기가 0일 경우 (예외 처리) - return { x: Big(v.x).div(magnitude).toNumber(), y: Big(v.y).div(magnitude).toNumber() } + return { x: Math.sign(Big(v.x).div(magnitude).toNumber()), y: Math.sign(Big(v.y).div(magnitude).toNumber()) } } /** @@ -5721,1593 +7614,16 @@ export const segmentsOverlap = (line1, line2) => { } /** - * 외벽선 속성에 따라서 모양을 수정한다. - * @param roof - * @param canvas - * @param textMode - */ -const modifyRidge = (roof, canvas, textMode) => { - const ridgeLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.RIDGE && object.attributes.roofId === roof.id) - const hipLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.HIP && object.attributes.roofId === roof.id) - - ridgeLines.forEach((ridge) => { - let ridgeHip1 = hipLines.filter((hip) => hip.x2 === ridge.x1 && hip.y2 === ridge.y1) - let ridgeHip2 = hipLines.filter((hip) => hip.x2 === ridge.x2 && hip.y2 === ridge.y2) - if (ridgeHip1.length >= 2) { - let currentRoof = roof.lines - .filter((roofLine) => roofLine.attributes !== undefined && roofLine.attributes.ridgeCoordinate !== undefined) - .find((roofLine) => roofLine.attributes.ridgeCoordinate.x1 === ridge.x1 && roofLine.attributes.ridgeCoordinate.y1 === ridge.y1) - if (currentRoof === undefined) { - currentRoof = roof.lines.find( - (roofLine) => - (roofLine.x1 === ridgeHip1[0].x1 && - roofLine.y1 === ridgeHip1[0].y1 && - roofLine.x2 === ridgeHip1[1].x1 && - roofLine.y2 === ridgeHip1[1].y1) || - (roofLine.x1 === ridgeHip1[1].x1 && - roofLine.y1 === ridgeHip1[1].y1 && - roofLine.x2 === ridgeHip1[0].x1 && - roofLine.y2 === ridgeHip1[0].y1), - ) - if (currentRoof !== undefined) { - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } - } - } - if (currentRoof !== undefined) { - switch (currentRoof.attributes.type) { - case LINE_TYPE.WALLLINE.EAVES: - changeEavesRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.GABLE: - changeGableRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.HIPANDGABLE: - changeHipAndGableRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.JERKINHEAD: - changeJerkInHeadRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.WALL: - changeWallRoof(currentRoof, canvas, textMode) - break - } - } - } - if (ridgeHip2.length >= 2) { - let currentRoof = roof.lines - .filter((roofLine) => roofLine.attributes !== undefined && roofLine.attributes.ridgeCoordinate !== undefined) - .find((roofLine) => roofLine.attributes.ridgeCoordinate.x1 === ridge.x2 && roofLine.attributes.ridgeCoordinate.y1 === ridge.y2) - if (currentRoof === undefined) { - currentRoof = roof.lines.find( - (roofLine) => - (roofLine.x1 === ridgeHip2[0].x1 && - roofLine.y1 === ridgeHip2[0].y1 && - roofLine.x2 === ridgeHip2[1].x1 && - roofLine.y2 === ridgeHip2[1].y1) || - (roofLine.x1 === ridgeHip2[1].x1 && - roofLine.y1 === ridgeHip2[1].y1 && - roofLine.x2 === ridgeHip2[0].x1 && - roofLine.y2 === ridgeHip2[0].y1), - ) - if (currentRoof !== undefined) { - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } - } - } - if (currentRoof !== undefined) { - switch (currentRoof.attributes.type) { - case LINE_TYPE.WALLLINE.EAVES: - changeEavesRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.GABLE: - changeGableRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.HIPANDGABLE: - changeHipAndGableRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.JERKINHEAD: - changeJerkInHeadRoof(currentRoof, canvas, textMode) - break - case LINE_TYPE.WALLLINE.WALL: - changeWallRoof(currentRoof, canvas, textMode) - break - } - } - } - }) -} - -/* - 최대 생성 마루 갯수 + * 최대 생성 마루 갯수 + * @param length + * @returns {number} */ const getMaxRidge = (length) => { return (length - 4) / 2 + 1 } /** - * 처마지붕으로 변경 - * @param currentRoof - * @param canvas - * @param textMode - */ -const changeEavesRoof = (currentRoof, canvas, textMode) => { - if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES) { - const roofId = currentRoof.attributes.roofId - const wall = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roofId) - const roof = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.ROOF && object.id === roofId) - let hipLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.HIP && object.attributes.roofId === roofId) - let ridgeLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.RIDGE && object.attributes.roofId === roofId) - let wallLine = wall.lines.filter((w) => w.id === currentRoof.attributes.wallLine) - if (wallLine.length > 0) { - wallLine = wallLine[0] - } - let prevRoof, nextRoof - roof.lines.forEach((r, index) => { - if (r.id === currentRoof.id) { - currentRoof = r - prevRoof = roof.lines[index === 0 ? roof.lines.length - 1 : index - 1] - nextRoof = roof.lines[index === roof.lines.length - 1 ? 0 : index + 1] - } - }) - - const midX = Big(currentRoof.x1).plus(Big(currentRoof.x2)).div(2) // 지붕의 X 중심 - const midY = Big(currentRoof.y1).plus(Big(currentRoof.y2)).div(2) // 지붕의 Y 중심 - const midWallX = Big(wallLine.x1).plus(Big(wallLine.x2)).div(2) - const midWallY = Big(wallLine.y1).plus(Big(wallLine.y2)).div(2) // 벽의 Y 중심 - const alpha = midX.minus(midWallX) // 벽과 지붕의 X 거리 - const beta = midY.minus(midWallY) // 벽과 지붕의 Y 거리 - const hypotenuse = alpha.pow(2).plus(beta.pow(2)).sqrt() // 벽과 지붕의 거리 - const hipX2 = midX.plus(alpha.div(hypotenuse).times(Big(currentRoof.length).div(2)).neg()) - const hipY2 = midY.plus(beta.div(hypotenuse).times(Big(currentRoof.length).div(2)).neg()) - - const innerLines = canvas - ?.getObjects() - .filter( - (object) => - object.attributes?.roofId === roofId && - object.attributes?.currentRoofId === currentRoof.id && - object.x1 !== undefined && - object.x2 !== undefined, - ) - - innerLines - .filter( - (line) => - line.name !== LINE_TYPE.SUBLINE.RIDGE && - line.name !== LINE_TYPE.SUBLINE.HIP && - line.name !== LINE_TYPE.SUBLINE.VALLEY && - line.name !== OUTER_LINE_TYPE.OUTER_LINE && - line.name !== 'wallLine', - ) - .forEach((line) => { - roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) - canvas?.remove(line) - }) - - ridgeLines = ridgeLines.filter( - (ridge) => - (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || - (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), - ) - hipLines = hipLines.filter( - (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), - ) - - if (hipLines === undefined || hipLines.length === 0) { - hipLines = innerLines.filter( - (line) => - (line.x1 === currentRoof.x1 && line.y1 === currentRoof.y1) || - (line.x2 === currentRoof.x1 && line.y2 === currentRoof.y1) || - (line.x1 === currentRoof.x2 && line.y1 === currentRoof.y2) || - (line.x2 === currentRoof.x2 && line.y2 === currentRoof.y2), - ) - } - - if ((ridgeLines === undefined || ridgeLines.length === 0) && hipLines.length >= 2) { - let points = [] - hipLines.forEach((hip) => { - points.push({ x: hip.x1, y: hip.y1 }) - points.push({ x: hip.x2, y: hip.y2 }) - }) - - const pointSet = new Set() - const duplicatePoints = [] - - points.forEach((point) => { - const pointKey = `${point.x},${point.y}` - if (pointSet.has(pointKey)) { - duplicatePoints.push(point) - } else { - pointSet.add(pointKey) - } - }) - - ridgeLines = innerLines - .filter((r) => r !== hipLines[0] && r !== hipLines[1]) - .filter( - (r) => (r.x1 === duplicatePoints[0].x && r.y1 === duplicatePoints[0].y) || (r.x2 === duplicatePoints[0].x && r.y2 === duplicatePoints[0].y), - ) - if (ridgeLines.length > 0) { - currentRoof.attributes.ridgeCoordinate = { x1: duplicatePoints[0].x, y1: duplicatePoints[0].y } - } - } - - if (ridgeLines.length > 0) { - const ridge = ridgeLines[0] - if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { - ridge.set({ - x1: hipX2.toNumber(), - y1: hipY2.toNumber(), - x2: ridge.x2, - y2: ridge.y2, - }) - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } - } - if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { - ridge.set({ - x1: ridge.x1, - y1: ridge.y1, - x2: hipX2.toNumber(), - y2: hipY2.toNumber(), - }) - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } - } - //Math.round(Math.sqrt(Math.pow(ridge.x1 - ridge.x2, 2) + Math.pow(ridge.y1 - ridge.y2, 2)) * 10) - ridge.attributes.planeSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - ridge.attributes.actualSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - } - - hipLines.forEach((hip) => { - roof.innerLines = roof.innerLines.filter((h) => h.id !== hip.id) - canvas.remove(hip) - }) - - canvas?.renderAll() - - const prevDegree = prevRoof.attributes.pitch > 0 ? getDegreeByChon(prevRoof.attributes.pitch) : prevRoof.attributes.degree - const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree - const nextDegree = nextRoof.attributes.pitch > 0 ? getDegreeByChon(nextRoof.attributes.pitch) : nextRoof.attributes.degree - - const hip1 = new QLine([currentRoof.x1, currentRoof.y1, hipX2.toNumber(), hipY2.toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: hipX2.toNumber(), - y2: hipY2.toNumber(), - }), - actualSize: - prevDegree === currentDegree - ? calcLineActualSize( - { - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: hipX2.toNumber(), - y2: hipY2.toNumber(), - }, - currentDegree, - ) - : 0, - }, - }) - const hip1Base = ((Math.abs(hip1.x1 - hip1.x2) + Math.abs(hip1.y1 - hip1.y2)) / 2) * 10 - const hip1Height = Math.round(hip1Base / Math.tan(((90 - currentDegree) * Math.PI) / 180)) - canvas?.add(hip1) - roof.innerLines.push(hip1) - - const hip2 = new QLine([currentRoof.x2, currentRoof.y2, hipX2.toNumber(), hipY2.toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: hipX2.toNumber(), - y2: hipY2.toNumber(), - }), - actualSize: - currentDegree === nextDegree - ? calcLineActualSize( - { - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: hipX2.toNumber(), - y2: hipY2.toNumber(), - }, - currentDegree, - ) - : 0, - }, - }) - canvas?.add(hip2) - roof.innerLines.push(hip2) - } -} - -/** - * 박공지붕으로 변경 - * @param currentRoof - * @param canvas - * @param textMode - */ -const changeGableRoof = (currentRoof, canvas, textMode) => { - if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.GABLE) { - const roofId = currentRoof.attributes.roofId - const roof = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.ROOF && object.id === roofId) - let hipLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.HIP && object.attributes.roofId === roofId) - let ridgeLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.RIDGE && object.attributes.roofId === roofId) - - const midX = Big(currentRoof.x1).plus(Big(currentRoof.x2)).div(2) // 지붕의 X 중심 - const midY = Big(currentRoof.y1).plus(Big(currentRoof.y2)).div(2) // 지붕의 Y 중심 - - const innerLines = canvas - ?.getObjects() - .filter( - (object) => - object.attributes?.roofId === roofId && - object.attributes?.currentRoofId === currentRoof.id && - object.x1 !== undefined && - object.x2 !== undefined, - ) - - let prevRoof, nextRoof - roof.lines.forEach((r, index) => { - if (r.id === currentRoof.id) { - currentRoof = r - prevRoof = roof.lines[index === 0 ? roof.lines.length - 1 : index - 1] - nextRoof = roof.lines[index === roof.lines.length - 1 ? 0 : index + 1] - } - }) - - innerLines - .filter( - (line) => - line.name !== LINE_TYPE.SUBLINE.RIDGE && - line.name !== LINE_TYPE.SUBLINE.HIP && - line.name !== LINE_TYPE.SUBLINE.VALLEY && - line.name !== OUTER_LINE_TYPE.OUTER_LINE && - line.name !== 'wallLine', - ) - .forEach((line) => { - roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) - canvas?.remove(line) - }) - canvas.renderAll() - - ridgeLines = ridgeLines.filter( - (ridge) => - (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || - (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), - ) - hipLines = hipLines.filter( - (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), - ) - - if (hipLines === undefined || hipLines.length === 0) { - hipLines = innerLines.filter( - (line) => - (line.x1 === currentRoof.x1 && line.y1 === currentRoof.y1) || - (line.x2 === currentRoof.x1 && line.y2 === currentRoof.y1) || - (line.x1 === currentRoof.x2 && line.y1 === currentRoof.y2) || - (line.x2 === currentRoof.x2 && line.y2 === currentRoof.y2), - ) - } - - hipLines.forEach((hip) => { - roof.innerLines = roof.innerLines.filter((h) => h.id !== hip.id) - canvas.remove(hip) - }) - - if ((ridgeLines === undefined || ridgeLines.length === 0) && hipLines.length >= 2) { - let points = [] - hipLines.forEach((hip) => { - points.push({ x: hip.x1, y: hip.y1 }) - points.push({ x: hip.x2, y: hip.y2 }) - }) - - const pointSet = new Set() - const duplicatePoints = [] - - points.forEach((point) => { - const pointKey = `${point.x},${point.y}` - if (pointSet.has(pointKey)) { - duplicatePoints.push(point) - } else { - pointSet.add(pointKey) - } - }) - - ridgeLines = innerLines - .filter((r) => r !== hipLines[0] && r !== hipLines[1]) - .filter( - (r) => (r.x1 === duplicatePoints[0].x && r.y1 === duplicatePoints[0].y) || (r.x2 === duplicatePoints[0].x && r.y2 === duplicatePoints[0].y), - ) - if (ridgeLines.length > 0) { - currentRoof.attributes.ridgeCoordinate = { x1: duplicatePoints[0].x, y1: duplicatePoints[0].y } - } - } - - if (ridgeLines !== undefined && ridgeLines.length > 0) { - const prevDegree = prevRoof.attributes.pitch > 0 ? getDegreeByChon(prevRoof.attributes.pitch) : prevRoof.attributes.degree - const nextDegree = nextRoof.attributes.pitch > 0 ? getDegreeByChon(nextRoof.attributes.pitch) : nextRoof.attributes.degree - - const ridge = ridgeLines[0] - if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { - ridge.set({ - x1: midX.toNumber(), - y1: midY.toNumber(), - x2: ridge.x2, - y2: ridge.y2, - }) - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } - } - if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { - ridge.set({ - x1: ridge.x1, - y1: ridge.y1, - x2: midX.toNumber(), - y2: midY.toNumber(), - }) - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } - } - ridge.attributes.planeSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - ridge.attributes.actualSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - - let hip1 = new QLine([currentRoof.x1, currentRoof.y1, midX.toNumber(), midY.toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - attributes: { - roofId: roofId, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: midX.toNumber(), - y2: midY.toNumber(), - }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: midX.toNumber(), - y2: midY.toNumber(), - }, - prevDegree, - ), - }, - }) - canvas?.add(hip1) - // const hip1Base = ((Math.abs(hip1.x1 - hip1.x2) + Math.abs(hip1.y1 - hip1.y2)) / 2) * 10 - // const hip1Height = Math.round(hip1Base / Math.tan(((90 - prevDegree) * Math.PI) / 180)) - // hip1.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip1.x1 - hip1.x2, 2) + Math.pow(hip1.y1 - hip1.y2, 2))) * 10 - // hip1.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip1.attributes.planeSize, 2) + Math.pow(hip1Height, 2))) - roof.innerLines.push(hip1) - - let hip2 = new QLine([currentRoof.x2, currentRoof.y2, midX.toNumber(), midY.toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - attributes: { - roofId: roofId, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: midX.toNumber(), - y2: midY.toNumber(), - }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: midX.toNumber(), - y2: midY.toNumber(), - }, - nextDegree, - ), - }, - }) - canvas?.add(hip2) - // const hip2Base = ((Math.abs(hip2.x1 - hip2.x2) + Math.abs(hip2.y1 - hip2.y2)) / 2) * 10 - // const hip2Height = Math.round(hip2Base / Math.tan(((90 - nextDegree) * Math.PI) / 180)) - // hip2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip2.x1 - hip2.x2, 2) + Math.pow(hip2.y1 - hip2.y2, 2))) * 10 - // hip2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip2.attributes.planeSize, 2) + Math.pow(hip2Height, 2))) - roof.innerLines.push(hip2) - canvas?.renderAll() - } - } -} - -/** - * 팔작지붕으로 변경 - * @param currentRoof - * @param canvas - * @param textMode - */ -const changeHipAndGableRoof = (currentRoof, canvas, textMode) => { - if ( - currentRoof.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE && - currentRoof.attributes.width !== undefined && - currentRoof.attributes.width > 0 - ) { - const roofId = currentRoof.attributes.roofId - const wall = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roofId) - const roof = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.ROOF && object.id === roofId) - let hipLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.HIP && object.attributes.roofId === roofId) - let ridgeLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.RIDGE && object.attributes.roofId === roofId) - let wallLine = wall.lines.filter((w) => w.id === currentRoof.attributes.wallLine) - if (wallLine.length > 0) { - wallLine = wallLine[0] - } - let prevRoof, nextRoof - roof.lines.forEach((r, index) => { - if (r.id === currentRoof.id) { - currentRoof = r - prevRoof = roof.lines[index === 0 ? roof.lines.length - 1 : index - 1] - nextRoof = roof.lines[index === roof.lines.length - 1 ? 0 : index + 1] - } - }) - - const midX = Big(currentRoof.x1).plus(Big(currentRoof.x2)).div(2) // 지붕의 X 중심 - const midY = Big(currentRoof.y1).plus(Big(currentRoof.y2)).div(2) // 지붕의 Y 중심 - const midWallX = Big(wallLine.x1).plus(Big(wallLine.x2)).div(2) // 벽의 X 중심 - const midWallY = Big(wallLine.y1).plus(Big(wallLine.y2)).div(2) // 벽의 Y 중심 - const alpha = midX.minus(midWallX) // 벽과 지붕의 X 거리 - const beta = midY.minus(midWallY) // 벽과 지붕의 Y 거리 - // Math.sqrt(Math.pow(alpha, 2) + Math.pow(beta, 2)) - const hypotenuse = alpha.pow(2).plus(beta.pow(2)).sqrt() // 벽과 지붕의 거리 - const xWidth = Big(Math.sign(midX.minus(midWallX).toNumber())) - .times(alpha.div(hypotenuse)) - .times(currentRoof.attributes.width) // 지붕의 X 너비 - const yWidth = Big(Math.sign(midY.minus(midWallY))) - .times(beta.div(hypotenuse)) - .times(currentRoof.attributes.width) // 지붕의 Y 너비 - const hipX2 = Big(Math.sign(midX.minus(midWallX).toNumber())) - .times(alpha.div(hypotenuse)) - .times(currentRoof.length / 2) // 추녀마루의 X 너비 - const hipY2 = Big(Math.sign(midY.minus(midWallY))) - .times(beta.div(hypotenuse)) - .times(currentRoof.length / 2) // 추녀마루의 Y 너비 - - // if (Math.sqrt(Math.pow(xWidth, 2) + Math.pow(yWidth, 2)) < Math.sqrt(Math.pow(hipX2, 2) + Math.pow(hipY2, 2))) { - if ( - xWidth - .pow(2) - .plus(yWidth.pow(2)) - .sqrt() - .lt(hipX2.pow(2).plus(hipY2.pow(2)).sqrt()) - ) { - const innerLines = canvas - ?.getObjects() - .filter( - (object) => - object.attributes?.roofId === roofId && - object.attributes?.currentRoofId === currentRoof.id && - object.x1 !== undefined && - object.x2 !== undefined, - ) - - innerLines - .filter( - (line) => - line.name !== LINE_TYPE.SUBLINE.RIDGE && - line.name !== LINE_TYPE.SUBLINE.HIP && - line.name !== LINE_TYPE.SUBLINE.VALLEY && - line.name !== OUTER_LINE_TYPE.OUTER_LINE && - line.name !== 'wallLine', - ) - .forEach((line) => { - roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) - canvas?.remove(line) - }) - - ridgeLines = ridgeLines.filter( - (ridge) => - (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || - (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), - ) - hipLines = hipLines.filter( - (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), - ) - - if (hipLines === undefined || hipLines.length === 0) { - hipLines = innerLines.filter( - (line) => - (line.x1 === currentRoof.x1 && line.y1 === currentRoof.y1) || - (line.x2 === currentRoof.x1 && line.y2 === currentRoof.y1) || - (line.x1 === currentRoof.x2 && line.y1 === currentRoof.y2) || - (line.x2 === currentRoof.x2 && line.y2 === currentRoof.y2), - ) - } - - if ((ridgeLines === undefined || ridgeLines.length === 0) && hipLines.length >= 2) { - let points = [] - hipLines.forEach((hip) => { - points.push({ x: hip.x1, y: hip.y1 }) - points.push({ x: hip.x2, y: hip.y2 }) - }) - - const pointSet = new Set() - const duplicatePoints = [] - - points.forEach((point) => { - const pointKey = `${point.x},${point.y}` - if (pointSet.has(pointKey)) { - duplicatePoints.push(point) - } else { - pointSet.add(pointKey) - } - }) - - ridgeLines = innerLines - .filter((r) => r !== hipLines[0] && r !== hipLines[1]) - .filter( - (r) => - (r.x1 === duplicatePoints[0].x && r.y1 === duplicatePoints[0].y) || (r.x2 === duplicatePoints[0].x && r.y2 === duplicatePoints[0].y), - ) - if (ridgeLines.length > 0) { - currentRoof.attributes.ridgeCoordinate = { x1: duplicatePoints[0].x, y1: duplicatePoints[0].y } - } - } - - hipLines.forEach((hip) => { - roof.innerLines = roof.innerLines.filter((h) => h.id !== hip.id) - canvas.remove(hip) - }) - hipLines = [] - - if (ridgeLines.length > 0) { - const ridge = ridgeLines[0] - if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { - const signX = Math.sign(midX.minus(ridge.x1).toNumber()) - const signY = Math.sign(midY.minus(ridge.y1).toNumber()) - ridge.set({ - x1: midX.minus(xWidth.abs().times(signX)).toNumber(), - y1: midY.minus(yWidth.abs().times(signY)).toNumber(), - x2: ridge.x2, - y2: ridge.y2, - }) - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } - } - if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { - const signX = Math.sign(midX.minus(ridge.x2).toNumber()) - const signY = Math.sign(midY.minus(ridge.y2).toNumber()) - ridge.set({ - x1: ridge.x1, - y1: ridge.y1, - x2: midX.minus(xWidth.abs().times(signX)).toNumber(), - y2: midY.minus(yWidth.abs().times(signY)).toNumber(), - }) - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } - } - ridge.attributes.planeSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - ridge.attributes.actualSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - } - - const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree - - const hip1 = new QLine([currentRoof.x1, currentRoof.y1, midX.plus(hipX2).toNumber(), midY.plus(hipY2).toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: midX.plus(hipX2).toNumber(), - y2: midY.plus(hipY2).toNumber(), - }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: midX.plus(hipX2).toNumber(), - y2: midY.plus(hipY2).toNumber(), - }, - currentDegree, - ), - }, - }) - - // const hip1Base = ((Math.abs(hip1.x1 - hip1.x2) + Math.abs(hip1.y1 - hip1.y2)) / 2) * 10 - // const hip1Height = Math.round(hip1Base / Math.tan(((90 - prevDegree) * Math.PI) / 180)) - // hip1.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip1.x1 - hip1.x2, 2) + Math.pow(hip1.y1 - hip1.y2, 2))) * 10 - // hip1.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip1.attributes.planeSize, 2) + Math.pow(hip1Height, 2))) - canvas?.add(hip1) - roof.innerLines.push(hip1) - - const hip2 = new QLine([currentRoof.x2, currentRoof.y2, midX.plus(hipX2).toNumber(), midY.plus(hipY2).toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: midX.plus(hipX2).toNumber(), - y2: midY.plus(hipY2).toNumber(), - }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: midX.plus(hipX2).toNumber(), - y2: midY.plus(hipY2).toNumber(), - }, - currentDegree, - ), - }, - }) - // const hip2Base = ((Math.abs(hip2.x1 - hip2.x2) + Math.abs(hip2.y1 - hip2.y2)) / 2) * 10 - // const hip2Height = Math.round(hip2Base / Math.tan(((90 - nextDegree) * Math.PI) / 180)) - // hip2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip2.x1 - hip2.x2, 2) + Math.pow(hip2.y1 - hip2.y2, 2))) * 10 - // hip2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip2.attributes.planeSize, 2) + Math.pow(hip2Height, 2))) - canvas?.add(hip2) - roof.innerLines.push(hip2) - - hipLines.push(hip1) - hipLines.push(hip2) - - hipLines.forEach((hip) => { - const singHipX = Math.sign(hip.x1 - midWallX.toNumber()) - const singHipY = Math.sign(hip.y1 - midWallY.toNumber()) - - hip.set({ - x1: hip.x1, - y1: hip.y1, - x2: hip.x1 - singHipX * currentRoof.attributes.width, - y2: hip.y1 - singHipY * currentRoof.attributes.width, - }) - }) - - hipLines.forEach((hip, i) => { - const gableLine = new QLine([hip.x2, hip.y2, currentRoof.attributes.ridgeCoordinate.x1, currentRoof.attributes.ridgeCoordinate.y1], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.GABLE, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - textMode: textMode, - planeSize: calcLinePlaneSize({ - x1: hip.x2, - y1: hip.y2, - x2: currentRoof.attributes.ridgeCoordinate.x1, - y2: currentRoof.attributes.ridgeCoordinate.y1, - }), - actualSize: calcLineActualSize( - { - x1: hip.x2, - y1: hip.y2, - x2: currentRoof.attributes.ridgeCoordinate.x1, - y2: currentRoof.attributes.ridgeCoordinate.y1, - }, - currentDegree, - ), - }, - }) - - // const gableBase = ((Math.abs(gableLine.x1 - gableLine.x2) + Math.abs(gableLine.y1 - gableLine.y2)) / 2) * 10 - // const gableHeight = Math.round(gableBase / Math.tan(((90 - gableDegree) * Math.PI) / 180)) - // gableLine.attributes.planeSize = - // Math.round(Math.sqrt(Math.pow(gableLine.x1 - gableLine.x2, 2) + Math.pow(gableLine.y1 - gableLine.y2, 2))) * 10 - // gableLine.attributes.actualSize = Math.round(Math.sqrt(Math.pow(gableLine.attributes.planeSize, 2) + Math.pow(gableHeight, 2))) - canvas?.add(gableLine) - roof.innerLines.push(gableLine) - }) - } - } - canvas?.renderAll() -} - -/** - * 반절처 지붕으로 변경 - * @param currentRoof - * @param canvas - * @param textMode - */ -const changeJerkInHeadRoof = (currentRoof, canvas, textMode) => { - if ( - currentRoof.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD && - currentRoof.attributes.width !== undefined && - currentRoof.attributes.width > 0 - ) { - const roofId = currentRoof.attributes.roofId - const wall = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roofId) - const roof = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.ROOF && object.id === roofId) - let hipLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.HIP && object.attributes.roofId === roofId) - let ridgeLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.RIDGE && object.attributes.roofId === roofId) - let wallLine = wall.lines.filter((w) => w.id === currentRoof.attributes.wallLine) - if (wallLine.length > 0) { - wallLine = wallLine[0] - } - - let prevRoof, nextRoof - roof.lines.forEach((r, index) => { - if (r.id === currentRoof.id) { - currentRoof = r - prevRoof = roof.lines[index === 0 ? roof.lines.length - 1 : index - 1] - nextRoof = roof.lines[index === roof.lines.length - 1 ? 0 : index + 1] - } - }) - - const prevDegree = prevRoof.attributes.pitch > 0 ? getDegreeByChon(prevRoof.attributes.pitch) : prevRoof.attributes.degree - const nextDegree = nextRoof.attributes.pitch > 0 ? getDegreeByChon(nextRoof.attributes.pitch) : nextRoof.attributes.degree - - const midX = Big(currentRoof.x1).plus(Big(currentRoof.x2)).div(2) // 지붕의 X 중심 - const midY = Big(currentRoof.y1).plus(Big(currentRoof.y2)).div(2) // 지붕의 Y 중심 - const midWallX = Big(wallLine.x1).plus(Big(wallLine.x2)).div(2) // 벽의 X 중심 - const midWallY = Big(wallLine.y1).plus(Big(wallLine.y2)).div(2) // 벽의 Y 중심 - const alpha = midX.minus(midWallX) // 벽과 지붕의 X 거리 - const beta = midY.minus(midWallY) // 벽과 지붕의 Y 거리 - // Math.sqrt(Math.pow(alpha, 2) + Math.pow(beta, 2)) - const hypotenuse = alpha.pow(2).plus(beta.pow(2)).sqrt() // 벽과 지붕의 거리 - const xWidth = Big(Math.sign(midX.minus(midWallX).toNumber())) - .times(alpha.div(hypotenuse)) - .times(currentRoof.attributes.width / 2) // 지붕의 X 너비 - const yWidth = Big(Math.sign(midY.minus(midWallY))) - .times(beta.div(hypotenuse)) - .times(currentRoof.attributes.width / 2) // 지붕의 Y 너비 - const addHipX2 = Big(Math.sign(midX.minus(midWallX).toNumber())) - .times(alpha.div(hypotenuse)) - .times(currentRoof.length / 2) // 추녀마루의 X 너비 - const addHipY2 = Big(Math.sign(midY.minus(midWallY))) - .times(beta.div(hypotenuse)) - .times(currentRoof.length / 2) // 추녀마루의 Y 너비 - let hipX2 = 0 - let hipY2 = 0 - - // if (Math.sqrt(Math.pow(xWidth, 2) + Math.pow(yWidth, 2)) < Math.sqrt(Math.pow(addHipX2, 2) + Math.pow(addHipY2, 2))) { - if ( - xWidth - .pow(2) - .plus(yWidth.pow(2)) - .lt(addHipX2.pow(2).plus(addHipY2.pow(2))) - ) { - // reDrawPolygon(roof, canvas) - - const innerLines = canvas - ?.getObjects() - .filter( - (object) => - object.attributes !== undefined && - object.attributes.roofId === roofId && - object.attributes.currentRoofId === currentRoof.id && - object.x1 !== undefined && - object.x2 !== undefined, - ) - - innerLines - .filter( - (line) => - line.name !== LINE_TYPE.SUBLINE.RIDGE && - line.name !== LINE_TYPE.SUBLINE.HIP && - line.name !== LINE_TYPE.SUBLINE.VALLEY && - line.name !== OUTER_LINE_TYPE.OUTER_LINE && - line.name !== 'wallLine', - ) - .forEach((line) => { - roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) - canvas?.remove(line) - }) - - ridgeLines = ridgeLines.filter( - (ridge) => - (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || - (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), - ) - hipLines = hipLines.filter( - (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), - ) - - if (hipLines === undefined || hipLines.length === 0) { - hipLines = innerLines.filter( - (line) => - (line.x1 === currentRoof.x1 && line.y1 === currentRoof.y1) || - (line.x2 === currentRoof.x1 && line.y2 === currentRoof.y1) || - (line.x1 === currentRoof.x2 && line.y1 === currentRoof.y2) || - (line.x2 === currentRoof.x2 && line.y2 === currentRoof.y2), - ) - } - - if ((ridgeLines === undefined || ridgeLines.length === 0) && hipLines.length >= 2) { - let points = [] - hipLines.forEach((hip) => { - points.push({ x: hip.x1, y: hip.y1 }) - points.push({ x: hip.x2, y: hip.y2 }) - }) - - const pointSet = new Set() - const duplicatePoints = [] - - points.forEach((point) => { - const pointKey = `${point.x},${point.y}` - if (pointSet.has(pointKey)) { - duplicatePoints.push(point) - } else { - pointSet.add(pointKey) - } - }) - - ridgeLines = innerLines - .filter((r) => r !== hipLines[0] && r !== hipLines[1]) - .filter( - (r) => - (r.x1 === duplicatePoints[0].x && r.y1 === duplicatePoints[0].y) || (r.x2 === duplicatePoints[0].x && r.y2 === duplicatePoints[0].y), - ) - if (ridgeLines.length > 0) { - currentRoof.attributes.ridgeCoordinate = { x1: duplicatePoints[0].x, y1: duplicatePoints[0].y } - } - } - - hipLines.forEach((hip) => { - roof.innerLines = roof.innerLines.filter((h) => h.id !== hip.id) - canvas.remove(hip) - }) - - if (ridgeLines.length > 0) { - const ridge = ridgeLines[0] - if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { - const signX = Math.sign(midX.minus(ridge.x1).toNumber()) - const signY = Math.sign(midY.minus(ridge.y1).toNumber()) - ridge.set({ - x1: midX.minus(xWidth.abs().times(signX)).toNumber(), - y1: midY.minus(yWidth.abs().times(signY)).toNumber(), - x2: ridge.x2, - y2: ridge.y2, - }) - - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } - hipX2 = ridge.x1 - hipY2 = ridge.y1 - } - if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { - const signX = Math.sign(midX - ridge.x2) - const signY = Math.sign(midY - ridge.y2) - ridge.set({ - x1: ridge.x1, - y1: ridge.y1, - x2: midX.minus(xWidth.abs().times(signX)).toNumber(), - y2: midY.minus(yWidth.abs().times(signY)).toNumber(), - }) - - currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } - hipX2 = ridge.x2 - hipY2 = ridge.y2 - } - ridge.attributes.planeSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - ridge.attributes.actualSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - } - - let hipX1 = (Math.sign(currentRoof.x1 - midX) * currentRoof.attributes.width) / 2 - let hipY1 = (Math.sign(currentRoof.y1 - midY) * currentRoof.attributes.width) / 2 - - const gableDegree = currentRoof.attributes.degree > 0 ? currentRoof.attributes.degree : getDegreeByChon(currentRoof.attributes.pitch) - const gable1 = new QLine([midX.plus(hipX1).toNumber(), midY.plus(hipY1).toNumber(), hipX2, hipY2], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.GABLE, - textMode: textMode, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: midX.plus(hipX1).toNumber(), - y1: midY.plus(hipY1).toNumber(), - x2: hipX2, - y2: hipY2, - }), - actualSize: calcLineActualSize( - { - x1: midX.plus(hipX1).toNumber(), - y1: midY.plus(hipY1).toNumber(), - x2: hipX2, - y2: hipY2, - }, - gableDegree, - ), - }, - }) - // const gable1Base = ((Math.abs(gable1.x1 - gable1.x2) + Math.abs(gable1.y1 - gable1.y2)) / 2) * 10 - // const gable1Height = Math.round(gable1Base / Math.tan(((90 - gableDegree) * Math.PI) / 180)) - // gable1.attributes.planeSize = Math.round(Math.sqrt(Math.pow(gable1.x1 - gable1.x2, 2) + Math.pow(gable1.y1 - gable1.y2, 2))) * 10 - // gable1.attributes.actualSize = Math.round(Math.sqrt(Math.pow(gable1.attributes.planeSize, 2) + Math.pow(gable1Height, 2))) - canvas?.add(gable1) - roof.innerLines.push(gable1) - - hipX1 = (Math.sign(currentRoof.x2 - midX) * currentRoof.attributes.width) / 2 - hipY1 = (Math.sign(currentRoof.y2 - midY) * currentRoof.attributes.width) / 2 - - const gable2 = new QLine([midX.plus(hipX1).toNumber(), midY.plus(hipY1).toNumber(), hipX2, hipY2], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.GABLE, - textMode: textMode, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: midX.plus(hipX1).toNumber(), - y1: midY.plus(hipY1).toNumber(), - x2: hipX2, - y2: hipY2, - }), - actualSize: calcLineActualSize( - { - x1: midX.plus(hipX1).toNumber(), - y1: midY.plus(hipY1).toNumber(), - x2: hipX2, - y2: hipY2, - }, - gableDegree, - ), - }, - }) - // const gable2Base = ((Math.abs(gable2.x1 - gable2.x2) + Math.abs(gable2.y1 - gable2.y2)) / 2) * 10 - // const gable2Height = Math.round(gable2Base / Math.tan(((90 - gableDegree) * Math.PI) / 180)) - // gable2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(gable2.x1 - gable2.x2, 2) + Math.pow(gable2.y1 - gable2.y2, 2))) * 10 - // gable2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(gable2.attributes.planeSize, 2) + Math.pow(gable2Height, 2))) - canvas?.add(gable2) - roof.innerLines.push(gable2) - - const gable3 = new QLine([gable1.x1, gable1.y1, gable2.x1, gable2.y1], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.GABLE, - textMode: textMode, - visible: false, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ x1: gable1.x1, y1: gable1.y1, x2: gable2.x1, y2: gable2.y1 }), - actualSize: calcLinePlaneSize({ x1: gable1.x1, y1: gable1.y1, x2: gable2.x1, y2: gable2.y1 }), - }, - }) - // gable3.attributes.planeSize = Math.round(Math.sqrt(Math.pow(gable3.x1 - gable3.x2, 2) + Math.pow(gable3.y1 - gable3.y2, 2))) * 10 - // gable3.attributes.actualSize = Math.round(Math.sqrt(Math.pow(gable3.x1 - gable3.x2, 2) + Math.pow(gable3.y1 - gable3.y2, 2))) * 10 - canvas?.add(gable3) - // roof.innerLines.push(gable3) - - const hip1 = new QLine([currentRoof.x1, currentRoof.y1, gable1.x1, gable1.y1], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - visible: false, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ x1: currentRoof.x1, y1: currentRoof.y1, x2: gable1.x1, y2: gable1.y1 }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: gable1.x1, - y2: gable1.y1, - }, - prevDegree, - ), - }, - }) - // const hip1Base = ((Math.abs(hip1.x1 - hip1.x2) + Math.abs(hip1.y1 - hip1.y2)) / 2) * 10 - // const hip1Height = Math.round(hip1Base / Math.tan(((90 - prevDegree) * Math.PI) / 180)) - // hip1.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip1.x1 - hip1.x2, 2) + Math.pow(hip1.y1 - hip1.y2, 2))) * 10 - // hip1.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip1.attributes.planeSize, 2) + Math.pow(hip1Height, 2))) - canvas?.add(hip1) - // roof.innerLines.push(hip1) - - const hip2 = new QLine([currentRoof.x2, currentRoof.y2, gable2.x1, gable2.y1], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - visible: false, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ x1: currentRoof.x2, y1: currentRoof.y2, x2: gable2.x1, y2: gable2.y1 }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: gable2.x1, - y2: gable2.y1, - }, - nextDegree, - ), - }, - }) - // const hip2Base = ((Math.abs(hip2.x1 - hip2.x2) + Math.abs(hip2.y1 - hip2.y2)) / 2) * 10 - // const hip2Height = Math.round(hip2Base / Math.tan(((90 - nextDegree) * Math.PI) / 180)) - // hip2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip2.x1 - hip2.x2, 2) + Math.pow(hip2.y1 - hip2.y2, 2))) * 10 - // hip2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip2.attributes.planeSize, 2) + Math.pow(hip2Height, 2))) - canvas?.add(hip2) - - // hip1.set({ visible: false }) - hip1.setViewLengthText(false) - // gable3.set({ visible: false }) - gable3.setViewLengthText(false) - // hip2.set({ visible: false }) - hip2.setViewLengthText(false) - } - } -} - -/** - * 벽지붕으로 변경 - * @param currentRoof - * @param canvas - * @param textMode - */ -const changeWallRoof = (currentRoof, canvas, textMode) => { - const roofId = currentRoof.attributes.roofId - const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) - const roofLines = roof.lines - let prevRoof, nextRoof - roofLines.forEach((r, index) => { - if (r.id === currentRoof.id) { - currentRoof = r - prevRoof = roofLines[index === 0 ? roofLines.length - 1 : index - 1] - nextRoof = roofLines[index === roofLines.length - 1 ? 0 : index + 1] - } - }) - - const wall = canvas?.getObjects().find((object) => object.name === 'wall' && object.attributes.roofId === roofId) - let wallLine = wall.lines.filter((w) => w.id === currentRoof.attributes.wallLine) - let hipLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.HIP && object.attributes.roofId === roofId) - let ridgeLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.RIDGE && object.attributes.roofId === roofId) - - if (wallLine.length > 0) { - wallLine = wallLine[0] - } - - ridgeLines = ridgeLines.filter( - (ridge) => - (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || - (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), - ) - hipLines = hipLines.filter( - (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), - ) - - const wallMidX = Big(wallLine.x1).plus(Big(wallLine.x2)).div(2) - const wallMidY = Big(wallLine.y1).plus(Big(wallLine.y2)).div(2) - const roofMidX = Big(currentRoof.x1).plus(Big(currentRoof.x2)).div(2) - const roofMidY = Big(currentRoof.y1).plus(Big(currentRoof.y2)).div(2) - - const alpha = wallMidX.minus(roofMidX) - const beta = wallMidY.minus(roofMidY) - - currentRoof.set({ - x1: alpha.plus(currentRoof.x1).toNumber(), - y1: beta.plus(currentRoof.y1).toNumber(), - x2: alpha.plus(currentRoof.x2).toNumber(), - y2: beta.plus(currentRoof.y2).toNumber(), - }) - - prevRoof.set({ - x1: prevRoof.x1, - y1: prevRoof.y1, - x2: alpha.plus(prevRoof.x2), - y2: beta.plus(prevRoof.y2), - }) - - nextRoof.set({ - x1: alpha.plus(nextRoof.x1), - y1: beta.plus(nextRoof.y1), - x2: nextRoof.x2, - y2: nextRoof.y2, - }) - - const innerLines = canvas - ?.getObjects() - .filter( - (object) => - object.attributes?.roofId === roofId && - object.attributes?.currentRoofId === currentRoof.id && - object.x1 !== undefined && - object.x2 !== undefined, - ) - - innerLines - .filter( - (line) => - line.name !== LINE_TYPE.SUBLINE.RIDGE && - line.name !== LINE_TYPE.SUBLINE.HIP && - line.name !== LINE_TYPE.SUBLINE.VALLEY && - line.name !== OUTER_LINE_TYPE.OUTER_LINE && - line.name !== 'wallLine', - ) - .forEach((line) => { - roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) - canvas?.remove(line) - }) - - const prevDegree = prevRoof.attributes.pitch > 0 ? getDegreeByChon(prevRoof.attributes.pitch) : prevRoof.attributes.degree - const nextDegree = nextRoof.attributes.pitch > 0 ? getDegreeByChon(nextRoof.attributes.pitch) : nextRoof.attributes.degree - - if (currentRoof.attributes.sleeve && currentRoof.attributes.width > 0 && prevRoof.attributes.offset > 0 && nextRoof.attributes.offset > 0) { - const prevSignX = Math.sign(prevRoof.x1 - prevRoof.x2) - const prevSignY = Math.sign(prevRoof.y1 - prevRoof.y2) - const nextSignX = Math.sign(nextRoof.x1 - nextRoof.x2) - const nextSignY = Math.sign(nextRoof.y1 - nextRoof.y2) - - const prevWidthX = prevSignX === 0 ? 0 : prevSignX * currentRoof.attributes.width - const prevWidthY = prevSignY === 0 ? 0 : prevSignY * currentRoof.attributes.width - const nextWidthX = nextSignX === 0 ? 0 : nextSignX * currentRoof.attributes.width - const nextWidthY = nextSignY === 0 ? 0 : nextSignY * currentRoof.attributes.width - const prevX2 = Big(prevRoof.x2).minus(prevWidthX) - const prevY2 = Big(prevRoof.y2).minus(prevWidthY) - const nextX1 = Big(nextRoof.x1).plus(nextWidthX) - const nextY1 = Big(nextRoof.y1).plus(nextWidthY) - - currentRoof.set({ - x1: wallLine.x1, - y1: wallLine.y1, - x2: wallLine.x2, - y2: wallLine.y2, - }) - - prevRoof.set({ - x1: prevRoof.x1, - y1: prevRoof.y1, - x2: prevX2.toNumber(), - y2: prevY2.toNumber(), - }) - - nextRoof.set({ - x1: nextX1.toNumber(), - y1: nextY1.toNumber(), - x2: nextRoof.x2, - y2: nextRoof.y2, - }) - - const addPrevWallLine1 = new QLine( - [prevX2.toNumber(), prevY2.toNumber(), Big(wallLine.x1).minus(prevWidthX).toNumber(), Big(wallLine.y1).minus(prevWidthY).toNumber()], - { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: 'roofLine', - textMode: textMode, - attributes: { - roofId: roofId, - type: LINE_TYPE.WALLLINE.ETC, - planeSize: calcLinePlaneSize({ - x1: prevX2.toNumber(), - y1: prevY2.toNumber(), - x2: Big(wallLine.x1).minus(prevWidthX).toNumber(), - y2: Big(wallLine.y1).minus(prevWidthY).toNumber(), - }), - actualSize: calcLinePlaneSize({ - x1: prevX2.toNumber(), - y1: prevY2.toNumber(), - x2: Big(wallLine.x1).minus(prevWidthX).toNumber(), - y2: Big(wallLine.y1).minus(prevWidthY).toNumber(), - }), - }, - }, - ) - - const addPrevWallLine2 = new QLine( - [ - addPrevWallLine1.x2, - addPrevWallLine1.y2, - Big(addPrevWallLine1.x2).plus(prevWidthX).toNumber(), - Big(addPrevWallLine1.y2).plus(prevWidthY).toNumber(), - ], - { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: 'roofLine', - textMode: textMode, - attributes: { - roofId: roofId, - type: LINE_TYPE.WALLLINE.ETC, - planeSize: calcLinePlaneSize({ - x1: addPrevWallLine1.x2, - y1: addPrevWallLine1.y2, - x2: Big(addPrevWallLine1.x2).plus(prevWidthX).toNumber(), - y2: Big(addPrevWallLine1.y2).plus(prevWidthY).toNumber(), - }), - actualSize: calcLinePlaneSize({ - x1: addPrevWallLine1.x2, - y1: addPrevWallLine1.y2, - x2: Big(addPrevWallLine1.x2).plus(prevWidthX).toNumber(), - y2: Big(addPrevWallLine1.y2).plus(prevWidthY).toNumber(), - }), - }, - }, - ) - - const addNextWallLine1 = new QLine( - [wallLine.x2, wallLine.y2, Big(wallLine.x2).plus(nextWidthX).toNumber(), Big(wallLine.y2).plus(nextWidthY).toNumber()], - { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: 'roofLine', - textMode: textMode, - attributes: { - roofId: roofId, - type: LINE_TYPE.WALLLINE.ETC, - planeSize: calcLinePlaneSize({ - x1: wallLine.x2, - y1: wallLine.y2, - x2: Big(wallLine.x2).plus(nextWidthX).toNumber(), - y2: Big(wallLine.y2).plus(nextWidthY).toNumber(), - }), - actualSize: calcLinePlaneSize({ - x1: wallLine.x2, - y1: wallLine.y2, - }), - }, - }, - ) - - const addNextWallLine2 = new QLine([addNextWallLine1.x2, addNextWallLine1.y2, nextX1.toNumber(), nextY1.toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: 'roofLine', - attributes: { - roofId: roofId, - type: LINE_TYPE.WALLLINE.ETC, - planeSize: calcLinePlaneSize({ - x1: addNextWallLine1.x2, - y1: addNextWallLine1.y2, - x2: nextX1.toNumber(), - y2: nextY1.toNumber(), - }), - actualSize: calcLinePlaneSize({ - x1: addNextWallLine1.x2, - y1: addNextWallLine1.y2, - x2: nextX1.toNumber(), - y2: nextY1.toNumber(), - }), - }, - }) - - canvas?.renderAll() - const prevIndex = roof.lines.indexOf(prevRoof) + 1 - roof.lines.splice(prevIndex, 0, addPrevWallLine1, addPrevWallLine2) - - const nextIndex = roof.lines.indexOf(currentRoof) + 1 - roof.lines.splice(nextIndex, 0, addNextWallLine1, addNextWallLine2) - } - - reDrawPolygon(roof, canvas) - - if (ridgeLines.length > 0) { - const ridge = ridgeLines[0] - if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { - const diffX = Big(ridge.x1).minus(wallMidX) - const diffY = Big(ridge.y1).minus(wallMidY) - - ridge.set({ - x1: Big(ridge.x1).minus(diffX).toNumber(), - y1: Big(ridge.y1).minus(diffY).toNumber(), - x2: ridge.x2, - y2: ridge.y2, - }) - } - if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { - const diffX = Big(ridge.x2).minus(wallMidX) - const diffY = Big(ridge.y2).minus(wallMidY) - - ridge.set({ - x1: ridge.x1, - y1: ridge.y1, - x2: Big(ridge.x2).minus(diffX).toNumber(), - y2: Big(ridge.y2).minus(diffY).toNumber(), - }) - } - // ridge.attributes.planeSize = Math.round(Math.sqrt(Math.pow(ridge.x1 - ridge.x2, 2) + Math.pow(ridge.y1 - ridge.y2, 2)) * 10) - ridge.attributes.planeSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - ridge.attributes.actualSize = calcLinePlaneSize({ x1: ridge.x1, y1: ridge.y1, x2: ridge.x2, y2: ridge.y2 }) - - let hip1 = new QLine([currentRoof.x1, currentRoof.y1, wallMidX.toNumber(), wallMidY.toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - textMode: textMode, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: wallMidX.toNumber(), - y2: wallMidY.toNumber(), - }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x1, - y1: currentRoof.y1, - x2: wallMidX.toNumber(), - y2: wallMidY.toNumber(), - }, - prevDegree, - ), - }, - }) - // const hip1Base = ((Math.abs(hip1.x1 - hip1.x2) + Math.abs(hip1.y1 - hip1.y2)) / 2) * 10 - // const hip1Height = Math.round(hip1Base / Math.tan(((90 - prevDegree) * Math.PI) / 180)) - // hip1.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip1.x1 - hip1.x2, 2) + Math.pow(hip1.y1 - hip1.y2, 2))) * 10 - // hip1.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip1.attributes.planeSize, 2) + Math.pow(hip1Height, 2))) - - let hip2 = new QLine([currentRoof.x2, currentRoof.y2, wallMidX.toNumber(), wallMidY.toNumber()], { - parentId: roof.id, - fontSize: roof.fontSize, - stroke: '#1083E3', - strokeWidth: 2, - name: LINE_TYPE.SUBLINE.HIP, - attributes: { - roofId: roof.id, - currentRoofId: currentRoof.id, - planeSize: calcLinePlaneSize({ - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: wallMidX.toNumber(), - y2: wallMidY.toNumber(), - }), - actualSize: calcLineActualSize( - { - x1: currentRoof.x2, - y1: currentRoof.y2, - x2: wallMidX.toNumber(), - y2: wallMidY.toNumber(), - }, - nextDegree, - ), - }, - }) - // const hip2Base = ((Math.abs(hip2.x1 - hip2.x2) + Math.abs(hip2.y1 - hip2.y2)) / 2) * 10 - // const hip2Height = Math.round(hip2Base / Math.tan(((90 - nextDegree) * Math.PI) / 180)) - // hip2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip2.x1 - hip2.x2, 2) + Math.pow(hip2.y1 - hip2.y2, 2))) * 10 - // hip2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip2.attributes.planeSize, 2) + Math.pow(hip2Height, 2))) - canvas?.add(hip1) - canvas?.add(hip2) - roof.innerLines.push(hip1) - roof.innerLines.push(hip2) - } - if (hipLines.length > 0) { - hipLines.forEach((hip) => { - roof.innerLines = roof.innerLines.filter((h) => h.id !== hip.id) - canvas?.remove(hip) - }) - } -} - -/** - * 지붕을 변경한다. - * @param currentRoof - * @param canvas - */ -export const changeCurrentRoof = (currentRoof, canvas) => { - const roofId = currentRoof.attributes.roofId - const originRoof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) - const wall = canvas?.getObjects().find((object) => object.name === 'wall' && object.attributes.roofId === roofId) - const wallLine = wall.lines.filter((w) => w.id === currentRoof.attributes.wallLine)[0] - const innerLines = canvas - ?.getObjects() - .filter((object) => object.attributes !== undefined && object.attributes.roofId === roofId && object.x1 !== undefined && object.x2 !== undefined) - - wallLine.attributes.type = currentRoof.attributes.type - wallLine.attributes.offset = currentRoof.attributes.offset - wallLine.attributes.width = currentRoof.attributes.width - wallLine.attributes.pitch = currentRoof.attributes.pitch - wallLine.attributes.sleeve = currentRoof.attributes.sleeve - - canvas?.remove(originRoof) - - innerLines.filter((line) => line.name !== OUTER_LINE_TYPE.OUTER_LINE).forEach((line) => canvas?.remove(line)) - - const polygon = createPolygon(wall.points) - const originPolygon = new QPolygon(wall.points, { fontSize: 0 }) - originPolygon.setViewLengthText(false) - let offsetPolygon - - let result = createRoofMarginPolygon(polygon, wall.lines).vertices - const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point)) - - if (allPointsOutside) { - offsetPolygon = createRoofMarginPolygon(polygon, wall.lines).vertices - } else { - offsetPolygon = createRoofPaddingPolygon(polygon, wall.lines).vertices - } - - const newRoof = new QPolygon(offsetPolygon, { - fill: originRoof.fill, - stroke: originRoof.stroke, - strokeWidth: originRoof.strokeWidth, - selectable: originRoof.selectable, - fontSize: originRoof.fontSize, - }) - - newRoof.name = POLYGON_TYPE.ROOF - newRoof.setWall(wall) - - newRoof.lines.forEach((line, index) => { - const lineLength = Math.sqrt( - Math.pow(Math.round(Math.abs(line.x1 - line.x2) * 10), 2) + Math.pow(Math.round(Math.abs(line.y1 - line.y2) * 10), 2), - ) - line.attributes = { - roofId: newRoof.id, - planeSize: lineLength, - actualSize: lineLength, - wallLine: wall.lines[index].id, - type: wall.lines[index].attributes.type, - offset: wall.lines[index].attributes.offset, - width: wall.lines[index].attributes.width, - pitch: wall.lines[index].attributes.pitch, - sleeve: wall.lines[index].attributes.sleeve || false, - } - }) - wall.attributes = { - roofId: newRoof.id, - } - - wall.lines.forEach((line, index) => { - line.attributes.roofId = newRoof.id - line.attributes.currentRoofId = newRoof.lines[index].id - }) - canvas?.add(newRoof) - canvas?.renderAll() - - newRoof.drawHelpLine() -} - -/** - * 지붕을 변경한다. + * 지붕 모양 을 변경한다. * @param polygon * @param canvas */ @@ -7558,7 +7874,7 @@ const drawCenterLine = (roof, canvas, textMode) => { } } if (points?.length > 0) { - const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree + const currentDegree = getDegreeByChon(currentRoof.attributes.pitch) const length = currentDegree !== undefined && currentDegree > 0 ? calcLineActualSize({ x1: points[0], y1: points[1], x2: points[2], y2: points[3] }, currentDegree) @@ -7586,68 +7902,6 @@ const drawCenterLine = (roof, canvas, textMode) => { }) } -function createRoofMarginPolygon(polygon, lines, arcSegments = 0) { - const offsetEdges = [] - - polygon.edges.forEach((edge, i) => { - const offset = - lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0 - ? 0.1 - : lines[i % lines.length].attributes.offset - const dx = edge.outwardNormal.x * offset - const dy = edge.outwardNormal.y * offset - offsetEdges.push(createOffsetEdge(edge, dx, dy)) - }) - - const vertices = [] - - offsetEdges.forEach((thisEdge, i) => { - const prevEdge = offsetEdges[(i + offsetEdges.length - 1) % offsetEdges.length] - const vertex = edgesIntersection(prevEdge, thisEdge) - if (vertex && (!vertex.isIntersectionOutside || arcSegments < 1)) { - vertices.push({ - x: vertex.x, - y: vertex.y, - }) - } - }) - - const marginPolygon = createPolygon(vertices) - marginPolygon.offsetEdges = offsetEdges - return marginPolygon -} - -function createRoofPaddingPolygon(polygon, lines, arcSegments = 0) { - const offsetEdges = [] - - polygon.edges.forEach((edge, i) => { - const offset = - lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0 - ? 0.1 - : lines[i % lines.length].attributes.offset - const dx = edge.inwardNormal.x * offset - const dy = edge.inwardNormal.y * offset - offsetEdges.push(createOffsetEdge(edge, dx, dy)) - }) - - const vertices = [] - - offsetEdges.forEach((thisEdge, i) => { - const prevEdge = offsetEdges[(i + offsetEdges.length - 1) % offsetEdges.length] - const vertex = edgesIntersection(prevEdge, thisEdge) - if (vertex && (!vertex.isIntersectionOutside || arcSegments < 1)) { - vertices.push({ - x: vertex.x, - y: vertex.y, - }) - } - }) - - const paddingPolygon = createPolygon(vertices) - paddingPolygon.offsetEdges = offsetEdges - return paddingPolygon -} - function arePointsEqual(point1, point2) { return Math.abs(point1.x - point2.x) <= 1 && Math.abs(point1.y - point2.y) <= 1 } @@ -7701,7 +7955,6 @@ export const calcLinePlaneSize = (points) => { * @returns number */ export const calcLineActualSize = (points, degree = 0) => { - const { x1, y1, x2, y2 } = points const planeSize = calcLinePlaneSize(points) const theta = Big(Math.cos(Big(degree).times(Math.PI).div(180))) return Big(planeSize).div(theta).round().toNumber() @@ -7723,7 +7976,7 @@ export const createLinesFromPolygon = (points) => { } /** 포인트 정렬 가장왼쪽, 가장위 부터 */ -const getSortedPoint = (points) => { +const getSortedPoint = (points, lines) => { const startPoint = points .filter((point) => point.x === Math.min(...points.map((point) => point.x))) .reduce((prev, curr) => { @@ -7733,22 +7986,69 @@ const getSortedPoint = (points) => { sortedPoints.push(startPoint) let prevPoint = startPoint + let prevDirection for (let i = 0; i < points.length - 1; i++) { - const samePoints = [] - points - .filter((point) => !sortedPoints.includes(point)) - .forEach((point) => { - if (i % 2 === 1 && prevPoint.y === point.y) { - samePoints.push({ point, size: Math.abs(point.x - prevPoint.x) }) - } - if (i % 2 === 0 && prevPoint.x === point.x) { - samePoints.push({ point, size: Math.abs(point.y - prevPoint.y) }) + const samePoint = [] + if (i === 0) { + points.forEach((point) => { + if (point.x === prevPoint.x && point.y > prevPoint.y) { + samePoint.push({ point, direction: 'bottom', size: Math.abs(prevPoint.y - point.y) }) } }) - const samePoint = samePoints.sort((a, b) => a.size - b.size)[0].point - sortedPoints.push(samePoint) - prevPoint = samePoint + if (samePoint.length > 0) { + samePoint.sort((a, b) => a.size - b.size) + sortedPoints.push(samePoint[0].point) + prevDirection = samePoint[0].direction + prevPoint = samePoint[0].point + } else { + points.forEach((point) => { + if (point.y === prevPoint.y && point.x > prevPoint.x) { + samePoint.push({ point, direction: 'right', size: Math.abs(prevPoint.x - point.x) }) + } + }) + if (samePoint.length > 0) { + samePoint.sort((a, b) => a.size - b.size) + sortedPoints.push(samePoint[0].point) + prevDirection = samePoint[0].direction + prevPoint = samePoint[0].point + } + } + } else { + points + .filter((point) => !sortedPoints.includes(point)) + .forEach((point) => { + if ((prevDirection === 'top' || prevDirection === 'bottom') && point.y === prevPoint.y) { + const direction = point.x > prevPoint.x ? 'right' : 'left' + const size = Math.abs(point.x - prevPoint.x) + samePoint.push({ point, direction, size }) + } + if ((prevDirection === 'left' || prevDirection === 'right') && point.x === prevPoint.x) { + const direction = point.y > prevPoint.y ? 'bottom' : 'top' + const size = Math.abs(point.y - prevPoint.y) + samePoint.push({ point, direction, size }) + } + if (Math.round(Math.abs(point.x - prevPoint.x)) === Math.round(Math.abs(point.y - prevPoint.y))) { + const isLinePoint = + lines.filter( + (line) => + (line.x1 === prevPoint.x && line.y1 === prevPoint.y && line.x2 === point.x && line.y2 === point.y) || + (line.x2 === prevPoint.x && line.y2 === prevPoint.y && line.x1 === point.x && line.y1 === point.y), + ).length > 0 + if (isLinePoint) { + const direction = prevDirection + const size = Big(point.x).minus(prevPoint.x).abs().pow(2).plus(Big(point.y).minus(prevPoint.y).abs().pow(2)).sqrt().round().toNumber() + samePoint.push({ point, direction, size }) + } + } + }) + if (samePoint.length > 0) { + samePoint.sort((a, b) => a.size - b.size) + sortedPoints.push(samePoint[0].point) + prevDirection = samePoint[0].direction + prevPoint = samePoint[0].point + } + } } return sortedPoints } @@ -7759,7 +8059,6 @@ const reCalculateSize = (line) => { const theta = Big(Math.acos(Big(oldPlaneSize).div(oldActualSize))) .times(180) .div(Math.PI) - console.log('theta : ', theta.toNumber()) const planeSize = calcLinePlaneSize({ x1: line.x1, y1: line.y1,