📜  检查给定点是否在凸多边形的给定N点内

📅  最后修改于: 2021-04-29 08:16:51             🧑  作者: Mango

给定凸多边形N个点的坐标。任务是检查给定点(X,Y)是否位于多边形内。

例子:

方法:想法是使用Graham扫描算法来查找给定点是否位于凸多边形内。以下是一些观察结果:

  • 假设点(X,Y)是凸多边形的一组点中的一个点。如果在这组点上使用Graham扫描算法,则将获得另一组点,它们构成了凸包。
  • 如果点(X,Y)位于多边形内,则它不会位于凸包上,因此不会出现在凸包的新生成的点集中。
  • 如果点(X,Y)位于多边形外部,则它将位于形成的凸包上,因此将出现在新生成的凸包点集中。

以下是解决问题的步骤:

  1. 将给定点和查询点按其横坐标值的升序排序。如果任意两点的横坐标值(x坐标)相同,则根据其纵坐标值对它们进行排序。
  2. 设置左下点作为开始点和右上点作为凸包的终点
  3. 遍历所有点并找出这些点,形成凸多边形,该多边形位于顺时针方向的起点和终点之间。将这些点存储在向量中。
  4. 遍历所有点,找出点,形成凸多边形,该多边形位于逆时针方向的起点和终点之间。将这些点存储在向量中。
  5. 检查查询点是否在向量中,然后该点位于凸包之外。因此,返回“否”
  6. 如果矢量中不存在该点,则该点位于凸包打印“是”内部

以下是基于上述方法的实现:

// C++ program for the above approach
#include 
using namespace std;
  
// Sorting Function to sort points
bool cmp(pair& a,
         pair& b)
{
  
    if (a.first == b.first)
        return a.second < b.second;
    return a.first < b.first;
}
  
// Function To Check Clockwise
// Orientation
int cw(pair& a,
       pair& b,
       pair& c)
{
  
    int p = a.first * (b.second - c.second)
            + b.first * (c.second - a.second)
            + c.first * (a.second - b.second);
  
    return p < 0ll;
}
  
// Function To Check Counter
// Clockwise Orientation
int ccw(pair& a,
        pair& b,
        pair& c)
{
  
    int p = a.first * (b.second - c.second)
            + b.first * (c.second - a.second)
            + c.first * (a.second - b.second);
  
    return p > 0ll;
}
  
// Graham Scan algorithm to find Convex
// Hull from given points
vector > convexHull(
    vector >& v)
{
    // Sort the points
    sort(v.begin(),
         v.end(), cmp);
  
    int n = v.size();
    if (n <= 3)
        return v;
  
    // Set starting and ending points as
    // left bottom and top right
    pair p1 = v[0];
    pair p2 = v[n - 1];
  
    // Vector to store points in
    // upper half and lower half
    vector > up, down;
  
    // Insert StartingEnding Points
    up.push_back(p1);
    down.push_back(p1);
  
    // Iterate over points
    for (int i = 1; i < n; i++) {
  
        if (i == n - 1 || !ccw(p1, v[i], p2)) {
  
            while (up.size() > 1
                   && ccw(up[up.size() - 2],
                          up[up.size() - 1],
                          v[i])) {
  
                // Exclude this point
                // if we can form better
  
                up.pop_back();
            }
  
            up.push_back(v[i]);
        }
  
        if (i == n - 1 || !cw(p1, v[i], p2)) {
  
            while (down.size() > 1
                   && cw(down[down.size() - 2],
                         down[down.size() - 1],
                         v[i])) {
  
                // Exclude this point
                // if we can form better
                down.pop_back();
            }
            down.push_back(v[i]);
        }
    }
  
    // Combine upper and  lower half
    for (int i = down.size() - 2;
         i > 0; i--)
        up.push_back(down[i]);
  
    // Remove duplicate points
    up.resize(unique(up.begin(),
                     up.end())
              - up.begin());
  
    // Return the points on Convex Hull
    return up;
}
  
// Function to find if point lies inside
// a convex polygon
bool isInside(vector > points,
              pair query)
{
    // Include the query point in the
    // polygon points
    points.push_back(query);
  
    // Form a convex hull from the points
    points = convexHull(points);
  
    // Iterate over the points
    // of convex hull
    for (auto x : points) {
  
        // If the query point lies
        // on the convex hull
        // then it wasn't inside
        if (x == query)
            return false;
    }
  
    // Otherwise it was Inside
    return true;
}
  
// Driver Code
int main()
{
  
    // Points of the polygon
    // given in any order
    int n = 7;
    vector > points;
  
    points = { { 1, 1 }, { 2, 1 }, { 3, 1 },
               { 4, 1 }, { 4, 2 }, { 4, 3 },
               { 4, 4 } };
  
    // Query Points
    pair query = { 3, 2 };
  
    // Check if its inside
    if (isInside(points, query)) {
        cout << "YES" << endl;
    }
    else {
        cout << "NO" << endl;
    }
  
    return 0;
}
输出:
YES

时间复杂度: O(N * log(N))
辅助空间: O(N)