Merge branch 'feature/jaeyoung' of https://git.hanasys.jp/qcast3/qcast-front into feature/jaeyoung
This commit is contained in:
commit
f0c2f0bad2
@ -12,7 +12,7 @@ import { usePlan } from '@/hooks/usePlan'
|
|||||||
import { useContextMenu } from '@/hooks/useContextMenu'
|
import { useContextMenu } from '@/hooks/useContextMenu'
|
||||||
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
|
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
|
||||||
import { currentMenuState } from '@/store/canvasAtom'
|
import { currentMenuState } from '@/store/canvasAtom'
|
||||||
import { totalDisplaySelector } from '@/store/settingAtom'
|
import { roofMaterialsAtom, totalDisplaySelector } from '@/store/settingAtom'
|
||||||
import { MENU, POLYGON_TYPE } from '@/common/common'
|
import { MENU, POLYGON_TYPE } from '@/common/common'
|
||||||
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
|
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
|
||||||
import { QcastContext } from '@/app/QcastProvider'
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
@ -30,8 +30,35 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
|||||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||||
import { useEvent } from '@/hooks/useEvent'
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
import { compasDegAtom } from '@/store/orientationAtom'
|
import { compasDegAtom } from '@/store/orientationAtom'
|
||||||
|
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
|
||||||
|
import { useMasterController } from '@/hooks/common/useMasterController'
|
||||||
|
|
||||||
export default function CanvasFrame() {
|
export default function CanvasFrame() {
|
||||||
|
const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom)
|
||||||
|
const { getRoofMaterialList } = useMasterController()
|
||||||
|
useEffect(async () => {
|
||||||
|
if (roofMaterials.length !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { data } = await getRoofMaterialList()
|
||||||
|
|
||||||
|
const roofLists = data.map((item, idx) => ({
|
||||||
|
...item,
|
||||||
|
id: item.roofMatlCd,
|
||||||
|
name: item.roofMatlNm,
|
||||||
|
selected: idx === 0,
|
||||||
|
index: idx,
|
||||||
|
nameJp: item.roofMatlNmJp,
|
||||||
|
length: item.lenBase && parseInt(item.lenBase),
|
||||||
|
width: item.widBase && parseInt(item.widBase),
|
||||||
|
raft: item.raftBase && parseInt(item.raftBase),
|
||||||
|
layout: ['ROOF_ID_SLATE', 'ROOF_ID_SINGLE'].includes(item.roofMatlCd) ? ROOF_MATERIAL_LAYOUT.STAIRS : ROOF_MATERIAL_LAYOUT.PARALLEL,
|
||||||
|
hajebichi: item.roofPchBase && parseInt(item.roofPchBase),
|
||||||
|
pitch: item.pitch ? parseInt(item.pitch) : 4,
|
||||||
|
angle: item.angle ? parseInt(item.angle) : 21.8,
|
||||||
|
}))
|
||||||
|
setRoofMaterials(roofLists)
|
||||||
|
}, [])
|
||||||
const canvasRef = useRef(null)
|
const canvasRef = useRef(null)
|
||||||
const { canvas } = useCanvas('canvas')
|
const { canvas } = useCanvas('canvas')
|
||||||
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
||||||
|
|||||||
@ -23,102 +23,65 @@ export function useRoofFn() {
|
|||||||
|
|
||||||
//면형상 선택 클릭시 지붕 패턴 입히기
|
//면형상 선택 클릭시 지붕 패턴 입히기
|
||||||
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial, isForceChange = false, isDisplay = false) {
|
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial, isForceChange = false, isDisplay = false) {
|
||||||
if (!polygon) {
|
try {
|
||||||
return
|
if (!polygon) {
|
||||||
}
|
return
|
||||||
if (polygon.points.length < 3) {
|
}
|
||||||
return
|
if (polygon.points.length < 3) {
|
||||||
}
|
return
|
||||||
if (isForceChange && !isDisplay) {
|
}
|
||||||
/*if (polygon.roofMaterial) {
|
if (isForceChange && !isDisplay) {
|
||||||
|
/*if (polygon.roofMaterial) {
|
||||||
polygon.roofMaterial = null
|
polygon.roofMaterial = null
|
||||||
}*/
|
}*/
|
||||||
}
|
|
||||||
if (!roofMaterial) {
|
|
||||||
roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial
|
|
||||||
}
|
|
||||||
|
|
||||||
const ratio = window.devicePixelRatio || 1
|
|
||||||
const layout = roofMaterial.layout
|
|
||||||
|
|
||||||
let width = (roofMaterial.width || 226) / 10
|
|
||||||
let height = (roofMaterial.length || 158) / 10
|
|
||||||
const index = roofMaterial.index ?? 0
|
|
||||||
let roofStyle = 2
|
|
||||||
const inputPatternSize = { width: width, height: height } //임시 사이즈
|
|
||||||
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
|
||||||
|
|
||||||
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
|
||||||
//세로형이면 width height를 바꿈
|
|
||||||
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 패턴 소스를 위한 임시 캔버스 생성
|
|
||||||
const patternSourceCanvas = document.createElement('canvas')
|
|
||||||
patternSourceCanvas.width = polygon.width * ratio
|
|
||||||
patternSourceCanvas.height = polygon.height * ratio
|
|
||||||
const ctx = patternSourceCanvas.getContext('2d')
|
|
||||||
let offset = roofStyle === 1 ? 0 : patternSize.width / 2
|
|
||||||
|
|
||||||
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
|
|
||||||
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
|
|
||||||
|
|
||||||
ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index]
|
|
||||||
ctx.lineWidth = 2
|
|
||||||
ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white'
|
|
||||||
|
|
||||||
if (trestleMode) {
|
|
||||||
ctx.strokeStyle = 'black'
|
|
||||||
ctx.lineWidth = 0.2
|
|
||||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
|
|
||||||
} else {
|
|
||||||
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
|
||||||
offset = roofStyle === 1 ? 0 : patternSize.height / 2
|
|
||||||
for (let col = 0; col <= cols; col++) {
|
|
||||||
const x = col * patternSize.width
|
|
||||||
const yStart = 0
|
|
||||||
const yEnd = patternSourceCanvas.height
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(x, yStart) // 선 시작점
|
|
||||||
ctx.lineTo(x, yEnd) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
if (mode === 'allPainted' || trestleMode) {
|
|
||||||
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let row = 0; row <= rows; row++) {
|
|
||||||
const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height
|
|
||||||
const xStart = col * patternSize.width
|
|
||||||
const xEnd = xStart + patternSize.width
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(xStart, y) // 선 시작점
|
|
||||||
ctx.lineTo(xEnd, y) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
if (mode === 'allPainted' || trestleMode) {
|
|
||||||
ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
if (!roofMaterial) {
|
||||||
for (let row = 0; row <= rows; row++) {
|
roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial
|
||||||
const y = row * patternSize.height
|
}
|
||||||
|
|
||||||
ctx.beginPath()
|
const ratio = window.devicePixelRatio || 1
|
||||||
ctx.moveTo(0, y) // 선 시작점
|
const layout = roofMaterial.layout
|
||||||
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
if (mode === 'allPainted' || trestleMode) {
|
|
||||||
ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let width = (roofMaterial.width || 226) / 10
|
||||||
|
let height = (roofMaterial.length || 158) / 10
|
||||||
|
const index = roofMaterial.index ?? 0
|
||||||
|
let roofStyle = 2
|
||||||
|
const inputPatternSize = { width: width, height: height } //임시 사이즈
|
||||||
|
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
||||||
|
|
||||||
|
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
||||||
|
//세로형이면 width height를 바꿈
|
||||||
|
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 소스를 위한 임시 캔버스 생성
|
||||||
|
const patternSourceCanvas = document.createElement('canvas')
|
||||||
|
patternSourceCanvas.width = polygon.width * ratio
|
||||||
|
patternSourceCanvas.height = polygon.height * ratio
|
||||||
|
const ctx = patternSourceCanvas.getContext('2d')
|
||||||
|
let offset = roofStyle === 1 ? 0 : patternSize.width / 2
|
||||||
|
|
||||||
|
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
|
||||||
|
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
|
||||||
|
|
||||||
|
ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index]
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white'
|
||||||
|
|
||||||
|
if (trestleMode) {
|
||||||
|
ctx.strokeStyle = 'black'
|
||||||
|
ctx.lineWidth = 0.2
|
||||||
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
|
||||||
|
} else {
|
||||||
|
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
||||||
|
offset = roofStyle === 1 ? 0 : patternSize.height / 2
|
||||||
for (let col = 0; col <= cols; col++) {
|
for (let col = 0; col <= cols; col++) {
|
||||||
const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width
|
const x = col * patternSize.width
|
||||||
const yStart = row * patternSize.height
|
const yStart = 0
|
||||||
const yEnd = yStart + patternSize.height
|
const yEnd = patternSourceCanvas.height
|
||||||
|
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(x, yStart) // 선 시작점
|
ctx.moveTo(x, yStart) // 선 시작점
|
||||||
ctx.lineTo(x, yEnd) // 선 끝점
|
ctx.lineTo(x, yEnd) // 선 끝점
|
||||||
@ -126,49 +89,90 @@ export function useRoofFn() {
|
|||||||
if (mode === 'allPainted' || trestleMode) {
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let row = 0; row <= rows; row++) {
|
||||||
|
const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height
|
||||||
|
const xStart = col * patternSize.width
|
||||||
|
const xEnd = xStart + patternSize.width
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(xStart, y) // 선 시작점
|
||||||
|
ctx.lineTo(xEnd, y) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
|
ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let row = 0; row <= rows; row++) {
|
||||||
|
const y = row * patternSize.height
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(0, y) // 선 시작점
|
||||||
|
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
|
ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let col = 0; col <= cols; col++) {
|
||||||
|
const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width
|
||||||
|
const yStart = row * patternSize.height
|
||||||
|
const yEnd = yStart + patternSize.height
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(x, yStart) // 선 시작점
|
||||||
|
ctx.lineTo(x, yEnd) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
|
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const hachingPatternSourceCanvas = document.createElement('canvas')
|
const hachingPatternSourceCanvas = document.createElement('canvas')
|
||||||
|
|
||||||
if (mode === 'lineHatch') {
|
if (mode === 'lineHatch') {
|
||||||
hachingPatternSourceCanvas.width = polygon.width * ratio
|
hachingPatternSourceCanvas.width = polygon.width * ratio
|
||||||
hachingPatternSourceCanvas.height = polygon.height * ratio
|
hachingPatternSourceCanvas.height = polygon.height * ratio
|
||||||
|
|
||||||
const ctx1 = hachingPatternSourceCanvas.getContext('2d')
|
const ctx1 = hachingPatternSourceCanvas.getContext('2d')
|
||||||
|
|
||||||
const gap = 10
|
const gap = 10
|
||||||
|
|
||||||
ctx1.strokeStyle = 'green' // 선 색상
|
ctx1.strokeStyle = 'green' // 선 색상
|
||||||
ctx1.lineWidth = 0.3 // 선 두께
|
ctx1.lineWidth = 0.3 // 선 두께
|
||||||
|
|
||||||
for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) {
|
for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) {
|
||||||
ctx1.beginPath()
|
ctx1.beginPath()
|
||||||
ctx1.moveTo(x, 0) // 선 시작점
|
ctx1.moveTo(x, 0) // 선 시작점
|
||||||
ctx1.lineTo(0, x) // 선 끝점
|
ctx1.lineTo(0, x) // 선 끝점
|
||||||
ctx1.stroke()
|
ctx1.stroke()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const combinedPatternCanvas = document.createElement('canvas')
|
||||||
|
combinedPatternCanvas.width = polygon.width * ratio
|
||||||
|
combinedPatternCanvas.height = polygon.height * ratio
|
||||||
|
const combinedCtx = combinedPatternCanvas.getContext('2d')
|
||||||
|
// 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘
|
||||||
|
combinedCtx.drawImage(patternSourceCanvas, 0, 0)
|
||||||
|
combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0)
|
||||||
|
|
||||||
|
// 패턴 생성
|
||||||
|
const pattern = new fabric.Pattern({
|
||||||
|
source: combinedPatternCanvas,
|
||||||
|
repeat: 'repeat',
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.set('fill', null)
|
||||||
|
polygon.set('fill', pattern)
|
||||||
|
polygon.roofMaterial = roofMaterial
|
||||||
|
polygon.canvas?.renderAll()
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
const combinedPatternCanvas = document.createElement('canvas')
|
|
||||||
combinedPatternCanvas.width = polygon.width * ratio
|
|
||||||
combinedPatternCanvas.height = polygon.height * ratio
|
|
||||||
const combinedCtx = combinedPatternCanvas.getContext('2d')
|
|
||||||
// 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘
|
|
||||||
combinedCtx.drawImage(patternSourceCanvas, 0, 0)
|
|
||||||
combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0)
|
|
||||||
|
|
||||||
// 패턴 생성
|
|
||||||
const pattern = new fabric.Pattern({
|
|
||||||
source: combinedPatternCanvas,
|
|
||||||
repeat: 'repeat',
|
|
||||||
})
|
|
||||||
|
|
||||||
polygon.set('fill', null)
|
|
||||||
polygon.set('fill', pattern)
|
|
||||||
polygon.roofMaterial = roofMaterial
|
|
||||||
polygon.canvas?.renderAll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeRoofMaterial(roof = currentObject) {
|
function removeRoofMaterial(roof = currentObject) {
|
||||||
|
|||||||
@ -148,7 +148,7 @@ export function useCanvasSetting(executeEffect = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 초 1회만 실행하도록 처리 */
|
/** 초 1회만 실행하도록 처리 */
|
||||||
addRoofMaterials()
|
//addRoofMaterials()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -849,8 +849,14 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
if (
|
if (
|
||||||
lineHistory.current.some(
|
lineHistory.current.some(
|
||||||
(history) =>
|
(history) =>
|
||||||
JSON.stringify(history.startPoint) === JSON.stringify(line.startPoint) &&
|
(Math.abs(history.startPoint.x - line.startPoint.x) < 2 &&
|
||||||
JSON.stringify(history.endPoint) === JSON.stringify(line.endPoint),
|
Math.abs(history.startPoint.y - line.startPoint.y) < 2 &&
|
||||||
|
Math.abs(history.endPoint.x - line.endPoint.x) < 2 &&
|
||||||
|
Math.abs(history.endPoint.y - line.endPoint.y) < 2) ||
|
||||||
|
(Math.abs(history.startPoint.x - line.endPoint.x) < 2 &&
|
||||||
|
Math.abs(history.startPoint.y - line.endPoint.y) < 2 &&
|
||||||
|
Math.abs(history.endPoint.x - line.startPoint.x) < 2 &&
|
||||||
|
Math.abs(history.endPoint.y - line.startPoint.y) < 2),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
canvas.remove(line)
|
canvas.remove(line)
|
||||||
|
|||||||
@ -412,7 +412,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** 외곽선 삭제 */
|
/** 외곽선 삭제 */
|
||||||
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine')
|
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine' || obj.name === 'pitchText')
|
||||||
removeTargets.forEach((obj) => {
|
removeTargets.forEach((obj) => {
|
||||||
canvas.remove(obj)
|
canvas.remove(obj)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -38,12 +38,12 @@ export const useLine = () => {
|
|||||||
line.set({
|
line.set({
|
||||||
visible: false,
|
visible: false,
|
||||||
})
|
})
|
||||||
canvas
|
const obj = canvas?.getObjects().find((obj) => obj.parentId === line.id)
|
||||||
?.getObjects()
|
if (obj) {
|
||||||
.find((obj) => obj.parentId === line.id)
|
obj.set({
|
||||||
.set({
|
|
||||||
visible: false,
|
visible: false,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom'
|
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom'
|
||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, isPointOnLine, toFixedWithoutRounding } from '@/util/canvas-util'
|
import {
|
||||||
|
distanceBetweenPoints,
|
||||||
|
findAndRemoveClosestPoint,
|
||||||
|
getDegreeByChon,
|
||||||
|
getDegreeInOrientation,
|
||||||
|
isPointOnLine,
|
||||||
|
toFixedWithoutRounding,
|
||||||
|
} from '@/util/canvas-util'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
||||||
import { flowDisplaySelector } from '@/store/settingAtom'
|
import { flowDisplaySelector } from '@/store/settingAtom'
|
||||||
@ -755,7 +762,7 @@ export const usePolygon = () => {
|
|||||||
|
|
||||||
const splitPolygonWithLines = (polygon) => {
|
const splitPolygonWithLines = (polygon) => {
|
||||||
polygon.set({ visible: false })
|
polygon.set({ visible: false })
|
||||||
let innerLines = [...polygon.innerLines]
|
let innerLines = [...polygon.innerLines].filter((line) => line.visible)
|
||||||
|
|
||||||
/*// innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
|
/*// innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
|
||||||
if (!innerLines || innerLines.length === 0) {
|
if (!innerLines || innerLines.length === 0) {
|
||||||
@ -822,11 +829,11 @@ export const usePolygon = () => {
|
|||||||
line.endPoint = endPoint
|
line.endPoint = endPoint
|
||||||
})
|
})
|
||||||
|
|
||||||
polygonLines.forEach((line) => {
|
/*polygonLines.forEach((line) => {
|
||||||
line.set({ strokeWidth: 10 })
|
line.set({ strokeWidth: 10 })
|
||||||
canvas.add(line)
|
canvas.add(line)
|
||||||
})
|
})
|
||||||
canvas.renderAll()
|
canvas.renderAll()*/
|
||||||
|
|
||||||
polygonLines.forEach((line) => {
|
polygonLines.forEach((line) => {
|
||||||
/*const originStroke = line.stroke
|
/*const originStroke = line.stroke
|
||||||
@ -838,12 +845,14 @@ export const usePolygon = () => {
|
|||||||
innerLine.set({ stroke: 'red' })
|
innerLine.set({ stroke: 'red' })
|
||||||
canvas.renderAll()*/
|
canvas.renderAll()*/
|
||||||
if (isPointOnLine(line, innerLine.startPoint)) {
|
if (isPointOnLine(line, innerLine.startPoint)) {
|
||||||
|
canvas.renderAll()
|
||||||
if (isSamePoint(line.startPoint, innerLine.startPoint) || isSamePoint(line.endPoint, innerLine.startPoint)) {
|
if (isSamePoint(line.startPoint, innerLine.startPoint) || isSamePoint(line.endPoint, innerLine.startPoint)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
intersections.push(innerLine.startPoint)
|
intersections.push(innerLine.startPoint)
|
||||||
}
|
}
|
||||||
if (isPointOnLine(line, innerLine.endPoint)) {
|
if (isPointOnLine(line, innerLine.endPoint)) {
|
||||||
|
canvas.renderAll()
|
||||||
if (isSamePoint(line.startPoint, innerLine.endPoint) || isSamePoint(line.endPoint, innerLine.endPoint)) {
|
if (isSamePoint(line.startPoint, innerLine.endPoint) || isSamePoint(line.endPoint, innerLine.endPoint)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -858,61 +867,66 @@ export const usePolygon = () => {
|
|||||||
canvas.renderAll()*/
|
canvas.renderAll()*/
|
||||||
})
|
})
|
||||||
|
|
||||||
const divideLines = polygonLines.filter((line) => line.intersections.length > 0)
|
const divideLines = polygonLines.filter((line) => line.intersections?.length > 0)
|
||||||
let newLines = []
|
let newLines = []
|
||||||
|
polygonLines = polygonLines.filter((line) => !line.intersections || line.intersections.length === 0)
|
||||||
divideLines.forEach((line) => {
|
for (let i = divideLines.length - 1; i >= 0; i--) {
|
||||||
|
const line = divideLines[i]
|
||||||
const { intersections, startPoint, endPoint } = line
|
const { intersections, startPoint, endPoint } = line
|
||||||
|
|
||||||
if (intersections.length === 1) {
|
if (intersections.length === 1) {
|
||||||
// 한 점만 교차하는 경우
|
|
||||||
const newLinePoint1 = [line.x1, line.y1, intersections[0].x, intersections[0].y]
|
const newLinePoint1 = [line.x1, line.y1, intersections[0].x, intersections[0].y]
|
||||||
const newLinePoint2 = [intersections[0].x, intersections[0].y, line.x2, line.y2]
|
const newLinePoint2 = [intersections[0].x, intersections[0].y, line.x2, line.y2]
|
||||||
|
|
||||||
const newLine1 = new QLine(newLinePoint1, {
|
const newLine1 = new QLine(newLinePoint1, {
|
||||||
stroke: 'blue',
|
stroke: 'blue',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
const newLine2 = new QLine(newLinePoint2, {
|
const newLine2 = new QLine(newLinePoint2, {
|
||||||
stroke: 'blue',
|
stroke: 'blue',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
|
|
||||||
newLine1.attributes = {
|
newLine1.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine1.x1 - newLine1.x2, 2) + Math.pow(newLine1.y1 - newLine1.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine1.x1 - newLine1.x2, newLine1.y1 - newLine1.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine1.x1 - newLine1.x2, 2) + Math.pow(newLine1.y1 - newLine1.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine1.x1 - newLine1.x2, newLine1.y1 - newLine1.y2)) * 10,
|
||||||
}
|
}
|
||||||
newLine2.attributes = {
|
newLine2.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine2.x1 - newLine2.x2, 2) + Math.pow(newLine2.y1 - newLine2.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine2.x1 - newLine2.x2, newLine2.y1 - newLine2.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine2.x1 - newLine2.x2, 2) + Math.pow(newLine2.y1 - newLine2.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine2.x1 - newLine2.x2, newLine2.y1 - newLine2.y2)) * 10,
|
||||||
}
|
}
|
||||||
newLines.push(newLine1)
|
|
||||||
newLines.push(newLine2)
|
|
||||||
} else {
|
|
||||||
// 두 점 이상 교차하는 경우
|
|
||||||
//1. intersections중에 startPoint와 가장 가까운 점을 찾는다.
|
|
||||||
//2. 가장 가까운 점을 기준으로 line을 나눈다.
|
|
||||||
|
|
||||||
|
newLines.push(newLine1, newLine2)
|
||||||
|
divideLines.splice(i, 1) // 기존 line 제거
|
||||||
|
} else {
|
||||||
let currentPoint = startPoint
|
let currentPoint = startPoint
|
||||||
|
|
||||||
while (intersections.length !== 0) {
|
while (intersections.length !== 0) {
|
||||||
const minDistancePoint = findAndRemoveClosestPoint(currentPoint, intersections)
|
const minDistancePoint = findAndRemoveClosestPoint(currentPoint, intersections)
|
||||||
const newLinePoint = [currentPoint.x, currentPoint.y, minDistancePoint.x, minDistancePoint.y]
|
const newLinePoint = [currentPoint.x, currentPoint.y, minDistancePoint.x, minDistancePoint.y]
|
||||||
|
|
||||||
const newLine = new QLine(newLinePoint, {
|
const newLine = new QLine(newLinePoint, {
|
||||||
stroke: 'blue',
|
stroke: 'blue',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
|
|
||||||
newLine.attributes = {
|
newLine.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
newLines.push(newLine)
|
newLines.push(newLine)
|
||||||
currentPoint = minDistancePoint
|
currentPoint = minDistancePoint
|
||||||
}
|
}
|
||||||
@ -923,18 +937,21 @@ export const usePolygon = () => {
|
|||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
newLine.attributes = {
|
newLine.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
newLines.push(newLine)
|
newLines.push(newLine)
|
||||||
|
divideLines.splice(i, 1) // 기존 line 제거
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
//polygonLines에서 divideLines를 제거하고 newLines를 추가한다.
|
//polygonLines에서 divideLines를 제거하고 newLines를 추가한다.
|
||||||
polygonLines = polygonLines.filter((line) => line.intersections?.length === 0)
|
newLines = newLines.filter((line) => !(Math.abs(line.startPoint.x - line.endPoint.x) < 1 && Math.abs(line.startPoint.y - line.endPoint.y) < 1))
|
||||||
|
|
||||||
polygonLines = [...polygonLines, ...newLines]
|
polygonLines = [...polygonLines, ...newLines]
|
||||||
|
|
||||||
@ -1004,6 +1021,13 @@ export const usePolygon = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*innerLines.forEach((line) => {
|
||||||
|
const startPoint = line.startPoint
|
||||||
|
const endPoint = line.endPoint
|
||||||
|
/!*canvas.add(new fabric.Circle({ left: startPoint.x, top: startPoint.y + 10, radius: 5, fill: 'red' }))
|
||||||
|
canvas.add(new fabric.Circle({ left: endPoint.x, top: endPoint.y - 10, radius: 5, fill: 'blue' }))*!/
|
||||||
|
})*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 왼쪽 상단을 startPoint로 전부 변경
|
* 왼쪽 상단을 startPoint로 전부 변경
|
||||||
*/
|
*/
|
||||||
@ -1030,23 +1054,18 @@ export const usePolygon = () => {
|
|||||||
line.endPoint = endPoint
|
line.endPoint = endPoint
|
||||||
})
|
})
|
||||||
|
|
||||||
// polygonLines에서 시작점 혹은 끝점이 innerLines와 연결된 line만 가져온다.
|
//allLines에서 중복을 제거한다.
|
||||||
let startLines = polygonLines.filter((line) => {
|
allLines = allLines.filter((line, index, self) => {
|
||||||
const startPoint = line.startPoint
|
return (
|
||||||
const endPoint = line.endPoint
|
index ===
|
||||||
|
self.findIndex((l) => {
|
||||||
return innerLines.some((innerLine) => {
|
return isSamePoint(l.startPoint, line.startPoint) && isSamePoint(l.endPoint, line.endPoint)
|
||||||
return (
|
})
|
||||||
isSamePoint(innerLine.startPoint, startPoint) ||
|
)
|
||||||
isSamePoint(innerLine.endPoint, startPoint) ||
|
|
||||||
isSamePoint(innerLine.startPoint, endPoint) ||
|
|
||||||
isSamePoint(innerLine.endPoint, endPoint)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 나눠서 중복 제거된 roof return
|
// 나눠서 중복 제거된 roof return
|
||||||
const newRoofs = getSplitRoofsPoints(startLines, allLines, innerLines, uniquePoints)
|
const newRoofs = getSplitRoofsPoints(allLines)
|
||||||
|
|
||||||
newRoofs.forEach((roofPoint, index) => {
|
newRoofs.forEach((roofPoint, index) => {
|
||||||
let defense, pitch
|
let defense, pitch
|
||||||
@ -1105,7 +1124,7 @@ export const usePolygon = () => {
|
|||||||
defense = 'north'
|
defense = 'north'
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
pitch = polygon.lines[index].attributes?.pitch ?? 0
|
pitch = polygon.lines[index]?.attributes?.pitch ?? 0
|
||||||
|
|
||||||
const roof = new QPolygon(roofPoint, {
|
const roof = new QPolygon(roofPoint, {
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
@ -1147,32 +1166,48 @@ export const usePolygon = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSplitRoofsPoints = (startLines, allLines, innerLines, uniquePoints) => {
|
const getSplitRoofsPoints = (allLines) => {
|
||||||
|
// ==== Utility functions ====
|
||||||
|
|
||||||
|
function isSamePoint(p1, p2, epsilon = 1) {
|
||||||
|
return Math.abs(p1.x - p2.x) <= 2 && Math.abs(p1.y - p2.y) <= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePoint(p, epsilon = 1) {
|
||||||
|
return {
|
||||||
|
x: Math.round(p.x / epsilon) * epsilon,
|
||||||
|
y: Math.round(p.y / epsilon) * epsilon,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pointToKey(p, epsilon = 1) {
|
||||||
|
const norm = normalizePoint(p, epsilon)
|
||||||
|
return `${norm.x},${norm.y}`
|
||||||
|
}
|
||||||
|
|
||||||
// 거리 계산
|
// 거리 계산
|
||||||
function calcDistance(p1, p2) {
|
function calcDistance(p1, p2) {
|
||||||
return Math.hypot(p2.x - p1.x, p2.y - p1.y)
|
return Math.hypot(p2.x - p1.x, p2.y - p1.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 바로 연결 체크
|
// ==== Direct edge check ====
|
||||||
function isDirectlyConnected(start, end, graph) {
|
|
||||||
const startKey = `${start.x},${start.y}`
|
|
||||||
if (!graph[startKey]) return false
|
|
||||||
return graph[startKey].some((neighbor) => neighbor.point.x === end.x && neighbor.point.y === end.y)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dijkstra 최단 경로
|
function isDirectlyConnected(start, end, graph, epsilon = 1) {
|
||||||
function findShortestPath(start, end, graph) {
|
const startKey = pointToKey(start, epsilon)
|
||||||
const startKey = `${start.x},${start.y}`
|
return (graph[startKey] || []).some((neighbor) => isSamePoint(neighbor.point, end, epsilon))
|
||||||
const endKey = `${end.x},${end.y}`
|
}
|
||||||
|
// ==== Dijkstra pathfinding ====
|
||||||
|
|
||||||
|
function findShortestPath(start, end, graph, epsilon = 1) {
|
||||||
|
const startKey = pointToKey(start, epsilon)
|
||||||
|
const endKey = pointToKey(end, epsilon)
|
||||||
|
|
||||||
const distances = {}
|
const distances = {}
|
||||||
const previous = {}
|
const previous = {}
|
||||||
const visited = new Set()
|
const visited = new Set()
|
||||||
const queue = [{ key: startKey, dist: 0 }]
|
const queue = [{ key: startKey, dist: 0 }]
|
||||||
|
|
||||||
for (const key in graph) {
|
for (const key in graph) distances[key] = Infinity
|
||||||
distances[key] = Infinity
|
|
||||||
}
|
|
||||||
distances[startKey] = 0
|
distances[startKey] = 0
|
||||||
|
|
||||||
while (queue.length > 0) {
|
while (queue.length > 0) {
|
||||||
@ -1181,8 +1216,8 @@ export const usePolygon = () => {
|
|||||||
if (visited.has(key)) continue
|
if (visited.has(key)) continue
|
||||||
visited.add(key)
|
visited.add(key)
|
||||||
|
|
||||||
for (const neighbor of graph[key]) {
|
for (const neighbor of graph[key] || []) {
|
||||||
const neighborKey = `${neighbor.point.x},${neighbor.point.y}`
|
const neighborKey = pointToKey(neighbor.point, epsilon)
|
||||||
const alt = distances[key] + neighbor.distance
|
const alt = distances[key] + neighbor.distance
|
||||||
if (alt < distances[neighborKey]) {
|
if (alt < distances[neighborKey]) {
|
||||||
distances[neighborKey] = alt
|
distances[neighborKey] = alt
|
||||||
@ -1192,40 +1227,42 @@ export const usePolygon = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 경로 복구
|
|
||||||
const path = []
|
const path = []
|
||||||
let currentKey = endKey
|
let currentKey = endKey
|
||||||
|
|
||||||
if (!previous[currentKey]) {
|
if (!previous[currentKey]) return null
|
||||||
return null // 경로 없음
|
|
||||||
}
|
|
||||||
|
|
||||||
while (currentKey !== startKey) {
|
while (currentKey !== startKey) {
|
||||||
const [x, y] = currentKey.split(',').map(Number)
|
const [x, y] = currentKey.split(',').map(Number)
|
||||||
path.unshift({ x, y })
|
path.unshift({ x, y })
|
||||||
currentKey = previous[currentKey]
|
currentKey = previous[currentKey]
|
||||||
}
|
}
|
||||||
path.unshift(start)
|
|
||||||
|
const [sx, sy] = startKey.split(',').map(Number)
|
||||||
|
path.unshift({ x: sx, y: sy })
|
||||||
|
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// 최종 함수
|
// 최종 함수
|
||||||
function getPath(start, end, graph) {
|
function getPath(start, end, graph, epsilon = 1) {
|
||||||
if (isDirectlyConnected(start, end, graph)) {
|
if (isDirectlyConnected(start, end, graph, epsilon)) {
|
||||||
return null
|
console.log('직선 연결 있음. 무시.')
|
||||||
} else {
|
return []
|
||||||
const path = findShortestPath(start, end, graph)
|
|
||||||
if (!path || path.length < 3) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const path = findShortestPath(start, end, graph, epsilon)
|
||||||
|
if (!path || path.length < 3) {
|
||||||
|
console.log('경로 존재하나 3개 미만 좌표. 무시.')
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
const roofs = []
|
const roofs = []
|
||||||
|
|
||||||
startLines.forEach((line) => {
|
allLines.forEach((line) => {
|
||||||
// 그래프 생성
|
// 그래프 생성
|
||||||
const graph = {}
|
const graph = {}
|
||||||
const edges = allLines
|
const edges = allLines
|
||||||
@ -1235,8 +1272,8 @@ export const usePolygon = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
for (const [p1, p2] of edges) {
|
for (const [p1, p2] of edges) {
|
||||||
const key1 = `${p1.x},${p1.y}`
|
const key1 = pointToKey(p1)
|
||||||
const key2 = `${p2.x},${p2.y}`
|
const key2 = pointToKey(p2)
|
||||||
const distance = calcDistance(p1, p2)
|
const distance = calcDistance(p1, p2)
|
||||||
|
|
||||||
if (!graph[key1]) graph[key1] = []
|
if (!graph[key1]) graph[key1] = []
|
||||||
|
|||||||
@ -515,24 +515,29 @@ export const sortedPointLessEightPoint = (points) => {
|
|||||||
* @param line
|
* @param line
|
||||||
* @param point
|
* @param point
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
|
* @param epsilon
|
||||||
*/
|
*/
|
||||||
// 직선의 방정식.
|
// 직선의 방정식.
|
||||||
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
|
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
|
||||||
export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }) {
|
export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }, epsilon = 2) {
|
||||||
/*const a = line.y2 - line.y1
|
/*const a = y2 - y1
|
||||||
|
const b = x1 - x2
|
||||||
|
const c = x2 * y1 - x1 * y2
|
||||||
|
return Math.abs(a * x + b * y + c) < 1000*/
|
||||||
|
/*/!*const a = line.y2 - line.y1
|
||||||
const b = line.x1 - line.x2
|
const b = line.x1 - line.x2
|
||||||
const c = line.x2 * line.y1 - line.x1 * line.y2
|
const c = line.x2 * line.y1 - line.x1 * line.y2
|
||||||
const result = Math.abs(a * point.x + b * point.y + c) / 100
|
const result = Math.abs(a * point.x + b * point.y + c) / 100
|
||||||
|
|
||||||
// 점이 선 위에 있는지 확인
|
// 점이 선 위에 있는지 확인
|
||||||
return result <= 10*/
|
return result <= 10*!*/
|
||||||
// 직선 방정식 만족 여부 확인
|
// 직선 방정식 만족 여부 확인
|
||||||
const crossProduct = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
|
const crossProduct = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
|
||||||
if (Math.abs(crossProduct) > 5) return false // 작은 오차 허용
|
if (Math.abs(crossProduct) > 1000) return false // 작은 오차 허용
|
||||||
|
|
||||||
// 점이 선분의 범위 내에 있는지 확인
|
// 점이 선분의 범위 내에 있는지 확인
|
||||||
const withinXRange = Math.min(x1, x2) <= x && x <= Math.max(x1, x2)
|
const withinXRange = Math.abs(Math.min(x1, x2) - x) <= 2 || 2 <= Math.abs(Math.max(x1, x2) - x)
|
||||||
const withinYRange = Math.min(y1, y2) <= y && y <= Math.max(y1, y2)
|
const withinYRange = Math.abs(Math.min(y1, y2) - y) <= 2 || 2 <= Math.abs(Math.max(y1, y2) - y)
|
||||||
|
|
||||||
return withinXRange && withinYRange
|
return withinXRange && withinYRange
|
||||||
}
|
}
|
||||||
|
|||||||
@ -294,8 +294,9 @@ function arePolygonsEqual(polygon1, polygon2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function removeDuplicatePolygons(polygons) {
|
export function removeDuplicatePolygons(polygons) {
|
||||||
const uniquePolygons = []
|
let uniquePolygons = []
|
||||||
|
|
||||||
|
// x가 전부 같거나, y가 전부 같은 경우 제거
|
||||||
polygons.forEach((polygon) => {
|
polygons.forEach((polygon) => {
|
||||||
const isDuplicate = uniquePolygons.some((uniquePolygon) => arePolygonsEqual(polygon, uniquePolygon))
|
const isDuplicate = uniquePolygons.some((uniquePolygon) => arePolygonsEqual(polygon, uniquePolygon))
|
||||||
if (!isDuplicate) {
|
if (!isDuplicate) {
|
||||||
@ -303,9 +304,40 @@ export function removeDuplicatePolygons(polygons) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
uniquePolygons = uniquePolygons.filter((polygon) => {
|
||||||
|
return isValidPoints(polygon)
|
||||||
|
})
|
||||||
|
|
||||||
return uniquePolygons
|
return uniquePolygons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 현재 point의 x와 이전 포인트의 x와 같을경우, 다음 포인트의 x와 달라야 함.
|
||||||
|
// 현재 point의 y와 이전 포인트의 y와 같을경우, 다음 포인트의 y와 달라야 함.
|
||||||
|
const isValidPoints = (points) => {
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
let prev = points[i - 1]
|
||||||
|
let curr = points[i]
|
||||||
|
let next = points[i + 1]
|
||||||
|
|
||||||
|
if (i === points.length - 1) {
|
||||||
|
prev = points[i - 1]
|
||||||
|
curr = points[i]
|
||||||
|
next = points[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 현재와 이전의 x가 같다면 다음의 x는 달라야 함
|
||||||
|
if (Math.abs(curr.x - prev.x) < 1 && Math.abs(curr.x - next.x) < 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 현재와 이전의 y가 같다면 다음의 y는 달라야 함
|
||||||
|
if (Math.abs(curr.y - prev.y) < 1 && Math.abs(curr.y - next.y) < 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
export const isSamePoint = (a, b) => {
|
export const isSamePoint = (a, b) => {
|
||||||
if (!a || !b) {
|
if (!a || !b) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user