多边形切割折线

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Security.Cryptography;
  5 using System.Text;
  6 using System.Windows;
  7 using System.Windows.Media;
  8 using System.Windows.Shapes;
  9 
 10 namespace geometry
 11 {
 12     public partial class Help
 13     {
 14 
 15         #region 线段与多边形的交点集合,按从p1到p2的方向进行排序
 16         /// <summary>
 17         /// 对一线段与多边形的交点集合,按从p1到p2的方向进行排序
 18         /// </summary>
 19         /// <param name="p1"></param>
 20         /// <param name="p2"></param>
 21         /// <param name="interPoints"></param>
 22         /// <returns></returns>
 23         public List<Point> SortPointsBySlopeOfLine(Point p1, Point p2, List<Point> interPoints)
 24         {
 25             List<Point> points = new List<Point>();
 26             List<Point> newInterPoints = new List<Point>();
 27             points.Add(p1);
 28             if (Equals(p1.X, p2.X))//垂直线段
 29             {
 30                 if (p1.Y > p2.Y)
 31                 {
 32                     newInterPoints = interPoints.OrderByDescending(t => t.Y).ToList();
 33                 }
 34                 else
 35                 {
 36                     newInterPoints = interPoints.OrderBy(t => t.Y).ToList();
 37                 }
 38             }
 39             else
 40             {
 41                 if (Equals(p1.Y, p2.Y))//水平线段
 42                 {
 43                     if (p1.X > p2.X)
 44                     {
 45                         newInterPoints = interPoints.OrderByDescending(t => t.X).ToList();
 46                     }
 47                     else
 48                     {
 49                         newInterPoints = interPoints.OrderBy(t => t.X).ToList();
 50                     }
 51 
 52                 }
 53                 else//普通斜率线段,按x或y都行
 54                 {
 55                     if (p1.X > p2.X)
 56                     {
 57                         newInterPoints = interPoints.OrderByDescending(t => t.X).ToList();
 58                     }
 59                     else
 60                     {
 61                         newInterPoints = interPoints.OrderBy(t => t.X).ToList();
 62                     }
 63 
 64                 }
 65 
 66             }
 67 
 68             foreach (Point interPoint in newInterPoints)
 69             {
 70                 points.Add(interPoint);
 71             }
 72             points.Add(p2);
 73             return points;
 74         }
 75         #endregion
 76 
 77 
 78         #region 获取线段和线段的交点
 79 
 80         private double eps = 1e-8;
 81         /// <summary>
 82         /// 判断一个数值是否在误差范围内
 83         /// </summary>
 84         /// <param name="x"></param>
 85         /// <returns></returns>
 86         private bool zero(double x)
 87         {
 88 
 89             return (((x) > 0 ? (x) : -(x)) < eps);
 90         }
 91 
 92 
 93         /// <summary>
 94         /// 计算交叉乘积(P1-P0)x(P2-P0)
 95         /// </summary>
 96         /// <param name="p1"></param>
 97         /// <param name="p2"></param>
 98         /// <param name="p0"></param>
 99         /// <returns></returns>
100         private double xmult(Point p1, Point p2, Point p0)
101         {
102             return (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y);
103         }
104 
105         /// <summary>
106         /// 判点是否在线段上,包括端点
107         /// </summary>
108         /// <param name="p"></param>
109         /// <param name="l1"></param>
110         /// <param name="l2"></param>
111         /// <returns></returns>
112         private bool dot_online_in(Point p, Point l1, Point l2)
113         {
114             return zero(xmult(p, l1, l2)) && (l1.X - p.X) * (l2.X - p.X) < eps && (l1.Y - p.Y) * (l2.Y - p.Y) < eps;
115         }
116 
117         /// <summary>
118         /// 判两点在线段同侧,点在线段上返回0
119         /// </summary>
120         /// <param name="p1"></param>
121         /// <param name="p2"></param>
122         /// <param name="l1"></param>
123         /// <param name="l2"></param>
124         /// <returns></returns>
125         private bool same_side(Point p1, Point p2, Point l1, Point l2)
126         {
127             return xmult(l1, p1, l2) * xmult(l1, p2, l2) > eps;
128         }
129 
130         /// <summary>
131         /// 判断两直线平行
132         /// </summary>
133         /// <param name="u1"></param>
134         /// <param name="u2"></param>
135         /// <param name="v1"></param>
136         /// <param name="v2"></param>
137         /// <returns></returns>
138         private bool parallel(Point u1, Point u2, Point v1, Point v2)
139         {
140             return zero((u1.X - u2.X) * (v1.Y - v2.Y) - (v1.X - v2.X) * (u1.Y - u2.Y));
141         }
142 
143         /// <summary>
144         /// 判三点共线
145         /// </summary>
146         /// <param name="p1"></param>
147         /// <param name="p2"></param>
148         /// <param name="p3"></param>
149         /// <returns></returns>
150         private bool dots_inline(Point p1, Point p2, Point p3)
151         {
152             return zero(xmult(p1, p2, p3));
153         }
154 
155         /// <summary>
156         /// 判两线段相交,包括端点和部分重合
157         /// </summary>
158         /// <param name="u1"></param>
159         /// <param name="u2"></param>
160         /// <param name="v1"></param>
161         /// <param name="v2"></param>
162         /// <returns></returns>
163         private bool intersect_in(Point u1, Point u2, Point v1, Point v2)
164         {
165             if (!dots_inline(u1, u2, v1) || !dots_inline(u1, u2, v2))
166                 return !same_side(u1, u2, v1, v2) && !same_side(v1, v2, u1, u2);
167             return dot_online_in(u1, v1, v2) || dot_online_in(u2, v1, v2) || dot_online_in(v1, u1, u2) || dot_online_in(v2, u1, u2);
168         }
169 
170         /// <summary>
171         /// 计算两线段交点,请判线段是否相交(同时还是要判断是否平行!)
172         /// </summary>
173         /// <param name="u1"></param>
174         /// <param name="u2"></param>
175         /// <param name="v1"></param>
176         /// <param name="v2"></param>
177         /// <param name="ret"></param>
178         /// <returns></returns>
179         private int GetIntersectionPoint(Point u1, Point u2, Point v1, Point v2, out Point ret)
180         {
181             ret = u1;
182             if (parallel(u1, u2, v1, v2) || !intersect_in(u1, u2, v1, v2))
183             {
184                 return 0;
185             }
186             double t = ((u1.X - v1.X) * (v1.Y - v2.Y) - (u1.Y - v1.Y) * (v1.X - v2.X))
187               / ((u1.X - u2.X) * (v1.Y - v2.Y) - (u1.Y - u2.Y) * (v1.X - v2.X));
188             ret.X += (u2.X - u1.X) * t;
189             ret.Y += (u2.Y - u1.Y) * t;
190             return 1;
191         }
192         #endregion
193 
194 
195         #region 多边形包含点
196         /// <summary>
197         /// 判断多边形是否包含某个点
198         /// </summary>
199         /// <param name="poly">多边形边框上每个角的点坐标数组</param>
200         /// <param name="p">要进行判断的点</param>
201         /// <returns>true:包含; false:不包含</returns>
202         public bool InPoly(Polygon polygon, Point p)
203         {
204 
205             Point[] poly = polygon.Points.ToArray();
206             int i = 0, f = 0;
207             double xi = 0, a = 0, b = 0, c = 0;
208             Point ps, pe;
209             ///遍历每一个点
210             for (i = 0; i <= Microsoft.VisualBasic.Information.UBound(poly, 1); i++)
211             {
212                 ps = poly[i];
213                 if (i < Microsoft.VisualBasic.Information.UBound(poly, 1))
214                 {
215                     pe = poly[i + 1];
216                 }
217                 else
218                 {
219                     pe = poly[0];
220                 }
221                 GetStdLine(ps, pe, ref a, ref b, ref c);
222                 if (a != 0)
223                 {
224                     xi = 0 - ((b * p.Y + c) / a);
225                     if (xi == p.X)
226                     {
227                         return true;
228                     }
229                     else if (xi < p.X)
230                     {
231                         f = f + Sgn(pe.Y - p.Y) - Sgn(ps.Y - p.Y);
232                     }
233                 }
234             }
235             return f != 0;
236         }
237 
238         /// <summary>
239         /// 根据两个点的坐标求经过两点的直线的标准方程参数A、B、C
240         /// </summary>
241         /// <param name="ps"></param>
242         /// <param name="pe"></param>
243         /// <param name="a"></param>
244         /// <param name="b"></param>
245         /// <param name="c"></param>
246         private void GetStdLine(Point ps, Point pe, ref double a, ref double b, ref double c)
247         {
248             double xs, ys, xe, ye;
249             double p1, p2;
250             xs = ps.X;
251             ys = ps.Y;
252             xe = pe.X;
253             ye = pe.Y;
254             p1 = (xs * ye);
255             p2 = (xe * ys);
256             if (p1 == p2)
257             {
258                 if (xs == 0)
259                 {
260                     if (xe == 0)
261                     {
262                         a = 1;
263                         b = 0;
264                         c = 0;
265                     }
266                     else if (ys == 0)
267                     {
268                         a = ye;
269                         b = 0 - xe;
270                         c = 0;
271                     }
272                 }
273                 else if (ye == 0)
274                 {
275                     if (ys == 0)
276                     {
277                         a = 0;
278                         b = 1;
279                         c = 0;
280                     }
281                     else if (xe == 0)
282                     {
283                         a = 0 - ys;
284                         b = xs;
285                         c = 0;
286                     }
287                 }
288             }
289             else
290             {
291                 a = (ys - ye) / (p1 - p2);
292                 c = 1;
293                 if (ys == 0)
294                 {
295                     if (ye == 0)
296                     {
297                         b = 1;
298                         c = 0;
299                     }
300                     else
301                     {
302                         b = 0 - ((a * xe + 1) / ye);
303                     }
304                 }
305                 else
306                 {
307                     b = 0 - ((a * xs + 1) / ys);
308                 }
309             }
310         }
311         private int Sgn(double a)
312         {
313             if (a == 0)
314             {
315                 return 0;
316             }
317             else if (a < 0)
318             {
319                 return -1;
320             }
321             else
322             {
323                 return 1;
324             }
325         }
326 
327         #endregion
328 
329         /// <summary>
330         /// 求出线段和多边形的交点,不包括p1p2
331         /// </summary>
332         /// <param name="p1"></param>
333         /// <param name="p2"></param>
334         /// <param name="polygon"></param>
335         /// <returns></returns>
336         public List<Point> GetInterPoints(Point p1, Point p2, Polygon polygon)
337         {
338             List<Point> interPoints = new List<Point>();
339             List<Point> polygonPoints = polygon.Points.ToList();
340             for (int i = 0; i < polygonPoints.Count; i++)
341             {
342                 Point polygon1 = polygonPoints[i];
343                 Point polygon2 = new Point();
344                 if (i == polygonPoints.Count - 1)
345                 {
346                     polygon2 = polygonPoints[0];
347                 }
348                 else
349                 {
350                     polygon2 = polygonPoints[i + 1];
351 
352                 }
353                 Point inter = new Point();
354                 int interType = GetIntersectionPoint(p1, p2, polygon1, polygon2, out inter);
355                 switch (interType)
356                 {
357 
358                     case 1:
359 
360                         if (!Equals(inter, p1) && !Equals(inter, p2))
361                         {
362                             interPoints.Add(inter);
363                         }
364                         break;
365                     case 0:
366                     default:
367                         break;
368                 }
369             }
370             return interPoints;
371         }
372 
373         /// <summary>
374         /// 取两个点的中点
375         /// </summary>
376         /// <param name="p1"></param>
377         /// <param name="p2"></param>
378         /// <returns></returns>
379         public Point GetCenter(Point p1, Point p2)
380         {
381             return new Point((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
382         }
383 
384         /// <summary>
385         /// 获取多边形裁剪折线形成的线段集合
386         /// </summary>
387         /// <param name="polyline"></param>
388         /// <param name="polygon"></param>
389         /// <returns></returns>
390         public List<Polyline> GetInterPolylines(Polyline polyline, Polygon polygon)
391         {
392             List<Polyline> list = new List<Polyline>();
393             //TODO: 1.遍历折线上的每相邻的两个个点,组成线段,与多边形的每一条边计算,求出此线段与多边形的边的交点
394             //TODO:  2.对此线段的上的交点进行排序,组成连续点的折线,判断这些线段在多边形内部的部分,加入集合
395 
396             List<Point> polinePoints = polyline.Points.ToList();
397             List<Point> polygonPoints = polygon.Points.ToList();
398 
399             for (int i = 0; i < polinePoints.Count - 1; i++)
400             {
401                 Point one = polinePoints[i];
402                 Point two = new Point();
403                 if (i == polinePoints.Count - 1)
404                 {
405 
406                 }
407                 else
408                 {
409                     two = polinePoints[i + 1];
410                 }
411                 List<Point> inters = GetInterPoints(one, two, polygon);
412                 List<Point> sortInters = SortPointsBySlopeOfLine(one, two, inters);
413 
414                 for (int j = 0; j < sortInters.Count; j++)
415                 {
416                     if (j < sortInters.Count - 1)
417                     {
418                         if (InPoly(polygon, GetCenter(sortInters[j], sortInters[j + 1])))
419                         {
420                             Polyline interPolyline = new Polyline();
421                             interPolyline.Points.Add(sortInters[j]);
422                             interPolyline.Points.Add(sortInters[j + 1]);
423                             list.Add(interPolyline);
424                         }
425                     }
426 
427                 }
428             }
429             return list;
430         }
431     }
432 }
View Code
原文地址:https://www.cnblogs.com/shanranlei/p/4316200.html