记录导致计算轮廓面积出错的一个坑点

28 篇文章 0 订阅
2 篇文章 0 订阅

1.前言

        计算轮廓面积是常见的几何算法话题,获取轮廓面积、计算轮廓法线等场景会涉及到。计算轮廓面积的方法有很多,一种常用的是微积分思路的分段求和办法,即组成轮廓的每条线段与X轴或Y轴进行有向投影,轮廓边线与X轴或Y轴的投影之和即为轮廓的有向面积。

上图中轮廓共有7条边,每条边与Y轴投影,投影面积有向,每个投影均为梯形,计算公式为:

double areaThis = (abs(d0X) + abs(d1X)) * (d1Y - d0Y) * 0.5;

其中第0、1、6的投影为正,第2、3、4、5的投影为负,累积即为轮廓面积(绿色填充部分)。 

如上所示,如果关心面积的正负时,一般将轮廓移到第一或第四象限再求面积。满足上述条件时,逆时针轮廓的面积为正,顺时针轮廓的面积为负。

2.问题

在调试问题时发现上图中的轮廓面积计算为负,摸不着头脑 !=-=,好吧,那就调试,发现此轮廓有如下特点:

  • X坐标很大;
  • 同时边线之间并不是“紧密连接”的,而是在一定误差内连接;
  • 边线都比较短;

2.1. 问题分析

正常来说该轮廓面积为正,且值比较小,为什么会计算错误呢?

轮廓的边没有紧密连接,之间是有缝隙的,也就是如果紧密连接的话需要再加很短的线,轮廓的“准确”面积应该要包括要“紧密”连接而添加的短线与坐标轴的有向投影面积。

加之该轮廓X坐标值很大,上述系列短线与Y轴投影面积值(梯形)加起来就比较大了,影响到了最终的面积和的值,甚至影响了面积和的符号!

3. 解决办法

3.1. 方案一

将轮廓偏置到贴近Y轴位置,再进行面积计算,这样导致该问题的的“短线”围成的面积会很小,不足以影响轮廓边线“不紧密连接”导致的误差。

这种办法是一种中和兼容的处理办法,兼容轮廓边线可能不紧密连接的情况,同时也需要计算轮廓的包围盒最小点,以将轮廓偏置到贴近Y轴的第一或第四象限,也增加了计算的耗时。

3.2. 方案二

处理导致此问题的轮廓,在生成轮廓或计算面积前将轮廓边线紧密连接。

4. 写在后面

double GeometryUtils::GetArea(const list<Line>& polygon, const Transform& trsW2L)
{
     //  目前只支持边为线段的轮廓
     double dArea = 0;
     for(auto curve : polygon)
     {
         Vector3f pt0, pt1;
         Transform::MultPoint(trsW2L, curve.pt0, pt0);
         Transform::MultPoint(trsW2L, curve.pt1, pt1);

         //  保证轮廓在第一/四象限,这样逆时针轮廓的面积为正
         double d0X = pt0.X + 100000.0;
         double d0Y = pt0.Y + 100000.0;
         double d1X = pt1.X + 100000.0;
         double d1Y = pt1.Y + 100000.0;

         double areaThis = (abs(d0X) + abs(d1X)) * (d1Y - d0Y) * 0.5;
         dArea += areaThis;
     }

     return dArea;
}

根据需要进行方案的选取,博主采用了方案二,具体是在生成轮廓的函数中进行了处理保证轮廓边线“紧密连接”,这有利于规避由“不紧密连接”带来的很多问题,降低问题处理的复杂度,同时减少了兼容处理过程,也可以节省了时间。

欢迎交流:公众号:geometrylib

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值