之前尝试过很多的任意多边形截面积计算,都有不同的局限性,直到使用了这个公式后,问题就解决了,感谢原作者的分享。
//堰槽坐标定义
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;
}
最后测试生成的效果,用于对一个任意河道的不同过水断面进行计算,这个断面就是一个任意多边形。
代码的核心就是计算多边形面积,以及寻找水位线与断面(多边形)的交点,根据交点获取水位以下河道多边形的坐标。
这个绿线对应的就是水位与河道形成的多边形,这个公式可以允许2个相连接的多边形,比如上图所示的,水位Y值为15,灰色区域就是河道,没有水的地方,这个多边形计算公式会自动的计算左右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轴一样\r\n");
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 <= pMinCoor->y) return pMinCoor->x; //小于小的点
//斜线,并且处于中间
ftemp = ((pMaxCoor->y - y) * (pMaxCoor->x - pMinCoor->x)) / (pMaxCoor->y - pMinCoor->y);
ftemp = pMaxCoor->x - ftemp;
return ftemp;
}
这个函数用于计算水位(一个水平横线)与河道交叉点的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++) //循环寻找交点-一对
{
//从第一个坐标开始,先寻找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,%f\r\n", 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)\r\n", 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,%f\r\n", 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)\r\n", X, this->VarY);
for (int k = StartIndex; k <= i; k++)
{
TempWeirCoor1[count].x = this->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; //选择的点数量
memcpy(this->pSelectWeirCoor1, TempWeirCoor1, sizeof(WeirCoorType) * count);
this->mBackgroundWorker->ReportProgress(1); //状态改变
//打印最终的坐标
USER_DEBUG.Printf("多边形坐标:");
for (i = 0; i < count; i++)
{
USER_DEBUG.Printf("%f,%f \t", TempWeirCoor1[i].x, TempWeirCoor1[i].y);
}
USER_DEBUG.Printf("\r\n");
//WeirCoorType WeirCoor1[8] = { {0,0}, {100,0}, {100,100},{1,100}};
//任意多边形面积计算
ftemp = this->PolygonAreaCalculation(TempWeirCoor1, count);
USER_DEBUG.Printf("面积:%f\r\n", ftemp);
this->SectionalArea = ftemp; //最终的截面积
this->SectionalAreaBuff[n] = this->SectionalArea; //截面积写入全局缓冲区中
this->VarY += this->VerticalResVal;
if (this->VarY > this->pWeirCoorBuff[0].y)
{
USER_DEBUG.Printf("垂直高度超出范围了,退出!\r\n");
break;
}
Sleep(20);
}
ftemp = this->SectionalArea;
for (; n < 256; n++) //补充不足256个截面数据,后面截面积固定
{
this->SectionalAreaBuff[n] = ftemp;
ftemp += 0.00001; //截面积只能增大,不能不变,有效位数5位小数自增
}
//生成datatable
this->mDataTable->Rows->Clear(); //清空行
for (int i = 0; i < 256; i++) //循环添加行
{
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);
}
}
感谢网友分享的任意多边形计算公式,见:https://www.cdsy.xyz/computer/programme/Other/230326/cd41971.html