C++实现多边形面积的计算

前言

多边形面积的计算一般是将其剖分为三角形,利用海伦公式计算每个三角形的面积,然后将所有三角形的面积加起来。但是,这种方法程序实现起来比较复杂,因为无法预知多边形的形状,需要判断多边形的“凸凹”,从而避免重复计算。本文采用向量的叉乘的方法,不管坐标原点怎样选取,只要顺序输入多边形每个顶点的坐标,按同样的顺序(顺时针或反时针)两两叉乘。这些叉乘的和的绝对值的一半就是该多边形面积。这就是所谓的“鞋带公式”(Shoelace formula)。

计算公式

设O为原点,多边形由点 P 0 , P 1 , . . . , P n 1 P_0, P_1, ..., P_{n-1} 连线围成,则面积S为:
S = 1 2 i = 0 n 1 ( O P i × O P i + 1 ) , ( P n = P 0 ) S=\frac{1}{2}|\sum_{i=0}^{n-1}({\overline{OP_i}\times\overline{OP_{i+1}}})|, (P_n=P_0)
举一个最简单的例子,n=3。也就是三角形的面积。
S = 1 2 O P 0 × O P 1 + O P 1 × O P 2 + O P 2 × O P 0 S=\frac{1}{2}| \overline{OP_0}\times \overline{OP_1}+\overline{OP_1}\times \overline{OP_2}+\overline{OP_2}\times \overline{OP_0}|

如图,三角形 P 0 P 1 P 2 P_0P_1P_2 的面积(即粉红色部分)等于三角形 O P 1 P 2 OP_1P_2 减去三角形 O P 0 P 1 OP_0P_1 和三角形 O P 2 P 1 OP_2P_1 而得。粗粗看上去好像问题搞复杂了,其实不然,因为三角形 O P 1 P 2 OP_1P_2 O P 0 P 1 OP_0P_1 O P 2 P 1 OP_2P_1 的面积(带符号)都通过叉乘而得,编程非常简单。这几个带符号面积相加,自动消除了重复计算的部分。可以说非常巧妙。当推广到一般n的时候,这种算法的优势就很明显了。

程序说明

本文用C++实现多边形面积计算。由于程序比较小,所有定义都放在一个文件中。程序中将多边形定义为一个类:Polygon。顶点存储在一个属性ps(数组)中。定义了顶点数据的输入输出函数。为了简便起见,不考虑顶点数据的修改或删除。属性函数getArea()运用以上公式计算多边形面积。

程序源文件

#include<iostream>
#include<vector>
#include<stdio.h>
using namespace std;

struct Point
{
    double x, y;
};

double operator*(const Point &p1,const Point &p2) { return (p1.x*p2.y-p1.y*p2.x); }

class Polygon
{
private:
    vector<Point> ps;
protected:

public:
    double getArea();
    void pushPoint(double _x, double _y);
    void printPoints();
};

double Polygon::getArea()
{
    double area=0.0;

    for(size_t i=0;i!=ps.size();++i)
    {
        area+=ps[i] * ps[(i + 1) % ps.size()];
    }

    return 0.5 * (area >=0 ? area : -area);
}

void Polygon::pushPoint(double _x, double _y)
{
    Point pt;
    pt.x=_x;
    pt.y=_y;

    ps.push_back(pt);
}

void Polygon::printPoints()
{
    for (size_t i=0;i!=ps.size();++i) {
        cout<<"P["<<i<<"]"<<"=("<<ps[i].x<<","<<ps[i].y<<")"<<endl;
    }
}

void inputData(Polygon &plygn) //input data from console
{
    double vx,vy;
    size_t i=0;

    cout<<"\nInput points coordinates, separated by space key. ^Z to end."<<endl;
    cout<<"P["<<i<<"]=";
    while (cin>>vx>>vy) {
           plygn.pushPoint(vx,vy);
           cout<<"P["<<++i<<"]=";
    }
    return;
}

int readData(string &dataFileName, Polygon &plygn)  //read data from file
{
   int itemsRead=0;
   FILE *sf;
   double vx,vy;

   if (sf=fopen(dataFileName.c_str(),"r")) {
        cout<<"Read data from "+dataFileName+" ... ... ";
        while (!feof(sf)) {
            fscanf(sf,"%lf %lf",&vx,&vy);
            plygn.pushPoint(vx,vy);
            itemsRead++;
        }
        cout<<itemsRead<<" points read."<<endl;
        fclose(sf);
        sf=NULL;
   }
   else itemsRead=-1;

   return itemsRead;

}

// main
int main()
{

    Polygon pn;
    string sn="data.txt";

    if (readData(sn,pn)!=-1) {
        pn.printPoints();
        cout<<"Area="<<pn.getArea()<<endl;
    }
    else cout<<"404 File not found."<<endl;

    return 0;
}

实验数据文件:data.txt

3 4
5 11
12 8
9 5
5 6
6 5
5 9
8 12
11 5
4 3

参考文献

计算公式参考:
https://en.wikipedia.org/wiki/Shoelace_formula

原创文章 8 获赞 9 访问量 4万+

猜你喜欢

转载自blog.csdn.net/yang_deyuan/article/details/78863424
今日推荐