本文很多内容主要来自博客 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
std::vector
std::vector
std::vector
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;
}