/HelixToolkit/Geometry/Polygon3D.cs

http://mecprev.codeplex.com · C# · 95 lines · 75 code · 10 blank · 10 comment · 7 complexity · 6c869a1df5d176f60d6fba9e4f967514 MD5 · raw file

  1. using System;
  2. using System.Windows;
  3. using System.Windows.Media;
  4. using System.Windows.Media.Media3D;
  5. namespace HelixToolkit
  6. {
  7. /// <summary>
  8. /// 3D Polygon
  9. /// </summary>
  10. public class Polygon3D
  11. {
  12. internal Point3DCollection points;
  13. public Polygon3D()
  14. {
  15. }
  16. public Polygon3D(Point3DCollection pts)
  17. {
  18. points = pts;
  19. }
  20. public Point3DCollection Points
  21. {
  22. get { return points ?? (points = new Point3DCollection()); }
  23. set { points = value; }
  24. }
  25. // http://en.wikipedia.org/wiki/Polygon_triangulation
  26. // http://en.wikipedia.org/wiki/Monotone_polygon
  27. // http://www.codeproject.com/KB/recipes/hgrd.aspx LGPL
  28. // http://www.springerlink.com/content/g805787811vr1v9v/
  29. public bool IsPlanar()
  30. {
  31. Vector3D v1 = Points[1] - Points[0];
  32. var normal = new Vector3D();
  33. for (int i = 2; i < Points.Count; i++)
  34. {
  35. var n = Vector3D.CrossProduct(v1, Points[i] - Points[0]);
  36. n.Normalize();
  37. if (i == 2)
  38. normal = n;
  39. else
  40. if (Math.Abs(Vector3D.DotProduct(n, normal) - 1) > 1e-8)
  41. {
  42. return false;
  43. }
  44. }
  45. return true;
  46. }
  47. public Vector3D GetNormal()
  48. {
  49. if (Points.Count < 3)
  50. throw new InvalidOperationException("At least three points required in the polygon to find a normal.");
  51. Vector3D v1 = Points[1] - Points[0];
  52. for (int i = 2; i < Points.Count; i++)
  53. {
  54. var n = Vector3D.CrossProduct(v1, Points[i] - Points[0]);
  55. if (n.LengthSquared > 1e-8)
  56. {
  57. n.Normalize();
  58. return n;
  59. }
  60. }
  61. throw new InvalidOperationException("Invalid polygon.");
  62. }
  63. public Polygon Flatten()
  64. {
  65. // http://forums.xna.com/forums/p/16529/86802.aspx
  66. // http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane
  67. var up = GetNormal();
  68. up.Normalize();
  69. var right = Vector3D.CrossProduct(up, Math.Abs(up.X) > Math.Abs(up.Z) ? new Vector3D(0, 0, 1) : new Vector3D(1, 0, 0));
  70. var backward = Vector3D.CrossProduct(right, up);
  71. var m = new Matrix3D(backward.X, right.X, up.X, 0, backward.Y, right.Y, up.Y, 0, backward.Z, right.Z, up.Z, 0, 0, 0, 0, 1);
  72. // make first point origin
  73. var offs = m.Transform(Points[0]);
  74. m.OffsetX = -offs.X;
  75. m.OffsetY = -offs.Y;
  76. var polygon = new Polygon { Points = new PointCollection(Points.Count) };
  77. foreach (Point3D p in Points)
  78. {
  79. var pp = m.Transform(p);
  80. polygon.Points.Add(new Point(pp.X, pp.Y));
  81. }
  82. return polygon;
  83. }
  84. }
  85. }