多边形扩展算法



本文很多内容主要来自博客 http://blog.csdn.net/happy__888/archive/2005/03/09/315762.aspx 

但原文是用swift 语言写的, 并不怎么好懂。原文内容是深刻的,我学习了swift 语言, 还有矢量积算法,终于明白了他的内容,

然后改写了我熟悉的c++ 语言。


文章的组织是原文内容,因为他对算法的描述很到位。然后包含一些我的解说,最后是我的c++程序。


给定一个简单多边形,多边形按照顺时针或者逆时针的数许排列

内部等距离缩小或者外部放大的多边形,实际上是由距离一系列平行已知多边形的边,并且距离为L的线段所构成的。


外围的是原多边形,内侧是新的多边形

算法构造

多边形的相邻两条边,L1和L2,交于Pi点

做平行于L1和L2,平行线间距是L的,并且位于多边形内部的两条边,交于Qi

我们要计算出Qi的坐标

如图,


PiQi向量,显然是等于平行四边形的两个相邻边的向量v1和v2的和的

v1和v2向量的方向,就是组成多边形的边的方向,可以用顶点差来表示

v1和v2向量的长度是相同的,等于平行线间距L与两个线段夹角的sin值的除法。

即: Qi = Pi + (v1 + v2)

    Qi = Pi + L / sinθ * ( Normalize(v2) + Normalize(v1))

    Sin θ = |v1 × v2 | /|v1|/|v2|

计算步骤:

⑴、获取多边形顶点数组PList;

⑵、计算DPList[Vi+1-Vi];

⑶、单位化NormalizeDPList,得到NDP[DPi];(用同一个数组存储)

⑷、Sinα = Dp(i+1) X DP(i);

⑸、Qi = Pi + d/sinα (NDPi+1-NDPi)

⑹、这样一次性可以把所有顶点计算完。

注意,交换Qi表达式当中NDPi+1-NDPi的顺序就可以得到外部多边形顶点数组。


在原文中,最不好理解的是(4) 矢量积的算法

我查找了资料,AxB =|A|x|B|x sin(sita) 也就是平行四边形的面积。

原文是用swift 语言写的,apple 的一种语言,特棒,但一直找不到语言开发调试的环境,原文的语言就是swift.

如果你想看swift 版本,就去看原文吧。

我这里附上的c++语言。


//Point2D 的类定义,也包括运算符重构

class Point2D  {

 public:
 float x;
 float y;

    Point2D()
 {
  x=0;y=0;
 }

 Point2D(float x, float y)
 {
  this->x=x;this->y=y;
 }

 friend Point2D operator +(Point2D a, Point2D b)
 {
  Point2D p;
  p.x=a.x+b.x;
  p.y=a.y+b.y;
  return p;
 };

 friend Point2D operator -(Point2D a, Point2D b)
 {
  Point2D p;
  p.x=a.x-b.x;
  p.y=a.y-b.y;
  return p;
 };

 friend float operator *(Point2D a, Point2D b)
 {
  float p=a.x*b.x+a.y*b.y;
  return p;
 };

 friend Point2D operator *(Point2D a, float value)
 {
  Point2D p;
  p.x=a.x*value;
  p.y=a.y*value;
  return p;
 };

 friend float xlJi(Point2D a, Point2D b)
 {
  float p=((a.x)*(b.y))-((a.y)*(b.x));
  return p;
 };

};


//测试程序

int main()

{
 std::vector pList;
 std::vector DpList;
 std::vector nDpList;
 std::vector newList;

 Point2D  p2d,p2;
 //p2d.x=0;p2d.y=0;pList.push_back(p2d);
 //p2d.x=0;p2d.y=100;pList.push_back(p2d);
 //p2d.x=100;p2d.y=100;pList.push_back(p2d);
 //p2d.x=50;p2d.y=50;pList.push_back(p2d);
 //p2d.x=100;p2d.y=0;pList.push_back(p2d);
//--注释的是原文数据,我这里把数据的顺序反了一下
 p2d.x=0;p2d.y=0;pList.push_back(p2d);
 p2d.x=100;p2d.y=0;pList.push_back(p2d);
 p2d.x=50;p2d.y=50;pList.push_back(p2d);
 p2d.x=100;p2d.y=100;pList.push_back(p2d);
 p2d.x=0;p2d.y=100;pList.push_back(p2d);
 
 
 
//-------------------------------------------

 int i,index,count;
 count=pList.size();
 for(i=0;i  {
  index=(i+1)%count;
  p2d=pList[index]-pList[i];
  DpList.push_back(p2d);
 }
 // 初始化ndpList,单位化两顶点向量差
 float r;
 for(i=0;i  {
  r=sqrt(DpList[i]*DpList[i]);
  r=1/r;
  p2d=DpList[i]*r;
  nDpList.push_back(p2d);
 }

 
 // 计算新顶点, 注意参数dist为负是向内收缩, 为正是向外扩张
 //上述说法只是对于顺时针而言
 //我把数据改为逆时针,结论刚好相反
 float lenth;
 float dist=5;
 int startindex,endindex;
 for(i=0;i  {
  startindex= i==0?count-1:i-1;
  endindex=i;
  float sina=xlJi(nDpList[startindex],nDpList[endindex]);
  lenth=dist/sina;
  p2d=nDpList[endindex]-nDpList[startindex];
  p2=pList[i]+p2d*lenth;
  newList.push_back(p2);
  TRACE(" %.1f,%.1f\n",p2.x,p2.y);
 }

 return 0;
}




你可能感兴趣的:(c++)