using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
namespace HelixToolkit
{
///
/// Helper methods for objects.
///
public static class Visual3DHelper
{
///
/// Finds the bounding box for a collection of Visual3Ds.
///
/// The children.
///
public static Rect3D FindBounds(Visual3DCollection children)
{
var bounds = Rect3D.Empty;
foreach (var visual in children)
{
var b = FindBounds(visual, Transform3D.Identity);
bounds.Union(b);
}
return bounds;
}
///
/// Finds the bounding box for the specified visual.
///
/// The visual.
/// The transform if the visual.
///
public static Rect3D FindBounds(Visual3D visual, Transform3D transform)
{
var bounds = Rect3D.Empty;
var childTransform = Transform3DHelper.CombineTransform(visual.Transform, transform);
var model = GetModel(visual);
if (model != null)
{
// apply transform
var transformedBounds = childTransform.TransformBounds(model.Bounds);
bounds.Union(transformedBounds);
}
foreach (var child in GetChildren(visual))
{
var b = FindBounds(child, childTransform);
bounds.Union(b);
}
return bounds;
}
private static readonly PropertyInfo Visual3DModelPropertyInfo =
typeof(Visual3D).GetProperty("Visual3DModel", BindingFlags.Instance | BindingFlags.NonPublic);
private static Model3D GetModel(Visual3D visual)
{
Model3D model;
var mv = visual as ModelVisual3D;
if (mv != null)
{
model = mv.Content;
}
else
{
model = Visual3DModelPropertyInfo.GetValue(visual, null) as Model3D;
}
return model;
}
private static IEnumerable GetChildren(Visual3D visual)
{
int n = VisualTreeHelper.GetChildrenCount(visual);
for (int i = 0; i < n; i++)
{
var child = VisualTreeHelper.GetChild(visual, i) as Visual3D;
if (child == null)
continue;
yield return child;
}
}
///
/// Traverses the Visual3D/Model3D tree. Run the specified action for each Model3D.
///
///
/// The visuals.
/// The action.
public static void Traverse(Visual3DCollection visuals, Action action) where T : Model3D
{
foreach (var child in visuals)
Traverse(child, action);
}
///
/// Traverses the Visual3D/Model3D tree. Run the specified action for each Model3D.
///
///
/// The visual.
/// The action.
public static void Traverse(Visual3D visual, Action action) where T : Model3D
{
Traverse(visual, Transform3D.Identity, action);
}
private static void Traverse(Visual3D visual, Transform3D transform,
Action action) where T : Model3D
{
var childTransform = Transform3DHelper.CombineTransform(visual.Transform, transform);
var model = GetModel(visual);
if (model != null)
{
TraverseModel(model, childTransform, action);
}
foreach (var child in GetChildren(visual))
{
Traverse(child, childTransform, action);
}
}
///
/// Traverses the Model3D tree. Run the specified action for each Model3D.
///
///
/// The model.
/// The action.
public static void TraverseModel(Model3D model, Action action) where T : Model3D
{
TraverseModel(model, Transform3D.Identity, action);
}
///
/// Traverses the Model3D tree. Run the specified action for each Model3D.
///
///
/// The model.
/// The transform.
/// The action.
public static void TraverseModel(Model3D model, Transform3D transform, Action action)
where T : Model3D
{
var mg = model as Model3DGroup;
if (mg != null)
{
var childTransform = Transform3DHelper.CombineTransform(model.Transform, transform);
foreach (var m in mg.Children)
TraverseModel(m, childTransform, action);
}
var gm = model as T;
if (gm != null)
{
var childTransform = Transform3DHelper.CombineTransform(model.Transform, transform);
action(gm, childTransform);
}
}
public static T Find(DependencyObject parent) where T : DependencyObject
{
// todo: this should be improved
foreach (DependencyObject d in LogicalTreeHelper.GetChildren(parent))
{
var a = Find(d);
if (a != null) return a;
}
var model = parent as ModelVisual3D;
if (model != null)
{
var modelgroup = model.Content as Model3DGroup;
if (modelgroup != null)
{
return modelgroup.Children.OfType().FirstOrDefault();
}
}
return null;
}
public static Matrix3D GetTotalTransform(Visual3D visual)
{
var totalTransform = Matrix3D.Identity;
DependencyObject obj = visual;
while (obj!=null)
{
var vis = obj as Viewport3DVisual;
if (vis!=null)
{
var matxViewport = Viewport3DHelper.GetTotalTransform(vis);
totalTransform.Append(matxViewport);
return totalTransform;
}
var mv = obj as ModelVisual3D;
if (mv!=null)
{
if (mv.Transform != null)
totalTransform.Append(mv.Transform.Value);
}
obj = VisualTreeHelper.GetParent(obj);
}
throw new InvalidOperationException("The visual is not added to a Viewport3D.");
// At this point, we know obj is Viewport3DVisual
}
public static bool IsAttachedToViewport3D(Visual3D visual)
{
DependencyObject obj = visual;
while (obj != null)
{
var vis = obj as Viewport3DVisual;
if (vis != null)
{
return true;
}
obj = VisualTreeHelper.GetParent(obj);
}
return false;
}
}
}