zoukankan      html  css  js  c++  java
  • inPolygonTest学习和C++实现

    大家好,我是小鸭酱,博客地址为:http://www.cnblogs.com/xiaoyajiang  
    此篇博客实现了判定平面一点是否在给定多边形内部的功能。精确,性能优良,因为只包含加法和乘法运算,效率极高。
    实现的C++源码如下,注意点在源码的相应注释中。
    有错误和不好的地方还望各位批评指正。
     
    #include<iostream>
    using namespace std;
     
    struct Point2f  // 用以进行简单测试的结构。opencv中也有同名的数据类型,注意其x和y与我们想的不一样。
    {
        double x;
        double y;
    };
     
    bool onPolygonTest(Point2f polygon[], int num, Point2f test_point);  // 用以测试在多边形边上的退化情况
    bool onLineTest(Point2f p, Point2f q, Point2f s);  // 用以测试在边上的退化情况
    bool inPolygonTest(Point2f polygon[], int num, Point2f test_point);  // 一般情况
    bool toLeftTest(Point2f p, Point2f q, Point2f s);  // 核心技术
    double Area2(Point2f p, Point2f q, Point2f s);  // 核心技术实现
    /*----------------------------------------------------------------------*/
    /*   函数bool isInner(Point2f [], int num, Point2f, bool)               */
    /*   输入                                                                                 */
    /*         参数1 多边形顶点: Point2f polygon[]                             */
    /*         参数2 多边形顶点个数                                                    */
    /*         参数3 测试点:Point2f test_point                                   */
    /*         参数4 是否包含边上的点:bool isIncludeLine                    */
    /*   输出                                                                                */
    /*         true:在多边形内;                                                      */
    /*         false:不在多边形内                                                     */
    /*  作者:小鸭酱的书签                                                            */ 
    /*  日期:2016年9月28日                                                        */ 
    /*--------------------------------------------------------------------*/
    bool isInner(Point2f polygon[], int num, Point2f test_point, bool isIncludeLine)  
    {
        if(num < 3)
            return false;
        if (isIncludeLine)  // 首先判断退化情况
            return (onPolygonTest(polygon, num, test_point) || inPolygonTest(polygon, num, test_point));
        else  // 一般情况
            return inPolygonTest(polygon, num, test_point);
    }
     
    bool onPolygonTest(Point2f polygon[], int num, Point2f test_point)  // 只要点在任意一条边上,都算作在内部
    {
        int sum = 0;
        int i = 0;
        for(; i < num - 1; ++i)
        {
            sum += onLineTest(polygon[i], polygon[i+1], test_point);
            if (sum > 0)
                return true;
        }
        sum += onLineTest(polygon[i], polygon[0], test_point);
        return sum > 0;
    }
    bool onLineTest(Point2f p, Point2f q, Point2f s)  // 处理退化情况,判断点是否在线上;这里只处理多边形是没有旋转的矩形的情况。后期更新任意线段
    {
        if(p.x == q.x && q.x == s.x && (s.y - p.y) * (s.y - q.y) <= 0 )
            return true;
        else if(q.y == p.y && p.y == s.y && (s.x - p.x) * (s.x - q.x) <= 0 )
            return true;
        else
            return false;
    }
     
    bool inPolygonTest(Point2f polygon[], int num, Point2f test_point)  // 根据点在每条边的left或者right的pattern来判断是否在内部
    {
        int sum = 0;  // 用以记录有多少个left的pattern
        int i = 0;
        for(; i < num - 1; ++i)
        {
            sum += toLeftTest(polygon[i], polygon[i+1], test_point);
        }
        sum += toLeftTest(polygon[i], polygon[0], test_point);
     
        return (sum == 0 || sum == num) ? true : false;  // 很显然,当点在多边形的每条有向边的right或者left,它才会在内部
    }
     
    bool toLeftTest(Point2f p, Point2f q, Point2f s)  // 主要技术。有向面积值大于0则在有向边的左边
    {
        return Area2(p, q, s) > 0;
    }
     
    double Area2(Point2f p, Point2f q, Point2f s)  // 可见其只包含加法和乘法运算,计算给定点和多边形的一条有向边所组成的三角形的2倍面积,我们是要使用其符号来判断在左边还是右边
    {
     
        return
        p.x * q.y - p.y * q.x
        + q.x * s.y - q.y * s.x
        + s.x * p.y - s.y * p.x;
     
    }
     
    int main()                  // test
    {
        Point2f polygon[4];
        polygon[0].x = 0;
        polygon[0].y = 0;
        polygon[1].x = 2;
        polygon[1].y = 0;
        polygon[2].x = 2;
        polygon[2].y = 1;
        polygon[3].x = 0;
        polygon[3].y = 1;
        Point2f test_point;
     
        test_point.x = 0;
        test_point.y = 2;
        int n = sizeof(polygon) / sizeof(Point2f);
        cout << "in = " << inPolygonTest(polygon, n, test_point) << endl;
        cout << "online = " << onPolygonTest(polygon, n, test_point) << endl;
        cout << "output = " << isInner(polygon, n, test_point, false) << endl;
        cout << n << endl << endl;
     
        return 0;
    }
  • 相关阅读:
    “菜鸟”程序员和“大神”程序员差距在哪里?别告诉我你连菜鸟都不算!
    Android开发:为什么你的学习效率如此低,为什么你很迷茫?
    Android架构师吐槽腾讯王者荣耀的程序员,排位匹配算法怎么搞的,每次都输
    程序员如何回答面试官“请介绍一下自己”这类问题
    Android程序员事件分发机制学习笔记
    面试时,问哪些问题能试出一个 Android 应用开发者真正的水平?
    List、Set、Map的区别
    在Eclipse中使用JUnit4进行单元测试(图文教程一)
    1
    2016、11、17
  • 原文地址:https://www.cnblogs.com/xiaoyajiang/p/5950091.html
Copyright © 2011-2022 走看看