计算几何之多边形

81 篇文章 2 订阅
33 篇文章 0 订阅

最近解决一个多边形带洞的问题,需要判断多边形的顶点顺序,顺便复习下计算几何的一些基础知识。。
判断顶点顺序需要计算多边形的面积,面积有正负之分,符号决定了顺时针CW还是逆时针CCW。计算面积两种思路:
- 直角梯形的思路
- 向量叉乘

直角梯形思路

任何一个边p0p1,两个顶点向x轴投垂线,构成了直角梯形。它的面积是

(p1.x – p0.x) * (p1.y + p2.y) / 2.0

直角梯形
面积符号受deltaX,averageY影响。二者综合影响。

下图中,多边形面积等于所有边与x轴构成直角梯形面积总和。N个顶点,则N个边的面积之和,尤其注意首尾顶点(n-1, 0)的 这个线段的面积需要考虑进去。。
这里写图片描述
上图中,多边形顶点顺序为顺时针ABCDEFG,
TopAreas是AB,BC,CD,DE 与x轴构成的梯形,面积都大于0;
BottomAreas是EF,FG,GA与x轴构成的梯形,deltax为负,面积都小于0;最终多边形面积为正。

因此

这种方式下,多边形顶点顺序为逆时针,则面积为负值;顺时针时候,面积为正值。

向量叉乘的方式

向量叉乘
最经简单的例子,

unit_x(1, 0, 0) cross unit_y(0, 1, 0) = unit_z(0, 0, 1)

叉乘的右手法则:右手四指,从a开始以不超过180的转角握向b,大拇指的指向就是叉乘结果向量的方向。
2D向量叉乘的物理意义:a向量叉乘b向量的模,代表|b|*sin为高,a为底的三角形面积。面积可以有符号,叉乘向量是z轴正向时,面积为正,否则为负。

多边形的面积计算,多边形每个边两个端点跟原点组成一系列三角形,它们的面积有正负,所面积之和就是多边形的面积。
这里写图片描述
右图中,多边形是逆时针方向,ABCDEFG
第一个三角形:ABP面积为负,为什么呢?AP.cross(BP) 向量的方向是z轴负方向。
最后一个三角形GAP,面积为正,why?GP.cross(AP) 向量的方向是z轴正方向。

结论

多边形顶点顺序为逆时针时,计算的面积为正;顺时针时,面积为负值。

代码

// http://www.cnblogs.com/void/archive/2011/04/17/2018729.html
bool IsPolygonClockWise(const std::vector<Point_Double>& vPolygon)
{
    // compute area of a contour/polygon
    int n = vPolygon.size();

    double A = 0.0;

    for(int p=n-1,q=0; q<n; p=q++)
    {
        A+= vPolygon[p].x * vPolygon[q].y - vPolygon[q].x * vPolygon[p].y;
    }
    double Area = A * 0.5;

    // we want a counter-clockwise polygon in V
    if ( 0.0 < Area )
    {
        return false;
    }
    else
    {
        return true;
    }
}

// http://csharphelper.com/blog/2014/07/calculate-the-area-of-a-polygon-in-c/
bool IsPolygonClockWise_WhenYUp(TXMapPoint* polygon, int count)
{
    double rst = 0.0;

#if 1
    // first point must be equal to last point.
    for (int i = 0; i < count; i++)
    {
        int next = (i + 1) % count;
        double dx = polygon[next].x - polygon[i].x;
        double dy = polygon[next].y + polygon[i].y;
        rst += (dx * dy);

        // overflow issue.
        // rst += ( (polygon[next].x - polygon[i].x) * (polygon[next].y + polygon[i].y) / 2.0 );
    }
#else
    // bad version
    // 没有计算首尾两个点构成的面积。。。
    for (int i = 1; i <count; i++)
    {
        double dx = (polygon[i].x - polygon[i - 1].x);
        double ay = (polygon[i].y + polygon[i - 1].y);
        rst += (dx * ay);
    }
#endif

    if (rst >= 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

踩过的坑
地图中坐标很大,如果使用int存储,计算面积的时候有越界的可能。越界后结果为负数,也会影响到最终的计算结果。

function 1---------
p   q
2, 0
0, 1
1, 2

2x * 0y - 0x * 2y
0x * 1y - 1x * 0y
1x * 2y - 2x * 1y

function 2---------
(1x - 0x) * (1y + 0y) = 1x * 1y + 1x * 0y - 0x * 1y - 0x * 0y

2x * 2y + 2x * 1y - 1x * 2y - 1x * 1y

(0x - 2x) * (0y + 2y) = 0x * 0y + 0x * 2y - 2x * 0y - 2x * 2y

optim: 
1x * 0y - 0x * 1y
2x * 1y - 1x * 2y
0x * 2y - 2x * 0y
---------
  • 第一种方式计算量更加少
  • 第二种方式有点冗余,循环中每次的计算结果中有可以抵消的部分
  • 第二种优化的结果与第一种正好差一个符号

OpenGL模板测试渲染任意凹多边形

如下图,多边形1234567。A,D,F区域组成了多边形,且这三个区域都是由奇数个三角形覆盖;其他区域由偶数个,或者0个三角形覆盖。如图中右边的列表,B由123,134两个三角形覆盖。
这里写图片描述

选择任意一点P作为基准点,分别渲染P12,P23,P34,P45,P56,P67,P71 三角形。多边形内部的区域被填充了奇数次,外部的区域被填充了偶数次。
OpenGL渲染凹多边形的思路:借助帧缓冲区,两次渲染多边形的三角形列表。

  1. 禁止写入颜色缓冲区,清空帧缓冲区;
  2. 遍历三角形渲染,帧缓冲函数采用GL_INVERT。这个函数的效果是,三角形渲染时,它覆盖的每个像素的帧缓冲区值,都在0和非0之间翻转。所有三角形画完,像素被覆盖了偶数次的话,帧缓冲区对应位置的值是0,奇数次的话帧缓冲对应的值是非零。
  3. 画一个大多边形,能够包含整个多边形,例如它的boundingbox,但是只允许帧缓冲区中非零的区域通过测试。

点评

  • 技术虽有点过时了,这种技术适应任何复杂带洞的多边形渲染。
  • 相比较直接凹多边形三角化后渲染,重叠地方的被多次栅格化,性能消耗较大。opengl渲染的步骤,顶点处理,栅格化,片段处理,然后裁剪测试,alpha测试,模板测试(帧缓冲区),深度测试(深度缓冲区)。

ref:http://glprogramming.com/red/chapter14.html#name13

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断圆是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 圆的基本运算 1 .点是否在圆内 20 2 .求不共线的三点所确定的圆 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两圆关系: 24 2.判断圆是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两圆交点: 27 8.两圆公共面积: 28 9. 圆和直线关系: 29 10. 内切圆: 30 11. 求切点: 31 12. 线段的左右旋: 31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值