public void SelectData(SphereDataView selectedPositionData, Point mousePosition)
        {
            // Show tooltip with details
            DataToolTipBorder.DataContext = selectedPositionData;

            Canvas.SetLeft(DataToolTipBorder, mousePosition.X + 10);
            Canvas.SetTop(DataToolTipBorder, mousePosition.Y + 10);

            DataToolTipBorder.Visibility = Visibility.Visible;


            // Add additional 3D lines that will show where the sphere is in the 3D space
            var centerPosition = AxesBox.CenterPosition;
            var size           = AxesBox.Size;

            double wireBoxBottom = centerPosition.Y - size.Y * 0.5;

            var verticalLineVisual3D = new Ab3d.Visuals.LineVisual3D()
            {
                StartPosition = selectedPositionData.Position,
                EndPosition   = new Point3D(selectedPositionData.Position.X, wireBoxBottom, selectedPositionData.Position.Z),
                LineThickness = 2,
                LineColor     = Colors.Gray
            };

            SelectedSphereLinesVisual.Children.Add(verticalLineVisual3D);

            double x1 = centerPosition.X - size.X * 0.5;
            double x2 = centerPosition.X + size.X * 0.5;

            var xLineVisual3D = new Ab3d.Visuals.LineVisual3D()
            {
                StartPosition = new Point3D(x1, wireBoxBottom, selectedPositionData.Position.Z),
                EndPosition   = new Point3D(x2, wireBoxBottom, selectedPositionData.Position.Z),
                LineThickness = 2,
                LineColor     = Colors.Gray
            };

            SelectedSphereLinesVisual.Children.Add(xLineVisual3D);

            double z1 = centerPosition.Z - size.Z * 0.5;
            double z2 = centerPosition.Z + size.Z * 0.5;

            var zLineVisual3D = new Ab3d.Visuals.LineVisual3D()
            {
                StartPosition = new Point3D(selectedPositionData.Position.X, wireBoxBottom, z1),
                EndPosition   = new Point3D(selectedPositionData.Position.X, wireBoxBottom, z2),
                LineThickness = 2,
                LineColor     = Colors.Gray
            };

            SelectedSphereLinesVisual.Children.Add(zLineVisual3D);
        }
        public static SphereDataView Create(SphereData originalSphereData, Rect3D displayedDataBounds, double maxTime, Rect xyDataRange, Color color)
        {
            // First calculate normalized values (from 0 to 1)
            double x = originalSphereData.Time / maxTime;
            double y = (originalSphereData.Location.Y - xyDataRange.Y) / xyDataRange.Height;
            double z = (originalSphereData.Location.X - xyDataRange.X) / xyDataRange.Width;


            // Now put normalized values into a 3D space that is defined by displayedDataBounds
            x = (x * displayedDataBounds.SizeX) + displayedDataBounds.X;
            y = (y * displayedDataBounds.SizeY) + displayedDataBounds.Y;
            z = (z * displayedDataBounds.SizeZ) + displayedDataBounds.Z;

            Point3D position3D = new Point3D(x, y, z);

            // Now we have all the data to create the SphereDataView
            var sphereDataView = new SphereDataView(originalSphereData, position3D, color, originalSphereData.Size);

            return(sphereDataView);
        }
        public void ShowData(List <SphereData> originalData, Rect3D displayedDataBounds, Rect xyDataRange)
        {
            // Now use original data to create our data view objects

            // All data will be displayed in a 3D box defined below:
            //var displayedDataBounds = new Rect3D(AxesBox.CenterPosition.X - AxesBox.Size.X * 0.5,
            //                                     AxesBox.CenterPosition.Y - AxesBox.Size.Y * 0.5,
            //                                     AxesBox.CenterPosition.Z - AxesBox.Size.Z * 0.5,
            //                                     AxesBox.Size.X,
            //                                     AxesBox.Size.Y,
            //                                     AxesBox.Size.Z);

            _allSpheresData = new List <SphereDataView>(originalData.Count);

            foreach (var originalSphereData in originalData)
            {
                // Set color of the sphere based on its y position
                // We choose the color from the gradient defined in EnsureGradientColorsArray
                double relativeY = (originalSphereData.Location.Y - xyDataRange.Y) / xyDataRange.Height;

                int   colorArrayIndex = (int)(relativeY * (_gradientColorsArray.Length - 1));
                Color color           = _gradientColorsArray[colorArrayIndex];


                var sphereDataView = SphereDataView.Create(originalSphereData, displayedDataBounds, originalData.Count, xyDataRange, color);

                sphereDataView.IsSelectedChanged += delegate(object sender, EventArgs args)
                {
                    var changedPositionDataView = (SphereDataView)sender;
                    if (changedPositionDataView.IsSelected)
                    {
                        DataListBox.SelectedItems.Add(changedPositionDataView);
                    }
                    else
                    {
                        DataListBox.SelectedItems.Remove(changedPositionDataView);
                    }

                    UpdateSelectedSpheresData();
                };

                _allSpheresData.Add(sphereDataView);
            }

            // Bind positions data to ListBox
            DataListBox.ItemsSource = _allSpheresData;


            // Create curve through all positions
            // This is done by first creating all points that define the curve (10 points between each position that define the curve)
            List <Point3D> allPositions = new List <Point3D>();

            foreach (var positionData in _allSpheresData)
            {
                allPositions.Add(positionData.Position);
            }

            BezierCurve       bezierCurve = Ab3d.Utilities.BezierCurve.CreateFromCurvePositions(allPositions);
            Point3DCollection curvePoints = bezierCurve.CreateBezierCurve(positionsPerSegment: 10); // How many points between each defined position in the curve

            // Create 3D Polyline from curvePoints
            Model3D curveModel = Ab3d.Models.Line3DFactory.CreatePolyLine3D(curvePoints, thickness: 2, color: Colors.Blue, isClosed: false, startLineCap: LineCap.Flat, endLineCap: LineCap.Flat, parentViewport3D: MainViewport);

            CurveModelVisual.Content = curveModel;


            // Now create 3D sphere objects for each position
            SpheresModelVisual.Children.Clear();

            // Each sphere will also need MouseEnter, MouseLeave and MouseClick event handlers
            // We use EventManager3D for that
            var eventManager3D = new Ab3d.Utilities.EventManager3D(MainViewport);


            // Add 3D sphere for each position
            foreach (var positionData in _allSpheresData)
            {
                SpheresModelVisual.Children.Add(positionData.ModelVisual3D); // Sphere Visual3D is created in SphereDataView object

                // Add event handlers (sphere Visual3D will be the source of the events)
                var visualEventSource3D = new VisualEventSource3D(positionData.ModelVisual3D);

                visualEventSource3D.MouseEnter += delegate(object sender, Mouse3DEventArgs e)
                {
                    if (_isSelecting)
                    {
                        return;
                    }

                    // Use hand cursor
                    Mouse.OverrideCursor = Cursors.Hand;

                    // Find selected position data
                    var selectedPositionData = _allSpheresData.FirstOrDefault(p => p.ModelVisual3D == e.HitObject);

                    SelectData(selectedPositionData, e.CurrentMousePosition);
                };

                visualEventSource3D.MouseLeave += delegate(object sender, Mouse3DEventArgs e)
                {
                    if (_isSelecting)
                    {
                        return;
                    }

                    Mouse.OverrideCursor = null;

                    DataToolTipBorder.Visibility  = Visibility.Collapsed;
                    DataToolTipBorder.DataContext = null;

                    SelectedSphereLinesVisual.Children.Clear();
                };

                visualEventSource3D.MouseClick += delegate(object sender, MouseButton3DEventArgs e)
                {
                    // Select / deselect on mouse click
                    var clickedPositionData = _allSpheresData.FirstOrDefault(p => p.ModelVisual3D == e.HitObject);

                    if (clickedPositionData != null)
                    {
                        positionData.IsSelected = !clickedPositionData.IsSelected;
                    }
                };

                // Register the event source
                eventManager3D.RegisterEventSource3D(visualEventSource3D);
            }
        }