• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
代码的天空
博客园    首页    新随笔    联系   管理    订阅  订阅

获取离散点的边界点

今天公司要求实现一个算法,在给出一堆离散点中,画出最外层的边界。实际就是从离散点中找出最外面的点(或称边界点),这些点用线连接起来即可。

一、实现的原理:

1.任意点(point1)找出最远距离的一个点(point2),该点point2即为其中一个边界点。
2.point1与point2组成的向量v1(point1 - point2)中找出与其最大夹角的一个向量v2。
3.重复:v2中找与其最大夹角的向量v3.....
4.直到最后找到的向量方向为点point2的向量时结束。

二、这里实现的代码为C#,只要搞懂原理,可以转为各种语言的实现

1.首先是平面向量类 PlaneVector

PlaneVector
  1     /// <summary>
  2     /// 平面向量类
  3     /// </summary>
  4     public struct PlaneVector
  5     {
  6         public static readonly PlaneVector Empty;
  7 
  8         /// <summary>
  9         /// 向量的X值
 10         /// </summary>
 11         private double _X;
 12 
 13         /// <summary>
 14         /// 向量的Y值
 15         /// </summary>
 16         private double _Y;
 17 
 18         public double X
 19         {
 20             get
 21             {
 22                 return _X;
 23             }
 24             set
 25             {
 26                 _X = value;
 27             }
 28         }
 29 
 30         public double Y
 31         {
 32             get
 33             {
 34                 return _Y;
 35             }
 36             set
 37             {
 38                 _Y = value;
 39             }
 40         }
 41 
 42         public PlaneVector(double x, double y)
 43         {
 44             _X = x;
 45             _Y = y;
 46         }
 47 
 48         public PlaneVector(Point destPoint, Point sourcePoint)
 49         {
 50             _X = destPoint.X - sourcePoint.X;
 51             _Y = destPoint.Y - sourcePoint.Y;
 52         }
 53 
 54         public PlaneVector(PointF destPoint, PointF sourcePoint)
 55         {
 56             _X = destPoint.X - sourcePoint.X;
 57             _Y = destPoint.Y - sourcePoint.Y;
 58         }
 59 
 60         public PlaneVector(PlaneVector destPlaneVector, PlaneVector sourcePlaneVector)
 61         {
 62             _X = destPlaneVector._X - sourcePlaneVector._X;
 63             _Y = destPlaneVector._Y - sourcePlaneVector._Y;
 64         }
 65 
 66         public void Add(PlaneVector pv)
 67         {
 68             _X += pv._X;
 69             _Y += pv._Y;
 70         }
 71 
 72         public void Subtract(PlaneVector pv)
 73         {
 74             _X -= pv._X;
 75             _Y -= pv._Y;
 76         }
 77 
 78         public override bool Equals(object obj)
 79         {
 80             if (!(obj is PlaneVector))
 81             {
 82                 return false;
 83             }
 84             PlaneVector tf = (PlaneVector) obj;
 85             return (((tf.X == this.X) && (tf.Y == this.Y)) && tf.GetType().Equals(base.GetType()));
 86         }
 87 
 88         public override int GetHashCode()
 89         {
 90             return base.GetHashCode();
 91         }
 92 
 93         public override string ToString()
 94         {
 95             return string.Format("[{0},{1}]", this._X, this._Y);
 96         }
 97 
 98         static PlaneVector()
 99         {
100             Empty = new PlaneVector(0f, 0f);
101         }
102 
103         public static PlaneVector operator +(PlaneVector left, PlaneVector right)
104         {
105             return Add(left, right);
106         }
107 
108         public static PlaneVector operator -(PlaneVector left, PlaneVector right)
109         {
110             return Subtract(left, right);
111         }
112 
113         public static bool operator ==(PlaneVector left, PlaneVector right)
114         {
115             return ((left.X == right.X) && (left.Y == right.Y));
116         }
117 
118         public static bool operator !=(PlaneVector left, PlaneVector right)
119         {
120             return !(left == right);
121         }
122 
123         public static PlaneVector Add(PlaneVector left, PlaneVector right)
124         {
125             return new PlaneVector(left.X + right.X, left.Y + right.Y);
126         }
127 
128         public static PlaneVector Subtract(PlaneVector left, PlaneVector right)
129         {
130             return new PlaneVector(left.X - right.X, left.Y - right.Y);
131         }
132 
133     }

2.算法的实现

GetBorderPointFs
  1     public static class Common
  2     {
  3         /// <summary>
  4         /// 获取两个向量的夹角
  5         /// </summary>
  6         /// <param name="sourcePlaneVector">源向量</param>
  7         /// <param name="destPlaneVector">目标向量</param>
  8         /// <returns></returns>
  9         public static double GetAngle(PlaneVector sourcePlaneVector, PlaneVector destPlaneVector)
 10         {
 11             double temp = 0;
 12             double norm1 = 0;
 13             double norm2 = 0;
 14 
 15             norm1 = System.Math.Sqrt(sourcePlaneVector.X * sourcePlaneVector.X + sourcePlaneVector.Y * sourcePlaneVector.Y);
 16             norm2 = System.Math.Sqrt(destPlaneVector.X * destPlaneVector.X + destPlaneVector.Y * destPlaneVector.Y);
 17 
 18             temp = sourcePlaneVector.X * destPlaneVector.X + sourcePlaneVector.Y * destPlaneVector.Y;
 19 
 20             if (norm1 == 0 || norm2 == 0)
 21             {
 22                 return 0;
 23             }
 24             else
 25             {
 26                 temp = temp / (norm1 * norm2);
 27 
 28                 if (temp > 1.0)
 29                 {
 30                     temp = 1.0;
 31                 }
 32                 else if (temp < -1.0)
 33                 {
 34                     temp = -1.0;
 35                 }
 36 
 37                 return System.Math.Acos(temp);
 38             }
 39         }
 40 
 41         /// <summary>
 42         /// 获取一个点在一个点集合中的最远点
 43         /// </summary>
 44         /// <param name="aPointF">点</param>
 45         /// <param name="aPoints">点集合</param>
 46         /// <returns>最远点</returns>
 47         public static System.Drawing.PointF GetFarthestPointF(System.Drawing.PointF aPointF, List<System.Drawing.PointF> aPoints)
 48         {
 49             if (aPointF == null)
 50             {
 51                 throw new ArgumentNullException("aPointF");
 52             }
 53 
 54             if (aPoints == null)
 55             {
 56                 throw new ArgumentNullException("aPoints");
 57             }
 58 
 59             System.Drawing.PointF farthestPointF = System.Drawing.PointF.Empty;
 60 
 61             double maxLength = 0;
 62             double tempLength = 0;
 63 
 64             double x = 0;
 65             double y = 0;
 66 
 67             foreach (System.Drawing.PointF aDestPoint in aPoints)
 68             {
 69                 x = (double)(aDestPoint.X - aPointF.X);
 70                 y = (double)(aDestPoint.Y - aPointF.Y);
 71 
 72                 tempLength = Math.Sqrt(x * x + y * y);
 73 
 74                 if (maxLength < tempLength)
 75                 {
 76                     maxLength = tempLength;
 77                     farthestPointF = aDestPoint;
 78                 }
 79             }
 80 
 81             return farthestPointF;
 82         }
 83 
 84         /// <summary>
 85         /// 获取离散点集的边界点
 86         /// </summary>
 87         /// <param name="aPoints">一组离散点</param>
 88         /// <returns>离散点的边界点</returns>
 89         public static List<System.Drawing.PointF> GetBorderPointFs(List<System.Drawing.PointF> aPoints)
 90         {
 91             List<System.Drawing.PointF> aBorderPoints = new List<System.Drawing.PointF>();
 92 
 93             if (aPoints == null)
 94             {
 95                 throw new ArgumentNullException("aPoints");
 96             }
 97 
 98             if (aPoints.Count < 3)
 99             {
100                 aBorderPoints.AddRange(aPoints);
101 
102                 return aBorderPoints;
103             }
104 
105             //1.获取任意点的最远点
106 
107             System.Drawing.PointF farthestPointF = GetFarthestPointF(aPoints.First(), aPoints);
108 
109             //2.获取边界点 --------------------------------------->
110 
111             System.Drawing.PointF sourcePointF = farthestPointF;
112             System.Drawing.PointF destPointF = aPoints.First();
113 
114             System.Drawing.PointF maxAnglePoint = System.Drawing.PointF.Empty;
115 
116             while (!farthestPointF.Equals(maxAnglePoint))
117             {
118                 PlaneVector sourcePlaneVector = new PlaneVector(destPointF, sourcePointF);
119 
120                 double maxAngle = 0;
121 
122                 foreach (System.Drawing.PointF aDestPoint in aPoints)
123                 {
124                     PlaneVector destPlaneVector = new PlaneVector(aDestPoint, sourcePointF);
125 
126                     double tempAngle = GetAngle(sourcePlaneVector, destPlaneVector);
127 
128                     if (maxAngle <= tempAngle)
129                     {
130                         maxAngle =tempAngle;
131                         maxAnglePoint = aDestPoint;
132                     }
133                 }
134 
135                 aBorderPoints.Add(maxAnglePoint);
136 
137                 destPointF = sourcePointF;
138                 sourcePointF = maxAnglePoint;
139                 
140 
141             } //---------------------------------------< 2.获取边界点 
142 
143             return aBorderPoints;
144         }
145     }

GetBorderPointFs 返回的经过计算最后得出的边界点集合。这里主要是使用GetAngle方法来获取连个向量的角度大小,注意的是,角度的单位不是一般的度,而是pi。

这里是实现的代码,里面做有一个测试的程序,在窗体上随便点上几个点,按生成图形即可看到结果。

附件: 实现的代码.rar

posted @ 2010-01-27 21:47  黑翼  阅读(4240)  评论(2)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3