多边形切割折线
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 }