Ejemplo n.º 1
0
        private static Vector <VelocityUnit> WindVector(ShotParameters shot, Wind wind, VelocityUnit units)
        {
            double sightCosine = shot.SightAngle.Cos();
            double sightSine   = shot.SightAngle.Sin();
            double cantCosine  = (shot.CantAngle ?? AngularUnit.Radian.New(0)).Cos();
            double cantSine    = (shot.CantAngle ?? AngularUnit.Radian.New(0)).Sin();

            Measurement <VelocityUnit> rangeVelocity, crossComponent;

            if (wind != null)
            {
                rangeVelocity  = (wind.Velocity * wind.Direction.Cos()).To(units);
                crossComponent = (wind.Velocity * wind.Direction.Sin()).To(units);
            }
            else
            {
                rangeVelocity  = new Measurement <VelocityUnit>(0, units);
                crossComponent = new Measurement <VelocityUnit>(0, units);
            }

            Measurement <VelocityUnit> rangeFactor = -rangeVelocity * sightSine;

            return(new Vector <VelocityUnit>(rangeVelocity * sightCosine, rangeFactor * cantCosine + crossComponent * cantSine, crossComponent * cantCosine - rangeFactor * cantSine));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Calculates the trajectory for the specified parameters.
        /// </summary>
        /// <param name="ammunition"></param>
        /// <param name="rifle"></param>
        /// <param name="atmosphere"></param>
        /// <param name="shot"></param>
        /// <param name="wind"></param>
        /// <returns></returns>
        public TrajectoryPoint[] Calculate(Ammunition ammunition, Rifle rifle, Atmosphere atmosphere, ShotParameters shot, Wind[] wind)
        {
            Measurement <DistanceUnit> rangeTo         = shot.MaximumDistance;
            Measurement <DistanceUnit> step            = shot.Step;
            Measurement <DistanceUnit> calculationStep = GetCalculationStep(step);

            if (atmosphere == null)
            {
                atmosphere = new Atmosphere();
            }

            Measurement <DistanceUnit> alt0 = atmosphere.Altitude;
            Measurement <DistanceUnit> altDelta = new Measurement <DistanceUnit>(1, DistanceUnit.Meter);
            double densityFactor = 0, drag;
            Measurement <VelocityUnit> mach = new Measurement <VelocityUnit>(0, VelocityUnit.MetersPerSecond);

            double stabilityCoefficient = 1;
            bool   calculateDrift;

            if (rifle.Rifling != null && ammunition.BulletDiameter != null && ammunition.BulletLength != null)
            {
                stabilityCoefficient = CalculateStabilityCoefficient(ammunition, rifle, atmosphere);
                calculateDrift       = true;
            }
            else
            {
                calculateDrift = false;
            }

            TrajectoryPoint[] trajectoryPoints = new TrajectoryPoint[(int)(Math.Floor(rangeTo / step)) + 1];

            var barrelAzimuth   = new Measurement <AngularUnit>(0.0, AngularUnit.Radian);
            var barrelElevation = shot.SightAngle;

            if (shot.ShotAngle != null)
            {
                barrelElevation += shot.ShotAngle.Value;
            }

            Measurement <VelocityUnit> velocity = ammunition.MuzzleVelocity;
            TimeSpan time = new TimeSpan(0);

            int currentWind = 0;
            Measurement <DistanceUnit> nextWindRange = new Measurement <DistanceUnit>(1e7, DistanceUnit.Meter);
            Vector <VelocityUnit>      windVector;

            if (wind == null || wind.Length < 1)
            {
                windVector = new Vector <VelocityUnit>();
            }
            else
            {
                if (wind.Length > 1 && wind[0].MaximumRange != null)
                {
                    nextWindRange = wind[0].MaximumRange.Value;
                }
                windVector = WindVector(shot, wind[0], velocity.Unit);
            }

            //x - distance towards target,
            //y - drop and
            //z - windage
            var rangeVector = new Vector <DistanceUnit>(new Measurement <DistanceUnit>(0, DistanceUnit.Meter),
                                                        -rifle.Sight.SightHeight,
                                                        new Measurement <DistanceUnit>(0, DistanceUnit.Meter));

            var velocityVector = new Vector <VelocityUnit>(velocity * barrelElevation.Cos() * barrelAzimuth.Cos(),
                                                           velocity * barrelElevation.Sin(),
                                                           velocity * barrelElevation.Cos() * barrelAzimuth.Sin());

            int currentItem = 0;
            Measurement <DistanceUnit> maximumRange      = rangeTo + calculationStep;
            Measurement <DistanceUnit> nextRangeDistance = new Measurement <DistanceUnit>(0, DistanceUnit.Meter);

            Measurement <DistanceUnit> lastAtAltitude = new Measurement <DistanceUnit>(-1000000, DistanceUnit.Meter);
            DragTableNode dragTableNode = null;

            double adjustBallisticFactorForVelocityUnits = Measurement <VelocityUnit> .Convert(1, velocity.Unit, VelocityUnit.FeetPerSecond);

            double ballisicFactor = 2.08551e-04 * adjustBallisticFactorForVelocityUnits / ammunition.BallisticCoefficient.Value;
            var    earthGravity   = (new Measurement <VelocityUnit>(Measurement <AccelerationUnit> .Convert(1, AccelerationUnit.EarthGravity, AccelerationUnit.MeterPerSecondSquare),
                                                                    VelocityUnit.MetersPerSecond)).To(velocity.Unit);

            //run all the way down the range
            while (rangeVector.X <= maximumRange)
            {
                Measurement <DistanceUnit> alt = alt0 + rangeVector.Y;

                //update density and Mach velocity each 10 feet of altitude
                if (MeasurementMath.Abs(lastAtAltitude - alt) > altDelta)
                {
                    atmosphere.AtAltitude(alt, out densityFactor, out mach);
                    lastAtAltitude = alt;
                }

                if (velocity < MinimumVelocity || rangeVector.Y < -MaximumDrop)
                {
                    break;
                }

                if (rangeVector.X >= nextWindRange)
                {
                    currentWind++;
                    windVector = WindVector(shot, wind[currentWind], velocity.Unit);

                    if (currentWind == wind.Length - 1 || wind[currentWind].MaximumRange == null)
                    {
                        nextWindRange = new Measurement <DistanceUnit>(1e7, DistanceUnit.Meter);
                    }
                    else
                    {
                        nextWindRange = wind[currentWind].MaximumRange.Value;
                    }
                }

                if (rangeVector.X >= nextRangeDistance)
                {
                    var windage = rangeVector.Z;
                    if (calculateDrift)
                    {
                        windage += new Measurement <DistanceUnit>(1.25 * (stabilityCoefficient + 1.2) * Math.Pow(time.TotalSeconds, 1.83) * (rifle.Rifling.Direction == TwistDirection.Right ? 1 : -1), DistanceUnit.Inch);
                    }

                    trajectoryPoints[currentItem] = new TrajectoryPoint(
                        time: time,
                        weight: ammunition.Weight,
                        distance: rangeVector.X,
                        velocity: velocity,
                        mach: velocity / mach,
                        drop: rangeVector.Y,
                        windage: windage);
                    nextRangeDistance += step;
                    currentItem++;
                    if (currentItem == trajectoryPoints.Length)
                    {
                        break;
                    }
                }

                TimeSpan deltaTime = BallisticMath.TravelTime(calculationStep, velocityVector.X);

                var velocityAdjusted = velocityVector - windVector;
                velocity = velocityAdjusted.Magnitude;
                double currentMach = velocity / mach;

                //find Mach node for the first time
                if (dragTableNode == null)
                {
                    dragTableNode = DragTable.Get(ammunition.BallisticCoefficient.Table).Find(currentMach);
                }

                //walk towards the beginning the table as velocity drops
                while (dragTableNode.Mach > currentMach)
                {
                    dragTableNode = dragTableNode.Previous;
                }

                drag = ballisicFactor * densityFactor * dragTableNode.CalculateDrag(currentMach) * velocity.Value;

                velocityVector = new Vector <VelocityUnit>(
                    velocityVector.X - deltaTime.TotalSeconds * drag * velocityAdjusted.X,
                    velocityVector.Y - deltaTime.TotalSeconds * drag * velocityAdjusted.Y
                    - earthGravity * deltaTime.TotalSeconds,
                    velocityVector.Z - deltaTime.TotalSeconds * drag * velocityAdjusted.Z);

                var deltaRangeVector = new Vector <DistanceUnit>(calculationStep,
                                                                 new Measurement <DistanceUnit>(velocityVector.Y.In(VelocityUnit.MetersPerSecond) * deltaTime.TotalSeconds, DistanceUnit.Meter),
                                                                 new Measurement <DistanceUnit>(velocityVector.Z.In(VelocityUnit.MetersPerSecond) * deltaTime.TotalSeconds, DistanceUnit.Meter));

                rangeVector += deltaRangeVector;
                velocity     = velocityVector.Magnitude;
                time         = time.Add(BallisticMath.TravelTime(deltaRangeVector.Magnitude, velocity));
            }

            return(trajectoryPoints);
        }