之前嘗試過很多的任意多邊形截面積計算,都有不同的局限性,直到使用了這個公式后,問題就解決了,感謝原作者的分享。
//堰槽坐標定義 typedef?struct?? { double?x; double?y; }WeirCoorType;
//任意多邊形面積計算 double?CLASS_NAME::PolygonAreaCalculation(WeirCoorType?*pWeirCoor,?WORD?CoorCnt) { double?sum0?=?0; double?square; //這個多邊形計算代碼如此簡單,可以計算任意的多邊形,就算是弧形都行,只要你輸入坐標點就行 for?(int?i?=?0;?i?<?CoorCnt?-?1;?i++) { sum0?+=?(pWeirCoor[i].x?*?pWeirCoor[i?+?1].y?-?pWeirCoor[i?+?1].x?*?pWeirCoor[i].y); } square?=?(fabs(sum0?+?(pWeirCoor[CoorCnt?-?1].x?*?pWeirCoor[0].y)?-?(pWeirCoor[0].x?*?pWeirCoor[CoorCnt?-?1].y)))?/?2; return?square; }
最后測試生成的效果,用于對一個任意河道的不同過水斷面進行計算,這個斷面就是一個任意多邊形。
代碼的核心就是計算多邊形面積,以及尋找水位線與斷面(多邊形)的交點,根據(jù)交點獲取水位以下河道多邊形的坐標。
這個綠線對應的就是水位與河道形成的多邊形,這個公式可以允許2個相連接的多邊形,比如上圖所示的,水位Y值為15,灰色區(qū)域就是河道,沒有水的地方,這個多邊形計算公式會自動的計算左右2個過水斷面的面積。
//計算交點的X值 double?CLASS_NAME::CalculateIntersectionX(WeirCoorType?*pWeirCoor1,?WeirCoorType?*pWeirCoor2,?double?y) { double?ftemp; WeirCoorType?*pMaxCoor,?*pMinCoor; if?(pWeirCoor1->y?==?pWeirCoor2->y)?//Y軸一樣,不允許的,隨便輸出一個X軸 { SYS_LOG.Write(__FILE__?+?__LINE__?+?"?t:不允許2個坐標的Y軸一樣rn"); return?pWeirCoor1->x; } else?if?(pWeirCoor1->y?>?pWeirCoor2->y) { pMaxCoor?=?pWeirCoor1; //Y軸大的點 pMinCoor?=?pWeirCoor2; //Y軸小的點 } else { pMaxCoor?=?pWeirCoor2; //Y軸大的點 pMinCoor?=?pWeirCoor1; //Y軸小的點 } if?(y?>=?pMaxCoor->y)?return?pMaxCoor->x; //大于大的點 if?(y?y)?return?pMinCoor->x; //小于小的點 //斜線,并且處于中間 ftemp?=?((pMaxCoor->y?-?y)?*?(pMaxCoor->x?-?pMinCoor->x))?/?(pMaxCoor->y?-?pMinCoor->y); ftemp?=?pMaxCoor->x?-?ftemp; return?ftemp; }
這個函數(shù)用于計算水位(一個水平橫線)與河道交叉點的X坐標,由于水位是一個Y值,X值就是距離河道邊零點的距離,通過這個就可以知道水位與河道的交叉點坐標,也就是水位與河道形成的過水斷面多邊形的交差坐標。
通過下面的這個線程就可以不聽的計算任意水位對應的過水斷面面積,我的做法是人為設置一個分辨率,比如1cm,程序會計算0cm斷面面積,1cm水位斷面面積,2cm水位斷面面積,依次類推。
//線程-運行核心?? System::Void?CLASS_NAME::BackgroundWorker_DoWork(System::Object^??sender,?System::ComponentModel::DoWorkEventArgs^??e) { double?ftemp; double?Y_Inc?=?0.1; //Y軸增量 WORD?i; double?X; int?Status; WORD?count; WORD?StartIndex; int?n; char?buff[32]; WeirCoorType?TempWeirCoor1[256]; try { this->VarY?=?0; for?(n?=?0;?n?<?256;?n++) { //WeirCoorType?WeirCoor1[9]?=?{?{0,0},?{25,0},?{25,50},?{75,50},{75,0},?{90,0},{100,0},?{100,100},{0,100}}; //坐標必須按照順序,從左上角,左下角,右下角,右上角順序,X軸依次增加,左上角與右上角Y軸相等并且最大 //WeirCoorType?WeirCoor1[9]?=?{?{?0,?100?},?{?0,?0?},?{?25,?0?},?{?25,?50?},?{?75,?50?},?{?75,?0?},?{?100,?0?},?{?100,?100?}}; //尋找Y軸交點坐標 i?=?0; count?=?0; for?(int?j?=?0;?j?<?this->WeirCoorNum?/?2;?j++) //循環(huán)尋找交點-一對 { //從第一個坐標開始,先尋找Y值對應的X坐標 for?(;?i?<?(this->WeirCoorNum?-?1);?i++) { if?(this->pWeirCoorBuff[i].y?>=?this->VarY?&&?this->pWeirCoorBuff[i?+?1].y?<?this->VarY)?//左邊交點 { USER_DEBUG.Printf("左交點:%f,%f~%f,%frn",?this->pWeirCoorBuff[i].x,?this->pWeirCoorBuff[i].y,?this->pWeirCoorBuff[i?+?1].x,?this->pWeirCoorBuff[i?+?1].y); //計算交點坐標 X?=?this->CalculateIntersectionX(&this->pWeirCoorBuff[i],?&this->pWeirCoorBuff[i?+?1],?this->VarY); USER_DEBUG.Printf("左交點:(%f,%f)rn",?X,?this->VarY); TempWeirCoor1[count].x?=?X; TempWeirCoor1[count].y?=?this->VarY; count++; StartIndex?=?i?+?1; break; } } //從第一個坐標開始,先尋找Y值對應的X坐標 for?(;?i?<?(this->WeirCoorNum?-?1);?i++) { if?(this->pWeirCoorBuff[i].y?<?this->VarY?&&?this->pWeirCoorBuff[i?+?1].y?>=?this->VarY)?//右邊交點 { USER_DEBUG.Printf("右交點:%f,%f~%f,%frn",?this->pWeirCoorBuff[i].x,?this->pWeirCoorBuff[i].y,?this->pWeirCoorBuff[i?+?1].x,?this->pWeirCoorBuff[i?+?1].y); //計算交點坐標 X?=?this->CalculateIntersectionX(&this->pWeirCoorBuff[i],?&this->pWeirCoorBuff[i?+?1],?this->VarY); USER_DEBUG.Printf("右交點:(%f,%f)rn",?X,?this->VarY); for?(int?k?=?StartIndex;?k?pWeirCoorBuff[k].x; TempWeirCoor1[count].y?=?this->pWeirCoorBuff[k].y; count++; } TempWeirCoor1[count].x?=?X; TempWeirCoor1[count].y?=?this->VarY; count++; break; } } if?(i?>=?this->WeirCoorNum?-?1)?break; } this->SelectCoorCount?=?count;??//選擇的點數(shù)量 memcpy(this->pSelectWeirCoor1,?TempWeirCoor1,?sizeof(WeirCoorType)?*?count); this->mBackgroundWorker->ReportProgress(1); //狀態(tài)改變 //打印最終的坐標 USER_DEBUG.Printf("多邊形坐標:"); for?(i?=?0;?i?<?count;?i++) { USER_DEBUG.Printf("%f,%f?t",?TempWeirCoor1[i].x,?TempWeirCoor1[i].y); } USER_DEBUG.Printf("rn"); //WeirCoorType?WeirCoor1[8]?=?{?{0,0},?{100,0},?{100,100},{1,100}}; //任意多邊形面積計算 ftemp?=?this->PolygonAreaCalculation(TempWeirCoor1,?count); USER_DEBUG.Printf("面積:%frn",?ftemp); this->SectionalArea?=?ftemp; //最終的截面積 this->SectionalAreaBuff[n]?=?this->SectionalArea;?//截面積寫入全局緩沖區(qū)中 this->VarY?+=?this->VerticalResVal; if?(this->VarY?>?this->pWeirCoorBuff[0].y) { USER_DEBUG.Printf("垂直高度超出范圍了,退出!rn"); break; } Sleep(20); } ftemp?=?this->SectionalArea; for?(;?n?<?256;?n++) //補充不足256個截面數(shù)據(jù),后面截面積固定 { this->SectionalAreaBuff[n]?=?ftemp; ftemp?+=?0.00001;?//截面積只能增大,不能不變,有效位數(shù)5位小數(shù)自增 } //生成datatable this->mDataTable->Rows->Clear(); //清空行 for?(int?i?=?0;?i?<?256;?i++) //循環(huán)添加行 { DataRow?^dr?=?this->mDataTable->NewRow();//新建行 sprintf_s(buff,?31,?"%.5f",?this->SectionalAreaBuff[i]); dr[0]?=?CharToString(buff); this->mDataTable->Rows->Add(dr);//添加行 } } catch?(Exception?^e1) { SYS_LOG.Write(__FILE__?+?__LINE__?+?"t:"?+?e1->Message?+?e1->StackTrace); } }