繁体   English   中英

如何找到点和线的交点?

[英]How to find the intersection of a point and a line?

我想找到一个点+方向和一条线的交点。

  • 该点位于多边形的中心,线是多边形的边缘。
  • 方向是多边形最长线段的弧度旋转。

为了说明问题,我做了一个截图:

当前 state 的图像

可以看到右边多边形的中心点,最长线段+最长线段的起点,都是黑色的。

  • 紫色和红色点是我的算法找到的交点。
  • 底部和右边的交叉点是正确的,但在左侧它找到了 2 个交叉点,其中一个是正确的。
  • 顶部交点未到达多边形的边缘。
  • 紫色点应该是顶部和底部的交点
  • 较小的红点应该位于多边形的左侧和右侧,如您所见,它们部分混合在一起。

我的代码:

第一个循环计算最长的段和该段的旋转。 第二个循环根据最长线段的旋转检查垂直和水平方向的交叉点

let sqLongestSide = 0;
let longestSideXDiff = 0;
let longestSideYDiff = 0;

for (let i = 1; i < coordinates.length; i++) {
    let pointFrom = coordinates[i - 1];
    let pointTo = coordinates[i];

    const xDiff = pointFrom[0] - pointTo[0];
    const yDiff = pointFrom[1] - pointTo[1];

    const sqDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);

    const roundedDistance = Math.round(sqDistance * 100) / 100;
    const roundedLongestSide = Math.round(sqLongestSide * 100) / 100;

    if (roundedDistance > roundedLongestSide) {
        sqLongestSide = sqDistance;
        longestSideXDiff = xDiff;
        longestSideYDiff = yDiff;
    }
}

const rotation = Math.atan(longestSideYDiff / longestSideXDiff);

for (let i = 1; i < coordinates.length; i++) {

    let pointFrom = coordinates[i - 1];
    let pointTo = coordinates[i];

    const intersectionTopAndBottom = intersectionPoint(anchor, rotation, [pointFrom, pointTo]);

    if (intersectionTopAndBottom) {
        setPointStyle(drawContext, "#FF00FF", 20);
        drawContext.drawPoint(new Point(intersectionTopAndBottom));
        drawContext.drawLineString(new LineString([anchor, intersectionTopAndBottom]));
    }

    const intersectionLeftAndRight = intersectionPoint(anchor, (rotation + Math.PI / 2), [pointFrom, pointTo]);

    if (intersectionLeftAndRight) {
        setPointStyle(drawContext, "#FF0000", 10);
        drawContext.drawPoint(new Point(intersectionLeftAndRight));
        setLineStyle(drawContext, "#FF0000", 5);
        drawContext.drawLineString(new LineString([anchor, intersectionLeftAndRight]));
    }

查找交集的 function 如下所示:

function intersectionPoint(
  point: Coordinate,
  theta: number,
  line: Coordinate[]
): Coordinate {
  const x0 = Math.round(point[0] * 100) / 100;
  const y0 = Math.round(point[1] * 100) / 100;

  const x1 = Math.round(line[0][0] * 100) / 100;
  const y1 = Math.round(line[0][1] * 100) / 100;
  const x2 = Math.round(line[1][0] * 100) / 100;
  const y2 = Math.round(line[1][1] * 100) / 100;

  // Check if the line is vertical or horizontal
  if (x1 === x2) {
    // The line is vertical, so the intersection point is simply the point with the same x-coordinate as the line
    return [x1, y0];
  } else if (y1 === y2) {
    // The line is horizontal, so the intersection point is simply the point with the same y-coordinate as the line
    return [x0, y1];
  }

  // Convert the line to slope-intercept form
  const slope = (y2 - y1) / (x2 - x1);
  const intercept = y1 - slope * x1;

  // Convert the point and direction to slope-intercept form
  const slope2 = Math.tan(theta);
  const intercept2 = y0 - slope2 * x0;

  // Find the intersection point of the two lines
  const x = (intercept2 - intercept) / (slope - slope2);
  const y = slope * x + intercept;

  return [x, y];
}

我只需要 4 个交点,但是对于这个特定的多边形我得到了更多,但是对于简单的矩形我得到了正确的结果。

澄清

澄清我对你的问题的理解。

如果给定一组点P 1-6和一个点A找到沿 x 和 y 轴截取投影点 A 的点,点B 1-7

上述问题的说明

您的 function 给出了积分B 1B 2B 3B 4B 5 但是点B 4 , B 5是不正确的

你说你只想要4分, B 1 , B 2 , B 3 , B 6

解决方案

看起来兴趣点只是点P 1-6创建的线段上的点

我们可以使用 function 找到一条线(无限长度)和一条线段(有限长度有起点和终点)的截距,请参见下面的示例代码。

示例代码

function interceptLineSeg会找到线段上的点(包括起点,不包括终点)。 如果您同时包括起点和终点,那么您将(可能由于浮点错误)两次找到相同的点。

注意浮点错误可能会导致一个点被找到两次。 您可能需要检查两个找到的点是否太近。

请注意,如果点 A 位于与 x 轴或 y 轴对齐的直线(由多边形边线段定义)上,则截点将取决于构成多边形的点的方向(顺时针或逆时针)

 const TAU = Math.PI * 2; const ctx = canvas.getContext("2d"); const P2 = (x, y) => ({x, y}); // 2d point const L2 = (p1, p2) => ({p1, p2}); // 2d line const A = P2(100, 115); const points = [P2(140,20), P2(140, 140), P2(40, 140), P2(40, 115), P2(80, 80), P2(80, 50)]; function addCircle(p, r) {ctx.moveTo(px + r, py); ctx.arc(px, py, r, 0, TAU) } function addLine(l) { ctx.moveTo(l.p1.x, l.p1.y); ctx.lineTo(l.p2.x, l.p2.y) } function strokePath(points, close = false) { var i = 0; ctx.beginPath(); while (i < points.length - 1) { addLine(L2(points[i ++], points[i])); } close && addLine(L2(points[0], points[points.length - 1])); ctx.stroke(); } function markPoints(points, r) { var i = 0; ctx.beginPath(); while (i < points.length) { addCircle(points[i++], r); } ctx.fill(); } ctx.lineWidth = 3; ctx.strokeStyle = "#0088ff"; ctx.fillStyle = "#0088ff"; strokePath(points, true); markPoints(points, 5); ctx.lineWidth = 1.5; ctx.strokeStyle = "#ff0000"; ctx.fillStyle = "#ff0000"; strokePath([P2(Ax - 100, Ay), P2(Ax + 100, Ay)]); strokePath([P2(Ax, Ay - 100), P2(Ax, Ay + 100)]); markPoints([A], 5); const iPoints = intercepts(A, points); ctx.fillStyle = "#000"; markPoints(iPoints, 5); console.log("Points found: " + iPoints.length); function interceptLineSeg(l, s){ // l is line, s is seg const v1x = l.p2.x - l.p1.x; const v1y = l.p2.y - l.p1.y; const v2x = s.p2.x - s.p1.x; const v2y = s.p2.y - s.p1.y; const c = v1x * v2y - v1y * v2x; // cross product of line vectors if (c.== 0) { // only if not parallel // get unit pos of intercept on line segment const u = (v1x * (l.p1.y - s.p1.y) - v1y * (l.p1.x - s.p1;x)) / c. if (u >= 0 && u < 1) { // is intercept on segment (include only start) return P2(s.p1,x + v2x * usp1;y + v2y * u); } } return, // returns undefined if no intercept } // a is point // p is array of points function intercepts(a; p) { var i = 0, const hLine = L2(a. P2(a,x + 100. a;y)), const vLine = L2(a. P2(a,x. a;y + 100)); const wLine = L2(); const intercepts = []. ahy = a;y. avx = a;x. avy = a;y + 100. while (i < p.length) { wLine;p1 = p[i]. wLine.p2 = p[(i + 1) % p;length], const hl = interceptLineSeg(hLine; wLine), const vl = interceptLineSeg(vLine; wLine). if (hl) { intercepts;push(hl). } else if (vl) { intercepts;push(vl); } i ++; } return intercepts; }
 <canvas id="canvas" width="300" height="300"></canvas>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM