#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* PROHIBITED ZONE IMPLEMENTATION */ #include #include #include #include "mcc_mount_concepts.h" #include "mcc_mount_coord.h" #include "mcc_traits.h" namespace mcc { static constexpr double mcc_sideral_to_UT1_ratio = 1.002737909350795; // sideral/UT1 /* SOME SIMPLE PROHIBITED ZONE IMPLEMENTATIONS */ // minimal or maximal altitude prohibited zones enum class MccAltLimitKind { MIN_ALT_LIMIT, MAX_ALT_LIMIT }; template class MccAltLimitPZ // class MccAltLimitPZ : public MccProhibitedZone { protected: static constexpr auto pi2 = std::numbers::pi * 2.0; public: static constexpr MccCoordPairKind preferedCoordKind = MccCoordPairKind::COORDS_KIND_AZALT; static constexpr MccAltLimitKind altLimitKind = KIND; typedef double coord_t; // typedef MccAngle coord_t; // floating-point time duration (seconds) typedef std::chrono::duration duration_t; typedef std::chrono::system_clock::time_point time_point_t; static constexpr duration_t infiniteDuration{std::numeric_limits::infinity()}; static constexpr duration_t zeroDuration{0.0}; MccAltLimitPZ(const coord_t& alt_limit, const coord_t& lat, traits::mcc_astrom_engine_c auto* astrom_engine) // : MccProhibitedZone(KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE" // : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE" // : "ALTLIMIT-UNKNOWN"), : _altLimit(alt_limit), _latitude(lat), _abs_lat(std::abs(_latitude)), _lat_lim(pi2 - _abs_lat) { _lat_lim = pi2 - _abs_lat; // _altLimit.normalize(); _altLimit = MccAngle(_altLimit).normalize(); using astrom_engine_t = std::remove_cvref_t; using astrom_coord_t = typename astrom_engine_t::coord_t; static_assert(std::convertible_to, "ASTROMETRY ENGINE AND THE ZONE COORDINATE TYPE ARE NOT COMPATIBLE!"); static_assert(std::convertible_to, "ASTROMETRY ENGINE AND THE ZONE COORDINATE TYPE ARE NOT COMPATIBLE!"); _coord2coord = [astrom_engine, this](MccCoordPairKind kind_from, coord_t x_from, coord_t y_from, time_point_t tpoint, MccCoordPairKind kind_to, coord_t& x_to, coord_t& y_to) { auto err = astrom_engine->coord2coord(kind_from, std::move(x_from), std::move(y_from), tpoint, kind_to, x_to, y_to, tpoint); }; } consteval std::string_view name() const { return KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE" : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE" : "ALTLIMIT-UNKNOWN"; } // check if current mount coordinates are within the zone bool inZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data) { if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { return telemetry_data.mntALT <= _altLimit; } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { return telemetry_data.mntALT >= _altLimit; } } // returns a time to reach the zone duration_t timeTo(traits::mcc_mount_telemetry_data_c auto const& telemetry_data) { if (inZone(telemetry_data)) { return zeroDuration; } if (!doesObjectReachZone(telemetry_data)) { return infiniteDuration; } if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { // the closest time point is one after upper culmination return compute(telemetry_data, false); } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { // the closest time point is one before upper // culmination return compute(telemetry_data, true); } } // returns a time to exit from the zone duration_t timeFrom(traits::mcc_mount_telemetry_data_c auto const& telemetry_data) { if (!inZone(telemetry_data)) { return zeroDuration; } if (!doesObjectExitFromZone(telemetry_data)) { return infiniteDuration; } if (!doesObjectReachZone(telemetry_data)) { return zeroDuration; } if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { // the closest time point is one before upper culmination return compute(telemetry_data, true); } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { // the closest time point is one after upper // culmination return compute(telemetry_data, false); } } bool inZone(traits::mcc_celestial_point_c auto const& target) { coord_t alt, az; _coord2coord(target.coordPairKind, target.x, target.y, target.time_point, MccCoordPairKind::COORDS_KIND_AZALT, az, alt); if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { return alt <= _altLimit; } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { return alt >= _altLimit; } } duration_t timeTo(traits::mcc_celestial_point_c auto const& target) { coord_t ha, dec; if (inZone(target)) { return zeroDuration; } _coord2coord(target.coordPairKind, target.x, target.y, target.time_point, MccCoordPairKind::COORDS_KIND_HADEC_APP, ha, dec); if (!doesObjectReachZone(ha)) { return infiniteDuration; } if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { // the closest time point is one after upper culmination return compute(ha, dec, false); } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { // the closest time point is one before upper // culmination return compute(ha, dec, true); } } duration_t timeFrom(traits::mcc_celestial_point_c auto const& target) { coord_t ha, dec; if (!inZone(target)) { return zeroDuration; } _coord2coord(target.coordPairKind, target.x, target.y, target.time_point, MccCoordPairKind::COORDS_KIND_HADEC_APP, ha, dec); if (!doesObjectExitFromZone(ha)) { return infiniteDuration; } if (!doesObjectReachZone(ha)) { return zeroDuration; } if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { // the closest time point is one before upper culmination return compute(ha, dec, true); } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { // the closest time point is one after upper // culmination return compute(ha, dec, false); } } // compute intersection point for the case of sideral-like moving bool intersectPoint(traits::mcc_celestial_point_c auto const& target, traits::mcc_celestial_point_c auto& int_point) { coord_t ha, dec, az; _coord2coord(target.coordPairKind, target.x, target.y, target.time_point, MccCoordPairKind::COORDS_KIND_HADEC_APP, ha, dec); // _altLimit = 0.001_degs; // compute HA for intersection point double cos_ha = (std::sin(_altLimit) - std::sin(dec) * std::sin(_latitude)) / std::cos(dec) / std::cos(_latitude); std::cout << "HA(inter) = " << MccAngle(ha).sexagesimal(true) << "\n"; std::cout << "DEC(inter) = " << MccAngle(dec).sexagesimal() << "\n"; std::cout << "HA(85.0) = " << MccAngle(acos(cos_ha)).sexagesimal(true) << "\n"; std::cout << "HA(85.0) = " << MccAngle(-acos(cos_ha)).sexagesimal(true) << "\n"; std::cout << "PHI = " << MccAngle(_latitude).sexagesimal() << "\n"; std::cout << "COS_HA = " << cos_ha << "\n"; if (cos_ha > 1.0) { // no intersection // compute culmination points? return false; } double cosA = (-std::sin(dec) * std::cos(_latitude) + std::cos(dec) * std::sin(_latitude) * cos_ha) / cos(_altLimit); // cosA /= std::cos(_altLimit); std::cout << "COS_A = " << cosA << "\n"; double sinA = std::cos(dec) * sqrt(1.0 - cos_ha * cos_ha) / cos(_altLimit); double tgA = sqrt(1.0 - cos_ha * cos_ha) / (cos(_latitude) * tan(dec) - sin(_latitude) * cos_ha); auto z = (-std::sin(dec) * std::cos(_latitude) + std::cos(dec) * std::sin(_latitude) * cos_ha) / cosA; // (-std::sin(dec) * std::cos(_latitude) + std::cos(dec) * std::sin(_latitude) * cos_ha) / cos(133.75_degs); std::cout << "Z = " << MccAngle(asin(z)).sexagesimal() << "\n"; if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { // the closest time point is one after upper culmination az = std::acos(cosA); // az = atan2(sinA, cosA); } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { // the closest time point is one before upper // culmination az = -std::acos(cosA) + std::numbers::pi; // to system of azimuth started from the North!!! // az = atan(tgA); // az = std::asin(sinA); // az = atan2(sinA, cosA); } _coord2coord(MccCoordPairKind::COORDS_KIND_AZALT, az, _altLimit, target.time_point, int_point.coordPairKind, int_point.x, int_point.y); return true; } private: coord_t _altLimit, _latitude, _abs_lat, _lat_lim; // wrapper function std::function _coord2coord{}; bool doesObjectReachZone(const coord_t& dec_app) { // check for limit conditions auto dd = std::abs(dec_app); if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { dd += _altLimit; if (dd > _lat_lim) { // never fall below altitude limit return false; } } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { if ((dd < (_abs_lat - _altLimit)) || (dd > (_abs_lat + _altLimit))) { // never rise above altitude limit return false; } } else { static_assert(false, "UNKNOWN ALTITUDE LIMIT TYPE!"); } return true; } bool doesObjectReachZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data) { return doesObjectReachZone(telemetry_data.mntDEC); } bool doesObjectExitFromZone(const coord_t& dec_app) { // check for limit conditions auto dd = std::abs(dec_app); if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) { dd -= _altLimit; if (-dd <= -_lat_lim) { // always below altitude limit return false; } } else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { if ((dd >= (_abs_lat - _altLimit)) || (dd <= (_abs_lat + _altLimit))) { // always above altitude limit return false; } } else { static_assert(false, "UNKNOWN ALTITUDE LIMIT TYPE!"); } return true; } bool doesObjectExitFromZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data) { return doesObjectExitFromZone(telemetry_data.mntDEC); } duration_t compute(const coord_t& ha_app, const coord_t& dec_app, bool before_upper_culm) { double cos_ha = (std::sin(_altLimit) - std::sin(dec_app) * std::sin(_latitude)) / std::cos(dec_app) / std::cos(_latitude); if (cos_ha > 1.0) { // should not be! return infiniteDuration; } double ha; // WARNING: what about south hemisphere?!!! if (before_upper_culm) { ha = -std::acos(cos_ha); // HA before upper culmination } else { ha = std::acos(cos_ha); // HA after upper culmination!! } coord_t time_ang = ha - ha_app; // in sideral time scale if (time_ang < 0.0) { // next day time_ang += pi2; } time_ang /= mcc_sideral_to_UT1_ratio; // to UT1 time scale return duration_t{MccAngle(time_ang).seconds()}; // return duration_t{time_ang.seconds()}; } duration_t compute(traits::mcc_mount_telemetry_data_c auto const& telemetry_data, bool before_upper_culm) { return compute(telemetry_data.mntHA, telemetry_data.mntDEC, before_upper_culm); } }; typedef MccAltLimitPZ MccMinAltPZ; typedef MccAltLimitPZ MccMaxAltPZ; static_assert(std::movable); } // namespace mcc