Пример #1
0
        private void ComputeCachedProperties()
        {
            DVector2 difference = GravitationalParent.Position - Position;

            double totalDistance = difference.Length() - TotalHeight * 0.5;

            _cachedAltitude = totalDistance - GravitationalParent.SurfaceRadius;

            double altitude = GetRelativeAltitude();

            if (altitude > GravitationalParent.AtmosphereHeight)
            {
                _cachedRelativeVelocity = Velocity - GravitationalParent.Velocity;
            }
            else
            {
                difference.Normalize();

                var surfaceNormal = new DVector2(-difference.Y, difference.X);

                double altitudeFromCenter = altitude + GravitationalParent.SurfaceRadius;

                // Distance of circumference at this altitude ( c= 2r * pi )
                double pathCirumference = 2 * Math.PI * altitudeFromCenter;

                double rotationalSpeed = pathCirumference / GravitationalParent.RotationPeriod;

                _cachedRelativeVelocity = Velocity - (GravitationalParent.Velocity + surfaceNormal * rotationalSpeed);
            }
        }
Пример #2
0
        protected virtual void RenderAbove(Graphics graphics, Camera camera)
        {
            if (EntryFlame != null)
            {
                EntryFlame.Draw(graphics, camera);
            }

            // Only show the vectors when it's requested and the craft is not parented
            if (_showDisplayVectors && Parent == null)
            {
                // The length of the vector is based on the width of the camera bounds
                float lengthFactor = (float)(camera.Bounds.Width * 0.1);

                PointF start = RenderUtils.WorldToScreen(Position, camera.Bounds);

                DVector2 relativeVelocity = GetRelativeVelocity();

                // Only draw the velocity vector when it can be normalized
                if (relativeVelocity.Length() > 0)
                {
                    relativeVelocity.Normalize();

                    PointF velocityEnd = RenderUtils.WorldToScreen(Position + relativeVelocity * lengthFactor, camera.Bounds);

                    graphics.DrawLine(Pens.White, start, velocityEnd);
                }

                DVector2 pitchVector = DVector2.FromAngle(Pitch);
                pitchVector.Normalize();

                PointF pitchEnd = RenderUtils.WorldToScreen(Position + pitchVector * lengthFactor, camera.Bounds);

                graphics.DrawLine(Pens.Red, start, pitchEnd);
            }
        }
Пример #3
0
        public override void Update(double dt)
        {
            base.Update(dt);

            foreach (GridFin gridFin in _gridFins)
            {
                gridFin.Update(dt);
            }

            foreach (LandingLeg landingLeg in _landingLegs)
            {
                landingLeg.Update(dt);
            }

            DVector2 velocity = GetRelativeVelocity();
            double   altitude = GetRelativeAltitude();

            DVector2 normalizedVelocity = velocity.Clone();

            normalizedVelocity.Normalize();

            DVector2 rotation = new DVector2(Math.Cos(Pitch), Math.Sin(Pitch));

            // If we are going retro-grade and firing rockets adds soot
            if (altitude < 70000 && normalizedVelocity.Dot(rotation) < 0 && velocity.Length() > 400)
            {
                foreach (IEngine engine in Engines)
                {
                    if (engine.IsActive && engine.Throttle > 0)
                    {
                        _sootRatio = Math.Min(_sootRatio + 0.015 * dt, 1.0);
                    }
                }
            }
        }
Пример #4
0
        // Interpolate between current and target orientation over the duration
        public override void Update(double elapsedTime, SpaceCraftBase spaceCraft)
        {
            double altitude         = spaceCraft.GetRelativeAltitude();
            double atmosphereheight = spaceCraft.GravitationalParent.AtmosphereHeight;

            DVector2 retrograde = spaceCraft.GetRelativeVelocity();

            if (altitude > atmosphereheight)
            {
                retrograde = spaceCraft.GetInertialVelocity();
            }

            retrograde.Negate();
            retrograde.Normalize();

            double retrogradeAngle = retrograde.Angle();

            double adjustRatio = (elapsedTime - StartTime) / _adjustmentTime;

            if (adjustRatio > 1)
            {
                spaceCraft.SetPitch(retrogradeAngle);
            }
            else
            {
                double interpolatedAdjust = MathHelper.LerpAngle(_curentOrientation, retrogradeAngle, adjustRatio);

                spaceCraft.SetPitch(interpolatedAdjust);
            }
        }
Пример #5
0
        public void SetRelativePitch(double pitch)
        {
            double altitude = GetRelativeAltitude();

            if (altitude > GravitationalParent.AtmosphereHeight)
            {
                Pitch = GravitationalParent.Pitch + pitch;
            }
            else
            {
                DVector2 difference = GravitationalParent.Position - Position;
                difference.Normalize();
                var    surfaceNormal = new DVector2(difference.Y, difference.X);
                double normal        = surfaceNormal.Angle();
                if (double.IsNaN(normal))
                {
                    Pitch = GravitationalParent.Pitch + pitch;
                }
                else
                {
                    Pitch = GravitationalParent.Pitch + pitch - normal;
                }
            }

            foreach (ISpaceCraft child in Children)
            {
                child.SetRelativePitch(pitch);
            }
        }
Пример #6
0
        public override double GetRelativePitch()
        {
            double altitude      = GetRelativeAltitude();
            double relativePitch = Pitch - GravitationalParent.Pitch;

            if (altitude > GravitationalParent.AtmosphereHeight)
            {
                return(relativePitch);
            }

            DVector2 difference = GravitationalParent.Position - Position;

            difference.Normalize();
            var    surfaceNormal = new DVector2(difference.Y, difference.X);
            double normal        = surfaceNormal.Angle();

            if (!double.IsNaN(normal))
            {
                if (altitude > 0.1)
                {
                    relativePitch += normal;
                }
                else
                {
                    relativePitch = normal;
                }
            }

            return(relativePitch);
        }
Пример #7
0
        /// <summary>
        /// Gets the down range distance along the equator of the parent planet.
        /// </summary>
        public double GetDownrangeDistance(DVector2 pointOfReference)
        {
            if (GravitationalParent == null)
            {
                return(0.0);
            }

            DVector2 pofOffset = GravitationalParent.Position - pointOfReference;

            pofOffset.Normalize();

            DVector2 spaceCraftOffset = GravitationalParent.Position - Position;

            spaceCraftOffset.Normalize();

            // Find angle between normal vectors
            double angle = Math.Acos(pofOffset.X * spaceCraftOffset.X + pofOffset.Y * spaceCraftOffset.Y);

            if (double.IsNaN(angle))
            {
                angle = 0;
            }

            // Fixing wrapping around a circle
            if (angle > Math.PI)
            {
                angle -= Math.PI;
            }

            // Take the ratio of the angle to the full circumference
            double arcRatio = angle / (Math.PI * 2);

            return(arcRatio * (2.0 * GravitationalParent.SurfaceRadius * Math.PI));
        }
Пример #8
0
        // Interpolate between current and target orientation over the duration
        public override void Update(double elapsedTime, SpaceCraftBase spaceCraft)
        {
            DVector2 prograde = spaceCraft.GetRelativeVelocity();

            prograde.Normalize();

            double retrogradeAngle = prograde.Angle();

            if (retrogradeAngle > 0)
            {
                retrogradeAngle -= Math.PI * 2;
            }

            double adjustRatio = (elapsedTime - StartTime) / _adjustmentTime;

            if (adjustRatio > 1)
            {
                spaceCraft.SetPitch(retrogradeAngle);
            }
            else
            {
                double interpolatedAdjust = MathHelper.LerpAngle(_curentOrientation, retrogradeAngle, adjustRatio);

                spaceCraft.SetPitch(interpolatedAdjust);
            }
        }
Пример #9
0
        public override double GetRelativePitch()
        {
            DVector2 difference = GravitationalParent.Position - Position;

            difference.Normalize();
            double surfaceNormal = difference.Angle() - Constants.PiOverTwo;

            return(Pitch - surfaceNormal);
        }
Пример #10
0
        public void ResolveAtmopsherics(IMassiveBody body)
        {
            DVector2 difference = body.Position - Position;

            double distance = difference.Length();

            difference.Normalize();

            double altitude = distance - body.SurfaceRadius;

            // The object is in the atmosphere of body B
            if (altitude < body.AtmosphereHeight)
            {
                var surfaceNormal = new DVector2(-difference.Y, difference.X);

                double altitudeFromCenter = altitude + body.SurfaceRadius;

                // Distance of circumference at this altitude ( c= 2r * pi )
                double pathCirumference = 2 * Math.PI * altitudeFromCenter;

                double rotationalSpeed = pathCirumference / body.RotationPeriod;

                // Simple collision detection
                if (altitude <= 0)
                {
                    var normal = new DVector2(-difference.X, -difference.Y);

                    Position = body.Position + normal * (body.SurfaceRadius);

                    Velocity = (body.Velocity + surfaceNormal * rotationalSpeed);

                    Rotation = normal.Angle();

                    AccelerationN.X = -AccelerationG.X;
                    AccelerationN.Y = -AccelerationG.Y;
                }

                double atmosphericDensity = body.GetAtmosphericDensity(altitude);

                DVector2 relativeVelocity = (body.Velocity + surfaceNormal * rotationalSpeed) - Velocity;

                double velocityMagnitude = relativeVelocity.LengthSquared();

                if (velocityMagnitude > 0)
                {
                    relativeVelocity.Normalize();

                    // Drag ( Fd = 0.5pv^2dA )
                    DVector2 dragForce = relativeVelocity * (0.5 * atmosphericDensity * velocityMagnitude * DragCoefficient * CrossSectionalArea);

                    AccelerationD += dragForce / Mass;
                }
            }
        }
Пример #11
0
        public void RenderCl(OpenCLProxy clProxy, Camera camera, IPhysicsBody sun)
        {
            RectangleD bounds = ComputeBoundingBox();

            // Not in range easy return
            if (!camera.Intersects(bounds))
            {
                return;
            }

            DVector2 sunNormal = DVector2.Zero;

            if (sun != null)
            {
                sunNormal = sun.Position - Position;

                sunNormal.Normalize();
            }

            if (clProxy.HardwareAccelerationEnabled)
            {
                clProxy.UpdateDoubleArgument("cX", camera.Bounds.X);
                clProxy.UpdateDoubleArgument("cY", camera.Bounds.Y);

                clProxy.UpdateDoubleArgument("cWidth", camera.Bounds.Width);
                clProxy.UpdateDoubleArgument("cHeight", camera.Bounds.Height);

                clProxy.UpdateDoubleArgument("cRot", -camera.Rotation);

                clProxy.UpdateDoubleArgument("sunNormalX", sunNormal.X);
                clProxy.UpdateDoubleArgument("sunNormalY", sunNormal.Y);

                clProxy.UpdateDoubleArgument("bodyX", Position.X);
                clProxy.UpdateDoubleArgument("bodyY", Position.Y);
                clProxy.UpdateDoubleArgument("bodyRot", Pitch);

                clProxy.RunKernel(_computeKernel, RenderUtils.ScreenArea);
            }
            else
            {
                int totalSize = RenderUtils.ScreenArea;

                for (int i = 0; i < totalSize; i++)
                {
                    Kernel.Run(clProxy.ReadIntBuffer("image", totalSize), RenderUtils.ScreenWidth, RenderUtils.ScreenHeight,
                               camera.Bounds.X, camera.Bounds.Y, camera.Bounds.Width, camera.Bounds.Height, camera.Rotation,
                               sunNormal.X, sunNormal.Y, Position.X, Position.Y, Pitch);
                }

                Kernel.Finish();
            }
        }
Пример #12
0
        private void SetCameraRotation()
        {
            IGravitationalBody target = _gravitationalBodies[_targetIndex];

            if (target is ISpaceCraft)
            {
                if (_rotateInOrbit)
                {
                    if (target.InOrbit)
                    {
                        if (!_targetInOrbit)
                        {
                            _camera.SetRotation(0, true);

                            _targetInOrbit = true;
                        }
                        else
                        {
                            _camera.SetRotation(0);
                        }
                    }
                    else
                    {
                        DVector2 craftOffset = target.GravitationalParent.Position - target.Position;
                        craftOffset.Normalize();

                        if (_targetInOrbit)
                        {
                            _camera.SetRotation(Constants.PiOverTwo - craftOffset.Angle(), true);

                            _targetInOrbit = false;
                        }
                        else
                        {
                            _camera.SetRotation(Constants.PiOverTwo - craftOffset.Angle());
                        }
                    }
                }
                else
                {
                    DVector2 craftOffset = target.GravitationalParent.Position - target.Position;
                    craftOffset.Normalize();
                    _camera.SetRotation(Constants.PiOverTwo - craftOffset.Angle());
                }
            }
            else
            {
                _camera.SetRotation(0);
            }
        }
Пример #13
0
        public void SetRelativePitch(double pitch)
        {
            DVector2 difference = GravitationalParent.Position - Position;

            difference.Normalize();
            double surfaceNormal = difference.Angle() - Constants.PiOverTwo;

            Pitch = surfaceNormal + pitch;

            foreach (ISpaceCraft child in Children)
            {
                child.SetRelativePitch(pitch);
            }
        }
Пример #14
0
        public void RenderCl(OpenCLProxy clProxy, RectangleD cameraBounds, IPhysicsBody sun)
        {
            RectangleD bounds = ComputeBoundingBox();

            // Not in range easy return
            if (!cameraBounds.IntersectsWith(bounds))
            {
                return;
            }

            DVector2 sunNormal = DVector2.Zero;

            if (sun != null)
            {
                sunNormal = sun.Position - Position;

                sunNormal.Normalize();
            }

            var normalizedPosition = new DVector2(cameraBounds.X - Position.X, cameraBounds.Y - Position.Y);

            if (clProxy.HardwareAccelerationEnabled)
            {
                clProxy.UpdateDoubleArgument("cameraLeft", normalizedPosition.X);
                clProxy.UpdateDoubleArgument("cameraTop", normalizedPosition.Y);

                clProxy.UpdateDoubleArgument("cameraWidth", cameraBounds.Width);
                clProxy.UpdateDoubleArgument("cameraHeight", cameraBounds.Height);

                clProxy.UpdateDoubleArgument("sunNormalX", sunNormal.X);
                clProxy.UpdateDoubleArgument("sunNormalY", sunNormal.Y);

                clProxy.UpdateDoubleArgument("rotation", Rotation);

                clProxy.RunKernel(_computeKernel, RenderUtils.ScreenArea);
            }
            else
            {
                int totalSize = RenderUtils.ScreenArea;

                for (int i = 0; i < totalSize; i++)
                {
                    Kernel.Run(clProxy.ReadIntBuffer("image", totalSize), RenderUtils.ScreenWidth, RenderUtils.ScreenHeight,
                               normalizedPosition.X, normalizedPosition.Y, cameraBounds.Width, cameraBounds.Height,
                               sunNormal.X, sunNormal.Y, Rotation);
                }

                Kernel.Finish();
            }
        }
Пример #15
0
        public virtual void ResolveGravitation(IPhysicsBody other)
        {
            DVector2 difference = other.Position - Position;

            double r2 = difference.LengthSquared();

            double massDistanceRatio = other.Mass / r2;

            // Ignore the force, the planet is too far away to matter
            if (massDistanceRatio < 2500)
            {
                return;
            }

            difference.Normalize();

            // Gravitation ( aG = G m1 / r^2 )
            AccelerationG += difference * Constants.GravitationConstant * massDistanceRatio;
        }
Пример #16
0
        // Interpolate between current and target orientation over the duration
        public override void Update(double elapsedTime, ISpaceCraft spaceCraft)
        {
            DVector2 prograde = spaceCraft.GetRelativeVelocity();

            prograde.Normalize();

            double retrogradeAngle = prograde.Angle();

            double adjustRatio = (elapsedTime - StartTime) / _adjustmentTime;

            if (adjustRatio > 1)
            {
                spaceCraft.SetRotation(retrogradeAngle);
            }
            else
            {
                double interpolatedAdjust = _curentOrientation * (1 - adjustRatio) + retrogradeAngle * adjustRatio;

                spaceCraft.SetRotation(interpolatedAdjust);
            }
        }
Пример #17
0
        public virtual void Update(double dt)
        {
            ElapsedTime += dt;

            if (IsPrograde)
            {
                DVector2 prograde = SpaceCraft.GetRelativeVelocity();
                prograde.Normalize();

                SpaceCraft.SetRotation(prograde.Angle());
            }

            if (IsRetrograde)
            {
                DVector2 retrograde = SpaceCraft.GetRelativeVelocity();
                retrograde.Negate();
                retrograde.Normalize();

                SpaceCraft.SetRotation(retrograde.Angle());
            }
        }
Пример #18
0
        // Gets bodies sorted by distance that point the direction of the camera normal
        private static List <Tuple <double, int> > GetSortedBodyDistances(int currentIndex, IList <IGravitationalBody> bodies, DVector2 cameraNormal)
        {
            DVector2 targetCenter = bodies[currentIndex].Position;

            var bodiesByDistance = new List <Tuple <double, int> >();

            for (int i = 0; i < bodies.Count; i++)
            {
                if (i == currentIndex)
                {
                    continue;
                }

                var spaceCraft = bodies[i] as ISpaceCraft;

                // Skip terminated bodies
                if (spaceCraft != null && spaceCraft.Terminated)
                {
                    continue;
                }

                DVector2 difference = bodies[i].Position - targetCenter;

                double distance = difference.LengthSquared();

                difference.Normalize();

                // Only add bodies in the same direction as the camera normal
                if (difference.Dot(cameraNormal) > 0)
                {
                    bodiesByDistance.Add(new Tuple <double, int>(distance, i));
                }
            }

            bodiesByDistance.Sort(Compare);

            return(bodiesByDistance);
        }
Пример #19
0
        /// <summary>
        /// Gets the relative velocity of the spacecraft. If the space craft is within the parent's
        /// atmosphere than the rotation of the planet is taken in account. Otherwise its a simple difference of velocities.
        /// </summary>
        public override DVector2 GetRelativeVelocity()
        {
            double altitude = GetRelativeAltitude();

            if (altitude > GravitationalParent.AtmosphereHeight)
            {
                return(Velocity - GravitationalParent.Velocity);
            }

            DVector2 difference = GravitationalParent.Position - Position;

            difference.Normalize();

            var surfaceNormal = new DVector2(-difference.Y, difference.X);

            double altitudeFromCenter = altitude + GravitationalParent.SurfaceRadius;

            // Distance of circumference at this altitude ( c= 2r * pi )
            double pathCirumference = 2 * Math.PI * altitudeFromCenter;

            double rotationalSpeed = pathCirumference / GravitationalParent.RotationPeriod;

            return(Velocity - (GravitationalParent.Velocity + surfaceNormal * rotationalSpeed));
        }
Пример #20
0
        public void ResolveAtmopsherics(IMassiveBody body)
        {
            // Don't resolve drag for children
            if (Parent != null)
            {
                return;
            }

            DVector2 difference = body.Position - Position;

            double heightOffset = Children.Count > 0 ? TotalHeight - Height * 0.5 : Height * 0.5;

            double distance = difference.Length() - heightOffset;

            difference.Normalize();

            double altitude = distance - body.SurfaceRadius;

            // The spacecraft is in the bodies atmopshere
            if (altitude < body.AtmosphereHeight)
            {
                var surfaceNormal = new DVector2(-difference.Y, difference.X);

                double altitudeFromCenter = altitude + body.SurfaceRadius;

                // Distance of circumference at this altitude ( c= 2r * pi )
                double pathCirumference = 2 * Math.PI * altitudeFromCenter;

                double rotationalSpeed = pathCirumference / body.RotationPeriod;

                // Rough metric for staying on ground from frame to frame
                if (altitude <= 0.0001)
                {
                    _onGroundIterations = Math.Min(_onGroundIterations + 1, 10);
                }
                else
                {
                    _onGroundIterations = Math.Max(_onGroundIterations - 1, 0);
                }

                // Simple collision detection
                if (_onGroundIterations > 5)
                {
                    OnGround = true;

                    var normal = new DVector2(-difference.X, -difference.Y);

                    Position = body.Position + normal * (body.SurfaceRadius + heightOffset);

                    Velocity = (body.Velocity + surfaceNormal * rotationalSpeed);

                    Pitch = normal.Angle();

                    AccelerationN.X = -AccelerationG.X;
                    AccelerationN.Y = -AccelerationG.Y;

                    AccelerationY = new DVector2(0, 0);
                }
                else
                {
                    OnGround = false;
                }

                double atmosphericDensity = body.GetAtmosphericDensity(altitude);

                DVector2 relativeVelocity = (body.Velocity + surfaceNormal * rotationalSpeed) - Velocity;

                double velocityMagnitude = relativeVelocity.LengthSquared();

                if (velocityMagnitude > 0)
                {
                    double speed = relativeVelocity.Length();

                    // Heating
                    double qConv = 1.83e-4 * Math.Pow(speed, 3) * Math.Sqrt(atmosphericDensity / (Width * 0.5));
                    double qRad  = 3.2e-22 * Math.Pow(speed, 8) * Math.Pow(atmosphericDensity, 1.2) * Math.Sqrt((Width * 0.5));
                    HeatingRate = qConv + qRad;

                    relativeVelocity.Normalize();

                    double formDragCoefficient     = TotalFormDragCoefficient();
                    double skinFrictionCoefficient = TotalSkinFrictionCoefficient();
                    double liftCoefficient         = TotalLiftCoefficient();

                    double formDragTerm     = formDragCoefficient * TotalFormDragArea();
                    double skinFrictionTerm = skinFrictionCoefficient * TotalSkinFrictionArea();

                    double dragTerm = formDragTerm;
                    if (!double.IsNaN(skinFrictionTerm))
                    {
                        dragTerm += skinFrictionTerm;
                    }

                    double liftTerm = liftCoefficient * TotalLiftArea();
                    double turnTerm = 0;
                    if (Settings.Default.UseTheTurnForce)
                    {
                        turnTerm  = liftTerm * Math.Sin(Roll);
                        liftTerm *= Math.Cos(Roll);
                    }

                    // Form Drag ( Fd = 0.5pv^2dA )
                    // Skin friction ( Fs = 0.5CfpV^2S )
                    DVector2 drag = relativeVelocity * (0.5 * atmosphericDensity * velocityMagnitude * dragTerm);
                    DVector2 lift = relativeVelocity * (0.5 * atmosphericDensity * velocityMagnitude * liftTerm);

                    AccelerationD = drag / Mass;
                    DVector2 accelerationLift = lift / Mass;

                    double alpha        = GetAlpha();
                    double halfPi       = Math.PI / 2;
                    bool   isRetrograde = alpha > halfPi || alpha < -halfPi;

                    if (Settings.Default.UseTheTurnForce && isRetrograde)
                    {
                        AccelerationL.X -= accelerationLift.Y;
                        AccelerationL.Y += accelerationLift.X;
                    }
                    else
                    {
                        AccelerationL.X += accelerationLift.Y;
                        AccelerationL.Y -= accelerationLift.X;
                    }
                }
            }
            else
            {
                HeatingRate = 0;
            }
        }
Пример #21
0
        public void ResolveAtmopsherics(IMassiveBody body)
        {
            DVector2 difference = body.Position - Position;

            double distance = difference.Length() - Height * 0.5;

            difference.Normalize();

            Altitude = distance - body.SurfaceRadius;

            // The object is in the atmosphere of body B
            if (Altitude < body.AtmosphereHeight)
            {
                var surfaceNormal = new DVector2(-difference.Y, difference.X);

                double altitudeFromCenter = Altitude + body.SurfaceRadius;

                // Distance of circumference at this altitude ( c= 2r * pi )
                double pathCirumference = 2 * Math.PI * altitudeFromCenter;

                double rotationalSpeed = pathCirumference / body.RotationPeriod;

                // Simple collision detection
                if (Altitude <= 0)
                {
                    var normal = new DVector2(-difference.X, -difference.Y);

                    Position = body.Position + normal * (body.SurfaceRadius);

                    Pitch = normal.Angle();

                    AccelerationN.X = -AccelerationG.X;
                    AccelerationN.Y = -AccelerationG.Y;

                    OnGround = true;
                }
                else
                {
                    OnGround = false;
                }

                double atmosphericDensity = body.GetAtmosphericDensity(Altitude);

                RelativeVelocity = (body.Velocity + surfaceNormal * rotationalSpeed) - Velocity;

                double velocityMagnitude = RelativeVelocity.LengthSquared();

                if (velocityMagnitude > 0)
                {
                    DVector2 normalizedRelativeVelocity = RelativeVelocity.Clone();
                    normalizedRelativeVelocity.Normalize();

                    double formDragTerm     = FormDragCoefficient * FrontalArea;
                    double skinFrictionTerm = SkinFrictionCoefficient * ExposedSurfaceArea;
                    double dragTerm         = formDragTerm + skinFrictionTerm;

                    // Drag ( Fd = 0.5pv^2dA )
                    DVector2 dragForce = normalizedRelativeVelocity * (0.5 * atmosphericDensity * velocityMagnitude * dragTerm);

                    // Reject insane forces
                    if (dragForce.Length() < 50000000)
                    {
                        AccelerationD = dragForce / Mass;
                    }
                }
            }
        }
Пример #22
0
        /// <summary>
        /// Updates the spacecraft and it's children.
        /// </summary>
        public override void Update(double dt)
        {
            ComputeCachedProperties();

            double altitude = GetRelativeAltitude();

            if (GravitationalParent == null)
            {
                IspMultiplier = 1;
            }
            else
            {
                IspMultiplier = GravitationalParent.GetIspMultiplier(altitude);
            }

            if (Parent == null)
            {
                UpdateEngines(dt);

                if (Thrust > 0 && _isReleased)
                {
                    var thrustVector = new DVector2(Math.Cos(Pitch) * Math.Cos(Yaw), Math.Sin(Pitch) * Math.Cos(Yaw));
                    var yawVector    = new DVector2(Math.Cos(Pitch) * Math.Sin(Yaw), Math.Sin(Pitch) * Math.Sin(Yaw));

                    AccelerationN += (thrustVector * Thrust) / Mass;
                    AccelerationY += (yawVector * Thrust) / Mass;
                }

                if (_requiresStaging)
                {
                    // Simulate simple staging mechanism
                    double sAngle = StageOffset.Angle();

                    DVector2 stagingNormal = DVector2.FromAngle(Pitch + sAngle + Constants.PiOverTwo);

                    AccelerationN += stagingNormal * StagingForce;

                    _requiresStaging = false;
                }

                if (_isReleased)
                {
                    // Integrate acceleration
                    Velocity += AccelerationG * dt;
                    Velocity += AccelerationD * dt;
                    Velocity += AccelerationL * dt;
                    Velocity += AccelerationN * dt;

                    LateralVelocity += AccelerationY * dt;
                    LateralPosition += LateralVelocity * dt;
                }

                // Re-normalize FTL scenarios
                if (Velocity.LengthSquared() > Constants.SpeedLightSquared)
                {
                    Velocity.Normalize();

                    Velocity *= Constants.SpeedOfLight;
                }

                // If the craft is on the ground with high time warpd don't update the position as normal.
                // Instead just keep putting the ship at the correct spot on it's gravitational body based on rotation.
                if (OnGround && dt > 5)
                {
                    DVector2 parentOffset = GravitationalParent.Position - Position;
                    parentOffset.Normalize();

                    Position = GravitationalParent.Position + parentOffset * GravitationalParent.SurfaceRadius;
                }
                else
                {
                    // Integrate velocity
                    Position += Velocity * dt;
                }

                MachNumber = GetRelativeVelocity().Length() * 0.0029411764;

                foreach (ISpaceCraft child in Children)
                {
                    child.UpdateChildren(Position, Velocity);
                }

                _trailTimer += dt;

                // Somewhat arbitrary conditions for launch trails
                if (dt < 0.1666666666 && !InOrbit && !OnGround && _cachedAltitude > 50 && _cachedAltitude < GravitationalParent.AtmosphereHeight * 2 && _trailTimer > 1)
                {
                    string parentName = GravitationalParent.ToString();

                    if (!_launchTrails.ContainsKey(parentName))
                    {
                        _launchTrails.Add(parentName, new LaunchTrail());
                    }

                    _launchTrails[parentName].AddPoint(Position, GravitationalParent, Throttle > 0);
                    _trailTimer = 0;
                }
            }
        }
Пример #23
0
        /// <summary>
        /// Traces a space craft orbit by re-centering the world around the parent.
        /// </summary>
        public static void TraceSpaceCraft(SpaceCraftBase satellite, OrbitTrace trace)
        {
            IMassiveBody parent = satellite.GravitationalParent;

            DVector2 initialPosition = satellite.Position - parent.Position;

            var shipOffset = new DVector2(Math.Cos(satellite.Pitch) * (satellite.TotalWidth - satellite.Width),
                                          Math.Sin(satellite.Pitch) * (satellite.TotalHeight - satellite.Height)) * 0.5;

            initialPosition -= shipOffset;

            var proxyParent    = new MassiveBodyProxy(DVector2.Zero, DVector2.Zero, parent);
            var proxySatellite = new SpaceCraftProxy(initialPosition, satellite.Velocity - parent.Velocity, satellite);

            proxySatellite.SetGravitationalParent(proxyParent);

            int stepCount;

            double targetDt;
            double proximityDt;
            double orbitalDt = 0;

            bool isOrbiting;

            double altitude          = proxyParent.GetRelativeHeight(proxySatellite.Position);
            double proximityAltitude = proxyParent.SurfaceRadius * 0.15;

            if (altitude < proximityAltitude)
            {
                stepCount = 1100;

                isOrbiting = false;

                proximityDt = GetProximityDt(altitude, proximityAltitude);

                targetDt = proximityDt;
            }
            else
            {
                stepCount = 600;

                isOrbiting = true;

                orbitalDt = GetOrbitalDt(initialPosition.Length(), parent.Mass, proxySatellite.Velocity.Length());

                targetDt = orbitalDt;
            }

            // Assumes that the parent is (0,0) which will be true in this case
            double previousAngle            = proxySatellite.Position.Angle();
            double totalAngularDisplacement = 0;

            trace.Reset(satellite.Position - shipOffset);

            // Update steps based on orbit vs atmosphere
            for (int step = 0; step < stepCount; step++)
            {
                proxySatellite.ResetAccelerations();

                proxySatellite.ResolveGravitation(proxyParent);
                proxySatellite.ResolveAtmopsherics(proxyParent);

                proxySatellite.Update(targetDt);

                double currentAngle = proxySatellite.Position.Angle();

                totalAngularDisplacement += DeltaAngle(currentAngle, previousAngle);

                // Made a full orbit
                if (totalAngularDisplacement > AngularCutoff)
                {
                    break;
                }

                previousAngle = currentAngle;

                altitude = proxyParent.GetRelativeHeight(proxySatellite.Position);

                double velocity = proxySatellite.GetRelativeVelocity().Length();

                double offsetFactor = 0.0;

                //if (altitude < proxyParent.AtmosphereHeight*2)
                if (altitude < proxyParent.AtmosphereHeight * 4)
                {
                    if (velocity < 3000)
                    {
                        offsetFactor = 1.0;
                    }
                    else if (velocity < 4000)
                    {
                        offsetFactor = 1.0 - velocity / 3000.0;
                    }
                }

                // Check if reference frame shifting needs to occur in atmosphere
                if (offsetFactor > 0.0001)
                {
                    DVector2 difference = proxyParent.Position - proxySatellite.Position;
                    difference.Normalize();

                    var surfaceNormal = new DVector2(-difference.Y, difference.X);

                    double altitudeFromCenter = altitude + proxyParent.SurfaceRadius;

                    // Distance of circumference at this altitude ( c= r * 2pi )
                    double pathCirumference = Constants.TwoPi * altitudeFromCenter;

                    double rotationalSpeed = pathCirumference / parent.RotationPeriod;

                    DVector2 atmopshereVelocity = surfaceNormal * rotationalSpeed;

                    proxySatellite.ApplyFrameOffset(atmopshereVelocity * offsetFactor * targetDt);
                }

                // Return early if the trace goes into a planet
                if (altitude <= 0)
                {
                    trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
                    break;
                }

                // Determine the correct change overs from orbital to surface proximity
                if (isOrbiting)
                {
                    if (altitude < proximityAltitude)
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);

                        isOrbiting = false;

                        stepCount = 1000;
                    }
                    else
                    {
                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);
                    }
                }
                else
                {
                    if (altitude > proximityAltitude)
                    {
                        orbitalDt = GetOrbitalDt(proxySatellite.Position.Length(), parent.Mass, proxySatellite.Velocity.Length());

                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);

                        isOrbiting = true;

                        stepCount = 600;
                    }
                    else
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);
                    }
                }

                trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
            }
        }
Пример #24
0
        public void ResolveAtmopsherics(IMassiveBody body)
        {
            // Don't resolve drag for children
            if (Parent != null)
            {
                return;
            }

            DVector2 difference = body.Position - Position;

            double distance = difference.Length();

            difference.Normalize();

            double altitude = distance - body.SurfaceRadius;

            // The spacecraft is in the bodies atmopshere
            if (altitude < body.AtmosphereHeight)
            {
                var surfaceNormal = new DVector2(-difference.Y, difference.X);

                double altitudeFromCenter = altitude + body.SurfaceRadius;

                // Distance of circumference at this altitude ( c= 2r * pi )
                double pathCirumference = 2 * Math.PI * altitudeFromCenter;

                double rotationalSpeed = pathCirumference / body.RotationPeriod;

                // Simple collision detection
                if (altitude <= 0)
                {
                    var normal = new DVector2(-difference.X, -difference.Y);

                    Position = body.Position + normal * (body.SurfaceRadius);

                    Velocity = (body.Velocity + surfaceNormal * rotationalSpeed);

                    Rotation = normal.Angle();

                    AccelerationN.X = -AccelerationG.X;
                    AccelerationN.Y = -AccelerationG.Y;
                }

                double atmosphericDensity = body.GetAtmosphericDensity(altitude);

                DVector2 relativeVelocity = (body.Velocity + surfaceNormal * rotationalSpeed) - Velocity;

                double velocity        = relativeVelocity.Length();
                double velocitySquared = relativeVelocity.LengthSquared();

                if (velocitySquared > 0)
                {
                    double speed = relativeVelocity.Length();

                    // Heating
                    HeatingRate = 1.83e-4 * Math.Pow(speed, 3) * Math.Sqrt(atmosphericDensity / (Width * 0.5));

                    relativeVelocity.Normalize();

                    double dragTerm = TotalDragCoefficient() * TotalDragArea();

                    // Drag ( Fd = 0.5pv^2dA )
                    DVector2 dragForce = relativeVelocity * (0.5 * atmosphericDensity * velocitySquared * dragTerm);

                    AccelerationD += dragForce / Mass;

                    double reynoldsNumber = (velocity * Height) / body.GetAtmosphericViscosity(altitude);

                    double frictionCoefficient = 0.455 / Math.Pow(Math.Log10(reynoldsNumber), 2.58);

                    double frictionTerm = frictionCoefficient * TotalSurfaceArea();

                    // Skin friction ( Fs = 0.5CfpV^2S )
                    DVector2 skinFriction = relativeVelocity * (0.5 * atmosphericDensity * velocitySquared * frictionTerm);

                    AccelerationD += skinFriction / Mass;
                }
            }
            else
            {
                HeatingRate = 0;
            }
        }
Пример #25
0
        /// <summary>
        /// Traces a space craft orbit by re-centering the world around the parent.
        /// </summary>
        public static void TraceSpaceCraft(SpaceCraftBase satellite, OrbitTrace trace)
        {
            IMassiveBody parent = satellite.GravitationalParent;

            DVector2 initialPosition = satellite.Position - parent.Position;

            var shipOffset = new DVector2(Math.Cos(satellite.Pitch) * (satellite.TotalWidth - satellite.Width),
                                          Math.Sin(satellite.Pitch) * (satellite.TotalHeight - satellite.Height)) * 0.5;

            initialPosition -= shipOffset;

            var proxyParent    = new MassiveBodyProxy(DVector2.Zero, DVector2.Zero, parent);
            var proxySatellite = new SpaceCraftProxy(initialPosition, satellite.Velocity - parent.Velocity, satellite);

            proxySatellite.SetGravitationalParent(proxyParent);

            int stepCount;

            double targetDt;
            double proximityDt;
            double orbitalDt = 0;

            bool   isOrbiting;
            double orbitalTerminationRadius = 0;

            double altitude          = proxyParent.GetRelativeHeight(proxySatellite.Position);
            double proximityAltitude = proxyParent.SurfaceRadius * 0.15;

            if (altitude < proximityAltitude)
            {
                stepCount = 1100;

                isOrbiting = false;

                proximityDt = GetProximityDt(altitude, proximityAltitude);

                targetDt = proximityDt;
            }
            else
            {
                stepCount = 600;

                isOrbiting = true;

                orbitalDt = GetOrbitalDt(initialPosition, proxySatellite.Velocity, out orbitalTerminationRadius);

                targetDt = orbitalDt;
            }

            trace.Reset(satellite.Position - shipOffset);

            // Simulate 300 orbital steps, more for proximity
            for (int step = 0; step < stepCount; step++)
            {
                proxySatellite.ResetAccelerations();

                proxySatellite.ResolveGravitation(proxyParent);
                proxySatellite.ResolveAtmopsherics(proxyParent);

                proxySatellite.Update(targetDt);

                altitude = proxyParent.GetRelativeHeight(proxySatellite.Position);

                double velocity = proxySatellite.GetRelativeVelocity().Length();

                double offsetFactor = 0.0;

                if (altitude < proxyParent.AtmosphereHeight * 2)
                {
                    if (velocity < 3000)
                    {
                        offsetFactor = 1.0;
                    }
                    else if (velocity < 4000)
                    {
                        offsetFactor = 1.0 - velocity / 3000.0;
                    }
                }

                // Check if reference frame shifting needs to occur in atmosphere
                if (offsetFactor > 0.0001)
                {
                    DVector2 difference = proxyParent.Position - proxySatellite.Position;
                    difference.Normalize();

                    var surfaceNormal = new DVector2(-difference.Y, difference.X);

                    double altitudeFromCenter = altitude + proxyParent.SurfaceRadius;

                    // Distance of circumference at this altitude ( c= 2r * pi )
                    double pathCirumference = 2 * Math.PI * altitudeFromCenter;

                    double rotationalSpeed = pathCirumference / parent.RotationPeriod;

                    DVector2 atmopshereVelocity = surfaceNormal * rotationalSpeed;

                    proxySatellite.ApplyFrameOffset(atmopshereVelocity * offsetFactor * targetDt);

                    // Return early if the trace goes into a planet
                    if (altitude <= 0)
                    {
                        trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
                        break;
                    }
                }

                // Determine the correct change overs from orbital to surface proximity
                if (isOrbiting)
                {
                    if (altitude < proximityAltitude)
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);

                        isOrbiting = false;

                        stepCount = 1000;
                    }
                    else
                    {
                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);
                    }
                }
                else
                {
                    if (altitude > proximityAltitude)
                    {
                        orbitalDt = GetOrbitalDt(proxySatellite.Position, proxySatellite.Velocity, out orbitalTerminationRadius);

                        targetDt = MathHelper.Lerp(targetDt, orbitalDt, 0.1);

                        isOrbiting = true;

                        stepCount = 600;
                    }
                    else
                    {
                        proximityDt = GetProximityDt(altitude, proximityAltitude);

                        targetDt = MathHelper.Lerp(targetDt, proximityDt, 0.75);
                    }
                }

                // Check expensive termination conditions after half of the iterations
                if (isOrbiting && step > 100)
                {
                    DVector2 offsetVector = proxySatellite.Position - initialPosition;

                    double distanceFromStart = offsetVector.Length();

                    // Terminate and add the end point
                    if (distanceFromStart < orbitalTerminationRadius)
                    {
                        trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
                        break;
                    }
                }

                trace.AddPoint(proxySatellite.Position + parent.Position, altitude);
            }
        }