1. 程式人生 > >(三)建築物多邊形化簡系列——去除冗餘點

(三)建築物多邊形化簡系列——去除冗餘點

製圖綜合和建築物資料處理等都涉及到建築物多邊形的化簡。製圖綜合中,由於比例尺的變小,建築物在小比例尺地圖上所佔面積變小,這意味著建築物圖形的形狀精度也有一定的損失,為了更好地表示原有建築物的特徵(面積、圖形和方向),需要對建築物多邊形進行化簡。另外,從遙感影像提取的建築物向量資料需要經過圖形化簡等一系列操作才能作為可使用的資料。

首先明確,向量資料結構中,建築物多邊形是由一些列環(circle)組成,環則由一串首尾相同的點構造。這意味著對建築物多邊形化簡其實是對這些環(線狀)處理,更具體地說,是對環的各個點進行處理(刪除、移位)。

對建築物多邊形的化簡到最後得到能較好擬合建築物的成果多邊形,這中間需要一系列操作。首先要進行去除冗餘點

的操作。

1)冗餘點

對於建築物多邊形邊界上的鄰近三點,若它們所組成兩條直線的夾角為平角(或零角),則該三點共線,且位於中間位置那個點的取捨對建築物多邊形的 幾 何形狀沒有影響,因此該三點中位於中間位置那個點是冗餘的。

需要注意的是由於資料採集誤差、製圖不規範等原因,使得地圖上建築物多邊形邊界上出現冗餘點的情況很少,出於方法的合理性考慮,選取5°作為緩衝角度,對冗餘點的定義做出以下修正定義:對於建築物多邊形邊界上的鄰近三點,若它們所組成兩條直線的夾角與平角(或零角)相差的角度小於5°時,稱該三點中位於中間位置的那個點為冗餘點。

2)基本思想

取環上鄰近三點作為一個單元,分析夾角:若夾角小於閾值,則刪除中間點,加入下一個點構成新的分析單元;若夾角大於閾值,則保留中間點,繼續遍歷。

3)程式碼實現

// 去除冗餘點,zf,0717
void CGeoPolygon::RemoveRedundant(void)
{
    for(int i = 0;i<circles.size();i++)  //遍歷每個circles
    {
        vector<int> temp;                //用於存放冗餘點的下標
        bool odinary = true;             //設定狀態,以確定三點單元的首點
        int count = 0;                   //記錄刪除的點數,一旦有正常情況恢復為0
        int ptsNum = circles[i]->pts.size();
        for(int n = 0;n<ptsNum-2;n++)
        {
            CMyPoint*first,*middle,*last;  //定義三點
            if(odinary)   //正常,沒有冗餘點的情況
            {
                first = circles[i]->pts[n];
                middle = circles[i]->pts[n+1];
                last = circles[i]->pts[n+2];
            }
            else         //不正常,存在冗餘點的情況
            {
                first = circles[i]->pts[n-count];   //存在冗餘點,刪除後判斷冗餘點之後的點是否為冗餘點還需要之前三點單元的首點
                middle = circles[i]->pts[n+1];
                last = circles[i]->pts[n+2];
            }
            double angle = calAngle(first,middle,last);   //計算角度
            if(angle >= 10&&angle<=170)         //角度閾值設為10°(可根據需要調整),當角度大於閾值,情況正常,不需要去除點
            {
                odinary = true;
                count = 0;                 //記錄刪除的點數,一旦有正常情況恢復為0
            }
            else   // 存在冗餘點
            {
                temp.push_back(n+1);     //記錄冗餘點在circles[i]->pts中下標
                odinary = false;         //情況不正常
                count++;                 //連續不正常時都要記錄
            }
        }<br>
        vector<CMyPoint*> tempPoints;    //定義臨時點集
        if(tempPoints.size()!=0) vector<CMyPoint*>().swap(tempPoints); //防止點集不為空
        for(int j = 0;j<ptsNum;j++)
        {
            bool answer = isContained(temp,j);    //判斷j是否存在temp中,若存在說明為冗餘點,新點集中不應有此點
            if(answer == false)                   //若不存在說明不為冗餘點,新點集應存此點
                tempPoints.push_back(circles[i]->pts[j]);  
        }
        tempPoints.swap(circles[i]->pts);         //交換,得到去除冗餘點之後的環circles[i]->pts
    }
}

  其中calAngle函式是計算三點的夾角,具體程式碼如下:

// 計算三點之間的角度,zf,0717,要#include<math.h>
double CGeoPolygon::calAngle(CMyPoint* p1, CMyPoint* p2, CMyPoint* p3)
{
    double x1 = p1->Getx();
    double y1 = p1->Gety();
    double x2 = p2->Getx();
    double y2 = p2->Gety();
    double x3 = p3->Getx();
    double y3 = p3->Gety();
 
    double angle,p1p2,p2p3,p1p3;
    p1p2 = sqrt(((x1 - x2) * (x1 - x2) + (y1 -y2) * (y1 -y2)));
    p2p3 = sqrt(((x3 - x2) * (x3 - x2) + (y3 -y2) * (y3 -y2)));
    p1p3 = sqrt(((x1 - x3) * (x1 - x3) + (y1 -y3) * (y1 -y3)));
    angle = acos((p1p2 * p1p2 + p2p3 * p2p3 - p1p3 * p1p3) / (2 * p1p2 * p2p3)) * 180.0 / 3.1415926;
    if(angle<0)
        angle = angle*(-1);
    return angle;
}

  isContained函式判斷某個數是不是在陣列中,見下

// 判斷某個數是不是在陣列中,zf,0717
bool CGeoPolygon::isContained(vector<int> temp, int i)
{
    bool answer = false;
    for(int j = 0;j<temp.size();j++)
    {
        if(i == temp[j]) answer = true;
        if(answer) break;
    }
    return answer;
}

4)效果展示

去除冗餘點之前

 

去除冗餘點之後

5)小結

去除冗餘點是建築物化簡的第一步,雖然看起來前後差別不大,但是細細觀察還是有一定區別,更近一步的化簡將在下一篇部落格中講述。