polygon 선택이 잘 안되는 현상 수정중
This commit is contained in:
parent
7e0e4643e2
commit
5102fa2ec0
@ -721,8 +721,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ray casting 알고리즘
|
// Ray casting 알고리즘
|
||||||
if (((yi > testY) !== (yj > testY)) &&
|
if (yi > testY !== yj > testY && testX < ((xj - xi) * (testY - yi)) / (yj - yi) + xi) {
|
||||||
(testX < (xj - xi) * (testY - yi) / (yj - yi) + xi)) {
|
|
||||||
inside = !inside
|
inside = !inside
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -773,36 +772,140 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
// 먼저 좌표 업데이트
|
// 먼저 좌표 업데이트
|
||||||
this.setCoords()
|
this.setCoords()
|
||||||
|
|
||||||
// 캔버스 줌과 viewport transform 고려한 좌표 변환
|
// 기본 Fabric.js bounding box 체크 먼저 수행
|
||||||
let localPoint = point
|
if (!this.callSuper('containsPoint', point)) {
|
||||||
if (this.canvas) {
|
return false
|
||||||
const vpt = this.canvas.viewportTransform
|
|
||||||
if (vpt) {
|
|
||||||
// viewport transform 역변환
|
|
||||||
const inverted = fabric.util.invertTransform(vpt)
|
|
||||||
localPoint = fabric.util.transformPoint(point, inverted)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 오브젝트의 transform matrix를 고려한 좌표 변환
|
// 줌 레벨에 관계없이 안정적인 좌표 변환
|
||||||
const matrix = this.calcTransformMatrix()
|
const matrix = this.calcTransformMatrix()
|
||||||
const invertedMatrix = fabric.util.invertTransform(matrix)
|
const invertedMatrix = fabric.util.invertTransform(matrix)
|
||||||
const transformedPoint = fabric.util.transformPoint(localPoint, invertedMatrix)
|
|
||||||
|
|
||||||
// pathOffset을 고려한 최종 좌표 계산
|
// 캔버스 줌 고려
|
||||||
|
let testPoint = point
|
||||||
|
if (this.canvas && this.canvas.viewportTransform) {
|
||||||
|
const vpt = this.canvas.viewportTransform
|
||||||
|
const invertedVpt = fabric.util.invertTransform(vpt)
|
||||||
|
testPoint = fabric.util.transformPoint(point, invertedVpt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 오브젝트 좌표계로 변환
|
||||||
|
const localPoint = fabric.util.transformPoint(testPoint, invertedMatrix)
|
||||||
|
|
||||||
|
// pathOffset 적용
|
||||||
const pathOffset = this.get('pathOffset')
|
const pathOffset = this.get('pathOffset')
|
||||||
const finalPoint = {
|
const finalPoint = {
|
||||||
x: transformedPoint.x + pathOffset.x,
|
x: localPoint.x + pathOffset.x,
|
||||||
y: transformedPoint.y + pathOffset.y,
|
y: localPoint.y + pathOffset.y,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.name === POLYGON_TYPE.ROOF && this.isFixed) {
|
// 단순하고 안정적인 point-in-polygon 알고리즘 사용
|
||||||
const isInside = this.inPolygonImproved(finalPoint)
|
return this.simplePointInPolygon(finalPoint, this.get('points'))
|
||||||
this.set('selectable', isInside)
|
},
|
||||||
return isInside
|
|
||||||
} else {
|
simplePointInPolygon: function (point, polygon) {
|
||||||
return this.inPolygonImproved(finalPoint)
|
const x = point.x
|
||||||
|
const y = point.y
|
||||||
|
let inside = false
|
||||||
|
|
||||||
|
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
||||||
|
const xi = polygon[i].x
|
||||||
|
const yi = polygon[i].y
|
||||||
|
const xj = polygon[j].x
|
||||||
|
const yj = polygon[j].y
|
||||||
|
|
||||||
|
if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) {
|
||||||
|
inside = !inside
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inside
|
||||||
|
},
|
||||||
|
|
||||||
|
isPointInPolygonRobust: function (point, polygon) {
|
||||||
|
const x = point.x
|
||||||
|
const y = point.y
|
||||||
|
let inside = false
|
||||||
|
|
||||||
|
// 부동소수점 정밀도를 고려한 허용 오차
|
||||||
|
const epsilon = 1e-10
|
||||||
|
|
||||||
|
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
||||||
|
const xi = polygon[i].x
|
||||||
|
const yi = polygon[i].y
|
||||||
|
const xj = polygon[j].x
|
||||||
|
const yj = polygon[j].y
|
||||||
|
|
||||||
|
// 점이 정점 위에 있는지 확인 (확장된 허용 오차)
|
||||||
|
if (Math.abs(xi - x) < 0.5 && Math.abs(yi - y) < 0.5) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 점이 선분 위에 있는지 확인
|
||||||
|
if (this.isPointOnLineSegment(point, { x: xi, y: yi }, { x: xj, y: yj })) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ray casting 알고리즘 - 개선된 버전
|
||||||
|
if (Math.abs(yi - yj) > epsilon) {
|
||||||
|
const minY = Math.min(yi, yj)
|
||||||
|
const maxY = Math.max(yi, yj)
|
||||||
|
|
||||||
|
if (y > minY && y <= maxY) {
|
||||||
|
// 교차점 계산
|
||||||
|
const intersectionX = xi + ((y - yi) / (yj - yi)) * (xj - xi)
|
||||||
|
if (intersectionX > x) {
|
||||||
|
inside = !inside
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inside
|
||||||
|
},
|
||||||
|
|
||||||
|
isPointOnLineSegment: function (point, lineStart, lineEnd) {
|
||||||
|
const tolerance = 2.0 // 더 큰 허용 오차
|
||||||
|
const x = point.x
|
||||||
|
const y = point.y
|
||||||
|
const x1 = lineStart.x
|
||||||
|
const y1 = lineStart.y
|
||||||
|
const x2 = lineEnd.x
|
||||||
|
const y2 = lineEnd.y
|
||||||
|
|
||||||
|
// 선분의 길이가 0인 경우 (점)
|
||||||
|
if (Math.abs(x2 - x1) < 1e-10 && Math.abs(y2 - y1) < 1e-10) {
|
||||||
|
return Math.abs(x - x1) < tolerance && Math.abs(y - y1) < tolerance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 점과 선분 사이의 거리 계산
|
||||||
|
const A = x - x1
|
||||||
|
const B = y - y1
|
||||||
|
const C = x2 - x1
|
||||||
|
const D = y2 - y1
|
||||||
|
|
||||||
|
const dot = A * C + B * D
|
||||||
|
const lenSq = C * C + D * D
|
||||||
|
const param = dot / lenSq
|
||||||
|
|
||||||
|
let xx, yy
|
||||||
|
|
||||||
|
if (param < 0 || (x1 === x2 && y1 === y2)) {
|
||||||
|
xx = x1
|
||||||
|
yy = y1
|
||||||
|
} else if (param > 1) {
|
||||||
|
xx = x2
|
||||||
|
yy = y2
|
||||||
|
} else {
|
||||||
|
xx = x1 + param * C
|
||||||
|
yy = y1 + param * D
|
||||||
|
}
|
||||||
|
|
||||||
|
const dx = x - xx
|
||||||
|
const dy = y - yy
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy)
|
||||||
|
|
||||||
|
return distance < tolerance
|
||||||
},
|
},
|
||||||
|
|
||||||
inPolygonABType(x, y, polygon) {
|
inPolygonABType(x, y, polygon) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user