C++實現多邊形面積的計算

多邊形面積的計算一般是將其剖分爲三角形,利用海倫公式計算每個三角形的面積,然後將所有三角形的面積加起來。但是,這種方法程序實現起來比較複雜,因爲無法預知多邊形的形狀,需要判斷多邊形的“凸凹”,從而避免重複計算。本文采用向量的叉乘的方法,不管座標原點怎樣選取,只要順序輸入多邊形每個頂點的座標,按同樣的順序(順時針或反時針)兩兩叉乘。這些叉乘的和的絕對值的一半就是該多邊形面積。這就是所謂的“鞋帶公式”(Shoelace formula)。

計算公式
設O爲原點,多邊形由點P0,P1,...,Pn1 連線圍成,則面積S爲:

S=12|i=0n1(OPi¯×OPi+1¯)|,(Pn=P0)

舉一個最簡單的例子,n=3。也就是三角形的面積。
S=12|OP0¯×OP1¯+OP1¯×OP2¯+OP2¯×OP0¯|

如圖,三角形P0P1P2 的面積(即粉紅色部分)等於三角形OP1P2 減去三角形OP0P1 和三角形OP2P1 而得。粗粗看上去好像問題搞複雜了,其實不然,因爲三角形OP1P2OP0P1OP2P1 的面積(帶符號)都通過叉乘而得,編程非常簡單。這幾個帶符號面積相加,自動消除了重複計算的部分。可以說非常巧妙。當推廣到一般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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章