Beispiel #1
0
        public void AddBodyActual(double mass, bool isGravitySource, double diameter, int color, SimPoint startPosition, SimPoint startVelocity)
        {
            var velocity = new SimPoint(startVelocity.X / simSpace.VelocityConnversionFactor, startVelocity.Y / simSpace.VelocityConnversionFactor);

            bodies.Add(new Body(mass, diameter, startPosition, velocity, isGravitySource, simSpace));
            renderer.Add(diameter, color, bodies.Last());
        }
Beispiel #2
0
        public TranslateTransform CircleTransform(SimPoint position, double size)
        {
            TranslateTransform t = new TranslateTransform();
            double             circleCenterTranslation = -size / 2.0;

            t.X = position.X * scaleFactor + simulationCenterTranslation.X + circleCenterTranslation;
            t.Y = position.Y * -scaleFactor + simulationCenterTranslation.Y + circleCenterTranslation;

            return(t);
        }
Beispiel #3
0
 public Body(double bodyMass, double bodySize, SimPoint bodyStartingPosition, SimPoint bodyStartingVelocity, SimulationSpace space)
 {
     Mass            = bodyMass;
     Size            = bodySize;
     Position        = bodyStartingPosition;
     Velocity        = bodyStartingVelocity;
     IsGravitySource = defaultGravitySource;
     simSpace        = space;
     bodyNumber      = currentBodyNumber++;
 }
Beispiel #4
0
        /// <summary>
        /// Puts a body into a clockwise circular orbit
        /// </summary>
        /// <param name="startingPosition">Angle, measured in degrees, with 0 degrees at top of orbit</param>
        /// <param name="orbitRadius"></param>
        /// <param name="position"></param>
        /// <param name="velocity"></param>
        public void InitializeCircularOrbit(double startingPosition, double orbitRadius, double centralMass, out SimPoint position, out SimPoint velocity)
        {
            double startingPositionRadians = Math.PI * 2.0 * (startingPosition / 360.0);

            position = new SimPoint(orbitRadius * Math.Sin(startingPositionRadians), orbitRadius * Math.Cos(startingPositionRadians));

            double orbitVelocity = CircularOrbitVelocity(centralMass, orbitRadius);

            velocity = new SimPoint(orbitVelocity * Math.Cos(startingPositionRadians), -orbitVelocity * Math.Sin(startingPositionRadians));
        }
Beispiel #5
0
 public Body(SimPoint bodyStartingPosition, SimulationSpace space)
 {
     Mass            = defaultValue;
     Size            = defaultValue;
     Position        = bodyStartingPosition;
     Velocity        = defaultStartingVelocity;
     IsGravitySource = defaultGravitySource;
     simSpace        = space;
     bodyNumber      = currentBodyNumber++;
 }
Beispiel #6
0
        public void Move(SimPoint accel, double deltaT)
        {
            if (!((accel.X == 0.0) && (accel.Y == 0.0)))
            {
                // Apply linear acceleration during the time interval

                double newVelocityX = velocity.X + (accel.X * deltaT);
                position.X += (velocity.X + newVelocityX) / 2 * deltaT;
                velocity.X  = newVelocityX;

                double newVelocityY = velocity.Y + (accel.Y * deltaT);
                position.Y += (velocity.Y + newVelocityY) / 2 * deltaT;
                velocity.Y  = newVelocityY;
            }
        }
Beispiel #7
0
        public void PlotTrailDot(SimPoint position)
        {
            // Always plot the first dot
            // Don't plot subsequent dots iff they're in the same position as the previous dot
            if ((trailsPositions.Count == 0) || !position.Equals(previousTrailPosition))
            {
                previousTrailPosition = position;

                trailsPositions.Add(position);

                Rectangle dot = new Rectangle();
                dot.Width           = dot.Height = dotSize;
                dot.Fill            = trailsBrush;
                dot.RenderTransform = CircleTransform(position, dotSize);
                simCanvas.Children.Add(dot);
            }
        }
Beispiel #8
0
 // Updated to be marshalled onto the UI thread
 public void UpdateMonitoredValues(Body body, double simElapsedTime)
 {
     if (UI_UpdatesStopped())
     {
         return;                        // Stop UI updates while app is suspended or changing scenarios
     }
     var ignore = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
     {
         SimPoint velocity      = body.Velocity * sim.simSpace.VelocityConnversionFactor;
         velocityTextBlock.Text = "velocity: " + FormatPointToString(velocity) +
                                  String.Format(", v = {0:N1} {1}", velocity.Magnitude(), sim.simSpace.VelocityUnitsAbbr);
         positionTextBlock.Text = "position: " + FormatPointToString(body.Position) +
                                  String.Format(", r = {0:N1} {1}", body.Position.Magnitude() - sim.simSpace.DistanceOffset,
                                                sim.simSpace.DistanceUnitsAbbr);
         timeTextBlock.Text = $"time: {TimeDisplay.FormatElapsedTime(simElapsedTime, sim.simSpace.TimeUnits)}";
     });
 }
Beispiel #9
0
        public void MoveWithPrecisionCheck(SimPoint accel, double deltaT)
        {
            if (!((accel.X == 0.0) && (accel.Y == 0.0)))
            {
                // Apply linear acceleration during the time interval

                double deltaVX = accel.X * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(velocity.X, deltaVX))
                {
                    DisplayPrecisionIssue(velocity.X, deltaVX, "Adding DeltaV to VX", bodyNumber);
                }
                double newVelocityX = velocity.X + deltaVX;

                double deltaPX = (velocity.X + newVelocityX) / 2 * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(position.X, deltaPX))
                {
                    DisplayPrecisionIssue(position.X, deltaPX, "Adding to Position.X", bodyNumber);
                }
                position.X += deltaPX;

                velocity.X = newVelocityX;


                double deltaVY = accel.Y * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(velocity.Y, deltaVY))
                {
                    DisplayPrecisionIssue(velocity.Y, deltaVY, "Adding DeltaV to VY", bodyNumber);
                }
                double newVelocityY = velocity.Y + deltaVY;

                double deltaPY = (velocity.Y + newVelocityY) / 2 * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(position.Y, deltaPY))
                {
                    DisplayPrecisionIssue(position.Y, deltaPY, "Adding to Position.Y", bodyNumber);
                }
                position.Y += deltaPY;

                velocity.Y = newVelocityY;
            }
        }
Beispiel #10
0
        // Calculates the mapping from simulation coordinates to XAML coordinates
        //  Called when the simulation is loaded and whenever the window is resized
        public void SetSimulationTransform(double screenWidth, double screenHeight)
        {
            screenDimensions = new Point(screenWidth, screenHeight);
            double minDimension = Math.Min(screenWidth, screenHeight);


            // This can be called before any scenarios have been loaded, provide a placeholder value in this case
            double simBoxDimensions;

            if (simSpace == null)
            {
                simBoxDimensions = 1.0;
            }
            else
            {
                simBoxDimensions = simSpace.SimBoxHeightAndWidth;
            }

            scaleFactor = minDimension / simBoxDimensions;
            simulationCenterTranslation = new Point(screenWidth / 2, screenHeight / 2);
            screenSimulationDimensions  = new SimPoint(screenWidth / scaleFactor, screenHeight / scaleFactor);

            scaleFactor = scaleFactor * ZoomFactor;
        }
Beispiel #11
0
        // Returns starting position for a body in simulation space coordinates
        public SimPoint GetStartingPosition(GravitySim.BodyStartPosition startPos)
        {
            const double stagePosition = 0.5; // For the "stage" positions - proportion of the way from the center of the stage to the edge
                                              //    in all directions

            double simBoxMaxXY = simSpace.SimBoxHeightAndWidth / 2.0;
            double stageXY     = simBoxMaxXY * stagePosition;

            double screenMaxX = screenSimulationDimensions.X / 2.0;
            double screenMaxY = screenSimulationDimensions.Y / 2.0;

            switch (startPos)
            {
            case GravitySim.BodyStartPosition.StageLeft:
                return(new SimPoint(-stageXY, 0.0));

            case GravitySim.BodyStartPosition.StageRight:
                return(new SimPoint(stageXY, 0.0));

            case GravitySim.BodyStartPosition.StageTop:
                return(new SimPoint(0.0, stageXY));

            case GravitySim.BodyStartPosition.StageBottom:
                return(new SimPoint(0.0, -stageXY));

            case GravitySim.BodyStartPosition.StageTopLeft:
                return(new SimPoint(-stageXY, stageXY));

            case GravitySim.BodyStartPosition.StageTopRight:
                return(new SimPoint(stageXY, stageXY));

            case GravitySim.BodyStartPosition.StageBottomLeft:
                return(new SimPoint(-stageXY, -stageXY));

            case GravitySim.BodyStartPosition.StageBottomRight:
                return(new SimPoint(stageXY, -stageXY));

            case GravitySim.BodyStartPosition.ScreenLeft:
                return(new SimPoint(-screenMaxX, 0.0));

            case GravitySim.BodyStartPosition.ScreenRight:
                return(new SimPoint(screenMaxX, 0.0));

            case GravitySim.BodyStartPosition.ScreenTop:
                return(new SimPoint(0.0, screenMaxY));

            case GravitySim.BodyStartPosition.ScreenBottom:
                return(new SimPoint(0.0, -screenMaxY));

            case GravitySim.BodyStartPosition.CenterOfTheUniverse:
                return(new SimPoint(0.0, 0.0));

            case GravitySim.BodyStartPosition.RandomStagePosition:
                return(new SimPoint(rand.Next((int)-simBoxMaxXY, (int)simBoxMaxXY),
                                    rand.Next((int)-simBoxMaxXY, (int)simBoxMaxXY)));

            case GravitySim.BodyStartPosition.RandomScreenPosition:
                return(new SimPoint(rand.Next((int)-screenMaxX, (int)screenMaxX),
                                    rand.Next((int)-screenMaxY, (int)screenMaxY)));

            // This approach gives us higher density toward the center of the circle
            case GravitySim.BodyStartPosition.RandomDenseCenterCircularCluster:
                double length = rand.NextDouble() * simBoxMaxXY * 0.9;
                double angle  = rand.NextDouble() * Math.PI * 2.0;    // radians
                return(new SimPoint(length * Math.Cos(angle), length * Math.Sin(angle)));

            // This approach gives us uniform density throughout the circle
            case GravitySim.BodyStartPosition.RandomUniformDensityCircularCluster:
                SimPoint newBodyPosition;
                double   limitXY = 0.9 * simBoxMaxXY;
                do
                {
                    newBodyPosition = new SimPoint(rand.Next((int)-limitXY, (int)limitXY),
                                                   rand.Next((int)-limitXY, (int)limitXY));
                }while (newBodyPosition.Magnitude() > limitXY);
                return(newBodyPosition);

            default:
                return(new SimPoint(0.0, 0.0));
            }
        }
Beispiel #12
0
        //  simRunning - true if sim is auto-running
        //               false if sim is single stepping
        public void Step(double timeInterval, bool simRunning)
        {
            Stopwatch perfStopwatch     = new Stopwatch();
            long      perfIntervalTicks = 0L;
            bool      simStepping       = !simRunning;

            double scaledTimeInterval = timeInterval * SpeedFactor;

            SetTimeForTrailMark(simElapsedTime);

            if (simStepping)
            {
                Debug.WriteLine("Elapsed times for {0} bodies:", bodies.Count());
                perfStopwatch.Start();
            }

            if (accelerations == null)
            {
                accelerations = new SimPoint[bodies.Count()];
            }

            if (checkSim)
            {
                if (positions == null)
                {
                    positions = new SimPoint[bodies.Count()];
                }
                if (velocities == null)
                {
                    velocities = new SimPoint[bodies.Count()];
                }
            }

            double timeIntervalPerCycle = scaledTimeInterval / (double)simCalcSettings.CalculationCyclesPerFrame;

            List <SimPoint> otherPositions     = new List <SimPoint>();
            List <SimPoint> otherAccelerations = new List <SimPoint>();

            if (checkSim)
            {
                for (int i = 0; i < bodies.Count(); i++)
                {
                    positions[i]  = bodies[i].Position;
                    velocities[i] = bodies[i].Velocity;
                }
                Validate5BodyCross(positions, "Positions Before Update");
                Validate5BodyCross(velocities, "Velocities Before Update");
            }

            for (int calcCycle = 0; calcCycle < simCalcSettings.CalculationCyclesPerFrame; calcCycle++)
            {
                // Calculate NBody acceleration
                if (simCalcSettings.CheckAllAdditionPrecision)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        accelerations[i].X = 0.0;
                        accelerations[i].Y = 0.0;

                        for (int j = 0; j < bodies.Count(); j++)
                        {
                            if ((i != j) && bodies[j].IsGravitySource)
                            {
                                SimPoint accel = bodies[i].BodyToBodyAccelerate(bodies[j]);
                                if (simRounding > 0)
                                {
                                    accel.X += Math.Round(accel.X, simRounding, MidpointRounding.AwayFromZero);
                                    accel.Y += Math.Round(accel.Y, simRounding, MidpointRounding.AwayFromZero);
                                }
                                if (FloatingPointUtil.CheckAdditionPrecision(accelerations[i].X, accel.X))
                                {
                                    Body.DisplayPrecisionIssue(accelerations[i].X, accel.X, "Accumulating Accel.X", i);
                                }
                                accelerations[i].X += accel.X;
                                if (FloatingPointUtil.CheckAdditionPrecision(accelerations[i].Y, accel.Y))
                                {
                                    Body.DisplayPrecisionIssue(accelerations[i].Y, accel.Y, "Accumulating Accel.Y", i);
                                }
                                accelerations[i].Y += accel.Y;
                            }
                        }
                    }
                }
                else if (simRounding > 0)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        accelerations[i].X = 0.0;
                        accelerations[i].Y = 0.0;

                        for (int j = 0; j < bodies.Count(); j++)
                        {
                            if ((i != j) && bodies[j].IsGravitySource)
                            {
                                SimPoint accel = bodies[i].BodyToBodyAccelerate(bodies[j]);
                                accelerations[i].X += Math.Round(accel.X, simRounding, MidpointRounding.AwayFromZero);
                                accelerations[i].Y += Math.Round(accel.Y, simRounding, MidpointRounding.AwayFromZero);
                            }
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        accelerations[i].X = 0.0;
                        accelerations[i].Y = 0.0;

                        for (int j = 0; j < bodies.Count(); j++)
                        {
                            if ((i != j) && bodies[j].IsGravitySource)
                            {
                                SimPoint accel = bodies[i].BodyToBodyAccelerate(bodies[j]);
                                accelerations[i].X += accel.X;
                                accelerations[i].Y += accel.Y;
                            }
                        }
                    }
                }

                //if (checkSim) Validate5BodyCross(accelerations, "Accelerations Before Limit and Rounding");

                if (accelerationLimitOn)
                {
                    EnforceAccelerationLimit(accelerations, accelerationLimit);
                }

                if (simRounding > 0)
                {
                    RoundAccelerations(accelerations, simRounding);
                }

                if (checkSim)
                {
                    Validate5BodyCross(accelerations, "Accelerations After Limit and Rounding");
                }

                // Update positons and velocities
                if (simCalcSettings.CheckAllAdditionPrecision)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        bodies[i].MoveWithPrecisionCheck(accelerations[i], timeIntervalPerCycle);
                    }
                }
                else
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        bodies[i].Move(accelerations[i], timeIntervalPerCycle);
                    }
                }

                if (checkSim)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        positions[i]  = bodies[i].Position;
                        velocities[i] = bodies[i].Velocity;
                    }
                    Validate5BodyCross(positions, "Positions After Update");
                    Validate5BodyCross(velocities, "Velocities After Update");
                }

                simElapsedTime += timeIntervalPerCycle;

                if ((MainPage.trailsEnabled) && TimeForTrailsMark(simElapsedTime))
                {
                    DrawTrails();
                }
            }
            if (simStepping)
            {
                perfIntervalTicks = DisplayPerfIntervalElapsed(perfStopwatch, perfIntervalTicks,
                                                               String.Format("Compute N-body accelerations, update positions & velocities ({0} iterations)", simCalcSettings.CalculationCyclesPerFrame));
            }


            // Update rendering
            renderer.BodiesMoved(bodies);
            simPage.UpdateMonitoredValues(bodies[monitoredBody], simElapsedTime);

            if (simStepping)
            {
                perfIntervalTicks = DisplayPerfIntervalElapsed(perfStopwatch, perfIntervalTicks, "Update transforms of XAML shapes & monitored values");
            }

            if (simStepping)
            {
                Debug.WriteLine("Total elapsed time = {0:F2} ms", (double)perfIntervalTicks / (double)(Stopwatch.Frequency / 1000L));
                Debug.WriteLine("");
            }

            // stepRunning = false;
        }
Beispiel #13
0
 public void AddBody(double mass, double size, int color, BodyStartPosition startPosition, SimPoint startVelocity,
                     bool isGravitySource)
 {
     bodies.Add(new Body(mass, size, renderer.GetStartingPosition(startPosition), startVelocity, isGravitySource, simSpace));
     renderer.Add(size, color, bodies.Last());
 }
Beispiel #14
0
 static string FormatPointToString(SimPoint p)
 {
     return(String.Format("x = {0:N1}, y = {1:N1}", p.X, p.Y));
 }