From 8f1874c3cdb511ad931cf6ada6694e444ac98222 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Mon, 22 Dec 2025 14:45:23 +0900 Subject: [PATCH] =?UTF-8?q?=ED=95=98=EB=8B=A8=EB=A0=88=EB=B2=A8=20?= =?UTF-8?q?=EC=A7=80=EB=B6=95=EC=84=A0=20=EC=9E=91=EC=84=B1=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20B=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/qpolygon-utils.js | 547 ++++++++++++++++++++++++++----------- 1 file changed, 383 insertions(+), 164 deletions(-) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 93b78a62..3811e438 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -4848,6 +4848,9 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => { const prevLineVector = { x: Math.sign(prevLine.x1 - prevLine.x2), y: Math.sign(prevLine.y1 - prevLine.y2) } const nextLineVector = { x: Math.sign(nextLine.x1 - nextLine.x2), y: Math.sign(nextLine.y1 - nextLine.y2) } + const midX = (baseLine.x1 + baseLine.x2) / 2 + const midY = (baseLine.y1 + baseLine.y2) / 2 + const checkPoint = { x: midX + nextLineVector.x, y: midY + nextLineVector.y } //반절마루 생성불가이므로 지붕선 분기를 해야하는지 확인 후 처리. if ( prevLineVector.x === nextLineVector.x && @@ -4855,198 +4858,408 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => { baseLine.attributes.type === LINE_TYPE.WALLLINE.EAVES && (prevLine.attributes.type === LINE_TYPE.WALLLINE.GABLE || nextLine.attributes.type === LINE_TYPE.WALLLINE.GABLE) ) { - downRoofGable.push({ currLine: baseLine, currIndex: index }) + downRoofGable.push({ currLine: baseLine, currIndex: index, type: 'A' }) + } + + if ( + (prevLineVector.x !== nextLineVector.x || prevLineVector.y !== nextLineVector.y) && + checkWallPolygon.inPolygon(checkPoint) && + prevLine.attributes.type === LINE_TYPE.WALLLINE.GABLE && + nextLine.attributes.type === LINE_TYPE.WALLLINE.GABLE + ) { + downRoofGable.push({ currLine: baseLine, currIndex: index, type: 'B' }) } }) const downRoofLines = [] // 하단지붕 파생 라인 처리후 innerLines에 추가. - downRoofGable.forEach(({ currLine, currIndex }) => { - // 라인의 방향 - const currVector = { x: Math.sign(clamp01(currLine.x1 - currLine.x2)), y: Math.sign(clamp01(currLine.y1 - currLine.y2)) } + //A타입 하단 지붕 prevLine과 nextLine이 같은 방향으로 가는 경우 + downRoofGable + .filter((l) => l.type === 'A') + .forEach(({ currLine, currIndex }) => { + // 라인의 방향 + const currVector = { x: Math.sign(clamp01(currLine.x1 - currLine.x2)), y: Math.sign(clamp01(currLine.y1 - currLine.y2)) } - //어느쪽이 기준인지 확인. - //대각선 제외 - if (currVector.x !== 0 && currVector.y !== 0) return + //어느쪽이 기준인지 확인. + //대각선 제외 + if (currVector.x !== 0 && currVector.y !== 0) return - const prevLine = baseLines[(currIndex - 1 + baseLines.length) % baseLines.length] - const nextLine = baseLines[(currIndex + 1) % baseLines.length] + const prevLine = baseLines[(currIndex - 1 + baseLines.length) % baseLines.length] + const nextLine = baseLines[(currIndex + 1) % baseLines.length] - const prevVector = { x: Math.sign(clamp01(prevLine.x1 - prevLine.x2)), y: Math.sign(clamp01(prevLine.y1 - prevLine.y2)) } - const nextVector = { x: Math.sign(clamp01(nextLine.x1 - nextLine.x2)), y: Math.sign(clamp01(nextLine.y1 - nextLine.y2)) } + const prevVector = { x: Math.sign(clamp01(prevLine.x1 - prevLine.x2)), y: Math.sign(clamp01(prevLine.y1 - prevLine.y2)) } + const nextVector = { x: Math.sign(clamp01(nextLine.x1 - nextLine.x2)), y: Math.sign(clamp01(nextLine.y1 - nextLine.y2)) } - let gableLine - //가로선 - if (currVector.y === 0) { - if (currVector.x === 1) { - if (prevVector.y === 1 && nextVector.y === 1) { - gableLine = nextLine + let gableLine + //가로선 + if (currVector.y === 0) { + if (currVector.x === 1) { + if (prevVector.y === 1 && nextVector.y === 1) { + gableLine = nextLine + } + if (prevVector.y === -1 && nextVector.y === -1) { + gableLine = prevLine + } } - if (prevVector.y === -1 && nextVector.y === -1) { - gableLine = prevLine + if (currVector.x === -1) { + if (prevVector.y === 1 && nextVector.y === 1) { + gableLine = prevLine + } + if (prevVector.y === -1 && nextVector.y === -1) { + gableLine = nextLine + } } } - if (currVector.x === -1) { - if (prevVector.y === 1 && nextVector.y === 1) { - gableLine = prevLine + + //세로선 + if (currVector.x === 0) { + if (currVector.y === 1) { + if (prevVector.x === 1 && nextVector.x === 1) { + gableLine = prevLine + } + if (prevVector.x === -1 && nextVector.x === -1) { + gableLine = nextLine + } } - if (prevVector.y === -1 && nextVector.y === -1) { - gableLine = nextLine + if (currVector.y === -1) { + if (prevVector.x === 1 && nextVector.x === 1) { + gableLine = nextLine + } + if (prevVector.x === -1 && nextVector.x === -1) { + gableLine = prevLine + } } } - } - //세로선 - if (currVector.x === 0) { - if (currVector.y === 1) { - if (prevVector.x === 1 && nextVector.x === 1) { - gableLine = prevLine - } - if (prevVector.x === -1 && nextVector.x === -1) { - gableLine = nextLine - } + //기준점 + let stdPoint = [] + //반대쪽 라인을 찾기위한 vector + let oppFindVector + if (gableLine === prevLine) { + stdPoint.push(currLine.x1, currLine.y1) + stdPoint.push(currLine.x2 + -currVector.x * nextLine.attributes.offset, currLine.y2 + -currVector.y * nextLine.attributes.offset) + oppFindVector = { x: Math.sign(clamp01(nextLine.x2 - nextLine.x1)), y: Math.sign(clamp01(nextLine.y2 - nextLine.y1)) } + } else { + stdPoint.push(currLine.x2, currLine.y2) + stdPoint.push(currLine.x1 + currVector.x * prevLine.attributes.offset, currLine.y1 + currVector.y * prevLine.attributes.offset) + oppFindVector = { x: Math.sign(clamp01(prevLine.x1 - prevLine.x2)), y: Math.sign(clamp01(prevLine.y1 - prevLine.y2)) } } - if (currVector.y === -1) { - if (prevVector.x === 1 && nextVector.x === 1) { - gableLine = nextLine - } - if (prevVector.x === -1 && nextVector.x === -1) { - gableLine = prevLine - } - } - } - //기준점 - let stdPoint = [] - //반대쪽 라인을 찾기위한 vector - let oppFindVector - if (gableLine === prevLine) { - stdPoint.push(currLine.x1, currLine.y1) - stdPoint.push(currLine.x2 + -currVector.x * nextLine.attributes.offset, currLine.y2 + -currVector.y * nextLine.attributes.offset) - oppFindVector = { x: Math.sign(clamp01(nextLine.x2 - nextLine.x1)), y: Math.sign(clamp01(nextLine.y2 - nextLine.y1)) } - } else { - stdPoint.push(currLine.x2, currLine.y2) - stdPoint.push(currLine.x1 + currVector.x * prevLine.attributes.offset, currLine.y1 + currVector.y * prevLine.attributes.offset) - oppFindVector = { x: Math.sign(clamp01(prevLine.x1 - prevLine.x2)), y: Math.sign(clamp01(prevLine.y1 - prevLine.y2)) } - } - - //반대쪽 라인들 (마루선을 위함) - const oppLines = baseLines.filter((line) => { - const lineVector = { x: Math.sign(clamp01(line.x1 - line.x2)), y: Math.sign(clamp01(line.y1 - line.y2)) } - const oppVector = - lineVector.x === 0 ? { x: Math.sign(clamp01(line.x1 - stdPoint[0])), y: 0 } : { x: 0, y: Math.sign(clamp01(line.y1 - stdPoint[1])) } - - const rightDirection = - (currVector.x === lineVector.x && currVector.y !== lineVector.y) || (currVector.x !== lineVector.x && currVector.y === lineVector.y) - const rightOpp = oppFindVector.x === oppVector.x && oppFindVector.y === oppVector.y - return rightDirection && rightOpp - }) - - const innerRidge = innerLines - .filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE) - .filter((line) => { + //반대쪽 라인들 (마루선을 위함) + const oppLines = baseLines.filter((line) => { const lineVector = { x: Math.sign(clamp01(line.x1 - line.x2)), y: Math.sign(clamp01(line.y1 - line.y2)) } - //마루선을 찾는다. - if ((currVector.x === 0 && lineVector.x === 0) || (currVector.y === 0 && lineVector.y === 0)) { - //세로선 - if (lineVector.x === 0) { - const minY = Math.min(line.y1, line.y2) - const maxY = Math.max(line.y1, line.y2) - // 기준 라인 안에 들어있는 경우에만 처리. - if ( - Math.min(stdPoint[1], stdPoint[3]) <= minY && - maxY <= Math.max(stdPoint[1], stdPoint[3]) && - Math.min(stdPoint[0], ...oppLines.map((line) => line.x1)) <= line.x1 && - line.x1 <= Math.max(stdPoint[0], ...oppLines.map((line) => line.x1)) - ) { - return true + const oppVector = + lineVector.x === 0 ? { x: Math.sign(clamp01(line.x1 - stdPoint[0])), y: 0 } : { x: 0, y: Math.sign(clamp01(line.y1 - stdPoint[1])) } + + const rightDirection = + (currVector.x === lineVector.x && currVector.y !== lineVector.y) || (currVector.x !== lineVector.x && currVector.y === lineVector.y) + const rightOpp = oppFindVector.x === oppVector.x && oppFindVector.y === oppVector.y + return rightDirection && rightOpp + }) + + const innerRidge = innerLines + .filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE) + .filter((line) => { + const lineVector = { x: Math.sign(clamp01(line.x1 - line.x2)), y: Math.sign(clamp01(line.y1 - line.y2)) } + //마루선을 찾는다. + if ((currVector.x === 0 && lineVector.x === 0) || (currVector.y === 0 && lineVector.y === 0)) { + //세로선 + if (lineVector.x === 0) { + const minY = Math.min(line.y1, line.y2) + const maxY = Math.max(line.y1, line.y2) + // 기준 라인 안에 들어있는 경우에만 처리. + if ( + Math.min(stdPoint[1], stdPoint[3]) <= minY && + maxY <= Math.max(stdPoint[1], stdPoint[3]) && + Math.min(stdPoint[0], ...oppLines.map((line) => line.x1)) <= line.x1 && + line.x1 <= Math.max(stdPoint[0], ...oppLines.map((line) => line.x1)) + ) { + return true + } + } + //가로선 + if (lineVector.y === 0) { + const minX = Math.min(line.x1, line.x2) + const maxX = Math.max(line.x1, line.x2) + // 기준 라인 안에 들어있는 경우에만 처리 + if ( + Math.min(stdPoint[0], stdPoint[2]) <= minX && + maxX <= Math.max(stdPoint[0], stdPoint[2]) && + Math.min(stdPoint[1], ...oppLines.map((line) => line.y1)) <= line.y1 && + line.y1 <= Math.max(stdPoint[1], ...oppLines.map((line) => line.y1)) + ) { + return true + } } } - //가로선 - if (lineVector.y === 0) { - const minX = Math.min(line.x1, line.x2) - const maxX = Math.max(line.x1, line.x2) - // 기준 라인 안에 들어있는 경우에만 처리 - if ( - Math.min(stdPoint[0], stdPoint[2]) <= minX && - maxX <= Math.max(stdPoint[0], stdPoint[2]) && - Math.min(stdPoint[1], ...oppLines.map((line) => line.y1)) <= line.y1 && - line.y1 <= Math.max(stdPoint[1], ...oppLines.map((line) => line.y1)) - ) { - return true + }) + + //1. 현재 라인을 기준으로 지붕선 추가. + //1-1 stdPoint을 현재라인의 지붕 출폭 만큼 조정 + const currOffset = currLine.attributes.offset + const noGableLine = gableLine === prevLine ? nextLine : prevLine + + let roofLinePoint = stdPoint + if (currVector.x === 0) { + //세로일때 + //x축 조정 + roofLinePoint[0] = roofLinePoint[0] + currVector.y * currOffset + roofLinePoint[2] = roofLinePoint[2] + currVector.y * currOffset + } else if (currVector.y === 0) { + //가로일때 + //y축 조정 + roofLinePoint[1] = roofLinePoint[1] - currVector.x * currOffset + roofLinePoint[3] = roofLinePoint[3] - currVector.x * currOffset + } + + //지붕선추가. + downRoofLines.push(drawRoofLine(roofLinePoint, canvas, roof, textMode)) + + //1-2 지붕선에서 oppLine으로 향하는 중 가장 가까운 마루선까지의 연결선 생성 + const findRidgeEdge = { + vertex1: { x: roofLinePoint[0], y: roofLinePoint[1] }, + vertex2: { x: roofLinePoint[0] + oppFindVector.x, y: roofLinePoint[1] + oppFindVector.y }, + } + let minDistance = Infinity + let minPoint + let isLine + innerRidge.forEach((line) => { + const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } + const intersect = edgesIntersection(lineEdge, findRidgeEdge) + if (intersect) { + let distance = Infinity + if (currVector.x === 0) { + const lineDistance1 = Math.abs(line.y1 - roofLinePoint[1]) + const lineDistance2 = Math.abs(line.y2 - roofLinePoint[1]) + distance = Math.min(lineDistance1, lineDistance2) + } else if (currVector.y === 0) { + const lineDistance1 = Math.abs(line.x1 - roofLinePoint[0]) + const lineDistance2 = Math.abs(line.x2 - roofLinePoint[0]) + distance = Math.min(lineDistance1, lineDistance2) + } + if (distance < minDistance) { + minDistance = distance + minPoint = intersect + isLine = line + } + } + }) + if (minPoint) { + const hipPoint = [roofLinePoint[0], roofLinePoint[1], minPoint.x, minPoint.y] + downRoofLines.push( + drawHipLine(hipPoint, canvas, roof, textMode, null, getDegreeByChon(currLine.attributes.pitch), getDegreeByChon(currLine.attributes.pitch)), + ) + + if (isLine) { + const newRidgePoint = [minPoint.x, minPoint.y] + const distance1 = Math.sqrt(Math.pow(minPoint.x - isLine.x1, 2) + Math.pow(minPoint.y - isLine.y1, 2)) + const distance2 = Math.sqrt(Math.pow(minPoint.x - isLine.x2, 2) + Math.pow(minPoint.y - isLine.y2, 2)) + if (distance2 < distance1) { + newRidgePoint.push(isLine.x1, isLine.y1) + } else { + newRidgePoint.push(isLine.x2, isLine.y2) + } + downRoofLines.push(drawRoofLine(newRidgePoint, canvas, roof, textMode)) + } + } + }) + + // B타입 하단지붕 prevLine과 nextLine의 방향이 반대인데 현재 라인이 지붕 안쪽으로 들어가는 모양. + downRoofGable + .filter((l) => l.type === 'B') + .forEach(({ currLine, currIndex }) => { + const checkLine = new fabric.Line([currLine.x1, currLine.y1, currLine.x2, currLine.y2], { + stroke: 'red', + strokeWidth: 4, + parentId: roofId, + name: 'check', + }) + canvas.add(checkLine).renderAll() + + // 라인의 방향 + const currVector = { x: Math.sign(clamp01(currLine.x1 - currLine.x2)), y: Math.sign(clamp01(currLine.y1 - currLine.y2)) } + + //어느쪽이 기준인지 확인. + //대각선 제외 + if (currVector.x !== 0 && currVector.y !== 0) return + + const prevLine = baseLines[(currIndex - 1 + baseLines.length) % baseLines.length] + const nextLine = baseLines[(currIndex + 1) % baseLines.length] + + const prevVector = { x: Math.sign(clamp01(prevLine.x1 - prevLine.x2)), y: Math.sign(clamp01(prevLine.y1 - prevLine.y2)) } + const nextVector = { x: Math.sign(clamp01(nextLine.x1 - nextLine.x2)), y: Math.sign(clamp01(nextLine.y1 - nextLine.y2)) } + + const minX = Math.min(currLine.x1, currLine.x2) + const maxX = Math.max(currLine.x1, currLine.x2) + const minY = Math.min(currLine.y1, currLine.y2) + const maxY = Math.max(currLine.y1, currLine.y2) + const midX = (currLine.x1 + currLine.x2) / 2 + const midY = (currLine.y1 + currLine.y2) / 2 + let ridgeFindVector = { x: nextVector.x, y: nextVector.y } + if (!checkWallPolygon.inPolygon({ x: midX, y: midY })) { + ridgeFindVector = { x: prevVector.x, y: prevVector.y } + } + + // 마루를 따라 생성되어야 하는 지붕선 추가. + const oppLines = innerLines + .filter((l) => l.name === LINE_TYPE.SUBLINE.RIDGE) + .filter((line) => { + const lineVector = { x: Math.sign(clamp01(line.x1 - line.x2)), y: Math.sign(clamp01(line.y1 - line.y2)) } + let oppVector + if (currVector.x === 0) { + if (currVector.y === 1) { + oppVector = { x: Math.sign(clamp01(currLine.x1 - line.x1)), y: 0 } + } else if (currVector.y === -1) { + oppVector = { x: Math.sign(clamp01(line.x1 - currLine.x1)), y: 0 } } + } else if (currVector.y === 0) { + if (currVector.x === 1) { + oppVector = { x: 0, y: Math.sign(clamp01(line.y1 - currLine.y1)) } + } else if (currVector.x === -1) { + oppVector = { x: 0, y: Math.sign(clamp01(currLine.y1 - line.y1)) } + } + } + + 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) + + const isInside = lineVector.y === 0 ? minX <= lineMinX && lineMaxX <= maxX : minY <= lineMinY && lineMaxY <= maxY + + const rightOpp = ridgeFindVector.x === oppVector.x && ridgeFindVector.y === oppVector.y + return rightOpp && isInside + }) + + // 현재 라인의 지붕선 추가. + const currOffset = currLine.attributes.offset + const roofPoint = [ + currLine.x1 + -nextVector.x * currOffset, + currLine.y1 + -nextVector.y * currOffset, + currLine.x2 + -nextVector.x * currOffset, + currLine.y2 + -nextVector.y * currOffset, + ] + downRoofLines.push(drawRoofLine(roofPoint, canvas, roof, textMode)) + + // 현재 라인 좌표의 시작과 끝 포인트에서 직교하는 포인트와 라인을 찾는다 + let orthogonalStartPoint, + orthogonalStartDistance = Infinity, + orthogonalStartLine + let orthogonalEndPoint, + orthogonalEndDistance = Infinity, + orthogonalEndLine + oppLines.forEach((line) => { + const checkLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], { stroke: 'red', strokeWidth: 4, parentId: roofId, name: 'check' }) + canvas.add(checkLine).renderAll() + + if (currVector.x === 0) { + //세로선 + // 시작포인트와 가까운 포인트의 길이 + const lineStartDist = + Math.abs(currLine.y1 - line.y1) < Math.abs(currLine.y1 - line.y2) ? Math.abs(currLine.y1 - line.y1) : Math.abs(currLine.y1 - line.y2) + const lineStartPoint = + Math.abs(currLine.y1 - line.y1) < Math.abs(currLine.y1 - line.y2) ? { x: line.x1, y: currLine.y1 } : { x: line.x2, y: currLine.y1 } + if (lineStartDist < orthogonalStartDistance) { + orthogonalStartDistance = lineStartDist + orthogonalStartPoint = lineStartPoint + orthogonalStartLine = line + } + // 종료포인트와 가까운 포인트의 길이 + const lineEndDist = + Math.abs(currLine.y2 - line.y1) < Math.abs(currLine.y2 - line.y2) ? Math.abs(currLine.y2 - line.y2) : Math.abs(currLine.y2 - line.y1) + const lineEndPoint = + Math.abs(currLine.y2 - line.y1) < Math.abs(currLine.y2 - line.y2) ? { x: line.x2, y: currLine.y2 } : { x: line.x1, y: currLine.y2 } + if (lineEndDist < orthogonalEndDistance) { + orthogonalEndDistance = lineEndDist + orthogonalEndPoint = lineEndPoint + orthogonalEndLine = line + } + } else if (currVector.y === 0) { + //가로선 + // 시작포인트와 가까운 포인트의 길이 + const lineStartDist = + Math.abs(currLine.x1 - line.x1) < Math.abs(currLine.x1 - line.x2) ? Math.abs(currLine.x1 - line.x1) : Math.abs(currLine.x1 - line.x2) + const lineStartPoint = + Math.abs(currLine.x1 - line.x1) < Math.abs(currLine.x1 - line.x2) ? { x: currLine.x1, y: line.y1 } : { x: currLine.x1, y: line.y2 } + if (lineStartDist < orthogonalStartDistance) { + orthogonalStartDistance = lineStartDist + orthogonalStartPoint = lineStartPoint + orthogonalStartLine = line + } + //종료포인트와 가까운 포인트의 길이 + const lineEndDist = + Math.abs(currLine.x2 - line.x1) < Math.abs(currLine.x2 - line.x2) ? Math.abs(currLine.x2 - line.x1) : Math.abs(currLine.x2 - line.x2) + const lineEndPoint = + Math.abs(currLine.x2 - line.x1) < Math.abs(currLine.x2 - line.x2) ? { x: currLine.x2, y: line.y1 } : { x: currLine.x2, y: line.y2 } + if (lineEndDist < orthogonalEndDistance) { + orthogonalEndDistance = lineEndDist + orthogonalEndPoint = lineEndPoint + orthogonalEndLine = line } } }) - //1. 현재 라인을 기준으로 지붕선 추가. - //1-1 stdPoint을 현재라인의 지붕 출폭 만큼 조정 - const currOffset = currLine.attributes.offset - const noGableLine = gableLine === prevLine ? nextLine : prevLine + //직교 라인이 있는 경우 + if (orthogonalStartLine !== undefined && orthogonalEndLine !== undefined) { + if (orthogonalStartLine === orthogonalEndLine) { + //직교 라인이 1개일때 처리 + downRoofLines.push( + drawRoofLine([orthogonalStartPoint.x, orthogonalStartPoint.y, orthogonalEndPoint.x, orthogonalEndPoint.y], canvas, roof, textMode), + ) + } else { + //직교 라인이 2개일때 처리 + // 시작 라인 처리 + const startDist1 = Math.sqrt( + Math.pow(orthogonalStartPoint.x - orthogonalStartLine.x1, 2) + Math.pow(orthogonalStartPoint.y - orthogonalStartLine.y1, 2), + ) + const startDist2 = Math.sqrt( + Math.pow(orthogonalStartPoint.x - orthogonalStartLine.x2, 2) + Math.pow(orthogonalStartPoint.y - orthogonalStartLine.y2, 2), + ) + const otherStartPoint = + startDist1 > startDist2 + ? { x: orthogonalStartLine.x1, y: orthogonalStartLine.y1 } + : { x: orthogonalStartLine.x2, y: orthogonalStartLine.y2 } + downRoofLines.push( + drawRoofLine([orthogonalStartPoint.x, orthogonalStartPoint.y, otherStartPoint.x, otherStartPoint.y], canvas, roof, textMode), + ) - let roofLinePoint = stdPoint - if (currVector.x === 0) { - //세로일때 - //x축 조정 - roofLinePoint[0] = roofLinePoint[0] + currVector.y * currOffset - roofLinePoint[2] = roofLinePoint[2] + currVector.y * currOffset - } else if (currVector.y === 0) { - //가로일때 - //y축 조정 - roofLinePoint[1] = roofLinePoint[1] - currVector.x * currOffset - roofLinePoint[3] = roofLinePoint[3] - currVector.x * currOffset - } - - //지붕선추가. - downRoofLines.push(drawRoofLine(roofLinePoint, canvas, roof, textMode)) - - //1-2 지붕선에서 oppLine으로 향하는 중 가장 가까운 마루선까지의 연결선 생성 - const findRidgeEdge = { - vertex1: { x: roofLinePoint[0], y: roofLinePoint[1] }, - vertex2: { x: roofLinePoint[0] + oppFindVector.x, y: roofLinePoint[1] + oppFindVector.y }, - } - let minDistance = Infinity - let minPoint - let isLine - innerRidge.forEach((line) => { - const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } } - const intersect = edgesIntersection(lineEdge, findRidgeEdge) - if (intersect) { - let distance = Infinity - if (currVector.x === 0) { - const lineDistance1 = Math.abs(line.y1 - roofLinePoint[1]) - const lineDistance2 = Math.abs(line.y2 - roofLinePoint[1]) - distance = Math.min(lineDistance1, lineDistance2) - } else if (currVector.y === 0) { - const lineDistance1 = Math.abs(line.x1 - roofLinePoint[0]) - const lineDistance2 = Math.abs(line.x2 - roofLinePoint[0]) - distance = Math.min(lineDistance1, lineDistance2) - } - if (distance < minDistance) { - minDistance = distance - minPoint = intersect - isLine = line + const endDist1 = Math.sqrt( + Math.pow(orthogonalEndPoint.x - orthogonalEndLine.x1, 2) + Math.pow(orthogonalEndPoint.y - orthogonalEndLine.y1, 2), + ) + const endDist2 = Math.sqrt( + Math.pow(orthogonalEndPoint.x - orthogonalEndLine.x2, 2) + Math.pow(orthogonalEndPoint.y - orthogonalEndLine.y2, 2), + ) + const otherEndPoint = + endDist1 > endDist2 ? { x: orthogonalEndLine.x1, y: orthogonalEndLine.y1 } : { x: orthogonalEndLine.x2, y: orthogonalEndLine.y2 } + downRoofLines.push(drawRoofLine([orthogonalEndPoint.x, orthogonalEndPoint.y, otherEndPoint.x, otherEndPoint.y], canvas, roof, textMode)) } + + //지붕선(roofPoint)에서 직교포인트까지 연결하는 라인을 추가한다. + const orthogonalPoint1 = [roofPoint[0], roofPoint[1], orthogonalStartPoint.x, orthogonalStartPoint.y] + const orthogonalPoint2 = [roofPoint[2], roofPoint[3], orthogonalEndPoint.x, orthogonalEndPoint.y] + downRoofLines.push( + drawHipLine( + orthogonalPoint1, + canvas, + roof, + textMode, + null, + getDegreeByChon(currLine.attributes.pitch), + getDegreeByChon(currLine.attributes.pitch), + ), + ) + downRoofLines.push( + drawHipLine( + orthogonalPoint2, + canvas, + roof, + textMode, + null, + getDegreeByChon(currLine.attributes.pitch), + getDegreeByChon(currLine.attributes.pitch), + ), + ) } }) - if (minPoint) { - const hipPoint = [roofLinePoint[0], roofLinePoint[1], minPoint.x, minPoint.y] - downRoofLines.push( - drawHipLine(hipPoint, canvas, roof, textMode, null, getDegreeByChon(currLine.attributes.pitch), getDegreeByChon(currLine.attributes.pitch)), - ) - - if (isLine) { - const newRidgePoint = [minPoint.x, minPoint.y] - const distance1 = Math.sqrt(Math.pow(minPoint.x - isLine.x1, 2) + Math.pow(minPoint.y - isLine.y1, 2)) - const distance2 = Math.sqrt(Math.pow(minPoint.x - isLine.x2, 2) + Math.pow(minPoint.y - isLine.y2, 2)) - if (distance2 < distance1) { - newRidgePoint.push(isLine.x1, isLine.y1) - } else { - newRidgePoint.push(isLine.x2, isLine.y2) - } - downRoofLines.push(drawRoofLine(newRidgePoint, canvas, roof, textMode)) - } - } - }) //추가된 하단 지붕 라인 innerLines에 추가. innerLines.push(...downRoofLines) @@ -5107,7 +5320,13 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => { } startPoint = point } - innerLines.push(drawHipLine([startPoint.x, startPoint.y, currentLine.x2, currentLine.y2], canvas, roof, textMode, null, nextDegree, nextDegree)) + if (splitPoint.length === 1) { + innerLines.push(drawRoofLine([startPoint.x, startPoint.y, currentLine.x2, currentLine.y2], canvas, roof, textMode)) + } else { + innerLines.push( + drawHipLine([startPoint.x, startPoint.y, currentLine.x2, currentLine.y2], canvas, roof, textMode, null, nextDegree, nextDegree), + ) + } } else { innerLines.push(drawRoofLine([currentLine.x1, currentLine.y1, currentLine.x2, currentLine.y2], canvas, roof, textMode)) }