internal static Vector ConvertAltAzmToAxes(Vector altAz)
        {
            Vector axes = altAz;

            switch (TelescopeHardware.AlignmentMode)
            {
            case ASCOM.DeviceInterface.AlignmentModes.algAltAz:
                break;

            case ASCOM.DeviceInterface.AlignmentModes.algGermanPolar:
                axes = AstronomyFunctions.CalculateHaDec(altAz, TelescopeHardware.Latitude, TelescopeHardware.Longitude);
                if (TelescopeHardware.Latitude < 0)
                {
                    axes.Y = -axes.Y;
                }
                axes = RangeAltAzm(axes);
                if (axes.X > 180.0 || axes.X < 0)
                {
                    // adjust the targets to be through the pole
                    axes.X += 180;
                    axes.Y  = 180 - axes.Y;
                }
                break;

            case ASCOM.DeviceInterface.AlignmentModes.algPolar:
                axes = AstronomyFunctions.CalculateHaDec(altAz, TelescopeHardware.Latitude, TelescopeHardware.Longitude);
                if (TelescopeHardware.Latitude < 0)
                {
                    axes.Y = -axes.Y;
                }
                axes = RangeAltAzm(axes);
                break;
            }
            return(RangeAxes(axes));
        }
        internal static Vector ConvertAxesToAltAzm(Vector axes)
        {
            Vector altAzm = axes;

            switch (TelescopeHardware.AlignmentMode)
            {
            case ASCOM.DeviceInterface.AlignmentModes.algAltAz:
                break;

            case ASCOM.DeviceInterface.AlignmentModes.algGermanPolar:
                if (axes.Y > 90)
                {
                    axes.X += 180;
                    axes.Y  = 180 - axes.Y;
                }
                if (TelescopeHardware.Latitude < 0)
                {
                    axes.Y = -axes.Y;
                }
                var ra = TelescopeHardware.SiderealTime - axes.X / 15.0;
                altAzm = AstronomyFunctions.CalculateAltAzm(ra, axes.Y, TelescopeHardware.Latitude);
                break;

            case ASCOM.DeviceInterface.AlignmentModes.algPolar:
                ra = TelescopeHardware.SiderealTime - axes.X / 15.0;
                if (TelescopeHardware.Latitude < 0)
                {
                    axes.Y = -axes.Y;
                }
                altAzm = AstronomyFunctions.CalculateAltAzm(ra, axes.Y, TelescopeHardware.Latitude);
                break;
            }
            return(RangeAltAzm(altAzm));
        }
        internal static Vector ConvertAxesToRaDec(Vector axes)
        {
            Vector raDec = new Vector();

            switch (TelescopeHardware.AlignmentMode)
            {
            case ASCOM.DeviceInterface.AlignmentModes.algAltAz:
                raDec    = AstronomyFunctions.CalculateRaDec(axes, TelescopeHardware.Latitude, TelescopeHardware.Longitude);
                raDec.X /= 15.0;     // Convert RA in degrees to hours - Added by Peter 4th August 2018 to fix the hand box RA displayed value when in Alt/Az mode
                break;

            case ASCOM.DeviceInterface.AlignmentModes.algGermanPolar:
            case ASCOM.DeviceInterface.AlignmentModes.algPolar:
                // undo through the pole
                if (axes.Y > 90)
                {
                    axes.X += 180.0;
                    axes.Y  = 180 - axes.Y;
                    axes    = RangeAltAzm(axes);
                }
                raDec.X = TelescopeHardware.SiderealTime - axes.X / 15.0;
                raDec.Y = (TelescopeHardware.Latitude >= 0) ? axes.Y : -axes.Y;
                break;
            }

            return(RangeRaDec(raDec));
        }
        /// <summary>
        /// Calculate HA/Dec vector from AltAz vector - Return RA and Dec in degrees
        /// </summary>
        /// <param name="targetAltAzm"></param>
        /// <param name="latitude"></param>
        /// <param name="longitude"></param>
        /// <returns>HA/Dec vector in degrees</returns>
        internal static Vector CalculateHaDec(Vector targetAltAzm, double latitude, double longitude)
        {
            Vector raDec = new Vector();
            var    ra    = AstronomyFunctions.CalculateRA(targetAltAzm.Y, targetAltAzm.X, latitude, longitude);

            raDec.X = AstronomyFunctions.HourAngle(ra, longitude) * 15.0;
            raDec.Y = AstronomyFunctions.CalculateDec(targetAltAzm.Y, targetAltAzm.X, latitude);
            return(raDec);
        }
        /// <summary>
        /// convert a RaDec position to an axes positions.
        /// </summary>
        /// <param name="raDec"></param>
        /// <param name="preserveSop">used for sync</param>
        /// <returns></returns>
        internal static Vector ConvertRaDecToAxes(Vector raDec, bool preserveSop = false)
        {
            Vector axes = new Vector();

            switch (TelescopeHardware.AlignmentMode)
            {
            case ASCOM.DeviceInterface.AlignmentModes.algAltAz:
                axes = AstronomyFunctions.CalculateAltAzm(raDec.X, raDec.Y, TelescopeHardware.Latitude);
                break;

            case ASCOM.DeviceInterface.AlignmentModes.algGermanPolar:
                var sop = TelescopeHardware.SideOfPier;
                axes.X = (TelescopeHardware.SiderealTime - raDec.X) * 15.0;
                axes.Y = (TelescopeHardware.Latitude >= 0) ? raDec.Y : -raDec.Y;
                axes.X = RangeAzm(axes.X);
                if (axes.X > 180.0 || axes.X < 0)
                {
                    // adjust the targets to be through the pole
                    axes.X += 180;
                    axes.Y  = 180 - axes.Y;
                }
                var newsop = (axes.Y <= 90 && axes.Y >= -90) ?
                             PierSide.pierEast : PierSide.pierWest;

                if (preserveSop && newsop != sop)
                {
                    if (TelescopeHardware.NoSyncPastMeridian)
                    {
                        throw new InvalidOperationException("Sync is not allowed when the mount has tracked past the meridian");
                    }

                    axes.X -= 180;
                    axes.Y  = 180 - axes.Y;
                }
                break;

            case ASCOM.DeviceInterface.AlignmentModes.algPolar:
                axes.X = (TelescopeHardware.SiderealTime - raDec.X) * 15.0;
                axes.Y = (TelescopeHardware.Latitude >= 0) ? raDec.Y : -raDec.Y;
                break;
            }
            return(RangeAxes(axes));
        }