React Konva中检测线多边形完全位于另一线多边形内的实现方法
Konva线多边形包含关系判断实现方案
多边形包含判断本质是几何计算问题,和React Konva框架本身没有强绑定,核心逻辑是拿到两个多边形的绝对坐标顶点后,用标准几何规则校验即可,具体实现步骤如下:
1. 预处理:获取多边形绝对坐标顶点
如果多边形做过平移、旋转、缩放等变换,原始存储的顶点坐标会和画布实际渲染位置不一致,需要先转换为全局坐标系下的绝对坐标:
// 入参为Konva.Polygon实例 const getAbsolutePoints = (polygonNode) => { const rawPoints = polygonNode.points(); const transform = polygonNode.getAbsoluteTransform(); const points = []; for (let i = 0; i < rawPoints.length; i += 2) { const absolutePoint = transform.point({ x: rawPoints[i], y: rawPoints[i + 1] }); points.push([absolutePoint.x, absolutePoint.y]); } return points; }
2. 核心几何算法实现
判断多边形A完全处于多边形B内部,需要同时满足两个条件:
- 多边形A的所有顶点都在多边形B内部
- 多边形A的所有边和多边形B的所有边没有交点
点是否在多边形内(射线法)
const isPointInPolygon = (point, polygonPoints) => { const [px, py] = point; let inside = false; const len = polygonPoints.length; for (let i = 0, j = len - 1; i < len; j = i++) { const [xi, yi] = polygonPoints[i]; const [xj, yj] = polygonPoints[j]; const intersect = ((yi > py) !== (yj > py)) && (px < (xj - xi) * (py - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } return inside; }
两条线段是否相交
const isSegmentsIntersect = (seg1, seg2) => { const [[x1, y1], [x2, y2]] = seg1; const [[x3, y3], [x4, y4]] = seg2; // 叉积计算判断朝向 const ccw = (a, b, c) => (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); return ccw([x1, y1], [x3, y3], [x4, y4]) * ccw([x2, y2], [x3, y3], [x4, y4]) < 0 && ccw([x1, y1], [x2, y2], [x3, y3]) * ccw([x1, y1], [x2, y2], [x4, y4]) < 0; }
3. 组合逻辑完成判断
const isPolygonFullyInside = (innerPolygon, outerPolygon) => { // 先做包围盒快速过滤,减少不必要的计算 const innerRect = innerPolygon.getClientRect(); const outerRect = outerPolygon.getClientRect(); if ( innerRect.x < outerRect.x || innerRect.y < outerRect.y || innerRect.x + innerRect.width > outerRect.x + outerRect.width || innerRect.y + innerRect.height > outerRect.y + outerRect.height ) { return false; } const innerPoints = getAbsolutePoints(innerPolygon); const outerPoints = getAbsolutePoints(outerPolygon); // 校验所有内多边形顶点都在外多边形内部 const allPointsInside = innerPoints.every(p => isPointInPolygon(p, outerPoints)); if (!allPointsInside) return false; // 提取多边形边 const getEdges = (points) => { return points.map((p, i) => [p, points[(i + 1) % points.length]]); } const innerEdges = getEdges(innerPoints); const outerEdges = getEdges(outerPoints); // 校验无交叉边 for (const innerEdge of innerEdges) { for (const outerEdge of outerEdges) { if (isSegmentsIntersect(innerEdge, outerEdge)) return false; } } return true; }
该方案不需要引入任何额外第三方库,性能足以应对前端常规场景下的多边形判断需求。
内容的提问来源于stack exchange,提问作者user1791139
相关产品推荐
相关产品推荐

