모듈 설치 영역 꼬임 수정
This commit is contained in:
parent
3e97eb379b
commit
fdaefd79e9
@ -17,7 +17,7 @@ import {
|
||||
import { calculateVisibleModuleHeight, getDegreeByChon, polygonToTurfPolygon, rectToPolygon, toFixedWithoutRounding } from '@/util/canvas-util'
|
||||
import '@/util/fabric-extensions' // fabric 객체들에 getCurrentPoints 메서드 추가
|
||||
import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom'
|
||||
import offsetPolygon, { calculateAngle, createLinesFromPolygon } from '@/util/qpolygon-utils'
|
||||
import offsetPolygon, { calculateAngle, createLinesFromPolygon, cleanSelfIntersectingPolygon } from '@/util/qpolygon-utils'
|
||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { BATCH_TYPE, LINE_TYPE, MODULE_SETUP_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||
@ -384,6 +384,8 @@ export function useModuleBasicSetting(tabNum) {
|
||||
} else {
|
||||
offsetPoints = createPaddingPolygon(polygon, roof.lines).vertices
|
||||
}
|
||||
// 자기교차(꼬임) 제거
|
||||
offsetPoints = cleanSelfIntersectingPolygon(offsetPoints)
|
||||
}
|
||||
|
||||
//모듈설치영역?? 생성
|
||||
|
||||
@ -5,6 +5,7 @@ import { getAdjacent, getDegreeByChon, isPointOnLine, isPointOnLineNew } from '@
|
||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||
import Big from 'big.js'
|
||||
import * as turf from '@turf/turf'
|
||||
|
||||
const TWO_PI = Math.PI * 2
|
||||
const EPSILON = 1e-10 //좌표계산 시 최소 차이값
|
||||
@ -248,6 +249,47 @@ function createPaddingPolygon(polygon, offset, arcSegments = 0) {
|
||||
return paddingPolygon
|
||||
}
|
||||
|
||||
/**
|
||||
* 자기교차(self-intersection)가 있는 폴리곤을 정리하는 함수
|
||||
* turf.js의 unkinkPolygon을 사용하여 꼬인 부분을 제거하고 가장 큰 폴리곤을 반환
|
||||
* @param {Array} vertices - [{x, y}, ...] 형태의 점 배열
|
||||
* @returns {Array} 정리된 점 배열
|
||||
*/
|
||||
export function cleanSelfIntersectingPolygon(vertices) {
|
||||
if (!vertices || vertices.length < 3) return vertices
|
||||
|
||||
try {
|
||||
// vertices를 GeoJSON 폴리곤으로 변환
|
||||
const coords = vertices.map((p) => [p.x, p.y])
|
||||
coords.push([vertices[0].x, vertices[0].y]) // ring 닫기
|
||||
|
||||
const turfPoly = turf.polygon([coords])
|
||||
|
||||
// 자기교차 검사
|
||||
const kinked = turf.kinks(turfPoly)
|
||||
|
||||
if (kinked.features.length === 0) {
|
||||
return vertices // 꼬임 없음
|
||||
}
|
||||
|
||||
// 꼬인 폴리곤을 분리
|
||||
const unkinked = turf.unkinkPolygon(turfPoly)
|
||||
|
||||
if (unkinked.features.length > 0) {
|
||||
// 가장 큰 면적의 폴리곤 선택
|
||||
const largest = unkinked.features.reduce((max, f) => (turf.area(f) > turf.area(max) ? f : max))
|
||||
|
||||
// GeoJSON 좌표를 다시 {x, y} 형태로 변환
|
||||
const cleanedCoords = largest.geometry.coordinates[0]
|
||||
return cleanedCoords.slice(0, -1).map((c) => ({ x: c[0], y: c[1] }))
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to clean self-intersecting polygon:', e)
|
||||
}
|
||||
|
||||
return vertices
|
||||
}
|
||||
|
||||
export default function offsetPolygon(vertices, offset) {
|
||||
const polygon = createPolygon(vertices)
|
||||
const arcSegments = 0
|
||||
@ -255,25 +297,29 @@ export default function offsetPolygon(vertices, offset) {
|
||||
const originPolygon = new QPolygon(vertices, { fontSize: 0 })
|
||||
originPolygon.setViewLengthText(false)
|
||||
|
||||
let result
|
||||
if (offset > 0) {
|
||||
let result = createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||
const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
|
||||
let marginResult = createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||
const allPointsOutside = marginResult.every((point) => !originPolygon.inPolygon(point))
|
||||
|
||||
if (allPointsOutside) {
|
||||
return createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||
result = createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||
} else {
|
||||
return createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||
result = createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||
}
|
||||
} else {
|
||||
let result = createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||
const allPointsInside = result.every((point) => originPolygon.inPolygon(point))
|
||||
let paddingResult = createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||
const allPointsInside = paddingResult.every((point) => originPolygon.inPolygon(point))
|
||||
|
||||
if (allPointsInside) {
|
||||
return createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||
result = createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||
} else {
|
||||
return createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||
result = createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||
}
|
||||
}
|
||||
|
||||
// 자기교차(꼬임) 제거
|
||||
return cleanSelfIntersectingPolygon(result)
|
||||
}
|
||||
|
||||
function normalizePoint(point) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user