【问题标题】:How to check if a circle is "outside" of a polygon?如何检查一个圆是否在多边形的“外部”?
【发布时间】:2021-09-12 05:47:05
【问题描述】:

我正在尝试编写一个函数来检查一个圆是否包含在一个多边形内。

我的算法是:

if they intersect, return false

if the circle is "outside" of the polygon, return false

return true

在外面,我的意思是这样的:

我考虑在圆心和多边形中心之间创建一条线段,如果它们与多边形上的一条边相交,那么圆就在多边形之外。 但是还有其他方法吗?

【问题讨论】:

  • 你如何定义/找出“多边形的中心”?你知道如何编写一个函数来告诉你一个点是否在多边形内吗?

标签: math geometry


【解决方案1】:

您有一个由点列表定义的多边形A0, A1, A2, ..., Ak,以及一个由中心C 和半径r 定义的圆。

可能的算法:

  1. 判断中心C是否在多边形内;
  2. 如果C 在多边形之外,返回 False
  3. 否则,在多边形上找到最接近圆心C的点P
  4. 比较距离PC和半径r
  5. 返回布尔值r < PC

这给我们留下了两个要解决的子问题:

  • 如何判断点C是否在多边形内;
  • 如何找到多边形上最近的点。

解决这些子问题的相关问题:

【讨论】:

    【解决方案2】:
    1. 如果圆心在多边形内部,则圆要么重叠,要么在多边形内部。
    2. 如果多边形的任何点位于圆上或圆内,则它们是重叠的。
    3. 如果多边形的任何线段与圆相交,则它们是重叠的。
    4. 否则圆在多边形之外。

    这样的东西应该可以工作(C++):

    #include <iostream>
    #include <vector>
    #include <cmath>
    
    namespace math
    {
    
    struct Point
    {
        int x;
        int y;
    };
    
    bool PointInCircle(Point p, Point center, std::size_t radius)
    {
        return ((p.x - center.x) * (p.x - center.x) + (p.y - center.y) * (p.y - center.y)) < (radius * radius);
    }
    
    bool PointOnCircle(Point p, Point center, std::size_t radius)
    {
        return ((p.x - center.x) * (p.x - center.x) + (p.y - center.y) * (p.y - center.y)) == (radius * radius);
    }
    
    bool LineIntersectsCircle(int ax, int by, int c, Point center, std::size_t radius)
    {
        // radius == distance = touching/tangent
        // radius > distance = not intersecting
        // radius < distance = intersecting
        int distance = (std::abs(ax * center.x + by * center.y + c)) / sqrt(ax * ax + by * by);
        return distance <= radius;
    }
    
    bool PointInPolygon(Point p, std::vector<Point> poly)
    {
        bool result = false;
        
        std::size_t j = poly.size();
        for (std::size_t i = 0; i < poly.size(); ++i)
        {
            if (((poly[i].y <= p.y && p.y < poly[j].y) || (poly[j].y <= p.y && p.y < poly[i].y))
                &&
                p.x < ((poly[j].x - poly[i].x) * (p.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x))
            {
                 result = !result;
            }
    
            j = i;
        }
        return result;
    }
    
    bool CircleInsidePolygon(Point center, std::size_t radius, std::vector<Point> poly)
    {
        // Circle with radius 0 isn't a circle
        if (radius == 0)
        {
            return false;
        }
        
        // If the center of the circle is not within the polygon,
        // then the circle may overlap, but it'll never be "contained"
        // so return false
        if (!PointInPolygon(center, poly))
        {
            return false;
        }
        
        for (std::size_t i = 0; i < poly.size(); ++i)
        {
            // If any point of the polygon is within the circle,
            // the circle is not "contained"
            // so return false
            if (PointInCircle(poly[i], center, radius))
            {
                return false;
            }
        }
        
        for (std::size_t i = 0; i < poly.size(); ++i)
        {
            // If any line-segment of the polygon intersects the circle,
            // the circle is not "contained"
            // so return false
            
            Point P1 = i == 0 ? poly[0] : poly[i];
            Point P2 = i == 0 ? poly[poly.size() - 1] : poly[i + 1];
            
            int X1 = P1.x;
            int X2 = P2.x;
            int Y1 = P1.y;
            int Y2 = P2.y;
            
            int A = Y1 - Y2;
            int B = X2 - X1;
            int C = (X1 * Y2) - (X2 * Y1);
            
            if (LineIntersectsCircle(A, B, C, center, radius))
            {
                return false;
            }
        }
        
        return true;
    }
    
    bool CircleOutsidePolygon(Point center, std::size_t radius, std::vector<Point> poly)
    {
        // Circle with radius 0 isn't a circle
        if (radius == 0)
        {
            return false;
        }
        
        // If the center of the circle is within the polygon,
        // the circle is not outside of the polygon completely.
        // so return false.
        if (PointInPolygon(center, poly))
        {
            return false;
        }
        
        for (std::size_t i = 0; i < poly.size(); ++i)
        {
            // If any point of the polygon is within the circle,
            // or any point of the polygon lies on the circle,
            // the circle is not outside of the polygon
            // so return false.
            if (PointInCircle(poly[i], center, radius) || PointOnCircle(poly[i], center, radius))
            {
                return false;
            }
        }
        
        for (std::size_t i = 0; i < poly.size(); ++i)
        {
            // If any line-segment of the polygon intersects the circle,
            // the circle is not outside the polygon, it is overlapping,
            // so return false
            
            Point P1 = i == 0 ? poly[0] : poly[i];
            Point P2 = i == 0 ? poly[poly.size() - 1] : poly[i + 1];
            
            int X1 = P1.x;
            int X2 = P2.x;
            int Y1 = P1.y;
            int Y2 = P2.y;
            
            int A = Y1 - Y2;
            int B = X2 - X1;
            int C = (X1 * Y2) - (X2 * Y1);
            
            if (LineIntersectsCircle(A, B, C, center, radius))
            {
                return false;
            }
        }
        
        return true;
    }
    
    }
    
    int main()
    {
        std::size_t radius = 1;
        math::Point p = {-2, -2};
        
        std::vector<math::Point> poly = {
            {0, 0},
            {100, 0},
            {100, 100},
            {0, 100}
        };
        
        bool is_inside = math::CircleInsidePolygon(p, radius, poly);
        bool is_outside = math::CircleOutsidePolygon(p, radius, poly);
        bool is_intersecting = !is_inside && !is_outside;
        
        std::cout<<"Circle In Polygon: "<<std::boolalpha<<is_inside<<"\n";
        std::cout<<"Circle Outside Polygon: "<<std::boolalpha<<is_outside<<"\n";
        std::cout<<"Circle Intersecting Polygon: "<<std::boolalpha<<is_intersecting<<"\n";
        
        return 0;
    }
    

    【讨论】:

    • 对于您的第 1 点和第 2 点,圆圈也可能围绕多边形。
    • @JosephSible-ReinstateMonica 我正在代码中检查 :)。 // If any point of the polygon is within the circle
    • 不过,您的代码上方的列表似乎忽略了这一点。
    猜你喜欢
    • 1970-01-01
    • 2019-03-11
    • 2019-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 2017-04-29
    • 2018-03-09
    相关资源
    最近更新 更多