diff --git a/src/components/common/input/CalcInput.jsx b/src/components/common/input/CalcInput.jsx
index 17af010e..d386bd7d 100644
--- a/src/components/common/input/CalcInput.jsx
+++ b/src/components/common/input/CalcInput.jsx
@@ -3,7 +3,7 @@ import { createCalculator } from '@/util/calc-utils'
import '@/styles/calc.scss'
export const CalculatorInput = forwardRef(
- ({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false, placeholder, name='', disabled = false }, ref) => {
+ ({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false, placeholder, name='', disabled = false, maxLength = 6 }, ref) => {
const [showKeypad, setShowKeypad] = useState(false)
const [displayValue, setDisplayValue] = useState(value || '0')
const [hasOperation, setHasOperation] = useState(false)
@@ -48,28 +48,56 @@ export const CalculatorInput = forwardRef(
const calculator = calculatorRef.current
let newDisplayValue = ''
+ // maxLength 체크
+ if (maxLength > 0) {
+ const currentLength = (calculator.currentOperand || '').length + (calculator.previousOperand || '').length + (calculator.operation || '').length
+ if (currentLength >= maxLength) {
+ return
+ }
+ }
+
// 소수점 이하 2자리 제한 로직 추가
const shouldPreventInput = (value) => {
- const decimalParts = (value || '').split('.')
+ if (!value) return false
+ const decimalParts = value.toString().split('.')
return decimalParts.length > 1 && decimalParts[1].length >= 2
}
+ // 숫자 추가 함수
+ const appendNumber = (current, num) => {
+ // maxLength 체크
+ if (maxLength > 0 && (current + num).length > maxLength) {
+ return current
+ }
+ // 현재 값이 0이고 소수점이 없을 때 0이 아닌 숫자를 입력하면 대체
+ if (current === '0' && num !== '.' && !current.includes('.')) {
+ return num.toString()
+ }
+ // 0. 다음에 0을 입력하는 경우 허용
+ if (current === '0' && num === '0') {
+ return '0.'
+ }
+ return current + num
+ }
+
if (hasOperation) {
// 연산자 이후 숫자 입력 시
- if (calculator.currentOperand === '0' || calculator.shouldResetDisplay) {
+ if (calculator.shouldResetDisplay) {
calculator.currentOperand = num.toString()
calculator.shouldResetDisplay = false
- }else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리
- calculator.currentOperand = (calculator.currentOperand || '') + num
+ } else if (num === '.') {
+ if (!calculator.currentOperand.includes('.')) {
+ calculator.currentOperand = calculator.currentOperand || '0' + '.'
+ }
+ } else if (!shouldPreventInput(calculator.currentOperand)) {
+ calculator.currentOperand = appendNumber(calculator.currentOperand || '0', num)
}
- // else {
- // calculator.currentOperand = (calculator.currentOperand || '') + num
- // }
+
newDisplayValue = calculator.previousOperand + calculator.operation + calculator.currentOperand
setDisplayValue(newDisplayValue)
} else {
// 첫 번째 숫자 입력 시
- if (displayValue === '0' || calculator.shouldResetDisplay) {
+ if (calculator.shouldResetDisplay) {
calculator.currentOperand = num.toString()
calculator.shouldResetDisplay = false
newDisplayValue = calculator.currentOperand
@@ -77,8 +105,17 @@ export const CalculatorInput = forwardRef(
if (!hasOperation) {
onChange(calculator.currentOperand)
}
- } else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리
- calculator.currentOperand = (calculator.currentOperand || '') + num
+ } else if (num === '.') {
+ if (!calculator.currentOperand.includes('.')) {
+ calculator.currentOperand = (calculator.currentOperand || '0') + '.'
+ newDisplayValue = calculator.currentOperand
+ setDisplayValue(newDisplayValue)
+ if (!hasOperation) {
+ onChange(newDisplayValue)
+ }
+ }
+ } else if (!shouldPreventInput(calculator.currentOperand)) {
+ calculator.currentOperand = appendNumber(calculator.currentOperand || '0', num)
newDisplayValue = calculator.currentOperand
setDisplayValue(newDisplayValue)
if (!hasOperation) {
@@ -382,6 +419,7 @@ export const CalculatorInput = forwardRef(
placeholder={placeholder}
autoComplete={'off'}
disabled={disabled}
+ maxLength={maxLength}
/>
{showKeypad && !readOnly && (
diff --git a/src/components/community/Qna.jsx b/src/components/community/Qna.jsx
index 033f7424..f13a8639 100644
--- a/src/components/community/Qna.jsx
+++ b/src/components/community/Qna.jsx
@@ -57,6 +57,7 @@ export default function Qna() {
endRow : endRow,
schMainYn : 'N',
siteTpCd : 'QC',
+ langCd : 'JA',
})
const apiUrl = `${url}?${params.toString()}`
diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx
index d8b127fc..a8f5f148 100644
--- a/src/components/estimate/Estimate.jsx
+++ b/src/components/estimate/Estimate.jsx
@@ -24,6 +24,7 @@ import { useSwal } from '@/hooks/useSwal'
import { QcastContext } from '@/app/QcastProvider'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import {normalizeDigits, normalizeDecimal} from '@/util/input-utils'
+import { CalculatorInput } from '@/components/common/input/CalcInput'
export default function Estimate({}) {
const [uniqueData, setUniqueData] = useState([])
const [handlePricingFlag, setHandlePricingFlag] = useState(false)
@@ -1693,13 +1694,13 @@ export default function Estimate({}) {
{/* 파일첨부 끝 */}
{/* 견적특이사항 시작 */}
@@ -2106,25 +2107,60 @@ export default function Estimate({}) {
- {*/}
+ {/* onChangeAmount(e.target.value, item.dispOrder, index)*/}
+ {/* }}*/}
+ {/* maxLength={6}*/}
+ {/*/>*/}
+ {
- onChangeAmount(e.target.value, item.dispOrder, index)
+ onChange={(value) =>{
+ onChangeAmount(value, item.dispOrder, index)
}}
- maxLength={6}
- />
+ options={{
+ allowNegative: false,
+ allowDecimal: false
+ }}
+ />
|
{item.unit} |
- {*/}
+ {/* onChangeSalePrice(e.target.value, item.dispOrder, index)*/}
+ {/* }}*/}
+ {/* maxLength={12}*/}
+ {/*/>*/}
+ {
- onChangeSalePrice(e.target.value, item.dispOrder, index)
+ onChange={(value) =>{
+ onChangeSalePrice(value, item.dispOrder, index)
}}
maxLength={12}
+ options={{
+ allowNegative: false,
+ allowDecimal: false
+ }}
/>
{item.openFlg === '1' && (
diff --git a/src/components/floor-plan/modal/basic/step/Module.jsx b/src/components/floor-plan/modal/basic/step/Module.jsx
index 426724eb..a708f749 100644
--- a/src/components/floor-plan/modal/basic/step/Module.jsx
+++ b/src/components/floor-plan/modal/basic/step/Module.jsx
@@ -235,11 +235,23 @@ export default function Module({ setTabNum }) {
- setInputVerticalSnowCover(normalizeDecimal(e.target.value))}*/}
+ {/*/>*/}
+ setInputVerticalSnowCover(normalizeDecimal(e.target.value))}
+ onChange={(value) => setInputVerticalSnowCover(value)}
+ options={{
+ allowNegative: false,
+ allowDecimal: false
+ }}
/>
cm
diff --git a/src/components/floor-plan/modal/basic/step/Orientation.jsx b/src/components/floor-plan/modal/basic/step/Orientation.jsx
index fdf599be..4feeb41b 100644
--- a/src/components/floor-plan/modal/basic/step/Orientation.jsx
+++ b/src/components/floor-plan/modal/basic/step/Orientation.jsx
@@ -638,7 +638,7 @@ export const Orientation = forwardRef((props, ref) => {
name=""
label=""
className="input-origin block"
- value={inputInstallHeight}
+ value={inputVerticalSnowCover}
onChange={(value) => handleChangeVerticalSnowCover(value)}
options={{
allowNegative: false,
diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx
index dfcc547c..cc9d71ea 100644
--- a/src/components/management/StuffDetail.jsx
+++ b/src/components/management/StuffDetail.jsx
@@ -2125,12 +2125,12 @@ export default function StuffDetail() {
{/* {...register('verticalSnowCover')}*/}
{/*/>*/}
{}}
+ onChange={(value) => form.setValue('verticalSnowCover', value)}
options={{
allowNegative: false,
allowDecimal: false
@@ -2197,12 +2197,12 @@ export default function StuffDetail() {
{/* {...register('installHeight')}*/}
{/*/>*/}
{}}
+ onChange={(value) => form.setValue('installHeight', value)}
options={{
allowNegative: false,
allowDecimal: false
@@ -2721,12 +2721,12 @@ export default function StuffDetail() {
{/* {...register('verticalSnowCover')}*/}
{/*/>*/}
{}}
+ onChange={(value) => form.setValue('verticalSnowCover', value)}
options={{
allowNegative: false,
allowDecimal: false
@@ -2797,12 +2797,12 @@ export default function StuffDetail() {
{/*/>*/}
{}}
+ onChange={(value) => form.setValue('installHeight', value)}
options={{
allowNegative: false,
allowDecimal: false
diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js
index 795086fb..e74a59e3 100644
--- a/src/hooks/roofcover/useMovementSetting.js
+++ b/src/hooks/roofcover/useMovementSetting.js
@@ -631,7 +631,7 @@ export function useMovementSetting(id) {
}
return Big(0); // 기본값으로 0 반환 또는 다른 적절한 기본값
})();
- if (target.y1 === target.y2) {
+ if (Math.abs(target.y1 - target.y2) < 0.5) {
value = value.neg()
}
} else {
diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js
index f93e230d..3ebaa56c 100644
--- a/src/hooks/roofcover/useRoofAllocationSetting.js
+++ b/src/hooks/roofcover/useRoofAllocationSetting.js
@@ -473,7 +473,20 @@ export function useRoofAllocationSetting(id) {
// Filter out any eaveHelpLines that are already in lines to avoid duplicates
const existingEaveLineIds = new Set(roofBase.lines.map((line) => line.id))
const newEaveLines = roofEaveHelpLines.filter((line) => !existingEaveLineIds.has(line.id))
- roofBase.lines = [...newEaveLines]
+ // Filter out lines from roofBase.lines that share any points with newEaveLines
+ const linesToKeep = roofBase.lines.filter(roofLine => {
+ return !newEaveLines.some(eaveLine => {
+ // Check if any endpoint of roofLine matches any endpoint of eaveLine
+ return (
+ // Check if any endpoint of roofLine matches any endpoint of eaveLine
+ (Math.abs(roofLine.x1 - eaveLine.x1) < 0.1 && Math.abs(roofLine.y1 - eaveLine.y1) < 0.1) || // p1 matches p1
+ (Math.abs(roofLine.x2 - eaveLine.x2) < 0.1 && Math.abs(roofLine.y2 - eaveLine.y2) < 0.1) // p2 matches p2
+ );
+ });
+ });
+
+// Combine remaining lines with newEaveLines
+ roofBase.lines = [...linesToKeep, ...newEaveLines];
} else {
roofBase.lines = [...roofEaveHelpLines]
}
diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js
index f8c011f0..3811e438 100644
--- a/src/util/qpolygon-utils.js
+++ b/src/util/qpolygon-utils.js
@@ -2591,6 +2591,9 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
case LINE_TYPE.WALLLINE.JERKINHEAD:
offset = oppLine.attributes.width / 2
break
+ case LINE_TYPE.WALLLINE.WALL:
+ offset = 0
+ break
default:
break
}
@@ -2936,6 +2939,9 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
case LINE_TYPE.WALLLINE.JERKINHEAD:
offset = oppLine.attributes.width / 2
break
+ case LINE_TYPE.WALLLINE.WALL:
+ offset = 0
+ break
default:
break
}
@@ -3396,6 +3402,9 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
case LINE_TYPE.WALLLINE.JERKINHEAD:
offset = oppLine.attributes.width / 2
break
+ case LINE_TYPE.WALLLINE.WALL:
+ offset = 0
+ break
default:
break
}
@@ -3515,7 +3524,7 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
const oMidX = (oppLine.x1 + oppLine.x2) / 2
const oMidY = (oppLine.y1 + oppLine.y2) / 2
const cOffset = currentLine.attributes.offset
- const oOffset = oppLine.attributes.offset
+ const oOffset = oppLine.attributes.type === LINE_TYPE.WALLLINE.WALL ? 0 : oppLine.attributes.offset
const ridgeVector = { x: Math.sign(clamp01(cMidX - oMidX)), y: Math.sign(clamp01(cMidY - oMidY)) }
const ridgePoint = [
cMidX + ridgeVector.x * cOffset,
@@ -3531,6 +3540,9 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
case LINE_TYPE.WALLLINE.JERKINHEAD:
offset = oppLine.attributes.width / 2
break
+ case LINE_TYPE.WALLLINE.WALL:
+ offset = 0
+ break
default:
break
}
@@ -4664,8 +4676,8 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
}
}
}
- const checkNewLine = new fabric.Line(linePoint, { stroke: 'cyan', strokeWidth: 4, parentId: roofId, name: 'check' })
- canvas.add(checkNewLine).renderAll()
+ // const checkNewLine = new fabric.Line(linePoint, { stroke: 'cyan', strokeWidth: 4, parentId: roofId, name: 'check' })
+ // canvas.add(checkNewLine).renderAll()
newAnalysis.push({
start: { x: linePoint[0], y: linePoint[1] },
@@ -4827,8 +4839,8 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
})
}
- //하단 지붕 라인처리
- const downRoofLines = []
+ //케라바에서 파생된 하단 지붕 라인처리
+ const downRoofGable = []
baseLines.forEach((baseLine, index) => {
const nextLine = baseLines[(index + 1) % baseLines.length]
const prevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length]
@@ -4836,16 +4848,422 @@ 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 &&
prevLineVector.y === nextLineVector.y &&
+ baseLine.attributes.type === LINE_TYPE.WALLLINE.EAVES &&
(prevLine.attributes.type === LINE_TYPE.WALLLINE.GABLE || nextLine.attributes.type === LINE_TYPE.WALLLINE.GABLE)
) {
- downRoofLines.push(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에 추가.
+ //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
+
+ 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)) }
+
+ 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 (currVector.x === -1) {
+ if (prevVector.y === 1 && nextVector.y === 1) {
+ gableLine = prevLine
+ }
+ if (prevVector.y === -1 && nextVector.y === -1) {
+ gableLine = nextLine
+ }
+ }
+ }
+
+ //세로선
+ 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 (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 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
+ }
+ }
+ }
+ })
+
+ //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
+ }
+ }
+ })
+
+ //직교 라인이 있는 경우
+ 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),
+ )
+
+ 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),
+ ),
+ )
+ }
+ })
+
+ //추가된 하단 지붕 라인 innerLines에 추가.
+ innerLines.push(...downRoofLines)
+
//지붕선에 따라 라인추가 작업 처리.
const innerLinesPoints = []
innerLines.forEach((line) => {
@@ -4857,9 +5275,8 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
roof.lines.forEach((currentLine, index) => {
const prevLine = roof.lines[(index - 1 + roof.lines.length) % roof.lines.length]
const nextLine = roof.lines[(index + 1) % roof.lines.length]
- const prevDegree = getDegreeByChon(prevLine.attributes.pitch)
- const nextDegree = getDegreeByChon(nextLine.attributes.pitch)
- console.log('prevDegree, nextDegree: ', prevDegree, nextDegree)
+ const prevDegree = prevLine.attributes.pitch ? getDegreeByChon(prevLine.attributes.pitch) : 0
+ const nextDegree = nextLine.attributes.pitch ? getDegreeByChon(nextLine.attributes.pitch) : 0
const splitPoint = []
let hasOverlapLine = false
@@ -4903,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))
}
@@ -4917,730 +5340,6 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
.filter((object) => object.name === 'check')
.forEach((object) => canvas.remove(object))
canvas.renderAll()
- //return
- /*while (linesAnalysis.length > 0 && iterations < MAX_ITERATIONS) {
- iterations++
-
- linesAnalysis.forEach((line) => {
- const point = [line.start.x, line.start.y, line.end.x, line.end.y]
- const checkLine = new fabric.Line(point, {
- stroke: 'red',
- strokeWidth: 2,
- parentId: roofId,
- name: 'check',
- })
- canvas.add(checkLine)
- canvas.renderAll()
- })
- // 각 가선분의 최단 교점 찾기
- const intersections = []
- for (let i = 0; i < linesAnalysis.length; i++) {
- let minDistance = Infinity //최단거리
- let intersectPoint = null //교점 좌표
- let partners = new Set() //교점 선분의 index
-
- const lineI = linesAnalysis[i]
- const lengthI = Math.sqrt(Math.pow(lineI.end.x - lineI.start.x, 2) + Math.pow(lineI.end.y - lineI.start.y, 2))
- console.log('lengthI', lengthI)
- const checkLineI = new fabric.Line([lineI.start.x, lineI.start.y, lineI.end.x, lineI.end.y], {
- stroke: 'blue',
- strokeWidth: 2,
- parentId: roofId,
- name: 'check',
- })
- canvas.add(checkLineI).renderAll()
-
- if (lineI.type === TYPES.GABLE_LINE && lineI.connectCnt > 1) continue
-
- if (lengthI > EPSILON) {
- const otherLines = linesAnalysis.filter((j) => j !== lineI)
- const zeroLines = linesAnalysis.filter((j) => Math.sqrt(Math.pow(j.end.x - j.start.x, 2) + Math.pow(j.end.y - j.start.y, 2)) < EPSILON)
- if (otherLines.length === zeroLines.length) {
- zeroLines.forEach((j) => {
- const jIndex = linesAnalysis.indexOf(j)
- if (isPointOnLineNew({ x1: lineI.start.x, y1: lineI.start.y, x2: lineI.end.x, y2: lineI.end.y }, { x: j.start.x, y: j.start.y })) {
- const distance = Math.sqrt(Math.pow(j.start.x - lineI.start.x, 2) + Math.pow(j.start.y - lineI.start.y, 2))
- if (distance < minDistance) {
- minDistance = distance
- intersectPoint = { x: j.start.x, y: j.start.y }
- partners = new Set([jIndex])
- } else if (almostEqual(distance, minDistance)) {
- partners.add(jIndex)
- }
- }
- })
- if (intersectPoint) {
- intersections.push({ index: i, intersectPoint, partners, distance: minDistance })
- partners.forEach((j) => {
- const p = new Set([i])
- intersections.push({ index: j, intersectPoint, partners: p, distance: 0 })
- })
- continue
- }
- }
- }
-
- for (let j = 0; j < linesAnalysis.length; j++) {
- const lineJ = linesAnalysis[j]
- if (lineI === lineJ) continue
- if (lineI.type === TYPES.GABLE_LINE && lineJ.type === TYPES.GABLE_LINE && i.gableId === lineJ.gableId) continue
- if (lineJ.type === TYPES.GABLE_LINE && lineJ.connectCnt > 1) continue
-
- const intersection = lineIntersection(lineI.start, lineI.end, lineJ.start, lineJ.end, canvas)
- if (intersection) {
- const distance = Math.sqrt((intersection.x - lineI.start.x) ** 2 + (intersection.y - lineI.start.y) ** 2)
- const distance2 = Math.sqrt((intersection.x - lineJ.start.x) ** 2 + (intersection.y - lineJ.start.y) ** 2)
- if (lineI.type === TYPES.GABLE_LINE && distance < EPSILON) continue
- if (distance < minDistance && !almostEqual(distance, minDistance) && !(distance < EPSILON && distance2 < EPSILON)) {
- minDistance = distance
- intersectPoint = intersection
- partners = new Set([j])
- } else if (almostEqual(distance, minDistance)) {
- partners.add(j)
- }
- }
- }
- if (intersectPoint) {
- intersections.push({ index: i, intersectPoint, partners, distance: minDistance })
- }
- canvas.remove(checkLineI).renderAll()
- }
-
- // 제일 가까운 교점부터 처리
- intersections.sort((a, b) => a.distance - b.distance)
-
- console.log('intersections', intersections)
- // 교점에 대한 적합 여부 판단 및 처리.
- let newAnalysis = [] //신규 발생 선
- const processed = new Set() //처리된 선
- for (const { index, intersectPoint, partners } of intersections) {
- canvas
- .getObjects()
- .filter((object) => object.name === 'check')
- .forEach((object) => canvas.remove(object))
- canvas.renderAll()
- let isProceed = false
- for (const pIndex of partners) {
- console.log('pIndex : ', pIndex)
- const check1 = linesAnalysis[index]
- const checkLine1 = new fabric.Line([check1.start.x, check1.start.y, check1.end.x, check1.end.y], {
- stroke: 'red',
- strokeWidth: 2,
- parentId: roofId,
- name: 'check',
- })
- const checkCircle1 = new fabric.Circle({ left: check1.start.x, top: check1.start.y, radius: 5, fill: 'red', parentId: roofId, name: 'check' })
- const checkCircle2 = new fabric.Circle({ left: check1.end.x, top: check1.end.y, radius: 5, fill: 'green', parentId: roofId, name: 'check' })
- canvas.add(checkLine1, checkCircle1, checkCircle2)
- canvas.renderAll()
-
- const check2 = linesAnalysis[pIndex]
- const checkLine2 = new fabric.Line([check2.start.x, check2.start.y, check2.end.x, check2.end.y], {
- stroke: 'green',
- strokeWidth: 2,
- parentId: roofId,
- name: 'check',
- })
-
- const checkCircle3 = new fabric.Circle({ left: check2.start.x, top: check2.start.y, radius: 5, fill: 'red', parentId: roofId, name: 'check' })
- const checkCircle4 = new fabric.Circle({ left: check2.end.x, top: check2.end.y, radius: 5, fill: 'green', parentId: roofId, name: 'check' })
- canvas.add(checkLine2, checkCircle3, checkCircle4)
- canvas.renderAll()
-
- console.log('!intersectPoint || processed.has(index)', !intersectPoint, processed.has(index))
- //교점이 없거나, 이미 처리된 선분이면 처리하지 않는다.
- if (!intersectPoint || processed.has(index)) continue
-
- const partner = intersections.find((p) => p.index === pIndex)
- //교점이 없거나, 교점 선분이 없으면 처리하지 않는다.
- if (!partner || !partner.intersectPoint) continue
-
- //상호 최단 교점 여부 확인.
- if (partner.partners.has(index)) {
- const line1 = linesAnalysis[index]
- const line2 = linesAnalysis[pIndex]
-
- //좌,우 선 중 공통 선 존재 확인.
- const isSameLine = line1.left === line2.left || line1.left === line2.right || line1.right === line2.left || line1.right === line2.right
- if (isSameLine) {
- // 현재 선이 처리 되었음을 표기
- let point1 = [line1.start.x, line1.start.y, intersectPoint.x, intersectPoint.y]
- let point2 = [line2.start.x, line2.start.y, intersectPoint.x, intersectPoint.y]
- let length1 = Math.sqrt((point1[2] - point1[0]) ** 2 + (point1[3] - point1[1]) ** 2)
- let length2 = Math.sqrt((point2[2] - point2[0]) ** 2 + (point2[3] - point2[1]) ** 2)
- if (length1 < EPSILON && length2 < EPSILON) continue
- isProceed = true
-
- //gable라인과 붙는경우 length가 0에 가까우면 포인트를 뒤집는다.
- if (line1.type === TYPES.GABLE_LINE && length2 < EPSILON) {
- point2 = [line2.end.x, line2.end.y, intersectPoint.x, intersectPoint.y]
- length2 = Math.sqrt((point2[2] - point2[0]) ** 2 + (point2[3] - point2[1]) ** 2)
- }
- if (line2.type === TYPES.GABLE_LINE && length1 < EPSILON) {
- point1 = [line1.end.x, line1.end.y, intersectPoint.x, intersectPoint.y]
- length1 = Math.sqrt((point1[2] - point1[0]) ** 2 + (point1[3] - point1[1]) ** 2)
- }
-
- if (length1 > 0 && !alreadyPoints(innerLines, point1)) {
- if (line1.type === TYPES.HIP) {
- innerLines.push(drawHipLine(point1, canvas, roof, textMode, null, line1.degree, line1.degree))
- } else if (line1.type === TYPES.RIDGE) {
- innerLines.push(drawRidgeLine(point1, canvas, roof, textMode))
- } else if (line1.type === TYPES.NEW) {
- const isDiagonal = Math.abs(point1[0] - point1[2]) >= 1 && Math.abs(point1[1] - point1[3]) >= 1
- if (isDiagonal) {
- innerLines.push(drawHipLine(point1, canvas, roof, textMode, null, line1.degree, line1.degree))
- } else {
- innerLines.push(drawRidgeLine(point1, canvas, roof, textMode))
- }
- } else if (line1.type === TYPES.GABLE_LINE) {
- if (line1.degree > 0) {
- innerLines.push(drawHipLine(point1, canvas, roof, textMode, null, line1.degree, line1.degree))
- } else {
- innerLines.push(drawRidgeLine(point1, canvas, roof, textMode))
- }
- }
- }
-
- if (length2 > 0 && !alreadyPoints(innerLines, point2)) {
- if (line2.type === TYPES.HIP) {
- innerLines.push(drawHipLine(point2, canvas, roof, textMode, null, line2.degree, line2.degree))
- } else if (line2.type === TYPES.RIDGE) {
- innerLines.push(drawRidgeLine(point2, canvas, roof, textMode))
- } else if (line2.type === TYPES.NEW) {
- const isDiagonal = Math.abs(point2[0] - point2[2]) >= 1 && Math.abs(point2[1] - point2[3]) >= 1
- if (isDiagonal) {
- innerLines.push(drawHipLine(point2, canvas, roof, textMode, null, line2.degree, line2.degree))
- } else {
- innerLines.push(drawRidgeLine(point2, canvas, roof, textMode))
- }
- } else if (line2.type === TYPES.GABLE_LINE) {
- if (line2.degree > 0) {
- innerLines.push(drawHipLine(point2, canvas, roof, textMode, null, line2.degree, line2.degree))
- } else {
- innerLines.push(drawRidgeLine(point2, canvas, roof, textMode))
- }
- }
- }
-
- if (line1.type === TYPES.GABLE_LINE || line2.type === TYPES.GABLE_LINE) {
- console.log('gableLine newAnalyze start')
- const gableLine = line1.type === TYPES.GABLE_LINE ? line1 : line2
- gableLine.connectCnt++
-
- const checkLine = new fabric.Line([gableLine.start.x, gableLine.start.y, gableLine.end.x, gableLine.end.y], {
- stroke: 'red',
- strokeWidth: 4,
- parentId: roofId,
- name: 'check',
- })
- const checkCircle = new fabric.Circle({
- left: intersectPoint.x,
- top: intersectPoint.y,
- radius: 5,
- parentId: roofId,
- name: 'check',
- })
- canvas.add(checkLine, checkCircle)
- canvas.renderAll()
-
- const relationBaseLines = [line1.left, line1.right, line2.left, line2.right]
- const uniqueBaseLines = [...new Set(relationBaseLines)]
- if (uniqueBaseLines.length === 3) {
- const linesCounts = new Map()
- relationBaseLines.forEach((e) => {
- linesCounts.set(e, (linesCounts.get(e) || 0) + 1)
- })
- const uniqueLines = Array.from(linesCounts.entries())
- .filter(([_, count]) => count === 1)
- .map(([line, _]) => line)
-
- if (uniqueLines.length === 2) {
- if (gableLine.connectCnt < 2) {
- newAnalysis.push({
- start: { x: intersectPoint.x, y: intersectPoint.y },
- end: { x: gableLine.end.x, y: gableLine.end.y },
- left: gableLine.left,
- right: gableLine.right,
- type: TYPES.GABLE_LINE,
- degree: getDegreeByChon(baseLines[gableLine.right].attributes.pitch),
- gableId: gableLine.gableId,
- connectCnt: gableLine.connectCnt,
- })
- }
- if (gableLine.connectCnt >= 2) {
- //가선분 발생만 시키는 더미 생성.
- newAnalysis.push({
- start: { x: intersectPoint.x, y: intersectPoint.y },
- end: { x: intersectPoint.x, y: intersectPoint.y },
- left: gableLine.gableId,
- right: gableLine.gableId,
- type: TYPES.HIP,
- degree: 0,
- })
- }
- }
- }
- console.log('gableLine newAnalyze end')
- } else {
- // 연결점에서 새로운 가선분을 생성
- const relationBaseLines = [line1.left, line1.right, line2.left, line2.right]
- const uniqueBaseLines = [...new Set(relationBaseLines)]
- if (uniqueBaseLines.length === 3) {
- const linesCounts = new Map()
- relationBaseLines.forEach((e) => {
- linesCounts.set(e, (linesCounts.get(e) || 0) + 1)
- })
-
- const uniqueLines = Array.from(linesCounts.entries())
- .filter(([_, count]) => count === 1)
- .map(([line, _]) => line)
-
- if (uniqueLines.length === 2) {
- // 두 변의 이등분선 방향 계산
- // uniqueLines.sort((a, b) => a - b)
- console.log('uniqueLines : ', uniqueLines)
- const baseLine1 = baseLines[uniqueLines[0]]
- const baseLine2 = baseLines[uniqueLines[1]]
-
- const checkLine1 = new fabric.Line([baseLine1.x1, baseLine1.y1, baseLine1.x2, baseLine1.y2], {
- stroke: 'yellow',
- strokeWidth: 4,
- parentId: roofId,
- name: 'check',
- })
- const checkLine2 = new fabric.Line([baseLine2.x1, baseLine2.y1, baseLine2.x2, baseLine2.y2], {
- stroke: 'blue',
- strokeWidth: 4,
- parentId: roofId,
- name: 'check',
- })
- canvas.add(checkLine1, checkLine2)
- canvas.renderAll()
- let bisector
- console.log('isParallel(baseLine1, baseLine2)', isParallel(baseLine1, baseLine2))
- if (isParallel(baseLine1, baseLine2)) {
- bisector = getBisectLines(
- { x1: line1.start.x, x2: line1.end.x, y1: line1.start.y, y2: line1.end.y },
- { x1: line2.start.x, y1: line2.start.y, x2: line2.end.x, y2: line2.end.y },
- )
- } else {
- //이등분선
- bisector = getBisectBaseLines(baseLine1, baseLine2, intersectPoint, canvas)
- }
-
- //마주하는 지붕선을 찾는다.
- const intersectionsByRoof = []
- const checkEdge = {
- vertex1: { x: intersectPoint.x, y: intersectPoint.y },
- vertex2: { x: intersectPoint.x + bisector.x, y: intersectPoint.y + bisector.y },
- }
- const checkVector = {
- x: Math.sign(checkEdge.vertex1.x - checkEdge.vertex2.x),
- y: Math.sign(checkEdge.vertex1.y - checkEdge.vertex2.y),
- }
- roof.lines.forEach((line) => {
- const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } }
- const is = edgesIntersection(lineEdge, checkEdge)
- if (is && isPointOnLineNew(line, is)) {
- const distance = Math.sqrt((is.x - intersectPoint.x) ** 2 + (is.y - intersectPoint.y) ** 2)
- const isVector = { x: Math.sign(intersectPoint.x - is.x), y: Math.sign(intersectPoint.y - is.y) }
- if (isVector.x === checkVector.x && isVector.y === checkVector.y) {
- intersectionsByRoof.push({ is, distance })
- }
- }
- })
- intersectionsByRoof.sort((a, b) => a.distance - b.distance)
- //지붕 선과의 교점이 존재 할때
- if (intersectionsByRoof.length > 0) {
- let is = intersectionsByRoof[0].is
- let linePoint = [intersectPoint.x, intersectPoint.y, is.x, is.y]
- const isDiagonal = Math.abs(is.x - intersectPoint.x) >= 1 && Math.abs(is.y - intersectPoint.y) >= 1
- const length = Math.sqrt((linePoint[2] - linePoint[0]) ** 2 + (linePoint[3] - linePoint[1]) ** 2)
- if (!isDiagonal) {
- const line1 = baseLines[uniqueLines[0]]
- const line2 = baseLines[uniqueLines[1]]
- const vector1 = { x: Math.sign(line1.x1 - line1.x2), y: Math.sign(line1.y1 - line1.y2) }
-
- const prevLine = checkVector.x === vector1.x && checkVector.y === vector1.y ? line2 : line1
- const nextLine = checkVector.x === vector1.x && checkVector.y === vector1.y ? line1 : line2
- const drivePoint = getRidgeDrivePoint(linePoint, prevLine, nextLine, baseLines)
- if (drivePoint !== null) {
- const driveLength = Math.sqrt((drivePoint.x - intersectPoint.x) ** 2 + (drivePoint.y - intersectPoint.y) ** 2)
-
- if (driveLength < length) {
- linePoint = [intersectPoint.x, intersectPoint.y, drivePoint.x, drivePoint.y]
- }
- }
- }
- const checkNewLine = new fabric.Line(linePoint, { stroke: 'cyan', strokeWidth: 4, parentId: roofId, name: 'check' })
- canvas.add(checkNewLine).renderAll()
-
- newAnalysis.push({
- start: { x: linePoint[0], y: linePoint[1] },
- end: { x: linePoint[2], y: linePoint[3] },
- left: uniqueLines[0],
- right: uniqueLines[1],
- type: TYPES.NEW,
- degree: isDiagonal ? line1.degree : 0,
- })
- }
- }
- canvas
- .getObjects()
- .filter((object) => object.name === 'check')
- .forEach((object) => canvas.remove(object))
- canvas.renderAll()
- }
- }
- processed.add(pIndex)
- }
- }
- canvas
- .getObjects()
- .filter((object) => object.name === 'check')
- .forEach((object) => canvas.remove(object))
- canvas.renderAll()
- }
- if (isProceed) {
- processed.add(index)
- break
- }
- }
- // 처리된 가선분 제외
- linesAnalysis = newAnalysis.concat(linesAnalysis.filter((_, index) => !processed.has(index)))
- console.log('lineAnalysis: ', linesAnalysis)
-
- canvas
- .getObjects()
- .filter((object) => object.name === 'check' || object.name === 'checkAnalysis')
- .forEach((object) => canvas.remove(object))
- canvas.renderAll()
- // 새로운 가선분이 없을때 종료
- console.log('newAnalysis.length : ', newAnalysis.length)
- if (newAnalysis.length === 0) break
- }
- console.log('lineAnalysis: end ', linesAnalysis)*/
-
- // 가선분 중 처리가 안되어있는 붙어있는 라인에 대한 예외처리.
- /* const proceedAnalysis = []
- linesAnalysis
- .filter((line) => {
- const dx = line.end.x - line.start.x
- const dy = line.end.y - line.start.y
- const length = Math.sqrt(dx ** 2 + dy ** 2)
- return length > 0
- })
- .forEach((currentLine) => {
- if (proceedAnalysis.find((p) => p === currentLine)) return
- //현재와 같으면 제외, 이미 처리된 라인은 제외, 현재와 공통선분이 존재하지 않으면 제외
- linesAnalysis
- .filter((line) => {
- const dx = line.end.x - line.start.x
- const dy = line.end.y - line.start.y
- const length = Math.sqrt(dx ** 2 + dy ** 2)
- return length > 0
- })
- .filter(
- (partnerLine) =>
- partnerLine !== currentLine &&
- !proceedAnalysis.find((p) => p === partnerLine) &&
- (currentLine.left === partnerLine.left ||
- currentLine.left === partnerLine.right ||
- partnerLine.left === currentLine.left ||
- partnerLine.left === currentLine.right),
- )
- .forEach((partnerLine) => {
- const dx1 = currentLine.end.x - currentLine.start.x
- const dy1 = currentLine.end.y - currentLine.start.y
- const dx2 = partnerLine.end.x - partnerLine.start.x
- const dy2 = partnerLine.end.y - partnerLine.start.y
- const denominator = dy2 * dx1 - dx2 * dy1
- const isOpposite = dx1 * dx2 + dy1 * dy2 < 0
- //평행하지 않으면 제외
- if (Math.abs(denominator) > EPSILON) return
-
- const currentDegree = getDegreeByChon(baseLines[currentLine.left].attributes.pitch)
- if (isOpposite) {
- const points = [currentLine.start.x, currentLine.start.y, partnerLine.start.x, partnerLine.start.y]
- const length = Math.sqrt((points[0] - points[2]) ** 2 + (points[1] - points[3]) ** 2)
-
- if (length > 0) {
- if (currentLine.type === TYPES.HIP) {
- innerLines.push(drawHipLine(points, canvas, roof, textMode, null, currentDegree, currentDegree))
- } else if (currentLine.type === TYPES.RIDGE) {
- innerLines.push(drawRidgeLine(points, canvas, roof, textMode))
- } else if (currentLine.type === TYPES.NEW) {
- const isDiagonal = Math.abs(points[0] - points[2]) >= 1 && Math.abs(points[1] - points[3]) >= 1
- if (isDiagonal && almostEqual(Math.abs(points[0] - points[2]), Math.abs(points[1] - points[3]))) {
- innerLines.push(drawHipLine(points, canvas, roof, textMode, null, currentDegree, currentDegree))
- }
- if (!isDiagonal) {
- innerLines.push(drawRidgeLine(points, canvas, roof, textMode))
- }
- }
- proceedAnalysis.push(currentLine, partnerLine)
- }
- } else {
- const allPoints = [currentLine.start, currentLine.end, partnerLine.start, partnerLine.end]
- let points = []
- allPoints.forEach((point) => {
- let count = 0
- allPoints.forEach((p) => {
- if (almostEqual(point.x, p.x) && almostEqual(point.y, p.y)) count++
- })
- if (count === 1) points.push(point)
- })
-
- if (points.length === 2) {
- const length = Math.sqrt((points[0].x - points[1].x) ** 2 + (points[0].y - points[1].y) ** 2)
- if (length < EPSILON) return
- const isDiagonal = Math.abs(points[0].x - points[1].x) >= 1 && Math.abs(points[0].y - points[1].y) >= 1
- if (isDiagonal) {
- innerLines.push(
- drawHipLine([points[0].x, points[0].y, points[1].x, points[1].y], canvas, roof, textMode, null, currentDegree, currentDegree),
- )
- } else {
- innerLines.push(drawRidgeLine([points[0].x, points[0].y, points[1].x, points[1].y], canvas, roof, textMode))
- }
- proceedAnalysis.push(currentLine, partnerLine)
- }
- }
- })
- })
- linesAnalysis = linesAnalysis.filter((line) => !proceedAnalysis.find((p) => p === line))*/
-
- //하단 지붕 라인처리
- /* const downRoofLines = []
- baseLines.forEach((baseLine, index) => {
- const nextLine = baseLines[(index + 1) % baseLines.length]
- const prevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length]
-
- 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) }
-
- //반절마루 생성불가이므로 지붕선 분기를 해야하는지 확인 후 처리.
- if (
- prevLineVector.x === nextLineVector.x &&
- prevLineVector.y === nextLineVector.y &&
- (prevLine.attributes.type === LINE_TYPE.WALLLINE.GABLE || nextLine.attributes.type === LINE_TYPE.WALLLINE.GABLE)
- ) {
- downRoofLines.push(index)
- }
- })*/
-
- /*if (downRoofLines.length > 0) {
- downRoofLines.forEach((index) => {
- const currentLine = baseLines[index]
- // const nextLine = baseLines[(index + 1) % baseLines.length]
- // const prevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length]
-
- const analyze = analyzeLine(currentLine)
- if (analyze.isDiagonal) {
- return
- }
-
- const roofLine = analyze.roofLine
- let roofPoint = [analyze.startPoint.x, analyze.startPoint.y, analyze.endPoint.x, analyze.endPoint.y]
-
- if (analyze.isVertical) {
- roofPoint[0] = roofLine.x1
- roofPoint[2] = roofLine.x2
- }
- if (analyze.isHorizontal) {
- roofPoint[1] = roofLine.y1
- roofPoint[3] = roofLine.y2
- }
-
- console.log('analyze: ', analyze)
- const findRidgeVector = { x: 0, y: 0 }
- if (analyze.isVertical) {
- // noinspection JSSuspiciousNameCombination
- findRidgeVector.x = analyze.directionVector.y
- }
- if (analyze.isHorizontal) {
- // noinspection JSSuspiciousNameCombination
- findRidgeVector.y = analyze.directionVector.x
- }
-
- console.log('findRidgeVector: ', findRidgeVector)
- innerLines
- .filter((line) => {
- if (line.name === LINE_TYPE.SUBLINE.RIDGE) {
- if (analyze.isVertical) {
- const signX = Math.sign(currentLine.x1 - line.x1)
- console.log('signX: ', signX)
- return signX === findRidgeVector.x
- }
- if (analyze.isHorizontal) {
- const signY = Math.sign(currentLine.y1 - line.y1)
- console.log('signY: ', signY)
- return signY === findRidgeVector.y
- }
- return false
- }
- return false
- })
- .forEach((line) => {
- if (line.name === LINE_TYPE.SUBLINE.RIDGE) {
- const checkLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
- stroke: 'red',
- strokeWidth: 4,
- parentId: roofId,
- name: 'check',
- })
- canvas.add(checkLine)
- canvas.renderAll()
- }
- })
-
- /!*const oppositeLines = []
- baseLines
- .filter((line) => {
- //평행한 반대방향 라인인지 확인.
- const lineAnalyze = analyzeLine(line)
- return (
- (analyze.isHorizontal &&
- lineAnalyze.directionVector.x !== analyze.directionVector.x &&
- lineAnalyze.directionVector.y === analyze.directionVector.y) ||
- (analyze.isVertical &&
- lineAnalyze.directionVector.x === analyze.directionVector.x &&
- lineAnalyze.directionVector.y !== analyze.directionVector.y)
- )
- })
- .filter((line) => {
- //라인이 현재라인에 overlap 되거나, 현재 라인을 full overlap하는지 확인.
- if (analyze.isHorizontal) {
- const currentMinX = Math.min(currentLine.x1, currentLine.x2)
- const currentMaxX = Math.max(currentLine.x1, currentLine.x2)
- const minX = Math.min(line.x1, line.x2)
- const maxX = Math.max(line.x1, line.x2)
- //full overlap
- if (minX <= currentMinX && maxX >= currentMaxX) {
- return true
- }
- //라인 포인트중 하나라도 현재 라인의 범위에 들어와있으면 overlap으로 판단.
- if ((currentMinX <= minX && minX <= currentMaxX) || (currentMinX <= maxX && maxX <= currentMaxX)) {
- return true
- }
- }
- if (analyze.isVertical) {
- const currentMinY = Math.min(currentLine.y1, currentLine.y2)
- const currentMaxY = Math.max(currentLine.y1, currentLine.y2)
- const minY = Math.min(line.y1, line.y2)
- const maxY = Math.max(line.y1, line.y2)
- //full overlap
- if (minY <= currentMinY && maxY >= currentMaxY) {
- return true
- }
- //라인 포인트중 하나라도 현재 라인의 범위에 들어와있으면 overlap으로 판단.
- if ((currentMinY <= minY && minY <= currentMaxY) || (currentMinY <= maxY && maxY <= currentMaxY)) {
- return true
- }
- }
- return false
- })
- .forEach((line, i) => {
- const checkLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
- stroke: 'green',
- strokeWidth: 4,
- parentId: roofId,
- name: 'check',
- })
- canvas.add(checkLine)
- canvas.renderAll()
- })*!/
-
- // innerLines.push(drawRoofLine(roofPoint, canvas, roof, textMode))
- })
- }*/
-
- /*if (linesAnalysis.length > 0) {
- linesAnalysis
- .filter((line) => {
- const dx = line.end.x - line.start.x
- const dy = line.end.y - line.start.y
- const length = Math.sqrt(dx ** 2 + dy ** 2)
- return length > 0
- })
- .forEach((line) => {
- const startOnLine = roof.lines.find((l) => isPointOnLineNew(l, line.start))
- const endOnLine = roof.lines.find((l) => isPointOnLineNew(l, line.end))
- console.log('startOnLine, endOnLine: ', startOnLine, endOnLine)
- const allLinesPoints = []
- innerLines.forEach((innerLine) => {
- allLinesPoints.push({ x: innerLine.x1, y: innerLine.y1 }, { x: innerLine.x2, y: innerLine.y2 })
- })
-
- if (
- allLinesPoints.filter((p) => almostEqual(p.x, line.start.x) && almostEqual(p.y, line.start.y)).length < 3 &&
- allLinesPoints.filter((p) => almostEqual(p.x, line.end.x) && almostEqual(p.y, line.end.y)).length === 0
- ) {
- if (startOnLine || endOnLine) {
- if (line.degree === 0) {
- innerLines.push(drawRoofLine([line.start.x, line.start.y, line.end.x, line.end.y], canvas, roof, textMode))
- } else {
- innerLines.push(
- drawHipLine([line.start.x, line.start.y, line.end.x, line.end.y], canvas, roof, textMode, null, line.degree, line.degree),
- )
- }
- }
- }
- })
- }*/
-
- //지붕선에 따라 라인추가 작업 처리.
- /*const innerLinesPoints = []
- innerLines.forEach((line) => {
- const hasCoord1 = innerLinesPoints.find((p) => p.x === line.x1 && p.y === line.y1)
- const hasCoord2 = innerLinesPoints.find((p) => p.x === line.x2 && p.y === line.y2)
- if (!hasCoord1) innerLinesPoints.push({ x: line.x1, y: line.y1 })
- if (!hasCoord2) innerLinesPoints.push({ x: line.x2, y: line.y2 })
- })
- roof.lines.forEach((line) => {
- const splitPoint = []
- let hasOverlapLine = false
- const minX = Math.min(line.x1, line.x2)
- const maxX = Math.max(line.x1, line.x2)
- const minY = Math.min(line.y1, line.y2)
- const maxY = Math.max(line.y1, line.y2)
- innerLines.forEach((innerLine) => {
- const innerLineMinX = Math.min(innerLine.x1, innerLine.x2)
- const innerLineMaxX = Math.max(innerLine.x1, innerLine.x2)
- const innerLineMinY = Math.min(innerLine.y1, innerLine.y2)
- const innerLineMaxY = Math.max(innerLine.y1, innerLine.y2)
- if (innerLineMinX <= minX && innerLineMaxX >= maxX && innerLineMinY <= minY && innerLineMaxY >= maxY) {
- hasOverlapLine = true
- }
- if (minX <= innerLineMinX && maxX >= innerLineMaxX && minY <= innerLineMinY && maxY >= innerLineMaxY) {
- hasOverlapLine = true
- }
- })
- if (hasOverlapLine) return
-
- innerLinesPoints.forEach((point) => {
- if (
- isPointOnLineNew(line, point) &&
- !(almostEqual(line.x1, point.x) && almostEqual(line.y1, point.y)) &&
- !(almostEqual(line.x2, point.x) && almostEqual(line.y2, point.y))
- ) {
- const distance = Math.sqrt((point.x - line.x1) ** 2 + (point.y - line.y1) ** 2)
- splitPoint.push({ point, distance })
- }
- })
- if (splitPoint.length > 0) {
- splitPoint.sort((a, b) => a[1] - b[1])
- let startPoint = { x: line.x1, y: line.y1 }
- for (let i = 0; i < splitPoint.length; i++) {
- const point = splitPoint[i].point
- innerLines.push(drawRoofLine([startPoint.x, startPoint.y, point.x, point.y], canvas, roof, textMode))
- startPoint = point
- }
- innerLines.push(drawRoofLine([startPoint.x, startPoint.y, line.x2, line.y2], canvas, roof, textMode))
- } else {
- innerLines.push(drawRoofLine([line.x1, line.y1, line.x2, line.y2], canvas, roof, textMode))
- }
- })*/
}
/**
diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js
index de7bd91f..943f1f38 100644
--- a/src/util/skeleton-utils.js
+++ b/src/util/skeleton-utils.js
@@ -494,29 +494,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
}
});
- /*
- //2. 연결이 끊어진 스켈레톤 선을 찾아 연장합니다.
- const { disconnectedLines } = findDisconnectedSkeletonLines(skeletonLines, roof.lines);
- if(disconnectedLines.length > 0) {
-
- disconnectedLines.forEach(dLine => {
- const { index, extendedLine, p1Connected, p2Connected } = dLine;
- const newPoint = extendedLine?.point;
- if (!newPoint) return;
- // p1이 끊어졌으면 p1을, p2가 끊어졌으면 p2를 연장된 지점으로 업데이트
- if (p1Connected) { //p2 연장
- skeletonLines[index].p2 = { ...skeletonLines[index].p2, x: newPoint.x, y: newPoint.y };
- } else if (p2Connected) {//p1 연장
- skeletonLines[index].p1 = { ...skeletonLines[index].p1, x: newPoint.x, y: newPoint.y };
- }
- });
-
- //2-1 확장된 스켈레톤 선이 연장되다가 서로 만나면 만난점(접점)에서 멈추어야 된다.
- trimIntersectingExtendedLines(skeletonLines, disconnectedLines);
-
- }
- */
//2. 연결이 끊어진 라인이 있을경우 찾아서 추가한다(동 이동일때)
@@ -549,17 +527,6 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
{ x: sktLine.p2.x, y: sktLine.p2.y }
);
- //그림을 그릴때 idx 가 필요함 roof는 왼쪽부터 시작됨 - 그림그리는 순서가 필요함
-
-
- // roofLines.forEach((roofLine) => {
- //
- // if (isSameLine(p1.x, p1.y, p2.x, p2.y, roofLine) || isSameLine(p2.x, p2.y, p1.x, p1.y, roofLine)) {
- // roofIdx = roofLine.idx;
- // console.log("roofIdx::::::", roofIdx)
- // return false; // forEach 중단
- // }
- // });
const skeletonLine = new QLine([p1.x, p1.y, p2.x, p2.y], {
@@ -596,9 +563,6 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
});
-
-
-
}else{
@@ -608,906 +572,908 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
canvas.renderAll();
});
- //if((roof.moveUpDown??0 > 0) ) {
+ if (Math.abs(roof.moveUpDown ?? 0) > 0 || Math.abs(roof.moveFlowLine ?? 0) > 0) {
+ const getMoveUpDownLine = () => {
+ // 같은 라인이 없으므로 새 다각형 라인 생성
+ //라인 편집
+ // let i = 0
+ const currentRoofLines = canvas.getObjects().filter((obj) => obj.lineName === 'roofLine' && obj.attributes.roofId === roofId)
+ let roofLineRects = canvas.getObjects().filter((obj) => obj.name === 'roofLineRect' && obj.roofId === roofId)
- // 같은 라인이 없으므로 새 다각형 라인 생성
- //라인 편집
- // let i = 0
- const currentRoofLines = canvas.getObjects().filter((obj) => obj.lineName === 'roofLine' && obj.attributes.roofId === roofId)
- let roofLineRects = canvas.getObjects().filter((obj) => obj.name === 'roofLineRect' && obj.roofId === roofId)
+ roofLineRects.forEach((roofLineRect) => {
+ canvas.remove(roofLineRect)
+ canvas.renderAll()
+ })
+ let helpLines = canvas.getObjects().filter((obj) => obj.lineName === 'helpLine' && obj.roofId === roofId)
+ helpLines.forEach((helpLine) => {
+ canvas.remove(helpLine)
+ canvas.renderAll()
+ })
- roofLineRects.forEach((roofLineRect) => {
- canvas.remove(roofLineRect)
- canvas.renderAll()
- })
+ function sortCurrentRoofLines(lines) {
+ return [...lines].sort((a, b) => {
+ // Get all coordinates in a consistent order
+ const getCoords = (line) => {
+ const x1 = line.x1 ?? line.get('x1')
+ const y1 = line.y1 ?? line.get('y1')
+ const x2 = line.x2 ?? line.get('x2')
+ const y2 = line.y2 ?? line.get('y2')
- let helpLines = canvas.getObjects().filter((obj) => obj.lineName === 'helpLine' && obj.roofId === roofId)
- helpLines.forEach((helpLine) => {
- canvas.remove(helpLine)
- canvas.renderAll()
- })
-
- function sortCurrentRoofLines(lines) {
- return [...lines].sort((a, b) => {
- // Get all coordinates in a consistent order
- const getCoords = (line) => {
- const x1 = line.x1 ?? line.get('x1');
- const y1 = line.y1 ?? line.get('y1');
- const x2 = line.x2 ?? line.get('x2');
- const y2 = line.y2 ?? line.get('y2');
-
- // Sort points left-to-right, then top-to-bottom
- return x1 < x2 || (x1 === x2 && y1 < y2)
- ? [x1, y1, x2, y2]
- : [x2, y2, x1, y1];
- };
-
- const aCoords = getCoords(a);
- const bCoords = getCoords(b);
-
- // Compare each coordinate in order
- for (let i = 0; i < 4; i++) {
- if (Math.abs(aCoords[i] - bCoords[i]) > 0.1) {
- return aCoords[i] - bCoords[i];
+ // Sort points left-to-right, then top-to-bottom
+ return x1 < x2 || (x1 === x2 && y1 < y2) ? [x1, y1, x2, y2] : [x2, y2, x1, y1]
}
- }
- return 0;
- });
+
+ const aCoords = getCoords(a)
+ const bCoords = getCoords(b)
+
+ // Compare each coordinate in order
+ for (let i = 0; i < 4; i++) {
+ if (Math.abs(aCoords[i] - bCoords[i]) > 0.1) {
+ return aCoords[i] - bCoords[i]
+ }
+ }
+ return 0
+ })
+ }
+
+ // 각 라인 집합 정렬
+ const sortWallLines = ensureCounterClockwiseLines(wallLines)
+ const sortWallBaseLines = ensureCounterClockwiseLines(wall.baseLines)
+ const sortRoofLines = ensureCounterClockwiseLines(roofLines)
+
+ // roofLines의 방향에 맞춰 currentRoofLines의 방향을 조정
+ const alignLineDirection = (sourceLines, targetLines) => {
+ return sourceLines.map((sourceLine) => {
+ // 가장 가까운 targetLine 찾기
+ const nearestTarget = targetLines.reduce((nearest, targetLine) => {
+ const sourceCenter = {
+ x: (sourceLine.x1 + sourceLine.x2) / 2,
+ y: (sourceLine.y1 + sourceLine.y2) / 2,
+ }
+ const targetCenter = {
+ x: (targetLine.x1 + targetLine.x2) / 2,
+ y: (targetLine.y1 + targetLine.y2) / 2,
+ }
+ const distance = Math.hypot(sourceCenter.x - targetCenter.x, sourceCenter.y - targetCenter.y)
+
+ return !nearest || distance < nearest.distance ? { line: targetLine, distance } : nearest
+ }, null)?.line
+
+ if (!nearestTarget) return sourceLine
+
+ // 방향이 반대인지 확인 (벡터 내적을 사용)
+ const sourceVec = {
+ x: sourceLine.x2 - sourceLine.x1,
+ y: sourceLine.y2 - sourceLine.y1,
+ }
+ const targetVec = {
+ x: nearestTarget.x2 - nearestTarget.x1,
+ y: nearestTarget.y2 - nearestTarget.y1,
+ }
+
+ const dotProduct = sourceVec.x * targetVec.x + sourceVec.y * targetVec.y
+
+ // 내적이 음수이면 방향이 반대이므로 뒤집기
+ if (dotProduct < 0) {
+ return {
+ ...sourceLine,
+ x1: sourceLine.x2,
+ y1: sourceLine.y2,
+ x2: sourceLine.x1,
+ y2: sourceLine.y1,
+ }
+ }
+
+ return sourceLine
+ })
+ }
+
+ console.log('wallBaseLines', wall.baseLines)
+
+ //wall.baseLine은 움직인라인
+ let movedLines = []
+
+ // 조건에 맞는 라인들만 필터링
+ const validWallLines = [...wallLines].sort((a, b) => a.idx - b.idx).filter((wallLine, index) => wallLine.idx - 1 === index)
+
+ console.log('', sortRoofLines, sortWallLines, sortWallBaseLines)
+ sortWallLines.length > 3 &&
+ sortWallLines.forEach((wallLine, index) => {
+
+ const roofLine = sortRoofLines[index]
+ const wallBaseLine = sortWallBaseLines[index]
+
+ //roofline 외곽선 설정
+
+ console.log('index::::', index)
+ console.log('roofLine:', roofLine.x1, roofLine.y1, roofLine.x2, roofLine.y2)
+ console.log('wallLine:', wallLine.x1, wallLine.y1, wallLine.x2, wallLine.y2)
+ console.log('wallBaseLine:', wallBaseLine.x1, wallBaseLine.y1, wallBaseLine.x2, wallBaseLine.y2)
+ console.log('isSamePoint result:', isSameLine2(wallBaseLine, wallLine))
+
+ if (isSameLine2(wallBaseLine, wallLine)) {
+ return
+ }
+
+ const movedStart = Math.abs(wallBaseLine.x1 - wallLine.x1) > EPSILON || Math.abs(wallBaseLine.y1 - wallLine.y1) > EPSILON
+ const movedEnd = Math.abs(wallBaseLine.x2 - wallLine.x2) > EPSILON || Math.abs(wallBaseLine.y2 - wallLine.y2) > EPSILON
+
+ const fullyMoved = movedStart && movedEnd
+
+ //반시계 방향
+ let newPStart //= {x:roofLine.x1, y:roofLine.y1}
+ let newPEnd //= {x:movedLines.x2, y:movedLines.y2}
+
+ //현재 roof는 무조건 시계방향
+
+ const getAddLine = (p1, p2, stroke = '') => {
+ movedLines.push({ index, p1, p2 })
+
+ //console.log("mergeLines:::::::", mergeLines);
+ const line = new QLine([p1.x, p1.y, p2.x, p2.y], {
+ parentId: roof.id,
+ fontSize: roof.fontSize,
+ stroke: 'black',
+ strokeWidth: 4,
+ name: 'eaveHelpLine',
+ lineName: 'eaveHelpLine',
+ visible: true,
+ roofId: roofId,
+ selectable: true,
+ hoverCursor: 'pointer',
+ attributes: {
+ type: 'eaveHelpLine',
+ isStart: true,
+ pitch: wallLine.attributes.pitch,
+ },
+ })
+
+ //coordinateText(line)
+ canvas.add(line)
+ line.bringToFront()
+ canvas.renderAll()
+ return line
+ }
+
+ //getAddLine(roofLine.startPoint, roofLine.endPoint, ) //외곽선을 그린다
+
+ newPStart = { x: roofLine.x1, y: roofLine.y1 }
+ newPEnd = { x: roofLine.x2, y: roofLine.y2 }
+
+ const getInnerLines = (lines, point) => {}
+ let isIn = false
+ let isOut = false
+
+ //두 포인트가 변경된 라인인
+ if (fullyMoved) {
+ //반시계방향향
+
+ const mLine = getSelectLinePosition(wall, wallBaseLine)
+
+ if (getOrientation(roofLine) === 'vertical') {
+ if (['left', 'right'].includes(mLine.position)) {
+ if (Math.abs(wallLine.x1 - wallBaseLine.x1) < 0.1 || Math.abs(wallLine.x2 - wallBaseLine.x2) < 0.1) {
+ return false
+ }
+ const isLeftPosition = mLine.position === 'left'
+ const isRightPosition = mLine.position === 'right'
+ const isInPosition =
+ (isLeftPosition && wallLine.x1 < wallBaseLine.x1) ||
+ (isRightPosition && wallLine.x1 > wallBaseLine.x1) ||
+ (isLeftPosition && wallLine.x2 < wallBaseLine.x2) ||
+ (isRightPosition && wallLine.x2 > wallBaseLine.x2)
+
+ const positionType = isInPosition ? 'in' : 'out'
+
+ const condition = `${mLine.position}_${positionType}`
+ let isStartEnd = findInteriorPoint(wallBaseLine, sortWallBaseLines)
+ let sPoint, ePoint
+ if (condition === 'left_in') {
+ isIn = true
+
+ if (isStartEnd.start) {
+ newPEnd.y = roofLine.y2
+ newPEnd.x = roofLine.x2
+
+ const moveDist = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
+ ePoint = { x: wallBaseLine.x1, y: wallBaseLine.y1 }
+ newPStart.y = wallBaseLine.y1
+
+ findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'left_in_start' })
+ const newPointX = Big(roofLine.x1).plus(moveDist).abs().toNumber()
+ const pDist = Big(wallLine.x1).minus(roofLine.x1).toNumber()
+ const pLineY = Big(roofLine.y1).minus(0).abs().toNumber()
+ // let idx = 0 > index - 1 ? sortRoofLines.length : index
+ // const pLineX = sortRoofLines[idx - 1].x1
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineX = sortRoofLines[prevIndex].x1
+
+ getAddLine({ x: newPStart.x, y: newPStart.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
+ getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
+
+ if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
+ getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
+ }
+ }
+
+ if (isStartEnd.end) {
+ newPStart.y = roofLine.y1
+ newPStart.x = roofLine.x1
+
+ const moveDist = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
+ ePoint = { x: wallBaseLine.x2, y: wallBaseLine.y2 }
+ newPEnd.y = wallBaseLine.y2
+
+ findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'left_in_end' })
+ const newPointX = Big(roofLine.x1).plus(moveDist).toNumber()
+ const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
+ const pLineY = Big(roofLine.y2).minus(0).toNumber()
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const pLineX = sortRoofLines[idx + 1].x2
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineX = sortRoofLines[nextIndex].x2
+
+ getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
+ getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: newPointX, y: roofLine.y1 }, 'orange')
+
+ if (Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
+ getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
+ }
+ //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
+ }
+ } else if (condition === 'left_out') {
+ console.log('left_out::::isStartEnd:::::', isStartEnd)
+ if (isStartEnd.start) {
+ const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
+ const aStartY = Big(roofLine.y1).minus(moveDist).abs().toNumber()
+ const bStartY = Big(wallLine.y1).minus(moveDist).abs().toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x2 })
+
+ const eLineY = Big(bStartY).minus(wallLine.y1).abs().toNumber()
+ newPStart.y = aStartY
+ newPEnd.y = roofLine.y2 //Big(roofLine.y2).minus(eLineY).toNumber()
+ // let idx = 0 >= index - 1 ? sortRoofLines.length : index
+ // const newLine = sortRoofLines[idx - 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const newLine = sortRoofLines[nextIndex]
+
+ if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
+ if (inLine) {
+ if (inLine.x1 < inLine.x2) {
+ getAddLine({ y: bStartY, x: wallLine.x2 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
+ } else {
+ getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: bStartY, x: wallLine.x2 }, 'pink')
+ }
+ }
+ getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta')
+ getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray')
+ findPoints.push({ y: aStartY, x: newPStart.x, position: 'left_out_start' })
+ } else {
+ const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
+ newPStart.y = Big(newPStart.y).minus(cLineY).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.x1 < inLine.x2) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x }, 'purple')
+ }
+ } else {
+ //newPStart.y = wallLine.y1;
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber()
+ newPStart.y = Big(wallBaseLine.y1).minus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.x2 > inLine.x1) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ }
+ }
+ }
+ }
+
+ if (isStartEnd.end) {
+ const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
+ const aStartY = Big(roofLine.y2).plus(moveDist).toNumber()
+ const bStartY = Big(wallLine.y2).plus(moveDist).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 })
+ console.log('startLines:::::::', inLine)
+ const eLineY = Big(bStartY).minus(wallLine.y2).abs().toNumber()
+ newPEnd.y = aStartY
+ newPStart.y = roofLine.y1 //Big(roofLine.y1).plus(eLineY).toNumber()
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const newLine = sortRoofLines[idx + 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length;
+ const nextIndex = (index + 1) % sortRoofLines.length;
+ const newLine = sortRoofLines[prevIndex]
+
+
+ if (Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
+ if (inLine) {
+ if (inLine.x1 < inLine.x2) {
+ getAddLine({ y: bStartY, x: wallLine.x1 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x1 }, 'pink')
+ }
+ }
+ getAddLine({ y: bStartY, x: wallLine.x1 }, { y: roofLine.y2, x: wallLine.x2 }, 'magenta')
+ getAddLine({ y: newLine.y2, x: newLine.x2 }, { y: newLine.y1, x: wallLine.x1 }, 'Gray')
+ findPoints.push({ y: aStartY, x: newPEnd.x, position: 'left_out_end' })
+ } else {
+ const cLineY = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
+ newPEnd.y = Big(newPEnd.y).plus(cLineY).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.x1 < inLine.x2) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ } else {
+ // newPEnd.y = wallLine.y2
+
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber()
+ newPEnd.y = Big(wallBaseLine.y2).plus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.x2 > inLine.x1) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ }
+ }
+ }
+ findPoints.push({ y: newPStart.y, x: newPEnd.x, position: 'left_out_end' })
+ }
+ } else if (condition === 'right_in') {
+ if (isStartEnd.start) {
+ newPEnd.y = roofLine.y2
+ newPEnd.x = roofLine.x2
+
+ const moveDist = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
+ ePoint = { x: wallBaseLine.x1, y: wallBaseLine.y1 }
+ newPStart.y = wallBaseLine.y1
+
+ findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'right_in_start' })
+ const newPointX = Big(roofLine.x1).minus(moveDist).abs().toNumber()
+ const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
+ const pLineY = Big(roofLine.y1).minus(0).abs().toNumber()
+ // let idx = 0 >= index - 1 ? sortRoofLines.length : index
+ // const pLineX = sortRoofLines[idx - 1].x1
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineX = sortRoofLines[prevIndex].x1
+
+ getAddLine({ x: newPStart.x, y: newPStart.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
+ //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
+
+ if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
+ getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
+ }
+ }
+
+ if (isStartEnd.end) {
+ newPStart.y = roofLine.y1
+ newPStart.x = roofLine.x1
+
+ const moveDist = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
+ ePoint = { x: wallBaseLine.x2, y: wallBaseLine.y2 }
+ newPEnd.y = wallBaseLine.y2
+
+ findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'right_in_end' })
+ const newPointX = Big(roofLine.x1).minus(moveDist).toNumber()
+ const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
+ const pLineY = Big(roofLine.y2).minus(0).abs().toNumber()
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const pLineX = sortRoofLines[idx + 1].x2
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineX = sortRoofLines[nextIndex].x2
+
+ getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
+ getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: newPointX, y: roofLine.y1 }, 'orange')
+
+ if (Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
+ getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
+ }
+ getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
+ }
+ } else if (condition === 'right_out') {
+ console.log('right_out::::isStartEnd:::::', isStartEnd)
+ if (isStartEnd.start) {
+ //x1 inside
+ const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
+ const aStartY = Big(roofLine.y1).plus(moveDist).abs().toNumber()
+ const bStartY = Big(wallLine.y1).plus(moveDist).abs().toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 })
+ console.log('startLines:::::::', inLine)
+ const eLineY = Big(bStartY).minus(wallLine.y1).abs().toNumber()
+ newPStart.y = aStartY
+ newPEnd.y = roofLine.y2 //Big(roofLine.y2).plus(eLineY).toNumber()
+ // let idx = 0 >= index - 1 ? sortRoofLines.length : index
+ // const newLine = sortRoofLines[idx - 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const newLine = sortRoofLines[nextIndex]
+
+ if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
+ if (inLine) {
+ if (inLine.x2 < inLine.x1) {
+ getAddLine({ y: bStartY, x: wallLine.x2 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x2 }, 'pink')
+ }
+ }
+ getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta')
+ getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray')
+ findPoints.push({ y: aStartY, x: newPEnd.x, position: 'right_out_start' })
+ } else {
+ const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
+ newPStart.y = Big(newPStart.y).plus(cLineY).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.x2 < inLine.x1) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x }, 'purple')
+ }
+ } else {
+ //newPStart.y = wallLine.y1;
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.x1).minus(roofLine.x1).abs().toNumber()
+ newPStart.y = Big(wallBaseLine.y1).plus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.x2 > inLine.x1) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: newPStart.y, x: newPStart.x }, 'purple')
+ }
+ }
+ }
+ }
+ }
+
+ if (isStartEnd.end) {
+ const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
+ const aStartY = Big(roofLine.y2).minus(moveDist).abs().toNumber()
+ const bStartY = Big(wallLine.y2).minus(moveDist).abs().toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 })
+ console.log('startLines:::::::', inLine)
+ const eLineY = Big(bStartY).minus(wallLine.y2).abs().toNumber()
+ newPEnd.y = aStartY
+ newPStart.y = roofLine.y1 //Big(roofLine.y1).minus(eLineY).toNumber()
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const newLine = sortRoofLines[idx + 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length;
+ const nextIndex = (index + 1) % sortRoofLines.length;
+ const newLine = sortRoofLines[prevIndex]
+
+ if (inLine) {
+ if (inLine.x2 < inLine.x1) {
+ getAddLine({ y: bStartY, x: wallLine.x1 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x1 }, 'pink')
+ }
+ }
+ if (Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
+ getAddLine({ y: bStartY, x: wallLine.x1 }, { y: roofLine.y2, x: wallLine.x2 }, 'magenta')
+ getAddLine({ y: newLine.y2, x: newLine.x2 }, { y: newLine.y1, x: wallLine.x1 }, 'Gray')
+ findPoints.push({ y: aStartY, x: newPEnd.x, position: 'right_out_end' })
+ } else {
+ const cLineY = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
+ newPEnd.y = Big(newPEnd.y).minus(cLineY).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.x2 < inLine.x1) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ } else {
+ //newPEnd.y = wallLine.y2;
+
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber()
+ newPEnd.y = Big(wallBaseLine.y2).minus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.x2 > inLine.x1) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (getOrientation(roofLine) === 'horizontal') {
+ //red
+
+ if (['top', 'bottom'].includes(mLine.position)) {
+ if (Math.abs(wallLine.y1 - wallBaseLine.y1) < 0.1 || Math.abs(wallLine.y2 - wallBaseLine.y2) < 0.1) {
+ return false
+ }
+ const isTopPosition = mLine.position === 'top'
+ const isBottomPosition = mLine.position === 'bottom'
+ const isInPosition =
+ (isTopPosition && wallLine.y1 < wallBaseLine.y1) ||
+ (isBottomPosition && wallLine.y1 > wallBaseLine.y1) ||
+ (isTopPosition && wallLine.y2 < wallBaseLine.y2) ||
+ (isBottomPosition && wallLine.y2 > wallBaseLine.y2)
+
+ const positionType = isInPosition ? 'in' : 'out'
+ const condition = `${mLine.position}_${positionType}`
+ let isStartEnd = findInteriorPoint(wallBaseLine, sortWallBaseLines)
+
+ let sPoint, ePoint
+
+ if (condition === 'top_in') {
+ if (isStartEnd.start) {
+ const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
+ sPoint = { x: wallBaseLine.x1, y: wallBaseLine.y1 }
+ newPStart.x = wallBaseLine.x1
+
+ const newPointY = Big(roofLine.y2).plus(moveDist).toNumber()
+
+ const pDist = Big(wallLine.y2).minus(roofLine.y2).abs().toNumber()
+ const pLineX = Big(roofLine.x1).minus(0).toNumber()
+ // let idx = 0 >= index - 1 ? sortRoofLines.length : index
+ // const pLineY = sortRoofLines[idx - 1].y1
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineY = sortRoofLines[prevIndex].y1
+
+
+ getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
+ findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'top_in_start' })
+
+ if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
+ getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
+ }
+ //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
+ }
+
+ if (isStartEnd.end) {
+ const moveDist = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
+ sPoint = { x: wallBaseLine.x2, y: wallBaseLine.y2 }
+ newPEnd.x = wallBaseLine.x2
+
+ const newPointY = Big(roofLine.y1).plus(moveDist).toNumber()
+
+ const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber()
+ const pLineX = Big(roofLine.x2).minus(0).abs().toNumber()
+
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const pLineY = sortRoofLines[idx + 1].y2
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineY = sortRoofLines[nextIndex].y2
+
+ getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
+ findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'top_in_end' })
+
+ if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
+ getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
+ }
+
+ //getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange')
+ }
+ } else if (condition === 'top_out') {
+ console.log('top_out isStartEnd:::::::', isStartEnd)
+
+ if (isStartEnd.start) {
+ const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
+ const aStartX = Big(roofLine.x1).plus(moveDist).toNumber()
+ const bStartX = Big(wallLine.x1).plus(moveDist).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: newPEnd.y })
+
+ const eLineX = Big(bStartX).minus(wallLine.x1).abs().toNumber()
+ newPEnd.x = roofLine.x2 //Big(newPEnd.x).plus(eLineX).toNumber()
+ newPStart.x = aStartX
+ // let idx = 0 > index - 1 ? sortRoofLines.length : index
+ // const newLine = sortRoofLines[idx - 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length;
+ const nextIndex = (index + 1) % sortRoofLines.length;
+ const newLine = sortRoofLines[nextIndex]
+
+ if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
+ if (inLine) {
+ if (inLine.y2 > inLine.y1) {
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
+ } else {
+ getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
+ }
+ }
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta')
+ getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
+ findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_start' })
+ } else {
+ const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber()
+ newPStart.x = Big(newPStart.x).plus(cLineX).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.y2 > inLine.y1) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x }, 'purple')
+ }
+ } else {
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber()
+ newPStart.x = Big(wallBaseLine.x1).plus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.y2 > inLine.y1) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x }, 'purple')
+ }
+ }
+ }
+ }
+ }
+ if (isStartEnd.end) {
+ const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
+ const aStartX = Big(roofLine.x2).minus(moveDist).abs().toNumber()
+ const bStartX = Big(wallLine.x2).minus(moveDist).abs().toNumber()
+ const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: newPEnd.y })
+ console.log('startLines:::::::', inLine)
+ const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber()
+ newPStart.x = roofLine.x1 //Big(newPStart.x).minus(eLineX).abs().toNumber()
+ newPEnd.x = aStartX
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const newLine = sortRoofLines[idx + 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length;
+ const nextIndex = (index + 1) % sortRoofLines.length;
+ const newLine = sortRoofLines[prevIndex]
+
+ if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
+ if (inLine) {
+ if (inLine.y2 > inLine.y1) {
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
+ } else {
+ getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
+ }
+ }
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
+ getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
+ findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_end' })
+ } else {
+ const cLineX = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
+ newPEnd.x = Big(newPEnd.x).minus(cLineX).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.y2 > inLine.y1) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ } else {
+ //newPEnd.x = wallLine.x2;
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber()
+ newPEnd.x = Big(wallBaseLine.x2).minus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.y1 > inLine.y2) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ }
+ }
+ }
+ }
+ } else if (condition === 'bottom_in') {
+ if (isStartEnd.start) {
+ const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
+ sPoint = { x: wallBaseLine.x1, y: wallBaseLine.y1 }
+ newPStart.x = wallBaseLine.x1
+
+ const newPointY = Big(roofLine.y2).minus(moveDist).toNumber()
+
+ const pDist = Big(wallLine.y2).minus(roofLine.y2).abs().toNumber()
+ const pLineX = Big(roofLine.x1).minus(0).abs().toNumber()
+
+ // let idx = 0 > index - 1 ? sortRoofLines.length : index
+ // const pLineY = sortRoofLines[idx - 1].y1
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineY = sortRoofLines[prevIndex].y1
+
+ getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
+ findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'bottom_in_start' })
+
+ if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
+ getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
+ }
+ getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
+ }
+
+ if (isStartEnd.end) {
+ const moveDist = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
+ sPoint = { x: wallBaseLine.x2, y: wallBaseLine.y2 }
+ newPEnd.x = wallBaseLine.x2
+
+ const newPointY = Big(roofLine.y1).minus(moveDist).toNumber()
+
+ const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber()
+ const pLineX = Big(roofLine.x2).minus(0).abs().toNumber()
+
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const pLineY = sortRoofLines[idx + 1].y2
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length
+ const nextIndex = (index + 1) % sortRoofLines.length
+ const pLineY = sortRoofLines[nextIndex].y2
+
+
+ getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
+ findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'bottom_in_end' })
+
+ if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
+ getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
+ getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
+ }
+ getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange')
+ }
+ } else if (condition === 'bottom_out') {
+ console.log('bottom_out isStartEnd:::::::', isStartEnd)
+ if (isStartEnd.start) {
+ const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
+ const aStartX = Big(roofLine.x1).minus(moveDist).abs().toNumber()
+ const bStartX = Big(wallLine.x1).minus(moveDist).abs().toNumber()
+ const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: roofLine.y1 })
+ console.log('startLines:::::::', inLine)
+ const eLineX = Big(bStartX).minus(wallLine.x1).abs().toNumber()
+ newPEnd.x = roofLine.x2 //Big(roofLine.x2).minus(eLineX).toNumber()
+ newPStart.x = aStartX
+ // let idx = 0 > index - 1 ? sortRoofLines.length : index
+ // const newLine = sortRoofLines[idx - 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length;
+ const nextIndex = (index + 1) % sortRoofLines.length;
+ const newLine = sortRoofLines[nextIndex]
+
+ if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
+ if (inLine) {
+ if (inLine.y2 < inLine.y1) {
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
+ } else {
+ getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
+ }
+ }
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta')
+ getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
+ findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_start' })
+ } else {
+ const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber()
+ newPStart.x = Big(newPStart.x).minus(cLineX).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.y2 < inLine.y1) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x }, 'purple')
+ }
+ } else {
+ //newPStart.x = wallLine.x1;
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber()
+ newPStart.x = Big(wallBaseLine.x1).minus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
+ if (inLine) {
+ if (inLine.y2 > inLine.y1) {
+ getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: newPStart.y, x: newPStart.x }, 'purple')
+ }
+ }
+ }
+ }
+ }
+
+ if (isStartEnd.end) {
+ const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
+ const aStartX = Big(roofLine.x2).plus(moveDist).toNumber()
+ const bStartX = Big(wallLine.x2).plus(moveDist).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: roofLine.y1 })
+ console.log('startLines:::::::', inLine)
+ const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber()
+ newPEnd.x = aStartX
+ newPStart.x = roofLine.x1 //Big(roofLine.x1).plus(eLineX).toNumber()
+ // let idx = sortRoofLines.length < index + 1 ? 0 : index
+ // const newLine = sortRoofLines[idx + 1]
+
+ const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length;
+ const nextIndex = (index + 1) % sortRoofLines.length;
+ const newLine = sortRoofLines[prevIndex]
+
+ if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
+ if (inLine) {
+ if (inLine.y2 < inLine.y1) {
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
+ } else {
+ getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
+ }
+ }
+ getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
+ getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
+ findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_end' })
+ } else {
+ const cLineX = Big(wallBaseLine.y2).minus(wallLine.y2).abs().toNumber()
+ newPEnd.x = Big(newPEnd.x).plus(cLineX).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.y2 < inLine.y1) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ } else {
+ //newPEnd.x = wallLine.x2;
+ //외곽 라인 그리기
+ const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber()
+ newPEnd.x = Big(wallBaseLine.x2).plus(rLineM).toNumber()
+ const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
+ if (inLine) {
+ if (inLine.y1 > inLine.y2) {
+ getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
+ } else {
+ getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ getAddLine(newPStart, newPEnd, 'red')
+ //canvas.remove(roofLine)
+ } else {
+ getAddLine(roofLine.startPoint, roofLine.endPoint)
+ }
+
+ canvas.renderAll()
+ })
}
+ getMoveUpDownLine()
-
- // function sortCurrentRoofLines(lines) {
- // return [...lines].sort((a, b) => {
- // const aX = a.x1 ?? a.get('x1')
- // const aY = a.y1 ?? a.get('y1')
- // const bX = b.x1 ?? b.get('x1')
- // const bY = b.y1 ?? b.get('y1')
-
- // if (aX !== bX) return aX - bX
- // return aY - bY
- // })
- // }
-
-
- // 각 라인 집합 정렬
-
- // roofLines의 방향에 맞춰 currentRoofLines의 방향을 조정
- const alignLineDirection = (sourceLines, targetLines) => {
- return sourceLines.map(sourceLine => {
- // 가장 가까운 targetLine 찾기
- const nearestTarget = targetLines.reduce((nearest, targetLine) => {
- const sourceCenter = {
- x: (sourceLine.x1 + sourceLine.x2) / 2,
- y: (sourceLine.y1 + sourceLine.y2) / 2
- };
- const targetCenter = {
- x: (targetLine.x1 + targetLine.x2) / 2,
- y: (targetLine.y1 + targetLine.y2) / 2
- };
- const distance = Math.hypot(
- sourceCenter.x - targetCenter.x,
- sourceCenter.y - targetCenter.y
- );
-
- return !nearest || distance < nearest.distance
- ? { line: targetLine, distance }
- : nearest;
- }, null)?.line;
-
- if (!nearestTarget) return sourceLine;
-
- // 방향이 반대인지 확인 (벡터 내적을 사용)
- const sourceVec = {
- x: sourceLine.x2 - sourceLine.x1,
- y: sourceLine.y2 - sourceLine.y1
- };
- const targetVec = {
- x: nearestTarget.x2 - nearestTarget.x1,
- y: nearestTarget.y2 - nearestTarget.y1
- };
-
- const dotProduct = sourceVec.x * targetVec.x + sourceVec.y * targetVec.y;
-
- // 내적이 음수이면 방향이 반대이므로 뒤집기
- if (dotProduct < 0) {
- return {
- ...sourceLine,
- x1: sourceLine.x2,
- y1: sourceLine.y2,
- x2: sourceLine.x1,
- y2: sourceLine.y1
- };
- }
-
- return sourceLine;
- });
- };
-
- console.log("wallBaseLines", wall.baseLines)
- // const sortedWallLines = sortCurrentRoofLines(wall.lines);
- // roofLines의 방향에 맞춰 currentRoofLines 조정 후 정렬
- const alignedCurrentRoofLines = alignLineDirection(currentRoofLines, roofLines);
- const sortedCurrentRoofLines = sortCurrentRoofLines(alignedCurrentRoofLines);
- // const sortedRoofLines = sortCurrentRoofLines(roofLines);
- const sortedWallBaseLines = sortCurrentRoofLines(wall.baseLines);
- // const sortedBaseLines = sortBaseLinesByWallLines(wall.baseLines, wallLines);
- const sortRoofLines = sortBaseLinesByWallLines(roofLines, wallLines);
-
- // 원본 wallLines를 복사하여 사용
- const sortedWallLines = [...wallLines];
- const sortedBaseLines = sortBaseLinesByWallLines(wall.baseLines, sortedWallLines);
- const sortedRoofLines = sortBaseLinesByWallLines(roofLines, sortedWallLines);
-
- //wall.lines 는 기본 벽 라인
- //wall.baseLine은 움직인라인
- const movedLines = []
-
- // 조건에 맞는 라인들만 필터링
- const validWallLines = wallLines.filter((wallLine, index) => wallLine.idx - 1 === index);
-
-
- validWallLines.forEach((wallLine, index) => {
-
- const originalIndex = wallLines.indexOf(wallLine);
- const roofLine = sortRoofLines[originalIndex];
- const currentRoofLine = currentRoofLines[originalIndex];
- const moveLine = wall.baseLines[originalIndex];
- const wallBaseLine = wall.baseLines[originalIndex];
-
- // const roofLine = sortRoofLines[index];
-
- if(roofLine.attributes.wallLine !== wallLine.id || (roofLine.idx - 1) !== index ){
- console.log("wallLine2::::", wallLine.id)
- console.log('roofLine:::',roofLine.attributes.wallLine)
- console.log("w:::",wallLine.startPoint, wallLine.endPoint)
- console.log("R:::",roofLine.startPoint, roofLine.endPoint)
- console.log("not matching roofLine", roofLine);
- return false
- }//roofLines.find(line => line.attributes.wallLineId === wallLine.attributes.wallId);
-
- // const currentRoofLine = currentRoofLines[index];
- // const moveLine = wall.baseLines[index]
- // const wallBaseLine = wall.baseLines[index]
- //console.log("wallBaseLine", wallBaseLine);
-
- //roofline 외곽선 설정
- console.log("index::::", index)
- console.log('roofLine:::',roofLine)
- console.log('wallLine', wallLine)
- console.log('wallBaseLine', wallBaseLine)
-
-
- const origin = moveLine.attributes?.originPoint
- if (!origin) return
-
- if (isSamePoint(moveLine, wallLine)) {
-
- return false
- }
-
- const movedStart = Math.abs(moveLine.x1 - wallLine.x1) > EPSILON || Math.abs(moveLine.y1 - origin.y1) > EPSILON
- const movedEnd = Math.abs(moveLine.x2 - wallLine.x2) > EPSILON || Math.abs(moveLine.y2 - origin.y2) > EPSILON
-
-
- const fullyMoved = movedStart && movedEnd
-
-
-//반시계 방향
- let newPStart //= {x:roofLine.x1, y:roofLine.y1}
- let newPEnd //= {x:movedLines.x2, y:movedLines.y2}
-
-//현재 roof는 무조건 시계방향
-
- const getAddLine = (p1, p2, stroke = '') => {
- movedLines.push({ index, p1, p2 })
-
-// Usage:
- // let mergeLines = mergeMovedLines(movedLines);
- //console.log("mergeLines:::::::", mergeLines);
- const line = new QLine([p1.x, p1.y, p2.x, p2.y], {
- parentId : roof.id,
- fontSize : roof.fontSize,
- stroke : '#3FBAE6',
- strokeWidth: 4,
- name : 'eaveHelpLine',
- lineName : 'eaveHelpLine',
- selectable : true,
- visible : true,
- roofId : roofId,
- attributes : {
- type: 'eaveHelpLine',
- isStart : true,
- pitch: wallLine.attributes.pitch,
- }
- });
- //coordinateText(line)
- canvas.add(line)
- canvas.renderAll();
- return line
- }
-
- //getAddLine(roofLine.startPoint, roofLine.endPoint, ) //외곽선을 그린다
-
- newPStart = { x: roofLine.x1, y: roofLine.y1 }
- newPEnd = { x: roofLine.x2, y: roofLine.y2 }
-
- const getInnerLines = (lines, point) => {
-
- }
- let isIn = false
- let isOut = false
-
-//두 포인트가 변경된 라인인
- if (fullyMoved ) {
- //반시계방향향
-
- const mLine = getSelectLinePosition(wall, wallBaseLine)
-
- if (getOrientation(roofLine) === 'vertical') {
-
- if (['left', 'right'].includes(mLine.position)) {
- if(Math.abs(wallLine.x1 - wallBaseLine.x1) < 0.1 || Math.abs(wallLine.x2 - wallBaseLine.x2) < 0.1) {
- return false
- }
- const positionType =
- (mLine.position === 'left' && wallLine.x1 < wallBaseLine.x1) ||
- (mLine.position === 'right' && wallLine.x1 > wallBaseLine.x1)
- ? 'in' : 'out';
- const condition = `${mLine.position}_${positionType}`;
- let isStartEnd = findInteriorPoint(wallBaseLine, sortedBaseLines)
- let sPoint, ePoint;
- if(condition === 'left_in') {
- isIn = true
-
- if (isStartEnd.start ) {
- newPEnd.y = roofLine.y2;
- newPEnd.x = roofLine.x2;
-
- const moveDist = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
- ePoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
- newPStart.y = wallBaseLine.y1
-
- findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'left_in_start' });
- const newPointX = Big(roofLine.x1).plus(moveDist).abs().toNumber()
- const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
- const pLineY = Big(roofLine.y1).minus(0).abs().toNumber()
- let idx = (0 > index - 1)?roofLines.length:index
- const pLineX = roofLines[idx-1].x1
-
- getAddLine({ x: newPStart.x, y: newPStart.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
- getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
-
- if(Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
- getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
- }
- }
-
- if(isStartEnd.end) {
- newPStart.y = roofLine.y1;
- newPStart.x = roofLine.x1;
-
- const moveDist = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
- ePoint = {x: wallBaseLine.x2, y: wallBaseLine.y2};
- newPEnd.y = wallBaseLine.y2
-
- findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'left_in_end' });
- const newPointX = Big(roofLine.x1).plus(moveDist).toNumber()
- const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
- const pLineY = Big(roofLine.y2).minus(0).abs().toNumber()
- let idx = (roofLines.length < index + 1)?0:index
- const pLineX = roofLines[idx+1].x2
-
- getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
- getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: newPointX, y: roofLine.y1 }, 'orange')
-
- if(Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
- getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
- }
- //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
- }
-
- }else if(condition === 'left_out') {
- console.log("left_out::::isStartEnd:::::", isStartEnd);
- if(isStartEnd.start){
-
- const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
- const aStartY = Big(roofLine.y1).minus(moveDist).abs().toNumber()
- const bStartY = Big(wallLine.y1).minus(moveDist).abs().toNumber()
- const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x2 })
-
- const eLineY = Big(bStartY).minus(wallLine.y1).abs().toNumber()
- newPStart.y = aStartY
- newPEnd.y = roofLine.y2 //Big(roofLine.y2).minus(eLineY).toNumber()
- let idx = (0 >= index - 1)?roofLines.length:index
- const newLine = roofLines[idx-1];
-
- if(Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
- if(inLine){
- if(inLine.x1 < inLine.x2) {
- getAddLine({ y: bStartY, x: wallLine.x2 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
- }else{
- getAddLine({ y: inLine.y2, x: inLine.x2 },{ y: bStartY, x: wallLine.x2 }, 'pink')
- }
-
- }
- getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta')
- getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray')
- findPoints.push({ y: aStartY, x: newPStart.x, position: 'left_out_start' });
- }else{
- const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
- newPStart.y = Big(newPStart.y).minus(cLineY).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine){
- if(inLine.x1 < inLine.x2) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1},{ y: newPStart.y, x: newPStart.x }, 'purple')
- }
- }else {
- //newPStart.y = wallLine.y1;
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber();
- newPStart.y = Big(wallBaseLine.y1).minus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine) {
- if (inLine.x2 > inLine.x1) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- } else {
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
- }
- }
- }
-
- }
- }
-
-
- if(isStartEnd.end){
- const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
- const aStartY = Big(roofLine.y2).plus(moveDist).toNumber()
- const bStartY = Big(wallLine.y2).plus(moveDist).toNumber()
- const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 })
- console.log("startLines:::::::", inLine);
- const eLineY = Big(bStartY).minus(wallLine.y2).abs().toNumber()
- newPEnd.y = aStartY
- newPStart.y = roofLine.y1//Big(roofLine.y1).plus(eLineY).toNumber()
- let idx = (roofLines.length < index + 1)?0:index
- const newLine = roofLines[idx+1];
-
- if(Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
- if(inLine){
- if(inLine.x1 < inLine.x2) {
- getAddLine({ y: bStartY, x: wallLine.x1 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x1 }, 'pink')
- }
- }
- getAddLine({ y: bStartY, x: wallLine.x1 }, { y: roofLine.y2, x: wallLine.x2 }, 'magenta')
- getAddLine({ y: newLine.y2, x: newLine.x2 }, { y: newLine.y1, x: wallLine.x1 }, 'Gray')
- findPoints.push({ y: aStartY, x: newPEnd.x, position: 'left_out_end' });
- }else{
- const cLineY = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
- newPEnd.y = Big(newPEnd.y).plus(cLineY).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine){
- if(inLine.x1 < inLine.x2) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 },{ y: newPEnd.y, x: newPEnd.x }, 'purple')
- }
- }else {
-
- // newPEnd.y = wallLine.y2
-
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber();
- newPEnd.y = Big(wallBaseLine.y2).plus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine) {
- if (inLine.x2 > inLine.x1) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- } else {
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
- }
- }
- }
-
- }
- findPoints.push({ y: newPStart.y, x: newPEnd.x, position: 'left_out_end' });
- }
- }else if(condition === 'right_in') {
- if (isStartEnd.start ) {
-
- newPEnd.y = roofLine.y2;
- newPEnd.x = roofLine.x2;
-
- const moveDist = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
- ePoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
- newPStart.y = wallBaseLine.y1
-
- findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'right_in_start'});
- const newPointX = Big(roofLine.x1).minus(moveDist).abs().toNumber()
- const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
- const pLineY = Big(roofLine.y1).minus(0).abs().toNumber()
- let idx = (0 >= index - 1)?roofLines.length:index
- const pLineX = roofLines[idx-1].x1
-
- getAddLine({ x: newPStart.x, y: newPStart.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
- //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
-
- if(Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
- getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
- }
- }
-
- if(isStartEnd.end) {
- newPStart.y = roofLine.y1;
- newPStart.x = roofLine.x1;
-
- const moveDist = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
- ePoint = {x: wallBaseLine.x2, y: wallBaseLine.y2};
- newPEnd.y = wallBaseLine.y2
-
- findPoints.push({ x: ePoint.x, y: ePoint.y, position: 'right_in_end' });
- const newPointX = Big(roofLine.x1).minus(moveDist).toNumber()
- const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
- const pLineY = Big(roofLine.y2).minus(0).abs().toNumber()
- let idx = (roofLines.length < index + 1)?0:index
- const pLineX = roofLines[idx+1].x2
-
- getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
- getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: newPointX, y: roofLine.y1 }, 'orange')
-
- if(Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
- getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
- }
- getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
- }
-
- }else if(condition === 'right_out') {
- console.log("right_out::::isStartEnd:::::", isStartEnd);
- if (isStartEnd.start ) { //x1 inside
- const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
- const aStartY = Big(roofLine.y1).plus(moveDist).abs().toNumber()
- const bStartY = Big(wallLine.y1).plus(moveDist).abs().toNumber()
- const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 })
- console.log("startLines:::::::", inLine);
- const eLineY = Big(bStartY).minus(wallLine.y1).abs().toNumber()
- newPStart.y = aStartY
- newPEnd.y = roofLine.y2//Big(roofLine.y2).plus(eLineY).toNumber()
- let idx = (0 >= index - 1)?roofLines.length:index
- const newLine = roofLines[idx-1];
-
- if(Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) {
- if(inLine){
- if(inLine.x2 < inLine.x1) {
- getAddLine({ y: bStartY, x: wallLine.x2 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 },{ y: bStartY, x: wallLine.x2 }, 'pink')
- }
- }
- getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta')
- getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray')
- findPoints.push({ y: aStartY, x: newPEnd.x, position: 'right_out_start' });
- }else{
- const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
- newPStart.y = Big(newPStart.y).plus(cLineY).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine){
- if(inLine.x2 < inLine.x1 ) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 },{ y: newPStart.y, x: newPStart.x }, 'purple')
- }
- }else {
- //newPStart.y = wallLine.y1;
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.x1).minus(roofLine.x1).abs().toNumber();
- newPStart.y = Big(wallBaseLine.y1).plus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine){
- if(inLine.x2 > inLine.x1 ) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
- }else{
- getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: newPStart.y, x: newPStart.x } , 'purple')
- }
- }
-
- }
-
- }
-
- }
-
- if(isStartEnd.end){
- const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber()
- const aStartY = Big(roofLine.y2).minus(moveDist).abs().toNumber()
- const bStartY = Big(wallLine.y2).minus(moveDist).abs().toNumber()
- const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 })
- console.log("startLines:::::::", inLine);
- const eLineY = Big(bStartY).minus(wallLine.y2).abs().toNumber()
- newPEnd.y = aStartY
- newPStart.y = roofLine.y1//Big(roofLine.y1).minus(eLineY).toNumber()
- let idx = (roofLines.length < index + 1)?0:index
- const newLine = roofLines[idx+1];
- if(inLine){
- if(inLine.x2 < inLine.x1) {
- getAddLine({ y: bStartY, x: wallLine.x1 }, { y: inLine.y2, x: inLine.x2 }, 'pink')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 },{ y: bStartY, x: wallLine.x1 }, 'pink')
- }
- }
- if(Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
- getAddLine({ y: bStartY, x: wallLine.x1 }, { y: roofLine.y2, x: wallLine.x2 }, 'magenta')
- getAddLine({ y: newLine.y2, x: newLine.x2 }, { y: newLine.y1, x: wallLine.x1 }, 'Gray')
- findPoints.push({ y: aStartY, x: newPEnd.x, position: 'right_out_end' });
- }else{
- const cLineY = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
- newPEnd.y = Big(newPEnd.y).minus(cLineY).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine){
- if(inLine.x2 < inLine.x1) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x }, 'purple')
- }
- }else {
- //newPEnd.y = wallLine.y2;
-
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber();
- newPEnd.y = Big(wallBaseLine.y2).minus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine){
- if(inLine.x2 > inLine.x1 ) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
- }else{
- getAddLine({ y: inLine.y2, x: inLine.x2}, { y: newPEnd.y, x: newPEnd.x } , 'purple')
- }
- }
-
- }
-
- }
- }
- }
- }
- } else if (getOrientation(roofLine) === 'horizontal') { //red
-
- if (['top', 'bottom'].includes(mLine.position)) {
- if(Math.abs(wallLine.y1 - wallBaseLine.y1) < 0.1 || Math.abs(wallLine.y2 - wallBaseLine.y2) < 0.1) {
- return false
- }
- const positionType =
- (mLine.position === 'top' && wallLine.y1 < wallBaseLine.y1) ||
- (mLine.position === 'bottom' && wallLine.y1 > wallBaseLine.y1)
- ? 'in' : 'out';
-
- const condition = `${mLine.position}_${positionType}`;
- let isStartEnd = findInteriorPoint(wallBaseLine, sortedBaseLines)
-
- let sPoint, ePoint;
-
- if(condition === 'top_in') {
- if (isStartEnd.start ) {
- const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
- sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
- newPStart.x = wallBaseLine.x1;
-
-
- const newPointY = Big(roofLine.y2).plus(moveDist).toNumber()
-
- const pDist = Big(wallLine.y2).minus(roofLine.y2).abs().toNumber()
- const pLineX = Big(roofLine.x1).minus(0).abs().toNumber()
- let idx = (0 >= index - 1)?roofLines.length:index
- const pLineY = roofLines[idx-1].y1
- getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
- findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'top_in_start' });
-
- if(Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
- getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
- }
- //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
-
- }
-
- if(isStartEnd.end){
- const moveDist = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
- sPoint = { x: wallBaseLine.x2, y: wallBaseLine.y2 }
- newPEnd.x = wallBaseLine.x2
-
- const newPointY = Big(roofLine.y1).plus(moveDist).toNumber()
-
- const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber()
- const pLineX = Big(roofLine.x2).minus(0).abs().toNumber()
- let idx = roofLines.length < index + 1 ? 0 : index
- const pLineY = roofLines[idx + 1].y2
- getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
- findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'top_in_end' });
-
- if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
- getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
- }
-
-
- //getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange')
- }
-
- }else if(condition === 'top_out') {
- console.log("top_out isStartEnd:::::::", isStartEnd);
-
- if (isStartEnd.start ) {
- const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
- const aStartX = Big(roofLine.x1).plus(moveDist).toNumber()
- const bStartX = Big(wallLine.x1).plus(moveDist).toNumber()
- const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: newPEnd.y })
-
- const eLineX = Big(bStartX).minus(wallLine.x1).abs().toNumber()
- newPEnd.x = roofLine.x2 //Big(newPEnd.x).plus(eLineX).toNumber()
- newPStart.x = aStartX
- let idx = (0 > index - 1)?roofLines.length:index
- const newLine = roofLines[idx-1];
-
- if(Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
- if(inLine){
- if(inLine.y2 > inLine.y1 ) {
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
- }else{
- getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
- }
- }
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta')
- getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
- findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_start' });
- }else{
- const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber()
- newPStart.x = Big(newPStart.x).plus(cLineX).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine){
- if(inLine.y2 > inLine.y1 ) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x } , 'purple')
- }
-
- }else {
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber();
- newPStart.x = Big(wallBaseLine.x1).plus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine){
- if(inLine.y2 > inLine.y1 ) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x } , 'purple')
- }
- }
- }
-
- }
- }
- if(isStartEnd.end){
- const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
- const aStartX = Big(roofLine.x2).minus(moveDist).abs().toNumber()
- const bStartX = Big(wallLine.x2).minus(moveDist).abs().toNumber()
- const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: newPEnd.y })
- console.log("startLines:::::::", inLine);
- const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber()
- newPStart.x = roofLine.x1;//Big(newPStart.x).minus(eLineX).abs().toNumber()
- newPEnd.x = aStartX
- let idx = (roofLines.length < index + 1)?0:index
- const newLine = roofLines[idx+1];
-
- if(Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
- if(inLine){
- if(inLine.y2 > inLine.y1 ){
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
- }else{
- getAddLine({ x: inLine.x1, y: inLine.y1 },{ x: bStartX, y: wallLine.y1 }, 'pink')
- }
-
- }
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
- getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
- findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_end' });
- }else{
- const cLineX = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
- newPEnd.x = Big(newPEnd.x).minus(cLineX).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine){
- if(inLine.y2 > inLine.y1 ) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 },{ y: newPEnd.y, x: newPEnd.x }, 'purple')
- }
- }else {
- //newPEnd.x = wallLine.x2;
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber();
- newPEnd.x = Big(wallBaseLine.x2).minus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine){
- if(inLine.y1 > inLine.y2 ) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
- }else{
- getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: newPEnd.y, x: newPEnd.x } , 'purple')
- }
- }
- }
-
- }
- }
- }else if(condition === 'bottom_in') {
- if (isStartEnd.start ) {
- const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
- sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
- newPStart.x = wallBaseLine.x1;
-
-
- const newPointY = Big(roofLine.y2).minus(moveDist).toNumber()
-
- const pDist = Big(wallLine.y2).minus(roofLine.y2).abs().toNumber()
- const pLineX = Big(roofLine.x1).minus(0).abs().toNumber()
- let idx = (0 > index - 1)?roofLines.length:index
- const pLineY = roofLines[idx-1].y1
- getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
- findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'bottom_in_start' });
-
- if(Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
- getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
- }
- getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
- }
-
- if(isStartEnd.end){
- const moveDist = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
- sPoint = {x: wallBaseLine.x2, y: wallBaseLine.y2};
- newPEnd.x = wallBaseLine.x2;
-
-
- const newPointY = Big(roofLine.y1).minus(moveDist).toNumber()
-
- const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber()
- const pLineX = Big(roofLine.x2).minus(0).abs().toNumber()
- let idx = (roofLines.length < index + 1)?0:index
- const pLineY = roofLines[idx+1].y2
- getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
- findPoints.push({ x: sPoint.x, y: sPoint.y, position: 'bottom_in_end' });
-
- if(Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
- getAddLine({ x: pLineX, y: pLineY }, { x: pLineX, y: newPointY }, 'green')
- getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
- }
- getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange')
-
- }
- }else if(condition === 'bottom_out') {
- console.log("bottom_out isStartEnd:::::::", isStartEnd);
- if (isStartEnd.start ) {
- const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
- const aStartX = Big(roofLine.x1).minus(moveDist).abs().toNumber()
- const bStartX = Big(wallLine.x1).minus(moveDist).abs().toNumber()
- const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: roofLine.y1 })
- console.log("startLines:::::::", inLine);
- const eLineX = Big(bStartX).minus(wallLine.x1).abs().toNumber()
- newPEnd.x = roofLine.x2//Big(roofLine.x2).minus(eLineX).toNumber()
- newPStart.x = aStartX
- let idx = (0 > index - 1)?roofLines.length:index
- const newLine = roofLines[idx-1];
-
-
- if(Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
- if(inLine){
- if(inLine.y2 < inLine.y1 ) {
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
- }else{
- getAddLine({ x: inLine.x1, y: inLine.y1 },{ x: bStartX, y: wallLine.y1 }, 'pink')
- }
- }
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta')
- getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
- findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_start' });
- }else{
- const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber()
- newPStart.x = Big(newPStart.x).minus(cLineX).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine){
- if(inLine.y2 < inLine.y1 ) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPStart.y, x: newPStart.x }, 'purple')
- }
- }else{
- //newPStart.x = wallLine.x1;
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber();
- newPStart.x = Big(wallBaseLine.x1).minus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x })
- if(inLine){
- if(inLine.y2 > inLine.y1 ) {
- getAddLine({ y: newPStart.y, x: newPStart.x }, { y: inLine.y1, x: inLine.x1 }, 'purple')
- }else{
- getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: newPStart.y, x: newPStart.x } , 'purple')
- }
- }
- }
-
- }
- }
-
- if(isStartEnd.end){
- const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
- const aStartX = Big(roofLine.x2).plus(moveDist).toNumber()
- const bStartX = Big(wallLine.x2).plus(moveDist).toNumber()
- const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: roofLine.y1 })
- console.log("startLines:::::::", inLine);
- const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber()
- newPEnd.x = aStartX
- newPStart.x = roofLine.x1;//Big(roofLine.x1).plus(eLineX).toNumber()
- let idx = (roofLines.length < index + 1)?0:index
- const newLine = roofLines[idx + 1];
-
- if(Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
- if(inLine){
- if(inLine.y2 < inLine.y1 ) {
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
- }else{
- getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
- }
- }
- getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
- getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
- findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_end' });
- }else{
- const cLineX = Big(wallBaseLine.y2).minus(wallLine.y2).abs().toNumber()
- newPEnd.x = Big(newPEnd.x).plus(cLineX).toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine){
- if(inLine.y2 < inLine.y1 ) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 },{ y: newPEnd.y, x: newPEnd.x }, 'purple')
- }
- }else{
- //newPEnd.x = wallLine.x2;
- //외곽 라인 그리기
- const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber();
- newPEnd.x = Big(wallBaseLine.x2).plus(rLineM).abs().toNumber();
- const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x })
- if(inLine){
- if(inLine.y1 > inLine.y2 ) {
- getAddLine({ y: newPEnd.y, x: newPEnd.x }, { y: inLine.y2, x: inLine.x2 }, 'purple')
- }else{
- getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: newPEnd.y, x: newPEnd.x } , 'purple')
- }
- }
- }
-
- }
- }
- }
- }
- }
-
- getAddLine(newPStart, newPEnd, 'red')
- //canvas.remove(roofLine)
- }else{
- getAddLine(roofLine.startPoint, roofLine.endPoint, )
- }
-
-
-
- canvas.renderAll()
- });
- // }
+ }
if (findPoints.length > 0) {
// 모든 점에 대해 라인 업데이트를 누적
@@ -1796,6 +1762,115 @@ const isSameLine = (edgeStartX, edgeStartY, edgeEndX, edgeEndY, baseLine) => {
// --- Disconnected Line Processing ---
+/**
+ * 라인들이 반시계 방향이 되도록 정렬하고, 왼쪽 상단에서 시작하는 새 배열 반환
+ * @param {Array} lines - x1, y1, x2, y2 속성을 가진 라인 객체 배열
+ * @returns {Array} 반시계 방향으로 정렬된 새 라인 배열
+ */
+export function ensureCounterClockwiseLines(lines) {
+ if (!lines || lines.length < 3) return [...(lines || [])];
+
+ // 1. 모든 점을 연결 그래프로 구성
+ const graph = new Map();
+
+ // 각 점에서 연결된 점들을 저장
+ lines.forEach(line => {
+ const p1 = `${line.x1},${line.y1}`;
+ const p2 = `${line.x2},${line.y2}`;
+
+ if (!graph.has(p1)) graph.set(p1, []);
+ if (!graph.has(p2)) graph.set(p2, []);
+
+ // 양방향 연결
+ graph.get(p1).push({ x: line.x2, y: line.y2, line });
+ graph.get(p2).push({ x: line.x1, y: line.y1, line });
+ });
+
+ // 2. 왼쪽 상단 점 찾기
+ let startPoint = null;
+ let minY = Infinity;
+ let minX = Infinity;
+
+ for (const [pointStr] of graph) {
+ const [x, y] = pointStr.split(',').map(Number);
+ if (y < minY || (y === minY && x < minX)) {
+ minY = y;
+ minX = x;
+ startPoint = { x, y };
+ }
+ }
+
+ if (!startPoint) return [...lines];
+
+ // 3. 점들을 순회하며 라인 구성
+ const visited = new Set();
+ const result = [];
+ let current = `${startPoint.x},${startPoint.y}`;
+ let prev = null;
+
+ while (true) {
+ if (visited.has(current)) break;
+ visited.add(current);
+
+ const neighbors = graph.get(current) || [];
+ if (neighbors.length === 0) break;
+
+ // 이전 점 제외
+ const nextPoints = neighbors.filter(n =>
+ !prev || `${n.x},${n.y}` !== `${prev.x},${prev.y}`
+ );
+
+ if (nextPoints.length === 0) break;
+
+ // 각도가 가장 작은(반시계 방향) 이웃 선택
+ const [cx, cy] = current.split(',').map(Number);
+ const next = nextPoints.reduce((best, curr) => {
+ const angleBest = Math.atan2(best.y - cy, best.x - cx);
+ const angleCurr = Math.atan2(curr.y - cy, curr.x - cx);
+ return angleCurr > angleBest ? curr : best;
+ }, nextPoints[0]);
+
+ // 라인 추가 (방향 유지)
+ const line = next.line;
+ const isReversed = (line.x1 !== next.x || line.y1 !== next.y);
+
+ result.push({
+ ...line,
+ x1: isReversed ? line.x2 : line.x1,
+ y1: isReversed ? line.y2 : line.y1,
+ x2: isReversed ? line.x1 : line.x2,
+ y2: isReversed ? line.y1 : line.y2,
+ idx: result.length
+ });
+
+ prev = { x: cx, y: cy };
+ current = `${next.x},${next.y}`;
+ }
+
+ // 4. 시계 방향이면 뒤집기
+ let area = 0;
+ for (let i = 0; i < result.length; i++) {
+ const current = result[i];
+ const next = result[(i + 1) % result.length];
+ area += (next.x1 - current.x1) * (next.y1 + current.y1);
+ }
+
+ if (area > 0) {
+ return result.reverse().map((line, idx) => ({
+ ...line,
+ x1: line.x2,
+ y1: line.y2,
+ x2: line.x1,
+ y2: line.y1,
+ idx
+ }));
+ }
+
+ return result;
+}
+
+
+
/**
* 점을 선분에 투영한 점의 좌표를 반환합니다.
* @param {object} point - 투영할 점 {x, y}
@@ -2369,6 +2444,14 @@ function isSamePoint(p1, p2, tolerance = 0.1) {
return Math.abs(p1.x - p2.x) < tolerance && Math.abs(p1.y - p2.y) < tolerance;
}
+function isSameLine2(line1, line2, tolerance = 0.1) {
+ return (
+ Math.abs(line1.x1 - line2.x1) < tolerance &&
+ Math.abs(line1.y1 - line2.y1) < tolerance &&
+ Math.abs(line1.x2 - line2.x2) < tolerance &&
+ Math.abs(line1.y2 - line2.y2) < tolerance
+ );
+}
// 두 점을 지나는 직선의 기울기 계산
function calculateSlope(p1, p2) {
// 수직선인 경우 (기울기 무한대)
@@ -3014,17 +3097,32 @@ function pointToLineDistance(point, lineP1, lineP2) {
const getOrientation = (line, eps = 0.1) => {
- const x1 = line.get('x1')
- const y1 = line.get('y1')
- const x2 = line.get('x2')
- const y2 = line.get('y2')
- const dx = Math.abs(x2 - x1)
- const dy = Math.abs(y2 - y1)
+ if (!line) {
+ console.error('line 객체가 유효하지 않습니다:', line);
+ return null; // 또는 적절한 기본값 반환
+ }
- if (dx < eps && dy >= eps) return 'vertical'
- if (dy < eps && dx >= eps) return 'horizontal'
- if (dx < eps && dy < eps) return 'point'
- return 'diagonal'
+ // get 메서드가 있으면 사용하고, 없으면 직접 프로퍼티에 접근
+ const getValue = (obj, key) =>
+ obj && typeof obj.get === 'function' ? obj.get(key) : obj[key];
+
+ try {
+ const x1 = getValue(line, 'x1');
+ const y1 = getValue(line, 'y1');
+ const x2 = getValue(line, 'x2');
+ const y2 = getValue(line, 'y2');
+
+ const dx = Math.abs(x2 - x1);
+ const dy = Math.abs(y2 - y1);
+
+ if (dx < eps && dy >= eps) return 'vertical';
+ if (dy < eps && dx >= eps) return 'horizontal';
+ if (dx < eps && dy < eps) return 'point';
+ return 'diagonal';
+ } catch (e) {
+ console.error('방향 계산 중 오류 발생:', e);
+ return null;
+ }
}
@@ -3393,102 +3491,3 @@ function findInteriorPoint(line, polygonLines) {
};
}
-/**
- * baseLines의 순서를 wallLines의 순서와 일치시킵니다.
- * 1순위: 공통 ID(id, matchingId, parentId 등)를 이용한 직접 매칭
- * 2순위: 기하학적 유사성(기울기, 길이, 위치)을 점수화하여 매칭
- *
- * @param {Array} baseLines - 정렬할 원본 baseLine 배열
- * @param {Array} wallLines - 기준이 되는 wallLine 배열
- * @returns {Array} wallLines 순서에 맞춰 정렬된 baseLines
- */
-export const sortBaseLinesByWallLines = (baseLines, wallLines) => {
- if (!baseLines || !wallLines || baseLines.length === 0 || wallLines.length === 0) {
- return baseLines;
- }
-
- const sortedBaseLines = new Array(wallLines.length).fill(null);
- const usedBaseIndices = new Set();
-
- // [1단계] ID 매칭 (기존 로직 유지 - 혹시 ID가 있는 경우를 대비)
- // ... (ID 매칭 코드는 생략하거나 유지) ...
-
- // [2단계] 'originPoint' 또는 좌표 일치성을 이용한 강력한 기하학적 매칭
- wallLines.forEach((wLine, wIndex) => {
- if (sortedBaseLines[wIndex]) return;
-
- // 비교할 기준 좌표 설정 (originPoint가 있으면 그것을, 없으면 현재 좌표 사용)
- const wStart = wLine.attributes?.originPoint
- ? { x: wLine.attributes.originPoint.x1, y: wLine.attributes.originPoint.y1 }
- : { x: wLine.x1, y: wLine.y1 };
-
- const wEnd = wLine.attributes?.originPoint
- ? { x: wLine.attributes.originPoint.x2, y: wLine.attributes.originPoint.y2 }
- : { x: wLine.x2, y: wLine.y2 };
-
- // 수직/수평 여부 판단
- const isVertical = Math.abs(wStart.x - wEnd.x) < 0.1;
- const isHorizontal = Math.abs(wStart.y - wEnd.y) < 0.1;
-
- let bestMatchIndex = -1;
- let minDiff = Infinity;
-
- baseLines.forEach((bLine, bIndex) => {
- if (usedBaseIndices.has(bIndex)) return;
-
- let diff = Infinity;
-
- // 1. 수직선인 경우: X좌표가 일치해야 함 (예: 230.8 == 230.8)
- if (isVertical) {
- // bLine도 수직선인지 확인 (x1, x2 차이가 거의 없어야 함)
- if (Math.abs(bLine.x1 - bLine.x2) < 1.0) {
- // X좌표 차이를 오차(diff)로 계산
- diff = Math.abs(wStart.x - bLine.x1);
- }
- }
- // 2. 수평선인 경우: Y좌표가 일치해야 함
- else if (isHorizontal) {
- // bLine도 수평선인지 확인
- if (Math.abs(bLine.y1 - bLine.y2) < 1.0) {
- diff = Math.abs(wStart.y - bLine.y1);
- }
- }
- // 3. 대각선인 경우: 기울기와 절편 비교 (복잡하므로 거리로 대체)
- else {
- // 중점 간 거리 + 기울기 차이
- // (이전 답변의 로직 사용 가능)
- }
-
- // 오차가 매우 작으면(예: 1px 미만) 같은 라인으로 간주
- if (diff < 1.0 && diff < minDiff) {
- minDiff = diff;
- bestMatchIndex = bIndex;
- }
- });
-
- if (bestMatchIndex !== -1) {
- sortedBaseLines[wIndex] = baseLines[bestMatchIndex];
- usedBaseIndices.add(bestMatchIndex);
- }
- });
-
- // [3단계] 남은 라인 처리 (Fallback)
- // 매칭되지 않은 wallLine들에 대해 남은 baseLines를 순서대로 배정하거나
- // 거리 기반 근사 매칭을 수행
- // ... (기존 fallback 로직) ...
-
- // 빈 구멍 채우기 (null 방지)
- for(let i=0; i !usedBaseIndices.has(idx));
- if(unused !== -1) {
- sortedBaseLines[i] = baseLines[unused];
- usedBaseIndices.add(unused);
- } else {
- sortedBaseLines[i] = baseLines[0]; // 최후의 수단
- }
- }
- }
-
- return sortedBaseLines;
-};
\ No newline at end of file
|