You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KonvaJS技术问询:如何判断Line节点完全处于其他节点内部

检测线段是否完全处于任意形状节点内部的实现方案

要判断红线(线段)是否完全处于蓝色节点(任意形状)内部,仅检测首尾点的方式会遗漏线段中间穿出的情况,需结合多点采样检测和线段与形状边界交叉检测两种方式实现:

核心思路

  1. 采样线段上的多个点位(含首尾),确保所有点都在形状内部;
  2. 检测线段是否与形状的边界存在交叉(排除首尾点刚好在边界上的情况),若存在交叉则说明线段穿出了形状;
  3. 只有同时满足上述两个条件,才判定线段完全处于形状内部。

具体实现代码(基于SVG环境)

// 检测单个点是否在目标形状内
function isPointInShape(point, shapeElement) {
  const svg = shapeElement.ownerSVGElement;
  const svgPoint = svg.createSVGPoint();
  svgPoint.x = point.x;
  svgPoint.y = point.y;
  // 转换坐标到形状的本地坐标系
  const transformMatrix = shapeElement.getScreenCTM().inverse();
  const localPoint = svgPoint.matrixTransform(transformMatrix);
  return shapeElement.isPointInside(localPoint);
}

// 生成线段上的采样点,sampleCount为中间采样点数(默认10个,含首尾共11个点)
function getLineSamplePoints(start, end, sampleCount = 10) {
  const points = [];
  const deltaX = end.x - start.x;
  const deltaY = end.y - start.y;
  for (let i = 0; i <= sampleCount; i++) {
    const ratio = i / sampleCount;
    points.push({
      x: start.x + deltaX * ratio,
      y: start.y + deltaY * ratio
    });
  }
  return points;
}

// 检测线段是否与形状边界相交(排除首尾点在边界的情况)
function doesLineCrossShapeBoundary(start, end, shapeElement) {
  const svg = shapeElement.ownerSVGElement;
  // 创建临时线段用于检测交集
  const tempLine = document.createElementNS("http://www.w3.org/2000/svg", "line");
  tempLine.setAttribute("x1", start.x);
  tempLine.setAttribute("y1", start.y);
  tempLine.setAttribute("x2", end.x);
  tempLine.setAttribute("y2", end.y);
  
  // 获取线段与形状边界的所有交集
  const intersections = svg.getIntersectionList(tempLine, null);
  
  // 判断是否存在非首尾点的交集
  return intersections.some(intersect => {
    const intersectPoint = { x: intersect.x, y: intersect.y };
    const isStartPoint = Math.abs(intersectPoint.x - start.x) < 0.1 && Math.abs(intersectPoint.y - start.y) < 0.1;
    const isEndPoint = Math.abs(intersectPoint.x - end.x) < 0.1 && Math.abs(intersectPoint.y - end.y) < 0.1;
    return !isStartPoint && !isEndPoint;
  });
}

// 主检测函数:判断线段是否完全在形状内部
function isLineFullyInsideShape(lineElement, shapeElement) {
  // 获取线段的首尾坐标
  const startPoint = {
    x: parseFloat(lineElement.getAttribute("x1")),
    y: parseFloat(lineElement.getAttribute("y1"))
  };
  const endPoint = {
    x: parseFloat(lineElement.getAttribute("x2")),
    y: parseFloat(lineElement.getAttribute("y2"))
  };

  // 首尾点不在内部直接返回false
  if (!isPointInShape(startPoint, shapeElement) || !isPointInShape(endPoint, shapeElement)) {
    return false;
  }

  // 线段与边界交叉直接返回false
  if (doesLineCrossShapeBoundary(startPoint, endPoint, shapeElement)) {
    return false;
  }

  // 检测所有采样点是否都在内部
  const samplePoints = getLineSamplePoints(startPoint, endPoint);
  return samplePoints.every(point => isPointInShape(point, shapeElement));
}

注意事项

  • 采样点数量可根据线段长度调整:线段越长,建议增加采样点数量,避免遗漏局部超出的情况;
  • 坐标精度判断(代码中的0.1)可根据实际图形的缩放比例调整,避免因浮点误差导致误判;
  • 若使用非SVG的图形库,可替换对应API:点-in-形状判断用对应库的点包含检测函数,线段与边界交叉判断用线段-多边形/路径相交算法。

内容的提问来源于stack exchange,提问作者underfrankenwood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:32:37