public SphereDataView(SphereData originalSphereData, Point3D position, Color color, double radius)
        {
            OriginalSphereData = originalSphereData;

            Position = position;
            Color    = color;
            Radius   = radius;

            ScreenPosition = new Point(double.NaN, double.NaN);
        }
        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 static List <SphereData> GenerateRandomData(Rect xyDataRange, double relativeMargin, int dataCount)
        {
            // originalData will hold our original random data
            var originalData = new List <SphereData>();

            // Start in the middle
            var minX = xyDataRange.X;
            var minY = xyDataRange.Y;
            var maxX = xyDataRange.X + xyDataRange.Width;
            var maxY = xyDataRange.Y + xyDataRange.Height;

            minX += relativeMargin * xyDataRange.Width * 0.5;
            minY += relativeMargin * xyDataRange.Height * 0.5;
            maxX -= relativeMargin * xyDataRange.Width * 0.5;
            maxY -= relativeMargin * xyDataRange.Height * 0.5;


            // Set the initial position at the center of the xyDataRange
            double x = xyDataRange.X + xyDataRange.Width * 0.5;
            double y = xyDataRange.Y + xyDataRange.Height * 0.5;

            double vx = 0; // velocity
            double vy = 0;

            var    rnd = new Random();
            double randomizationFactor = 0.1; // How much data can adjust its position in one step (30%)

            // Add some random data - start at (x,y) and then move in random mostly positive direction
            for (int i = 0; i < dataCount; i++)
            {
                // Get random positive offset
                double dx = xyDataRange.Width * randomizationFactor * (rnd.NextDouble() * 2 - 1);  // random from -1 to +1
                double dy = xyDataRange.Height * randomizationFactor * (rnd.NextDouble() * 2 - 1);

                // Change velocity
                vx += dx;
                vy += dy;

                // change position based on current velocity
                x += vx;
                y += vy;


                // Prevent going out of limits
                if (x < minX)
                {
                    x  = minX + (minX - x);
                    vx = -vx;
                }
                else if (x > maxX)
                {
                    x  = maxX - (x - maxX);
                    vx = -vx;
                }

                if (y < minY)
                {
                    y  = minY + (minY - y);
                    vy = -vy;
                }
                else if (y > maxY)
                {
                    y  = maxY - (y - maxY);
                    vy = -vy;
                }


                // Just in case velocity is very high, we ensure that the values does not go out of bounds
                x = Math.Max(minX, Math.Min(maxX, x));
                y = Math.Max(minY, Math.Min(maxY, y));


                double sphereSize = rnd.NextDouble() * 3 + 1;

                var sphereData = new SphereData(time: i + 1, location: new Point(x, y), size: sphereSize);
                originalData.Add(sphereData);
            }

            return(originalData);
        }