diff --git a/src/common/common.js b/src/common/common.js
index d82d43f0..d336244f 100644
--- a/src/common/common.js
+++ b/src/common/common.js
@@ -203,6 +203,8 @@ export const SAVE_KEY = [
'fontWeight',
'dormerAttributes',
'toFixed',
+ 'startPoint',
+ 'endPoint',
]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]
diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js
index f19687aa..65fe9d11 100644
--- a/src/components/fabric/QPolygon.js
+++ b/src/components/fabric/QPolygon.js
@@ -29,12 +29,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.texts = []
this.hips = []
this.ridges = []
- this.connectRidges = []
this.cells = []
this.innerLines = []
this.children = []
this.separatePolygon = []
this.toFixed = options.toFixed ?? 1
+ this.baseLines = []
+ // this.colorLines = []
// 소수점 전부 제거
points.forEach((point) => {
@@ -211,6 +212,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
* @param settingModalFirstOptions
*/
drawHelpLine(settingModalFirstOptions) {
+ /* innerLines 초기화 */
+ this.innerLines.forEach((line) => {
+ this.canvas.remove(line)
+ })
+ this.canvas.renderAll()
+
let textMode = 'plane'
const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id
diff --git a/src/components/floor-plan/modal/movement/type/FlowLine.jsx b/src/components/floor-plan/modal/movement/type/FlowLine.jsx
index 565a9ff8..3c23a30a 100644
--- a/src/components/floor-plan/modal/movement/type/FlowLine.jsx
+++ b/src/components/floor-plan/modal/movement/type/FlowLine.jsx
@@ -15,13 +15,18 @@ export default function FlowLine({ FLOW_LINE_REF }) {
const currentObject = useRecoilValue(currentObjectState)
const handleFocus = () => {
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.blur()
}
}
const handleInput = (e) => {
- const value = e.target.value.replace(/^0+/, '')
- setFilledInput(value.replace(/[^0-9]/g, ''))
+ const regex = /^-?\d*$/
+ 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 (
<>
@@ -47,7 +52,7 @@ export default function FlowLine({ FLOW_LINE_REF }) {
diff --git a/src/components/floor-plan/modal/movement/type/Updown.jsx b/src/components/floor-plan/modal/movement/type/Updown.jsx
index bcc45590..786c7017 100644
--- a/src/components/floor-plan/modal/movement/type/Updown.jsx
+++ b/src/components/floor-plan/modal/movement/type/Updown.jsx
@@ -15,6 +15,7 @@ export default function Updown({ UP_DOWN_REF }) {
const currentObject = useRecoilValue(currentObjectState)
const handleFocus = () => {
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.blur()
}
@@ -48,7 +49,7 @@ export default function Updown({ UP_DOWN_REF }) {
diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js
index 1da5dcc8..558113ff 100644
--- a/src/hooks/roofcover/useMovementSetting.js
+++ b/src/hooks/roofcover/useMovementSetting.js
@@ -4,10 +4,9 @@ import { usePopup } from '@/hooks/usePopup'
import { useMessage } from '@/hooks/useMessage'
import { useEffect, useRef, useState } from 'react'
import { useEvent } from '@/hooks/useEvent'
-import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { useSwal } from '@/hooks/useSwal'
-import { QPolygon } from '@/components/fabric/QPolygon'
-import { getDegreeByChon } from '@/util/canvas-util'
+import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
+import Big from 'big.js'
//동선이동 형 올림 내림
export function useMovementSetting(id) {
@@ -17,7 +16,6 @@ export function useMovementSetting(id) {
}
const canvas = useRecoilValue(canvasState)
const { initEvent, addCanvasMouseEventListener } = useEvent()
- // const { initEvent, addCanvasMouseEventListener } = useContext(EventContext)
const { closePopup } = usePopup()
const { getMessage } = useMessage()
const currentObject = useRecoilValue(currentObjectState)
@@ -31,939 +29,407 @@ export function useMovementSetting(id) {
const { swalFire } = useSwal()
const FLOW_LINE_REF = {
+ POINTER_INPUT_REF: useRef(null),
FILLED_INPUT_REF: useRef(null),
DOWN_LEFT_RADIO_REF: useRef(null),
UP_RIGHT_RADIO_REF: useRef(null),
}
const UP_DOWN_REF = {
+ POINTER_INPUT_REF: useRef(null),
FILLED_INPUT_REF: useRef(null),
UP_RADIO_REF: useRef(null),
DOWN_RADIO_REF: useRef(null),
}
+ const CONFIRM_LINE_REF = useRef(null)
+ const FOLLOW_LINE_REF = useRef(null)
+
+ /** 동선이동, 형이동 선택시 속성 처리*/
useEffect(() => {
typeRef.current = type
+ selectedObject.current = null
+ if (FOLLOW_LINE_REF.current != null) {
+ canvas.remove(FOLLOW_LINE_REF.current)
+ canvas.renderAll()
+ FOLLOW_LINE_REF.current = null
+ }
+ if (CONFIRM_LINE_REF.current != null) {
+ canvas.remove(CONFIRM_LINE_REF.current)
+ canvas.renderAll()
+ CONFIRM_LINE_REF.current = null
+ }
+ clearRef()
+
+ canvas.discardActiveObject()
+ /** 전체 object 선택 불가 */
canvas.getObjects().forEach((obj) => {
obj.set({ selectable: false })
})
- const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // 기존 wallLine의 visible false
+
+ /** 지붕선 관련 속성 처리*/
+ const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => {
- roof.set({ selectable: false })
- roof.set({ strokeWidth: 1 })
roof.set({ stroke: '#000000' })
roof.innerLines.forEach((line) => {
- line.bringToFront()
- line.set({ selectable: false })
- line.set({ strokeWidth: 1 })
- line.set({ stroke: '#000000' })
- })
- roof.separatePolygon?.forEach((polygon) => {
- polygon.bringToFront()
- polygon.set({ selectable: false })
- polygon.set({ strokeWidth: 1 })
- polygon.set({ stroke: '#000000' })
+ if (type === TYPE.FLOW_LINE && line.name === LINE_TYPE.SUBLINE.RIDGE) {
+ line.set({ selectable: true, strokeWidth: 5, stroke: '#1083E3' })
+ line.bringToFront()
+ } else {
+ line.set({ selectable: false, strokeWidth: 2, stroke: '#000000' })
+ }
})
})
- if (type === TYPE.FLOW_LINE) {
- roofs.forEach((roof) => {
- roof.innerLines.forEach((line) => {
- if (line.name === LINE_TYPE.SUBLINE.RIDGE) {
- line.bringToFront()
- line.set({ visible: true })
- line.set({ selectable: true })
- line.set({ strokeWidth: 4 })
- line.set({ stroke: '#1083E3' })
- }
- })
+ /** 외벽선 관련 속성 처리*/
+ const walls = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
+ walls.forEach((wall) => {
+ if (wall.baseLines.length === 0) {
+ wall.baseLines = canvas.getObjects().filter((obj) => obj.name === 'baseLine' && obj.attributes.wallId === wall.id)
+ }
+ wall.baseLines.forEach((line) => {
+ if (type === TYPE.UP_DOWN) {
+ line.set({ selectable: true, visible: true, stroke: '#1083E3', strokeWidth: 5 })
+ line.bringToFront()
+ } else {
+ line.set({ selectable: false, visible: false })
+ }
})
- } else if (type === TYPE.UP_DOWN) {
- const wallLine = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 outerLine의 selectable true
- wallLine.forEach((line) => {
- line.bringToFront()
- line.set({ selectable: true })
- })
- }
+ })
+
+ /** outerLines 속성처리*/
+ const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
+ outerLines.forEach((line) => line.set({ visible: false }))
canvas.renderAll()
}, [type])
+ /** 팝업창이 열릴때,닫힐때 속성들을 처리*/
useEffect(() => {
- canvas.renderAll()
addCanvasMouseEventListener('mouse:move', mouseMoveEvent)
addCanvasMouseEventListener('mouse:down', mouseDownEvent)
return () => {
- initEvent()
-
- const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
- wallLines.forEach((line) => {
- line.set({ visible: true })
+ if (FOLLOW_LINE_REF.current != null) {
+ canvas.remove(FOLLOW_LINE_REF.current)
+ FOLLOW_LINE_REF.current = null
+ }
+ if (CONFIRM_LINE_REF.current != null) {
+ canvas.remove(CONFIRM_LINE_REF.current)
+ CONFIRM_LINE_REF.current = null
+ }
+ const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
+ roofs.forEach((roof) => {
+ roof.set({ stroke: '#1083E3' })
+ roof.innerLines.forEach((line) => line.set({ selectable: true, strokeWidth: 2, stroke: '#1083E3' }))
})
-
- const wallLine = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 outerLine의 selectable true
- wallLine.forEach((line) => {
- let wallStroke, wallStrokeWidth
- switch (line.attributes.type) {
- case LINE_TYPE.WALLLINE.EAVES:
- wallStroke = '#45CD7D'
- wallStrokeWidth = 4
- break
- case LINE_TYPE.WALLLINE.HIPANDGABLE:
- 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 walls = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
+ walls.forEach((wall) => {
+ if (wall.baseLines.length === 0) {
+ wall.baseLines = canvas.getObjects().filter((obj) => obj.name === 'baseLine' && obj.attributes.wallId === wall.id)
}
- line.set({ selectable: false, stroke: wallStroke, strokeWidth: wallStrokeWidth })
+ wall.baseLines.forEach((baseLine) => {
+ baseLine.set({ selectable: false, visible: false })
+ })
})
-
+ const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
+ outerLines.forEach((line) => line.set({ visible: true }))
canvas.renderAll()
}
}, [])
+ /** object 선택이 변경될 때 처리*/
useEffect(() => {
- console.log('selectedObject.current : ', selectedObject.current)
- if (selectedObject.current != null) {
- let wallStroke
- switch (selectedObject.current.attributes.type) {
- case LINE_TYPE.WALLLINE.EAVES:
- wallStroke = '#45CD7D'
- break
- case LINE_TYPE.WALLLINE.HIPANDGABLE:
- wallStroke = '#45CD7D'
- break
- case LINE_TYPE.WALLLINE.GABLE:
- wallStroke = '#3FBAE6'
- break
- case LINE_TYPE.WALLLINE.JERKINHEAD:
- wallStroke = '#3FBAE6'
- break
- case LINE_TYPE.WALLLINE.SHED:
- wallStroke = '#000000'
- break
- case LINE_TYPE.WALLLINE.WALL:
- wallStroke = '#000000'
- break
- }
- selectedObject.current.set({ stroke: wallStroke })
- selectedObject.current.bringToFront()
- }
- selectedObject.current = null
- if (!currentObject) {
- return
+ if (FOLLOW_LINE_REF.current != null) {
+ canvas.remove(FOLLOW_LINE_REF.current)
+ canvas.renderAll()
+ FOLLOW_LINE_REF.current = null
}
- clearRef()
- selectedObject.current = currentObject
- if (currentObject.name === 'wallLine') {
- currentObject.set({ stroke: '#EA10AC' })
- currentObject.bringToFront()
+ if (selectedObject.current != null) {
+ selectedObject.current.set({ stroke: '#1083E3' })
+ selectedObject.current = null
}
+ if (!currentObject) return
+
+ clearRef()
+
+ canvas
+ .getObjects()
+ .filter((obj) => obj.name === 'checkPoint' || obj.name === 'checkLine')
+ .forEach((obj) => canvas.remove(obj))
+ canvas.renderAll()
+
+ if (CONFIRM_LINE_REF.current != null) {
+ canvas.remove(CONFIRM_LINE_REF.current)
+ canvas.renderAll()
+ CONFIRM_LINE_REF.current = null
+ }
+
+ currentObject.set({ stroke: '#EA10AC' })
+ selectedObject.current = currentObject
+
+ const followLine = new fabric.Line([currentObject.x1, currentObject.y1, currentObject.x2, currentObject.y2], {
+ stroke: '#000000',
+ strokeWidth: 4,
+ selectable: false,
+ name: 'followLine',
+ })
+ canvas.add(followLine)
+ FOLLOW_LINE_REF.current = followLine
+
+ canvas.on('mouse:move', (event) => {
+ const mousePos = canvas.getPointer(event.e)
+ if (followLine.x1 === followLine.x2) {
+ followLine.left = mousePos.x - 2
+ } else {
+ followLine.top = mousePos.y - 2
+ }
+ canvas.renderAll()
+ })
+
canvas.renderAll()
}, [currentObject])
const clearRef = () => {
if (type === TYPE.FLOW_LINE) {
+ FLOW_LINE_REF.POINTER_INPUT_REF.current.value = ''
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true
FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = false
}
if (type === TYPE.UP_DOWN) {
+ UP_DOWN_REF.POINTER_INPUT_REF.current.value = ''
UP_DOWN_REF.FILLED_INPUT_REF.current.value = ''
UP_DOWN_REF.UP_RADIO_REF.current.checked = true
UP_DOWN_REF.DOWN_RADIO_REF.current.checked = false
}
}
- const mouseDownEvent = (e) => {
- if (typeRef.current === TYPE.FLOW_LINE) {
- saveFlowLine(e)
- } else {
- saveUpDownLine(e)
- }
- }
-
const mouseMoveEvent = (e) => {
+ const target = canvas.getActiveObject()
+ if (!target) return
+
+ const { top: targetTop, left: targetLeft } = target
+ const currentX = Big(canvas.getPointer(e.e).x).round(0, Big.roundUp)
+ const currentY = Big(canvas.getPointer(e.e).y).round(0, Big.roundUp)
+ let value = ''
+ if (target.y1 === target.y2) {
+ value = Big(targetTop).minus(currentY).times(10)
+ } else {
+ value = Big(targetLeft).minus(currentX).times(10).neg()
+ }
if (typeRef.current === TYPE.FLOW_LINE) {
- flowLineMoveEvent(e)
+ FLOW_LINE_REF.POINTER_INPUT_REF.current.value = value.toNumber()
} else {
- updownMoveEvent(e)
+ UP_DOWN_REF.POINTER_INPUT_REF.current.value = value.abs().toNumber()
+ const midX = Big(target.x1).plus(target.x2).div(2)
+ const midY = Big(target.y1).plus(target.y2).div(2)
+ const wall = canvas.getObjects().find((obj) => obj.id === target.attributes.wallId)
+ let checkPoint
+ if (target.y1 === target.y2) {
+ checkPoint = { x: midX.toNumber(), y: midY.plus(10).toNumber() }
+ if (wall.inPolygon(checkPoint)) {
+ if (value.s === -1) {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = false
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
+ } else {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = true
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = false
+ }
+ } else {
+ if (value.s === 1) {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = false
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
+ } else {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = true
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = false
+ }
+ }
+ } else {
+ checkPoint = { x: midX.plus(10).toNumber(), y: midY.toNumber() }
+ if (wall.inPolygon(checkPoint)) {
+ if (value.s === 1) {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = false
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
+ } else {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = true
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = false
+ }
+ } else {
+ if (value.s === -1) {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = false
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
+ } else {
+ UP_DOWN_REF.UP_RADIO_REF.current.checked = true
+ UP_DOWN_REF.DOWN_RADIO_REF.current.checked = false
+ }
+ }
+ }
}
}
- function edgesIntersection(edgeA, edgeB) {
- const den =
- (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex2.x - edgeA.vertex1.x) -
- (edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex2.y - edgeA.vertex1.y)
-
- if (den === 0) {
- return null // lines are parallel or coincident
- }
-
- const ua =
- ((edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
- (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
- den
-
- const ub =
- ((edgeA.vertex2.x - edgeA.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
- (edgeA.vertex2.y - edgeA.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
- den
-
- // Edges are not intersecting but the lines defined by them are
- const isIntersectionOutside = ua < 0 || ub < 0 || ua > 1 || ub > 1
-
- return {
- x: edgeA.vertex1.x + ua * (edgeA.vertex2.x - edgeA.vertex1.x),
- y: edgeA.vertex1.y + ua * (edgeA.vertex2.y - edgeA.vertex1.y),
- isIntersectionOutside,
- }
- }
-
- //동선 이동 마우스 클릭 이벤트
- const saveFlowLine = (e) => {
- const target = selectedObject.current
- if (!target) {
- return
- }
-
- let newPoint = []
- if (Math.sign(target.x1 - target.x2) !== 0) {
- const sign = FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked ? 1 : -1
- newPoint = [
- target.x1,
- target.y1 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
- target.x2,
- target.y2 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
- ]
- } else {
- const sign = FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked ? -1 : 1
- newPoint = [
- target.x1 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
- target.y1,
- target.x2 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
- target.y2,
- ]
- }
- newPoint = newPoint.map((point) => Math.round(point * 10) / 10)
- const cloned = new fabric.Line(newPoint, {})
- let currentObject = selectedObject.current
- const currentX1 = currentObject.x1,
- currentY1 = currentObject.y1,
- currentX2 = currentObject.x2,
- currentY2 = currentObject.y2
-
- const currentMidX = (currentX1 + currentX2) / 2
- const currentMidY = (currentY1 + currentY2) / 2
- const clonedMidX = (cloned.x1 + cloned.x2) / 2
- const clonedMidY = (cloned.y1 + cloned.y2) / 2
-
- const roof = canvas.getObjects().find((obj) => obj.id === currentObject.attributes.roofId)
- let isOutside = false
- roof.lines.forEach((line) => {
- const intersection = edgesIntersection(
- { vertex1: { x: currentMidX, y: currentMidY }, vertex2: { x: clonedMidX, y: clonedMidY } },
- { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
- )
- if (intersection && !intersection.isIntersectionOutside) {
- isOutside = true
- }
- })
- if (isOutside) {
- swalFire({ text: getMessage('modal.movement.flow.line.move.alert'), icon: 'error' })
- return
- }
- currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 })
- currentObject.setCoords()
- const otherRidges = roof.innerLines.filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE && line.id !== currentObject.id)
- const overlapRidges = otherRidges.filter((line) => {
- if (currentObject.x1 === currentObject.x2 && line.x1 === line.x2 && 0 < Math.abs(currentObject.x1 - line.x1) < 1) {
- if (
- currentObject.y1 <= line.y1 <= currentObject.y2 ||
- currentObject.y1 >= line.y1 >= currentObject.y2 ||
- currentObject.y1 <= line.y2 <= currentObject.y2 ||
- currentObject.y1 >= line.y2 >= currentObject.y2
- ) {
- return true
- }
- }
- if (currentObject.y1 === currentObject.y2 && line.y1 === line.y2 && 0 < Math.abs(currentObject.y1 - line.y1) < 1) {
- if (
- currentObject.x1 <= line.x1 <= currentObject.x2 ||
- currentObject.x1 >= line.x1 >= currentObject.x2 ||
- currentObject.x1 <= line.x2 <= currentObject.x2 ||
- currentObject.x1 >= line.x2 >= currentObject.x2
- ) {
- return true
- }
- }
- })
- if (overlapRidges.length > 0) {
- const minX = Math.min(...overlapRidges.flatMap((line) => [line.x1, line.x2]), currentObject.x1, currentObject.x2)
- const maxX = Math.max(...overlapRidges.flatMap((line) => [line.x1, line.x2]), currentObject.x1, currentObject.x2)
- const minY = Math.min(...overlapRidges.flatMap((line) => [line.y1, line.y2]), currentObject.y1, currentObject.y2)
- const maxY = Math.max(...overlapRidges.flatMap((line) => [line.y1, line.y2]), currentObject.y1, currentObject.y2)
- const newRidge = new fabric.Line([minX, minY, maxX, maxY], {
- name: LINE_TYPE.SUBLINE.RIDGE,
- selectable: true,
- stroke: '#1083E3',
- strokeWidth: 4,
- attributes: { roofId: roof.id, currentRoofId: currentObject.attributes.currentRoofId },
- })
-
- overlapRidges.forEach((line) =>
- line.attributes.currentRoofId.forEach((id) => {
- if (!newRidge.attributes.currentRoofId.includes(id)) {
- newRidge.attributes.currentRoofId.push(id)
- }
- }),
- )
- canvas.add(newRidge)
- newRidge.bringToFront()
- roof.innerLines.push(newRidge)
-
- canvas.remove(currentObject)
- roof.innerLines.forEach((innerLine, index) => {
- if (innerLine.id === currentObject.id) {
- roof.innerLines.splice(index, 1)
- }
- })
-
- overlapRidges.forEach((line) => {
- canvas.remove(line)
- roof.innerLines.forEach((innerLine, index) => {
- if (innerLine.id === line.id) {
- roof.innerLines.splice(index, 1)
- }
- })
- })
- }
-
- if (roof.separatePolygon.length > 0) {
- redrawSeparatePolygon(roof)
- } else {
- roof.innerLines
- .filter((line) => currentObject !== line)
- .filter(
- (line) =>
- (line.x1 === currentX1 && line.y1 === currentY1) ||
- (line.x2 === currentX1 && line.y2 === currentY1) ||
- (line.x1 === currentX2 && line.y1 === currentY2) ||
- (line.x2 === currentX2 && line.y2 === currentY2),
- )
- .forEach((line) => {
- const lineDegree = 90 - Math.asin(line.attributes.planeSize / line.attributes.actualSize) * (180 / Math.PI)
- if (line.x1 === currentX1 && line.y1 === currentY1) {
- line.set({ x1: newPoint[0], y1: newPoint[1] })
- } else if (line.x2 === currentX1 && line.y2 === currentY1) {
- line.set({ x2: newPoint[0], y2: newPoint[1] })
- } else if (line.x1 === currentX2 && line.y1 === currentY2) {
- line.set({ x1: newPoint[2], y1: newPoint[3] })
- } else if (line.x2 === currentX2 && line.y2 === currentY2) {
- line.set({ x2: newPoint[2], y2: newPoint[3] })
- }
- line.setCoords()
- line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
- line.attributes.actualSize = Math.round(
- Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(line.attributes.planeSize * Math.tan(lineDegree * (Math.PI / 180)), 2)),
- )
- })
- }
-
- currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 })
- currentObject.setCoords()
-
+ const mouseDownEvent = (e) => {
+ canvas
+ .getObjects()
+ .filter((obj) => obj.name === 'checkPoint' || obj.name === 'checkLine')
+ .forEach((obj) => canvas.remove(obj))
canvas.renderAll()
- canvas.discardActiveObject()
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
- }
-
- //형 올림내림 마우스 클릭 이벤트
- const saveUpDownLine = (e) => {
const target = selectedObject.current
- if (!target) {
- return
- }
+ if (!target) return
- const roof = canvas.getObjects().find((obj) => obj.id === target.attributes.roofId)
- const wallLines = roof.wall.lines
- const roofLines = roof.lines
- const currentWall = wallLines.find((line) => line.id === target.attributes.currentWall)
- let prevWall, nextWall
- let prevEave, nextEave
+ const roofId = target.attributes.roofId
+ const followLine = canvas.getObjects().find((obj) => obj.name === 'followLine')
- wallLines.forEach((wallLine, index) => {
- if (wallLine.id === currentWall.id) {
- prevWall = index === 0 ? wallLines[wallLines.length - 1] : wallLines[index - 1]
- nextWall = index === wallLines.length - 1 ? wallLines[0] : wallLines[index + 1]
- }
- })
-
- const eaves = roofLines.filter((line) => line.attributes?.type === LINE_TYPE.WALLLINE.EAVES)
-
- wallLines
- .filter((line) => line.attributes.type === LINE_TYPE.WALLLINE.EAVES)
- .forEach((eave, index) => {
- if (eave.id === currentWall.id) {
- prevEave = index === 0 ? eaves[eaves.length - 1] : eaves[index - 1]
- nextEave = index === eaves.length - 1 ? eaves[0] : eaves[index + 1]
- }
- })
-
- const currentRoof = roofLines.find((line) => line.id === target.attributes.currentRoof)
- const currentRidges = roof.innerLines.filter(
- (line) => line.name === LINE_TYPE.SUBLINE.RIDGE && line.attributes.currentRoof.includes(currentRoof.id),
- )
- /*const prevWallRidges = roof.innerLines.filter(
- (line) => line.name === LINE_TYPE.SUBLINE.RIDGE && line.attributes.currentRoof.includes(prevEave.id),
- )
- const nextWallRidges = roof.innerLines.filter(
- (line) => line.name === LINE_TYPE.SUBLINE.RIDGE && line.attributes.currentRoof.includes(nextEave.id),
- )
- //라인 확인 작업
- /!* const roofLine = new fabric.Line([currentRoof.x1, currentRoof.y1, currentRoof.x2, currentRoof.y2], {
- stroke: 'red',
- strokeWidth: 5,
+ const confirmLine = new fabric.Line([followLine.x1, followLine.y1, followLine.x2, followLine.y2], {
+ left: followLine.left,
+ top: followLine.top,
+ stroke: '#000000',
+ strokeWidth: 4,
selectable: false,
+ parentId: roofId,
+ name: 'confirmLine',
+ target,
})
- canvas.add(roofLine)
+ canvas.add(confirmLine)
+ canvas.renderAll()
+ CONFIRM_LINE_REF.current = confirmLine
- const prevEaves = new fabric.Line([prevEave.x1, prevEave.y1, prevEave.x2, prevEave.y2], {
- stroke: 'yellow',
- strokeWidth: 5,
- selectable: false,
- })
- canvas.add(prevEaves)
- currentRidges.forEach((ridge) => ridge.set({ stroke: 'purple', strokeWidth: 5 }))
- prevWallRidges.forEach((ridge) => ridge.set({ stroke: 'yellow', strokeWidth: 5 }))
- nextWallRidges.forEach((ridge) => ridge.set({ stroke: 'green', strokeWidth: 5 }))
- canvas.renderAll()*!/*/
-
- console.log(
- 'UP/DOWN',
- UP_DOWN_REF.UP_RADIO_REF.current.checked,
- UP_DOWN_REF.DOWN_RADIO_REF.current.checked,
- UP_DOWN_REF.FILLED_INPUT_REF.current.value,
- )
-
- let compareLine
- if (Math.sign(currentRoof.x1 - currentRoof.x2) === 0) {
- const currentDiff = currentRidges[0].x1 - currentRoof.x1
- const prevDiff = prevEave.x1 - currentRoof.x1
- const nextDiff = nextEave.x1 - currentRoof.x1
-
- console.log('currentDiff', Math.sign(currentDiff), currentDiff)
-
- if (UP_DOWN_REF.UP_RADIO_REF.current.checked) {
- if (Math.sign(currentDiff) === 1) {
- } else {
- if (Math.sign(prevDiff) === 1 && Math.sign(nextDiff) === 1) {
- } else {
- }
- }
- } else {
- if (Math.sign(currentDiff) === -1) {
- } else {
- if (Math.sign(prevDiff) === -1 && Math.sign(nextDiff) === -1) {
- } else {
- }
- }
- }
- } else {
- const currentDiff = currentRidges[0].y1 - currentRoof.y1
- const prevDiff = prevEave.y1 - currentRoof.y1
- const nextDiff = nextEave.y1 - currentRoof.y1
-
- if (UP_DOWN_REF.UP_RADIO_REF.current.checked) {
- if (Math.sign(currentDiff) === 1) {
- } else {
- if (Math.sign(prevDiff) === 1 && Math.sign(nextDiff) === 1) {
- } else {
- }
- }
- } else {
- if (Math.sign(currentDiff) === -1) {
- } else {
- if (Math.sign(prevDiff) === -1 && Math.sign(nextDiff) === -1) {
- } else {
- }
- }
- }
- }
-
- //확인
- /*const compareRoofLine = new fabric.Line([compareRoof.x1, compareRoof.y1, compareRoof.x2, compareRoof.y2], {
- stroke: 'red',
- strokeWidth: 5,
- selectable: false,
- })
- canvas.add(compareRoofLine)
- canvas.renderAll()*/
- }
-
- const redrawSeparatePolygon = (roof) => {
- roof.separatePolygon.forEach((polygon) => canvas.remove(polygon))
- roof.separatePolygon = []
- const roofLines = roof.lines
- const wallLines = roof.wall.lines
- const eaves = []
- roofLines.forEach((currentRoof, index) => {
- if (currentRoof.attributes?.type === LINE_TYPE.WALLLINE.EAVES) {
- eaves.push({ index: index, roof: currentRoof, length: currentRoof.attributes.planeSize })
- }
- })
- const ridges = roof.innerLines.filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE)
- eaves.sort((a, b) => a.length - b.length)
-
- const ridgeCount = eaves.length - 1
- console.log('ridgeCount', ridgeCount, 'ridges', ridges.length)
-
- const duplicatedEaves = []
- ridges.forEach((ridge) => {
- const positiveLines = []
- const negativeLines = []
- ridge.attributes.currentRoof.forEach((id) => {
- console.log('id : ', id)
- const eave = roofLines.find((obj) => obj.id === id)
- console.log('roof : ', eave)
- if (ridge.x1 === ridge.x2) {
- if (eave.y1 < eave.y2) {
- positiveLines.push(eave)
- } else {
- negativeLines.push(eave)
- }
- } else {
- if (eave.x1 < eave.x2) {
- positiveLines.push(eave)
- } else {
- negativeLines.push(eave)
- }
- }
- })
- if (positiveLines.length > 1) {
- duplicatedEaves.push(positiveLines)
- }
- if (negativeLines.length > 1) {
- duplicatedEaves.push(negativeLines)
- }
- })
- console.log('duplicatedEaves', duplicatedEaves)
-
- duplicatedEaves.forEach((duplicatedEave) => {
- duplicatedEave.forEach((eave) => {
- const index = eaves.findIndex((item) => item.roof.id === eave.id)
- eaves.splice(index, 1)
- })
- })
-
- // if (ridgeCount === ridges.length) {
- eaves.forEach((eave, i) => {
- const index = eave.index,
- currentRoof = eave.roof
- const currentWall = wallLines[index]
- const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.roof.id))
- let points = []
- const signX = Math.sign(currentRoof.x1 - currentRoof.x2)
- let currentX1 = currentRoof.x1,
- currentY1 = currentRoof.y1,
- currentX2 = currentRoof.x2,
- currentY2 = currentRoof.y2
- let changeX1 = [Math.min(currentRoof.x1, currentRoof.x2), Math.min(currentRoof.x1, currentRoof.x2)],
- changeY1 = [Math.min(currentRoof.y1, currentRoof.y2), Math.min(currentRoof.y1, currentRoof.y2)],
- changeX2 = [Math.max(currentRoof.x2, currentRoof.x1), Math.max(currentRoof.x2, currentRoof.x1)],
- changeY2 = [Math.max(currentRoof.y2, currentRoof.y1), Math.max(currentRoof.y2, currentRoof.y1)]
-
- if (signX === 0) {
- currentY1 = Math.min(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
- changeY1[1] = currentY1
- currentY2 = Math.max(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
- changeY2[1] = currentY2
- } else {
- currentX1 = Math.min(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
- changeX1[1] = currentX1
- currentX2 = Math.max(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
- changeX2[1] = currentX2
- }
- points.push({ x: currentX1, y: currentY1 }, { x: currentX2, y: currentY2 })
-
- currentRidges.forEach((ridge) => {
- let ridgeX1 = ridge.x1,
- ridgeY1 = ridge.y1,
- ridgeX2 = ridge.x2,
- ridgeY2 = ridge.y2
- if (signX === 0) {
- ridgeY1 = Math.min(ridge.y1, ridge.y2)
- ridgeY2 = Math.max(ridge.y1, ridge.y2)
- } else {
- ridgeX1 = Math.min(ridge.x1, ridge.x2)
- ridgeX2 = Math.max(ridge.x1, ridge.x2)
- }
- points.push({ x: ridgeX1, y: ridgeY1 }, { x: ridgeX2, y: ridgeY2 })
- })
-
- points.forEach((point) => {
- if (point.x === changeX1[0] && changeX1[0] !== changeX1[1]) {
- point.x = changeX1[1]
- }
- if (point.x === changeX2[0] && changeX2[0] !== changeX2[1]) {
- point.x = changeX2[1]
- }
- if (point.y === changeY1[0] && changeY1[0] !== changeY1[1]) {
- point.y = changeY1[1]
- }
- if (point.y === changeY2[0] && changeY2[0] !== changeY2[1]) {
- point.y = changeY2[1]
- }
- })
- //중복된 point 제거
- points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
- //point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
- const startPoint = points
- .filter((point) => point.x === Math.min(...points.map((point) => point.x)))
- .reduce((prev, current) => {
- return prev.y < current.y ? prev : current
- })
-
- const sortedPoints = []
- sortedPoints.push(startPoint)
-
- points.forEach((p, index) => {
- if (index === 0) {
- //시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
- const underStartPoint = points.filter((point) => point.y > startPoint.y)
- const nextPoint = underStartPoint
- .filter((point) => point.x === startPoint.x)
- .reduce((prev, current) => {
- if (prev === undefined) {
- return current
- }
- return Math.abs(prev.y - startPoint.y) < Math.abs(current.y - startPoint.y) ? prev : current
- }, undefined)
- if (nextPoint) {
- sortedPoints.push(nextPoint)
- } else {
- const nextPoint = underStartPoint.reduce((prev, current) => {
- const prevHypos = Math.sqrt(Math.abs(Math.pow(prev.x - startPoint.x, 2)) + Math.abs(Math.pow(prev.y - startPoint.y, 2)))
- const currentHypos = Math.sqrt(Math.abs(Math.pow(current.x - startPoint.x, 2)) + Math.abs(Math.pow(current.y - startPoint.y, 2)))
- return prevHypos < currentHypos ? prev : current
- }, undefined)
- sortedPoints.push(nextPoint)
- }
- } else {
- const lastPoint = sortedPoints[sortedPoints.length - 1]
- console.log('lastPoint', lastPoint)
- const prevPoint = sortedPoints[sortedPoints.length - 2]
- const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
- const nextPoint = otherPoints.reduce((prev, current) => {
- if (prev === undefined) {
- const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
- const adjacent = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
- const hypotenuse = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
-
- const angle = Math.round(
- Math.acos((Math.pow(adjacent, 2) + Math.pow(height, 2) - Math.pow(hypotenuse, 2)) / (2 * adjacent * height)) * (180 / Math.PI),
- )
- if (angle === 90) {
- return current
- }
- } else {
- return prev
- }
- }, undefined)
- if (nextPoint) {
- sortedPoints.push(nextPoint)
- } else {
- const nextPoint = otherPoints.reduce((prev, current) => {
- if (prev !== undefined) {
- const height = Math.abs(
- Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))),
- )
- const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
- const hypotenuseC = Math.abs(
- Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))),
- )
- const angleC = Math.round(
- Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
- )
- const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
- const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
- const angleP = Math.round(
- Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
- )
- if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
- return current
- } else {
- return prev
- }
- } else {
- return current
- }
- }, undefined)
- if (nextPoint) {
- sortedPoints.push(nextPoint)
- }
- }
- }
- })
-
- if (sortedPoints.length > 0) {
- const roofPolygon = new QPolygon(sortedPoints, {
- fill: 'transparent',
- stroke: '#000000',
- strokeWidth: 1,
- selectable: false,
- fontSize: roof.fontSize,
- name: 'roofPolygon',
- attributes: {
- roofId: roof.id,
- currentRoofId: currentRoof.id,
- pitch: currentRoof.attributes.pitch,
- degree: currentRoof.attributes.degree,
- direction: currentRoof.direction,
- },
- })
- const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree
- //지붕 각도에 따른 실측치 조정
- roofPolygon.lines.forEach((line) => {
- line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
- const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
-
- if (currentDegree > 0 && slope(line) !== slope(currentRoof)) {
- const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
- line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
- } else {
- line.attributes.actualSize = line.attributes.planeSize
- }
- })
- roof.separatePolygon.push(roofPolygon)
- canvas.add(roofPolygon)
- canvas.renderAll()
- }
- })
-
- duplicatedEaves.forEach((duplicatedEave) => {
- const currentRoof = duplicatedEave[0]
- let points = []
- duplicatedEave.forEach((eave) => {
- points.push({ x: eave.x1, y: eave.y1 }, { x: eave.x2, y: eave.y2 })
- const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.id))
- currentRidges.forEach((ridge) => {
- points.push({ x: ridge.x1, y: ridge.y1 }, { x: ridge.x2, y: ridge.y2 })
- })
- })
- console.log('points', points)
- points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
- //point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
-
- const startPoint = points
- .filter((point) => point.x === Math.min(...points.map((point) => point.x)))
- .reduce((prev, current) => {
- return prev.y < current.y ? prev : current
- })
-
- const sortedPoints = []
- sortedPoints.push(startPoint)
-
- points.forEach((p, index) => {
- if (index === 0) {
- //시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
- const underStartPoint = points.filter((point) => point.y > startPoint.y)
- const nextPoint = underStartPoint
- .filter((point) => point.x === startPoint.x)
- .reduce((prev, current) => {
- if (prev === undefined) {
- return current
- }
- return Math.abs(prev.y - startPoint.y) < Math.abs(current.y - startPoint.y) ? prev : current
- }, undefined)
- if (nextPoint) {
- sortedPoints.push(nextPoint)
- } else {
- const nextPoint = underStartPoint.reduce((prev, current) => {
- const prevHypos = Math.sqrt(Math.abs(Math.pow(prev.x - startPoint.x, 2)) + Math.abs(Math.pow(prev.y - startPoint.y, 2)))
- const currentHypos = Math.sqrt(Math.abs(Math.pow(current.x - startPoint.x, 2)) + Math.abs(Math.pow(current.y - startPoint.y, 2)))
- return prevHypos < currentHypos ? prev : current
- }, undefined)
- sortedPoints.push(nextPoint)
- }
- } else {
- const lastPoint = sortedPoints[sortedPoints.length - 1]
- console.log('lastPoint', lastPoint)
- const prevPoint = sortedPoints[sortedPoints.length - 2]
- const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
- const nextPoint = otherPoints.reduce((prev, current) => {
- if (prev === undefined) {
- const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
- const adjacent = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
- const hypotenuse = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
-
- const angle = Math.round(
- Math.acos((Math.pow(adjacent, 2) + Math.pow(height, 2) - Math.pow(hypotenuse, 2)) / (2 * adjacent * height)) * (180 / Math.PI),
- )
- if (angle === 90) {
- return current
- }
- } else {
- return prev
- }
- }, undefined)
- if (nextPoint) {
- sortedPoints.push(nextPoint)
- } else {
- const nextPoint = otherPoints.reduce((prev, current) => {
- if (prev !== undefined) {
- const height = Math.abs(
- Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))),
- )
- const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
- const hypotenuseC = Math.abs(
- Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))),
- )
- const angleC = Math.round(
- Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
- )
- const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
- const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
- const angleP = Math.round(
- Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
- )
- if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
- return current
- } else {
- return prev
- }
- } else {
- return current
- }
- }, undefined)
- if (nextPoint) {
- sortedPoints.push(nextPoint)
- }
- }
- }
- })
-
- if (sortedPoints.length > 0) {
- const roofPolygon = new QPolygon(sortedPoints, {
- fill: 'transparent',
- stroke: '#000000',
- strokeWidth: 1,
- selectable: false,
- fontSize: roof.fontSize,
- name: 'roofPolygon',
- attributes: {
- roofId: roof.id,
- currentRoofId: currentRoof.id,
- pitch: currentRoof.attributes.pitch,
- degree: currentRoof.attributes.degree,
- direction: currentRoof.direction,
- },
- })
- const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree
- //지붕 각도에 따른 실측치 조정
- roofPolygon.lines.forEach((line) => {
- line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
- const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
-
- if (currentDegree > 0 && slope(line) !== slope(currentRoof)) {
- const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
- line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
- } else {
- line.attributes.actualSize = line.attributes.planeSize
- }
- })
- roof.separatePolygon.push(roofPolygon)
- canvas.add(roofPolygon)
- canvas.renderAll()
- }
- })
- console.log('roof.separatePolygon : ', roof.separatePolygon)
-
- ridges.forEach((ridge) => ridge.bringToFront())
- console.log('ridges : ', ridges)
- }
-
- const flowLineMoveEvent = (e) => {
- const target = canvas.getActiveObject()
- if (!target) {
- return
- }
- const { top: targetTop, left: targetLeft } = target
- const currentX = canvas.getPointer(e.e).x
- const currentY = Math.floor(canvas.getPointer(e.e).y)
-
- if (Math.sign(target.x1 - target.x2) !== 0) {
- if (targetTop > currentY) {
- FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(targetTop - currentY))) / 10000).toFixed(5) * 100000)
- } else {
- FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(targetTop - currentY))) / 10000).toFixed(5) * 100000)
- }
- } else {
- if (targetLeft < currentX) {
- FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(currentX - targetLeft))) / 10000).toFixed(5) * 100000)
- } else {
- FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(currentX - targetLeft))) / 10000).toFixed(5) * 100000)
- }
- }
-
- canvas?.renderAll()
- }
-
- const updownMoveEvent = (e) => {
- const target = canvas.getActiveObject()
- if (!target) {
- return
- }
- const { top: targetTop, left: targetLeft } = target
- const currentX = canvas.getPointer(e.e).x
- const currentY = Math.floor(canvas.getPointer(e.e).y)
-
- if (Math.sign(target.x1 - target.x2) !== 0) {
- if (targetTop > currentY) {
- UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
- UP_DOWN_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000)
- } else {
- UP_DOWN_REF.UP_RADIO_REF.current.checked = true
- UP_DOWN_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000)
- }
- } else {
- if (targetLeft > currentX) {
- UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
- UP_DOWN_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000)
- } else {
- UP_DOWN_REF.UP_RADIO_REF.current.checked = true
- UP_DOWN_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000)
- }
- }
-
- canvas?.renderAll()
+ handleSave()
}
const handleSave = () => {
- if (type === TYPE.FLOW_LINE) {
- saveFlowLine()
+ const target = selectedObject.current !== null ? selectedObject.current : CONFIRM_LINE_REF.current?.target
+ if (!target) return
+
+ const roofId = target.attributes.roofId
+ const roof = canvas.getObjects().find((obj) => obj.id === roofId)
+ const wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes.roofId === roofId)
+ const baseLines = wall.baseLines
+ let targetBaseLines = []
+
+ if (typeRef.current === TYPE.FLOW_LINE) {
+ const lineVector =
+ target.y1 === target.y2
+ ? FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked
+ ? 'up'
+ : 'down'
+ : FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked
+ ? 'right'
+ : 'left'
+ switch (lineVector) {
+ case 'up':
+ baseLines
+ .filter((line) => line.y1 === line.y2 && line.y1 < target.y1)
+ .forEach((line) => targetBaseLines.push({ line, distance: Big(target.y1).minus(line.y1).abs().toNumber() }))
+ break
+ case 'down':
+ baseLines
+ .filter((line) => line.y1 === line.y2 && line.y1 > target.y1)
+ .forEach((line) => targetBaseLines.push({ line, distance: Big(line.y1).minus(target.y1).abs().toNumber() }))
+ break
+ case 'right':
+ baseLines
+ .filter((line) => line.x1 === line.x2 && line.x1 > target.x1)
+ .forEach((line) => targetBaseLines.push({ line, distance: Big(target.x1).minus(line.x1).abs().toNumber() }))
+
+ break
+ case 'left':
+ baseLines
+ .filter((line) => line.x1 === line.x2 && line.x1 < target.x1)
+ .forEach((line) => targetBaseLines.push({ line, distance: Big(line.x1).minus(target.x1).abs().toNumber() }))
+ break
+ }
} else {
- saveUpDownLine()
+ targetBaseLines.push({ line: target, distance: 0 })
}
+
+ targetBaseLines.sort((a, b) => a.distance - b.distance)
+ targetBaseLines = targetBaseLines.filter((line) => line.distance === targetBaseLines[0].distance)
+ let value
+ if (typeRef.current === TYPE.FLOW_LINE) {
+ value =
+ FLOW_LINE_REF.FILLED_INPUT_REF.current.value !== ''
+ ? Big(FLOW_LINE_REF.FILLED_INPUT_REF.current.value).times(2)
+ : Big(FLOW_LINE_REF.POINTER_INPUT_REF.current.value).times(2)
+ if (target.y1 === target.y2) {
+ value = value.neg()
+ }
+ } else {
+ value =
+ UP_DOWN_REF.FILLED_INPUT_REF.current.value !== ''
+ ? Big(UP_DOWN_REF.FILLED_INPUT_REF.current.value)
+ : Big(UP_DOWN_REF.POINTER_INPUT_REF.current.value)
+
+ const midX = Big(target.x1).plus(target.x2).div(2)
+ const midY = Big(target.y1).plus(target.y2).div(2)
+ const wall = canvas.getObjects().find((obj) => obj.id === target.attributes.wallId)
+ let checkPoint
+ if (target.y1 === target.y2) {
+ checkPoint = { x: midX.toNumber(), y: midY.plus(10).times(value.s).toNumber() }
+ } else {
+ checkPoint = { x: midX.plus(10).toNumber().times(value.s), y: midY.toNumber() }
+ }
+
+ const inPolygon = wall.inPolygon(checkPoint)
+
+ console.log('inPolygon', inPolygon)
+ if (UP_DOWN_REF.UP_RADIO_REF.current.checked && inPolygon) {
+ value = value.neg()
+ } else if (UP_DOWN_REF.DOWN_RADIO_REF.current.checked && !inPolygon) {
+ value = value.neg()
+ }
+ }
+ value = value.div(10)
+ targetBaseLines.forEach((target) => {
+ const currentLine = target.line
+ const index = baseLines.findIndex((line) => line === currentLine)
+ const nextLine = baseLines[(index + 1) % baseLines.length]
+ const prevLine = baseLines[(index - 1 + baseLines.length) % baseLines.length]
+ let deltaX = 0
+ let deltaY = 0
+ if (currentLine.y1 === currentLine.y2) {
+ deltaY = value.toNumber()
+ } else {
+ deltaX = value.toNumber()
+ }
+
+ currentLine.set({
+ x1: currentLine.x1 + deltaX,
+ y1: currentLine.y1 + deltaY,
+ x2: currentLine.x2 + deltaX,
+ y2: currentLine.y2 + deltaY,
+ startPoint: { x: currentLine.x1 + deltaX, y: currentLine.y1 + deltaY },
+ endPoint: { x: currentLine.x2 + deltaX, y: currentLine.y2 + deltaY },
+ })
+
+ nextLine.set({
+ x1: nextLine.x1 + deltaX,
+ y1: nextLine.y1 + deltaY,
+ startPoint: { x: nextLine.x1 + deltaX, y: nextLine.y1 + deltaY },
+ })
+
+ prevLine.set({
+ x2: prevLine.x2 + deltaX,
+ y2: prevLine.y2 + deltaY,
+ endPoint: { x: prevLine.x2 + deltaX, y: prevLine.y2 + deltaY },
+ })
+
+ canvas.renderAll()
+ })
+
+ if (CONFIRM_LINE_REF.current !== null) {
+ canvas.remove(CONFIRM_LINE_REF.current)
+ CONFIRM_LINE_REF.current = null
+ canvas.renderAll()
+ }
+ if (FOLLOW_LINE_REF.current !== null) {
+ canvas.remove(FOLLOW_LINE_REF.current)
+ FOLLOW_LINE_REF.current = null
+ canvas.renderAll()
+ }
+
+ roof.drawHelpLine()
+ initEvent()
+ closePopup(id)
}
return {
diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js
index f1139366..1b4036c0 100644
--- a/src/hooks/roofcover/useRoofShapeSetting.js
+++ b/src/hooks/roofcover/useRoofShapeSetting.js
@@ -108,6 +108,7 @@ export function useRoofShapeSetting(id) {
})
addPitchText(line)
+ line.bringToFront()
}
})
canvas.renderAll()
diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js
index e4beea37..788f9d22 100644
--- a/src/hooks/useMode.js
+++ b/src/hooks/useMode.js
@@ -1770,10 +1770,7 @@ export function useMode() {
afterLine.push(line)
}
})
-
wall.lines = afterLine.concat(beforeLine)
- wall.baseLines = wall.lines
- wall.colorLines = []
//외벽선을 기준으로 polygon을 생성한다. 지붕선의 기준이 됨.
const divWallLines = []
@@ -1905,55 +1902,21 @@ export function useMode() {
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()
line.attributes.roofId = roof.id
+ line.attributes.wallId = wall.id
// line.attributes.currentRoofId = roof.lines[index].id
line.attributes.planeSize = lineLength
line.attributes.actualSize = lineLength
- let wallStroke, wallStrokeWidth
- switch (line.attributes.type) {
- case LINE_TYPE.WALLLINE.EAVES:
- wallStroke = '#45CD7D'
- wallStrokeWidth = 4
- break
- case LINE_TYPE.WALLLINE.HIPANDGABLE:
- 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,
+ const baseLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
+ visible: false,
+ attributes: line.attributes,
+ startPoint: line.startPoint,
+ endPoint: line.endPoint,
+ parentId: roof.id,
+ name: 'baseLine',
})
- wall.colorLines.push(wallLine)
- canvas.add(wallLine)
+ roof.wall.baseLines.push(baseLine)
+ canvas.add(baseLine)
})
setRoof(roof)
diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js
index 52551cdd..17b97840 100644
--- a/src/util/qpolygon-utils.js
+++ b/src/util/qpolygon-utils.js
@@ -740,7 +740,9 @@ export const drawShedRoof = (roofId, canvas, textMode) => {
*/
export const drawRidgeRoof = (roofId, canvas, textMode) => {
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
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) {
@@ -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 }))
- console.log('지붕 마루 갯수 확인 : ', getMaxRidge(baseLines.length))
+ console.log('지붕 마루 갯수 확인 : ', getMaxRidge(baseLines.length), baseLinePoints)
/**
* baseLine을 기준으로 확인용 polygon 작성
@@ -801,6 +806,8 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
if (eavesType.includes(nextLine.attributes?.type)) {
const prevAngle = calculateAngle(prevLine.startPoint, prevLine.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) => {
const { currentLine, prevLine, nextLine } = current
@@ -1715,25 +1723,27 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
{ vertex1: { x: x1, y: y1 }, vertex2: prevEndPoint },
{ 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',
strokeWidth: 2,
parentId: roof.id,
+ name: 'checkLine',
})
canvas.add(checkLine)
- canvas.renderAll()*/
+ canvas.renderAll()
- /* if (intersection) {
+ if (intersection) {
const intersectCircle = new fabric.Circle({
left: intersection.x - 2,
top: intersection.y - 2,
radius: 4,
fill: 'red',
parentId: roof.id,
+ name: 'checkPoint',
})
canvas.add(intersectCircle)
canvas.renderAll()
- }*/
+ }
if (intersection && !intersection.isIntersectionOutside) {
intersectRidgeLine.push({
intersection,
@@ -1766,13 +1776,14 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
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',
strokeWidth: 2,
parentId: roof.id,
+ name: 'checkLine',
})
canvas.add(checkLine)
- canvas.renderAll()*/
+ canvas.renderAll()
let intersectPoints = []
/** 외벽선에서 추녀 마루가 겹치는 경우에 대한 확인*/
@@ -2279,7 +2290,7 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
})
/** hip을 그리기 위한 기본 길이*/
- let hipSize = 0
+ let hipSize = Big(0)
if (basePoints.length > 0) {
basePoints.sort((a, b) => {
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)
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)) {
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)
- 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도 방향으로만 그린다. */
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
}
})
- /** 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과 교차하지 않는 포인트를 추가한다.*/
if (notIntersect45) {
intersectPoints.push(checkEdge45.vertex2)
@@ -2363,6 +2373,13 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
if (notIntersect315) {
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) => {
const points = [current.x, current.y, is.x, is.y]
const hipLine = drawHipLine(points, canvas, roof, textMode, null, prevDegree, currentDegree)
@@ -2388,9 +2405,46 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
)
noRidgeHipPoints.forEach((current) => {
- const orthogonalPoints = noRidgeHipPoints.filter(
- (point) => point !== current && ((current.x2 === point.x2 && current.y2 !== point.y2) || (current.x2 !== point.x2 && current.y2 === point.y2)),
- )
+ const checkPoint = new fabric.Circle({
+ left: current.x2,
+ top: current.y2,
+ radius: 4,
+ fill: 'green',
+ parentId: roofId,
+ name: 'checkPoint',
+ })
+ canvas.add(checkPoint)
+ canvas.renderAll()
+ console.log('noRidgeHipPoints current : ', current.x1, current.y1, current.x2, current.y2)
+ const orthogonalPoints = noRidgeHipPoints.filter((point) => {
+ const checkPoint1 = new fabric.Circle({
+ left: point.x2,
+ top: point.y2,
+ radius: 4,
+ fill: 'blue',
+ parentId: roofId,
+ name: 'checkPoint',
+ })
+ canvas.add(checkPoint1)
+ canvas.renderAll()
+ console.log(' orthogonalPoints : ', point.x1, point.y1, point.x2, point.y2)
+ console.log(
+ 'same point :',
+ point !== current,
+ 'y point 다름',
+ current.x2 === point.x2 && current.y2 !== point.y2,
+ 'x point 다름',
+ current.x2 !== point.x2 && current.y2 === point.y2,
+ )
+ canvas.remove(checkPoint1)
+ canvas.renderAll()
+ if (point !== current && ((current.x2 === point.x2 && current.y2 !== point.y2) || (current.x2 !== point.x2 && current.y2 === point.y2))) {
+ return true
+ }
+ })
+
+ canvas.remove(checkPoint)
+ canvas.renderAll()
/** 직교 하는 포인트가 존재 할때 마루를 그린다. */
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))
.forEach((line) => unFinishedLines.push(line))
})
+
unFinishedLines.forEach((line) => {
const xVector = Math.sign(Big(line.x2).minus(Big(line.x1)))
const yVector = Math.sign(Big(line.y2).minus(Big(line.y1)))
@@ -2492,52 +2547,223 @@ export const drawRidgeRoof = (roofId, canvas, textMode) => {
}
})
- intersectPoints.forEach((intersection) => {
- const intersectPoint = intersection.intersection
- noRidgeHipPoints.forEach((hipPoint) => {
- const angle = calculateAngle({ x: intersectPoint.x, y: intersectPoint.y }, { x: hipPoint.x2, y: hipPoint.y2 })
- if (angle === 0 || angle === 180 || angle === 90 || angle === -90) {
- baseRidgeCount = baseRidgeCount + 1
- const ridgeLine = drawRidgeLine([intersectPoint.x, intersectPoint.y, hipPoint.x2, hipPoint.y2], canvas, roof, textMode)
- baseRidgeLines.push(ridgeLine)
- let baseHipLine = baseHipLines.filter((line) => line === intersection.line)[0]
- baseHipLine.x2 = intersectPoint.x
- baseHipLines.y2 = intersectPoint.y
- intersection.line.x2 = intersectPoint.x
- intersection.line.y2 = intersectPoint.y
- /** 보조선 라인 조정*/
- const hipLine = intersection.line.line
- /** 평면길이 */
- const planeSize = calcLinePlaneSize({
- x1: hipLine.x1,
- y1: hipLine.y1,
- x2: intersectPoint.x,
- y2: intersectPoint.y,
+ /** 마루를 그릴수 있는지 찾는다. */
+ noRidgeHipPoints.forEach((hipPoint) => {
+ const ridgePoints = []
+ 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(),
})
- /** 실제길이 */
- const actualSize =
- prevDegree === currentDegree
- ? calcLineActualSize(
- {
- x1: hipLine.x1,
- y1: hipLine.y1,
- x2: intersectPoint.x,
- y2: intersectPoint.y,
- },
- currentDegree,
- )
- : 0
- hipLine.set({ x2: intersectPoint.x, y2: intersectPoint.y, attributes: { roofId: roof.id, planeSize, actualSize } })
- hipLine.fire('modified')
- intersectPoints = intersectPoints.filter((isp) => isp !== intersection)
+ })
+ 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
+ baseRidgeLines.push(ridgeLine)
+
+ let baseHipLine = baseHipLines.filter((line) => line === intersection.line)[0]
+ baseHipLine.x2 = isPoint.x
+ baseHipLines.y2 = isPoint.y
+ /** 보조선 라인 조정*/
+ const hipLine = intersection.line.line
+ /** 평면길이 */
+ const planeSize = calcLinePlaneSize({
+ x1: hipLine.x1,
+ y1: hipLine.y1,
+ x2: isPoint.x,
+ y2: isPoint.y,
+ })
+ /** 실제길이 */
+ const actualSize =
+ prevDegree === currentDegree
+ ? calcLineActualSize(
+ {
+ x1: hipLine.x1,
+ y1: hipLine.y1,
+ x2: isPoint.x,
+ y2: isPoint.y,
+ },
+ currentDegree,
+ )
+ : 0
+ hipLine.set({
+ x2: isPoint.x,
+ y2: isPoint.y,
+ attributes: { roofId: roof.id, planeSize, actualSize },
+ })
+ hipLine.fire('modified')
+ intersectPoints = intersectPoints.filter((isp) => isp !== intersection)
+ 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 = []
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
.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 }
}
/** 대각선인 경우 hip확인*/
- if (
- Big(point.x)
- .minus(Big(current.x))
- .abs()
- .eq(Big(point.y).minus(Big(current.y)).abs())
- ) {
+ const hipX = Big(current.x).minus(Big(point.x)).abs()
+ const hipY = Big(current.y).minus(Big(point.y)).abs()
+ if (hipX.eq(hipY) && hipX.gt(0) && hipY.gt(0)) {
checkHipLine = { x1: current.x, y1: current.y, x2: point.x, y2: point.y }
}