继上一篇中与用户交互的多边形形态参数的计算(C#、窗体应用程序),本次为大家介绍多边形的凸包、如何生成标准差椭圆(衡量指标)以及最小约束矩形模型的计算。
一、凸包的算法
1.什么是凸包?
上一篇文章中为大家介绍了凸多边形的定义,这有助于对凸包的理解,凸包可以理解为将凹多边形最外层的点连接起来构成的多边形,这个多边形要满足两点:一是包含原来多边形中的所有的点。二是该多边形是一个凸多边形。
百度百科中讲,凸包(Convex Hull)是一个计算几何(图形学)中的概念。是在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。X的凸包可以用X内所有点(X1,...Xn)的凸组合来构造。在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。
2.凸包的计算方法
关于凸包的计算方法有很多种,下面为大家介绍凸包的相关计算方法:
(1)格雷厄姆算法
该算法的主要思想是夹角排序,依次连接。算法容易理解,但代码实现有一定的难度。
算法的主要步骤如下:
如图所示:
首先,找到点集中纵坐标最小的点P0。其次,将P0与其它点用线段连接,并计算这些线段的水平夹角。再按夹角大小对数据点排序;如夹角相同,则按距离排序,得到P1,P2,..., Pn。然后,依次连接点,得到一多边形。最后,循环删除多边形的非凸顶点得到点集的凸壳。需要注意的是,再最后循环删除多边形的非凸顶点时需要依次进行判断,算法设计较为困难。
(2)使用向量判断内角的大小
该方法的主要思想是按照多边形各顶点存储的顺序,依次确定相邻的三个顶点构成的向量叉乘正负(主要逆时针为正),如果内角叉乘小于零,则说明该角为大于180°的角,将向量中心顶点的坐标删除,重新判断,以下一个顶点为中心,循环完成,形成凸包。该算法不涉及格雷厄姆算法中角度的计算以及排序存储问题。
但也需要注意:
①按照画多边形的顺序进行存储和判断,对缠绕多边形的计算不准确。
②利用向量叉乘判断夹角,有方向要求,容易出现错误。
③涉及多边形顶点的删除操作,算法实现有一定困难。
④遍历多边形顶点,三个为一组,对索引值有很大限制,需要使用很多循环语句。
3.凸包的应用
①确定范围,我们常常会遇到,给定点的集合,确定范围,这时确定最外围的点集即可确定点集的范围,也即确定其凸包。
②凹多边形的分割,以及Delaunay三角网的构建。
4.部分代码:
p.Add(p[0]);
for (int i = 0; i < p.Count - 2; i++)
{
double a1 = p[i].X - p[i + 1].X;
double a2 = p[i].Y - p[i + 1].Y;
double b1 = p[i + 2].X - p[i + 1].X;
double b2 = p[i + 2].Y - p[i + 1].Y;
double fenzi = a1 * b2 - a2 * b1;
double fenmu = Math.Sqrt(a1 * a1 + a2 * a2) * Math.Sqrt(b1 * b1 + b2 * b2);
double sin = fenzi / fenmu;
if (sin < 0)
{
p.RemoveAt(i + 1);
i = i - 1;
}
}
List<Point> p0 = null;
int count1 = p.Count;
for (int j = 0; j < count1; j++)
{
if (j + 1 < count1)
{
graphics.DrawLine(pen, p[j].X, p[j].Y, p[j + 1].X, p[j + 1].Y);
}
if (p0 == null) p0 = new List<Point>();
p0.Add(p[j]);
}
5.实现效果
二、标准差椭圆的计算
1.什么是标准差椭圆?
标准差椭圆用于可用于衡量离散点的离散程度、方向分布以及分布形态。也可以用标准差雨哦元的各项参数(例如长轴、短轴)等来衡量离散点的特征。空间分析中的标准差椭圆(Stardard deviational ellipse)最早由Lefever在1926年提出。标准差椭圆可以用来汇总地理要素的空间特征:中心趋势、离散和方向趋势,在Arcgis中可以使用工具进行标准差椭圆的可视化。(原文链接:https://blog.csdn.net/weixin_41590039/article/details/115702316)
2.标准差椭圆的计算方法
计算平均中心->计算角度->计算长轴短轴的长度。
公式如下:
(原文链接:(2条消息) 方向分布(标准差椭圆)_HuFeiHu-Blog的博客-CSDN博客_标准差椭圆)
3.部分代码
int num = Points.Count;
//平均中心
double sumx = 0;
double sumy = 0;
for (int i = 0; i < num; i++)
{
sumx += Points[i].X;
sumy += Points[i].Y;
}
X0 = (int)sumx / num;
Y0 = (int)sumy / num;
AveragePoint = new Point(X0, Y0);
//圆心
double sumx1 = 0;
double sumy1 = 0;
for (int i = 0; i < num; i++)
{
sumx1 += (Points[i].X - X0) * (Points[i].X - X0);
sumy1 += (Points[i].Y - Y0) * (Points[i].Y - Y0);
}
//CenterX = (int)Math.Sqrt(sumx1 / num);
//CenterY = (int)Math.Sqrt(sumy1 / num);
CenterX = (int)(sumx1 / num);
CenterY = (int)(sumy1 / num);
CenterPoint = new Point(CenterX, CenterY);
graphics.DrawEllipse(pen, (float)CenterX, (float)CenterY, 4, 4);
//graphics.DrawEllipse(pen, (float)X0, (float)Y0, 4, 4
//计算角度
double AngleA = 0;
double AngleB = 0;
double AngleC = 0;
double tanAngle = 0;
double Angle = 0;
for (int i = 0; i < num; i++)
{
AngleA += (Points[i].X - X0) * (Points[i].X - X0) - (Points[i].Y - Y0) * (Points[i].Y - Y0);
AngleB += Math.Sqrt(Math.Pow((Points[i].X - X0) * (Points[i].X - X0) - (Points[i].Y - Y0) * (Points[i].Y - Y0), 2) + 4 * Math.Pow((Points[i].X - X0) * (Points[i].Y - Y0), 2));
AngleC += 2 * (Points[i].X - X0) * (Points[i].Y - Y0) * (Points[i].X - X0);
}
tanAngle = (AngleA + AngleB) / AngleC;
Angle = Math.Atan(tanAngle) * 180 / Math.PI;
//计算xy长度
double sinAngle = Math.Sin(Angle);
double cosAngle = Math.Cos(Angle);
double XLong = 0;
double YLong = 0;
for (int i = 0; i < num; i++)
{
XLong += Math.Sqrt(Math.Pow((((Points[i].X - X0) * cosAngle - (Points[i].Y - Y0) * sinAngle)), 2) / num) * Math.Sqrt(2);
YLong += Math.Sqrt(Math.Pow((((Points[i].X - X0) * sinAngle + (Points[i].Y - Y0) * cosAngle)), 2) / num) * Math.Sqrt(2);
//XLong = (Math.Pow(((Points[i].X - X0) * cosAngle - (Points[i].Y - Y0) * sinAngle), 2) / num) * Math.Sqrt(2);
//YLong = (Math.Pow(((Points[i].X - X0) * sinAngle + (Points[i].Y - Y0) * cosAngle), 2) / num) * Math.Sqrt(2);
}
graphics.DrawEllipse(pen, (float)X0 - (float)XLong / 2, (float)Y0 - (float)YLong / 2, (float)YLong, (float)XLong);
x = (float)X0 - (float)XLong / 2;
y = (float)Y0 - (float)YLong / 2;
w = (float)XLong;
h = (float)YLong;
4.实现效果
三、最小约束矩形模型
1.什么是最小约束矩形模型?
类似于标准差椭圆,也可以用来衡量离散点的离散程度、方向分布以及分布形态。但与之不同的是用矩形来比较,没有倾斜程度的计算。相对简单。
2.部分代码:
double num = p.Count;
double minx = 100000;
double miny = 100000;
double maxx = 0;
double maxy = 0;
for (int i = 0; i < num; i++)
{
if (p[i].X < minx)
{
minx = p[i].X;
}
if (p[i].X > maxx)
{
maxx = p[i].X;
}
if (p[i].Y < miny)
{
miny = p[i].Y;
}
if (p[i].Y > maxy)
{
maxy = p[i].Y;
}
}
Graphics graphics = pictureBox1.CreateGraphics();
Pen pen = new Pen(System.Drawing.Color.AliceBlue);
graphics.DrawLine(pen, (float)minx, (float)miny, (float)minx, (float)maxy);
graphics.DrawLine(pen, (float)minx, (float)maxy, (float)maxx, (float)maxy);
graphics.DrawLine(pen, (float)maxx, (float)maxy, (float)maxx, (float)miny);
graphics.DrawLine(pen, (float)maxx, (float)miny, (float)minx, (float)miny);
3.实现效果:
原创作品,禁止抄袭!
需要完整代码,欢迎留言!