Пример #1
0
 public static void RemoveAll(this Visual3DCollection collection, IEnumerable <Visual3D> visuals)
 {
     foreach (Visual3D visual in visuals)
     {
         collection.Remove(visual);
     }
 }
Пример #2
0
 public ViewportInformation(Visual3DCollection children, Camera camera, Size bounds, GeneralTransform transform)
 {
     this.children  = children;
     this.camera    = camera;
     this.bounds    = bounds;
     this.transform = transform;
 }
Пример #3
0
        private Model3DGroup ExtractModels(Visual3DCollection visuals)
        {
            Model3DGroup group = new Model3DGroup();

            // "visuals" cannot be null because we are not allowed
            //  to set the ModelVisual3D.Children property.
            System.Diagnostics.Debug.Assert(visuals != null, "Visual3DCollection should not be able to be null");

            foreach (Visual3D visual in visuals)
            {
                if (visual is ModelVisual3D)
                {
                    group.Children.Add(CreateModelGroupFromModelVisual3D((ModelVisual3D)visual));
                }

                #if TARGET_NET3_5
                else if (visual is ModelUIElement3D)
                {
                    group.Children.Add(CreateModelGroupFromModelUIElement3D((ModelUIElement3D)visual));
                }
                else if (visual is Viewport2DVisual3D)
                {
                    group.Children.Add(CreateModelGroupFromViewportVisual3D((Viewport2DVisual3D)visual));
                }
                #endif

                else
                {
                    throw new NotSupportedException("Only ModelVisual3D (+ViewportVisual3D & ModelUIElement3D in 3.5 build) is supported at this time");
                }
            }
            return(group);
        }
Пример #4
0
        // I got tired of writing these loops

        public static void AddRange(this Visual3DCollection collection, IEnumerable <Visual3D> visuals)
        {
            foreach (Visual3D visual in visuals)
            {
                collection.Add(visual);
            }
        }
Пример #5
0
        public static BoundingBox GetBoundingBox(Visual3DCollection visualItems)
        {
            BoundingBox result = new BoundingBox();

            foreach (Visual3D item in visualItems)
            {
                ModelVisual3D visual = (item as ModelVisual3D);
                if (visual != null)
                {
                    Body body = World.GetBody(visual);
                    if (body != null)
                    {
                        BoundingBox box = GetBoundingBox(body);

                        Matrix3D matrix = (body.Transform != null) ? body.Transform.Value : Matrix3D.Identity;
                        box.Min = matrix.Transform(box.Min);
                        box.Max = matrix.Transform(box.Max);

                        result.Union(box);
                    }
                }
            }

            return(result);
        }
Пример #6
0
 /// <summary>
 /// Traverses the Visual3D/Model3D tree. Run the specified action for each Model3D.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="visuals">The visuals.</param>
 /// <param name="action">The action.</param>
 public static void Traverse <T>(Visual3DCollection visuals, Action <T, Transform3D> action) where T : Model3D
 {
     foreach (var child in visuals)
     {
         Traverse(child, action);
     }
 }
        public static BoundingBox GetBoundingBox(Visual3DCollection visualItems)
        {
            BoundingBox result = new BoundingBox();

            foreach (Visual3D item in visualItems)
            {
                ModelVisual3D visual = (item as ModelVisual3D);
                if (visual != null)
                {
                    Body body = World.GetBody(visual);
                    if (body != null)
                    {
                        BoundingBox box = GetBoundingBox(body);

                        Matrix3D matrix = (body.Transform != null) ? body.Transform.Value : Matrix3D.Identity;
                        box.Min = matrix.Transform(box.Min);
                        box.Max = matrix.Transform(box.Max);

                        result.Union(box);
                    }
                }
            }

            return result;
        }
Пример #8
0
        public void DeletePart(int a_index)
        {
            if (a_index < m_collection.Count && a_index >= 0)
            {
                ModelPart     needDel  = m_collection[a_index];
                MeshElement3D modelDel = needDel.Node.GetModel();

                var parent = VisualTreeHelper.GetParent(modelDel);
                var pip    = parent.GetType().GetProperty("Children", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
                Visual3DCollection parentChildren = pip.GetValue(parent, null) as Visual3DCollection;
                parentChildren.Remove(modelDel);

                if (modelDel.Children.Count != 0)
                {
                    modelDel.Children.Clear();

                    int index = m_collection.IndexOf(needDel);
                    if (index > 0)
                    {
                        ModelPart parentModelPart = m_collection.ElementAt(index - 1);
                        parentModelPart.AddChild(m_collection.ElementAt(index + 1));
                    }
                    else
                    {
                        m_root.AddChild(m_collection.ElementAt(index + 1));
                    }
                }

                m_collection.Remove(needDel);
            }
        }
Пример #9
0
        public Scene()
        {
            sceneWindows = new SceneWindows();
            elementGroup = sceneWindows.model.Children;

            sceneWindows.MouseRightButtonDown += delegate { new ConfiguratedByForm(ElementList[0]); };
        }
Пример #10
0
 private void AddCubes(Visual3DCollection c, Brush brush, double x)
 {
     for (double y = -5; y <= 5; y += 10)
     {
         c.Add(new CubeVisual3D {
             Fill = brush, Center = new Point3D(x, y, 0)
         });
     }
 }
Пример #11
0
        /// <summary>
        /// Finds the bounding box for a collection of Visual3Ds.
        /// </summary>
        /// <param name="children">The children.</param>
        /// <returns></returns>
        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);
        }
Пример #12
0
 private static void PopulateChildVisuals(Variation v, string visualName, Visual3DCollection visualChildren)
 {
     if (v[visualName + "0"] != null)
     {
         Visual3D[] children = MakeVisuals(v, visualName);
         foreach (Visual3D v3d in children)
         {
             visualChildren.Add(v3d);
         }
     }
 }
Пример #13
0
 /// <summary>
 /// Sort Modelgroups in Farthest to Closest order, to enable transparency
 /// Should be applied whenever the scene is significantly re-oriented
 /// </summary>
 public static void AlphaSort(Point3D CameraPosition, Visual3DCollection Models)
 {
     ArrayList list = new ArrayList();
     foreach (Visual3D model in Models)
     {
         double distance = (Point3D.Subtract(CameraPosition, ((ModelUIElement3D)model).Model.Bounds.Location )).Length;
         list.Add(new ModelDistance(distance, model));
     }
     list.Sort(new DistanceComparer(SortDirection.FarToNear));
     Models.Clear();
     foreach (ModelDistance modelDistance in list)
     {
         Models.Add(modelDistance.model);
     }
 }
Пример #14
0
        private Visual3DCollection GetCorrespondingVisual3DCollection(AdornerSet3D.Location placement)
        {
            Visual3DCollection visual3Dcollection = (Visual3DCollection)null;

            switch (placement)
            {
            case AdornerSet3D.Location.ShadowLayer:
                visual3Dcollection = this.shadowAdorningContainer.Children;
                break;

            case AdornerSet3D.Location.OrthographicLayer:
                visual3Dcollection = this.orthographicAdorningContainer.Children;
                break;
            }
            return(visual3Dcollection);
        }
Пример #15
0
        public void AddToScene(Visual3DCollection elementGroup)
        {
            //pointDrawer.ElementGroup = elementGroup;

            meshGeneratorBase = new Petzold.Media3D.SphereMesh();
            sphere            = meshGeneratorBase.Geometry;
            //Color materialColor = new DiffuseMaterial(new SolidColorBrush(value));
            material = new DiffuseMaterial(new SolidColorBrush(Colors.AliceBlue));

            //foreach (IPosition3D position in position3DSet)
            //{
            //    //pointDrawer.Add(position.GetX(),
            //    //    position.GetY(),
            //    //    position.GetZ());

            //    GeometryModel3D geometryModel3D = new GeometryModel3D(sphere, material);
            //    Transform3DGroup transform3DGroup = new Transform3DGroup();
            //    transform3DGroup.Children.Add(new ScaleTransform3D(0.5, 0.5, 0.5));
            //    TranslateTransform3D translateTransform3D = new TranslateTransform3D(
            //        position.GetX(), position.GetY(), position.GetZ());
            //    transform3DGroup.Children.Add(translateTransform3D);
            //    geometryModel3D.Transform = transform3DGroup;
            //    modelGroup.Children.Add(geometryModel3D);
            //}

            //ModelVisual3D modelVisual3D = new ModelVisual3D();
            //modelVisual3D.Content = modelGroup;
            //elementGroup.Add(modelVisual3D);

            MeshGeometry3D positionSetMesh = new MeshGeometry3D();
            MeshGeometry3D sphereMesh      = new Sphere().Geometry;

            foreach (IPosition3D position in position3DSet)
            {
                MeshGeometry3D mesh = WPF3DHelper.Translate(sphereMesh, new Vector3D(
                                                                position.GetX(), position.GetY(), position.GetZ()));

                WPF3DHelper.CombineTo(positionSetMesh, mesh);
            }

            GeometryModel3D positionSetModel = new GeometryModel3D(positionSetMesh, material);

            ModelVisual3D modelVisual3D = new ModelVisual3D();

            modelVisual3D.Content = positionSetModel;
            elementGroup.Add(modelVisual3D);
        }
Пример #16
0
        /// <summary>
        /// Finds the bounding box for a collection of Visual3Ds.
        /// </summary>
        /// <param name="children">
        /// The children.
        /// </param>
        /// <returns>
        /// A <see cref="Rect3D"/>.
        /// </returns>
        public static Rect3D FindBounds(this Visual3DCollection children)
        {
            var bounds = Rect3D.Empty;

            foreach (var visual in children)
            {
                if (visual is IBoundsIgnoredVisual3D)
                {
                    continue;
                }

                var b = FindBounds(visual, Transform3D.Identity);
                bounds.Union(b);
            }

            return(bounds);
        }
Пример #17
0
        private static void AddChildren(FrameworkElementFactory factory, Visual3DCollection visuals)
        {
            foreach (Visual3D visual in visuals)
            {
                ModelVisual3D model = visual as ModelVisual3D;
                if (model == null)
                {
                    continue;
                }
                FrameworkElementFactory f = new FrameworkElementFactory(typeof(ModelVisual3D));
                f.SetValue(ModelVisual3D.ContentProperty, model.Content);
                f.SetValue(ModelVisual3D.TransformProperty, model.Transform);
                AddChildren(f, model.Children);

                factory.AppendChild(f);
            }
        }
Пример #18
0
        public static void CopyChildren(Visual3DCollection targetCollection, Visual3DCollection sourceCollection)
        {
            foreach (Visual3D item in sourceCollection)
            {
                Visual3D      newVisual3D = (Visual3D)Activator.CreateInstance(item.GetType());
                ModelVisual3D newModel    = (newVisual3D as ModelVisual3D);
                if (newModel != null)
                {
                    ModelVisual3D sourceModel = (ModelVisual3D)item;
                    newModel.Content   = sourceModel.Content;
                    newModel.Transform = sourceModel.Transform;

                    CopyChildren(newModel.Children, sourceModel.Children);
                }
                targetCollection.Add(newVisual3D);
            }
        }
Пример #19
0
        void UpdateMeshResolution(short resolution, double sampling_interval)
        {
            // ------------------------------
            // Adjust cursor size
            // ------------------------------
            CursorScaleB.ScaleX = CursorScaleB.ScaleY = CursorScaleB.ScaleZ = Math.PI / 8 / resolution;

            // ------------------------------
            // Create pixelization scheme
            // ------------------------------
            pixelization            = new Healpix.Healpix();
            pixelization.Resolution = resolution;

            // ------------------------------
            // Create border lines
            // ------------------------------
            border = new HealpixBorder();
            try
            {
                border.SamplingInterval = sampling_interval;
                border.Resolution       = resolution;
            }
            catch (Exception e)
            {
                Console.WriteLine("{0} Exception caught.", e);
            }

            Visual3DCollection elements = BorderContainer.Children;

            elements.Clear();
            int n = border.GetNumberOfBorderLines();

            for (int i = 0; i < n; i++)
            {
                WirePolyline line = new WirePolyline();
                line.Points    = border.GetAsCartesianCoord(i);
                line.Color     = Colors.Black;
                line.Thickness = border.GetBorderThickness(i);
                elements.Add(line);
            }

            UpdateMapMesh();
        }
Пример #20
0
        /*       MeshGeometry3D Mesh
         * {
         *  get
         *  {
         *      string s = source.Xaml + "";
         *      Visual3D v3d;
         *      object ob = System.Windows.Markup.XamlReader.Parse(s);
         *      MeshGeometry3D mg = null;
         *      if (ob is Visual3D)
         *      {
         *          v3d = ob as Visual3D;
         *          if (v3d is ModelVisual3D)
         *          {
         *              ModelVisual3D mv3d = v3d as ModelVisual3D;
         *              Model3DGroup mdg = mv3d.Content as Model3DGroup;
         *              foreach (Model3D g in mdg.Children)
         *              {
         *                  if (!(g is GeometryModel3D))
         *                  {
         *                      continue;
         *                  }
         *                  GeometryModel3D g3d = g as GeometryModel3D;
         *                  Geometry3D geo = g3d.Geometry;
         *                  if (geo is MeshGeometry3D)
         *                  {
         *                      mg = geo as MeshGeometry3D;
         *                      return mg;
         *                  }
         *              }
         *          }
         *      }
         *      return null;
         *  }
         * }
         */

        private void Detect(Visual3D v3d, List <MeshGeometry3D> list)
        {
            if (v3d is ModelVisual3D)
            {
                ModelVisual3D mv3d = v3d as ModelVisual3D;
                Model3D       m3d  = mv3d.Content;
                if (m3d is GeometryModel3D)
                {
                    GeometryModel3D g3d = m3d as GeometryModel3D;
                    Geometry3D      geo = g3d.Geometry;
                    if (geo is MeshGeometry3D)
                    {
                        list.Add(geo as MeshGeometry3D);
                    }
                }
                if (m3d is Model3DGroup)
                {
                    Model3DGroup mdg = m3d as Model3DGroup;
                    foreach (Model3D g in mdg.Children)
                    {
                        if (!(g is GeometryModel3D))
                        {
                            continue;
                        }
                        GeometryModel3D g3d = g as GeometryModel3D;
                        Geometry3D      geo = g3d.Geometry;
                        if (geo is MeshGeometry3D)
                        {
                            list.Add(geo as MeshGeometry3D);
                        }
                    }
                }
                else
                {
                    Visual3DCollection coll = mv3d.Children;
                    foreach (Visual3D v in coll)
                    {
                        Detect(v, list);
                    }
                }
            }
        }
Пример #21
0
        //----------------------------------------------------- 
        //
        //  Constructors
        //
        //----------------------------------------------------- 

        #region Constructors 
 
        /// <summary>
        ///     Default ctor 
        /// </summary>
        public ModelVisual3D()
        {
            _children = new Visual3DCollection(this); 
        }
Пример #22
0
 private void AddCubes(Visual3DCollection c, Brush brush, double x)
 {
     for (double y = -5; y <= 5; y += 10)
         c.Add(new CubeVisual3D { Fill = brush, Center = new Point3D(x, y, 0) });
 }
Пример #23
0
        /// <summary>
        /// Constructor. This form of constructor will encounter a slight perf hit since it needs to initialize Dispatcher for the instance.
        /// </summary>
        protected UIElement3D()
        {
            _children = new Visual3DCollection(this);

            Initialize();
        }
Пример #24
0
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        /// <summary>
        ///     Default constructor
        /// </summary>
        public Viewport3DVisual() : base(DUCE.ResourceType.TYPE_VIEWPORT3DVISUAL)
        {            
            _children = new Visual3DCollection(this);
        }
Пример #25
0
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors
        
        /// <summary>
        ///     Default ctor
        /// </summary>
        public ContainerUIElement3D()
        {
            _children = new Visual3DCollection(this);
        }
Пример #26
0
        private void GenerateAndAddShapeToCollection(List <Point3D> points, List <int> pointIndexes, Brush vertColor, Visual3DCollection collection)
        {
            // add all points (vertices)
            foreach (var point in points)
            {
                var vert = CreateVertex(point, vertColor);
                collection.Add(vert);
            }

            // add all lines (edges)
            for (int i = 0; i < pointIndexes.Count; i += 2)
            {
                var line = CreateLine(points[pointIndexes[i]], points[pointIndexes[i + 1]]);
                collection.Add(line);
            }
        }
Пример #27
0
        private bool WalkVisual3DChildren(Visual3DCollection visual3DCollection, Matrix3D currentTransform, RectangleHitTestResultTreeNode node)
        {
            bool flag1 = false;

            if (visual3DCollection == null)
            {
                return(false);
            }
            foreach (Visual3D reference in visual3DCollection)
            {
                Matrix3D currentTransform1 = currentTransform;
                if (reference.Transform != null)
                {
                    currentTransform1.Prepend(reference.Transform.Value);
                }
                if (this.TestSphereEnclosingBoundingBoxAgainstFrustum(VisualTreeHelper.GetContentBounds(reference), currentTransform1))
                {
                    RectangleHitTestResultTreeNode testResultTreeNode = new RectangleHitTestResultTreeNode(node, (DependencyObject)reference);
                    bool                 flag2                = false;
                    ModelVisual3D        modelVisual3D        = reference as ModelVisual3D;
                    ModelUIElement3D     modelUiElement3D     = reference as ModelUIElement3D;
                    ContainerUIElement3D containerUiElement3D = reference as ContainerUIElement3D;
                    Viewport2DVisual3D   viewport2Dvisual3D   = reference as Viewport2DVisual3D;
                    if (modelVisual3D != null)
                    {
                        if (this.WalkModelTree(modelVisual3D.Content, currentTransform1, testResultTreeNode))
                        {
                            flag1 = true;
                        }
                        if (this.WalkVisual3DChildren(modelVisual3D.Children, currentTransform1, testResultTreeNode))
                        {
                            flag1 = true;
                        }
                    }
                    else if (modelUiElement3D != null)
                    {
                        if (this.WalkModelTree(modelUiElement3D.Model, currentTransform1, testResultTreeNode))
                        {
                            flag1 = true;
                        }
                    }
                    else if (containerUiElement3D != null)
                    {
                        if (this.WalkVisual3DChildren(containerUiElement3D.Children, currentTransform1, testResultTreeNode))
                        {
                            flag1 = true;
                        }
                    }
                    else if (viewport2Dvisual3D != null && viewport2Dvisual3D.Geometry != null)
                    {
                        flag2 = this.HitTestAgainstGeometry((DependencyObject)viewport2Dvisual3D, viewport2Dvisual3D.Geometry.Bounds, viewport2Dvisual3D.Transform, viewport2Dvisual3D.Geometry as MeshGeometry3D, currentTransform, viewport2Dvisual3D.Material, (Material)null, node);
                    }
                    if (flag1)
                    {
                        node.AddChild(testResultTreeNode);
                    }
                    if (flag2)
                    {
                        flag1 = true;
                    }
                }
            }
            return(flag1);
        }
Пример #28
0
        // UpdateViewportCanvas will render the 3D scene with 2D polygons with transforming all 3D points to 2D coordinates
        // It will render all children of ObjectsRootVisual3D (to render all children of Viewport3D, use MainViewport.Children)
        // The method is static so it can be easily copied to some other location for some other testing
        private static void UpdateViewportCanvas(Visual3DCollection visuals, BaseCamera camera, Canvas viewportCanvas, bool fillPolygon)
        {
            // Get camera's view and projection matrixes
            Matrix3D viewMatrix, projectionMatrix;

            camera.GetCameraMatrixes(out viewMatrix, out projectionMatrix);

            // Calculate combined viewProjection matrix
            Matrix3D viewProjectionMatrix3D = viewMatrix * projectionMatrix;

            // Read target canvas size and its center point (half the size)
            double viewportCanvasWidth  = viewportCanvas.ActualWidth;
            double viewportCanvasHeight = viewportCanvas.ActualHeight;

            double viewportCanvasCenterX = viewportCanvasWidth * 0.5;
            double viewportCanvasCenterY = viewportCanvasHeight * 0.5;


            // Clear all existing Polygons
            viewportCanvas.Children.Clear();

            // IterateGeometryModel3DObjects will traverse the Visual3D and Model3DGroup objects
            // and will call the callback delegate for each GeometryModel3D.
            // The callback delegate also receives the transformation that were applied to the parents of the GeometryModel3D.
            // If you want to be called for each ModelVisual3D, use the IterateModelVisualsObjects method
            Ab3d.Utilities.ModelIterator.IterateGeometryModel3DObjects(visuals : visuals,
                                                                       parentTransform3D : null, // optionally we can specify the initial transformation
                                                                       callback : delegate(GeometryModel3D geometryModel3D, Transform3D parentTransform3D)
            {
                // This is called for each GeometryModel3D in the hierarchy
                var meshGeometry3D = geometryModel3D.Geometry as MeshGeometry3D;

                if (meshGeometry3D == null)
                {
                    return;
                }

                var positions       = meshGeometry3D.Positions;
                var triangleIndices = meshGeometry3D.TriangleIndices;

                if (positions == null || positions.Count == 0 || triangleIndices == null || triangleIndices.Count == 0)
                {
                    return;
                }

                // Get fill brush from material
                var materialBrush = GetMaterialBrush(geometryModel3D.Material);

                // If this geometryModel3D has any transformation, combine it with the parentTransform3D - this will be the world transformation for this geometryModel3D
                var worldTransform = CombineTransform(parentTransform3D, geometryModel3D.Transform);

                Matrix3D worldViewProjectionMatrix3D;

                // Get final worldViewProjectionMatrix3D
                if (worldTransform == null || worldTransform.Value.IsIdentity)
                {
                    worldViewProjectionMatrix3D = viewProjectionMatrix3D;
                }
                else
                {
                    worldViewProjectionMatrix3D = worldTransform.Value * viewProjectionMatrix3D;
                }


                var triangleIndicesCount = triangleIndices.Count;

                // Go through all triangles
                for (int i = 0; i < triangleIndicesCount; i += 3)
                {
                    // Read positions for one triangle
                    Point3D p1 = positions[triangleIndices[i]];
                    Point3D p2 = positions[triangleIndices[i + 1]];
                    Point3D p3 = positions[triangleIndices[i + 2]];

                    // Transform to homogeneous coordinates (to get final x and y we need to divide them by w)
                    Point4D h1 = worldViewProjectionMatrix3D.Transform(new Point4D(p1.X, p1.Y, p1.Z, 1));
                    Point4D h2 = worldViewProjectionMatrix3D.Transform(new Point4D(p2.X, p2.Y, p2.Z, 1));
                    Point4D h3 = worldViewProjectionMatrix3D.Transform(new Point4D(p3.X, p3.Y, p3.Z, 1));

                    // Do a simple clip test - if any position is behind the camera we will not render this triangle
                    if (h1.Z < 0 || h2.Z < 0 || h3.Z < 0)
                    {
                        return;
                    }


                    // Convert to screen coordinates by dividing by w and then adjust to the size of canvas (we also invert y)
                    Point canvas1 = new Point((h1.X * viewportCanvasWidth) / (2 * h1.W) + viewportCanvasCenterX,
                                              viewportCanvasHeight - ((h1.Y * viewportCanvasHeight) / (2 * h1.W) + viewportCanvasCenterY));  // invert y

                    Point canvas2 = new Point((h2.X * viewportCanvasWidth) / (2 * h2.W) + viewportCanvasCenterX,
                                              viewportCanvasHeight - ((h2.Y * viewportCanvasHeight) / (2 * h2.W) + viewportCanvasCenterY));

                    Point canvas3 = new Point((h3.X * viewportCanvasWidth) / (2 * h3.W) + viewportCanvasCenterX,
                                              viewportCanvasHeight - ((h3.Y * viewportCanvasHeight) / (2 * h3.W) + viewportCanvasCenterY));


                    // Create triangle
                    // TODO: This creates many Polyline objects on each change of camera - to improve performance it would be possible to reuse the existing Polylines and just change the position's coordinates

                    var points = new PointCollection(3);
                    points.Add(canvas1);
                    points.Add(canvas2);
                    points.Add(canvas3);

                    var polyline = new Polygon()
                    {
                        Points           = points,
                        StrokeThickness  = 1,
                        StrokeMiterLimit = 1
                    };

                    if (fillPolygon)
                    {
                        polyline.Fill   = materialBrush;
                        polyline.Stroke = Brushes.Black;
                    }
                    else
                    {
                        polyline.Fill   = null;
                        polyline.Stroke = materialBrush;
                    }

                    viewportCanvas.Children.Add(polyline);
                }
            });
        }
 public static void Add(this Visual3DCollection visuals, params Visual3D[] children)
 => visuals.AddRange(children);