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

# · C# · 402 lines · 218 code · 47 blank · 137 comment · 4 complexity · 911a3e599c31ce27ee12ca0ad040c6d2 MD5 · raw file

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