/Controls/HelixToolkit.Wpf/Geometry/Polygon3D.cs

https://bitbucket.org/kubrakms/thermalconductivity · C# · 168 lines · 96 code · 23 blank · 49 comment · 8 complexity · 0c0e21be8b514b4df15cf2959666ac59 MD5 · raw file

  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="Polygon3D.cs" company="Helix 3D Toolkit">
  3. // http://helixtoolkit.codeplex.com, license: Ms-PL
  4. // </copyright>
  5. // --------------------------------------------------------------------------------------------------------------------
  6. namespace HelixToolkit.Wpf
  7. {
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Windows;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Media3D;
  13. /// <summary>
  14. /// Represents a 3D polygon.
  15. /// </summary>
  16. public class Polygon3D
  17. {
  18. #region Constants and Fields
  19. /// <summary>
  20. /// The points.
  21. /// </summary>
  22. internal IList<Point3D> points;
  23. #endregion
  24. #region Constructors and Destructors
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref = "Polygon3D" /> class.
  27. /// </summary>
  28. public Polygon3D()
  29. {
  30. this.points = new List<Point3D>();
  31. }
  32. /// <summary>
  33. /// Initializes a new instance of the <see cref="Polygon3D"/> class.
  34. /// </summary>
  35. /// <param name="pts">
  36. /// The PTS.
  37. /// </param>
  38. public Polygon3D(IList<Point3D> pts)
  39. {
  40. this.points = pts;
  41. }
  42. #endregion
  43. #region Public Properties
  44. /// <summary>
  45. /// Gets or sets the points.
  46. /// </summary>
  47. /// <value>The points.</value>
  48. public IList<Point3D> Points
  49. {
  50. get
  51. {
  52. return this.points;
  53. }
  54. set
  55. {
  56. this.points = value;
  57. }
  58. }
  59. #endregion
  60. // http://en.wikipedia.org/wiki/Polygon_triangulation
  61. // http://en.wikipedia.org/wiki/Monotone_polygon
  62. // http://www.codeproject.com/KB/recipes/hgrd.aspx LGPL
  63. // http://www.springerlink.com/content/g805787811vr1v9v/
  64. #region Public Methods
  65. /// <summary>
  66. /// Flattens this polygon.
  67. /// </summary>
  68. /// <returns>
  69. /// The 2D polygon.
  70. /// </returns>
  71. public Polygon Flatten()
  72. {
  73. // http://forums.xna.com/forums/p/16529/86802.aspx
  74. // http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane
  75. var up = this.GetNormal();
  76. up.Normalize();
  77. var right = Vector3D.CrossProduct(
  78. up, Math.Abs(up.X) > Math.Abs(up.Z) ? new Vector3D(0, 0, 1) : new Vector3D(1, 0, 0));
  79. var backward = Vector3D.CrossProduct(right, up);
  80. var m = new Matrix3D(
  81. 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);
  82. // make first point origin
  83. var offs = m.Transform(this.Points[0]);
  84. m.OffsetX = -offs.X;
  85. m.OffsetY = -offs.Y;
  86. var polygon = new Polygon { Points = new PointCollection(this.Points.Count) };
  87. foreach (var p in this.Points)
  88. {
  89. var pp = m.Transform(p);
  90. polygon.Points.Add(new Point(pp.X, pp.Y));
  91. }
  92. return polygon;
  93. }
  94. /// <summary>
  95. /// Gets the normal of the polygon.
  96. /// </summary>
  97. /// <returns>
  98. /// The normal.
  99. /// </returns>
  100. public Vector3D GetNormal()
  101. {
  102. if (this.Points.Count < 3)
  103. {
  104. throw new InvalidOperationException("At least three points required in the polygon to find a normal.");
  105. }
  106. Vector3D v1 = this.Points[1] - this.Points[0];
  107. for (int i = 2; i < this.Points.Count; i++)
  108. {
  109. var n = Vector3D.CrossProduct(v1, this.Points[i] - this.Points[0]);
  110. if (n.LengthSquared > 1e-8)
  111. {
  112. n.Normalize();
  113. return n;
  114. }
  115. }
  116. throw new InvalidOperationException("Invalid polygon.");
  117. }
  118. /// <summary>
  119. /// Determines whether this polygon is planar.
  120. /// </summary>
  121. /// <returns>
  122. /// The is planar.
  123. /// </returns>
  124. public bool IsPlanar()
  125. {
  126. Vector3D v1 = this.Points[1] - this.Points[0];
  127. var normal = new Vector3D();
  128. for (int i = 2; i < this.Points.Count; i++)
  129. {
  130. var n = Vector3D.CrossProduct(v1, this.Points[i] - this.Points[0]);
  131. n.Normalize();
  132. if (i == 2)
  133. {
  134. normal = n;
  135. }
  136. else if (Math.Abs(Vector3D.DotProduct(n, normal) - 1) > 1e-8)
  137. {
  138. return false;
  139. }
  140. }
  141. return true;
  142. }
  143. #endregion
  144. }
  145. }