public float GetSegmentMissileAdjustment(int burnSegment, int acceleration, AimAdjustment aimAdjustment)
        {
            ValidateParameters(burnSegment, acceleration, aimAdjustment);

            int mpatAccelerationAdjustment = GetMpatAccelerationAdjustment(acceleration);

            return(_mpatData[(byte)aimAdjustment, burnSegment - 1 + mpatAccelerationAdjustment]);
        }
        public float GetSegmentMissileAdjustment(int burnSegment, int acceleration, AimAdjustment aimAdjustment)
        {
            ValidateParameters(burnSegment, acceleration, aimAdjustment);

            int mpatAccelerationAdjustment = GetMpatAccelerationAdjustment(acceleration);

            return _mpatData[(byte)aimAdjustment, burnSegment - 1 + mpatAccelerationAdjustment];
        }
        public float GetTotalMissileAdjustment(int burnDuration, int acceleration, AimAdjustment aimAdjustment, out int tableColumn)
        {
            ValidateParameters(burnDuration, acceleration, aimAdjustment);
            float totalPositionAdjustment = 0;

            int mpatAccelerationAdjustment = GetMpatAccelerationAdjustment(acceleration);

            for (int i = 0; i < burnDuration; i++)
            {
                totalPositionAdjustment += _mpatData[(byte)aimAdjustment, i + mpatAccelerationAdjustment];
            }

            tableColumn = 7 - burnDuration - mpatAccelerationAdjustment;

            return(totalPositionAdjustment);
        }
        public float GetTotalMissileAdjustment(int burnDuration, int acceleration, AimAdjustment aimAdjustment, out int tableColumn)
        {
            ValidateParameters(burnDuration, acceleration, aimAdjustment);
            float totalPositionAdjustment = 0;

            int mpatAccelerationAdjustment = GetMpatAccelerationAdjustment(acceleration);

            for (int i = 0; i < burnDuration; i++)
            {
                totalPositionAdjustment += _mpatData[(byte)aimAdjustment, i + mpatAccelerationAdjustment];
            }

            tableColumn = 7 - burnDuration - mpatAccelerationAdjustment;

            return totalPositionAdjustment;
        }
        public MissileAccelerationData CalculateMissileAcceleration(int targetRange, int burnDuration, int acceleration, AimAdjustment aimAdjustment, float roc)
        {
            int tableColumn;
            float totalPositionAdjustment = _missilePositionAdjustmentTable.GetTotalMissileAdjustment(burnDuration, acceleration, aimAdjustment, out tableColumn);

            var result = new MissileAccelerationData
            {
                TotalAcceleration = roc * burnDuration,
                TotalPositionAdjustment = totalPositionAdjustment,
                TableColumn = tableColumn,
                TargetRange = targetRange,
                BurnDuration = burnDuration,
                ValidLaunch = true
            };

            result.BurnDistance = result.TotalAcceleration - result.TotalPositionAdjustment;
            float nextRange = targetRange - result.BurnDistance;

            if (nextRange <= 0)
            {
                result.ValidLaunch = false;
                return result;
            }

            // Filling acceleration data per impulse.
            for (int i = 0; i < burnDuration; i++)
            {
                var currentImpulse = new MissileAccelerationImpulse
                {
                    PositionAdjustment = _missilePositionAdjustmentTable.GetSegmentMissileAdjustment(i + 1, acceleration, aimAdjustment),
                    Range = nextRange
                };

                result.ImpulseData.Add(currentImpulse);

                nextRange = nextRange + roc - currentImpulse.PositionAdjustment;
            }

            if (Math.Abs(nextRange - targetRange) > 0.3f)
            {
                throw new ArithmeticException(string.Format("After computing missile acceleration info, couldn't reach target range at launch ({0}). Final range = {1}",
                                              targetRange, nextRange));
            }

            return result;
        }
        private void ValidateParameters(int burnSegment, int acceleration, AimAdjustment aimAdjustment)
        {
            if (aimAdjustment == AimAdjustment.NoShot)
            {
                throw new ArgumentException("There should be a valid firing solution to reference MPAT.", "aimAdjustment");
            }

            if (burnSegment < 1 || burnSegment > 6)
            {
                throw new ArgumentException("Only burn durations 1 - 6 are supported by MPAT.", "burnSegment");
            }

            if (acceleration == 0 || acceleration % 8 != 0)
            {
                throw new ArgumentException("Acceleration should a multiple of 8, excluding zero.", "acceleration");
            }
        }
        private void ValidateParameters(int burnSegment, int acceleration, AimAdjustment aimAdjustment)
        {
            if (aimAdjustment == AimAdjustment.NoShot)
            {
                throw new ArgumentException("There should be a valid firing solution to reference MPAT.", "aimAdjustment");
            }

            if (burnSegment < 1 || burnSegment > 6)
            {
                throw new ArgumentException("Only burn durations 1 - 6 are supported by MPAT.", "burnSegment");
            }

            if (acceleration == 0 || acceleration % 8 != 0)
            {
                throw new ArgumentException("Acceleration should a multiple of 8, excluding zero.", "acceleration");
            }
        }
        public MissileAccelerationData CalculateMissileAcceleration(int targetRange, int burnDuration, int acceleration, AimAdjustment aimAdjustment, float roc)
        {
            int   tableColumn;
            float totalPositionAdjustment = _missilePositionAdjustmentTable.GetTotalMissileAdjustment(burnDuration, acceleration, aimAdjustment, out tableColumn);

            var result = new MissileAccelerationData
            {
                TotalAcceleration       = roc * burnDuration,
                TotalPositionAdjustment = totalPositionAdjustment,
                TableColumn             = tableColumn,
                TargetRange             = targetRange,
                BurnDuration            = burnDuration,
                ValidLaunch             = true
            };

            result.BurnDistance = result.TotalAcceleration - result.TotalPositionAdjustment;
            float nextRange = targetRange - result.BurnDistance;

            if (nextRange <= 0)
            {
                result.ValidLaunch = false;
                return(result);
            }

            // Filling acceleration data per impulse.
            for (int i = 0; i < burnDuration; i++)
            {
                var currentImpulse = new MissileAccelerationImpulse
                {
                    PositionAdjustment = _missilePositionAdjustmentTable.GetSegmentMissileAdjustment(i + 1, acceleration, aimAdjustment),
                    Range = nextRange
                };

                result.ImpulseData.Add(currentImpulse);

                nextRange = nextRange + roc - currentImpulse.PositionAdjustment;
            }

            if (Math.Abs(nextRange - targetRange) > 0.3f)
            {
                throw new ArithmeticException(string.Format("After computing missile acceleration info, couldn't reach target range at launch ({0}). Final range = {1}",
                                                            targetRange, nextRange));
            }

            return(result);
        }