diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 475d2ae6..e0175551 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -806,8 +806,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { let { x1, y1, x2, y2 } = currentLine - if (currentAngle !== prevAngle) { - if (currentAngle === nextAngle) { + if (currentAngle !== prevAngle || (currentAngle === prevAngle && currentLine.attributes.type !== prevLine.attributes.type)) { + if (currentAngle === nextAngle && currentLine.attributes.type === nextLine.attributes.type) { let nextIndex = baseLines.findIndex((line) => line === nextLine) while (nextIndex !== index) { const checkNextLine = baseLines[(nextIndex + 1 + baseLines.length) % baseLines.length] @@ -825,6 +825,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } }) + console.log('drawBaseLines : ', drawBaseLines) + /** baseLine을 기준으로 확인용 polygon 작성 */ const checkWallPolygon = new QPolygon(baseLinePoints, {}) @@ -1020,350 +1022,399 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const currentMidX = Big(x1).plus(Big(x2)).div(2).plus(Big(prevVectorX).times(currentLine.attributes.offset)) const currentMidY = Big(y1).plus(Big(y2)).div(2).plus(Big(prevVectorY).times(currentLine.attributes.offset)) - if (beforePrevBaseLine === afterNextBaseLine) { - const afterNextMidX = Big(afterNextLine.x1).plus(Big(afterNextLine.x2)).div(2) - const afterNextMidY = Big(afterNextLine.y1).plus(Big(afterNextLine.y2)).div(2) - const vectorMidX = Math.sign(currentMidX.minus(afterNextMidX)) - const vectorMidY = Math.sign(currentMidY.minus(afterNextMidY)) + /** 마루 반대 좌표*/ + let oppositeMidX = currentMidX, + oppositeMidY = currentMidY - let oppositeMidX, oppositeMidY - if (eavesType.includes(afterNextLine.attributes?.type)) { - const checkSize = currentMidX - .minus(afterNextMidX) - .pow(2) - .plus(currentMidY.minus(afterNextMidY).pow(2)) - .sqrt() - .minus(Big(afterNextLine.attributes.planeSize).div(20)) - .round(1) - oppositeMidX = currentMidX.plus(checkSize.times(vectorMidX).neg()) - oppositeMidY = currentMidY.plus(checkSize.times(vectorMidY).neg()) + if (prevAngle === beforePrevAngle || nextAngle === afterNextAngle) { + console.log('지붕선 분할 : start') + const checkLine1 = new fabric.Line([prevLine.x1, prevLine.y1, prevLine.x2, prevLine.y2], { + stroke: 'red', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + const checkLine2 = new fabric.Line([nextLine.x1, nextLine.y1, nextLine.x2, nextLine.y2], { + stroke: 'blue', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + const checkPoint = new fabric.Circle({ + left: currentMidX.toNumber(), + top: currentMidY.toNumber(), + radius: 5, + fill: 'red', + parentId: roofId, + name: 'checkPoint', + }) + canvas.add(checkLine1) + canvas.add(checkLine2) + canvas.add(checkPoint) + canvas.renderAll() - const xVector1 = Math.sign(Big(oppositeMidX).minus(Big(afterNextLine.x1)).neg().toNumber()) - const yVector1 = Math.sign(Big(oppositeMidY).minus(Big(afterNextLine.y1)).neg().toNumber()) - const xVector2 = Math.sign(Big(oppositeMidX).minus(Big(afterNextLine.x2)).neg().toNumber()) - const yVector2 = Math.sign(Big(oppositeMidY).minus(Big(afterNextLine.y2)).neg().toNumber()) + if (currentVectorX === 0) { + } else { + } - let addOppositeX1 = 0, - addOppositeY1 = 0, - addOppositeX2 = 0, - addOppositeY2 = 0 + console.log('지붕선 분할 : end') + } else { + if (beforePrevBaseLine === afterNextBaseLine) { + const afterNextMidX = Big(afterNextLine.x1).plus(Big(afterNextLine.x2)).div(2) + const afterNextMidY = Big(afterNextLine.y1).plus(Big(afterNextLine.y2)).div(2) + const vectorMidX = Math.sign(currentMidX.minus(afterNextMidX)) + const vectorMidY = Math.sign(currentMidY.minus(afterNextMidY)) - if (!checkWallPolygon.inPolygon({ x: oppositeMidX.toNumber(), y: oppositeMidY.toNumber() })) { - const checkScale = currentMidX.minus(oppositeMidX).pow(2).plus(currentMidY.minus(oppositeMidY).pow(2)).sqrt() - addOppositeX1 = checkScale.times(xVector1).toNumber() - addOppositeY1 = checkScale.times(yVector1).toNumber() - addOppositeX2 = checkScale.times(xVector2).toNumber() - addOppositeY2 = checkScale.times(yVector2).toNumber() - } + let oppositeMidX, oppositeMidY + if (eavesType.includes(afterNextLine.attributes?.type)) { + const checkSize = currentMidX + .minus(afterNextMidX) + .pow(2) + .plus(currentMidY.minus(afterNextMidY).pow(2)) + .sqrt() + .minus(Big(afterNextLine.attributes.planeSize).div(20)) + .round(1) + oppositeMidX = currentMidX.plus(checkSize.times(vectorMidX).neg()) + oppositeMidY = currentMidY.plus(checkSize.times(vectorMidY).neg()) - let scale1 = Big(afterNextLine.attributes.offset).pow(2).plus(Big(nextLine.attributes.offset).pow(2)).sqrt() - scale1 = scale1.eq(0) ? Big(1) : scale1 - let scale2 = Big(afterNextLine.attributes.offset).pow(2).plus(Big(prevLine.attributes.offset).pow(2)).sqrt() - scale2 = scale2.eq(0) ? Big(1) : scale2 + const xVector1 = Math.sign(Big(oppositeMidX).minus(Big(afterNextLine.x1)).neg().toNumber()) + const yVector1 = Math.sign(Big(oppositeMidY).minus(Big(afterNextLine.y1)).neg().toNumber()) + const xVector2 = Math.sign(Big(oppositeMidX).minus(Big(afterNextLine.x2)).neg().toNumber()) + const yVector2 = Math.sign(Big(oppositeMidY).minus(Big(afterNextLine.y2)).neg().toNumber()) - const checkHip1 = { - x1: Big(afterNextLine.x1).plus(scale1.times(xVector1)).toNumber(), - y1: Big(afterNextLine.y1).plus(scale1.times(yVector1)).toNumber(), - x2: oppositeMidX.plus(addOppositeX1).toNumber(), - y2: oppositeMidY.plus(addOppositeY1).toNumber(), - } + let addOppositeX1 = 0, + addOppositeY1 = 0, + addOppositeX2 = 0, + addOppositeY2 = 0 - const checkHip2 = { - x1: Big(afterNextLine.x2).plus(scale2.times(xVector2)).toNumber(), - y1: Big(afterNextLine.y2).plus(scale2.times(yVector2)).toNumber(), - x2: oppositeMidX.plus(addOppositeX2).toNumber(), - y2: oppositeMidY.plus(addOppositeY2).toNumber(), - } + if (!checkWallPolygon.inPolygon({ x: oppositeMidX.toNumber(), y: oppositeMidY.toNumber() })) { + const checkScale = currentMidX.minus(oppositeMidX).pow(2).plus(currentMidY.minus(oppositeMidY).pow(2)).sqrt() + addOppositeX1 = checkScale.times(xVector1).toNumber() + addOppositeY1 = checkScale.times(yVector1).toNumber() + addOppositeX2 = checkScale.times(xVector2).toNumber() + addOppositeY2 = checkScale.times(yVector2).toNumber() + } - const intersection1 = findRoofIntersection(roof, checkHip1, { x: oppositeMidX.plus(addOppositeX1), y: oppositeMidY.plus(addOppositeY1) }) - const intersection2 = findRoofIntersection(roof, checkHip2, { x: oppositeMidX.plus(addOppositeX2), y: oppositeMidY.plus(addOppositeY2) }) + let scale1 = Big(afterNextLine.attributes.offset).pow(2).plus(Big(nextLine.attributes.offset).pow(2)).sqrt() + scale1 = scale1.eq(0) ? Big(1) : scale1 + let scale2 = Big(afterNextLine.attributes.offset).pow(2).plus(Big(prevLine.attributes.offset).pow(2)).sqrt() + scale2 = scale2.eq(0) ? Big(1) : scale2 - const afterNextDegree = afterNextLine.attributes.pitch > 0 ? getDegreeByChon(afterNextLine.attributes.pitch) : afterNextLine.attributes.degree - - if (intersection1) { - const hipLine = drawHipLine( - [intersection1.intersection.x, intersection1.intersection.y, oppositeMidX.plus(addOppositeX1), oppositeMidY.plus(addOppositeY1)], - canvas, - roof, - textMode, - null, - nextDegree, - afterNextDegree, - ) - baseHipLines.push({ - x1: afterNextLine.x1, - y1: afterNextLine.y1, + const checkHip1 = { + x1: Big(afterNextLine.x1).plus(scale1.times(xVector1)).toNumber(), + y1: Big(afterNextLine.y1).plus(scale1.times(yVector1)).toNumber(), x2: oppositeMidX.plus(addOppositeX1).toNumber(), y2: oppositeMidY.plus(addOppositeY1).toNumber(), - line: hipLine, - }) + } + + const checkHip2 = { + x1: Big(afterNextLine.x2).plus(scale2.times(xVector2)).toNumber(), + y1: Big(afterNextLine.y2).plus(scale2.times(yVector2)).toNumber(), + x2: oppositeMidX.plus(addOppositeX2).toNumber(), + y2: oppositeMidY.plus(addOppositeY2).toNumber(), + } + + const intersection1 = findRoofIntersection(roof, checkHip1, { x: oppositeMidX.plus(addOppositeX1), y: oppositeMidY.plus(addOppositeY1) }) + const intersection2 = findRoofIntersection(roof, checkHip2, { x: oppositeMidX.plus(addOppositeX2), y: oppositeMidY.plus(addOppositeY2) }) + + const afterNextDegree = + afterNextLine.attributes.pitch > 0 ? getDegreeByChon(afterNextLine.attributes.pitch) : afterNextLine.attributes.degree + + if (intersection1) { + const hipLine = drawHipLine( + [intersection1.intersection.x, intersection1.intersection.y, oppositeMidX.plus(addOppositeX1), oppositeMidY.plus(addOppositeY1)], + canvas, + roof, + textMode, + null, + nextDegree, + afterNextDegree, + ) + baseHipLines.push({ + x1: afterNextLine.x1, + y1: afterNextLine.y1, + x2: oppositeMidX.plus(addOppositeX1).toNumber(), + y2: oppositeMidY.plus(addOppositeY1).toNumber(), + line: hipLine, + }) + } + if (intersection2) { + const hipLine = drawHipLine( + [intersection2.intersection.x, intersection2.intersection.y, oppositeMidX.plus(addOppositeX2), oppositeMidY.plus(addOppositeY2)], + canvas, + roof, + textMode, + null, + prevDegree, + afterNextDegree, + ) + baseHipLines.push({ + x1: afterNextLine.x2, + y1: afterNextLine.y2, + x2: oppositeMidX.plus(addOppositeX2).toNumber(), + y2: oppositeMidY.plus(addOppositeY2).toNumber(), + line: hipLine, + }) + } + } else { + oppositeMidX = Big(afterNextLine.x1).plus(Big(afterNextLine.x2)).div(2).plus(Big(prevVectorX).neg().times(afterNextLine.attributes.offset)) + oppositeMidY = Big(afterNextLine.y1).plus(Big(afterNextLine.y2)).div(2).plus(Big(prevVectorY).neg().times(afterNextLine.attributes.offset)) } - if (intersection2) { - const hipLine = drawHipLine( - [intersection2.intersection.x, intersection2.intersection.y, oppositeMidX.plus(addOppositeX2), oppositeMidY.plus(addOppositeY2)], + + const vectorOppositeX = Math.sign(currentMidX.minus(oppositeMidX)) + const vectorOppositeY = Math.sign(currentMidY.minus(oppositeMidY)) + + if (vectorMidX === vectorOppositeX && vectorMidY === vectorOppositeY && baseRidgeCount < getMaxRidge(baseLines.length)) { + const ridge = drawRidgeLine( + [currentMidX.toNumber(), currentMidY.toNumber(), oppositeMidX.toNumber(), oppositeMidY.toNumber()], canvas, roof, textMode, - null, - prevDegree, - afterNextDegree, ) - baseHipLines.push({ - x1: afterNextLine.x2, - y1: afterNextLine.y2, - x2: oppositeMidX.plus(addOppositeX2).toNumber(), - y2: oppositeMidY.plus(addOppositeY2).toNumber(), - line: hipLine, - }) + baseGableRidgeLines.push(ridge) + baseRidgeCount++ } } else { - oppositeMidX = Big(afterNextLine.x1).plus(Big(afterNextLine.x2)).div(2).plus(Big(prevVectorX).neg().times(afterNextLine.attributes.offset)) - oppositeMidY = Big(afterNextLine.y1).plus(Big(afterNextLine.y2)).div(2).plus(Big(prevVectorY).neg().times(afterNextLine.attributes.offset)) - } + const vectorMidX = Math.sign(Big(nextLine.x2).minus(nextLine.x1)) + const vectorMidY = Math.sign(Big(nextLine.y2).minus(nextLine.y1)) - const vectorOppositeX = Math.sign(currentMidX.minus(oppositeMidX)) - const vectorOppositeY = Math.sign(currentMidY.minus(oppositeMidY)) + let prevOppositeMidX, prevOppositeMidY, nextOppositeMidX, nextOppositeMidY + const beforePrevOffset = + currentAngle === beforePrevAngle + ? Big(beforePrevLine.attributes.offset) + : Big(beforePrevLine.attributes.offset).plus(currentLine.attributes.offset) + const afterNextOffset = + currentAngle === afterNextAngle + ? Big(afterNextLine.attributes.offset) + : Big(afterNextLine.attributes.offset).plus(currentLine.attributes.offset) + const prevSize = Big(prevLine.attributes.planeSize).div(10) + const nextSize = Big(nextLine.attributes.planeSize).div(10) - if (vectorMidX === vectorOppositeX && vectorMidY === vectorOppositeY && 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)) - const vectorMidY = Math.sign(Big(nextLine.y2).minus(nextLine.y1)) - let oppositeMidX = currentMidX, - oppositeMidY = currentMidY - let prevOppositeMidX, prevOppositeMidY, nextOppositeMidX, nextOppositeMidY - const beforePrevOffset = - currentAngle === beforePrevAngle - ? Big(beforePrevLine.attributes.offset) - : Big(beforePrevLine.attributes.offset).plus(currentLine.attributes.offset) - const afterNextOffset = - currentAngle === afterNextAngle - ? Big(afterNextLine.attributes.offset) - : Big(afterNextLine.attributes.offset).plus(currentLine.attributes.offset) - const prevSize = Big(prevLine.attributes.planeSize).div(10) - const nextSize = Big(nextLine.attributes.planeSize).div(10) + let prevHipCoords, nextHipCoords - let prevHipCoords, nextHipCoords + /** 다음 라인이 그 다음 라인과의 사이에 추녀마루가 존재 하는지 확인. 처마-처마 인 경우 추녀마루*/ + if (eavesType.includes(afterNextLine.attributes?.type)) { + /** 현재 라인의 길이를 기준으로 추녀 마루의 길이를 삼각함수를 사용하여 판단한다.*/ + let hipLength = Big(size).div(10).div(2).pow(2).plus(Big(size).div(10).div(2).pow(2)).sqrt() - /** 다음 라인이 그 다음 라인과의 사이에 추녀마루가 존재 하는지 확인. 처마-처마 인 경우 추녀마루*/ - if (eavesType.includes(afterNextLine.attributes?.type)) { - /** 현재 라인의 길이를 기준으로 추녀 마루의 길이를 삼각함수를 사용하여 판단한다.*/ - let hipLength = Big(size).div(10).div(2).pow(2).plus(Big(size).div(10).div(2).pow(2)).sqrt() + const nextHalfVector = getHalfAngleVector(nextLine, afterNextLine) + let nextHipVector = { x: nextHalfVector.x, y: nextHalfVector.y } - const nextHalfVector = getHalfAngleVector(nextLine, afterNextLine) - let nextHipVector = { x: nextHalfVector.x, y: nextHalfVector.y } + /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const nextCheckPoint = { + x: Big(nextLine.x2).plus(Big(nextHalfVector.x).times(10)), + y: Big(nextLine.y2).plus(Big(nextHalfVector.y).times(10)), + } + if (!checkWallPolygon.inPolygon(nextCheckPoint)) { + nextHipVector = { x: Big(nextHipVector.x).neg().toNumber(), y: Big(nextHipVector.y).neg().toNumber() } + } - /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ - const nextCheckPoint = { - x: Big(nextLine.x2).plus(Big(nextHalfVector.x).times(10)), - y: Big(nextLine.y2).plus(Big(nextHalfVector.y).times(10)), - } - if (!checkWallPolygon.inPolygon(nextCheckPoint)) { - nextHipVector = { x: Big(nextHipVector.x).neg().toNumber(), y: Big(nextHipVector.y).neg().toNumber() } - } + const nextEndPoint = { + x: Big(nextLine.x2).plus(Big(nextHipVector.x).times(hipLength)), + y: Big(nextLine.y2).plus(Big(nextHipVector.y).times(hipLength)), + } - const nextEndPoint = { - x: Big(nextLine.x2).plus(Big(nextHipVector.x).times(hipLength)), - y: Big(nextLine.y2).plus(Big(nextHipVector.y).times(hipLength)), - } - - let ridgeEdge = { - vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, - vertex2: { - x: currentMidX.plus(Big(nextVectorX).times(nextBaseLine.size)).toNumber(), - y: currentMidY.plus(Big(nextVectorY).times(nextBaseLine.size)).toNumber(), - }, - } - let hipEdge = { vertex1: { x: nextLine.x2, y: nextLine.y2 }, vertex2: { x: nextEndPoint.x, y: nextEndPoint.y } } - let intersection = edgesIntersection(ridgeEdge, hipEdge) - if (intersection) { - nextHipCoords = { x1: nextLine.x2, y1: nextLine.y2, x2: intersection.x, y2: intersection.y } - nextOppositeMidY = Big(intersection.y) - nextOppositeMidX = Big(intersection.x) - } - } else { - if (vectorMidX === 0) { - nextOppositeMidY = currentMidY.plus(nextSize.plus(afterNextOffset).times(vectorMidY)) - nextOppositeMidX = currentMidX + let ridgeEdge = { + vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + vertex2: { + x: currentMidX.plus(Big(nextVectorX).times(nextBaseLine.size)).toNumber(), + y: currentMidY.plus(Big(nextVectorY).times(nextBaseLine.size)).toNumber(), + }, + } + let hipEdge = { vertex1: { x: nextLine.x2, y: nextLine.y2 }, vertex2: { x: nextEndPoint.x, y: nextEndPoint.y } } + let intersection = edgesIntersection(ridgeEdge, hipEdge) + if (intersection) { + nextHipCoords = { x1: nextLine.x2, y1: nextLine.y2, x2: intersection.x, y2: intersection.y } + nextOppositeMidY = Big(intersection.y) + nextOppositeMidX = Big(intersection.x) + } } else { - nextOppositeMidX = currentMidX.plus(nextSize.plus(afterNextOffset).times(vectorMidX)) - nextOppositeMidY = currentMidY - } - } - - /** 이전 라인이 그 이전 라인과의 사이에 추녀마루가 존재 하는지 확인. 처마-처마 인 경우 추녀마루*/ - if (eavesType.includes(beforePrevLine.attributes?.type)) { - /** 현재 라인의 길이를 기준으로 추녀 마루의 길이를 삼각함수를 사용하여 판단한다.*/ - let hipLength = Big(size).div(10).div(2).pow(2).plus(Big(size).div(10).div(2).pow(2)).sqrt() - - const prevHalfVector = getHalfAngleVector(prevLine, beforePrevLine) - let prevHipVector = { x: prevHalfVector.x, y: prevHalfVector.y } - - /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ - const prevCheckPoint = { - x: Big(prevLine.x1).plus(Big(prevHalfVector.x).times(10)), - y: Big(prevLine.y1).plus(Big(prevHalfVector.y).times(10)), - } - - if (!checkWallPolygon.inPolygon(prevCheckPoint)) { - prevHipVector = { x: Big(prevHipVector.x).neg().toNumber(), y: Big(prevHipVector.y).neg().toNumber() } - } - - const prevEndPoint = { - x: Big(prevLine.x1).plus(Big(prevHipVector.x).times(hipLength)), - y: Big(prevLine.y1).plus(Big(prevHipVector.y).times(hipLength)), - } - - let ridgeEdge = { - vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, - vertex2: { - x: currentMidX.plus(Big(prevVectorX).times(prevBaseLine.size)).toNumber(), - y: currentMidY.plus(Big(prevVectorY).times(prevBaseLine.size)).toNumber(), - }, - } - let hipEdge = { vertex1: { x: prevLine.x1, y: prevLine.y1 }, vertex2: { x: prevEndPoint.x, y: prevEndPoint.y } } - let intersection = edgesIntersection(ridgeEdge, hipEdge) - if (intersection) { - prevHipCoords = { x1: prevLine.x1, y1: prevLine.y1, x2: intersection.x, y2: intersection.y } - prevOppositeMidY = Big(intersection.y) - prevOppositeMidX = Big(intersection.x) - } - } else { - if (vectorMidX === 0) { - prevOppositeMidY = currentMidY.plus(prevSize.plus(beforePrevOffset).times(vectorMidY)) - prevOppositeMidX = currentMidX - } else { - prevOppositeMidX = currentMidX.plus(prevSize.plus(beforePrevOffset).times(vectorMidX)) - prevOppositeMidY = currentMidY - } - } - const checkPrevSize = currentMidX.minus(prevOppositeMidX).pow(2).plus(currentMidY.minus(prevOppositeMidY).pow(2)).sqrt() - const checkNextSize = currentMidX.minus(nextOppositeMidX).pow(2).plus(currentMidY.minus(nextOppositeMidY).pow(2)).sqrt() - - /** 두 포인트 중에 current와 가까운 포인트를 사용*/ - if (checkPrevSize.gt(checkNextSize)) { - if (nextHipCoords) { - let intersectPoints = [] - const hipEdge = { vertex1: { x: nextHipCoords.x2, y: nextHipCoords.y2 }, vertex2: { x: nextHipCoords.x1, y: nextHipCoords.y1 } } - - /** 외벽선에서 라인 겹치는 경우에 대한 확인*/ - roof.lines.forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const intersection = edgesIntersection(hipEdge, lineEdge) - if ( - intersection && - Math.sign(nextHipCoords.x2 - nextHipCoords.x1) === Math.sign(nextHipCoords.x2 - intersection.x) && - Math.sign(nextHipCoords.y2 - nextHipCoords.y1) === Math.sign(nextHipCoords.y2 - intersection.y) - ) { - const intersectEdge = { vertex1: { x: nextHipCoords.x2, y: nextHipCoords.y2 }, vertex2: { x: intersection.x, y: intersection.y } } - const is = edgesIntersection(intersectEdge, lineEdge) - if (!is.isIntersectionOutside) { - const intersectSize = Big(nextHipCoords.x2) - .minus(Big(intersection.x)) - .pow(2) - .plus(Big(nextHipCoords.y2).minus(Big(intersection.y)).pow(2)) - .abs() - .sqrt() - .toNumber() - - intersectPoints.push({ - intersection, - size: intersectSize, - line, - }) - } - } - }) - 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 hipLine = drawHipLine( - [intersect.intersection.x, intersect.intersection.y, nextOppositeMidX.toNumber(), nextOppositeMidY.toNumber()], - canvas, - roof, - textMode, - null, - degree, - degree, - ) - baseHipLines.push({ - x1: nextHipCoords.x1, - y1: nextHipCoords.y1, - x2: nextHipCoords.x2, - y2: nextHipCoords.y2, - line: hipLine, - }) + if (vectorMidX === 0) { + nextOppositeMidY = currentMidY.plus(nextSize.plus(afterNextOffset).times(vectorMidY)) + nextOppositeMidX = currentMidX + } else { + nextOppositeMidX = currentMidX.plus(nextSize.plus(afterNextOffset).times(vectorMidX)) + nextOppositeMidY = currentMidY } } - oppositeMidY = nextOppositeMidY - oppositeMidX = nextOppositeMidX - } else { - if (prevHipCoords) { - let intersectPoints = [] - const hipEdge = { vertex1: { x: prevHipCoords.x2, y: prevHipCoords.y2 }, vertex2: { x: prevHipCoords.x1, y: prevHipCoords.y1 } } - /** 외벽선에서 라인 겹치는 경우에 대한 확인*/ - roof.lines.forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const intersection = edgesIntersection(hipEdge, lineEdge) - if ( - intersection && - Math.sign(prevHipCoords.x2 - prevHipCoords.x1) === Math.sign(prevHipCoords.x2 - intersection.x) && - Math.sign(prevHipCoords.y2 - prevHipCoords.y1) === Math.sign(prevHipCoords.y2 - intersection.y) - ) { - const intersectEdge = { vertex1: { x: prevHipCoords.x2, y: prevHipCoords.y2 }, vertex2: { x: intersection.x, y: intersection.y } } - const is = edgesIntersection(intersectEdge, lineEdge) - if (!is.isIntersectionOutside) { - const intersectSize = Big(prevHipCoords.x2) - .minus(Big(intersection.x)) - .pow(2) - .plus(Big(prevHipCoords.y2).minus(Big(intersection.y)).pow(2)) - .abs() - .sqrt() - .toNumber() + /** 이전 라인이 그 이전 라인과의 사이에 추녀마루가 존재 하는지 확인. 처마-처마 인 경우 추녀마루*/ + if (eavesType.includes(beforePrevLine.attributes?.type)) { + /** 현재 라인의 길이를 기준으로 추녀 마루의 길이를 삼각함수를 사용하여 판단한다.*/ + let hipLength = Big(size).div(10).div(2).pow(2).plus(Big(size).div(10).div(2).pow(2)).sqrt() - intersectPoints.push({ - intersection, - size: intersectSize, - line, - }) - } - } - }) - const intersect = intersectPoints.sort((a, b) => a.size - b.size)[0] + const prevHalfVector = getHalfAngleVector(prevLine, beforePrevLine) + let prevHipVector = { x: prevHalfVector.x, y: prevHalfVector.y } - if (intersect) { - const degree = intersect.line.attributes.pitch > 0 ? getDegreeByChon(intersect.line.attributes.pitch) : intersect.line.attributes.degree - const hipLine = drawHipLine( - [intersect.intersection.x, intersect.intersection.y, prevOppositeMidX.toNumber(), prevOppositeMidY.toNumber()], - canvas, - roof, - textMode, - null, - degree, - degree, - ) - baseHipLines.push({ - x1: prevHipCoords.x1, - y1: prevHipCoords.y1, - x2: prevHipCoords.x2, - y2: prevHipCoords.y2, - line: hipLine, - }) + /** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/ + const prevCheckPoint = { + x: Big(prevLine.x1).plus(Big(prevHalfVector.x).times(10)), + y: Big(prevLine.y1).plus(Big(prevHalfVector.y).times(10)), + } + + if (!checkWallPolygon.inPolygon(prevCheckPoint)) { + prevHipVector = { x: Big(prevHipVector.x).neg().toNumber(), y: Big(prevHipVector.y).neg().toNumber() } + } + + const prevEndPoint = { + x: Big(prevLine.x1).plus(Big(prevHipVector.x).times(hipLength)), + y: Big(prevLine.y1).plus(Big(prevHipVector.y).times(hipLength)), + } + + let ridgeEdge = { + vertex1: { x: currentMidX.toNumber(), y: currentMidY.toNumber() }, + vertex2: { + x: currentMidX.plus(Big(prevVectorX).times(prevBaseLine.size)).toNumber(), + y: currentMidY.plus(Big(prevVectorY).times(prevBaseLine.size)).toNumber(), + }, + } + let hipEdge = { vertex1: { x: prevLine.x1, y: prevLine.y1 }, vertex2: { x: prevEndPoint.x, y: prevEndPoint.y } } + let intersection = edgesIntersection(ridgeEdge, hipEdge) + if (intersection) { + prevHipCoords = { x1: prevLine.x1, y1: prevLine.y1, x2: intersection.x, y2: intersection.y } + prevOppositeMidY = Big(intersection.y) + prevOppositeMidX = Big(intersection.x) + } + } else { + if (vectorMidX === 0) { + prevOppositeMidY = currentMidY.plus(prevSize.plus(beforePrevOffset).times(vectorMidY)) + prevOppositeMidX = currentMidX + } else { + prevOppositeMidX = currentMidX.plus(prevSize.plus(beforePrevOffset).times(vectorMidX)) + prevOppositeMidY = currentMidY } } - oppositeMidY = prevOppositeMidY - oppositeMidX = prevOppositeMidX - } + const checkPrevSize = currentMidX.minus(prevOppositeMidX).pow(2).plus(currentMidY.minus(prevOppositeMidY).pow(2)).sqrt() + const checkNextSize = currentMidX.minus(nextOppositeMidX).pow(2).plus(currentMidY.minus(nextOppositeMidY).pow(2)).sqrt() + /** 두 포인트 중에 current와 가까운 포인트를 사용*/ + if (checkPrevSize.gt(checkNextSize)) { + if (nextHipCoords) { + let intersectPoints = [] + const hipEdge = { + vertex1: { x: nextHipCoords.x2, y: nextHipCoords.y2 }, + vertex2: { x: nextHipCoords.x1, y: nextHipCoords.y1 }, + } + + /** 외벽선에서 라인 겹치는 경우에 대한 확인*/ + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(hipEdge, lineEdge) + if ( + intersection && + Math.sign(nextHipCoords.x2 - nextHipCoords.x1) === Math.sign(nextHipCoords.x2 - intersection.x) && + Math.sign(nextHipCoords.y2 - nextHipCoords.y1) === Math.sign(nextHipCoords.y2 - intersection.y) + ) { + const intersectEdge = { + vertex1: { x: nextHipCoords.x2, y: nextHipCoords.y2 }, + vertex2: { x: intersection.x, y: intersection.y }, + } + const is = edgesIntersection(intersectEdge, lineEdge) + if (!is.isIntersectionOutside) { + const intersectSize = Big(nextHipCoords.x2) + .minus(Big(intersection.x)) + .pow(2) + .plus(Big(nextHipCoords.y2).minus(Big(intersection.y)).pow(2)) + .abs() + .sqrt() + .toNumber() + + intersectPoints.push({ + intersection, + size: intersectSize, + line, + }) + } + } + }) + 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 hipLine = drawHipLine( + [intersect.intersection.x, intersect.intersection.y, nextOppositeMidX.toNumber(), nextOppositeMidY.toNumber()], + canvas, + roof, + textMode, + null, + degree, + degree, + ) + baseHipLines.push({ + x1: nextHipCoords.x1, + y1: nextHipCoords.y1, + x2: nextHipCoords.x2, + y2: nextHipCoords.y2, + line: hipLine, + }) + } + } + oppositeMidY = nextOppositeMidY + oppositeMidX = nextOppositeMidX + } else { + if (prevHipCoords) { + let intersectPoints = [] + const hipEdge = { + vertex1: { x: prevHipCoords.x2, y: prevHipCoords.y2 }, + vertex2: { x: prevHipCoords.x1, y: prevHipCoords.y1 }, + } + + /** 외벽선에서 라인 겹치는 경우에 대한 확인*/ + roof.lines.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersection = edgesIntersection(hipEdge, lineEdge) + if ( + intersection && + Math.sign(prevHipCoords.x2 - prevHipCoords.x1) === Math.sign(prevHipCoords.x2 - intersection.x) && + Math.sign(prevHipCoords.y2 - prevHipCoords.y1) === Math.sign(prevHipCoords.y2 - intersection.y) + ) { + const intersectEdge = { + vertex1: { x: prevHipCoords.x2, y: prevHipCoords.y2 }, + vertex2: { x: intersection.x, y: intersection.y }, + } + const is = edgesIntersection(intersectEdge, lineEdge) + if (!is.isIntersectionOutside) { + const intersectSize = Big(prevHipCoords.x2) + .minus(Big(intersection.x)) + .pow(2) + .plus(Big(prevHipCoords.y2).minus(Big(intersection.y)).pow(2)) + .abs() + .sqrt() + .toNumber() + + intersectPoints.push({ + intersection, + size: intersectSize, + line, + }) + } + } + }) + 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 hipLine = drawHipLine( + [intersect.intersection.x, intersect.intersection.y, prevOppositeMidX.toNumber(), prevOppositeMidY.toNumber()], + canvas, + roof, + textMode, + null, + degree, + degree, + ) + baseHipLines.push({ + x1: prevHipCoords.x1, + y1: prevHipCoords.y1, + x2: prevHipCoords.x2, + y2: prevHipCoords.y2, + line: hipLine, + }) + } + } + oppositeMidY = prevOppositeMidY + oppositeMidX = prevOppositeMidX + } + } if (baseRidgeCount < getMaxRidge(baseLines.length)) { /** 마루가 맞은편 외벽선에 닿는 경우 해당 부분까지로 한정한다. */ const ridgeEdge = { @@ -2415,9 +2466,6 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } else { if (currentAngle !== beforePrevAngle && currentAngle !== afterNextAngle && beforePrevLine !== afterNextLine) { console.log('4각 아님') - // console.log('currentLine : ', currentLine.attributes.planeSize) - // console.log('beforePrevLine : ', beforePrevLine) - // console.log('afterNextLine : ', afterNextLine) const beforePrevX1 = beforePrevLine.x1, beforePrevY1 = beforePrevLine.y1, beforePrevX2 = beforePrevLine.x2, @@ -2692,6 +2740,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { /** 겹치는 외벽선이 있을때 추녀마루를 외벽선 까지 늘려서 수정*/ if (intersectPoints && intersectPoints.intersection) { + console.log('prevDegree', prevDegree, 'currentDegree', currentDegree) + prevHipLine = drawHipLine( [intersectPoints.intersection.x, intersectPoints.intersection.y, prevEndPoint.x.toNumber(), prevEndPoint.y.toNumber()], canvas, @@ -2788,8 +2838,53 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } } - // console.log('prevHipLine : ', prevHipLine) - // console.log('nextHipLine : ', nextHipLine) + console.log('prevHipLine : ', prevHipLine) + console.log('nextHipLine : ', nextHipLine) + /** 두 선이 교차하면 해당 포인트까지로 선 조정*/ + if (prevHipLine !== undefined && nextHipLine !== undefined) { + const prevEdge = { vertex1: { x: prevHipLine.x1, y: prevHipLine.y1 }, vertex2: { x: prevHipLine.x2, y: prevHipLine.y2 } } + const nextEdge = { vertex1: { x: nextHipLine.x1, y: nextHipLine.y1 }, vertex2: { x: nextHipLine.x2, y: nextHipLine.y2 } } + const intersection = edgesIntersection(prevEdge, nextEdge) + console.log('intersection : ', intersection) + if (intersection) { + const checkPoint = new fabric.Circle({ + left: intersection.x, + top: intersection.y, + radius: 4, + fill: 'yellow', + parentId: roofId, + name: 'checkPoint', + }) + canvas.add(checkPoint) + canvas.renderAll() + + /** 포인트 조정*/ + baseHipLines + .filter((line) => line.line === prevHipLine || line.line === nextHipLine) + .forEach((line) => { + line.x2 = intersection.x + line.y2 = intersection.y + line.line.set({ x2: intersection.x, y2: intersection.y }) + }) + prevHipLine.x2 = intersection.x + prevHipLine.y2 = intersection.y + const prevSize = reCalculateSize(prevHipLine) + + prevHipLine.attributes.planeSize = prevSize.planeSize + prevHipLine.attributes.actualSize = prevSize.actualSize + prevHipLine.fire('modified') + + nextHipLine.x2 = intersection.x + nextHipLine.y2 = intersection.y + const nextSize = reCalculateSize(nextHipLine) + + nextHipLine.attributes.planeSize = nextSize.planeSize + nextHipLine.attributes.actualSize = nextSize.actualSize + nextHipLine.fire('modified') + canvas.renderAll() + } + } + /** 두 추녀마루가 한점에서 만나는 경우 해당 점을 기점으로 마루를 작성한다.*/ if ( prevHipLine !== undefined && @@ -2797,34 +2892,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { Big(prevHipLine.x2).minus(Big(nextHipLine.x2)).abs().lte(1) && Big(prevHipLine.y2).minus(Big(nextHipLine.y2)).abs().lte(1) ) { - console.log('마루 작성') const startPoint = { x: prevHipLine.x2, y: prevHipLine.y2 } - - // 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 checkLength = Big(maxX) - .minus(Big(minX)) - .pow(2) - .plus(Big(maxY).minus(Big(minY)).pow(2)) - .sqrt() + let ridgeSize = 0 const currentMidX = Big(currentLine.x2).plus(Big(currentLine.x1)).div(2) const currentMidY = Big(currentLine.y2).plus(Big(currentLine.y1)).div(2) @@ -2832,130 +2901,192 @@ 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) - 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))), - }, - } - - const checkLine = new fabric.Line([checkEdges.vertex1.x, checkEdges.vertex1.y, checkEdges.vertex2.x, checkEdges.vertex2.y], { - stroke: 'purple', - strokeWidth: 2, - parentId: roof.id, - name: 'checkLine', - }) - canvas.add(checkLine) - canvas.renderAll() - - /** 맞은편 벽 까지의 길이 판단을 위한 교차되는 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, index) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const intersection = edgesIntersection(checkEdges, lineEdge) + console.log('beforePrevLine', beforePrevLine) + if (gableType.includes(beforePrevLine.line.attributes.type) || gableType.includes(afterNextLine.line.attributes.type)) { + console.log('박공지붕 확인 후 마루 작성 ') + const oppositeLine = gableType.includes(beforePrevLine.line.attributes.type) ? beforePrevLine.line : afterNextLine.line + const oppositeAngle = calculateAngle(oppositeLine.startPoint, oppositeLine.endPoint) + console.log('currentAngle', currentAngle, 'oppositeAngle', oppositeAngle) + 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 (currentAngle === oppositeAngle) { + const oppositeEdge = { vertex1: { x: oppositeLine.x1, y: oppositeLine.y1 }, vertex2: { x: oppositeLine.x2, y: oppositeLine.y2 } } + const intersection = edgesIntersection(oppositeEdge, checkEdge) + console.log('intersection', intersection) if (intersection) { - /* const intersectPoint = new fabric.Circle({ - left: intersection.x - 2, - top: intersection.y - 2, - radius: 4, - fill: 'green', - parentId: roof.id, + ridgeSize = Big(intersection.x) + .minus(Big(startPoint.x)) + .pow(2) + .plus(Big(intersection.y).minus(Big(startPoint.y)).pow(2)) + .sqrt() + } + console.log('aaa') + } 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) + console.log('intersection', intersection) + if (intersection) { + const checkPoint = new fabric.Circle({ + left: intersection.x, + top: intersection.y, + radius: 4, + fill: 'red', + parentId: roofId, + name: 'checkPoint', + }) + canvas.add(checkPoint) + canvas.renderAll() + 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 }) + } }) - canvas.add(intersectPoint) - canvas.renderAll()*/ - intersectBaseLine.push({ intersection, line }) + intersectPoints.sort((a, b) => a.size - b.size) + console.log('intersectPoints', intersectPoints) + if (intersectPoints.length > 0) { + ridgeSize = Big(intersectPoints[0].size) + } + console.log('bbb') + } + } else { + console.log('마루 작성') + // 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 } }) - - // console.log('intersectBaseLine : ', intersectBaseLine) - - /** 맞은편 라인 */ - 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]) - console.log('oppositeLine : ', oppositeLine) + 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))), + }, + } - /** 맞은편 라인까지의 길이 = 전체 길이 - 현재라인의 길이 */ - const oppositeSize = oppositeLine - ? Big(oppositeLine.intersection.x) + /** 맞은편 벽 까지의 길이 판단을 위한 교차되는 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, index) => { + 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]) - // console.log('startPoint : ', startPoint, 'currentSize : ', currentSize.toNumber()) + /** 맞은편 라인까지의 길이 = 전체 길이 - 현재라인의 길이 */ + 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) + : Infinity - /** 이전, 다음 라인중 길이가 짧은 길이*/ - /*const lineMinSize = - prevLine.attributes.planeSize < nextLine.attributes.planeSize - ? Big(prevLine.attributes.planeSize).div(10) - : Big(nextLine.attributes.planeSize).div(10)*/ - const lineMinSize = prevBaseLine.size < nextBaseLine.size ? Big(prevBaseLine.size).div(10) : Big(nextBaseLine.size).div(10) + /** 이전, 다음 라인중 길이가 짧은 길이*/ + const lineMinSize = prevBaseLine.size < nextBaseLine.size ? Big(prevBaseLine.size).div(10) : Big(nextBaseLine.size).div(10) - /** 마루의 길이는 이전 다음 라인중 짧은것의 길이와 현재라인부터 맞은편 라인까지의 길이에서 현재 라인의 길이를 뺀 것중 짧은 길이 */ - const ridgeSize = Big(Math.min(oppositeSize, lineMinSize)) - - // console.log('oppositeSize : ', oppositeSize, 'lineMinSize : ', lineMinSize.toNumber(), 'ridgeSize : ', ridgeSize.toNumber()) + /** 마루의 길이는 이전 다음 라인중 짧은것의 길이와 현재라인부터 맞은편 라인까지의 길이에서 현재 라인의 길이를 뺀 것중 짧은 길이 */ + ridgeSize = Big(Math.min(oppositeSize, lineMinSize)) + } + console.log('ridgeSize', ridgeSize) if (ridgeSize.gt(0) && baseRidgeCount < getMaxRidge(baseLines.length)) { - // console.log('baseRidgeCount : ', baseRidgeCount) const points = [ startPoint.x, startPoint.y, @@ -2981,16 +3112,12 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { return } - /* const checkMidLine = new fabric.Line(points, { - stroke: 'blue', - strokeWidth: 2, - parentId: roof.id, - }) - canvas.add(checkMidLine) - canvas.renderAll()*/ - // console.log('points : ', points) const ridgeLine = drawRidgeLine(points, canvas, roof, textMode) - baseRidgeLines.push(ridgeLine) + if (gableType.includes(beforePrevLine.line.attributes.type) || gableType.includes(afterNextLine.line.attributes.type)) { + baseGableRidgeLines.push(ridgeLine) + } else { + baseRidgeLines.push(ridgeLine) + } baseRidgeCount = baseRidgeCount + 1 /** 포인트 조정*/ @@ -2999,13 +3126,234 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { .forEach((line) => { line.x2 = points[0] line.y2 = points[1] + line.line.set({ x2: points[0], y2: points[1] }) + // line.line.fire('modified') }) prevHipLine.x2 = points[0] prevHipLine.y2 = points[1] + const prevSize = reCalculateSize(prevHipLine) + prevHipLine.attributes.planeSize = prevSize.planeSize + prevHipLine.attributes.actualSize = prevSize.actualSize + prevHipLine.fire('modified') nextHipLine.x2 = points[0] nextHipLine.y2 = points[1] - prevHipLine.fire('modified') + const nextSize = reCalculateSize(nextHipLine) + nextHipLine.attributes.planeSize = nextSize.planeSize + nextHipLine.attributes.actualSize = nextSize.actualSize nextHipLine.fire('modified') + canvas.renderAll() + + 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 + + const oppositeRoofPoints = [ + ridgeLine.x2, + ridgeLine.y2, + ridgeLine.x1 === firstHipLine.x1 ? firstHipLine.x2 : firstHipLine.x1, + ridgeLine.y2, + ] + const oppositeRoofLine = drawHipLine(oppositeRoofPoints, canvas, roof, textMode, null, firstDegree, firstDegree) + baseHipLines.push({ + x1: oppositeRoofLine.x1, + y1: oppositeRoofLine.y1, + x2: oppositeRoofLine.x2, + y2: oppositeRoofLine.y2, + line: oppositeRoofLine, + }) + + const connectRoofPoints = [oppositeRoofLine.x2, oppositeRoofLine.y2] + if (ridgeLine.x1 === firstHipLine.x1) { + connectRoofPoints.push(firstHipLine.x2, firstHipLine.y2) + } else { + connectRoofPoints.push(firstHipLine.x1, firstHipLine.y1) + } + const connectRoofLine = drawRoofLine(connectRoofPoints, canvas, roof, textMode) + baseHipLines.push({ + x1: connectRoofLine.x1, + y1: connectRoofLine.y1, + x2: connectRoofLine.x2, + y2: connectRoofLine.y2, + line: connectRoofLine, + }) + + /** 다른 방향의 추녀마루 */ + 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 + + const intersections = [] + const checkEdge = { + vertex1: { x: ridgeLine.x2, y: ridgeLine.y2 }, + vertex2: { x: ridgeLine.x1 === secondHipLine.x1 ? secondHipLine.x2 : secondHipLine.x1, y: ridgeLine.y2 }, + } + + baseGableRidgeLines + .filter((ridge) => ridge !== ridgeLine) + .forEach((ridge) => { + const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } + const intersection = edgesIntersection(ridgeEdge, checkEdge) + if (intersection && !intersections.includes(intersection)) { + const size = Big(intersection.x) + .minus(Big(ridgeLine.x2)) + .pow(2) + .plus(Big(intersection.y).minus(Big(ridgeLine.y2)).pow(2)) + .sqrt() + .toNumber() + intersections.push({ intersection, size, ridge }) + } + }) + intersections.sort((a, b) => a.size - b.size) + + if (intersections.length > 0) { + const intersection = intersections[0].intersection + const intersectRidge = intersections[0].ridge + const oppositeRoofPoints = [ridgeLine.x2, ridgeLine.y2, intersection.x, intersection.y] + const oppositeRoofLine = drawHipLine(oppositeRoofPoints, canvas, roof, textMode, null, secondDegree, secondDegree) + baseHipLines.push({ x1: oppositeLine.x1, y1: oppositeLine.y1, x2: oppositeLine.x2, y2: oppositeLine.y2, line: oppositeRoofLine }) + + const ridgeVector = Math.sign(ridgeLine.y1 - ridgeLine.y2) + const connectRoofPoints = [oppositeRoofLine.x2, oppositeRoofLine.y2] + if (ridgeVector === Math.sign(oppositeRoofLine.y1 - intersectRidge.y2)) { + connectRoofPoints.push(intersectRidge.x2, intersectRidge.y2) + } else { + connectRoofPoints.push(intersectRidge.x1, intersectRidge.y1) + } + + const connectRoofLine = drawRoofLine(connectRoofPoints, canvas, roof, textMode) + baseHipLines.push({ + x1: connectRoofLine.x1, + y1: connectRoofLine.y1, + x2: connectRoofLine.x2, + y2: connectRoofLine.y2, + line: connectRoofLine, + }) + } + } 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 + + const oppositeRoofPoints = [ + ridgeLine.x2, + ridgeLine.y2, + ridgeLine.x2, + ridgeLine.y1 === firstHipLine.y1 ? firstHipLine.y2 : firstHipLine.y1, + ] + const oppositeRoofLine = drawHipLine(oppositeRoofPoints, canvas, roof, textMode, null, firstDegree, firstDegree) + baseHipLines.push({ + x1: oppositeRoofLine.x1, + y1: oppositeRoofLine.y1, + x2: oppositeRoofLine.x2, + y2: oppositeRoofLine.y2, + line: oppositeRoofLine, + }) + + const connectRoofPoints = [oppositeRoofLine.x2, oppositeRoofLine.y2] + if (ridgeLine.y1 === firstHipLine.y1) { + connectRoofPoints.push(firstHipLine.x2, firstHipLine.y2) + } else { + connectRoofPoints.push(firstHipLine.x1, firstHipLine.y1) + } + + const connectRoofLine = drawRoofLine(connectRoofPoints, canvas, roof, textMode) + baseHipLines.push({ + x1: connectRoofLine.x1, + y1: connectRoofLine.y1, + x2: connectRoofLine.x2, + y2: connectRoofLine.y2, + line: connectRoofLine, + }) + + /** 다른 방향의 추녀마루 */ + 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 + + const intersections = [] + const checkEdge = { + vertex1: { x: ridgeLine.x2, y: ridgeLine.y2 }, + vertex2: { x: ridgeLine.x2, y: ridgeLine.y1 === secondHipLine.y1 ? secondHipLine.y2 : secondHipLine.y1 }, + } + baseGableRidgeLines + .filter((ridge) => ridge !== ridgeLine) + .forEach((ridge) => { + const ridgeEdge = { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } } + const intersection = edgesIntersection(ridgeEdge, checkEdge) + if (intersection && !intersections.includes(intersection)) { + const size = Big(intersection.x) + .minus(Big(ridgeLine.x2)) + .pow(2) + .plus(Big(intersection.y).minus(Big(ridgeLine.y2)).pow(2)) + .sqrt() + .toNumber() + intersections.push({ intersection, size, ridge }) + } + }) + intersections.sort((a, b) => a.size - b.size) + if (intersections.length > 0) { + const intersection = intersections[0].intersection + const intersectRidge = intersections[0].ridge + const oppositeRoofPoints = [ridgeLine.x2, ridgeLine.y2, intersection.x, intersection.y] + const oppositeRoofLine = drawHipLine(oppositeRoofPoints, canvas, roof, textMode, null, secondDegree, secondDegree) + baseHipLines.push({ x1: oppositeLine.x1, y1: oppositeLine.y1, x2: oppositeLine.x2, y2: oppositeLine.y2, line: oppositeRoofLine }) + + const ridgeVector = Math.sign(ridgeLine.x1 - ridgeLine.x2) + const connectRoofPoints = [oppositeRoofLine.x2, oppositeRoofLine.y2] + if (ridgeVector === Math.sign(oppositeRoofLine.x1 - intersectRidge.x2)) { + connectRoofPoints.push(intersectRidge.x2, intersectRidge.y2) + } else { + connectRoofPoints.push(intersectRidge.x1, intersectRidge.y1) + } + + const connectRoofLine = drawRoofLine(connectRoofPoints, canvas, roof, textMode) + baseHipLines.push({ + x1: connectRoofLine.x1, + y1: connectRoofLine.y1, + x2: connectRoofLine.x2, + y2: connectRoofLine.y2, + line: connectRoofLine, + }) + } + } + } } } @@ -3941,6 +4289,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { /** hip이 짝수개가 맞다아있는데 마루와 연결되지 않는 포인트를 찾는다. 그려지지 않은 마루를 찾기 위함.*/ let noRidgeHipPoints = baseHipLines + .filter((current) => current.x1 !== current.x2 && current.y1 !== current.y2) .filter((current) => { const lines = baseHipLines .filter((line) => line !== current) @@ -3951,43 +4300,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { .filter( (current) => baseRidgeLines.filter((line) => (line.x1 === current.x2 && line.y1 === current.y2) || (line.x2 === current.x2 && line.y2 === current.y2)) + .length === 0 && + baseGableRidgeLines.filter((line) => (line.x1 === current.x2 && line.y1 === current.y2) || (line.x2 === current.x2 && line.y2 === current.y2)) .length === 0, ) noRidgeHipPoints.forEach((current) => { - /* const checkPoint = new fabric.Circle({ - left: current.x2, - top: current.y2, - radius: 4, - fill: 'green', - parentId: roofId, - name: 'checkPoint', - }) - canvas.add(checkPoint) - canvas.renderAll() - console.log('noRidgeHipPoints current : ', current.x1, current.y1, current.x2, current.y2)*/ const orthogonalPoints = noRidgeHipPoints.filter((point) => { - /*const checkPoint1 = new fabric.Circle({ - left: point.x2, - top: point.y2, - radius: 4, - fill: 'blue', - parentId: roofId, - name: 'checkPoint', - }) - canvas.add(checkPoint1) - canvas.renderAll() - console.log(' orthogonalPoints : ', point.x1, point.y1, point.x2, point.y2) - console.log( - 'same point :', - point !== current, - 'y point 다름', - current.x2 === point.x2 && current.y2 !== point.y2, - 'x point 다름', - current.x2 !== point.x2 && current.y2 === point.y2, - ) - canvas.remove(checkPoint1) - canvas.renderAll()*/ if (point !== current && ((current.x2 === point.x2 && current.y2 !== point.y2) || (current.x2 !== point.x2 && current.y2 === point.y2))) { return true } @@ -4002,8 +4321,6 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { const points = [current.x2, current.y2, orthogonalPoints[0].x2, orthogonalPoints[0].y2] const ridgeLine = drawRidgeLine(points, canvas, roof, textMode) baseRidgeLines.push(ridgeLine) - /** array에서 object 삭제*/ - // noRidgeHipPoints = noRidgeHipPoints.filter((point) => point !== current && point !== orthogonalPoints[0]) } }) @@ -4097,8 +4414,18 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { } }) + console.log('noRidgeHipPoints : ', noRidgeHipPoints) /** 마루를 그릴수 있는지 찾는다. */ noRidgeHipPoints.forEach((hipPoint) => { + const checkLine = new fabric.Line([hipPoint.x2, hipPoint.y2, hipPoint.x1, hipPoint.y1], { + stroke: 'red', + strokeWidth: 4, + parentId: roofId, + name: 'checkLine', + }) + canvas.add(checkLine) + canvas.renderAll() + const ridgePoints = [] intersectPoints .filter( @@ -4214,11 +4541,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => { if (distanceX < distanceY) { linePoints.push({ intersection: intersectX, intersectPoint }) - } else { + } + if (distanceX > distanceY) { linePoints.push({ intersection: intersectY, intersectPoint }) } }) + console.log('linePoints : ', linePoints) const linePoint = linePoints.reduce((prev, current) => { const prevDistance = Big(prev.intersection.x) .minus(Big(hipPoint.x2)) @@ -4821,6 +5150,45 @@ const drawRidgeLine = (points, canvas, roof, textMode) => { return ridge } +/** + * 지붕선을 그린다. + * @param points + * @param canvas + * @param roof + * @param textMode + * @returns {*} + */ +const drawRoofLine = (points, canvas, roof, textMode) => { + const ridge = new QLine(points, { + parentId: roof.id, + fontSize: roof.fontSize, + stroke: '#1083E3', + strokeWidth: 2, + name: LINE_TYPE.SUBLINE.HIP, + textMode: textMode, + attributes: { + roofId: roof.id, + planeSize: calcLinePlaneSize({ + x1: points[0], + y1: points[1], + x2: points[2], + y2: points[3], + }), + actualSize: calcLinePlaneSize({ + x1: points[0], + y1: points[1], + x2: points[2], + y2: points[3], + }), + }, + }) + canvas.add(ridge) + ridge.bringToFront() + canvas.renderAll() + + return ridge +} + /** * 벡터를 정규화(Normalization)하는 함수 * @param v @@ -7685,3 +8053,31 @@ const getSortedPoint = (points) => { } return sortedPoints } + +const reCalculateSize = (line) => { + const oldPlaneSize = line.attributes.planeSize + const oldActualSize = line.attributes.actualSize + 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, + x2: line.x2, + y2: line.y2, + }) + const actualSize = + planeSize === oldActualSize + ? 0 + : calcLineActualSize( + { + x1: line.x1, + y1: line.y1, + x2: line.x2, + y2: line.y2, + }, + theta, + ) + return { planeSize, actualSize } +}