/trunk/Source/HelixToolkit.Wpf/Helpers/Visual3DHelper.cs

# · C# · 423 lines · 224 code · 44 blank · 155 comment · 44 complexity · e0b06c41a5b3410cd8ba25c55ee30e66 MD5 · raw file

  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="Visual3DHelper.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.Linq;
  11. using System.Reflection;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Media;
  15. using System.Windows.Media.Media3D;
  16. /// <summary>
  17. /// Helper methods for <see cref="Visual3D"/> objects.
  18. /// </summary>
  19. public static class Visual3DHelper
  20. {
  21. #region Constants and Fields
  22. /// <summary>
  23. /// The visual 3 d model property info.
  24. /// </summary>
  25. private static readonly PropertyInfo Visual3DModelPropertyInfo = typeof(Visual3D).GetProperty(
  26. "Visual3DModel", BindingFlags.Instance | BindingFlags.NonPublic);
  27. #endregion
  28. #region Public Methods
  29. /// <summary>
  30. /// Finds a child of the specified type.
  31. /// </summary>
  32. /// <typeparam name="T">
  33. /// </typeparam>
  34. /// <param name="parent">
  35. /// The parent.
  36. /// </param>
  37. /// <returns>
  38. /// </returns>
  39. public static T Find<T>(DependencyObject parent) where T : DependencyObject
  40. {
  41. // todo: this should be improved
  42. foreach (DependencyObject d in LogicalTreeHelper.GetChildren(parent))
  43. {
  44. var a = Find<T>(d);
  45. if (a != null)
  46. {
  47. return a;
  48. }
  49. }
  50. var model = parent as ModelVisual3D;
  51. if (model != null)
  52. {
  53. var modelgroup = model.Content as Model3DGroup;
  54. if (modelgroup != null)
  55. {
  56. return modelgroup.Children.OfType<T>().FirstOrDefault();
  57. }
  58. }
  59. return null;
  60. }
  61. /// <summary>
  62. /// Finds the bounding box for a collection of Visual3Ds.
  63. /// </summary>
  64. /// <param name="children">
  65. /// The children.
  66. /// </param>
  67. /// <returns>
  68. /// </returns>
  69. public static Rect3D FindBounds(Visual3DCollection children)
  70. {
  71. var bounds = Rect3D.Empty;
  72. foreach (var visual in children)
  73. {
  74. var b = FindBounds(visual, Transform3D.Identity);
  75. bounds.Union(b);
  76. }
  77. return bounds;
  78. }
  79. /// <summary>
  80. /// Finds the bounding box for the specified visual.
  81. /// </summary>
  82. /// <param name="visual">
  83. /// The visual.
  84. /// </param>
  85. /// <param name="transform">
  86. /// The transform of visual.
  87. /// </param>
  88. /// <returns>
  89. /// </returns>
  90. public static Rect3D FindBounds(Visual3D visual, Transform3D transform)
  91. {
  92. var bounds = Rect3D.Empty;
  93. var childTransform = Transform3DHelper.CombineTransform(visual.Transform, transform);
  94. var model = GetModel(visual);
  95. if (model != null)
  96. {
  97. // apply transform
  98. var transformedBounds = childTransform.TransformBounds(model.Bounds);
  99. if (!double.IsNaN(transformedBounds.X))
  100. {
  101. bounds.Union(transformedBounds);
  102. }
  103. }
  104. foreach (var child in GetChildren(visual))
  105. {
  106. var b = FindBounds(child, childTransform);
  107. bounds.Union(b);
  108. }
  109. return bounds;
  110. }
  111. /// <summary>
  112. /// Gets the transform for the specified visual.
  113. /// </summary>
  114. /// <param name="visual">
  115. /// The visual.
  116. /// </param>
  117. /// <returns>
  118. /// </returns>
  119. public static Matrix3D GetTransform(Visual3D visual)
  120. {
  121. var totalTransform = Matrix3D.Identity;
  122. DependencyObject obj = visual;
  123. while (obj != null)
  124. {
  125. var viewport3DVisual = obj as Viewport3DVisual;
  126. if (viewport3DVisual != null)
  127. {
  128. return totalTransform;
  129. }
  130. var mv = obj as ModelVisual3D;
  131. if (mv != null)
  132. {
  133. if (mv.Transform != null)
  134. {
  135. totalTransform.Append(mv.Transform.Value);
  136. }
  137. }
  138. obj = VisualTreeHelper.GetParent(obj);
  139. }
  140. throw new InvalidOperationException("The visual is not added to a Viewport3D.");
  141. }
  142. /// <summary>
  143. /// Gets the Viewport3D from the specified visual.
  144. /// </summary>
  145. /// <param name="visual">
  146. /// The visual.
  147. /// </param>
  148. /// <returns>
  149. /// The Viewport3D
  150. /// </returns>
  151. public static Viewport3D GetViewport3D(Visual3D visual)
  152. {
  153. DependencyObject obj = visual;
  154. while (obj != null)
  155. {
  156. var vis = obj as Viewport3DVisual;
  157. if (vis != null)
  158. {
  159. return VisualTreeHelper.GetParent(obj) as Viewport3D;
  160. }
  161. obj = VisualTreeHelper.GetParent(obj);
  162. }
  163. return null;
  164. }
  165. /// <summary>
  166. /// Gets the transform to viewport space.
  167. /// </summary>
  168. /// <param name="visual">
  169. /// The visual.
  170. /// </param>
  171. /// <returns>
  172. /// A transformation matrix.
  173. /// </returns>
  174. public static Matrix3D GetViewportTransform(Visual3D visual)
  175. {
  176. var totalTransform = Matrix3D.Identity;
  177. DependencyObject obj = visual;
  178. while (obj != null)
  179. {
  180. var viewport3DVisual = obj as Viewport3DVisual;
  181. if (viewport3DVisual != null)
  182. {
  183. var matxViewport = Viewport3DHelper.GetTotalTransform(viewport3DVisual);
  184. totalTransform.Append(matxViewport);
  185. return totalTransform;
  186. }
  187. var mv = obj as ModelVisual3D;
  188. if (mv != null)
  189. {
  190. if (mv.Transform != null)
  191. {
  192. totalTransform.Append(mv.Transform.Value);
  193. }
  194. }
  195. obj = VisualTreeHelper.GetParent(obj);
  196. }
  197. throw new InvalidOperationException("The visual is not added to a Viewport3D.");
  198. // At this point, we know obj is Viewport3DVisual
  199. }
  200. /// <summary>
  201. /// Determines whether the visual is attached to a Viewport3D.
  202. /// </summary>
  203. /// <param name="visual">
  204. /// The visual.
  205. /// </param>
  206. /// <returns>
  207. /// The is attached to viewport 3 d.
  208. /// </returns>
  209. public static bool IsAttachedToViewport3D(Visual3D visual)
  210. {
  211. DependencyObject obj = visual;
  212. while (obj != null)
  213. {
  214. var vis = obj as Viewport3DVisual;
  215. if (vis != null)
  216. {
  217. return true;
  218. }
  219. obj = VisualTreeHelper.GetParent(obj);
  220. }
  221. return false;
  222. }
  223. /// <summary>
  224. /// Traverses the Visual3D/Model3D tree. Run the specified action for each Model3D.
  225. /// </summary>
  226. /// <typeparam name="T">
  227. /// </typeparam>
  228. /// <param name="visuals">
  229. /// The visuals.
  230. /// </param>
  231. /// <param name="action">
  232. /// The action.
  233. /// </param>
  234. public static void Traverse<T>(Visual3DCollection visuals, Action<T, Transform3D> action) where T : Model3D
  235. {
  236. foreach (var child in visuals)
  237. {
  238. Traverse(child, action);
  239. }
  240. }
  241. /// <summary>
  242. /// Traverses the Visual3D/Model3D tree. Run the specified action for each Model3D.
  243. /// </summary>
  244. /// <typeparam name="T">
  245. /// </typeparam>
  246. /// <param name="visual">
  247. /// The visual.
  248. /// </param>
  249. /// <param name="action">
  250. /// The action.
  251. /// </param>
  252. public static void Traverse<T>(Visual3D visual, Action<T, Transform3D> action) where T : Model3D
  253. {
  254. Traverse(visual, Transform3D.Identity, action);
  255. }
  256. /// <summary>
  257. /// Traverses the Model3D tree. Run the specified action for each Model3D.
  258. /// </summary>
  259. /// <typeparam name="T">
  260. /// </typeparam>
  261. /// <param name="model">
  262. /// The model.
  263. /// </param>
  264. /// <param name="action">
  265. /// The action.
  266. /// </param>
  267. public static void TraverseModel<T>(Model3D model, Action<T, Transform3D> action) where T : Model3D
  268. {
  269. TraverseModel(model, Transform3D.Identity, action);
  270. }
  271. /// <summary>
  272. /// Traverses the Model3D tree. Run the specified action for each Model3D.
  273. /// </summary>
  274. /// <typeparam name="T">
  275. /// </typeparam>
  276. /// <param name="model">
  277. /// The model.
  278. /// </param>
  279. /// <param name="transform">
  280. /// The transform.
  281. /// </param>
  282. /// <param name="action">
  283. /// The action.
  284. /// </param>
  285. public static void TraverseModel<T>(Model3D model, Transform3D transform, Action<T, Transform3D> action)
  286. where T : Model3D
  287. {
  288. var mg = model as Model3DGroup;
  289. if (mg != null)
  290. {
  291. var childTransform = Transform3DHelper.CombineTransform(model.Transform, transform);
  292. foreach (var m in mg.Children)
  293. {
  294. TraverseModel(m, childTransform, action);
  295. }
  296. }
  297. var gm = model as T;
  298. if (gm != null)
  299. {
  300. var childTransform = Transform3DHelper.CombineTransform(model.Transform, transform);
  301. action(gm, childTransform);
  302. }
  303. }
  304. #endregion
  305. #region Methods
  306. /// <summary>
  307. /// Gets the children.
  308. /// </summary>
  309. /// <param name="visual">
  310. /// The visual.
  311. /// </param>
  312. /// <returns>
  313. /// </returns>
  314. private static IEnumerable<Visual3D> GetChildren(Visual3D visual)
  315. {
  316. int n = VisualTreeHelper.GetChildrenCount(visual);
  317. for (int i = 0; i < n; i++)
  318. {
  319. var child = VisualTreeHelper.GetChild(visual, i) as Visual3D;
  320. if (child == null)
  321. {
  322. continue;
  323. }
  324. yield return child;
  325. }
  326. }
  327. /// <summary>
  328. /// Gets the model for the specified Visual3D.
  329. /// </summary>
  330. /// <param name="visual">
  331. /// The visual.
  332. /// </param>
  333. /// <returns>
  334. /// </returns>
  335. private static Model3D GetModel(Visual3D visual)
  336. {
  337. Model3D model;
  338. var mv = visual as ModelVisual3D;
  339. if (mv != null)
  340. {
  341. model = mv.Content;
  342. }
  343. else
  344. {
  345. model = Visual3DModelPropertyInfo.GetValue(visual, null) as Model3D;
  346. }
  347. return model;
  348. }
  349. /// <summary>
  350. /// Traverses the specified visual.
  351. /// </summary>
  352. /// <typeparam name="T">
  353. /// </typeparam>
  354. /// <param name="visual">
  355. /// The visual.
  356. /// </param>
  357. /// <param name="transform">
  358. /// The transform.
  359. /// </param>
  360. /// <param name="action">
  361. /// The action.
  362. /// </param>
  363. private static void Traverse<T>(Visual3D visual, Transform3D transform, Action<T, Transform3D> action)
  364. where T : Model3D
  365. {
  366. var childTransform = Transform3DHelper.CombineTransform(visual.Transform, transform);
  367. var model = GetModel(visual);
  368. if (model != null)
  369. {
  370. TraverseModel(model, childTransform, action);
  371. }
  372. foreach (var child in GetChildren(visual))
  373. {
  374. Traverse(child, childTransform, action);
  375. }
  376. }
  377. #endregion
  378. }
  379. }