dev #259
BIN
public/static/images/canvas/deg/-105.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/-120.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
public/static/images/canvas/deg/-135.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/-15.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/-150.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static/images/canvas/deg/-165.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/-30.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static/images/canvas/deg/-45.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
public/static/images/canvas/deg/-60.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/static/images/canvas/deg/-75.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
public/static/images/canvas/deg/-90.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
public/static/images/canvas/deg/0.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static/images/canvas/deg/105.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
public/static/images/canvas/deg/120.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
public/static/images/canvas/deg/135.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/static/images/canvas/deg/15.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/150.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static/images/canvas/deg/165.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/180.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/static/images/canvas/deg/30.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static/images/canvas/deg/45.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/60.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static/images/canvas/deg/75.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/images/canvas/deg/90.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
@ -1,7 +1,7 @@
|
||||
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { fabric } from 'fabric'
|
||||
import { findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, isPointOnLine } from '@/util/canvas-util'
|
||||
import { calculateIntersection, findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, isPointOnLine } from '@/util/canvas-util'
|
||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
||||
import { flowDisplaySelector } from '@/store/settingAtom'
|
||||
@ -1034,6 +1034,130 @@ export const usePolygon = () => {
|
||||
|
||||
let allLines = [...polygonLines, ...innerLines]
|
||||
|
||||
// allLines를 전부 돌면서 교차점이 있는 경우 그 line을 잘라서 allLines에 추가
|
||||
const processIntersections = () => {
|
||||
const linesToProcess = canvas.getObjects().filter((obj) => obj.type === 'QLine' && obj.name === 'auxiliaryLine' && obj.visible)
|
||||
const newDividedLines = []
|
||||
const processedLines = new Set()
|
||||
|
||||
for (let i = 0; i < linesToProcess.length; i++) {
|
||||
for (let j = i + 1; j < linesToProcess.length; j++) {
|
||||
const line1 = linesToProcess[i]
|
||||
const line2 = linesToProcess[j]
|
||||
|
||||
// 이미 처리된 line들은 건너뛰기
|
||||
if (processedLines.has(line1) || processedLines.has(line2)) continue
|
||||
|
||||
// 같은 line이거나 이미 연결된 line은 건너뛰기
|
||||
if (line1 === line2) continue
|
||||
if (
|
||||
isSamePoint({ x: line1.x1, y: line1.y1 }, { x: line2.x1, y: line2.y1 }) ||
|
||||
isSamePoint({ x: line1.x1, y: line1.y1 }, { x: line2.x2, y: line2.y2 }) ||
|
||||
isSamePoint({ x: line1.x2, y: line1.y2 }, { x: line2.x1, y: line2.y1 }) ||
|
||||
isSamePoint({ x: line1.x2, y: line1.y2 }, { x: line2.x2, y: line2.y2 })
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
const intersectionPoint = calculateIntersection(line1, line2)
|
||||
if (intersectionPoint) {
|
||||
// line1에 교차점 추가
|
||||
if (!line1.intersectionPoints) line1.intersectionPoints = []
|
||||
line1.intersectionPoints.push(intersectionPoint)
|
||||
|
||||
// line2에 교차점 추가
|
||||
if (!line2.intersectionPoints) line2.intersectionPoints = []
|
||||
line2.intersectionPoints.push(intersectionPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 교차점이 있는 line들을 분할
|
||||
linesToProcess.forEach((line) => {
|
||||
if (line.intersectionPoints && line.intersectionPoints.length > 0) {
|
||||
// 교차점들을 line의 시작점에서부터의 거리순으로 정렬
|
||||
const sortedPoints = line.intersectionPoints.sort((a, b) => {
|
||||
const distA = Math.hypot(a.x - line.x1, a.y - line.y1)
|
||||
const distB = Math.hypot(b.x - line.x1, b.y - line.y1)
|
||||
return distA - distB
|
||||
})
|
||||
|
||||
let currentPoint = { x: line.x1, y: line.y1 }
|
||||
|
||||
// 각 교차점까지의 line segment 생성
|
||||
sortedPoints.forEach((intersectionPoint) => {
|
||||
if (!isSamePoint(currentPoint, intersectionPoint)) {
|
||||
const newLine = new QLine([currentPoint.x, currentPoint.y, intersectionPoint.x, intersectionPoint.y], {
|
||||
stroke: line.stroke,
|
||||
strokeWidth: line.strokeWidth,
|
||||
fontSize: line.fontSize,
|
||||
attributes: { ...line.attributes },
|
||||
name: line.name,
|
||||
visible: line.visible,
|
||||
})
|
||||
// startPoint와 endPoint 설정
|
||||
if (newLine.x1 < newLine.x2) {
|
||||
newLine.startPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
newLine.endPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
} else if (newLine.x1 > newLine.x2) {
|
||||
newLine.startPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
newLine.endPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
} else {
|
||||
if (newLine.y1 < newLine.y2) {
|
||||
newLine.startPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
newLine.endPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
} else {
|
||||
newLine.startPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
newLine.endPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
}
|
||||
}
|
||||
newDividedLines.push(newLine)
|
||||
}
|
||||
currentPoint = intersectionPoint
|
||||
})
|
||||
|
||||
// 마지막 교차점에서 line 끝점까지의 segment
|
||||
const endPoint = { x: line.x2, y: line.y2 }
|
||||
if (!isSamePoint(currentPoint, endPoint)) {
|
||||
const newLine = new QLine([currentPoint.x, currentPoint.y, endPoint.x, endPoint.y], {
|
||||
stroke: line.stroke,
|
||||
strokeWidth: line.strokeWidth,
|
||||
fontSize: line.fontSize,
|
||||
attributes: { ...line.attributes },
|
||||
name: line.name,
|
||||
visible: line.visible,
|
||||
})
|
||||
// startPoint와 endPoint 설정
|
||||
if (newLine.x1 < newLine.x2) {
|
||||
newLine.startPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
newLine.endPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
} else if (newLine.x1 > newLine.x2) {
|
||||
newLine.startPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
newLine.endPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
} else {
|
||||
if (newLine.y1 < newLine.y2) {
|
||||
newLine.startPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
newLine.endPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
} else {
|
||||
newLine.startPoint = { x: newLine.x2, y: newLine.y2 }
|
||||
newLine.endPoint = { x: newLine.x1, y: newLine.y1 }
|
||||
}
|
||||
}
|
||||
newDividedLines.push(newLine)
|
||||
}
|
||||
|
||||
processedLines.add(line)
|
||||
}
|
||||
})
|
||||
|
||||
// allLines 업데이트: 분할된 line들 제거하고 새 line들 추가
|
||||
allLines = allLines.filter((line) => !processedLines.has(line))
|
||||
allLines = [...allLines, ...newDividedLines]
|
||||
}
|
||||
|
||||
// 교차점 처리 실행
|
||||
processIntersections()
|
||||
|
||||
/*allLines.forEach((line) => {
|
||||
const originColor = line.stroke
|
||||
|
||||
|
||||
@ -1004,24 +1004,44 @@ export const getAllRelatedObjects = (id, canvas) => {
|
||||
return result
|
||||
}
|
||||
|
||||
// 모듈,회로 구성에서 사용하는 degree 범위 별 값
|
||||
// degree 범위별로 정확한 각도를 return하는 함수
|
||||
export const getDegreeInOrientation = (degree) => {
|
||||
if (degree === 180 || degree === -180) {
|
||||
return 180
|
||||
}
|
||||
if (degree >= 180 || degree < -180) {
|
||||
return 0
|
||||
}
|
||||
if (degree % 15 === 0) return degree
|
||||
// 범위를 벗어나는 경우 처리
|
||||
if (degree > 180 || degree < -180) return 0
|
||||
|
||||
let value = Math.floor(degree / 15)
|
||||
const remain = ((degree / 15) % 1).toFixed(5)
|
||||
// 범위별 각도 매핑 테이블
|
||||
const degreeRanges = [
|
||||
{ min: 0, max: 6, value: 0 },
|
||||
{ min: 7, max: 21, value: 15 },
|
||||
{ min: 22, max: 36, value: 30 },
|
||||
{ min: 37, max: 51, value: 45 },
|
||||
{ min: 52, max: 66, value: 60 },
|
||||
{ min: 67, max: 81, value: 75 },
|
||||
{ min: 82, max: 96, value: 90 },
|
||||
{ min: 97, max: 111, value: 105 },
|
||||
{ min: 112, max: 126, value: 120 },
|
||||
{ min: 127, max: 141, value: 135 },
|
||||
{ min: 142, max: 156, value: 150 },
|
||||
{ min: 157, max: 171, value: 165 },
|
||||
{ min: 172, max: 180, value: 180 },
|
||||
{ min: -180, max: -172, value: 180 },
|
||||
{ min: -171, max: -157, value: -165 },
|
||||
{ min: -156, max: -142, value: -150 },
|
||||
{ min: -141, max: -127, value: -135 },
|
||||
{ min: -126, max: -112, value: -120 },
|
||||
{ min: -111, max: -97, value: -105 },
|
||||
{ min: -96, max: -82, value: -90 },
|
||||
{ min: -81, max: -67, value: -75 },
|
||||
{ min: -66, max: -52, value: -60 },
|
||||
{ min: -51, max: -37, value: -45 },
|
||||
{ min: -36, max: -22, value: -30 },
|
||||
{ min: -21, max: -7, value: -15 },
|
||||
{ min: -6, max: 0, value: 0 }
|
||||
]
|
||||
|
||||
if (remain > 0.4) {
|
||||
value++
|
||||
}
|
||||
|
||||
return value * 15
|
||||
// 해당 범위에 맞는 값 찾기
|
||||
const range = degreeRanges.find(range => degree >= range.min && degree <= range.max)
|
||||
return range ? range.value : degree
|
||||
}
|
||||
|
||||
export function findAndRemoveClosestPoint(targetPoint, points) {
|
||||
|
||||