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 }