/Source/HelixToolkit.Wpf/Visual3Ds/MeshVisuals/GridLinesVisual3D.cs

http://helixtoolkit.codeplex.com · C# · 387 lines · 210 code · 40 blank · 137 comment · 4 complexity · 033397eabb69352c2a64c40a4c7ab721 MD5 · raw file

  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="GridLinesVisual3D.cs" company="Helix 3D Toolkit">
  3. // http://helixtoolkit.codeplex.com, license: MIT
  4. // </copyright>
  5. // --------------------------------------------------------------------------------------------------------------------
  6. namespace HelixToolkit.Wpf
  7. {
  8. using System;
  9. using System.Windows;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Media3D;
  12. /// <summary>
  13. /// A visual element that shows a set of grid lines.
  14. /// </summary>
  15. public class GridLinesVisual3D : MeshElement3D
  16. {
  17. /// <summary>
  18. /// Identifies the <see cref="Center"/> dependency property.
  19. /// </summary>
  20. public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
  21. "Center", typeof(Point3D), typeof(GridLinesVisual3D), new UIPropertyMetadata(new Point3D(), GeometryChanged));
  22. /// <summary>
  23. /// Identifies the <see cref="MinorDistance"/> dependency property.
  24. /// </summary>
  25. public static readonly DependencyProperty MinorDistanceProperty = DependencyProperty.Register(
  26. "MinorDistance", typeof(double), typeof(GridLinesVisual3D), new PropertyMetadata(2.5, GeometryChanged));
  27. /// <summary>
  28. /// Identifies the <see cref="LengthDirection"/> dependency property.
  29. /// </summary>
  30. public static readonly DependencyProperty LengthDirectionProperty =
  31. DependencyProperty.Register(
  32. "LengthDirection",
  33. typeof(Vector3D),
  34. typeof(GridLinesVisual3D),
  35. new UIPropertyMetadata(new Vector3D(1, 0, 0), GeometryChanged));
  36. /// <summary>
  37. /// Identifies the <see cref="Length"/> dependency property.
  38. /// </summary>
  39. public static readonly DependencyProperty LengthProperty = DependencyProperty.Register(
  40. "Length", typeof(double), typeof(GridLinesVisual3D), new PropertyMetadata(200.0, GeometryChanged));
  41. /// <summary>
  42. /// Identifies the <see cref="MajorDistance"/> dependency property.
  43. /// </summary>
  44. public static readonly DependencyProperty MajorDistanceProperty = DependencyProperty.Register(
  45. "MajorDistance", typeof(double), typeof(GridLinesVisual3D), new PropertyMetadata(10.0, GeometryChanged));
  46. /// <summary>
  47. /// Identifies the <see cref="Normal"/> dependency property.
  48. /// </summary>
  49. public static readonly DependencyProperty NormalProperty = DependencyProperty.Register(
  50. "Normal",
  51. typeof(Vector3D),
  52. typeof(GridLinesVisual3D),
  53. new UIPropertyMetadata(new Vector3D(0, 0, 1), GeometryChanged));
  54. /// <summary>
  55. /// Identifies the <see cref="Thickness"/> dependency property.
  56. /// </summary>
  57. public static readonly DependencyProperty ThicknessProperty = DependencyProperty.Register(
  58. "Thickness", typeof(double), typeof(GridLinesVisual3D), new PropertyMetadata(0.08, GeometryChanged));
  59. /// <summary>
  60. /// Identifies the <see cref="Width"/> dependency property.
  61. /// </summary>
  62. public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
  63. "Width", typeof(double), typeof(GridLinesVisual3D), new PropertyMetadata(200.0, GeometryChanged));
  64. /// <summary>
  65. /// The length direction.
  66. /// </summary>
  67. private Vector3D lengthDirection;
  68. /// <summary>
  69. /// The width direction.
  70. /// </summary>
  71. private Vector3D widthDirection;
  72. /// <summary>
  73. /// Initializes a new instance of the <see cref = "GridLinesVisual3D" /> class.
  74. /// </summary>
  75. public GridLinesVisual3D()
  76. {
  77. this.Fill = Brushes.Gray;
  78. }
  79. /// <summary>
  80. /// Gets or sets the center of the grid.
  81. /// </summary>
  82. /// <value>The center.</value>
  83. public Point3D Center
  84. {
  85. get
  86. {
  87. return (Point3D)this.GetValue(CenterProperty);
  88. }
  89. set
  90. {
  91. this.SetValue(CenterProperty, value);
  92. }
  93. }
  94. /// <summary>
  95. /// Gets or sets the length of the grid area.
  96. /// </summary>
  97. /// <value>The length.</value>
  98. public double Length
  99. {
  100. get
  101. {
  102. return (double)this.GetValue(LengthProperty);
  103. }
  104. set
  105. {
  106. this.SetValue(LengthProperty, value);
  107. }
  108. }
  109. /// <summary>
  110. /// Gets or sets the length direction of the grid.
  111. /// </summary>
  112. /// <value>The length direction.</value>
  113. public Vector3D LengthDirection
  114. {
  115. get
  116. {
  117. return (Vector3D)this.GetValue(LengthDirectionProperty);
  118. }
  119. set
  120. {
  121. this.SetValue(LengthDirectionProperty, value);
  122. }
  123. }
  124. /// <summary>
  125. /// Gets or sets the distance between major grid lines.
  126. /// </summary>
  127. /// <value>The distance.</value>
  128. public double MajorDistance
  129. {
  130. get
  131. {
  132. return (double)this.GetValue(MajorDistanceProperty);
  133. }
  134. set
  135. {
  136. this.SetValue(MajorDistanceProperty, value);
  137. }
  138. }
  139. /// <summary>
  140. /// Gets or sets the distance between minor grid lines.
  141. /// </summary>
  142. /// <value>The distance.</value>
  143. public double MinorDistance
  144. {
  145. get
  146. {
  147. return (double)this.GetValue(MinorDistanceProperty);
  148. }
  149. set
  150. {
  151. this.SetValue(MinorDistanceProperty, value);
  152. }
  153. }
  154. /// <summary>
  155. /// Gets or sets the normal vector of the grid plane.
  156. /// </summary>
  157. /// <value>The normal.</value>
  158. public Vector3D Normal
  159. {
  160. get
  161. {
  162. return (Vector3D)this.GetValue(NormalProperty);
  163. }
  164. set
  165. {
  166. this.SetValue(NormalProperty, value);
  167. }
  168. }
  169. /// <summary>
  170. /// Gets or sets the thickness of the grid lines.
  171. /// </summary>
  172. /// <value>The thickness.</value>
  173. public double Thickness
  174. {
  175. get
  176. {
  177. return (double)this.GetValue(ThicknessProperty);
  178. }
  179. set
  180. {
  181. this.SetValue(ThicknessProperty, value);
  182. }
  183. }
  184. /// <summary>
  185. /// Gets or sets the width of the grid area (perpendicular to the length direction).
  186. /// </summary>
  187. /// <value>The width.</value>
  188. public double Width
  189. {
  190. get
  191. {
  192. return (double)this.GetValue(WidthProperty);
  193. }
  194. set
  195. {
  196. this.SetValue(WidthProperty, value);
  197. }
  198. }
  199. /// <summary>
  200. /// Do the tesselation and return the <see cref="MeshGeometry3D"/>.
  201. /// </summary>
  202. /// <returns>
  203. /// </returns>
  204. protected override MeshGeometry3D Tessellate()
  205. {
  206. this.lengthDirection = this.LengthDirection;
  207. this.lengthDirection.Normalize();
  208. this.widthDirection = Vector3D.CrossProduct(this.Normal, this.lengthDirection);
  209. this.widthDirection.Normalize();
  210. var mesh = new MeshBuilder(true, false);
  211. double minX = -this.Width / 2;
  212. double minY = -this.Length / 2;
  213. double maxX = this.Width / 2;
  214. double maxY = this.Length / 2;
  215. double x = minX;
  216. double eps = this.MinorDistance / 10;
  217. while (x <= maxX + eps)
  218. {
  219. double t = this.Thickness;
  220. if (IsMultipleOf(x, this.MajorDistance))
  221. {
  222. t *= 2;
  223. }
  224. this.AddLineX(mesh, x, minY, maxY, t);
  225. x += this.MinorDistance;
  226. }
  227. double y = minY;
  228. while (y <= maxY + eps)
  229. {
  230. double t = this.Thickness;
  231. if (IsMultipleOf(y, this.MajorDistance))
  232. {
  233. t *= 2;
  234. }
  235. this.AddLineY(mesh, y, minX, maxX, t);
  236. y += this.MinorDistance;
  237. }
  238. var m = mesh.ToMesh();
  239. m.Freeze();
  240. return m;
  241. }
  242. /// <summary>
  243. /// Determines whether y is a multiple of d.
  244. /// </summary>
  245. /// <param name="y">
  246. /// The y.
  247. /// </param>
  248. /// <param name="d">
  249. /// The d.
  250. /// </param>
  251. /// <returns>
  252. /// The is multiple of.
  253. /// </returns>
  254. private static bool IsMultipleOf(double y, double d)
  255. {
  256. double y2 = d * (int)(y / d);
  257. return Math.Abs(y - y2) < 1e-3;
  258. }
  259. /// <summary>
  260. /// The add line x.
  261. /// </summary>
  262. /// <param name="mesh">
  263. /// The mesh.
  264. /// </param>
  265. /// <param name="x">
  266. /// The x.
  267. /// </param>
  268. /// <param name="minY">
  269. /// The min y.
  270. /// </param>
  271. /// <param name="maxY">
  272. /// The max y.
  273. /// </param>
  274. /// <param name="thickness">
  275. /// The thickness.
  276. /// </param>
  277. private void AddLineX(MeshBuilder mesh, double x, double minY, double maxY, double thickness)
  278. {
  279. int i0 = mesh.Positions.Count;
  280. mesh.Positions.Add(this.GetPoint(x - thickness / 2, minY));
  281. mesh.Positions.Add(this.GetPoint(x - thickness / 2, maxY));
  282. mesh.Positions.Add(this.GetPoint(x + thickness / 2, maxY));
  283. mesh.Positions.Add(this.GetPoint(x + thickness / 2, minY));
  284. mesh.Normals.Add(this.Normal);
  285. mesh.Normals.Add(this.Normal);
  286. mesh.Normals.Add(this.Normal);
  287. mesh.Normals.Add(this.Normal);
  288. mesh.TriangleIndices.Add(i0);
  289. mesh.TriangleIndices.Add(i0 + 1);
  290. mesh.TriangleIndices.Add(i0 + 2);
  291. mesh.TriangleIndices.Add(i0 + 2);
  292. mesh.TriangleIndices.Add(i0 + 3);
  293. mesh.TriangleIndices.Add(i0);
  294. }
  295. /// <summary>
  296. /// The add line y.
  297. /// </summary>
  298. /// <param name="mesh">
  299. /// The mesh.
  300. /// </param>
  301. /// <param name="y">
  302. /// The y.
  303. /// </param>
  304. /// <param name="minX">
  305. /// The min x.
  306. /// </param>
  307. /// <param name="maxX">
  308. /// The max x.
  309. /// </param>
  310. /// <param name="thickness">
  311. /// The thickness.
  312. /// </param>
  313. private void AddLineY(MeshBuilder mesh, double y, double minX, double maxX, double thickness)
  314. {
  315. int i0 = mesh.Positions.Count;
  316. mesh.Positions.Add(this.GetPoint(minX, y + thickness / 2));
  317. mesh.Positions.Add(this.GetPoint(maxX, y + thickness / 2));
  318. mesh.Positions.Add(this.GetPoint(maxX, y - thickness / 2));
  319. mesh.Positions.Add(this.GetPoint(minX, y - thickness / 2));
  320. mesh.Normals.Add(this.Normal);
  321. mesh.Normals.Add(this.Normal);
  322. mesh.Normals.Add(this.Normal);
  323. mesh.Normals.Add(this.Normal);
  324. mesh.TriangleIndices.Add(i0);
  325. mesh.TriangleIndices.Add(i0 + 1);
  326. mesh.TriangleIndices.Add(i0 + 2);
  327. mesh.TriangleIndices.Add(i0 + 2);
  328. mesh.TriangleIndices.Add(i0 + 3);
  329. mesh.TriangleIndices.Add(i0);
  330. }
  331. /// <summary>
  332. /// Gets a point on the plane.
  333. /// </summary>
  334. /// <param name="x">
  335. /// The x coordinate.
  336. /// </param>
  337. /// <param name="y">
  338. /// The y coordinate.
  339. /// </param>
  340. /// <returns>
  341. /// </returns>
  342. private Point3D GetPoint(double x, double y)
  343. {
  344. return this.Center + this.widthDirection * x + this.lengthDirection * y;
  345. }
  346. }
  347. }