Merge pull request 'dev' (#210) from dev into prd-deploy

Reviewed-on: #210
This commit is contained in:
ysCha 2025-07-15 14:45:26 +09:00
commit e9f3cb8e53
6 changed files with 198 additions and 58 deletions

View File

@ -701,14 +701,14 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
inPolygonImproved(point) { inPolygonImproved(point) {
const vertices = this.points const vertices = this.points
let inside = false let inside = false
const testX = point.x const testX = Number(point.x.toFixed(this.toFixed))
const testY = point.y const testY = Number(point.y.toFixed(this.toFixed))
for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) { for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
const xi = vertices[i].x const xi = Number(vertices[i].x.toFixed(this.toFixed))
const yi = vertices[i].y const yi = Number(vertices[i].y.toFixed(this.toFixed))
const xj = vertices[j].x const xj = Number(vertices[j].x.toFixed(this.toFixed))
const yj = vertices[j].y const yj = Number(vertices[j].y.toFixed(this.toFixed))
// 점이 정점 위에 있는지 확인 // 점이 정점 위에 있는지 확인
if (Math.abs(xi - testX) < 0.01 && Math.abs(yi - testY) < 0.01) { if (Math.abs(xi - testX) < 0.01 && Math.abs(yi - testY) < 0.01) {
@ -720,9 +720,16 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
return true return true
} }
// Ray casting 알고리즘 // Ray casting 알고리즘 - 부동소수점 정밀도 개선
if (yi > testY !== yj > testY && testX < ((xj - xi) * (testY - yi)) / (yj - yi) + xi) { if (yi > testY !== yj > testY) {
inside = !inside const denominator = yj - yi
if (Math.abs(denominator) > 1e-10) {
// 0으로 나누기 방지
const intersection = ((xj - xi) * (testY - yi)) / denominator + xi
if (testX < intersection) {
inside = !inside
}
}
} }
} }
@ -791,13 +798,15 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
// pathOffset을 고려한 최종 좌표 계산 // pathOffset을 고려한 최종 좌표 계산
const pathOffset = this.get('pathOffset') const pathOffset = this.get('pathOffset')
const finalPoint = { const finalPoint = {
x: transformedPoint.x + pathOffset.x, x: Number((transformedPoint.x + pathOffset.x).toFixed(this.toFixed)),
y: transformedPoint.y + pathOffset.y, y: Number((transformedPoint.y + pathOffset.y).toFixed(this.toFixed)),
} }
if (this.name === POLYGON_TYPE.ROOF && this.isFixed) { if (this.name === POLYGON_TYPE.ROOF && this.isFixed) {
const isInside = this.inPolygonImproved(finalPoint) const isInside = this.inPolygonImproved(finalPoint)
this.set('selectable', isInside) if (!this.selectable) {
this.set('selectable', isInside)
}
return isInside return isInside
} else { } else {
return this.inPolygonImproved(finalPoint) return this.inPolygonImproved(finalPoint)

View File

@ -32,7 +32,10 @@ export const useTrestle = () => {
const apply = () => { const apply = () => {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit) const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
if (notAllocationModules.length > 0) { if (notAllocationModules.length > 0) {
swalFire({ text: '回路番号が設定されていないモジュールがあります。 番号を設定しなおすか、 パネルを削除してください。', icon: 'error' }) swalFire({
text: '回路番号が設定されていないモジュールがあります。 番号を設定しなおすか、 パネルを削除してください。',
icon: 'error',
})
setIsGlobalLoading(false) setIsGlobalLoading(false)
return return
} }
@ -807,15 +810,12 @@ export const useTrestle = () => {
const getAzimuth = (parent) => { const getAzimuth = (parent) => {
const { moduleCompass, surfaceCompass, direction } = parent const { moduleCompass, surfaceCompass, direction } = parent
if(surfaceCompass) { if (surfaceCompass) {
return -surfaceCompass return -surfaceCompass
} }
let resultAzimuth = moduleCompass let resultAzimuth = moduleCompass
switch (direction) { switch (direction) {
case 'south': { case 'south': {
return resultAzimuth return resultAzimuth
@ -1882,7 +1882,15 @@ export const useTrestle = () => {
const { width, height } = { ...module } const { width, height } = { ...module }
widthArr.push(width) widthArr.push(width)
heightArr.push(height) heightArr.push(height)
centerPoints.push({ x, y, width: Math.floor(width), height: Math.floor(height), index, moduleInfo: module.moduleInfo, module }) centerPoints.push({
x,
y,
width: Math.floor(width),
height: Math.floor(height),
index,
moduleInfo: module.moduleInfo,
module,
})
}) })
//widthArr 중복 제거 1이상 차이가 나지 않으면 같은 너비로 간주 //widthArr 중복 제거 1이상 차이가 나지 않으면 같은 너비로 간주
@ -2055,8 +2063,8 @@ export const useTrestle = () => {
/** /**
* 디버깅용 * 디버깅용
module.set('fill', originFill) module.set('fill', originFill)
canvas.renderAll() canvas.renderAll()
*/ */
if (bottomCell) { if (bottomCell) {
return return
@ -2182,8 +2190,8 @@ export const useTrestle = () => {
/** /**
* 디버깅 * 디버깅
module.set('fill', originFill) module.set('fill', originFill)
canvas.renderAll() canvas.renderAll()
*/ */
if (leftTopCnt + rightTopCnt === 2) { if (leftTopCnt + rightTopCnt === 2) {
@ -3265,18 +3273,49 @@ export const useTrestle = () => {
return result return result
} }
function countMatchingCircuitNumbers(arrays) {
let cnt = 0
// 모든 고유한 circuitNumber 찾기
const allCircuitNumbers = new Set()
arrays.forEach((arr) => {
arr.forEach((item) => {
allCircuitNumbers.add(item.circuitNumber)
})
})
// 각 circuitNumber가 몇 개의 배열에 나타나는지 세기
allCircuitNumbers.forEach((circuitNum) => {
let arrayCount = 0
arrays.forEach((arr) => {
const hasCircuitNum = arr.some((item) => item.circuitNumber === circuitNum)
if (hasCircuitNum) {
arrayCount++
}
})
// 2개 이상의 배열에 나타나는 경우에만 카운트 (배열 개수 - 1)
if (arrayCount >= 2) {
cnt += arrayCount - 1
}
})
return cnt
}
// 양단 케이블 구하는 공식 // 양단 케이블 구하는 공식
const getTotalConnectCableCnt = () => { const getTotalConnectCableCnt = () => {
let cnt = 0 let cnt = 0
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
surfaces.forEach((surface) => { surfaces.forEach((surface) => {
const modules = surface.modules const modules = surface.modules
const groups = groupByType(modules) // 1. 현재 surface의 모듈들을 그룹화
groups.forEach((group) => { const groupInSurface = groupPoints(modules, surface)
const result = groupPoints(group, surface)
cnt += result.length - 1 cnt += countMatchingCircuitNumbers(groupInSurface)
})
}) })
const groupByCircuitAndSurfaceCnt = groupByCircuitAndSurface(modules) const groupByCircuitAndSurfaceCnt = groupByCircuitAndSurface(modules)

View File

@ -1,18 +1,17 @@
'use client' 'use client'
import { useEffect, useRef } from 'react' import { useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { BATCH_TYPE, INPUT_TYPE, POLYGON_TYPE } from '@/common/common' import { BATCH_TYPE, INPUT_TYPE, POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { import {
getDegreeByChon,
getTrianglePoints,
pointsToTurfPolygon, pointsToTurfPolygon,
polygonToTurfPolygon, polygonToTurfPolygon,
rectToPolygon, rectToPolygon,
triangleToPolygon,
getDegreeByChon,
toFixedWithoutRounding, toFixedWithoutRounding,
getTrianglePoints,
} from '@/util/canvas-util' } from '@/util/canvas-util'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
@ -23,6 +22,7 @@ import { fontSelector } from '@/store/fontAtom'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { roofDisplaySelector } from '@/store/settingAtom' import { roofDisplaySelector } from '@/store/settingAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useMouse } from '@/hooks/useMouse'
export function useObjectBatch({ isHidden, setIsHidden }) { export function useObjectBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -35,6 +35,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const lengthTextFont = useRecoilValue(fontSelector('lengthText')) const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const roofDisplay = useRecoilValue(roofDisplaySelector) const roofDisplay = useRecoilValue(roofDisplaySelector)
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { getIntersectMousePoint } = useMouse()
useEffect(() => { useEffect(() => {
if (canvas) { if (canvas) {
@ -59,7 +60,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
console.log('event', e) console.log('event', e)
if (e.target && e.target instanceof fabric.Group) { if (e.target && e.target instanceof fabric.Group) {
const pointer = canvas.getPointer(e.e) const pointer = getIntersectMousePoint(e)
const objects = e.target._objects const objects = e.target._objects
// 클릭한 위치에 있는 객체 찾기 // 클릭한 위치에 있는 객체 찾기
@ -98,7 +99,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (selectedType === INPUT_TYPE.FREE) { if (selectedType === INPUT_TYPE.FREE) {
addCanvasMouseEventListener('mouse:down', (e) => { addCanvasMouseEventListener('mouse:down', (e) => {
isDown = true isDown = true
const pointer = canvas.getPointer(e.e) const pointer = getIntersectMousePoint(e)
surfaceShapePolygons.forEach((surface) => { surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
@ -140,7 +141,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (!isDown) return if (!isDown) return
if (selectedSurface) { if (selectedSurface) {
const pointer = canvas.getPointer(e.e) const pointer = getIntersectMousePoint(e)
const width = pointer.x - origX const width = pointer.x - origX
const height = pointer.y - origY const height = pointer.y - origY
@ -208,7 +209,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (!isDown) return if (!isDown) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === objTempName)) //움직일때 일단 지워가면서 움직임 canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === objTempName)) //움직일때 일단 지워가면서 움직임
const pointer = canvas.getPointer(e.e) const pointer = getIntersectMousePoint(e)
surfaceShapePolygons.forEach((surface) => { surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
@ -220,8 +221,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
strokeWidth: 1, strokeWidth: 1,
width: width, width: width,
height: height, height: height,
left: pointer.x - width / 2, left: pointer.x,
top: pointer.y - height / 2, top: pointer.y,
selectable: true, selectable: true,
lockMovementX: true, lockMovementX: true,
lockMovementY: true, lockMovementY: true,
@ -329,7 +330,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (!isDown) return if (!isDown) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임 canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임
const pointer = canvas.getPointer(e.e) const pointer = getIntersectMousePoint(e)
surfaceShapePolygons.forEach((surface) => { surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
@ -679,7 +680,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (!isDown) return if (!isDown) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임 canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임
const pointer = canvas.getPointer(e.e) const pointer = getIntersectMousePoint(e)
surfaceShapePolygons.forEach((surface) => { surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {

View File

@ -8,6 +8,7 @@ import { useSwal } from '@/hooks/useSwal'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import Big from 'big.js' import Big from 'big.js'
import { calcLinePlaneSize } from '@/util/qpolygon-utils' import { calcLinePlaneSize } from '@/util/qpolygon-utils'
import { useMouse } from '@/hooks/useMouse'
//동선이동 형 올림 내림 //동선이동 형 올림 내림
export function useMovementSetting(id) { export function useMovementSetting(id) {
@ -19,6 +20,7 @@ export function useMovementSetting(id) {
const { initEvent, addCanvasMouseEventListener } = useEvent() const { initEvent, addCanvasMouseEventListener } = useEvent()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { getIntersectMousePoint } = useMouse()
const currentObject = useRecoilValue(currentObjectState) const currentObject = useRecoilValue(currentObjectState)
const selectedObject = useRef(null) const selectedObject = useRef(null)
const buttonType = [ const buttonType = [
@ -179,7 +181,7 @@ export function useMovementSetting(id) {
FOLLOW_LINE_REF.current = followLine FOLLOW_LINE_REF.current = followLine
canvas.on('mouse:move', (event) => { canvas.on('mouse:move', (event) => {
const mousePos = canvas.getPointer(event.e) const mousePos = getIntersectMousePoint(event)
if (followLine.x1 === followLine.x2) { if (followLine.x1 === followLine.x2) {
followLine.left = mousePos.x - 2 followLine.left = mousePos.x - 2
} else { } else {
@ -211,8 +213,8 @@ export function useMovementSetting(id) {
if (!target) return if (!target) return
const { top: targetTop, left: targetLeft } = target const { top: targetTop, left: targetLeft } = target
const currentX = Big(canvas.getPointer(e.e).x).round(0, Big.roundUp) const currentX = Big(getIntersectMousePoint(e).x).round(0, Big.roundUp)
const currentY = Big(canvas.getPointer(e.e).y).round(0, Big.roundUp) const currentY = Big(getIntersectMousePoint(e).y).round(0, Big.roundUp)
let value = '' let value = ''
if (target.y1 === target.y2) { if (target.y1 === target.y2) {
value = Big(targetTop).minus(currentY).times(10) value = Big(targetTop).minus(currentY).times(10)
@ -414,7 +416,12 @@ export function useMovementSetting(id) {
startPoint: { x: currentLine.x1 + deltaX, y: currentLine.y1 + deltaY }, startPoint: { x: currentLine.x1 + deltaX, y: currentLine.y1 + deltaY },
endPoint: { x: currentLine.x2 + deltaX, y: currentLine.y2 + deltaY }, endPoint: { x: currentLine.x2 + deltaX, y: currentLine.y2 + deltaY },
}) })
const currentSize = calcLinePlaneSize({ x1: currentLine.x1, y1: currentLine.y1, x2: currentLine.x2, y2: currentLine.y2 }) const currentSize = calcLinePlaneSize({
x1: currentLine.x1,
y1: currentLine.y1,
x2: currentLine.x2,
y2: currentLine.y2,
})
currentLine.attributes.planeSize = currentSize currentLine.attributes.planeSize = currentSize
currentLine.attributes.actualSize = currentSize currentLine.attributes.actualSize = currentSize

View File

@ -241,7 +241,11 @@ export function useRoofShapeSetting(id) {
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
let isValid = outerLines.every((line) => line.attributes?.isFixed) let isValid = outerLines.every((line) => line.attributes?.isFixed)
if (!isValid) { if (!isValid) {
swalFire({ text: getMessage('modal.canvas.setting.roofline.properties.setting.not.setting'), type: 'alert', icon: 'warning' }) swalFire({
text: getMessage('modal.canvas.setting.roofline.properties.setting.not.setting'),
type: 'alert',
icon: 'warning',
})
return return
} }
const pitch = outerLines.find((line) => line.attributes.type === LINE_TYPE.WALLLINE.SHED)?.attributes.pitch const pitch = outerLines.find((line) => line.attributes.type === LINE_TYPE.WALLLINE.SHED)?.attributes.pitch
@ -497,7 +501,13 @@ export function useRoofShapeSetting(id) {
canvas.remove(obj) canvas.remove(obj)
}) })
const polygon = addPolygonByLines(outerLines, { name: POLYGON_TYPE.WALL, direction, originX: 'center', originY: 'center' }) const polygon = addPolygonByLines(outerLines, {
name: POLYGON_TYPE.WALL,
direction,
originX: 'center',
originY: 'center',
})
polygon.setViewLengthText(false)
polygon.lines = [...outerLines] polygon.lines = [...outerLines]
addPitchTextsByOuterLines() addPitchTextsByOuterLines()

View File

@ -16,6 +16,7 @@ import { useTempGrid } from '@/hooks/useTempGrid'
import { gridColorState } from '@/store/gridAtom' import { gridColorState } from '@/store/gridAtom'
import { gridDisplaySelector } from '@/store/settingAtom' import { gridDisplaySelector } from '@/store/settingAtom'
import { MENU, POLYGON_TYPE } from '@/common/common' import { MENU, POLYGON_TYPE } from '@/common/common'
import { useMouse } from '@/hooks/useMouse'
export function useEvent() { export function useEvent() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
@ -35,6 +36,8 @@ export function useEvent() {
const textMode = useRecoilValue(textModeState) const textMode = useRecoilValue(textModeState)
const { getIntersectMousePoint } = useMouse()
// 이벤트 초기화 위치 수정 -> useCanvasSetting에서 세팅값 불러오고 나서 초기화 함수 호출 // 이벤트 초기화 위치 수정 -> useCanvasSetting에서 세팅값 불러오고 나서 초기화 함수 호출
// useEffect(() => { // useEffect(() => {
// initEvent() // initEvent()
@ -89,6 +92,7 @@ export function useEvent() {
const wheelEvent = (opt) => { const wheelEvent = (opt) => {
const delta = opt.e.deltaY // 휠 이동 값 (양수면 축소, 음수면 확대) const delta = opt.e.deltaY // 휠 이동 값 (양수면 축소, 음수면 확대)
let zoom = canvas.getZoom() // 현재 줌 값 let zoom = canvas.getZoom() // 현재 줌 값
// console.log('zoom', zoom, 'delta', delta)
zoom += delta > 0 ? -0.1 : 0.1 zoom += delta > 0 ? -0.1 : 0.1
@ -99,15 +103,14 @@ export function useEvent() {
setCanvasZoom(Number((zoom * 100).toFixed(0))) setCanvasZoom(Number((zoom * 100).toFixed(0)))
// 마우스 위치 기준으로 확대/축소 // 마우스 위치 기준으로 확대/축소
canvas.zoomToPoint(new fabric.Point(opt.e.offsetX, opt.e.offsetY), zoom) canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom)
canvas.calcOffset()
canvas.setViewportTransform(canvas.viewportTransform)
canvas.requestRenderAll()
canvas.getObjects().forEach((obj) => { canvas.getObjects().forEach((obj) => {
obj.setCoords() obj.setCoords()
}) })
canvas.renderAll()
// 이벤트의 기본 동작 방지 (스크롤 방지) // 이벤트의 기본 동작 방지 (스크롤 방지)
opt.e.preventDefault() opt.e.preventDefault()
opt.e.stopPropagation() opt.e.stopPropagation()
@ -129,7 +132,7 @@ export function useEvent() {
const roofsPoints = roofs.map((roof) => roof.points).flat() const roofsPoints = roofs.map((roof) => roof.points).flat()
roofAdsorptionPoints.current = [...roofsPoints] roofAdsorptionPoints.current = [...roofsPoints]
const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isFixed) const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine')
const otherAdsorptionPoints = [] const otherAdsorptionPoints = []
auxiliaryLines.forEach((line1) => { auxiliaryLines.forEach((line1) => {
@ -138,7 +141,17 @@ export function useEvent() {
return return
} }
const intersectionPoint = calculateIntersection(line1, line2) const intersectionPoint = calculateIntersection(line1, line2) // 보조선끼리 만나는 점
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 외벽선
outerLines.forEach((outerLine) => {
const outerIntersectionPoint = calculateIntersection(outerLine, line1) // 외벽선과 보조선의 교차점
if (outerIntersectionPoint) {
intersectionPoints.current.push(outerIntersectionPoint)
}
})
if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) { if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) {
return return
} }
@ -147,6 +160,7 @@ export function useEvent() {
}) })
let innerLinePoints = [] let innerLinePoints = []
let outerLinePoints = []
canvas canvas
.getObjects() .getObjects()
.filter((obj) => obj.innerLines) .filter((obj) => obj.innerLines)
@ -157,14 +171,68 @@ export function useEvent() {
}) })
}) })
const adsorptionPoints = [ const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
outerLinePoints.push({ x: line.x2, y: line.y2 })
outerLinePoints.push({ x: line.x1, y: line.y1 })
})
const allAuxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine')
allAuxiliaryLines.forEach((aux) => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => {
//지붕과 보조선이 만나는 지점
roof.lines.forEach((line) => {
const intersectionPoint = calculateIntersection(aux, line)
if (intersectionPoint) {
intersectionPoints.current.push(intersectionPoint)
}
})
//innerLines와 보조선이 만나는 지점
roof.innerLines.forEach((line) => {
const intersectionPoint = calculateIntersection(aux, line)
if (intersectionPoint) {
intersectionPoints.current.push(intersectionPoint)
}
})
})
// outerLines와의 교점
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((outerLine) => {
const intersectionPoint = calculateIntersection(aux, outerLine)
if (intersectionPoint) {
intersectionPoints.current.push(intersectionPoint)
}
})
})
let adsorptionPoints = [
...getAdsorptionPoints(), ...getAdsorptionPoints(),
...roofAdsorptionPoints.current, ...roofAdsorptionPoints.current,
...otherAdsorptionPoints, ...otherAdsorptionPoints,
...intersectionPoints.current, ...intersectionPoints.current,
...innerLinePoints, ...innerLinePoints,
...outerLinePoints,
...allAuxiliaryLines.map((line) => {
return {
x: line.x1,
y: line.y1,
}
}),
...allAuxiliaryLines.map((line) => {
return {
x: line.x2,
y: line.y2,
}
}),
] ]
adsorptionPoints = removeDuplicatePoints(adsorptionPoints)
if (dotLineGridSetting.LINE || canvas.getObjects().filter((obj) => ['lineGrid', 'tempGrid'].includes(obj.name)).length > 1) { if (dotLineGridSetting.LINE || canvas.getObjects().filter((obj) => ['lineGrid', 'tempGrid'].includes(obj.name)).length > 1) {
const closestLine = getClosestLineGrid(pointer) const closestLine = getClosestLineGrid(pointer)
@ -354,15 +422,10 @@ export function useEvent() {
canvas.renderAll() canvas.renderAll()
} }
const defaultKeyboardEvent = (e) => {
if (e.key === 'Escape') {
console.log('defaultKeyboardEvent')
}
}
const addCanvasMouseEventListener = (eventType, handler) => { const addCanvasMouseEventListener = (eventType, handler) => {
canvas.off(eventType) canvas.off(eventType)
canvas.on(eventType, handler) canvas.on(eventType, handler)
canvas.on('mouse:move', defaultMouseMoveEvent) // default mouse:move 이벤트는 항상 등록
mouseEventListeners.current.push({ eventType, handler }) mouseEventListeners.current.push({ eventType, handler })
} }
@ -421,6 +484,17 @@ export function useEvent() {
}) })
} }
const removeDuplicatePoints = (points) => {
const map = new Map()
points.forEach((point) => {
const key = `${point.x},${point.y}`
if (!map.has(key)) {
map.set(key, point)
}
})
return Array.from(map.values())
}
return { return {
addDocumentEventListener, addDocumentEventListener,
addCanvasMouseEventListener, addCanvasMouseEventListener,