1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
#pragma once
#include <vector>
#include <string>
#include <mutex>
#include "libs/predict/predict.h"
#include <thread>
#include "common/tracking/rotator/rotator_handler.h"
#include "common/geodetic/geodetic_coordinates.h"
#include "common/image/image.h"
namespace satdump
{
class ObjectTracker
{
public:
enum TrackingMode
{
TRACKING_SATELLITE,
TRACKING_HORIZONS,
TRACKING_NONE,
};
struct SatAzEl
{
float az = 0;
float el = 0;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(SatAzEl, az, el);
};
private: // QTH Config
double qth_lon = 0;
double qth_lat = 0;
double qth_alt = 0;
private: // General configs/utils
TrackingMode tracking_mode = TRACKING_NONE;
bool has_tle = false, is_gui;
std::mutex general_mutex;
inline float az_el_to_plot_x(float plot_size, float radius, float az, float el) { return sin(az * DEG_TO_RAD) * plot_size * radius * ((90.0 - el) / 90.0); }
inline float az_el_to_plot_y(float plot_size, float radius, float az, float el) { return cos(az * DEG_TO_RAD) * plot_size * radius * ((90.0 - el) / 90.0); }
private: // Satellite Tracking (libpredict)
std::vector<std::string> satoptions;
int current_satellite_id = 0;
std::string satellite_searchstr;
predict_orbital_elements_t *satellite_object = nullptr;
predict_position satellite_orbit;
predict_observer_t *satellite_observer_station = nullptr;
predict_observation satellite_observation_pos;
private: // Horizons Tracking (horizons)
struct HorizonsV
{
double timestamp;
float az, el;
};
std::vector<std::pair<int, std::string>> horizonsoptions = {{-234, "STEREO-A"}};
int current_horizons_id = 0;
std::vector<HorizonsV> horizons_data;
std::string horizons_searchstr;
inline void horizons_interpolate(double xvalue, float *az_out, float *el_out)
{
int start_pos = 0;
while (start_pos < (int)horizons_data.size() && xvalue > horizons_data[start_pos].timestamp)
start_pos++;
if (start_pos + 1 == (int)horizons_data.size())
start_pos--;
if (start_pos == 0)
start_pos++;
double x1 = horizons_data[start_pos].timestamp;
double x2 = horizons_data[start_pos + 1].timestamp;
double az_y1 = horizons_data[start_pos].az;
double az_y2 = horizons_data[start_pos + 1].az;
double el_y1 = horizons_data[start_pos].el;
double el_y2 = horizons_data[start_pos + 1].el;
// printf("%d - %f %f %f - %f %f\n", start_pos, x1, xvalue, x2, y1, y2);
double x_len = x2 - x1;
xvalue -= x1;
double az_y_len = az_y2 - az_y1;
double el_y_len = el_y2 - el_y1;
*az_out = az_y1 + (xvalue / x_len) * az_y_len;
*el_out = el_y1 + (xvalue / x_len) * el_y_len;
}
double last_horizons_fetch_time = 0;
std::vector<std::pair<int, std::string>> pullHorizonsList();
void loadHorizons(double curr_time);
std::vector<HorizonsV> pullHorizonsData(double start_time, double stop_time, int num_points);
private: // Internal threads
bool backend_should_run = true;
std::thread backend_thread;
void backend_run();
bool backend_needs_update = true;
bool rotatorth_should_run = true;
std::thread rotatorth_thread;
void rotatorth_run();
private: // Current satellite
SatAzEl sat_current_pos;
std::mutex upcoming_passes_mtx;
std::vector<SatAzEl> upcoming_pass_points;
void updateNextPass(double current_time);
float correctRotatorAzimuth(const float az);
double next_aos_time = -1, next_los_time = -1;
SatAzEl sat_next_aos_pos;
SatAzEl sat_next_los_pos;
private: // Rotator control
bool rotator_engaged = false;
bool rotator_tracking = false;
bool northbound_cross = false;
bool southbound_cross = false;
SatAzEl rot_current_pos;
SatAzEl rot_current_req_pos;
SatAzEl rot_current_reqlast_pos;
std::mutex rotator_handler_mtx;
std::shared_ptr<rotator::RotatorHandler> rotator_handler;
double rotator_update_period = 1;
bool rotator_park_while_idle = false;
bool rotator_rounding = false;
int rotator_decimal_multiplier = 1000;
int rotator_decimal_precision = 3;
SatAzEl rotator_park_position;
double rotator_unpark_at_minus = 60;
bool meridian_flip_correction = false;
int rotator_az_min = 0;
int rotator_az_max = 360;
bool rotator_arrowkeys_enable = false;
double rotator_arrowkeys_increment = 0.1;
public: // Handlers
std::function<void(double, double)> rotator_target_pos_updated_callback; //Todo: this calls from rotatorth_thread
public: // Functions
nlohmann::json getStatus();
image::Image getPolarPlotImg(int size = 256);
void setQTH(double qth_lon, double qth_lat, double qth_alt);
void setObject(TrackingMode mode, int objid);
void setRotator(std::shared_ptr<rotator::RotatorHandler> rot);
void setRotatorEngaged(bool v);
void setRotatorTracking(bool v);
void setRotatorReqPos(float az, float el);
void renderPolarPlot();
void renderSelectionMenu();
void renderObjectStatus();
void renderRotatorStatus();
void renderRotatorConfig();
nlohmann::json getRotatorConfig();
void setRotatorConfig(nlohmann::json v);
public:
ObjectTracker(bool is_gui = false);
~ObjectTracker();
};
}
|