dev #494

Merged
ysCha merged 8 commits from dev into prd-deploy 2025-12-18 09:35:18 +09:00
Showing only changes of commit 6c0cc73cb8 - Show all commits

View File

@ -2426,9 +2426,20 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
intersections.sort((a, b) => a.distance - b.distance)
if (intersections.length > 0) {
const intersect = intersections[0].intersect
const point = [midPoint.x, midPoint.y, intersect.x, intersect.y]
//마루가 최대로 뻗어나갈수 있는 포인트. null일때는 맞은편 지붕선 까지로 판단한다.
const drivePoint = getRidgeDrivePoints(point, prevLine, nextLine, baseLines, canvas)
console.log('drivePoint : ', drivePoint)
if (drivePoint) {
point[2] = drivePoint.x
point[3] = drivePoint.y
}
linesAnalysis.push({
start: { x: midPoint.x, y: midPoint.y },
end: { x: intersect.x, y: intersect.y },
start: { x: point[0], y: point[1] },
end: { x: point[2], y: point[3] },
left: baseLines.findIndex((line) => line === prevLine),
right: baseLines.findIndex((line) => line === nextLine),
type: 'ridge',
@ -2559,7 +2570,169 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
})
})
//4. 반절처(반절마루) 판단, 반절마루는 양옆이 처마여야 한다.
jerkinHeads.forEach((currentLine) => {
let prevLine, nextLine
baseLines.forEach((baseLine, index) => {
if (baseLine === currentLine) {
nextLine = baseLines[(index + 1) % baseLines.length]
prevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length]
}
})
//양옆이 처마가 아닐때 패스
if (prevLine.attributes.type !== LINE_TYPE.WALLLINE.EAVES || nextLine.attributes.type !== LINE_TYPE.WALLLINE.EAVES) {
return
}
const analyze = analyzeLine(currentLine)
const roofPoints = [analyze.roofLine.x1, analyze.roofLine.y1, analyze.roofLine.x2, analyze.roofLine.y2]
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) {
//반절마루 생성불가이므로 지붕선만 추가하고 끝냄
innerLines.push(drawRoofLine(roofPoints, canvas, roof, textMode))
} else {
const midX = (roofPoints[0] + roofPoints[2]) / 2
const midY = (roofPoints[1] + roofPoints[3]) / 2
const currentDegree = getDegreeByChon(currentLine.attributes.pitch)
const prevDegree = getDegreeByChon(prevLine.attributes.pitch)
const nextDegree = getDegreeByChon(nextLine.attributes.pitch)
const gableWidth = currentLine.attributes.width
const roofVector = { x: Math.sign(roofPoints[2] - roofPoints[0]), y: Math.sign(roofPoints[3] - roofPoints[1]) }
const roofDx = roofPoints[0] - roofPoints[2]
const roofDy = roofPoints[1] - roofPoints[3]
const roofLength = Math.sqrt(roofDx * roofDx + roofDy * roofDy)
const lineLength = (roofLength - gableWidth) / 2
const jerkinPoints = []
jerkinPoints.push(
{ x: roofPoints[0], y: roofPoints[1] },
{ x: roofPoints[0] + roofVector.x * lineLength, y: roofPoints[1] + roofVector.y * lineLength },
)
jerkinPoints.push({ x: jerkinPoints[1].x + roofVector.x * gableWidth, y: jerkinPoints[1].y + roofVector.y * gableWidth })
jerkinPoints.push({ x: jerkinPoints[2].x + roofVector.x * lineLength, y: jerkinPoints[2].y + roofVector.y * lineLength })
if (gableWidth >= roofLength) {
innerLines.push(drawRoofLine(roofPoints, canvas, roof, textMode))
} else if (jerkinPoints.length === 4) {
const gablePoint1 = [jerkinPoints[0].x, jerkinPoints[0].y, jerkinPoints[1].x, jerkinPoints[1].y]
const gablePoint2 = [jerkinPoints[1].x, jerkinPoints[1].y, jerkinPoints[2].x, jerkinPoints[2].y]
const gablePoint3 = [jerkinPoints[2].x, jerkinPoints[2].y, jerkinPoints[3].x, jerkinPoints[3].y]
const gableLength1 = Math.sqrt(Math.pow(gablePoint1[2] - gablePoint1[0], 2) + Math.pow(gablePoint1[3] - gablePoint1[1], 2))
const gableLength2 = Math.sqrt(Math.pow(gablePoint2[2] - gablePoint2[0], 2) + Math.pow(gablePoint2[3] - gablePoint2[1], 2))
const gableLength3 = Math.sqrt(Math.pow(gablePoint3[2] - gablePoint3[0], 2) + Math.pow(gablePoint3[3] - gablePoint3[1], 2))
if (gableLength1 >= 1) {
innerLines.push(drawHipLine(gablePoint1, canvas, roof, textMode, null, prevDegree, prevDegree))
}
if (gableLength2 >= 1) {
innerLines.push(drawRoofLine(gablePoint2, canvas, roof, textMode))
}
if (gableLength3 >= 1) {
innerLines.push(drawHipLine(gablePoint3, canvas, roof, textMode, null, nextDegree, nextDegree))
}
const currentRoofLine = analyze.roofLine
let prevRoofLine, nextRoofLine
roof.lines.forEach((roofLine, index) => {
if (roofLine === currentRoofLine) {
nextRoofLine = roof.lines[(index + 1) % roof.lines.length]
prevRoofLine = roof.lines[(index - 1 + roof.lines.length) % roof.lines.length]
}
})
/** 이전, 다음라인의 사잇각의 vector를 구한다. */
let prevVector = getHalfAngleVector(prevRoofLine, currentRoofLine)
let nextVector = getHalfAngleVector(currentRoofLine, nextRoofLine)
/** 이전 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/
const prevCheckPoint = {
x: currentRoofLine.x1 + prevVector.x * 10,
y: currentRoofLine.y1 + prevVector.y * 10,
}
/** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/
const nextCheckPoint = {
x: currentRoofLine.x2 + nextVector.x * 10,
y: currentRoofLine.y2 + nextVector.y * 10,
}
let prevHipVector, nextHipVector
if (roof.inPolygon(prevCheckPoint)) {
prevHipVector = { x: prevVector.x, y: prevVector.y }
} else {
prevHipVector = { x: -prevVector.x, y: -prevVector.y }
}
/** 다음 라인과의 사이 추녀마루의 각도를 확인한다, 각도가 지붕안쪽으로 향하지 않을때 반대로 처리한다.*/
if (roof.inPolygon(nextCheckPoint)) {
nextHipVector = { x: nextVector.x, y: nextVector.y }
} else {
nextHipVector = { x: -nextVector.x, y: -nextVector.y }
}
const prevHipEdge = {
vertex1: { x: gablePoint2[0], y: gablePoint2[1] },
vertex2: { x: gablePoint2[0] + prevHipVector.x * gableWidth, y: gablePoint2[1] + prevHipVector.y * gableWidth },
}
const nextHipEdge = {
vertex1: { x: gablePoint2[2], y: gablePoint2[3] },
vertex2: { x: gablePoint2[2] + nextHipVector.x * gableWidth, y: gablePoint2[3] + nextHipVector.y * gableWidth },
}
const hipIntersection = edgesIntersection(prevHipEdge, nextHipEdge)
if (hipIntersection) {
const prevHipPoint = [prevHipEdge.vertex1.x, prevHipEdge.vertex1.y, hipIntersection.x, hipIntersection.y]
const nextHipPoint = [nextHipEdge.vertex1.x, nextHipEdge.vertex1.y, hipIntersection.x, hipIntersection.y]
innerLines.push(drawHipLine(prevHipPoint, canvas, roof, textMode, null, currentDegree, currentDegree))
innerLines.push(drawHipLine(nextHipPoint, canvas, roof, textMode, null, currentDegree, currentDegree))
const midPoint = { x: hipIntersection.x, y: hipIntersection.y }
const checkEdge = {
vertex1: { x: midPoint.x, y: midPoint.y },
vertex2: { x: midPoint.x + -analyze.roofVector.x * 10000, y: midPoint.y + -analyze.roofVector.y * 10000 },
}
const intersections = []
roof.lines
.filter((line) => line !== currentRoofLine)
.forEach((line) => {
const lineEdge = { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } }
const intersect = edgesIntersection(lineEdge, checkEdge)
if (intersect && isPointOnLineNew(line, intersect)) {
const distance = Math.sqrt(Math.pow(midPoint.x - intersect.x, 2) + Math.pow(midPoint.y - intersect.y, 2))
intersections.push({ intersect, distance })
}
})
intersections.sort((a, b) => a.distance - b.distance)
if (intersections.length > 0) {
const intersect = intersections[0].intersect
const point = [midPoint.x, midPoint.y, intersect.x, intersect.y]
//마루가 최대로 뻗어나갈수 있는 포인트. null일때는 맞은편 지붕선 까지로 판단한다.
const drivePoint = getRidgeDrivePoints(point, prevLine, nextLine, baseLines, canvas)
console.log('drivePoint : ', drivePoint)
if (drivePoint) {
point[2] = drivePoint.x
point[3] = drivePoint.y
}
linesAnalysis.push({
start: { x: point[0], y: point[1] },
end: { x: point[2], y: point[3] },
left: baseLines.findIndex((line) => line === prevLine),
right: baseLines.findIndex((line) => line === nextLine),
type: 'ridge',
degree: 0,
})
}
}
}
}
})
//5. 케라바 판단, 케라바는 양옆이 처마여야 한다.
gables.forEach((currentLine) => {})
//각 선분의 교차점을 찾아 선을 그린다.
const MAX_ITERATIONS = 1000 //무한루프 방지
@ -2878,17 +3051,19 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
if (count === 1) points.push(point)
})
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))
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)
}
proceedAnalysis.push(currentLine, partnerLine)
}
})
})
@ -2903,6 +3078,106 @@ export const drawRoofByAttribute = (roofId, canvas, textMode) => {
canvas.renderAll()
}
/**
*
* @param testPoint
* @param prevLine
* @param nextLine
* @param baseLines
* @param canvas
*/
const getRidgeDrivePoints = (testPoint = [], prevLine, nextLine, baseLines, canvas) => {
if (prevLine.attributes.type !== LINE_TYPE.WALLLINE.EAVES && nextLine.attributes.type !== LINE_TYPE.WALLLINE.EAVES) return null
let prevPoint = null,
nextPoint = null
const baseLinePoints = baseLines.map((line) => ({ x: line.x1, y: line.y1 }))
const checkWallPolygon = new QPolygon(baseLinePoints, {})
const checkEdge = { vertex1: { x: testPoint[0], y: testPoint[1] }, vertex2: { x: testPoint[2], y: testPoint[3] } }
if (prevLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) {
const index = baseLines.findIndex((line) => line === prevLine)
const beforePrevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length]
if (!beforePrevLine || beforePrevLine.attributes.type !== LINE_TYPE.WALLLINE.EAVES) {
prevPoint = null
} else {
let prevVector = getHalfAngleVector(beforePrevLine, prevLine)
const prevCheckPoint = {
x: prevLine.x1 + prevVector.x * 10,
y: prevLine.y1 + prevVector.y * 10,
}
let prevHipVector
if (checkWallPolygon.inPolygon(prevCheckPoint)) {
prevHipVector = { x: prevVector.x, y: prevVector.y }
} else {
prevHipVector = { x: -prevVector.x, y: -prevVector.y }
}
const prevHipEdge = {
vertex1: { x: prevLine.x1, y: prevLine.y1 },
vertex2: { x: prevLine.x1 + prevHipVector.x * 10, y: prevLine.y1 + prevHipVector.y * 10 },
}
const intersection = edgesIntersection(prevHipEdge, checkEdge)
if (intersection) {
const checkVector = { x: Math.sign(prevLine.x1 - testPoint[0]), y: Math.sign(prevLine.y1 - testPoint[1]) }
const intersectVector = { x: Math.sign(prevLine.x1 - intersection.x), y: Math.sign(prevLine.y1 - intersection.y) }
if (checkVector.x === intersectVector.x && checkVector.y === intersectVector.y) {
const distance = Math.sqrt((intersection.x - testPoint[0]) ** 2 + (intersection.y - testPoint[1]) ** 2)
prevPoint = { intersection, distance }
}
}
}
}
if (nextLine.attributes.type === LINE_TYPE.WALLLINE.EAVES) {
const index = baseLines.findIndex((line) => line === nextLine)
const afterNextLine = baseLines[(index + 1) % baseLines.length]
if (!afterNextLine || afterNextLine.attributes.type !== LINE_TYPE.WALLLINE.EAVES) {
nextPoint = null
} else {
let nextVector = getHalfAngleVector(nextLine, afterNextLine)
const nextCheckPoint = {
x: nextLine.x2 + nextVector.x * 10,
y: nextLine.y2 + nextVector.y * 10,
}
let nextHipVector
if (checkWallPolygon.inPolygon(nextCheckPoint)) {
nextHipVector = { x: nextVector.x, y: nextVector.y }
} else {
nextHipVector = { x: -nextVector.x, y: -nextVector.y }
}
const nextHipEdge = {
vertex1: { x: nextLine.x2, y: nextLine.y2 },
vertex2: { x: nextLine.x2 + nextHipVector.x * 10, y: nextLine.y2 + nextHipVector.y * 10 },
}
const intersection = edgesIntersection(nextHipEdge, checkEdge)
if (intersection) {
const checkVector = { x: Math.sign(nextLine.x2 - testPoint[0]), y: Math.sign(nextLine.y2 - testPoint[1]) }
const intersectVector = { x: Math.sign(nextLine.x2 - intersection.x), y: Math.sign(nextLine.y2 - intersection.y) }
if (checkVector.x === intersectVector.x && checkVector.y === intersectVector.y) {
const distance = Math.sqrt((intersection.x - testPoint[0]) ** 2 + (intersection.y - testPoint[1]) ** 2)
nextPoint = { intersection, distance }
}
}
}
}
if (prevPoint && nextPoint) {
return prevPoint.distance < nextPoint.distance ? prevPoint.intersection : nextPoint.intersection
} else if (prevPoint) {
return prevPoint.intersection
} else if (nextPoint) {
return nextPoint.intersection
} else {
return null
}
}
/**
* 선분과 선분의 교점을 구한다.
* @param line1Start