Compare commits
No commits in common. "66d05f4f30d5e9a8b9c03bf5f42a68edefbd7fa6" and "048c30639cd4aab4824225d1d1c5067b7c75ae12" have entirely different histories.
66d05f4f30
...
048c30639c
@ -428,7 +428,7 @@ const Trestle = forwardRef((props, ref) => {
|
|||||||
const newCvrYn = constructionList[index].cvrYn
|
const newCvrYn = constructionList[index].cvrYn
|
||||||
const newCvrChecked = newCvrYn === 'Y'
|
const newCvrChecked = newCvrYn === 'Y'
|
||||||
const newSnowGdPossYn = constructionList[index].snowGdPossYn
|
const newSnowGdPossYn = constructionList[index].snowGdPossYn
|
||||||
const newSnowGdChecked = false
|
const newSnowGdChecked = newSnowGdPossYn === 'Y'
|
||||||
|
|
||||||
setCvrYn(newCvrYn)
|
setCvrYn(newCvrYn)
|
||||||
setSnowGdPossYn(newSnowGdPossYn)
|
setSnowGdPossYn(newSnowGdPossYn)
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
import { calculateVisibleModuleHeight, getDegreeByChon, polygonToTurfPolygon, rectToPolygon, toFixedWithoutRounding } from '@/util/canvas-util'
|
import { calculateVisibleModuleHeight, getDegreeByChon, polygonToTurfPolygon, rectToPolygon, toFixedWithoutRounding } from '@/util/canvas-util'
|
||||||
import '@/util/fabric-extensions' // fabric 객체들에 getCurrentPoints 메서드 추가
|
import '@/util/fabric-extensions' // fabric 객체들에 getCurrentPoints 메서드 추가
|
||||||
import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom'
|
import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom'
|
||||||
import offsetPolygon, { calculateAngle, cleanSelfIntersectingPolygon, clipOffsetToOriginal, createLinesFromPolygon } from '@/util/qpolygon-utils'
|
import offsetPolygon, { calculateAngle, cleanSelfIntersectingPolygon, createLinesFromPolygon } from '@/util/qpolygon-utils'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import { useEvent } from '@/hooks/useEvent'
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
import { BATCH_TYPE, LINE_TYPE, MODULE_SETUP_TYPE, POLYGON_TYPE } from '@/common/common'
|
import { BATCH_TYPE, LINE_TYPE, MODULE_SETUP_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||||
@ -55,7 +55,7 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
|
|
||||||
const setCurrentObject = useSetRecoilState(currentObjectState)
|
const setCurrentObject = useSetRecoilState(currentObjectState)
|
||||||
const { setModuleStatisticsData } = useCircuitTrestle()
|
const { setModuleStatisticsData } = useCircuitTrestle()
|
||||||
const { createRoofPolygon, createMarginPolygon, createPaddingPolygon, removeShortEdges } = useMode()
|
const { createRoofPolygon, createMarginPolygon, createPaddingPolygon } = useMode()
|
||||||
|
|
||||||
const moduleSetupOption = useRecoilValue(moduleSetupOptionState)
|
const moduleSetupOption = useRecoilValue(moduleSetupOptionState)
|
||||||
const setManualSetupMode = useSetRecoilState(toggleManualSetupModeState)
|
const setManualSetupMode = useSetRecoilState(toggleManualSetupModeState)
|
||||||
@ -388,14 +388,10 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
setSurfaceShapePattern(roof, roofDisplay.column, true, roof.roofMaterial) //패턴 변경
|
setSurfaceShapePattern(roof, roofDisplay.column, true, roof.roofMaterial) //패턴 변경
|
||||||
// let offsetPoints = createPaddingPolygon(createRoofPolygon(roof.points), roof.lines).vertices //안쪽 offset
|
// let offsetPoints = createPaddingPolygon(createRoofPolygon(roof.points), roof.lines).vertices //안쪽 offset
|
||||||
let offsetPoints = null
|
let offsetPoints = null
|
||||||
|
const polygon = createRoofPolygon(roof.getCurrentPoints())
|
||||||
// 겹치는 선(같은 방향) 중 짧은 edge를 제거하여 폴리곤 단순화
|
|
||||||
const cleaned = removeShortEdges(roof.getCurrentPoints(), roof.lines)
|
|
||||||
const polygon = createRoofPolygon(cleaned.vertices)
|
|
||||||
const cleanedLines = cleaned.lines
|
|
||||||
const originPolygon = new QPolygon(roof.getCurrentPoints(), { fontSize: 0 })
|
const originPolygon = new QPolygon(roof.getCurrentPoints(), { fontSize: 0 })
|
||||||
|
|
||||||
let result = createPaddingPolygon(polygon, cleanedLines).vertices
|
let result = createPaddingPolygon(polygon, roof.lines).vertices
|
||||||
|
|
||||||
//margin polygon 의 point가 기준 polygon의 밖에 있는지 판단한다.
|
//margin polygon 의 point가 기준 polygon의 밖에 있는지 판단한다.
|
||||||
const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
|
const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
|
||||||
@ -408,14 +404,12 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
} else {
|
} else {
|
||||||
//육지붕이 아닐때
|
//육지붕이 아닐때
|
||||||
if (allPointsOutside) {
|
if (allPointsOutside) {
|
||||||
offsetPoints = createMarginPolygon(polygon, cleanedLines).vertices
|
offsetPoints = createMarginPolygon(polygon, roof.lines).vertices
|
||||||
} else {
|
} else {
|
||||||
offsetPoints = createPaddingPolygon(polygon, cleanedLines).vertices
|
offsetPoints = createPaddingPolygon(polygon, roof.lines).vertices
|
||||||
}
|
}
|
||||||
// 자기교차(꼬임) 제거
|
// 자기교차(꼬임) 제거
|
||||||
offsetPoints = cleanSelfIntersectingPolygon(offsetPoints)
|
offsetPoints = cleanSelfIntersectingPolygon(offsetPoints)
|
||||||
// 둔각 꼭짓점에서 offset 선이 지붕 바깥으로 튀어나가는 문제 수정
|
|
||||||
offsetPoints = clipOffsetToOriginal(offsetPoints, roof.getCurrentPoints())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//모듈설치영역?? 생성
|
//모듈설치영역?? 생성
|
||||||
|
|||||||
@ -310,7 +310,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
|
|||||||
} else {
|
} else {
|
||||||
// 최초 선택: 설치 가능하면 디폴트 체크
|
// 최초 선택: 설치 가능하면 디폴트 체크
|
||||||
const defaultCvr = selectedConstruction.cvrYn === 'Y'
|
const defaultCvr = selectedConstruction.cvrYn === 'Y'
|
||||||
const defaultSnowGd = false
|
const defaultSnowGd = selectedConstruction.snowGdPossYn === 'Y'
|
||||||
selectedConstruction.setupCover = defaultCvr
|
selectedConstruction.setupCover = defaultCvr
|
||||||
selectedConstruction.setupSnowCover = defaultSnowGd
|
selectedConstruction.setupSnowCover = defaultSnowGd
|
||||||
setCvrChecked(defaultCvr)
|
setCvrChecked(defaultCvr)
|
||||||
|
|||||||
@ -1675,81 +1675,14 @@ export function useMode() {
|
|||||||
* @param arcSegments
|
* @param arcSegments
|
||||||
* @returns {{vertices, edges: *[], minX: *, minY: *, maxX: *, maxY: *}}
|
* @returns {{vertices, edges: *[], minX: *, minY: *, maxX: *, maxY: *}}
|
||||||
*/
|
*/
|
||||||
/**
|
|
||||||
* 같은 방향(각도)으로 겹치는 edge들을 감지하여, 가장 긴 선만 유지한다.
|
|
||||||
* 겹치는 짧은 edge의 꼭짓점을 제거하고 폴리곤을 단순화한다.
|
|
||||||
* @param {Array} vertices - 폴리곤 꼭짓점 배열
|
|
||||||
* @param {Array} lines - 대응하는 QLine 배열
|
|
||||||
* @returns {{ vertices: Array, lines: Array }} 정리된 꼭짓점과 lines
|
|
||||||
*/
|
|
||||||
function removeShortEdges(vertices, lines) {
|
|
||||||
if (!vertices || vertices.length < 4) return { vertices, lines }
|
|
||||||
|
|
||||||
// 각 edge의 각도와 길이를 계산
|
|
||||||
function edgeAngle(v1, v2) {
|
|
||||||
const rad = Math.atan2(v2.y - v1.y, v2.x - v1.x)
|
|
||||||
return Math.round(rad * (180 / Math.PI))
|
|
||||||
}
|
|
||||||
function edgeLength(v1, v2) {
|
|
||||||
const dx = v2.x - v1.x
|
|
||||||
const dy = v2.y - v1.y
|
|
||||||
return Math.sqrt(dx * dx + dy * dy)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 같은 방향인지 판단 (동일 각도 또는 정반대 180도)
|
|
||||||
function isSameDirection(angle1, angle2) {
|
|
||||||
const diff = Math.abs(angle1 - angle2) % 360
|
|
||||||
return diff <= 1 || Math.abs(diff - 180) <= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// 연속된 같은 방향 edge를 그룹으로 묶기
|
|
||||||
const n = vertices.length
|
|
||||||
const edges = []
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const next = (i + 1) % n
|
|
||||||
edges.push({
|
|
||||||
index: i,
|
|
||||||
angle: edgeAngle(vertices[i], vertices[next]),
|
|
||||||
length: edgeLength(vertices[i], vertices[next]),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeIndices = new Set()
|
|
||||||
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const next = (i + 1) % n
|
|
||||||
// 인접한 두 edge가 같은 방향이면 겹치는 선
|
|
||||||
if (isSameDirection(edges[i].angle, edges[next].angle)) {
|
|
||||||
// 짧은 쪽을 제거 대상으로 표시
|
|
||||||
if (edges[i].length <= edges[next].length) {
|
|
||||||
removeIndices.add(i)
|
|
||||||
} else {
|
|
||||||
removeIndices.add(next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removeIndices.size === 0) return { vertices, lines }
|
|
||||||
|
|
||||||
// 폴리곤이 3개 미만이 되지 않도록 보호
|
|
||||||
if (n - removeIndices.size < 3) return { vertices, lines }
|
|
||||||
|
|
||||||
const cleanedVertices = []
|
|
||||||
const cleanedLines = []
|
|
||||||
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
if (removeIndices.has(i)) continue
|
|
||||||
cleanedVertices.push(vertices[i])
|
|
||||||
cleanedLines.push(lines[i % lines.length])
|
|
||||||
}
|
|
||||||
|
|
||||||
return { vertices: cleanedVertices, lines: cleanedLines }
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMarginPolygon(polygon, lines, arcSegments = 0) {
|
function createMarginPolygon(polygon, lines, arcSegments = 0) {
|
||||||
const offsetEdges = []
|
const offsetEdges = []
|
||||||
|
|
||||||
polygon.edges.forEach((edge, i) => {
|
polygon.edges.forEach((edge, i) => {
|
||||||
|
/* const offset =
|
||||||
|
lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0
|
||||||
|
? 0.1
|
||||||
|
: lines[i % lines.length].attributes.offset*/
|
||||||
const offset = lines[i % lines.length].attributes.offset
|
const offset = lines[i % lines.length].attributes.offset
|
||||||
const dx = edge.outwardNormal.x * offset
|
const dx = edge.outwardNormal.x * offset
|
||||||
const dy = edge.outwardNormal.y * offset
|
const dy = edge.outwardNormal.y * offset
|
||||||
@ -1785,6 +1718,10 @@ export function useMode() {
|
|||||||
const offsetEdges = []
|
const offsetEdges = []
|
||||||
|
|
||||||
polygon.edges.forEach((edge, i) => {
|
polygon.edges.forEach((edge, i) => {
|
||||||
|
/*const offset =
|
||||||
|
lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0
|
||||||
|
? 0.1
|
||||||
|
: lines[i % lines.length].attributes.offset*/
|
||||||
const offset = lines[i % lines.length].attributes.offset
|
const offset = lines[i % lines.length].attributes.offset
|
||||||
|
|
||||||
const dx = edge.inwardNormal.x * offset
|
const dx = edge.inwardNormal.x * offset
|
||||||
@ -5837,6 +5774,5 @@ export function useMode() {
|
|||||||
createRoofPolygon,
|
createRoofPolygon,
|
||||||
createMarginPolygon,
|
createMarginPolygon,
|
||||||
createPaddingPolygon,
|
createPaddingPolygon,
|
||||||
removeShortEdges,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -255,40 +255,6 @@ function createPaddingPolygon(polygon, offset, arcSegments = 0) {
|
|||||||
* @param {Array} vertices - [{x, y}, ...] 형태의 점 배열
|
* @param {Array} vertices - [{x, y}, ...] 형태의 점 배열
|
||||||
* @returns {Array} 정리된 점 배열
|
* @returns {Array} 정리된 점 배열
|
||||||
*/
|
*/
|
||||||
/**
|
|
||||||
* offset 폴리곤을 원본 폴리곤 경계 안으로 클리핑한다.
|
|
||||||
* 둔각 꼭짓점에서 offset 교차점이 원본 바깥으로 튀어나가는 문제를 해결한다.
|
|
||||||
* @param {Array} offsetVertices - offset된 점 배열 [{x, y}, ...]
|
|
||||||
* @param {Array} originalVertices - 원본 폴리곤 점 배열 [{x, y}, ...]
|
|
||||||
* @returns {Array} 클리핑된 점 배열
|
|
||||||
*/
|
|
||||||
export function clipOffsetToOriginal(offsetVertices, originalVertices) {
|
|
||||||
if (!offsetVertices || offsetVertices.length < 3) return offsetVertices
|
|
||||||
if (!originalVertices || originalVertices.length < 3) return offsetVertices
|
|
||||||
|
|
||||||
try {
|
|
||||||
const offsetCoords = offsetVertices.map((p) => [p.x, p.y])
|
|
||||||
offsetCoords.push([offsetVertices[0].x, offsetVertices[0].y])
|
|
||||||
|
|
||||||
const origCoords = originalVertices.map((p) => [p.x, p.y])
|
|
||||||
origCoords.push([originalVertices[0].x, originalVertices[0].y])
|
|
||||||
|
|
||||||
const offsetPoly = turf.polygon([offsetCoords])
|
|
||||||
const origPoly = turf.polygon([origCoords])
|
|
||||||
|
|
||||||
const clipped = turf.intersect(turf.featureCollection([offsetPoly, origPoly]))
|
|
||||||
|
|
||||||
if (clipped) {
|
|
||||||
const clippedCoords = clipped.geometry.coordinates[0]
|
|
||||||
return clippedCoords.slice(0, -1).map((c) => ({ x: c[0], y: c[1] }))
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Failed to clip offset polygon to original:', e)
|
|
||||||
}
|
|
||||||
|
|
||||||
return offsetVertices
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cleanSelfIntersectingPolygon(vertices) {
|
export function cleanSelfIntersectingPolygon(vertices) {
|
||||||
if (!vertices || vertices.length < 3) return vertices
|
if (!vertices || vertices.length < 3) return vertices
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user