동이동, 형이동 기능 추가. 이에 따른 보조선 작성 수정 중

This commit is contained in:
Jaeyoung Lee 2025-03-24 13:38:46 +09:00
parent b6e70f6eb0
commit 25240bc3c2
8 changed files with 646 additions and 978 deletions

View File

@ -203,6 +203,8 @@ export const SAVE_KEY = [
'fontWeight', 'fontWeight',
'dormerAttributes', 'dormerAttributes',
'toFixed', 'toFixed',
'startPoint',
'endPoint',
] ]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]

View File

@ -29,12 +29,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.texts = [] this.texts = []
this.hips = [] this.hips = []
this.ridges = [] this.ridges = []
this.connectRidges = []
this.cells = [] this.cells = []
this.innerLines = [] this.innerLines = []
this.children = [] this.children = []
this.separatePolygon = [] this.separatePolygon = []
this.toFixed = options.toFixed ?? 1 this.toFixed = options.toFixed ?? 1
this.baseLines = []
// this.colorLines = []
// 소수점 전부 제거 // 소수점 전부 제거
points.forEach((point) => { points.forEach((point) => {
@ -211,6 +212,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
* @param settingModalFirstOptions * @param settingModalFirstOptions
*/ */
drawHelpLine(settingModalFirstOptions) { drawHelpLine(settingModalFirstOptions) {
/* innerLines 초기화 */
this.innerLines.forEach((line) => {
this.canvas.remove(line)
})
this.canvas.renderAll()
let textMode = 'plane' let textMode = 'plane'
const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id

View File

@ -15,13 +15,18 @@ export default function FlowLine({ FLOW_LINE_REF }) {
const currentObject = useRecoilValue(currentObjectState) const currentObject = useRecoilValue(currentObjectState)
const handleFocus = () => { const handleFocus = () => {
if (currentObject === null) { if (currentObject === null) {
FLOW_LINE_REF.POINTER_INPUT_REF.current.value = ''
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = '' FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
FLOW_LINE_REF.FILLED_INPUT_REF.current.blur() FLOW_LINE_REF.FILLED_INPUT_REF.current.blur()
} }
} }
const handleInput = (e) => { const handleInput = (e) => {
const value = e.target.value.replace(/^0+/, '') const regex = /^-?\d*$/
setFilledInput(value.replace(/[^0-9]/g, '')) let value = e.target.value
if (!regex.test(value) && value !== '') return
if (value.startsWith('0') || value === '-0') return
setFilledInput(value.replace(/[^0-9-]/g, ''))
} }
return ( return (
<> <>
@ -47,7 +52,7 @@ export default function FlowLine({ FLOW_LINE_REF }) {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}> <div className="input-grid mr5" style={{ width: '100px' }}>
{/*<input type="text" className="input-origin block" readOnly={true} ref={FLOW_LINE_REF.POINTER_INPUT_REF} />*/} {<input type="text" className="input-origin block" readOnly={true} ref={FLOW_LINE_REF.POINTER_INPUT_REF} />}
</div> </div>
</div> </div>
</div> </div>

View File

@ -15,6 +15,7 @@ export default function Updown({ UP_DOWN_REF }) {
const currentObject = useRecoilValue(currentObjectState) const currentObject = useRecoilValue(currentObjectState)
const handleFocus = () => { const handleFocus = () => {
if (currentObject === null) { if (currentObject === null) {
UP_DOWN_REF.POINTER_INPUT_REF.current.value = ''
UP_DOWN_REF.FILLED_INPUT_REF.current.value = '' UP_DOWN_REF.FILLED_INPUT_REF.current.value = ''
UP_DOWN_REF.FILLED_INPUT_REF.current.blur() UP_DOWN_REF.FILLED_INPUT_REF.current.blur()
} }
@ -48,7 +49,7 @@ export default function Updown({ UP_DOWN_REF }) {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}> <div className="input-grid mr5" style={{ width: '100px' }}>
{/*<input type="text" className="input-origin block" readOnly={true} ref={UP_DOWN_REF.UP_INPUT_REF} />*/} {<input type="text" className="input-origin block" readOnly={true} ref={UP_DOWN_REF.POINTER_INPUT_REF} />}
</div> </div>
</div> </div>
</div> </div>

File diff suppressed because it is too large Load Diff

View File

@ -108,6 +108,7 @@ export function useRoofShapeSetting(id) {
}) })
addPitchText(line) addPitchText(line)
line.bringToFront()
} }
}) })
canvas.renderAll() canvas.renderAll()

View File

@ -1770,10 +1770,7 @@ export function useMode() {
afterLine.push(line) afterLine.push(line)
} }
}) })
wall.lines = afterLine.concat(beforeLine) wall.lines = afterLine.concat(beforeLine)
wall.baseLines = wall.lines
wall.colorLines = []
//외벽선을 기준으로 polygon을 생성한다. 지붕선의 기준이 됨. //외벽선을 기준으로 polygon을 생성한다. 지붕선의 기준이 됨.
const divWallLines = [] const divWallLines = []
@ -1905,55 +1902,21 @@ export function useMode() {
const y2 = Big(line.y2) const y2 = Big(line.y2)
const lineLength = x1.minus(x2).abs().pow(2).plus(y1.minus(y2).abs().pow(2)).sqrt().times(10).round().toNumber() const lineLength = x1.minus(x2).abs().pow(2).plus(y1.minus(y2).abs().pow(2)).sqrt().times(10).round().toNumber()
line.attributes.roofId = roof.id line.attributes.roofId = roof.id
line.attributes.wallId = wall.id
// line.attributes.currentRoofId = roof.lines[index].id // line.attributes.currentRoofId = roof.lines[index].id
line.attributes.planeSize = lineLength line.attributes.planeSize = lineLength
line.attributes.actualSize = lineLength line.attributes.actualSize = lineLength
let wallStroke, wallStrokeWidth const baseLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
switch (line.attributes.type) { visible: false,
case LINE_TYPE.WALLLINE.EAVES: attributes: line.attributes,
wallStroke = '#45CD7D' startPoint: line.startPoint,
wallStrokeWidth = 4 endPoint: line.endPoint,
break parentId: roof.id,
case LINE_TYPE.WALLLINE.HIPANDGABLE: name: 'baseLine',
wallStroke = '#45CD7D'
wallStrokeWidth = 4
break
case LINE_TYPE.WALLLINE.GABLE:
wallStroke = '#3FBAE6'
wallStrokeWidth = 4
break
case LINE_TYPE.WALLLINE.JERKINHEAD:
wallStroke = '#3FBAE6'
wallStrokeWidth = 4
break
case LINE_TYPE.WALLLINE.SHED:
wallStroke = '#000000'
wallStrokeWidth = 4
break
case LINE_TYPE.WALLLINE.WALL:
wallStroke = '#000000'
wallStrokeWidth = 4
break
}
//외벽선의 색깔 표시를 위해 라인을 추가한다.
const wallLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
parentId: wall.id,
name: 'wallLine',
attributes: {
wallId: wall.id,
roofId: roof.id,
type: line.attributes.type,
currentRoofId: line.attributes.currentRoofId,
currentWall: line.id,
},
stroke: wallStroke,
strokeWidth: wallStrokeWidth,
selectable: false,
}) })
wall.colorLines.push(wallLine) roof.wall.baseLines.push(baseLine)
canvas.add(wallLine) canvas.add(baseLine)
}) })
setRoof(roof) setRoof(roof)

View File

@ -740,7 +740,9 @@ export const drawShedRoof = (roofId, canvas, textMode) => {
*/ */
export const drawRidgeRoof = (roofId, canvas, textMode) => { export const drawRidgeRoof = (roofId, canvas, textMode) => {
const roof = canvas?.getObjects().find((object) => object.id === roofId) const roof = canvas?.getObjects().find((object) => object.id === roofId)
const wall = canvas.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roofId)
console.log('wall :', wall)
//Math.abs(line.x1 - line.x2) > 1 && Math.abs(line.y1 - line.y2) > 1 //Math.abs(line.x1 - line.x2) > 1 && Math.abs(line.y1 - line.y2) > 1
const hasNonParallelLines = roof.lines.filter((line) => Big(line.x1).minus(Big(line.x2)).gt(1) && Big(line.y1).minus(Big(line.y2)).gt(1)) const hasNonParallelLines = roof.lines.filter((line) => Big(line.x1).minus(Big(line.x2)).gt(1) && Big(line.y1).minus(Big(line.y2)).gt(1))
if (hasNonParallelLines.length > 0) { if (hasNonParallelLines.length > 0) {
@ -757,10 +759,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
/** /**
* 외벽선 * 외벽선
*/ */
const baseLines = roof.wall.baseLines
const baseLines = wall.baseLines
const wallLines = wall.lines
console.log('wallLines :', wallLines)
const baseLinePoints = baseLines.map((line) => ({ x: line.x1, y: line.y1 })) const baseLinePoints = baseLines.map((line) => ({ x: line.x1, y: line.y1 }))
console.log('지붕 마루 갯수 확인 : ', getMaxRidge(baseLines.length)) console.log('지붕 마루 갯수 확인 : ', getMaxRidge(baseLines.length), baseLinePoints)
/** /**
* baseLine을 기준으로 확인용 polygon 작성 * baseLine을 기준으로 확인용 polygon 작성
@ -801,6 +806,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
if (eavesType.includes(nextLine.attributes?.type)) { if (eavesType.includes(nextLine.attributes?.type)) {
const prevAngle = calculateAngle(prevLine.startPoint, prevLine.endPoint) const prevAngle = calculateAngle(prevLine.startPoint, prevLine.endPoint)
const nextAngle = calculateAngle(nextLine.startPoint, nextLine.endPoint) const nextAngle = calculateAngle(nextLine.startPoint, nextLine.endPoint)
console.log('prevAngle :', prevAngle, 'nextAngle :', nextAngle)
/** /**
* 이전, 다음 라인이 처마일때 라인의 방향이 반대면 모양으로 판단한다. * 이전, 다음 라인이 처마일때 라인의 방향이 반대면 모양으로 판단한다.
*/ */
@ -1579,6 +1586,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
}) })
}) })
console.log('drawEavesSecondLines : ', drawEavesSecondLines)
/** ㄴ 모양 처마에 추녀마루를 그린다. */ /** ㄴ 모양 처마에 추녀마루를 그린다. */
drawEavesSecondLines.forEach((current) => { drawEavesSecondLines.forEach((current) => {
const { currentLine, prevLine, nextLine } = current const { currentLine, prevLine, nextLine } = current
@ -1715,25 +1723,27 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
{ vertex1: { x: x1, y: y1 }, vertex2: prevEndPoint }, { vertex1: { x: x1, y: y1 }, vertex2: prevEndPoint },
{ vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } }, { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
) )
/*const checkLine = new fabric.Line([x1, y1, prevEndPoint.x, prevEndPoint.y], { const checkLine = new fabric.Line([x1, y1, prevEndPoint.x, prevEndPoint.y], {
stroke: 'red', stroke: 'red',
strokeWidth: 2, strokeWidth: 2,
parentId: roof.id, parentId: roof.id,
name: 'checkLine',
}) })
canvas.add(checkLine) canvas.add(checkLine)
canvas.renderAll()*/ canvas.renderAll()
/* if (intersection) { if (intersection) {
const intersectCircle = new fabric.Circle({ const intersectCircle = new fabric.Circle({
left: intersection.x - 2, left: intersection.x - 2,
top: intersection.y - 2, top: intersection.y - 2,
radius: 4, radius: 4,
fill: 'red', fill: 'red',
parentId: roof.id, parentId: roof.id,
name: 'checkPoint',
}) })
canvas.add(intersectCircle) canvas.add(intersectCircle)
canvas.renderAll() canvas.renderAll()
}*/ }
if (intersection && !intersection.isIntersectionOutside) { if (intersection && !intersection.isIntersectionOutside) {
intersectRidgeLine.push({ intersectRidgeLine.push({
intersection, intersection,
@ -1766,13 +1776,14 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
vertex2: prevEndPoint, vertex2: prevEndPoint,
} }
/*const checkLine = new fabric.Line([hipEdge.vertex1.x, hipEdge.vertex1.y, hipEdge.vertex2.x, hipEdge.vertex2.y], { const checkLine = new fabric.Line([hipEdge.vertex1.x, hipEdge.vertex1.y, hipEdge.vertex2.x, hipEdge.vertex2.y], {
stroke: 'yellow', stroke: 'yellow',
strokeWidth: 2, strokeWidth: 2,
parentId: roof.id, parentId: roof.id,
name: 'checkLine',
}) })
canvas.add(checkLine) canvas.add(checkLine)
canvas.renderAll()*/ canvas.renderAll()
let intersectPoints = [] let intersectPoints = []
/** 외벽선에서 추녀 마루가 겹치는 경우에 대한 확인*/ /** 외벽선에서 추녀 마루가 겹치는 경우에 대한 확인*/
@ -2279,7 +2290,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
}) })
/** hip을 그리기 위한 기본 길이*/ /** hip을 그리기 위한 기본 길이*/
let hipSize = 0 let hipSize = Big(0)
if (basePoints.length > 0) { if (basePoints.length > 0) {
basePoints.sort((a, b) => { basePoints.sort((a, b) => {
const aSize = Big(a.x) const aSize = Big(a.x)
@ -2298,18 +2309,21 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
}) })
const baseHips = baseHipLines.filter((line) => line.x1 === basePoints[0].x && line.y1 === basePoints[0].y) const baseHips = baseHipLines.filter((line) => line.x1 === basePoints[0].x && line.y1 === basePoints[0].y)
if (baseHips.length > 0) { if (baseHips.length > 0) {
hipSize = Big(baseHips[0].line.attributes.planeSize).div(10) hipSize = Big(baseHips[0].line.attributes.planeSize)
} }
} }
console.log('hipSize : ', hipSize.toNumber())
if (hipSize.eq(0)) { if (hipSize.eq(0)) {
const ridge = current.line const ridge = current.line
basePoints = baseHipLines.filter((line) => (line.x2 === ridge.x1 && line.y2 === ridge.y1) || (line.x2 === ridge.x2 && line.y2 === ridge.y2)) basePoints = baseHipLines
.filter((line) => (line.x2 === ridge.x1 && line.y2 === ridge.y1) || (line.x2 === ridge.x2 && line.y2 === ridge.y2))
.filter((line) => baseLines.filter((baseLine) => baseLine.x1 === line.x1 && baseLine.y1 === line.y1).length > 0)
basePoints.sort((a, b) => a.line.attributes.planeSize - b.line.attributes.planeSize) basePoints.sort((a, b) => a.line.attributes.planeSize - b.line.attributes.planeSize)
hipSize = Big(basePoints[0].line.attributes.planeSize).div(10) hipSize = Big(basePoints[0].line.attributes.planeSize)
} }
hipSize = hipSize.times(hipSize).div(2).sqrt().round().toNumber() hipSize = hipSize.pow(2).div(2).sqrt().round().div(10).toNumber()
/** 현재 라인을 기준으로 45, 135, 225, 315 방향을 확인하기 위한 좌표, hip은 45도 방향으로만 그린다. */ /** 현재 라인을 기준으로 45, 135, 225, 315 방향을 확인하기 위한 좌표, hip은 45도 방향으로만 그린다. */
const checkEdge45 = { vertex1: { x: current.x, y: current.y }, vertex2: { x: current.x + hipSize, y: current.y - hipSize } } const checkEdge45 = { vertex1: { x: current.x, y: current.y }, vertex2: { x: current.x + hipSize, y: current.y - hipSize } }
@ -2346,10 +2360,6 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
notIntersect315 = false notIntersect315 = false
} }
}) })
/** baseLine의 각 좌표와 교차하는 경우로 한정*/
intersectPoints = intersectPoints.filter((is) => baseLinePoints.filter((point) => point.x === is.x && point.y === is.y).length > 0)
/** baseLine과 교차하는 좌표의 경우 이미 그려진 추녀마루가 존재한다면 제외한다. */
intersectPoints = intersectPoints.filter((point) => baseHipLines.filter((hip) => hip.x1 === point.x && hip.y1 === point.y).length === 0)
/** baseLine과 교차하지 않는 포인트를 추가한다.*/ /** baseLine과 교차하지 않는 포인트를 추가한다.*/
if (notIntersect45) { if (notIntersect45) {
intersectPoints.push(checkEdge45.vertex2) intersectPoints.push(checkEdge45.vertex2)
@ -2363,6 +2373,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
if (notIntersect315) { if (notIntersect315) {
intersectPoints.push(checkEdge315.vertex2) intersectPoints.push(checkEdge315.vertex2)
} }
/** baseLine의 각 좌표와 교차하는 경우로 한정*/
intersectPoints = intersectPoints.filter((is) => baseLinePoints.filter((point) => point.x === is.x && point.y === is.y).length > 0)
/** baseLine과 교차하는 좌표의 경우 이미 그려진 추녀마루가 존재한다면 제외한다. */
intersectPoints = intersectPoints.filter((point) => baseHipLines.filter((hip) => hip.x1 === point.x && hip.y1 === point.y).length === 0)
/** 중복제거 */
intersectPoints = intersectPoints.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
intersectPoints.forEach((is) => { intersectPoints.forEach((is) => {
const points = [current.x, current.y, is.x, is.y] const points = [current.x, current.y, is.x, is.y]
const hipLine = drawHipLine(points, canvas, roof, textMode, null, prevDegree, currentDegree) const hipLine = drawHipLine(points, canvas, roof, textMode, null, prevDegree, currentDegree)
@ -2388,9 +2405,46 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
) )
noRidgeHipPoints.forEach((current) => { noRidgeHipPoints.forEach((current) => {
const orthogonalPoints = noRidgeHipPoints.filter( const checkPoint = new fabric.Circle({
(point) => point !== current && ((current.x2 === point.x2 && current.y2 !== point.y2) || (current.x2 !== point.x2 && current.y2 === point.y2)), left: current.x2,
top: current.y2,
radius: 4,
fill: 'green',
parentId: roofId,
name: 'checkPoint',
})
canvas.add(checkPoint)
canvas.renderAll()
console.log('noRidgeHipPoints current : ', current.x1, current.y1, current.x2, current.y2)
const orthogonalPoints = noRidgeHipPoints.filter((point) => {
const checkPoint1 = new fabric.Circle({
left: point.x2,
top: point.y2,
radius: 4,
fill: 'blue',
parentId: roofId,
name: 'checkPoint',
})
canvas.add(checkPoint1)
canvas.renderAll()
console.log(' orthogonalPoints : ', point.x1, point.y1, point.x2, point.y2)
console.log(
'same point :',
point !== current,
'y point 다름',
current.x2 === point.x2 && current.y2 !== point.y2,
'x point 다름',
current.x2 !== point.x2 && current.y2 === point.y2,
) )
canvas.remove(checkPoint1)
canvas.renderAll()
if (point !== current && ((current.x2 === point.x2 && current.y2 !== point.y2) || (current.x2 !== point.x2 && current.y2 === point.y2))) {
return true
}
})
canvas.remove(checkPoint)
canvas.renderAll()
/** 직교 하는 포인트가 존재 할때 마루를 그린다. */ /** 직교 하는 포인트가 존재 할때 마루를 그린다. */
if (orthogonalPoints.length > 0) { if (orthogonalPoints.length > 0) {
@ -2458,6 +2512,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
.filter((line) => (line.x1 === point.x && line.y1 === point.y) || (line.x2 === point.x && line.y2 === point.y)) .filter((line) => (line.x1 === point.x && line.y1 === point.y) || (line.x2 === point.x && line.y2 === point.y))
.forEach((line) => unFinishedLines.push(line)) .forEach((line) => unFinishedLines.push(line))
}) })
unFinishedLines.forEach((line) => { unFinishedLines.forEach((line) => {
const xVector = Math.sign(Big(line.x2).minus(Big(line.x1))) const xVector = Math.sign(Big(line.x2).minus(Big(line.x1)))
const yVector = Math.sign(Big(line.y2).minus(Big(line.y1))) const yVector = Math.sign(Big(line.y2).minus(Big(line.y1)))
@ -2492,27 +2547,49 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
} }
}) })
intersectPoints.forEach((intersection) => { /** 마루를 그릴수 있는지 찾는다. */
const intersectPoint = intersection.intersection
noRidgeHipPoints.forEach((hipPoint) => { noRidgeHipPoints.forEach((hipPoint) => {
const angle = calculateAngle({ x: intersectPoint.x, y: intersectPoint.y }, { x: hipPoint.x2, y: hipPoint.y2 }) const ridgePoints = []
if (angle === 0 || angle === 180 || angle === 90 || angle === -90) { intersectPoints
.filter(
(intersectPoint) =>
(intersectPoint.intersection.x !== hipPoint.x2 && intersectPoint.intersection.y === hipPoint.y2) ||
(intersectPoint.intersection.x === hipPoint.x2 && intersectPoint.intersection.y !== hipPoint.y2),
)
.forEach((intersectPoint) => {
ridgePoints.push({
intersection: intersectPoint,
distance: Big(intersectPoint.intersection.x)
.minus(Big(hipPoint.x2))
.abs()
.pow(2)
.plus(Big(intersectPoint.intersection.y).minus(Big(hipPoint.y2)).abs().pow(2))
.sqrt()
.round(1)
.toNumber(),
})
})
ridgePoints.sort((a, b) => a.distance - b.distance)
if (ridgePoints.length > 0) {
const intersection = ridgePoints[0].intersection
const isPoint = intersection.intersection
const points = [hipPoint.x2, hipPoint.y2, isPoint.x, isPoint.y]
const ridgeLine = drawRidgeLine(points, canvas, roof, textMode)
baseRidgeCount = baseRidgeCount + 1 baseRidgeCount = baseRidgeCount + 1
const ridgeLine = drawRidgeLine([intersectPoint.x, intersectPoint.y, hipPoint.x2, hipPoint.y2], canvas, roof, textMode)
baseRidgeLines.push(ridgeLine) baseRidgeLines.push(ridgeLine)
let baseHipLine = baseHipLines.filter((line) => line === intersection.line)[0] let baseHipLine = baseHipLines.filter((line) => line === intersection.line)[0]
baseHipLine.x2 = intersectPoint.x baseHipLine.x2 = isPoint.x
baseHipLines.y2 = intersectPoint.y baseHipLines.y2 = isPoint.y
intersection.line.x2 = intersectPoint.x
intersection.line.y2 = intersectPoint.y
/** 보조선 라인 조정*/ /** 보조선 라인 조정*/
const hipLine = intersection.line.line const hipLine = intersection.line.line
/** 평면길이 */ /** 평면길이 */
const planeSize = calcLinePlaneSize({ const planeSize = calcLinePlaneSize({
x1: hipLine.x1, x1: hipLine.x1,
y1: hipLine.y1, y1: hipLine.y1,
x2: intersectPoint.x, x2: isPoint.x,
y2: intersectPoint.y, y2: isPoint.y,
}) })
/** 실제길이 */ /** 실제길이 */
const actualSize = const actualSize =
@ -2521,23 +2598,172 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
{ {
x1: hipLine.x1, x1: hipLine.x1,
y1: hipLine.y1, y1: hipLine.y1,
x2: intersectPoint.x, x2: isPoint.x,
y2: intersectPoint.y, y2: isPoint.y,
}, },
currentDegree, currentDegree,
) )
: 0 : 0
hipLine.set({ x2: intersectPoint.x, y2: intersectPoint.y, attributes: { roofId: roof.id, planeSize, actualSize } }) hipLine.set({
x2: isPoint.x,
y2: isPoint.y,
attributes: { roofId: roof.id, planeSize, actualSize },
})
hipLine.fire('modified') hipLine.fire('modified')
intersectPoints = intersectPoints.filter((isp) => isp !== intersection) intersectPoints = intersectPoints.filter((isp) => isp !== intersection)
noRidgeHipPoints = noRidgeHipPoints.filter((hip) => hip !== hipPoint) noRidgeHipPoints = noRidgeHipPoints.filter((hip) => hip !== hipPoint)
} else {
const linePoints = []
intersectPoints.forEach((intersectPoint) => {
const intersection = intersectPoint.intersection
const xVector = Math.sign(Big(intersection.x).minus(Big(hipPoint.x2)))
const yVector = Math.sign(Big(intersection.y).minus(Big(hipPoint.y2)))
const checkEdge = {
vertex1: { x: intersection.x, y: intersection.y },
vertex2: { x: Big(intersection.x).plus(Big(xVector).times(10)).toNumber(), y: Big(intersection.y).plus(Big(yVector).times(10)).toNumber() },
}
const intersectX = edgesIntersection(
{
vertex1: { x: hipPoint.x2, y: hipPoint.y2 },
vertex2: { x: Big(hipPoint.x2).plus(Big(xVector).neg().times(10)).toNumber(), y: hipPoint.y2 },
},
checkEdge,
)
const intersectY = edgesIntersection(
{
vertex1: { x: hipPoint.x2, y: hipPoint.y2 },
vertex2: { x: hipPoint.x2, y: Big(hipPoint.y2).plus(Big(yVector).neg().times(10)).toNumber() },
},
checkEdge,
)
let distanceX = Infinity,
distanceY = Infinity
if (intersectX) {
distanceX = Big(intersectX.x)
.minus(Big(intersection.x))
.abs()
.pow(2)
.plus(Big(intersectX.y).minus(Big(intersection.y)).abs().pow(2))
.sqrt()
.round(1)
.toNumber()
}
if (intersectY) {
distanceY = Big(intersectY.x)
.minus(Big(intersection.x))
.abs()
.pow(2)
.plus(Big(intersectY.y).minus(Big(intersection.y)).abs().pow(2))
.sqrt()
.round(1)
.toNumber()
}
if (distanceX < distanceY) {
linePoints.push({ intersection: intersectX, intersectPoint })
} else {
linePoints.push({ intersection: intersectY, intersectPoint })
} }
}) })
const linePoint = linePoints.reduce((prev, current) => {
const prevDistance = Big(prev.intersection.x)
.minus(Big(hipPoint.x2))
.abs()
.pow(2)
.plus(Big(prev.intersection.y).minus(Big(hipPoint.y2)).abs().pow(2))
.sqrt()
const currentDistance = Big(current.intersection.x)
.minus(Big(hipPoint.x2))
.abs()
.pow(2)
.plus(Big(current.intersection.y).minus(Big(hipPoint.y2)).abs().pow(2))
.sqrt()
if (prevDistance < currentDistance) {
return prev
} else {
return current
}
}, linePoints[0])
if (!linePoint) return
const hipStartPoint = [hipPoint.x2, hipPoint.y2, linePoint.intersection.x, linePoint.intersection.y]
console.log('hipStartPoint : ', hipStartPoint)
/** 직선인 경우 마루를 그린다.*/
if (
(hipStartPoint[0] === hipStartPoint[2] && hipStartPoint[1] !== hipStartPoint[3]) ||
(hipStartPoint[0] !== hipStartPoint[2] && hipStartPoint[1] === hipStartPoint[3])
) {
console.log('릿지1')
const ridgeLine = drawRidgeLine(hipStartPoint, canvas, roof, textMode)
baseRidgeCount = baseRidgeCount + 1
baseRidgeLines.push(ridgeLine)
noRidgeHipPoints = noRidgeHipPoints.filter((hip) => hip !== hipPoint)
}
console.log(
Big(hipStartPoint[0]).minus(Big(hipStartPoint[2])).abs().toNumber(),
Big(hipStartPoint[1]).minus(Big(hipStartPoint[3])).abs().toNumber(),
Big(hipStartPoint[0])
.minus(Big(hipStartPoint[2]))
.abs()
.minus(Big(hipStartPoint[1]).minus(Big(hipStartPoint[3])).abs())
.abs()
.lt(1),
)
/** 대각선인경우 hip을 그린다. */
if (
Big(hipStartPoint[0])
.minus(Big(hipStartPoint[2]))
.abs()
.minus(Big(hipStartPoint[1]).minus(Big(hipStartPoint[3])).abs())
.abs()
.lt(1)
) {
console.log('힙1')
const hipLine = drawHipLine(hipStartPoint, canvas, roof, textMode, null, prevDegree, currentDegree)
baseHipLines.push({ x1: hipStartPoint[0], y1: hipStartPoint[1], x2: hipStartPoint[2], y2: hipStartPoint[3], line: hipLine })
noRidgeHipPoints = noRidgeHipPoints.filter((hip) => hip !== hipPoint)
}
const isStartPoint = [
linePoint.intersection.x,
linePoint.intersection.y,
linePoint.intersectPoint.intersection.x,
linePoint.intersectPoint.intersection.y,
]
if (
(isStartPoint[0] === isStartPoint[2] && isStartPoint[1] !== isStartPoint[3]) ||
(isStartPoint[0] !== isStartPoint[2] && isStartPoint[1] === isStartPoint[3])
) {
const ridgeLine = drawRidgeLine(isStartPoint, canvas, roof, textMode)
baseRidgeCount = baseRidgeCount + 1
baseRidgeLines.push(ridgeLine)
}
console.log('isStartPoint : ', isStartPoint)
console.log(Big(isStartPoint[0]).minus(Big(isStartPoint[2])).toNumber())
if (
Big(isStartPoint[0])
.minus(Big(isStartPoint[2]))
.abs()
.minus(Big(isStartPoint[1]).minus(Big(isStartPoint[3])).abs())
.abs()
.lt(1)
) {
const hipLine = drawHipLine(isStartPoint, canvas, roof, textMode, null, prevDegree, currentDegree)
baseHipLines.push({ x1: isStartPoint[0], y1: isStartPoint[1], x2: isStartPoint[2], y2: isStartPoint[3], line: hipLine })
}
}
}) })
const ridgeAllPoints = [] const ridgeAllPoints = []
baseRidgeLines.forEach((line) => ridgeAllPoints.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 })) baseRidgeLines.forEach((line) => ridgeAllPoints.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 }))
console.log('ridge count', baseRidgeCount, getMaxRidge(baseLines.length))
ridgeAllPoints.forEach((current) => { ridgeAllPoints.forEach((current) => {
ridgeAllPoints ridgeAllPoints
.filter((point) => point !== current) .filter((point) => point !== current)
@ -2551,12 +2777,9 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
checkRidgeLine = { x1: current.x, y1: current.y, x2: point.x, y2: point.y } checkRidgeLine = { x1: current.x, y1: current.y, x2: point.x, y2: point.y }
} }
/** 대각선인 경우 hip확인*/ /** 대각선인 경우 hip확인*/
if ( const hipX = Big(current.x).minus(Big(point.x)).abs()
Big(point.x) const hipY = Big(current.y).minus(Big(point.y)).abs()
.minus(Big(current.x)) if (hipX.eq(hipY) && hipX.gt(0) && hipY.gt(0)) {
.abs()
.eq(Big(point.y).minus(Big(current.y)).abs())
) {
checkHipLine = { x1: current.x, y1: current.y, x2: point.x, y2: point.y } checkHipLine = { x1: current.x, y1: current.y, x2: point.x, y2: point.y }
} }