zoukankan      html  css  js  c++  java
  • 求多边形凸包(线性算法)--陈氏凸包算法--

    http://blog.sina.com.cn/s/blog_616e189f0100qc0u.html

    陈氏凸包算法算法参考:Computing the convex hull of a simple polygon 作者:Chern-Lin Chen

    陈氏算法提供了一个线性效率求凸包的算法,本文使用VS2008对算法进行了测试,论文中有很多错误的地方,大家可以参考源码进行更正。话不多说,大家请看源码,和运行效果。

    作者对原算法的错误处进行了校正,可以作为大家学习参考使用,如果在公共场合使用本资源和算法更正的内容请标明出处,并及时与作者取得联系。未经允许不得以任何形式在公共场合(包括论文)中使用或模仿本算法。版权归作者所有(中国石油大学(华东)QQ531961673)。

    本文算法更改和实现都是本人个人完成,如有转载或使用,请标明出处,并与作者取得联系,谢谢。

     

    #pragma once

    #include <vector>

    #include <deque>

    #include <algorithm>

    #include <cstddef>

    #include <cmath>

    #include<functional>

     

    using std::vector;

    using std::deque;

     

     

    class covexHull

    {

    public:

         covexHull(void);

         ~covexHull(void);

     

         void compute();//凸多边形计算的入口

         void draw(CClientDC & dc );//绘制凸多边形

         void addPoint(const CPoint &point);//添加计算的节点

     

    private:

         class PointAndAngle{//内部类,用于临时过程的处理(用于计算简单多边形)

         public:

             CPoint point;

             double angle;

             bool operator < (const PointAndAngle & p1)const{//小于运算符重载,用于排序

                  return angle < p1.angle;

             }

         };

     

         std::vector<CPoint>::iterator findLeftPoint();//找到最左边的点

         int computeS(const CPoint & p1, const CPoint &p2, const CPoint &p3)const;//计算S

         void computeSimplePolygon();//计算简单多边形

         void computeCovexHull();//计算凸多边形

    private:

     

         vector<CPoint> m_points;//点集合(无序)

         deque<PointAndAngle> m_pointAndAngle;//简单多边形排序后点集合(有序)

         deque<CPoint> m_stack;//凸多边形点集合(有序)

        

    };

     

     

    实现部分:

    #include "StdAfx.h"

    #include "covexHull.h"

     

    covexHull::covexHull(void)

    {

    }

     

    void covexHull::addPoint(const CPoint &point)

    {

         m_points.push_back(point);

    }

     

    inline vector<CPoint>::iterator covexHull:: findLeftPoint()

    {       

         //最左边的点,就是x的值最小的点

         std::vector<CPoint>::iterator ret = m_points.begin();

         for(std::vector<CPoint>::iterator it = m_points.begin() ; it != m_points.end() ; ++it)

         {

             if(it->x < ret->x)

                  ret = it;

         }

         return ret;

    }

     

    void covexHull::draw(CClientDC & dc)

    {

         //先绘制所有的点

         for(vector<CPoint>::iterator it = m_points.begin() ; it != m_points.end() ; ++it)

         {

             dc.Ellipse(it->x-3, it->y-3, it->x+3, it->y+3);

         }

         //绘制简单多边形

         {

             deque<PointAndAngle>::iterator it =  m_pointAndAngle.begin();

             if(it != m_pointAndAngle.end())//防止列表为空

                  dc.MoveTo(it->point.x,it->point.y);

             for(; it!= m_pointAndAngle.end() ; ++it)

             {

                  dc.LineTo(it->point.x,it->point.y);

             }

             if(m_pointAndAngle.size() != 0)//防止列表为空

                  dc.LineTo(m_pointAndAngle.begin()->point.x,m_pointAndAngle.begin()->point.y);

         }

         //绘制凸多边形

         {

             CPen * oldPen;

             CPen * newPen = new CPen(PS_SOLID,1,RGB(255,0,0));//更改画笔颜色

             oldPen = dc.SelectObject(newPen);

     

             deque<CPoint>::iterator it =  m_stack.begin();

             if(it != m_stack.end())

                  dc.MoveTo(it->x,it->y);

             for(; it!= m_stack.end() ; ++it)

             {

                  dc.LineTo(it->x,it->y);

             }

             if(m_stack.size() != 0)

                  dc.LineTo(m_stack.begin()->x,m_stack.begin()->y);

     

             dc.SelectObject(&oldPen);

             delete newPen;

         }

     

    }

     

    void covexHull::compute()

    {

         computeSimplePolygon();//先计算简单多边形

         computeCovexHull();//计算凸多边形

    }

     

    void covexHull::computeSimplePolygon()

    {

         m_pointAndAngle.clear();

         vector<CPoint>::iterator it = findLeftPoint();//先找到最左侧的点

     

         CPoint point(it->x,it->y);//将这个点保存下来

     

         m_points.erase(it);//将最左侧的点从列表中删除(因为这个点自身求角度无意义)

     

         PointAndAngle paa;

         for(vector<CPoint>::iterator i = m_points.begin() ; i != m_points.end() ; ++i)//计算所有点与最左侧点的角度

         {

             paa.point = *i;

             if(i->x - point.x == 0)//要先判断除数为的情况

             {

                  if(i->y > point.y)

                       paa.angle = 90.0/360.0*atan(1.0)*4;//PI = atan(1.0)*4

                  else

                       paa.angle = -90.0/360.0*atan(1.0)*4;

             }

             else

                  paa.angle = atan(double(double(i->y - point.y)/double(i->x - point.x)));//计算角度

             m_pointAndAngle.push_back(paa);//放入简单多变行容器

         }

     

         std::sort(m_pointAndAngle.begin(),m_pointAndAngle.end());//按照角度从小到大排序

         paa.point = point;

         m_pointAndAngle.push_front(paa);//最后将最左侧的点放入集合

         m_points.push_back(point);//将最左侧点放入点集合

        

    }

     

    int covexHull::computeS(const CPoint & p1, const CPoint &p2, const CPoint &p3)const

    {

         return (p3.x - p1.x)*(-p2.y + p1.y) - (-p3.y + p1.y)*(p2.x - p1.x);//计算S,注意实际坐标系与屏幕坐标系之间的转换

    }

     

    void covexHull::computeCovexHull()

    {

         m_stack.clear();

     

         if(m_pointAndAngle.size() < 3)//当小于个点,就不用计算了

             return;

         m_stack.push_front(m_pointAndAngle.at(0).point);//先将前两个点放入栈中

         m_stack.push_front(m_pointAndAngle.at(1).point);

     

         deque<PointAndAngle>::iterator it = m_pointAndAngle.begin() + 2;//迭代器先要移动两个位置(因为那两个位置已经放入栈中了)

     

         for(;it != m_pointAndAngle.end() ;)//迭代求解

         {

             if(computeS(m_stack.at(1),m_stack.at(0),it->point) > 0)//S大于,此时点在直线的右侧

             {

                  if(computeS(m_stack.back(),m_stack.front(),it->point) > 0)//S大于,将点压入栈中,否则不压入(不进栈,迭代器移动,相当于reject

                  {

                       m_stack.push_front(it->point);

                  }

                  ++it;//迭代器移动

             }else//S小于说明点在直线左侧,当前栈顶肯定不是凸点

             {

                  m_stack.pop_front();//弹出栈顶

                  if(m_stack.size() < 2)//栈内元素太少,将当前点直接填入栈中

                       m_stack.push_front(it->point);

                  //注意这里迭代器并没有移动

             }

         }

        

    }

     

     

    covexHull::~covexHull(void)

    {

    }

    测试效果:

    求多边形凸包(线性算法)--陈氏凸包算法--Computing <wbr>the <wbr>convex <wbr>hull <wbr>of <wbr>a <wbr>simple <wbr>polygon(源码)

    完整源码:http://guanxinquan.download.csdn.net/上下载

  • 相关阅读:
    MongoDB 之 手把手教你增删改查 MongoDB
    MongoDB 之 你得知道MongoDB是个什么鬼 MongoDB
    全栈12期的崛起之捡点儿有用的说说
    Python 常用模块
    Python3中的内置函数
    Python程序员之面试必回习题
    Django之初始庐山真面目
    Django之ORM操作
    MySQL-索引
    MySQL-函数
  • 原文地址:https://www.cnblogs.com/kex1n/p/3305786.html
Copyright © 2011-2022 走看看