diff --git a/docs/dictionary.txt b/docs/dictionary.txt index cef0921e..7e07124d 100644 --- a/docs/dictionary.txt +++ b/docs/dictionary.txt @@ -23,4 +23,5 @@ 개구: openSpace 도머: dormer 그림자: shadow - +복도치수: planeSize +실제치수: actualSize diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index fbe61038..910fd365 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -39,7 +39,7 @@ import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMen import InitSettingsModal from './InitSettingsModal' import GridSettingsModal from './GridSettingsModal' import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' -import { changeAllHipAndGableRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' +import { drawDirectionStringToArrow } from '@/util/qpolygon-utils' import ThumbnailList from '@/components/ui/ThumbnailLIst' import ObjectPlacement from '@/components/ui/ObjectPlacement' import { globalLocaleStore } from '@/store/localeAtom' @@ -409,6 +409,20 @@ export default function Roof2(props) { { x: 600, y: 100 }, ] + const rectangleType1 = [ + { x: 100, y: 100 }, + { x: 100, y: 600 }, + { x: 300, y: 600 }, + { x: 300, y: 100 }, + ] + + const rectangleType2 = [ + { x: 100, y: 100 }, + { x: 100, y: 300 }, + { x: 600, y: 300 }, + { x: 600, y: 100 }, + ] + const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint] const newP = [ { x: 450, y: 450 }, @@ -417,7 +431,7 @@ export default function Roof2(props) { { x: 450, y: 850 }, ] - const polygon = new QPolygon(twelvePoint, { + const polygon = new QPolygon(rectangleType2, { fill: 'transparent', stroke: 'green', strokeWidth: 1, diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 84e57974..9e034ac9 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -2,7 +2,7 @@ import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' import { QLine } from '@/components/fabric/QLine' import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util' -import { calculateAngle, drawDirectionArrow, drawHippedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' +import { calculateAngle, drawDirectionArrow, drawRidgeRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' import * as turf from '@turf/turf' export const QPolygon = fabric.util.createClass(fabric.Polygon, { @@ -174,9 +174,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }, // 보조선 그리기 - drawHelpLine(chon = 4) { - // drawHelpLineInHexagon(this, chon) - drawHippedRoof(this, chon) + drawHelpLine(pitch = 4) { + // drawHelpLineInHexagon(this, pitch) + console.log('drawHelpLine roofId : ', this.id) + drawRidgeRoof(this.id, pitch, this.canvas) }, addLengthText() { diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 6778bdba..e82c51f3 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -36,10 +36,7 @@ import { QPolygon } from '@/components/fabric/QPolygon' import offsetPolygon from '@/util/qpolygon-utils' import { isObjectNotEmpty } from '@/util/common-utils' import * as turf from '@turf/turf' -import { INPUT_TYPE, Mode } from '@/common/common' -import { m } from 'framer-motion' -import { set } from 'react-hook-form' -import { FaWineGlassEmpty } from 'react-icons/fa6' +import { INPUT_TYPE, LINE_TYPE, Mode } from '@/common/common' export function useMode() { const [mode, setMode] = useRecoilState(modeState) @@ -1509,6 +1506,25 @@ export function useMode() { *벽 지붕 외곽선 생성 polygon을 입력받아 만들기 */ const handleOuterlinesTest2 = (polygon, offset = 50) => { + console.log('polygon : ', polygon) + // TODO [ljyoung] : offset 입력 처리 후 제거 해야함. + polygon.lines.forEach((line, index) => { + if (index === 1 || index === 3) { + line.attributes = { + type: LINE_TYPE.WALLLINE.WALL, + offset: 50, + width: 100, + pitch: 4, + } + } else { + line.attributes = { + type: LINE_TYPE.WALLLINE.WALL, + offset: 50, + width: 100, + pitch: 4, + } + } + }) const roof = drawRoofPolygon(polygon) //지붕 그리기 roof.drawHelpLine() // roof.divideLine() @@ -1677,21 +1693,6 @@ export function useMode() { } const drawRoofPolygon = (wall) => { - // TODO [ljyoung] : offset 입력 처리 후 제거 해야함. - wall.lines.forEach((line, index) => { - if (index === wall.lines.length - 1 || index === 3) { - line.attributes = { - type: 'gable', - offset: 30, - } - } else { - line.attributes = { - type: 'hip', - offset: 50, - } - } - }) - const polygon = createRoofPolygon(wall.points) const originPolygon = new QPolygon(wall.points, { fontSize: 0 }) let offsetPolygon @@ -1710,13 +1711,33 @@ export function useMode() { return { x1: point.x, y1: point.y } }), ) - roof.name = 'roofBase' + roof.name = 'roof' roof.setWall(wall) roof.lines.forEach((line, index) => { - line.attributes = { type: wall.lines[index].attributes.type } + line.attributes = { + roofId: roof.id, + 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, + } }) + wall.attributes = { + roofId: roof.id, + } + + wall.lines.forEach((line, index) => { + line.attributes = { + roofId: roof.id, + } + }) + + console.log('roof : ', roof) + console.log('wall : ', wall) + setRoof(roof) setWall(wall) @@ -4852,12 +4873,6 @@ export function useMode() { ) } - const coordToTurfPolygon = (points) => { - const coordinates = points.map((point) => [point.x, point.y]) - coordinates.push(coordinates[0]) - return turf.polygon([coordinates]) - } - /** * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 로 진입여부를 확인 * 확인 후 셀을 이동시킴 @@ -4866,125 +4881,58 @@ export function useMode() { const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle') //가대를 가져옴 if (trestlePolygons.length !== 0) { + let lastPointPosition = { x: 0, y: 0 } let fabricPolygon = null let inside = false let turfPolygon - let manualDrawCells = drewRoofCells // 앞에서 자동으로 했을때 추가됨 - let direction + let manualDrawCells = drewRoofCells // + canvas.on('mouse:move', (e) => { //마우스 이벤트 삭제 후 재추가 const mousePoint = canvas.getPointer(e.e) + const turfPoint = turf.point([mousePoint.x, mousePoint.y]) + for (let i = 0; i < trestlePolygons.length; i++) { turfPolygon = polygonToTurfPolygon(trestlePolygons[i]) - direction = trestlePolygons[i].direction //도형의 방향 - let width = direction === 'south' || direction === 'north' ? 172 : 113 - let height = direction === 'south' || direction === 'north' ? 113 : 172 - - const points = [ - { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, - { x: mousePoint.x + width / 2, y: mousePoint.y - height / 2 }, - { x: mousePoint.x + width / 2, y: mousePoint.y + height / 2 }, - { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 }, - ] - - const turfPoints = coordToTurfPolygon(points) - - if (turf.booleanWithin(turfPoints, turfPolygon)) { + if (turf.booleanPointInPolygon(turfPoint, turfPolygon)) { //turf에 보면 폴리곤안에 포인트가 있는지 함수가 있다 + const direction = trestlePolygons[i].direction //도형의 방향 + let width = direction === 'south' || direction === 'north' ? 172.2 : 113.4 + let height = direction === 'south' || direction === 'north' ? 113.4 : 172.2 + if (Math.abs(mousePoint.x - lastPointPosition.x) >= 5 || Math.abs(mousePoint.y - lastPointPosition.y) >= 5) { + let isDrawing = false - // if (Math.abs(mousePoint.x - lastPointPosition.x) >= 5 || Math.abs(mousePoint.y - lastPointPosition.y) >= 5) { - let isDrawing = false + if (isDrawing) return + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임 - if (isDrawing) return - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임 + const points = [ + { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, + { x: mousePoint.x + width / 2, y: mousePoint.y - height / 2 }, + { x: mousePoint.x + width / 2, y: mousePoint.y + height / 2 }, + { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 }, + ] - fabricPolygon = new QPolygon(points, { - fill: '#BFFD9F', - // stroke: 'black', - // strokeWidth: 1, - selectable: false, // 선택 가능하게 설정 - lockMovementX: true, // X 축 이동 잠금 - lockMovementY: true, // Y 축 이동 잠금 - lockRotation: true, // 회전 잠금 - lockScalingX: true, // X 축 크기 조정 잠금 - lockScalingY: true, // Y 축 크기 조정 잠금 - opacity: 0.8, - parentId: trestlePolygons[i].parentId, - name: 'tmpCell', - }) + fabricPolygon = new QPolygon(points, { + fill: '#BFFD9F', + stroke: 'black', + selectable: false, // 선택 가능하게 설정 + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 + opacity: 0.8, + parentId: trestlePolygons[i].parentId, + name: 'tmpCell', + }) - canvas?.add(fabricPolygon) //움직여가면서 추가됨 - - /** - * 스냅기능 - */ - let snapDistance = 20 - - const bigLeft = trestlePolygons[i].left - const bigTop = trestlePolygons[i].top - const bigRight = bigLeft + trestlePolygons[i].width * trestlePolygons[i].scaleX - const bigBottom = bigTop + trestlePolygons[i].height * trestlePolygons[i].scaleY - const bigCenter = (bigTop + bigTop + trestlePolygons[i].height) / 2 - - // 작은 폴리곤의 경계 좌표 계산 - const smallLeft = fabricPolygon.left - const smallTop = fabricPolygon.top - const smallRight = smallLeft + fabricPolygon.width * fabricPolygon.scaleX - const smallBottom = smallTop + fabricPolygon.height * fabricPolygon.scaleY - const smallCenter = smallLeft + (fabricPolygon.width * fabricPolygon.scaleX) / 2 - - // 위쪽 변에 스냅 - if (Math.abs(smallTop - bigTop) < snapDistance) { - fabricPolygon.top = bigTop + canvas?.add(fabricPolygon) //움직여가면서 추가됨 + lastPointPosition = { x: mousePoint.x, y: mousePoint.y } } - // 아래쪽 변에 스냅 - if (Math.abs(smallTop + fabricPolygon.height * fabricPolygon.scaleY - (bigTop + trestlePolygons[i].height)) < snapDistance) { - fabricPolygon.top = bigTop + trestlePolygons[i].height - fabricPolygon.height * fabricPolygon.scaleY - } - - // 왼쪽변에 스냅 - if (Math.abs(smallLeft - bigLeft) < snapDistance) { - fabricPolygon.left = bigLeft - } - //오른쪽 변에 스냅 - if (Math.abs(smallRight - bigRight) < snapDistance) { - fabricPolygon.left = bigRight - fabricPolygon.width * fabricPolygon.scaleX - } - - if (direction === 'south' || direction === 'north') { - // 모듈왼쪽이 세로중앙선에 붙게 스냅 - if (Math.abs(smallLeft - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) { - fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - } - - // 모듈이 가운데가 세로중앙선에 붙게 스냅 - if (Math.abs(smallCenter - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) { - fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - (fabricPolygon.width * fabricPolygon.scaleX) / 2 - } - - // 모듈오른쪽이 세로중앙선에 붙게 스냅 - if (Math.abs(smallRight - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) { - fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - fabricPolygon.width * fabricPolygon.scaleX - } - } else { - // 모듈이 가로중앙선에 스냅 - if (Math.abs(smallTop + fabricPolygon.height / 2 - bigCenter) < snapDistance) { - fabricPolygon.top = bigCenter - fabricPolygon.height / 2 - } - - if (Math.abs(smallTop - (bigTop + trestlePolygons[i].height / 2)) < snapDistance) { - fabricPolygon.top = bigTop + trestlePolygons[i].height / 2 - } - // 모듈 밑면이 가로중앙선에 스냅 - if (Math.abs(smallBottom - (bigTop + trestlePolygons[i].height / 2)) < snapDistance) { - fabricPolygon.top = bigTop + trestlePolygons[i].height / 2 - fabricPolygon.height * fabricPolygon.scaleY - } - } - - fabricPolygon.setCoords() canvas?.renderAll() inside = true + break } else { inside = false } @@ -5000,26 +4948,20 @@ export function useMode() { if (!inside) return if (fabricPolygon) { const turfCellPolygon = polygonToTurfPolygon(fabricPolygon) - fabricPolygon.setCoords() //좌표 재정렬 + if (turf.booleanWithin(turfCellPolygon, turfPolygon)) { //마우스 클릭시 set으로 해당 위치에 셀을 넣음 - - manualDrawCells.forEach((cell) => { - console.log('cells', cell.points) - }) - console.log('turfCellPolygon', turfCellPolygon.geometry.coordinates) - const isOverlap = manualDrawCells.some((cell) => turf.booleanOverlap(turfCellPolygon, polygonToTurfPolygon(cell))) if (!isOverlap) { //안겹치면 넣는다 - fabricPolygon.setCoords() fabricPolygon.set({ name: 'cell' }) + fabricPolygon.setCoords() manualDrawCells.push(fabricPolygon) } else { alert('셀끼리 겹치면 안되죠?') } - // } else { - // alert('나갔으요!!') + } else { + alert('나갔으요!!') } setDrewRoofCells(manualDrawCells) } @@ -5096,6 +5038,27 @@ export function useMode() { // console.log('bbox', bbox) + const boxes = [] + const installedCellsArray = [] + + for (let x = bbox[0]; x < bbox[2]; x += width) { + for (let y = bbox[1]; y < bbox[3]; y += height) { + const box = turf.polygon([ + [ + [x, y], + [x + width, y], + [x + width, y + height], + [x, y + height], + [x, y], + ], + ]) + + if (turf.booleanWithin(box, turfTrestlePolygon)) { + boxes.push(box) + } + } + } + for (let col = 0; col <= cols; col++) { for (let row = 0; row <= rows; row++) { let x = 0, @@ -5145,6 +5108,20 @@ export function useMode() { const squarePolygon = turf.polygon([square]) + // console.log('turfTrestlePolygon', turfTrestlePolygon) + // console.log('squarePolygon', squarePolygon) + + const areaSize = turf.area(turfTrestlePolygon) + + // console.log('areaSize', areaSize) + const objSize = turf.area(squarePolygon) + + // console.log('objSize', objSize) + + const maxObject = Math.floor(areaSize / objSize) + + // console.log('maxObjectSize', maxObject) + const disjointFromTrestle = turf.booleanContains(turfTrestlePolygon, squarePolygon) || turf.booleanWithin(squarePolygon, turfTrestlePolygon) if (disjointFromTrestle) { @@ -5185,8 +5162,6 @@ export function useMode() { lockScalingY: true, // Y 축 크기 조정 잠금 opacity: 0.8, parentId: trestle.parentId, - lineCol: col, - lineRow: row, }) canvas?.add(fabricPolygon) drawCellsArray.push(fabricPolygon) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index a7bcb0e2..c7ccfece 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -3,6 +3,7 @@ import { QLine } from '@/components/fabric/QLine' import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDirectionByPoint } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import * as turf from '@turf/turf' +import { LINE_TYPE } from '@/common/common' const TWO_PI = Math.PI * 2 @@ -12,7 +13,7 @@ export const defineQPloygon = () => { } } -export const drawHelpLineInHexagon = (polygon, chon) => { +export const drawHelpLineInHexagon = (polygon, pitch) => { const centerLines = drawCenterLines(polygon) let helpLines = [] @@ -1191,26 +1192,33 @@ function calculateAngleBetweenLines(line1, line2) { return (angleInRadians * 180) / Math.PI } -export const drawHippedRoof = (polygon, chon) => { - const hasNonParallelLines = polygon.lines.filter((line) => line.x1 !== line.x2 && line.y1 !== line.y2) +export const drawRidgeRoof = (roofId, pitch, canvas) => { + console.log('drawRidgeRoof : ', roofId) + const roof = canvas?.getObjects().find((object) => object.id === roofId) + const hasNonParallelLines = roof.lines.filter((line) => line.x1 !== line.x2 && line.y1 !== line.y2) if (hasNonParallelLines.length > 0) { alert('대각선이 존재합니다.') return } - drawRidgeRoof(polygon, chon) - drawHips(polygon) - connectLinePoint(polygon) + drawRidge(roof, canvas) + drawHips(roof, canvas) + connectLinePoint(roof, canvas) + modifyRidge(roof, canvas) } /** + * 마루가 존재하면 그린다. 마루는 지붕의 중간에 위치한다. * - * @param polygon - * @param chon + * @param roof + * @param canvas */ -const drawRidgeRoof = (polygon, chon) => { - const walls = polygon.wall.lines // 외벽의 라인 - const roofs = polygon.lines // 지붕의 라인 +const drawRidge = (roof, canvas) => { + const walls = canvas?.getObjects().find((object) => object.name === 'wall' && object.attributes.roofId === roof.id).lines // 외벽의 라인 + const roofs = roof.lines // 지붕의 라인 let ridgeRoof = [] + console.log('drawRidge : ', roof.ridges) + console.log('walls : ', walls) + console.log('roofs : ', roofs) roofs.forEach((currentRoof, index) => { let prevRoof, @@ -1228,8 +1236,11 @@ const drawRidgeRoof = (polygon, chon) => { // 지붕의 길이가 짧은 순으로 정렬 ridgeRoof.sort((a, b) => a.length - b.length) + console.log('ridgeRoof : ', ridgeRoof) + ridgeRoof.forEach((item) => { - if (getMaxRidge(roofs.length) > polygon.ridges.length) { + console.log(getMaxRidge(roofs.length), roof.ridges.length) + if (getMaxRidge(roofs.length) > roof.ridges.length) { let index = item.index, beforePrevRoof, prevRoof, @@ -1463,37 +1474,38 @@ const drawRidgeRoof = (polygon, chon) => { } } } - const currentWall = walls[index] - if (currentWall.attributes.type === 'gable') { - if (currentRoof.x1 === currentRoof.x2) { - startXPoint = currentRoof.x1 - } - if (currentRoof.y1 === currentRoof.y2) { - startYPoint = currentRoof.y1 - } - } + console.log('startXPoint', startXPoint, 'startYPoint', startYPoint, 'endXPoint', endXPoint, 'endYPoint', endYPoint) // 마루 그리기 if (startXPoint !== undefined && startYPoint !== undefined && endXPoint !== undefined && endYPoint !== undefined) { const ridge = new QLine( [Math.min(startXPoint, endXPoint), Math.min(startYPoint, endYPoint), Math.max(startXPoint, endXPoint), Math.max(startYPoint, endYPoint)], { - fontSize: polygon.fontSize, + fontSize: roof.fontSize, stroke: 'blue', strokeWidth: 1, name: 'ridgeLine', + attributes: { roofId: roof.id }, }, ) - polygon.canvas.add(ridge) - polygon.ridges.push(ridge) - polygon.innerLines.push(ridge) + canvas.add(ridge) + roof.ridges.push(ridge) + roof.innerLines.push(ridge) + console.log('currentRoof', currentRoof.x1, currentRoof.y1) + console.log('startXPoint', startXPoint, 'startYPoint', startYPoint, 'endXPoint', endXPoint, 'endYPoint', endYPoint) + + const distance = (x1, y1, x2, y2) => Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) + const dist1 = distance(startXPoint, startYPoint, currentRoof.x1, currentRoof.y1) + const dist2 = distance(endXPoint, endYPoint, currentRoof.x1, currentRoof.y1) + + currentRoof.attributes.ridgeCoordinate = { x1: dist1 < dist2 ? startXPoint : endXPoint, y1: dist1 < dist2 ? startYPoint : endYPoint } } } }) //겹쳐지는 마루는 하나로 합침 - polygon.ridges.forEach((ridge, index) => { - polygon.ridges + roof.ridges.forEach((ridge, index) => { + roof.ridges .filter((ridge2) => !(ridge.x1 === ridge2.x1 && ridge.y1 === ridge2.y1 && ridge.x2 === ridge2.x2 && ridge.y2 === ridge2.y2)) .forEach((ridge2) => { let overlap = segmentsOverlap(ridge, ridge2) @@ -1503,22 +1515,21 @@ const drawRidgeRoof = (polygon, chon) => { let y1 = Math.min(ridge.y1, ridge2.y1, ridge.y2, ridge2.y2) let y2 = Math.max(ridge.y1, ridge2.y1, ridge.y2, ridge2.y2) const newRidge = new QLine([x1, y1, x2, y2], { - fontSize: polygon.fontSize, + fontSize: roof.fontSize, stroke: 'blue', strokeWidth: 1, + name: 'ridgeLine', + attributes: { roofId: roof.id }, }) - polygon.canvas.remove(ridge) - polygon.canvas.remove(ridge2) - polygon.ridges = polygon.ridges.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) - polygon.ridges = polygon.ridges.filter((r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2)) - polygon.innerLines = polygon.innerLines.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) - polygon.innerLines = polygon.innerLines.filter( - (r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2), - ) - - polygon.canvas.add(newRidge) - polygon.ridges.push(newRidge) - polygon.innerLines.push(newRidge) + roof.canvas.remove(ridge) + roof.canvas.remove(ridge2) + roof.ridges = roof.ridges.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) + roof.ridges = roof.ridges.filter((r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2)) + roof.innerLines = roof.innerLines.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) + roof.innerLines = roof.innerLines.filter((r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2)) + canvas.add(newRidge) + roof.ridges.push(newRidge) + roof.innerLines.push(newRidge) } }) }) @@ -1565,720 +1576,151 @@ const segmentsOverlap = (line1, line2) => { return false } -const drawHips = (polygon) => { - /* - 마루에서 시작되는 hip을 먼저 그립니다. - */ - polygon.ridges.forEach((ridge) => { - let leftTop, rightTop, leftBottom, rightBottom - if (ridge.y1 === ridge.y2) { - //왼쪽 좌표 기준 225, 315도 방향 라인확인 - leftTop = polygon.lines - .filter((line) => line.x1 < ridge.x1 && line.y1 < ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.x1 - current.x1) < Math.min(ridge.x1 - prev.x1) ? current : prev - } - }, undefined) +/** + * 추녀마루를 그린다. + * @param roof + * @param canvas + */ +const drawHips = (roof, canvas) => { + console.log('drawHips roofs : ', roof) - leftBottom = polygon.lines - .filter((line) => line.x1 < ridge.x1 && line.y1 > ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.x1 - current.x1) < Math.min(ridge.x1 - prev.x1) ? current : prev - } - }, undefined) + const roofLines = roof.lines + const ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roof.id) - //오른쪽 좌표 기준 45, 135도 방향 라인확인 - rightTop = polygon.lines - .filter((line) => line.x1 > ridge.x2 && line.y1 < ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.x1 - ridge.x2) < Math.min(prev.x1 - ridge.x2) ? current : prev - } - }, undefined) - - rightBottom = polygon.lines - .filter((line) => line.x1 > ridge.x2 && line.y1 > ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.x1 - ridge.x2) < Math.min(prev.x1 - ridge.x2) ? current : prev - } - }, undefined) - if (leftTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x1 && - r.y1 < ridge.y1 && - (r.y1 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x1 && - r.y2 < ridge.y1 && - (r.y2 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftTop.x1, leftTop.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (leftBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x1 && - r.y1 > ridge.y1 && - (r.y1 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x1 && - r.y2 > ridge.y1 && - (r.y2 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftBottom.x1, leftBottom.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 > ridge.x2 && - r.y1 < ridge.y2 && - (r.y1 - rightTop.y1) * (ridge.x2 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y2 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 > ridge.x2 && - r.y2 < ridge.y2 && - (r.y2 - rightTop.y1) * (ridge.x2 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y2 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightTop.x1, rightTop.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 > ridge.x2 && - r.y1 > ridge.y2 && - (r.y1 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x1 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 > ridge.x2 && - r.y2 > ridge.y2 && - (r.y2 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x2 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightBottom.x1, rightBottom.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - } - if (ridge.x1 === ridge.x2) { - //위쪽 좌표 기준 45, 315도 방향 라인확인 - leftTop = polygon.lines - .filter((line) => line.x1 < ridge.x1 && line.y1 < ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.y1 - current.y1) < Math.min(ridge.y1 - prev.y1) ? current : prev - } - }, undefined) - - rightTop = polygon.lines - .filter((line) => line.x1 > ridge.x1 && line.y1 < ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.y1 - current.y1) < Math.min(ridge.y1 - prev.y1) ? current : prev - } - }, undefined) - - //아래쪽 좌표 기준 135, 225도 방향 라인확인 - leftBottom = polygon.lines - .filter((line) => line.x1 < ridge.x2 && line.y1 > ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.y1 - ridge.y2) < Math.min(prev.y1 - ridge.y2) ? current : prev - } - }, undefined) - - rightBottom = polygon.lines - .filter((line) => line.x1 > ridge.x2 && line.y1 > ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.y1 - ridge.y2) < Math.min(prev.y1 - ridge.y2) ? current : prev - } - }, undefined) - - if (leftTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if (r.x1 < ridge.x1 && r.y1 < ridge.y1) { - if ((r.y1 - leftTop.y1) * (ridge.x1 - leftTop.x1) === (r.x1 - leftTop.x1) * (ridge.y1 - leftTop.y1)) { - isRidgePointOnLine = true - } - } - if (r.x2 < ridge.x1 && r.y2 < ridge.y1) { - if ((r.y2 - leftTop.y1) * (ridge.x1 - leftTop.x1) === (r.x2 - leftTop.x1) * (ridge.y1 - leftTop.y1)) { - isRidgePointOnLine = true - } - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftTop.x1, leftTop.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if (r.x1 > ridge.x1 && r.y1 < ridge.y1) { - if ((r.y1 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y1 - rightTop.y1)) { - isRidgePointOnLine = true - } - } - if (r.x2 > ridge.x1 && r.y2 < ridge.y1) { - if ((r.y2 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y1 - rightTop.y1)) { - isRidgePointOnLine = true - } - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightTop.x1, rightTop.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (leftBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x2 && - r.y1 > ridge.y2 && - (r.y1 - leftBottom.y1) * (ridge.x2 - leftBottom.x1) === (r.x1 - leftBottom.x1) * (ridge.y2 - leftBottom.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x2 && - r.y2 > ridge.y2 && - (r.y2 - leftBottom.y1) * (ridge.x2 - leftBottom.x1) === (r.x2 - leftBottom.x1) * (ridge.y2 - leftBottom.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftBottom.x1, leftBottom.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x2 && - r.y1 > ridge.y2 && - (r.y1 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x1 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x2 && - r.y2 > ridge.y2 && - (r.y2 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x2 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightBottom.x1, rightBottom.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - } - }) - - // 가장 가까운 마루를 확인하여 그릴 수 있는 라인이 존재하면 먼저 그린다. - let prevLine, currentLine, nextLine - polygon.lines.forEach((value, index) => { - if (index === 0) { - prevLine = polygon.lines[polygon.lines.length - 1] - } else { - prevLine = polygon.lines[index - 1] - } - currentLine = polygon.lines[index] - - if (index === polygon.lines.length - 1) { - nextLine = polygon.lines[0] - } else if (index === polygon.lines.length) { - nextLine = polygon.lines[1] - } else { - nextLine = polygon.lines[index + 1] - } - - if (!isAlreadyHip(polygon, currentLine)) { - let dVector = getDirectionForDegree(prevLine, currentLine) - let nearRidge - - switch (dVector) { - case 45: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 < ridge.x1 && currentLine.y1 > ridge.y1) || (currentLine.x1 < ridge.x2 && currentLine.y1 > ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x2 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - case 135: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 < ridge.x1 && currentLine.y1 < ridge.y1) || (currentLine.x1 < ridge.x2 && currentLine.y1 < ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - case 225: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 > ridge.x1 && currentLine.y1 < ridge.y1) || (currentLine.x1 > ridge.x2 && currentLine.y1 < ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - case 315: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 > ridge.x1 && currentLine.y1 > ridge.y1) || (currentLine.x1 > ridge.x2 && currentLine.y1 > ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - } - - if (nearRidge !== undefined) { - let endXPoint, endYPoint - let minX, maxX, minY, maxY - - switch (dVector) { - case 45: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - case 135: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - case 225: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - case 315: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - } - - let lineCoordinate = [ - { x: minX, y: minY }, - { x: minX, y: maxY }, - { x: maxX, y: maxY }, - { x: maxX, y: minY }, - ] - - let innerPoint = polygon.lines.filter((line) => { - if (getPointInPolygon(lineCoordinate, { x: line.x1, y: line.y1 })) { - return line - } - }) - - if (innerPoint <= 0) { - const hip = new QLine([currentLine.x1, currentLine.y1, endXPoint, endYPoint], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - } - }) - - // 마루와 연결되지 않은 hip을 그린다. - /*polygon.lines.forEach((line, index) => { - if (!isAlreadyHip(polygon, line)) { - console.log(' 확인 : ', line) - let prevLine, currentLine, nextLine - if (index === 0) { - prevLine = polygon.lines[polygon.lines.length - 1] - } else { - prevLine = polygon.lines[index - 1] - } - currentLine = polygon.lines[index] - - if (index === polygon.lines.length - 1) { - nextLine = polygon.lines[0] - } else if (index === polygon.lines.length) { - nextLine = polygon.lines[1] - } else { - nextLine = polygon.lines[index + 1] - } - - let endXPoint, endYPoint - let dVector = getDirectionForDegree(prevLine, currentLine) - - let minX = Math.min(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2) - let maxX = Math.max(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2) - let minY = Math.min(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2) - let maxY = Math.max(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2) - - let lineCoordinate = [ - { x: minX, y: minY }, - { x: minX, y: maxY }, - { x: maxX, y: maxY }, - { x: maxX, y: minY }, - ] - - let acrossLine = getAcrossLine(polygon, currentLine, dVector) - let hypotenuse, adjacent - console.log(acrossLine) - - if (getLineDirection(prevLine) === getLineDirection(nextLine)) { - hypotenuse = Math.round(getRoofHypotenuse(Math.abs(currentLine.x1 - acrossLine.x1) / 2)) - } else { - hypotenuse = Math.min( - Math.round(getRoofHypotenuse(currentLine.length / 2)), - Math.round(getRoofHypotenuse(Math.abs(currentLine.x1 - acrossLine.x1) / 2)), - ) - } - adjacent = getAdjacent(hypotenuse) - - switch (dVector) { - case 45: - endXPoint = currentLine.x1 + adjacent - endYPoint = currentLine.y1 - adjacent - break - case 135: - endXPoint = currentLine.x1 + adjacent - endYPoint = currentLine.y1 + adjacent - break - case 225: - endXPoint = currentLine.x1 - adjacent - endYPoint = currentLine.y1 + adjacent - break - case 315: - endXPoint = currentLine.x1 - adjacent - endYPoint = currentLine.y1 - adjacent - break - } - - const hip = new QLine([currentLine.x1, currentLine.y1, endXPoint, endYPoint], { - fontSize: polygon.fontSize, + //마루에서 시작되는 hip을 먼저 그립니다. + roofLines + .filter((roof) => roof.attributes.type === LINE_TYPE.WALLLINE.EAVES && roof.attributes.ridgeCoordinate !== undefined) + .forEach((currentRoof, index) => { + const ridgeCoordinate = currentRoof.attributes.ridgeCoordinate + const hip1 = new QLine([currentRoof.x1, currentRoof.y1, ridgeCoordinate.x1, ridgeCoordinate.y1], { + fontSize: roof.fontSize, stroke: 'red', strokeWidth: 1, name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) + canvas.add(hip1) + roof.hips.push(hip1) + roof.innerLines.push(hip1) + + const hip2 = new QLine([currentRoof.x2, currentRoof.y2, ridgeCoordinate.x1, ridgeCoordinate.y1], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas.add(hip2) + roof.hips.push(hip2) + roof.innerLines.push(hip2) + }) + + const hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roof.id) + + //마루에서 시작되지 않는 hip을 그립니다. + roofLines + .filter((roof) => { + let isHip = false + if (hipLines.some((hip) => hip.x1 === roof.x1 && hip.y1 === roof.y1)) { + isHip = true + } + return !isHip + }) + .forEach((currentRoof) => { + let prevRoof + roofLines.forEach((roof, index) => { + if (roof === currentRoof) { + prevRoof = index === 0 ? roofLines[roofLines.length - 1] : roofLines[index - 1] + } + }) + + // if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES && prevRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let ridgePoints = [] + ridgeLines.forEach((ridge) => { + const deltaX1 = ridge.x1 - currentRoof.x1 + const deltaY1 = ridge.y1 - currentRoof.y1 + const deltaX2 = ridge.x2 - currentRoof.x1 + const deltaY2 = ridge.y2 - currentRoof.y1 + + if (Math.abs(deltaY1 / deltaX1) === 1) { + ridgePoints.push({ x: ridge.x1, y: ridge.y1 }) + } + if (Math.abs(deltaY2 / deltaX2) === 1) { + ridgePoints.push({ x: ridge.x2, y: ridge.y2 }) + } + }) + + ridgePoints = ridgePoints.reduce((prev, current) => { + if (prev !== undefined) { + const deltaPrevX = Math.abs(prev.x - currentRoof.x1) + const deltaPrevY = Math.abs(prev.y - currentRoof.y1) + const deltaCurrentX = Math.abs(current.x - currentRoof.x1) + const deltaCurrentY = Math.abs(current.y - currentRoof.y1) + if (deltaPrevX < deltaCurrentX && deltaPrevY < deltaCurrentY) { + return prev + } else { + return current + } + } else { + return current + } + }, undefined) + + if (ridgePoints !== undefined) { + const hip = new QLine([currentRoof.x1, currentRoof.y1, ridgePoints.x, ridgePoints.y], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas.add(hip) + roof.hips.push(hip) + roof.innerLines.push(hip) + } + }) +} + +/** + * 라인 사이가 지붕골 인지 확인. + * @param polygon + * @param line1 + * @param line2 + * @returns {boolean} + */ +const checkValley = (polygon, line1, line2) => { + let points = [ + { x: line1.x1, y: line1.y1 }, + { x: line1.x2, y: line1.y2 }, + { x: line2.x1, y: line2.y1 }, + { x: line2.x2, y: line2.y2 }, + ] + + const uniquePointsMap = new Map() + points.forEach((point) => { + const key = `${point.x},${point.y}` + if (!uniquePointsMap.has(key)) { + uniquePointsMap.set(key, point) } - })*/ + }) + points = Array.from(uniquePointsMap.values()) + + const centroidX = points.reduce((acc, point) => acc + point.x, 0) / points.length + const centroidY = points.reduce((acc, point) => acc + point.y, 0) / points.length + + let isValley = false + const pPoints = polygon.points + pPoints.forEach((point, index) => { + let j = (index + 1) % pPoints.length + let xi = pPoints[index].x + polygon.left, + yi = pPoints[index].y + polygon.top + let xj = pPoints[j].x + polygon.left, + yj = pPoints[j].y + polygon.top + + let intersect = yi > centroidY !== yj > centroidY && centroidX < ((xj - xi) * (centroidY - yi)) / (yj - yi) + xi + if (intersect) isValley = !isValley + }) + return isValley } const getPointInPolygon = (polygon, point, isInclude = false) => { @@ -2564,6 +2006,7 @@ const connectLinePoint = (polygon) => { stroke: 'blue', strokeWidth: 1, name: 'ridgeLine', + attributes: { roofId: polygon.id }, }) if (polygon.ridges.filter((r) => newRidge.x1 === r.x1 && newRidge.y1 === r.y1 && newRidge.x2 === r.x2 && newRidge.y2 === r.y2).length === 0) { polygon.canvas.remove(ridge) @@ -2586,6 +2029,99 @@ const connectLinePoint = (polygon) => { console.log('polygon : ', polygon) } +const modifyRidge = (roof, canvas) => { + const roofLines = roof.lines + const ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roof.id) + const hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && 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) + console.log('1 currentRoof : ', currentRoof) + 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 } + } + } + console.log('2 currentRoof : ', currentRoof) + if (currentRoof !== undefined) { + switch (currentRoof.attributes.type) { + case LINE_TYPE.WALLLINE.EAVES: + break + case LINE_TYPE.WALLLINE.GABLE: + changeGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.HIPANDGABLE: + changeHipAndGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.JERKINHEAD: + changeJerkInHeadRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.WALL: + changeWallRoof(roof.id, currentRoof, canvas) + 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) + console.log('3 currentRoof : ', currentRoof) + 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 } + } + } + console.log('4 currentRoof : ', currentRoof) + if (currentRoof !== undefined) { + switch (currentRoof.attributes.type) { + case LINE_TYPE.WALLLINE.EAVES: + break + case LINE_TYPE.WALLLINE.GABLE: + changeGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.HIPANDGABLE: + changeHipAndGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.JERKINHEAD: + changeJerkInHeadRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.WALL: + changeWallRoof(roof.id, currentRoof, canvas) + break + } + } + } + }) +} + /* 최대 생성 마루 갯수 */ @@ -2593,74 +2129,405 @@ const getMaxRidge = (length) => { return (length - 4) / 2 + 1 } -/* - 두 라인의 사잇각 계산 +/** + * 처마지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas */ -const getDirectionForDegree = (line1, line2) => { - let degree = getLineDirection(line1) + getLineDirection(line2) - let vector +export const changeEavesRoof = (roofId, currentRoof, canvas) => {} - switch (degree) { - case 'rb': - vector = 45 - break - case 'br': - vector = 45 - break - case 'lb': - vector = 135 - break - case 'bl': - vector = 135 - break - case 'lt': - vector = 225 - break - case 'tl': - vector = 225 - break - case 'rt': - vector = 315 - break - case 'tr': - vector = 315 - break +/** + * 박공지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas + */ +export const changeGableRoof = (roofId, currentRoof, canvas) => { + if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.GABLE) { + const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) + let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) + + 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), + ) + let midX = (currentRoof.x1 + currentRoof.x2) / 2 + let midY = (currentRoof.y1 + currentRoof.y2) / 2 + if (ridgeLines !== undefined && ridgeLines.length > 0) { + const ridge = ridgeLines[0] + if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { + midX = ridge.x1 + (ridge.x1 - midX) + midY = ridge.y1 - (ridge.y1 - midY) + ridge.set({ + x1: midX, + y1: midY, + x2: ridge.x2, + y2: ridge.y2, + }) + } + if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { + midX = ridge.x2 + (ridge.x2 - midX) + midY = ridge.y2 - (ridge.y2 - midY) + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: midX, + y2: midY, + }) + } + } + + if (hipLines !== undefined && hipLines.length > 0) { + hipLines.forEach((hip) => + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: midX, + y2: midY, + }), + ) + } else { + let hip1 = new QLine([currentRoof.x1, currentRoof.y1, midX, midY], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roofId, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas?.add(hip1) + roof.hips.push(hip1) + roof.innerLines.push(hip1) + + let hip2 = new QLine([currentRoof.x2, currentRoof.y2, midX, midY], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roofId, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas?.add(hip2) + roof.hips.push(hip2) + roof.innerLines.push(hip2) + } } - - return vector } -/* - 현재 라인의 방향을 계산 +/** + * 팔작지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas */ -const getLineDirection = (line) => { - let x1, x2, y1, y2, xp, yp - x1 = Math.round(line.x1) - x2 = Math.round(line.x2) - y1 = Math.round(line.y1) - y2 = Math.round(line.y2) +export const changeHipAndGableRoof = (roofId, currentRoof, canvas) => { + if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) + let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) - xp = x1 - x2 - yp = y1 - y2 + 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 (xp === 0) { - if (yp < 0) { - return 'b' - } else { - return 't' + if (ridgeLines.length > 0) { + const ridge = ridgeLines[0] + let midX = (currentRoof.x1 + currentRoof.x2) / 2 + let midY = (currentRoof.y1 + currentRoof.y2) / 2 + let xWidth = currentRoof.attributes.width + let yWidth = currentRoof.attributes.width + let diffX = 0 + let diffY = 0 + + if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { + diffX = ridge.x1 - midX + diffY = ridge.y1 - midY + midX = ridge.x1 - diffX + midY = ridge.y1 - diffY + xWidth = diffX === 0 ? 0 : Math.sign(diffX) * xWidth + yWidth = diffY === 0 ? 0 : Math.sign(diffY) * yWidth + ridge.set({ + x1: midX + xWidth, + y1: midY + yWidth, + 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) { + diffX = ridge.x2 - midX + diffY = ridge.y2 - midY + midX = ridge.x2 - diffX + midY = ridge.y2 - diffY + xWidth = diffX === 0 ? 0 : Math.sign(diffX) * xWidth + yWidth = diffY === 0 ? 0 : Math.sign(diffY) * yWidth + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: midX + xWidth, + y2: midY + yWidth, + }) + + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } + } + + if (hipLines.length > 0) { + hipLines.forEach((hip) => { + const singX = Math.sign(hip.x1 - currentRoof.attributes.ridgeCoordinate.x1) + const singY = Math.sign(hip.y1 - currentRoof.attributes.ridgeCoordinate.y1) + const alpha = diffX === 0 ? 0 : Math.abs(diffX) - currentRoof.attributes.width + const beta = diffY === 0 ? 0 : Math.abs(diffY) - currentRoof.attributes.width + const hypotenuse = Math.sqrt(Math.pow(alpha, 2) + Math.pow(beta, 2)) + + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: hip.x2 + singX * hypotenuse, + y2: hip.y2 + singY * hypotenuse, + }) + }) + } + + if (ridgeLines.length > 0 && hipLines.length > 0) { + hipLines.forEach((hip) => { + const hipLine = new QLine([hip.x2, hip.y2, currentRoof.attributes.ridgeCoordinate.x1, currentRoof.attributes.ridgeCoordinate.y1], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'gableLine', + }) + canvas?.add(hipLine) + roof.innerLines.push(hipLine) + }) + } } } - if (yp === 0) { - if (xp < 0) { - return 'r' - } else { - return 'l' +} + +/** + * 반절처 지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas + */ +export const changeJerkInHeadRoof = (roofId, currentRoof, canvas) => { + if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + console.log('roofId : ', roofId) + console.log('currentRoof : ', currentRoof) + const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) + let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) + + 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), + ) + + console.log('ridgeLines : ', ridgeLines) + console.log('hipLines : ', hipLines) + + if (ridgeLines.length > 0) { + const ridge = ridgeLines[0] + let midX = (currentRoof.x1 + currentRoof.x2) / 2 + let midY = (currentRoof.y1 + currentRoof.y2) / 2 + let xWidth = currentRoof.attributes.width + let yWidth = currentRoof.attributes.width + if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { + const diffX = ridge.x1 - midX + const diffY = ridge.y1 - midY + midX = ridge.x1 - diffX + midY = ridge.y1 - diffY + xWidth = diffX === 0 ? 0 : (Math.sign(diffX) * xWidth) / 2 + yWidth = diffY === 0 ? 0 : (Math.sign(diffY) * yWidth) / 2 + ridge.set({ + x1: midX + xWidth, + y1: midY + yWidth, + 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 diffX = ridge.x2 - midX + const diffY = ridge.y2 - midY + midX = ridge.x2 - diffX + midY = ridge.y2 - diffY + xWidth = diffX === 0 ? 0 : (Math.sign(diffX) * xWidth) / 2 + yWidth = diffY === 0 ? 0 : (Math.sign(diffY) * yWidth) / 2 + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: midX + xWidth, + y2: midY + yWidth, + }) + + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } + } } + + if (hipLines.length > 0) { + const midX = (currentRoof.x1 + currentRoof.x2) / 2 + const midY = (currentRoof.y1 + currentRoof.y2) / 2 + + hipLines.forEach((hip) => { + const singX = Math.sign(hip.x1 - midX) + const singY = Math.sign(hip.y1 - midY) + const xWidth = singX === 0 ? 0 : (singX * currentRoof.attributes.width) / 2 + const yWidth = singY === 0 ? 0 : (singY * currentRoof.attributes.width) / 2 + + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: midX + xWidth, + y2: midY + yWidth, + }) + }) + } + + if (ridgeLines.length > 0 && hipLines.length > 0) { + console.log('currentRoof : ', currentRoof.attributes.ridgeCoordinate) + hipLines.forEach((hip) => { + const jerkinHeadLine = new QLine([hip.x2, hip.y2, currentRoof.attributes.ridgeCoordinate.x1, currentRoof.attributes.ridgeCoordinate.y1], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'jerkinHeadLine', + }) + canvas?.add(jerkinHeadLine) + roof.innerLines.push(jerkinHeadLine) + }) + + if (hipLines.length > 1) { + const jerkinHeadLine = new QLine([hipLines[0].x2, hipLines[0].y2, hipLines[1].x2, hipLines[1].y2], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'jerkinHeadLine', + }) + canvas?.add(jerkinHeadLine) + roof.innerLines.push(jerkinHeadLine) + } + } + } +} + +const changeWallRoof = (roofId, currentRoof, canvas) => { + console.log('roofId : ', roofId) + let 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 === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) + + 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 = (wallLine[0].x1 + wallLine[0].x2) / 2 + const wallMidY = (wallLine[0].y1 + wallLine[0].y2) / 2 + const roofMidX = (currentRoof.x1 + currentRoof.x2) / 2 + const roofMidY = (currentRoof.y1 + currentRoof.y2) / 2 + + const alpha = wallMidX - roofMidX === 0 ? 0 : wallMidX - roofMidX + const beta = wallMidY - roofMidY === 0 ? 0 : wallMidY - roofMidY + + currentRoof.set({ + x1: currentRoof.x1 + alpha, + y1: currentRoof.y1 + beta, + x2: currentRoof.x2 + alpha, + y2: currentRoof.y2 + beta, + }) + + prevRoof.set({ + x1: prevRoof.x1, + y1: prevRoof.y1, + x2: prevRoof.x2 + alpha, + y2: prevRoof.y2 + beta, + }) + + nextRoof.set({ + x1: nextRoof.x1 + alpha, + y1: nextRoof.y1 + beta, + x2: nextRoof.x2, + y2: nextRoof.y2, + }) + + 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 = ridge.x1 - wallMidX === 0 ? 0 : ridge.x1 - wallMidX + const diffY = ridge.y1 - wallMidY === 0 ? 0 : ridge.y1 - wallMidY + + ridge.set({ + x1: ridge.x1 - diffX, + y1: ridge.y1 - diffY, + x2: ridge.x2, + y2: ridge.y2, + }) + } + if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { + const diffX = ridge.x2 - wallMidX === 0 ? 0 : ridge.x2 - wallMidX + const diffY = ridge.y2 - wallMidY === 0 ? 0 : ridge.y2 - wallMidY + + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: ridge.x2 - diffX, + y2: ridge.y2 - diffY, + }) + } + } + + console.log('hipLines : ', hipLines) + if (hipLines.length > 0) { + hipLines.forEach((hip) => { + const diffX = hip.x1 - wallMidX + const diffY = hip.y1 - wallMidY + console.log('diffX : ', diffX, ' diffY : ', diffY) + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: wallMidX, + y2: wallMidY, + }) + }) } } export const changeAllHipAndGableRoof = (polygon, offset, canvas) => { - const roof = polygon.filter((p) => p.name === 'roofBase')[0] // 지붕 + const roof = polygon.filter((p) => p.name === 'roof')[0] // 지붕 const roofLines = roof.lines // 지붕의 라인 const ridges = roof.ridges // 마루의 라인 const hips = roof.hips // 추녀마루의 라인 @@ -2983,6 +2850,43 @@ const setHipAndGableRoof = (roof, ridge, hip1, hip2, offset, canvas) => { return gableLine } +/** + * 지붕을 변경한다. + * @param polygon + * @param canvas + */ +const reDrawPolygon = (polygon, canvas) => { + const lines = polygon.lines + let point = [] + lines.forEach((line) => point.push({ x: line.x1, y: line.y1 })) + + console.log('point : ', point) + + const newPolygon = new QPolygon(point, { + id: polygon.id, + name: polygon.name, + fill: polygon.fill, + stroke: polygon.stroke, + strokeWidth: polygon.strokeWidth, + selectable: polygon.selectable, + fontSize: polygon.fontSize, + wall: polygon.wall !== undefined ? polygon.wall : null, + }) + + const newLines = newPolygon.lines + + newLines.forEach((line, index) => { + lines.forEach((l, i) => { + if (index === i) { + line.id = l.id + line.attributes = l.attributes + } + }) + }) + canvas?.add(newPolygon) + canvas?.remove(polygon) +} + function arePointsEqual(point1, point2) { return point1.x === point2.x && point1.y === point2.y }