如何在 N 时间内确定一个点是不是在 2D 凸多边形内

Posted

技术标签:

【中文标题】如何在 N 时间内确定一个点是不是在 2D 凸多边形内【英文标题】:How to determine whether a point is inside a 2D convex polygon in faster than N time如何在 N 时间内确定一个点是否在 2D 凸多边形内 【发布时间】:2014-01-13 15:32:11 【问题描述】:

我知道用于查找点是否在任何多边形内的标准光线投射算法。但是,如果您将自己限制在一个凸多边形上,是否有更快的方法?

【问题讨论】:

【参考方案1】:

是的,您可以使用二进制搜索。为此,您可以递归地将多边形切割成其大小的一小部分(即一半)并检查您在哪一边。例如,您可以首先检查您是在通过顶点 0 和顶点 n/2 的线上的正侧还是负侧。有了 3 个顶点后,您只需对剩余的两条边进行测试,完成对那个三角形的测试。

这里有一些伪代码,希望能更容易理解:

function TestConvexPolygon(point, polygon)
  if polygon.size == 3 then
    return TestTriangle(point, polygon) // constant time

  if (TestLine(point, polygon[0], polygon[polygon.size/2]) > 0)
    return TestConvexPolygon(point, new polygon from polygon.size/2 to polygon.size-1 and 0)
  else
    return TestConvexPolygon(point, new polygon from 0 to polygon.size/2)

另一种可视化想法的方法是,您可以将多边形视为三角形扇形。然后,您首先测试您的点与中间内部边缘。这将从风扇中消除一半可能的三角形。由于半个三角形扇形仍然是三角形扇形,因此您可以递归地执行此操作,直到扇形中只剩下一个三角形,然后显式测试。

真正的实现需要一些索引杂耍,但其他方面则简单且健壮。

【讨论】:

我对你的算法有些困惑。顶点0是最左边的顶点吗?顶点是中间顶点吗?一旦你有3个顶点,你是什么意思?如何选择顶点? 您实际选择哪个顶点并不重要,唯一重要的是您可以“切断”大约一半的多边形。请注意,您只关心顶点的数量,而不是面积。该示例仅假设您的顶点编号从 0 到 n-1。这是有效的,因为从任何一个顶点到任何其他顶点的线会将多边形切割成两个凸多边形,并且您可以在恒定时间内决定您必须继续查看两个中的哪一个。【参考方案2】:

正如答案所述,该算法是递归的。在每一步中,您都切断了该点不能位于的多边形部分。这是一段 C++ 代码:

#include "stdafx.h"
#include <vector>
#include <iostream>

struct vec2d 
    double x, y;
    vec2d(double _x, double _y) : x(_x), y(_y) 
;

// Finds the cross product of the vectors: AB x BC
double crossProduct(vec2d pointA, vec2d pointB, vec2d pointC) 
    vec2d vectorAB = vec2d(pointB.x - pointA.x, pointB.y - pointA.y);
    vec2d vectorBC = vec2d(pointC.x - pointB.x, pointC.y - pointB.y);

    return vectorAB.x * vectorBC.y - vectorBC.x * vectorAB.y;


// Finds area for the triangle ABC
double S(vec2d A, vec2d B, vec2d C) 
    return crossProduct(A, B, C) / 2;


bool isPointInsideTriangle(vec2d A, vec2d B, vec2d C, vec2d point)

    return S(A, B, point) >= 0 && S(B, C, point) >= 0 && S(C, A, point) >= 0;


bool isPointAboveLine(vec2d A, vec2d B, vec2d point)

    return S(A, B, point) >= 0;


// O(logN), works only for convex polygons
bool isPointInsidePolygon(std::vector<vec2d> polygon, vec2d point) 
    if (polygon.size() == 3) 
        return isPointInsideTriangle(polygon[0], polygon[1], polygon[2], point);
    

    if (isPointAboveLine(polygon[0], polygon[polygon.size() / 2], point)) 
        std::vector<vec2d> polygonAbove(polygon.begin() + polygon.size() / 2, polygon.end());
        polygonAbove.emplace(polygonAbove.begin(), polygon[0]);
        return isPointInsidePolygon(polygonAbove, point);
    
    else 
        std::vector<vec2d> polygonBelow(polygon.begin(), polygon.begin() + polygon.size() / 2 + 1);
        return isPointInsidePolygon(polygonBelow, point);
    


int main()

    std::vector<vec2d> convexPolygon;
    convexPolygon.push_back(vec2d(0, 2));
    convexPolygon.push_back(vec2d(2, 0));
    convexPolygon.push_back(vec2d(4, 1));
    convexPolygon.push_back(vec2d(6, 3));
    convexPolygon.push_back(vec2d(6, 4));
    convexPolygon.push_back(vec2d(5, 6));
    convexPolygon.push_back(vec2d(2, 6));
    convexPolygon.push_back(vec2d(1, 4));
    std::cout << isPointInsidePolygon(convexPolygon, vec2d(2, 5));

    return 0;

【讨论】:

以上是关于如何在 N 时间内确定一个点是不是在 2D 凸多边形内的主要内容,如果未能解决你的问题,请参考以下文章

确定给定点是不是在多边形内

确定一个点是不是位于传单多边形内

如何判断一个指定的经纬度点是不是落在一个多边形区域内

确定点是不是在多边形内

如何判断一个指定的经纬度点是不是落在一个多边形区域内

MKPolygon - 如何确定 CLLocationCoordinate2D 是不是在 CLLocationCoordinate2D 多边形中?