polygon 선택이 잘 안되는 현상 수정중
This commit is contained in:
parent
7e0e4643e2
commit
5102fa2ec0
@ -721,8 +721,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
||||
}
|
||||
|
||||
// Ray casting 알고리즘
|
||||
if (((yi > testY) !== (yj > testY)) &&
|
||||
(testX < (xj - xi) * (testY - yi) / (yj - yi) + xi)) {
|
||||
if (yi > testY !== yj > testY && testX < ((xj - xi) * (testY - yi)) / (yj - yi) + xi) {
|
||||
inside = !inside
|
||||
}
|
||||
}
|
||||
@ -773,36 +772,140 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
||||
// 먼저 좌표 업데이트
|
||||
this.setCoords()
|
||||
|
||||
// 캔버스 줌과 viewport transform 고려한 좌표 변환
|
||||
let localPoint = point
|
||||
if (this.canvas) {
|
||||
const vpt = this.canvas.viewportTransform
|
||||
if (vpt) {
|
||||
// viewport transform 역변환
|
||||
const inverted = fabric.util.invertTransform(vpt)
|
||||
localPoint = fabric.util.transformPoint(point, inverted)
|
||||
}
|
||||
// 기본 Fabric.js bounding box 체크 먼저 수행
|
||||
if (!this.callSuper('containsPoint', point)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 오브젝트의 transform matrix를 고려한 좌표 변환
|
||||
// 줌 레벨에 관계없이 안정적인 좌표 변환
|
||||
const matrix = this.calcTransformMatrix()
|
||||
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 finalPoint = {
|
||||
x: transformedPoint.x + pathOffset.x,
|
||||
y: transformedPoint.y + pathOffset.y,
|
||||
x: localPoint.x + pathOffset.x,
|
||||
y: localPoint.y + pathOffset.y,
|
||||
}
|
||||
|
||||
if (this.name === POLYGON_TYPE.ROOF && this.isFixed) {
|
||||
const isInside = this.inPolygonImproved(finalPoint)
|
||||
this.set('selectable', isInside)
|
||||
return isInside
|
||||
} else {
|
||||
return this.inPolygonImproved(finalPoint)
|
||||
// 단순하고 안정적인 point-in-polygon 알고리즘 사용
|
||||
return this.simplePointInPolygon(finalPoint, this.get('points'))
|
||||
},
|
||||
|
||||
simplePointInPolygon: function (point, polygon) {
|
||||
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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user