dev #216
@ -1,17 +1,18 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { wordDisplaySelector } from '@/store/settingAtom'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { checkLineOrientation, getDistance } from '@/util/canvas-util'
|
||||
import { commonUtilsState, dimensionLineSettingsState } from '@/store/commonUtilsAtom'
|
||||
import { fontSelector } from '@/store/fontAtom'
|
||||
import { canvasState, currentMenuState } from '@/store/canvasAtom'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import Distance from '@/components/floor-plan/modal/distance/Distance'
|
||||
import { usePolygon } from '@/hooks/usePolygon'
|
||||
import { useObjectBatch } from '@/hooks/object/useObjectBatch'
|
||||
import { BATCH_TYPE } from '@/common/common'
|
||||
import { useMouse } from '@/hooks/useMouse'
|
||||
|
||||
export function useCommonUtils() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
@ -25,6 +26,7 @@ export function useCommonUtils() {
|
||||
const { addPopup, closeAll, targetClose } = usePopup()
|
||||
const { drawDirectionArrow, addLengthText } = usePolygon()
|
||||
const { applyDormers } = useObjectBatch({})
|
||||
const { getIntersectMousePoint } = useMouse()
|
||||
|
||||
useEffect(() => {
|
||||
commonTextMode()
|
||||
@ -213,7 +215,7 @@ export function useCommonUtils() {
|
||||
addCanvasMouseEventListener('mouse:down', (e) => {
|
||||
let groupObjects = []
|
||||
|
||||
const pointer = canvas.getPointer(e.e)
|
||||
const pointer = getIntersectMousePoint(e)
|
||||
|
||||
let point
|
||||
|
||||
@ -654,7 +656,11 @@ export function useCommonUtils() {
|
||||
clonedObj.setCoords()
|
||||
clonedObj.fire('modified')
|
||||
clonedObj.fire('polygonMoved')
|
||||
clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial })
|
||||
clonedObj.set({
|
||||
direction: obj.direction,
|
||||
directionText: obj.directionText,
|
||||
roofMaterial: obj.roofMaterial,
|
||||
})
|
||||
|
||||
obj.lines.forEach((line, index) => {
|
||||
clonedObj.lines[index].set({ attributes: line.attributes })
|
||||
|
||||
@ -210,6 +210,14 @@ export function useEvent() {
|
||||
})
|
||||
})
|
||||
|
||||
const modulePoints = []
|
||||
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
|
||||
modules.forEach((module) => {
|
||||
module.points.forEach((point) => {
|
||||
modulePoints.push({ x: point.x, y: point.y })
|
||||
})
|
||||
})
|
||||
|
||||
let adsorptionPoints = [
|
||||
...getAdsorptionPoints(),
|
||||
...roofAdsorptionPoints.current,
|
||||
@ -229,6 +237,7 @@ export function useEvent() {
|
||||
y: line.y2,
|
||||
}
|
||||
}),
|
||||
...modulePoints,
|
||||
]
|
||||
|
||||
adsorptionPoints = removeDuplicatePoints(adsorptionPoints)
|
||||
|
||||
@ -303,13 +303,119 @@ export function removeDuplicatePolygons(polygons, hasAuxiliaryLine = false) {
|
||||
}
|
||||
})
|
||||
|
||||
if (!hasAuxiliaryLine) {
|
||||
uniquePolygons = uniquePolygons.filter((polygon) => {
|
||||
return isValidPoints(polygon)
|
||||
uniquePolygons = uniquePolygons.filter((polygon) => {
|
||||
return !checkPolygonSelfIntersection(polygon)
|
||||
})
|
||||
|
||||
// uniquePolygons = uniquePolygons.filter((polygon) => {
|
||||
// return isValidPoints(polygon)
|
||||
// })
|
||||
|
||||
console.log('uniquePolygons2', uniquePolygons)
|
||||
|
||||
return uniquePolygons
|
||||
}
|
||||
|
||||
/**
|
||||
* 두 선분이 교차하는지 확인하는 함수
|
||||
* @param {Object} p1 첫 번째 선분의 시작점 {x, y}
|
||||
* @param {Object} q1 첫 번째 선분의 끝점 {x, y}
|
||||
* @param {Object} p2 두 번째 선분의 시작점 {x, y}
|
||||
* @param {Object} q2 두 번째 선분의 끝점 {x, y}
|
||||
* @returns {boolean} 교차하면 true, 아니면 false
|
||||
*/
|
||||
function doSegmentsIntersect(p1, q1, p2, q2) {
|
||||
// CCW (Counter-Clockwise) 방향 확인 함수
|
||||
function orientation(p, q, r) {
|
||||
const val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y)
|
||||
if (val === 0) return 0 // 일직선
|
||||
return val > 0 ? 1 : 2 // 시계방향 또는 반시계방향
|
||||
}
|
||||
|
||||
// 점 q가 선분 pr 위에 있는지 확인
|
||||
function onSegment(p, q, r) {
|
||||
return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y)
|
||||
}
|
||||
|
||||
// 같은 끝점을 공유하는 경우는 교차로 보지 않음
|
||||
if ((p1.x === p2.x && p1.y === p2.y) || (p1.x === q2.x && p1.y === q2.y) || (q1.x === p2.x && q1.y === p2.y) || (q1.x === q2.x && q1.y === q2.y)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const o1 = orientation(p1, q1, p2)
|
||||
const o2 = orientation(p1, q1, q2)
|
||||
const o3 = orientation(p2, q2, p1)
|
||||
const o4 = orientation(p2, q2, q1)
|
||||
|
||||
// 일반적인 교차 경우
|
||||
if (o1 !== o2 && o3 !== o4) return true
|
||||
|
||||
// 특별한 경우들 (한 점이 다른 선분 위에 있는 경우)
|
||||
if (o1 === 0 && onSegment(p1, p2, q1)) return true
|
||||
if (o2 === 0 && onSegment(p1, q2, q1)) return true
|
||||
if (o3 === 0 && onSegment(p2, p1, q2)) return true
|
||||
if (o4 === 0 && onSegment(p2, q1, q2)) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 다각형의 자기 교차를 검사하는 메인 함수
|
||||
* @param {Array} coordinates 다각형의 좌표 배열 [{x, y}, ...]
|
||||
* @returns {Object} 검사 결과 {hasSelfIntersection: boolean, intersections: Array}
|
||||
*/
|
||||
function checkPolygonSelfIntersection(coordinates) {
|
||||
if (coordinates.length < 3) {
|
||||
return {
|
||||
hasSelfIntersection: false,
|
||||
intersections: [],
|
||||
error: '다각형은 최소 3개의 점이 필요합니다.',
|
||||
}
|
||||
}
|
||||
|
||||
const intersections = []
|
||||
const edges = []
|
||||
|
||||
// 모든 변(edge) 생성
|
||||
for (let i = 0; i < coordinates.length; i++) {
|
||||
const start = coordinates[i]
|
||||
const end = coordinates[(i + 1) % coordinates.length]
|
||||
edges.push({
|
||||
start: start,
|
||||
end: end,
|
||||
index: i,
|
||||
})
|
||||
}
|
||||
|
||||
return uniquePolygons
|
||||
// 모든 변 쌍에 대해 교차 검사
|
||||
for (let i = 0; i < edges.length; i++) {
|
||||
for (let j = i + 1; j < edges.length; j++) {
|
||||
// 인접한 변들은 제외 (끝점을 공유하므로)
|
||||
if (Math.abs(i - j) === 1 || (i === 0 && j === edges.length - 1)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const edge1 = edges[i]
|
||||
const edge2 = edges[j]
|
||||
|
||||
if (doSegmentsIntersect(edge1.start, edge1.end, edge2.start, edge2.end)) {
|
||||
intersections.push({
|
||||
edge1Index: i,
|
||||
edge2Index: j,
|
||||
edge1: {
|
||||
from: edge1.start,
|
||||
to: edge1.end,
|
||||
},
|
||||
edge2: {
|
||||
from: edge2.start,
|
||||
to: edge2.end,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intersections.length > 0
|
||||
}
|
||||
|
||||
// 같은 직선상에 있는지 확인 같은 직선이라면 polygon을 생성할 수 없으므로 false
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user