确定一个点是不是在由具有给定纬度/经度的 3 个点组成的三角形内

Posted

技术标签:

【中文标题】确定一个点是不是在由具有给定纬度/经度的 3 个点组成的三角形内【英文标题】:Determine if a point is inside a triangle formed by 3 points with given latitude/longitude确定一个点是否在由具有给定纬度/经度的 3 个点组成的三角形内 【发布时间】:2010-03-17 18:35:36 【问题描述】:

我有 3 个点(纬度,经度)形成一个三角形。我怎样才能找到一个点是否在这个三角形内?

【问题讨论】:

这不是欧拉计划问题吗? 你的三角形可能有多大?它是否足够小,可以假设表面可以被认为是平坦的,还是需要球面几何形状? 进一步了解 Mark 所说的,您如何定义“内部”与“外部”?如果您的点是檀香山、曼谷和拉各斯,那么三角形边缘大致沿着赤道,北极在里面还是南极在里面? 首先我有一个起点A.我计算一个500m远的点B,方位角为60度。点C也是500m,但方位角为120度。我想知道如果一个点在角度范围为 60 度(从 60 到 120)的区域内。B 和 C 具有相同的 lon。我不知道我是否帮助过你。 【参考方案1】:

Java 代码仅用于三角形,即 3 个点。

    public static boolean pntInTriangle(double px, double py, double x1, double y1, double x2, double y2, double x3, double y3) 

    double o1 = getOrientationResult(x1, y1, x2, y2, px, py);
    double o2 = getOrientationResult(x2, y2, x3, y3, px, py);
    double o3 = getOrientationResult(x3, y3, x1, y1, px, py);

    return (o1 == o2) && (o2 == o3);


private static int getOrientationResult(double x1, double y1, double x2, double y2, double px, double py) 
    double orientation = ((x2 - x1) * (py - y1)) - ((px - x1) * (y2 - y1));
    if (orientation > 0) 
        return 1;
    
    else if (orientation < 0) 
        return -1;
    
    else 
        return 0;
    

【讨论】:

我不完全理解这是如何工作的。 getOrientationResult 中的神奇表达式从何而来? 方向公式错误。我发现多个来源证实了具有点 P1、P2 和 P3 的三角形的公式是:(p1.x - p3.x)*(p2.y - p3.y)-(p1.y - p3.y) *(p2.x - p3.x);另外,三个三角形的方向必须与原三角形的方向一致,这里不再赘述。来源(抱歉,它们是西班牙语,但公式是通用的 ;-) dma.fi.upm.es/mabellanas/tfcs/kirkpatrick/Aplicacion/… ouphenus.scienceontheweb.net/2008/07/13/…【参考方案2】:

这是重心坐标解决方案discussed here的javascript实现:

// Returns true if point P inside the triangle with vertices at A, B and C
// representing 2D vectors and points as [x,y]. Based on                        
// http://www.blackpawn.com/texts/pointinpoly/default.html
function pointInTriange(P, A, B, C) 
  // Compute vectors        
  function vec(from, to)   return [to[0] - from[0], to[1] - from[1]];  
  var v0 = vec(A, C);
  var v1 = vec(A, B);
  var v2 = vec(A, P);
  // Compute dot products
  function dot(u, v)   return u[0] * v[0] + u[1] * v[1];  
  var dot00 = dot(v0, v0);
  var dot01 = dot(v0, v1);
  var dot02 = dot(v0, v2);
  var dot11 = dot(v1, v1);
  var dot12 = dot(v1, v2);
  // Compute barycentric coordinates
  var invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
  var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  // Check if point is in triangle
  return (u >= 0) && (v >= 0) && (u + v < 1);

据说比基于交叉产品的解决方案更快。

【讨论】:

【参考方案3】:

大多数语言都为此提供了功能。在 Java 中是 Polygon.contains() http://docs.oracle.com/javase/7/docs/api/java/awt/Polygon.html

只需从您的点创建一个多边形,然后在您的测试点上调用 contains()。

【讨论】:

在这种情况下,这不是真正的语言,而是语言提供的框架。了解软件的功能总是好的。对于像确定一个点是否在三角形内这样简单的事情,我认为使用 Polygon 不是最好/最有效的解决方案。 我同意@Christo。你并不总是有awt 供你使用。 这并不理想,因为 Polygon.contains() 支持任何类型的多边形,因此,与此处在其他答案中提供的其他手动(但简单)解决方案相比,该算法更加复杂和繁重。此外,awt 并不是 Java 开发人员通常会疯狂使用的一组类。【参考方案4】:

您可以使用点多边形测试。

这很简单。从你的点到东画一条足够大的距离。计算该线与您的 plygon 相交的次数。如果它是偶数,你的点在外面,如果是奇数,它在里面。

这适用于任何类型的多边形。

【讨论】:

如果您使用此方法,请确保处理边缘情况 - 两条平行线可以有无限多的交点。【参考方案5】:

主要问题是您是否可以为此使用 2D 近似值(换句话说,您的三角形是否足够小)。

如果是这样,像重心坐标这样简单的东西会很好用。

【讨论】:

棘手的一点是,当它是嵌入在 3d 球体上的 2d 空间时,三角形的边缘不是线,它们是大弧线。从技术上讲你仍然可以使用重心坐标,但是距离函数不同,你必须处理周期性,这只是一个巨大的麻烦。您想要的答案与大三角形或放置不便的三角形的二维三角形答案不完全匹配。【参考方案6】:

试试光线投射算法。

http://en.wikipedia.org/wiki/Point_in_polygon

实现起来非常简单。

【讨论】:

【参考方案7】:
function SameSide(p1,p2, a,b)
    cp1 = CrossProduct(b-a, p1-a)
    cp2 = CrossProduct(b-a, p2-a)
    if DotProduct(cp1, cp2) >= 0 then return true
    else return false

function PointInTriangle(p, a,b,c)
    if SameSide(p,a, b,c) and SameSide(p,b, a,c)
        and SameSide(p,c, a,b) then return true
    else return false

在下面的链接中解释

http://www.blackpawn.com/texts/pointinpoly/default.html

【讨论】:

这个例子中有太多的“魔法”。 CrossProduct 永远不会被解释。【参考方案8】:

我今天做了这样的事情!还有(lat,lon),实际上是(theta,phi),虽然我对我正在使用的网格了解更多。我正在使用 (theta, phi) 0

如果其中一个顶点位于球体的顶部或底部,您会发现您可能会遇到一些麻烦,因为在我的例子中 phi 并没有真正定义。你最终会得到一个奇点。你基本上得到了一个正方形,这样更容易检查你的点是否在它里面。

在所有其他情况下,如果您已将点转换为 (lat, lon) / (theta, phi)。使用@Michelle Six 所描述的方法应该很简单。

【讨论】:

以上是关于确定一个点是不是在由具有给定纬度/经度的 3 个点组成的三角形内的主要内容,如果未能解决你的问题,请参考以下文章

如何使用python在给定纬度和经度周围确定网格数据库中的4个最近相邻点

如何找到给定纬度/经度以北 x 公里的纬度/经度?

给定初始纬度 lng,距离和方位角,在 php 中查找纬度经度点

检查多边形内部或外部的一个点(纬度,经度)

如何找到给定纬度/长度以北x km的纬度/经度?

查找一个点(纬度,经度)是不是在 OpenStreetMaps“方式”(区域)内