diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index a1a5a169..ebf4e625 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -772,140 +772,36 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { // 먼저 좌표 업데이트 this.setCoords() - // 기본 Fabric.js bounding box 체크 먼저 수행 - if (!this.callSuper('containsPoint', point)) { - return false + // 캔버스 줌과 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) + } } - // 줌 레벨에 관계없이 안정적인 좌표 변환 + // 오브젝트의 transform matrix를 고려한 좌표 변환 const matrix = this.calcTransformMatrix() const invertedMatrix = fabric.util.invertTransform(matrix) + const transformedPoint = fabric.util.transformPoint(localPoint, invertedMatrix) - // 캔버스 줌 고려 - 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 적용 + // pathOffset을 고려한 최종 좌표 계산 const pathOffset = this.get('pathOffset') const finalPoint = { - x: localPoint.x + pathOffset.x, - y: localPoint.y + pathOffset.y, + x: transformedPoint.x + pathOffset.x, + y: transformedPoint.y + pathOffset.y, } - // 단순하고 안정적인 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 + if (this.name === POLYGON_TYPE.ROOF && this.isFixed) { + const isInside = this.inPolygonImproved(finalPoint) + this.set('selectable', isInside) + return isInside } else { - xx = x1 + param * C - yy = y1 + param * D + return this.inPolygonImproved(finalPoint) } - - const dx = x - xx - const dy = y - yy - const distance = Math.sqrt(dx * dx + dy * dy) - - return distance < tolerance }, inPolygonABType(x, y, polygon) {