凸包、最小约束矩形、标准差椭圆

  继上一篇中与用户交互的多边形形态参数的计算(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.实现效果:

原创作品,禁止抄袭!

需要完整代码,欢迎留言!

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值