本文上传了除导星外的所有代码。
Astronomy.h
#ifndef ASTRONOMY_H
#define ASTRONOMY_H
#include<iostream>
#include<opencv2/opencv.hpp>
#include<Eigen/Dense>
#include<Windows.h>
#include<cmath>
#include"windows.h"
#include"atlstr.h"
#include<string.h>
#include<TCHAR.H>
#include<conio.h>
#include<stdarg.h>
#include"LsxMath.h"
#include"Global.h"
#include"StarPointDeal.h"
namespace lsx {
namespace astronomy {
/**
* @brief 当地恒星时计算器
*/
class AstroTimer {
public:
/**
* @brief 计算当地恒星时
* @param none
* @return void
*/
double get_local_sidereal_time();
private:
unsigned int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
/**
* @brief 计算系统当前时间
* @param none
* @return void
*/
void get_this_time();
/**
* @brief 计算(0h UT)儒略日,使用星图软件stellarium计算方法,
计算方式来源:https://blog.csdn.net/shaoguangleo/article/details/6248315
* @param none
* @return 返回的儒略日(long double类型)
*/
long double JD();
/**
* @brief 计算任意时刻的儒略日,使用星图软件stellarium计算方法,
计算方式来源:https://blog.csdn.net/shaoguangleo/article/details/6248315
* @param none
* @return 返回的儒略日(long double类型)
*/
long double _JD();
/**
* @brief 得到中介参数T(T = (JD - 2451545.0) / 36525)
* @param is_0h_UT 是否是计算(0h UT)标志位
* @return 中介参数T
*/
long double T(bool is_0h_UT = true);
/**
* @brief 格林尼治平恒星时(使用IAU1982标准)
* @param is_0h_UT 是否是计算(0h UT)标志位,当该位为true时计算格林尼治(0h UT)的平恒星时
,当该位为false时计算任意时刻的格林尼治平恒星时
* @return 格林尼治平恒星时
*/
long double Greenwich_mean_sidereal_time(bool is_0h_UT = true);
};
/**
* @brief 单个观测目标
*/
class ObservationTarget {
public:
double RA_angle = 0;//赤经角度坐标,单位:°
double DEC_angle = 0;//赤纬角度坐标,单位:°
double elevation = 0;//仰角,单位:°
double azimuth = 0;//方位角,单位:°
double RA_hour = 0;//赤经时
double RA_min = 0;//赤经分
double RA_second = 0;//赤经秒
double DEC_degree = 0;//赤纬度
double DEC_min = 0;//赤纬分
double DEC_second = 0;//赤纬秒
double position_in_image_x = 0;//该天体在自动寻星图像上的横坐标
double position_in_image_y = 0;//该天体在自动寻星图像上的纵坐标
bool error = true;//是否是错误星体
bool isStar = false;//是否是恒星标志位
bool origin_show = true;//一开始就展示名字
std::string name = "赤道仪零位";
std::string number = "赤道仪零位";
std::string ShowName = "000";
/**
* @brief 设置观测天体坐标
* @param number 天体编号
* @param name 天体名称
* @param RA_hour 赤经小时
* @param RA_min 赤经分
* @param RA_second 赤经秒
* @param DEC_degree 赤纬度
* @param DEC_min 赤纬分
* @param DEC_second 赤纬秒
* @return void
*/
void inputTarget(std::string number, std::string name, std::string showName, \
double RA_hour, double RA_min, double RA_second, double DEC_degree, double DEC_min, double DEC_second, \
bool is_star, bool origin_show = true);
/**
* @brief 打印天体参数
* @param none
* @return void
*/
void printTarget();
/**
* @brief 判断是否为当前天体
* @param none
* @return void
*/
bool isName(std::string& inputName_or_Number);
ObservationTarget(std::string number, std::string name, std::string showName, \
double RA_hour, double RA_min, double RA_second, double DEC_degree, double DEC_min, double DEC_second,\
bool is_star, bool origin_show = true);
ObservationTarget();
private:
};
/**
* @brief 观测目标列表
*/
class ObservationTable {
public:
std::vector<ObservationTarget> TargetTable;
/**
* @brief 在星表中插入一个新的天体,如果需要观测星表外的天体,可以通过该函数临时插入
* @param number 天体编号
* @param name 天体名称
* @param RA_hour 赤经小时
* @param RA_min 赤经分
* @param RA_second 赤经秒
* @param DEC_degree 赤纬度
* @param DEC_min 赤纬分
* @param DEC_second 赤纬秒
* @param is_star 是否是恒星的标志位,true:该天体为恒星;false:该天体不是恒星
* @return void
*/
void input_new_target(std::string number, std::string name, std::string showName, \
double RA_hour, double RA_min, double RA_second, double DEC_degree, double DEC_min, double DEC_second, \
bool is_star);
/**
* @brief 在目标列表中得到观测目标
* @param name_or_number 名称或编号
* @return 通过名称或编号寻找的观测目标
*/
lsx::astronomy::ObservationTarget findTarget(std::string& name_or_number);
/**
* @brief 判断该表格中是否存在这个天体
* @param name_or_number 名称或编号
* @return 查询到这个天体则返回true,否则返回false
*/
bool tatgetInTable(std::string& name_or_number);
/**
* @brief 生成自动寻星的图像界面
* @param width 图像宽度
* @param height 图像高度
* @return 包含天体位置、中天位置的图像界面
*/
cv::Mat getTargetTableImage();
/**
* @brief 用于找到鼠标就近的一个星点
*/
lsx::astronomy::ObservationTarget findCloseTarget(double& image_x, double& image_y, double& radius, bool* have_choose);
/**
* @brief 从图像坐标转换到天体实际坐标
*/
void get_ra_dec(double& image_x, double& image_y, double* ra, double* dec);
/**
* @brief 从赤经赤纬得到图像坐标
*/
void get_image_x_y(double& ra, double& dec, double* image_x, double* image_y);
ObservationTable();
private:
cv::Mat _TargetTableImage;
/**
* @brief 通过名称或者编号得到天体
*/
lsx::astronomy::ObservationTarget getTarget(std::string& name_or_number);
/**
* @brief 星表类初始化
*/
void input_data();
};
/**
* @brief 得到星点指向向量
* @param ra_degree 赤经,单位:°
* @param dec_degree 赤经,单位:°
* @param zenith_degree 中天赤经:单位:°
* @return 星点在天体坐标系下的指向向量
*/
Eigen::MatrixXd StarPointVector(double& ra_degree, double& dec_degree, double& zenith_degree);
/**
* @brief 将赤经角度转换到0~360°区间内
* @param inputRA 输入的角度,单位:°
* @return 转换后的角度
*/
double RA_inRegion_0_360(double inputRA);
/**
* @brief 得到中天位置的假想天体
*/
lsx::astronomy::ObservationTarget GetZenith();
/**
* @brief 两个天体之间的最短赤经角距离
* @param inputRA1 输入的天体1赤经,单位:°
* @param inputRA2 输入的天体2赤经,单位:°
* @return 最短角距离,单位:°
*/
double getMinAngle(double& inputRA1, double& inputRA2);
/**
* @brief 两个天体之间的最短赤经角距离
* @param inputTarget1 输入的天体1
* @param inputTarget2 输入的天体2
* @return 最短角距离,单位:°
*/
double getMinAngle(lsx::astronomy::ObservationTarget& inputTarget1, lsx::astronomy::ObservationTarget& inputTarget2);
/**
* @brief 判断天体是否通过中天
* @param inputarget 输入天体
* @return 通过中天则为true,否则为false
*/
bool RA_PassZenith(lsx::astronomy::ObservationTarget& inputTarget);
/**
* @brief 判断天体是否在地平线以下
* @param inputOberveTarget 输入天体
* @return 在地平线以下为true,否则为false
*/
bool TargetUnderHorizon(lsx::astronomy::ObservationTarget& inputOberveTarget);
/**
* @brief 将天体的赤道坐标转换为地平坐标,并保存在对应的成员变量其中
* @param inputTarget 输入天体
* @return void
*/
void Equ2EleAzi(lsx::astronomy::ObservationTarget* inputTarget);
/**
* @brief 计算地球运行角度
* @param inputTime_ms 输入的运行时间,单位:ms
* @return 地球运行的角度,单位:°
*/
double earthRotateAngle(double inputTime_ms);
/**
* @brief 计算地球转动时间
* @param inputAngle_degree 输入的运行角度,单位:°
* @return 地球转动的时间,单位:ms
*/
int earthRotateTime(double inputAngle_degree);
/**
* @brief 赤经坐标转换为角度
* @param hour 赤经时
* @param min 赤经分
* @param sec 赤经秒
* @return RA角度,单位:°
*/
double ra2degree(double hour, double min, double sec);
/**
* @brief 赤纬坐标转换为角度
* @param degree 赤纬度
* @param min 赤纬分
* @param sec 赤纬秒
* @return DEC角度,单位:°
*/
double dec2degree(double degree, double min, double sec);
/**
* @brief 赤纬坐标转换为时间
* @param inputAngle_degree 输入的角度
* @param ra_hour 赤经时
* @param ra_min 赤经分
* @param ra_sec 赤经秒
* @return void
*/
void degree2ra(double inputAngle_degree, double* ra_hour, double* ra_min, double* ra_sec);
/**
* @brief 将角度用度、分、秒表示
* @param input_angle_degree 输入的角度
* @param deg 度
* @param min 分
* @param sec 秒
* @return void
*/
void degree_2_deg_min_sec(double input_angle_degree, double* deg, double* min, double* sec);
/**
* @brief 将赤经角度转换到0~360°区间内
* @param inputAngle_degree 输入的角度,单位:°
* @return 转换后的角度,单位:°
*/
double angle_in_0_360(double inputAngle_degree);
/**
* @brief 得到地平线上的赤经范围
* @param dec_angle_degree 天体的赤纬坐标
* @param down_threhold 地平线上天体下阈值
* @param up_threhold 地平线上天体上阈值
* @return 角度范围
*/
double theta_on_horizon_degree(double dec_angle_degree, double* down_threhold, double* up_threhold);
}
}
#endif
Astronomy.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Astronomy.h"
extern double global_latitude;//观测地纬度
extern double global_longitude;//观测地经度
extern int zenith_line_color[3];//地平线颜色
extern cv::Scalar background;//背景颜色
extern cv::Scalar background_line;//刻度线颜色
extern cv::Scalar star_color;//恒星颜色
extern cv::Scalar not_star_color;//天体颜色
extern cv::Scalar big_word;//图样范围字符颜色
extern cv::Scalar zenith_str_line;//背景颜色
extern int goto_image_width, goto_image_height;//自动寻星的图像大小
void lsx::astronomy::AstroTimer::get_this_time() {
SYSTEMTIME time_;
GetLocalTime(&time_);
this->year = time_.wYear;
this->month = time_.wMonth;
this->day = time_.wDay;
this->hour = time_.wHour;
this->min = time_.wMinute;
this->sec = time_.wSecond;
}
long double lsx::astronomy::AstroTimer::_JD() {
int y, m, B;
this->get_this_time();
y = this->year;
m = this->month;
if (this->month <= 2)
{
y = this->year - 1;
m = this->month + 12;
}
B = -2;
if (this->year > 1582 || (this->year == 1582 && (this->month > 10 || (this->month == 10 && this->day >= 15))))
{
B = y / 400 - y / 100;
}
return (floor(365.25 * y) + floor(30.6001 * (double(m) + 1.0)) + B + 1720996.5 + this->day + this->hour / 24.0 + this->min / 1440.0 + this->sec / 86400.0);
}
long double lsx::astronomy::AstroTimer::JD() {
int y, m, B;
this->get_this_time();
y = this->year;
m = this->month;
if (this->month <= 2)
{
y = this->year - 1;
m = this->month + 12;
}
B = -2;
if (this->year > 1582 || (this->year == 1582 && (this->month > 10 || (this->month == 10 && this->day >= 15))))
{
B = y / 400 - y / 100;
}
return (floor(365.25 * y) + floor(30.6001 * (double(m) + 1.0)) + B + 1720996.5 + this->day);
}
long double lsx::astronomy::AstroTimer::T(bool is_0h_UT) {
if (is_0h_UT) {
return (this->JD() - long double(2451545.0)) / long double(36525.0);
}
else {
return (this->_JD() - long double(2451545.0)) / long double(36525.0);
}
}
long double lsx::astronomy::AstroTimer::Greenwich_mean_sidereal_time(bool is_0h_UT) {
long double this_T = this->T(is_0h_UT), greenwich_mean_sidereal_time = 0;
long double T = 0;
if (is_0h_UT) {
greenwich_mean_sidereal_time = long double(100.46061837) +
long double(36000.770053608) * this_T +
long double(0.000387933) * this_T * this_T -
this_T * this_T * this_T / long double(38710000);
}
else {
greenwich_mean_sidereal_time = long double(280.46061837) +
long double(360.98564736629) * (this->_JD() - 2451545.0) +
long double(0.000387933) * this_T * this_T -
this_T * this_T * this_T / long double(38710000);
}
return greenwich_mean_sidereal_time;
}
double lsx::astronomy::AstroTimer::get_local_sidereal_time() {
double output_local_sidereal_time = 0;
double local_time = 0;//地方平时
double greenwich_time = 0;//格林尼治平时
this->get_this_time();
local_time = lsx::astronomy::ra2degree(this->hour, this->min, this->sec) + global_longitude - lsx::astronomy::ra2degree(8, 0, 0);//地方平时
greenwich_time = local_time - global_longitude;//格林尼治平时
output_local_sidereal_time = local_time + double(this->Greenwich_mean_sidereal_time(true)) + greenwich_time / 365.2422;
output_local_sidereal_time = lsx::astronomy::RA_inRegion_0_360(output_local_sidereal_time);
return output_local_sidereal_time;
}
double lsx::astronomy::RA_inRegion_0_360(double inputRA) {
if (inputRA > 360.0) {
while (inputRA > 360.0)
inputRA -= 360.0;
}
else if (inputRA < 0) {
while (inputRA < 0)
inputRA += 360.0;
}
return inputRA;
}
double lsx::astronomy::theta_on_horizon_degree(double dec_angle_degree, double* down_threhold, double* up_threhold) {
double angle = 0;
if (dec_angle_degree >= 90.0 - global_latitude) {
*down_threhold = -180.0;
*up_threhold = 180.0;
return 360.0;
}
else if (dec_angle_degree >= 0 && 90.0 - global_latitude) {
angle = 360.0 - 2.0 * acos(tan(fabs(dec_angle_degree) / 180.0 * PI) * tan(fabs(global_latitude) / 180.0 * PI)) / PI * 180.0;
*down_threhold = lsx::astronomy::angle_in_0_360(local_sidreal_time_degree() - 0.5 * angle);
*up_threhold = lsx::astronomy::angle_in_0_360(local_sidreal_time_degree() + 0.5 * angle);
return angle;
}
else if (dec_angle_degree > -(90.0 - global_latitude) && dec_angle_degree < 0) {
angle = 2.0 * acos(tan(fabs(dec_angle_degree) / 180.0 * PI) * tan(global_latitude / 180.0 * PI)) / PI * 180.0;
*down_threhold = lsx::astronomy::angle_in_0_360(local_sidreal_time_degree() - 0.5 * angle);
*up_threhold = lsx::astronomy::angle_in_0_360(local_sidreal_time_degree() + 0.5 * angle);
return angle;
}
else {
*down_threhold = 0;
*up_threhold = 0;
return 0;
}
}
lsx::astronomy::ObservationTarget lsx::astronomy::GetZenith() {
lsx::astronomy::ObservationTarget outputTarget;
outputTarget.RA_angle = local_sidreal_time_degree();//*********************************************************
outputTarget.DEC_angle = 90.0;
return outputTarget;
}
double lsx::astronomy::getMinAngle(double& inputRA1, double& inputRA2) {
inputRA1 = lsx::astronomy::RA_inRegion_0_360(inputRA1);
inputRA2 = lsx::astronomy::RA_inRegion_0_360(inputRA2);
if (fabs(inputRA1 - inputRA2) > 180.0)
return 360.0 - fabs(inputRA1 - inputRA2);
return fabs(inputRA1 - inputRA2);
}
double lsx::astronomy::getMinAngle(lsx::astronomy::ObservationTarget& target1,\
lsx::astronomy::ObservationTarget& target2) {
return lsx::astronomy::getMinAngle(target1.RA_angle, target2.RA_angle);
}
bool lsx::astronomy::RA_PassZenith(lsx::astronomy::ObservationTarget& inputTarget) {
Eigen::MatrixXd zenith_vector(3, 1), target_vector(3, 1), z_axis(3, 1);
zenith_vector << 0, -1, 0;
z_axis << 0, 0, 1;
target_vector = lsx::math::RotationMatrix3(z_axis, (inputTarget.RA_angle - local_sidreal_time_degree()) / 180.0 * PI) * zenith_vector;
if (target_vector(0, 0) > 0) {
return false;
}
else {
return true;
}
}
void lsx::astronomy::ObservationTarget::inputTarget(std::string number, std::string name, std::string showName, \
double RA_hour, double RA_min, double RA_second, double DEC_degree, double DEC_min, double DEC_second, \
bool is_star, bool origin_show) {
this->RA_hour = RA_hour;
this->RA_min = RA_min;
this->RA_second = RA_second;
this->DEC_degree = DEC_degree;
this->DEC_min = DEC_min;
this->DEC_second = DEC_second;
this->RA_angle = lsx::astronomy::ra2degree(this->RA_hour, this->RA_min, this->RA_second);
if (this->DEC_degree < 0 || this->DEC_min < 0 || this->DEC_second < 0) {
this->DEC_degree = -fabs(this->DEC_degree);
this->DEC_min = -fabs(this->DEC_min);
this->DEC_second = -fabs(this->DEC_second);
}
this->DEC_angle = lsx::astronomy::dec2degree(this->DEC_degree, this->DEC_min, this->DEC_second);
this->name = name;
this->number = number;
this->ShowName = showName;
this->isStar = is_star;
this->origin_show = origin_show;
}
void lsx::astronomy::ObservationTarget::printTarget() {
std::cout <<" "<< this->name << std::endl;
std::cout << " " << "RA:" << this->RA_hour << " h " << this->RA_min << " min " << this->RA_second << " sec " << "(" << this->RA_angle << "°)" << std::endl;
std::cout << " " << "DEC:" << this->RA_hour << " ° " << this->RA_min << " ′ " << this->RA_second << " ″ " << "(" << this->DEC_angle << "°)" << std::endl;
}
bool lsx::astronomy::ObservationTarget::isName(std::string& inputName_or_Number) {
if (inputName_or_Number == this->name || inputName_or_Number == this->number) {
return true;
}
else {
return false;
}
}
lsx::astronomy::ObservationTarget::ObservationTarget(std::string number, std::string name, std::string showName, \
double RA_hour, double RA_min, double RA_second, double DEC_degree, double DEC_min, double DEC_second, \
bool is_star, bool origin_show) {
this->inputTarget(number, name, showName, RA_hour, RA_min, RA_second, DEC_degree, DEC_min, DEC_second, is_star, origin_show);
this->error = false;
}
lsx::astronomy::ObservationTarget::ObservationTarget() {
this->error = true;
}
void lsx::astronomy::ObservationTable::input_new_target(std::string number, std::string name, std::string showName, \
double RA_hour, double RA_min, double RA_second, double DEC_degree, double DEC_min, double DEC_second, \
bool is_star) {
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget(number, name, showName, RA_hour, RA_min, RA_second, DEC_degree, DEC_min, DEC_second, is_star));
}
lsx::astronomy::ObservationTable::ObservationTable() {
this->_TargetTableImage = cv::Mat(cv::Size(goto_image_width, goto_image_height), CV_8UC3, background);
cv::Point2d left_mid, right_mid, mid_up, mid_down, ra_gap1, ra_gap2, dec_gap1, dec_gap2;
std::string coordinate_font_[4] = { "RA(0 h)","RA(24 h)","Dec(90 deg)", "Dec(-90 deg)" };
cv::Size font_size[4];
double dec_length = 0, ra_length = 0, font_scale = 0.4;
double this_dec_degree = 0, down_threhold = 0, up_threhold = 0;
int image_down_threhold = 0, image_up_threhold = 0, coordinate_font_thickness = 1,
font_type = cv::FONT_HERSHEY_SIMPLEX, baseLine = 0, gap = 2;
for (int i = 0; i < 4; i++) {
font_size[i] = cv::getTextSize(coordinate_font_[i], font_type, font_scale, coordinate_font_thickness, &baseLine);
}
this->input_data();
dec_length = double(_TargetTableImage.rows) / 180.0;
ra_length = double(_TargetTableImage.cols) / 360.0;
left_mid = cv::Point2d(0, _TargetTableImage.rows / 2); right_mid = cv::Point2d(_TargetTableImage.cols, _TargetTableImage.rows / 2);
mid_up = cv::Point2d(_TargetTableImage.cols / 2, 0); mid_down = cv::Point2d(_TargetTableImage.cols / 2, _TargetTableImage.rows);
for (int i = 1; i < 18; i++) {
ra_gap1.x = i * double(goto_image_width) / 18.0; ra_gap1.y = 0;
ra_gap2.x = ra_gap1.x; ra_gap2.y = _TargetTableImage.rows;
cv::line(_TargetTableImage, ra_gap1, ra_gap2, background_line, 1);
}
for (int i = 1; i < 9; i++) {
dec_gap1.x = 0; dec_gap1.y = i * double(goto_image_height) / 9.0;
dec_gap2.x = _TargetTableImage.cols; dec_gap2.y = dec_gap1.y;
cv::line(_TargetTableImage, dec_gap1, dec_gap2, background_line, 1);
}
left_mid.x += 2; left_mid.y -= double(goto_image_height) / 160.0; right_mid.y -= double(goto_image_height) / 160.0; right_mid.x -= double(goto_image_height) * 3.0 / 20.0;
mid_up.x += double(goto_image_height) / 160.0; mid_down.x += double(goto_image_height) / 400.0; mid_up.y += double(goto_image_height) / 70.0; mid_down.y -= double(goto_image_height) / 60.0;
cv::putText(this->_TargetTableImage, coordinate_font_[0], cv::Point(gap, 0.5 * this->_TargetTableImage.rows - gap),
font_type, font_scale, big_word, coordinate_font_thickness, cv::LINE_AA);
cv::putText(this->_TargetTableImage, coordinate_font_[1], cv::Point(this->_TargetTableImage.cols - 2.0 * font_size[1].width - gap, 0.5 * this->_TargetTableImage.rows - gap),
font_type, font_scale, big_word, coordinate_font_thickness, cv::LINE_AA);
cv::putText(this->_TargetTableImage, coordinate_font_[2], cv::Point(0.5 * this->_TargetTableImage.cols + gap, gap + font_size[2].height),
font_type, font_scale, big_word, coordinate_font_thickness, cv::LINE_AA);
cv::putText(this->_TargetTableImage, coordinate_font_[3], cv::Point(0.5 * double(this->_TargetTableImage.cols) + gap, double(this->_TargetTableImage.rows) - double(gap) - 0.5 * font_size[3].height),
font_type, font_scale, big_word, coordinate_font_thickness, cv::LINE_AA);
for (int i = 0; i < this->TargetTable.size(); i++) {
this->TargetTable[i].position_in_image_x = this->TargetTable[i].RA_angle * ra_length;
this->TargetTable[i].position_in_image_y = double(this->_TargetTableImage.rows) - (this->TargetTable[i].DEC_angle + 90.0) * dec_length;
if (this->TargetTable[i].isStar) {
lsx::starProcessing::DrawStar(this->_TargetTableImage, this->TargetTable[i].position_in_image_x, \
this->TargetTable[i].position_in_image_y, star_color, 10);
if (this->TargetTable[i].origin_show) {
cv::putText(this->_TargetTableImage, this->TargetTable[i].ShowName, cv::Point(this->TargetTable[i].position_in_image_x + 15.0, this->TargetTable[i].position_in_image_y + 4.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, star_color, 1, cv::LINE_AA);
}
}
else {
cv::circle(this->_TargetTableImage, cv::Point(this->TargetTable[i].position_in_image_x, this->TargetTable[i].position_in_image_y), \
4, not_star_color, -1, cv::LINE_AA);
if (this->TargetTable[i].origin_show) {
cv::putText(this->_TargetTableImage, this->TargetTable[i].ShowName, cv::Point(this->TargetTable[i].position_in_image_x + 8.0, this->TargetTable[i].position_in_image_y + 4.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, not_star_color, 1, cv::LINE_AA);
}
}
}
}
//cv::Mat lsx::astronomy::ObservationTable::getTargetTableImage(int width, int height) {
// cv::Mat targetTableImage = cv::Mat(cv::Size(width, height), CV_8UC3, background);
// cv::Point2d left_mid, right_mid, mid_up, mid_down, zenith_up, zenith_down, ra_gap1, ra_gap2, dec_gap1, dec_gap2;
// double dec_length = 0, ra_length = 0;
// double this_dec_degree = 0, down_threhold = 0, up_threhold = 0;
// int image_down_threhold = 0, image_up_threhold = 0;
// dec_length = double(targetTableImage.rows) / 180.0;
// ra_length = double(targetTableImage.cols) / 360.0;
// left_mid = cv::Point2d(0, targetTableImage.rows / 2); right_mid = cv::Point2d(targetTableImage.cols, targetTableImage.rows / 2);
// mid_up = cv::Point2d(targetTableImage.cols / 2, 0); mid_down = cv::Point2d(targetTableImage.cols / 2, targetTableImage.rows);
// zenith_up.x = local_sidreal_time_degree() * ra_length;
// zenith_down.x = zenith_up.x;
// zenith_up.y = 0;
// zenith_down.y = targetTableImage.rows;
// for (int i = 1; i < 18; i++) {
// ra_gap1.x = i * double(width) / 18.0; ra_gap1.y = 0;
// ra_gap2.x = ra_gap1.x; ra_gap2.y = targetTableImage.rows;
// cv::line(targetTableImage, ra_gap1, ra_gap2, background_line, 1);
// }
// for (int i = 1; i < 9; i++) {
// dec_gap1.x = 0; dec_gap1.y = i * double(height) / 9.0;
// dec_gap2.x = targetTableImage.cols; dec_gap2.y = dec_gap1.y;
// cv::line(targetTableImage, dec_gap1, dec_gap2, background_line, 1);
// }
// cv::line(targetTableImage, zenith_up, zenith_down, cv::Scalar(zenith_line_color[0], zenith_line_color[1], zenith_line_color[2]), 1);
// left_mid.x += 2; left_mid.y -= double(height) / 160.0; right_mid.y -= double(height) / 160.0; right_mid.x -= double(height) * 3.0 / 20.0;
// mid_up.x += double(height) / 160.0; mid_down.x += double(height) / 400.0; mid_up.y += double(height) / 70.0; mid_down.y -= double(height) / 60.0;
// zenith_down.x += double(height) / 400.0;zenith_down.y -= double(height) / 20.0;
// cv::putText(targetTableImage, "RA 0h", left_mid, cv::FONT_HERSHEY_SIMPLEX, 0.4, big_word, 1, cv::LINE_AA);
// cv::putText(targetTableImage, "RA 24h", right_mid, cv::FONT_HERSHEY_SIMPLEX, 0.4, big_word, 1, cv::LINE_AA);
// cv::putText(targetTableImage, "DEC -90", mid_down, cv::FONT_HERSHEY_SIMPLEX, 0.4, big_word, 1, cv::LINE_AA);
// cv::putText(targetTableImage, "DEC 90", mid_up, cv::FONT_HERSHEY_SIMPLEX, 0.4, big_word, 1, cv::LINE_AA);
// cv::putText(targetTableImage, "Zenith", zenith_down, cv::FONT_HERSHEY_SIMPLEX, 0.4, big_word, 1, cv::LINE_AA);
// for (int i = 0; i < this->TargetTable.size(); i++) {
// this->TargetTable[i].position_in_image_x = this->TargetTable[i].RA_angle * ra_length;
// this->TargetTable[i].position_in_image_y = double(targetTableImage.rows) - (this->TargetTable[i].DEC_angle + 90.0) * dec_length;
// if (this->TargetTable[i].isStar) {
// lsx::starProcessing::DrawStar(targetTableImage, this->TargetTable[i].position_in_image_x, \
// this->TargetTable[i].position_in_image_y, star_color, 10);
// cv::putText(targetTableImage, this->TargetTable[i].ShowName, cv::Point(this->TargetTable[i].position_in_image_x + 15.0, this->TargetTable[i].position_in_image_y + 4.0), \
// cv::FONT_HERSHEY_SIMPLEX, 0.4, star_color, 1, cv::LINE_AA);
// }
// else {
// cv::circle(targetTableImage, cv::Point(this->TargetTable[i].position_in_image_x, this->TargetTable[i].position_in_image_y), \
// 4, not_star_color, -1, cv::LINE_AA);
// cv::putText(targetTableImage, this->TargetTable[i].ShowName, cv::Point(this->TargetTable[i].position_in_image_x + 8.0, this->TargetTable[i].position_in_image_y + 4.0), \
// cv::FONT_HERSHEY_SIMPLEX, 0.4, not_star_color, 1, cv::LINE_AA);
// }
// }
// for (int i = 0; i < targetTableImage.rows; i++) {
// this_dec_degree = 90.0 - i / dec_length;
// lsx::astronomy::theta_on_horizon_degree(this_dec_degree, &down_threhold, &up_threhold);
// if (this_dec_degree <= 90.0 - global_latitude && this_dec_degree >= -(90.0 - global_latitude)) {
// image_down_threhold = down_threhold * ra_length;
// image_up_threhold = up_threhold * ra_length;
// cv::Vec3b* pixelPtr = targetTableImage.ptr<cv::Vec3b>(i);
// pixelPtr[image_down_threhold][0] = zenith_line_color[0];
// pixelPtr[image_down_threhold][1] = zenith_line_color[1];
// pixelPtr[image_down_threhold][2] = zenith_line_color[2];
// pixelPtr[image_up_threhold] = pixelPtr[image_down_threhold];
// }
//
// }
// this->_TargetTableImage = targetTableImage;
// return targetTableImage;
//}
cv::Mat lsx::astronomy::ObservationTable::getTargetTableImage() {
cv::Mat targetTableImage;
cv::Point2d zenith_up, zenith_down, ra_gap1;
double dec_length = 0, ra_length = 0;
double this_dec_degree = 0, down_threhold = 0, up_threhold = 0;
int image_down_threhold = 0, image_up_threhold = 0;
this->_TargetTableImage.copyTo(targetTableImage);
dec_length = double(targetTableImage.rows) / 180.0;
ra_length = double(targetTableImage.cols) / 360.0;
zenith_up.x = local_sidreal_time_degree() * ra_length;
zenith_down.x = zenith_up.x;
zenith_up.y = 0;
zenith_down.y = targetTableImage.rows;
cv::line(targetTableImage, zenith_up, zenith_down, zenith_str_line, 1, cv::LINE_AA);
zenith_down.x += double(goto_image_height) / 400.0; zenith_down.y -= double(goto_image_height) / 20.0;
cv::putText(targetTableImage, "Zenith", zenith_down, cv::FONT_HERSHEY_SIMPLEX, 0.4, big_word, 1, cv::LINE_AA);
for (int i = 0; i < targetTableImage.rows; i++) {
this_dec_degree = 90.0 - i / dec_length;
lsx::astronomy::theta_on_horizon_degree(this_dec_degree, &down_threhold, &up_threhold);
if (this_dec_degree <= 90.0 - global_latitude && this_dec_degree >= -(90.0 - global_latitude)) {
image_down_threhold = down_threhold * ra_length;
image_up_threhold = up_threhold * ra_length;
cv::Vec3b* pixelPtr = targetTableImage.ptr<cv::Vec3b>(i);
pixelPtr[image_down_threhold][0] = zenith_line_color[0];
pixelPtr[image_down_threhold][1] = zenith_line_color[1];
pixelPtr[image_down_threhold][2] = zenith_line_color[2];
pixelPtr[image_up_threhold] = pixelPtr[image_down_threhold];
}
}
return targetTableImage;
}
void lsx::astronomy::ObservationTable::get_ra_dec(double& image_x, double& image_y, double* ra, double* dec) {
double ra_length = double(this->_TargetTableImage.cols) / 360.0, dec_length = double(this->_TargetTableImage.rows) / 180.0;
(*ra) = image_x / ra_length;
(*dec) = 90.0 - image_y / dec_length;
}
void lsx::astronomy::ObservationTable::get_image_x_y(double& ra, double& dec, double* image_x, double* image_y) {
double dec_length = 0, ra_length = 0;
dec_length = double(this->_TargetTableImage.rows) / 180.0;
ra_length = double(this->_TargetTableImage.cols) / 360.0;
(*image_x) = ra * ra_length;
(*image_y) = double(this->_TargetTableImage.rows) - (dec + 90.0) * dec_length;
}
lsx::astronomy::ObservationTarget lsx::astronomy::ObservationTable::findCloseTarget(double& image_x, double& image_y, double& radius, bool* have_choose) {
int i = 0, min_length = 2000000, this_length = 0, close_i = 0;
for (i = 0; i < this->TargetTable.size(); i++) {
this_length = lsx::math::PointLength(image_x, image_y, this->TargetTable[i].position_in_image_x, this->TargetTable[i].position_in_image_y);
if (this_length < min_length) {
close_i = i;
min_length = this_length;
}
}
if (min_length < radius) {
(*have_choose) = true;
return this->TargetTable[close_i];
}
else {
(*have_choose) = false;
return lsx::astronomy::ObservationTarget::ObservationTarget();
}
}
bool lsx::astronomy::ObservationTable::tatgetInTable(std::string& name_or_number) {
for (int i = 0; i < this->TargetTable.size(); i++) {
if (this->TargetTable[i].isName(name_or_number)) {
return true;
}
}
return false;
}
lsx::astronomy::ObservationTarget lsx::astronomy::ObservationTable::getTarget(std::string& name_or_number) {
for (int i = 0; i < this->TargetTable.size(); i++) {
if (this->TargetTable[i].isName(name_or_number)) {
return this->TargetTable[i];
}
}
}
lsx::astronomy::ObservationTarget lsx::astronomy::ObservationTable::findTarget(std::string& name_or_number) {
if (this->tatgetInTable(name_or_number)) {
return this->getTarget(name_or_number);
}
else {
return lsx::astronomy::ObservationTarget();
}
}
bool lsx::astronomy::TargetUnderHorizon(lsx::astronomy::ObservationTarget& inputOberveTarget) {
double gama = acos(tan(inputOberveTarget.DEC_angle / 180.0 * PI) * tan(global_latitude / 180.0 * PI));
lsx::astronomy::ObservationTarget zenithTarget;
double theta = 0;
zenithTarget = lsx::astronomy::GetZenith();
if (inputOberveTarget.DEC_angle > 90.0 - global_latitude) {
return false;
}
if (inputOberveTarget.DEC_angle > 0.0 && inputOberveTarget.DEC_angle < 90.0 - global_latitude) {
theta = 360.0 - 2.0 * gama;
}
else if (inputOberveTarget.DEC_angle < 0.0 && inputOberveTarget.DEC_angle > -(90.0 - global_latitude)) {
theta = 2.0 * gama;
}
else {
return true;
}
if (lsx::astronomy::getMinAngle(inputOberveTarget, zenithTarget) < 0.5 * theta) {
return false;
}
return true;
}
Eigen::MatrixXd lsx::astronomy::StarPointVector(double& ra_degree, double& dec_degree, double& zenith_degree) {
return lsx::math::StarPointVector3(ra_degree / 180.0 * PI, dec_degree / 180.0 * PI, zenith_degree / 180.0 * PI);
}
void lsx::astronomy::Equ2EleAzi(lsx::astronomy::ObservationTarget* inputTarget) {
Eigen::MatrixXd star_vector(3, 1), z_axis(3, 1), _x_axis(2, 1), star_vector_floor(2, 1);
double azimuth = 0;
z_axis << 0, 0, 1;
_x_axis << -1, 0;
star_vector = lsx::math::StarPointVector3(inputTarget->RA_angle / 180.0 * PI,
inputTarget->DEC_angle / 180.0 * PI,
local_sidreal_time_degree() / 180.0 * PI);
inputTarget->elevation = (0.5 * PI - lsx::math::VectorAngle_rad(star_vector, z_axis)) /
PI * 180.0 ;
star_vector_floor << star_vector(0, 0), star_vector(1, 0);
azimuth = lsx::math::VectorAngle_rad(star_vector_floor, _x_axis) / PI * 180.0;
if (star_vector(1, 0) > 0) {
inputTarget->azimuth = azimuth;
}
else {
inputTarget->azimuth = 360.0 - azimuth;//加减360°是等效的
}
}
double lsx::astronomy::earthRotateAngle(double inputTime_ms) {
return 360.0 * inputTime_ms / (86164.0 * 1000.0);
}
int lsx::astronomy::earthRotateTime(double inputAngle_degree) {
return int(inputAngle_degree * 1000.0 * 86164.0 / 360.0);
}
double lsx::astronomy::ra2degree(double hour, double min, double sec) {
return 15.0 * hour + 0.25 * min + sec / 240.0;
}
double lsx::astronomy::dec2degree(double degree, double min, double sec) {
return degree + min / 60.0 + sec / 3600.0;
}
void lsx::astronomy::degree2ra(double inputAngle_degree, double* ra_hour, double* ra_min, double* ra_sec) {
double stay_angle = 0;
inputAngle_degree = lsx::astronomy::angle_in_0_360(inputAngle_degree);
stay_angle = inputAngle_degree / 15.0;
(*ra_hour) = int(stay_angle);
inputAngle_degree -= int(stay_angle) * 15.0;
stay_angle = inputAngle_degree / 0.25;
(*ra_min) = int(stay_angle);
inputAngle_degree -= int(stay_angle) * 0.25;
stay_angle = inputAngle_degree / (0.25 / 60);
(*ra_sec) = stay_angle;
}
void lsx::astronomy::degree_2_deg_min_sec(double input_angle_degree, double* deg, double* min, double* sec) {
double _deg = 0, _min = 0, _sec = 0, angle = fabs(input_angle_degree);
_deg = floor(angle);
angle = (angle - _deg) * 60.0;
_min = floor(angle);
angle = (angle - _min) * 60.0;
_sec = angle;
if (input_angle_degree < 0) {
_deg *= -1; _min *= -1; _sec *= -1;
}
*deg = _deg; *min = _min; *sec = _sec;
}
double lsx::astronomy::angle_in_0_360(double inputAngle_degree) {
if (inputAngle_degree < 0) {
while (inputAngle_degree < 0) {
inputAngle_degree += 360.0;
}
}
else if (inputAngle_degree > 360.0) {
while (inputAngle_degree > 360.0) {
inputAngle_degree -= 360.0;
}
}
return inputAngle_degree;
}
AutoStarSearch.h
#ifndef AUTOSTARSEARCH_H
#define AUTOSTARSEARCH_H
#include"Global.h"
#include"Astronomy.h"
#include"EquatorialControl.h"
namespace lsx {
namespace autoSearch {
class AutoStarFindController {
public:
/**
* @brief 自动寻星系统函数
*/
void AutomaticStarFinding();
/**
* @brief 预先设置自动寻星控制器,将初始位置调整为当前指向
* @param targetName 当前赤道仪指向天体名称
* @param targetNumber 当前赤道仪指向天体编号
* @param decSide Dec转轴半盘位置,可选:DEC_IS_ON_THE_LEFT;DEC_IS_ON_THE_RIGHT
* @param afterGuide 导星结束标志位
* @return void
*/
void preSet(std::string targetName = "empty target", std::string targetNumber = "empty target", int decSide = DEC_IS_ON_THE_RIGHT);
private:
lsx::astronomy::ObservationTable targetTable;
lsx::astronomy::ObservationTarget start, end;
bool zero2star = false;//是否是从0位置开始的
bool ra_arrival = false, dec_arrival = false;
lsx::astronomy::ObservationTarget pointTarget;
bool this_target_is_star = false;
/**
* @brief 自动寻星系统主函数
*/
void gotoControl();
///**
// * @brief 判断天体是否在地平线之上
// */
//bool onHorizon(lsx::astronomy::ObservationTarget inputTarget);
/**
* @brief 两天体之间的最小赤经角距离
*/
double ra_minAngle(lsx::astronomy::ObservationTarget target1, lsx::astronomy::ObservationTarget target2);
/**
* @brief RA通过中天
*/
bool passZenith(lsx::astronomy::ObservationTarget inputTarget);
/**
* @brief 将赤经转换在0-360之间
*/
double ra_in_region_0_360(double input_ra);
///**
// * @brief 显示延时倒计时
// */
//void showRunTime(double RA_inputTime_ms, double DEC_inputTime_ms, lsx::astronomy::ObservationTarget start, lsx::astronomy::ObservationTarget end);
/**
* @brief 得到移动的赤道仪位置坐标
*/
void get_image_position(double start_x, double start_y, double end_x, double end_y, double x_runtime, double y_runtime, \
std::clock_t start_time, std::clock_t end_time, \
cv::Point* now);
};
}
}
#endif
AutoStarSearch.cpp
#include"AutoStarSearch.h"
extern bool noTarget;//是否是第一次使用自动寻星
extern bool after_guide;//是否是在导星之后进入自动寻星
extern int DEC_side;//DEC运行半圆所在的方位
extern std::string this_target_name;//当前目标名称
extern std::string this_target_number;//当前观测目标编号(如M42等)
extern cv::Scalar coordinate_words;//鼠标触摸到天体后显示坐标的颜色
extern cv::Scalar show_state_1_color;//Select a star with the mouse to calibrate the '0' position.提示符颜色
extern cv::Scalar my_equatorial_instrument_color;//赤道仪图像显示的颜色
extern cv::Scalar my_equatorial_instrument_line_color;//赤道仪移动线颜色
extern cv::Scalar optional_target_color;//可选天体的图像显示颜色
extern int goto_image_width, goto_image_height;//自动寻星的图像大小
double mouse_botton_x = -1, mouse_botton_y = -1, mouse_touch_x = -1, mouse_touch_y = -1;
bool mouse_get_coondinate = false;
bool goto_origin_position = false;
bool deal_mouse_event = true;
void autoStarSearch_mouse_callback(int event_, int x, int y, int flags, void* userData) {
if (deal_mouse_event) {
if (event_ == cv::EVENT_LBUTTONDOWN) {
mouse_botton_x = x;
mouse_botton_y = y;
mouse_get_coondinate = true;
/* std::cout << mouse_botton_x << " " << mouse_botton_y << std::endl;*/
}
else if (event_ == cv::EVENT_RBUTTONDOWN) {
mouse_botton_x = x;
mouse_botton_y = y;
mouse_get_coondinate = true;
goto_origin_position = true;
}
}
if (event_ == cv::EVENT_MOUSEMOVE) {
mouse_touch_x = x;
mouse_touch_y = y;
}
}
//bool lsx::autoSearch::AutoStarFindController::onHorizon(lsx::astronomy::ObservationTarget inputTarget) {
// lsx::astronomy::ObservationTarget thisTarget = inputTarget;
// lsx::astronomy::Equ2EleAzi(&thisTarget);
// if (thisTarget.elevation > 0) {
// return true;
// }
// else {
// return false;
// }
//}
double lsx::autoSearch::AutoStarFindController::ra_minAngle(lsx::astronomy::ObservationTarget target1, lsx::astronomy::ObservationTarget target2) {
return lsx::math::Min(fabs(target1.RA_angle - target2.RA_angle), 360.0 - fabs(target1.RA_angle - target2.RA_angle));
}
bool lsx::autoSearch::AutoStarFindController::passZenith(lsx::astronomy::ObservationTarget inputTarget) {
Eigen::MatrixXd zenith_vector(3, 1), target_vector(3, 1), z_axis(3, 1);
zenith_vector << 0, -1, 0;
z_axis << 0, 0, 1;
target_vector = lsx::math::RotationMatrix3(z_axis, (inputTarget.RA_angle - local_sidreal_time_degree()) / 180.0 * PI) * zenith_vector;
if (target_vector(0, 0) > 0) {
return false;
}
else {
return true;
}
}
double lsx::autoSearch::AutoStarFindController::ra_in_region_0_360(double input_ra) {
return lsx::astronomy::RA_inRegion_0_360(input_ra);
}
//void lsx::autoSearch::AutoStarFindController::showRunTime(double RA_inputTime_ms, double DEC_inputTime_ms, lsx::astronomy::ObservationTarget start, lsx::astronomy::ObservationTarget end) {
// int RA_runtime_sec = RA_inputTime_ms / 1000.0 + 1, DEC_runtime_sec = DEC_inputTime_ms / 1000.0 + 1;
// int max_runtime = lsx::math::Max(RA_runtime_sec, DEC_runtime_sec);
// std::cout << std::endl;
// SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);
// std::cout << " 起点:" << start.name << "(RA:" << start.RA_hour << " h " << start.RA_min << " min " << start.RA_second << " s , DEC:" \
// << start.DEC_degree << "°" << fabs(start.DEC_min) << " min " << fabs(start.DEC_second) << " sec)" << std::endl;
// std::cout << std::endl;
// SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
// std::cout << " 终点:" << end.name << "(RA:" << end.RA_hour << " h " << end.RA_min << " min " << end.RA_second << " s , DEC:" \
// << end.DEC_degree << "°" << fabs(end.DEC_min) << " min " << fabs(end.DEC_second) << " sec)" << std::endl;
// SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);
// std::cout << std::endl;
// std::cout << " 赤道仪运行中. . ." << std::endl;
// SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
// std::cout << std::endl;
// for (int i = 0; i < max_runtime; i++) {
// printf_s("\r");
// if (RA_runtime_sec - i > 0 && DEC_runtime_sec - i > 0)
// std::cout << " RA剩余时间:" << RA_runtime_sec - i << "秒 | DEC剩余时间:" << DEC_runtime_sec - i << "秒 ";
// else if (RA_runtime_sec - i <= 0 && DEC_runtime_sec - i > 0)
// std::cout << " RA运行结束!" << " | DEC剩余时间:" << DEC_runtime_sec - i << "秒 ";
// else if (RA_runtime_sec - i > 0 && DEC_runtime_sec - i <= 0)
// std::cout << " RA剩余时间:" << RA_runtime_sec - i << "秒 | DEC运行结束! ";
// else
// std::cout << "赤道仪到达目标位置! ";
// Sleep(1000);
// }
// system("cls");
//}
/**
* @brief 得到赤道仪的图像位置,时间单位都是毫秒
*/
void lsx::autoSearch::AutoStarFindController::get_image_position(double start_x, double start_y, double end_x, double end_y, double x_runtime, double y_runtime, \
std::clock_t start_time, std::clock_t end_time, \
cv::Point* now) {
double k_y = (end_y - start_y) / y_runtime, k_x = (end_x - start_x) / x_runtime;
double d_time = double(end_time) - double(start_time);
now->x = k_x * d_time + start_x;
now->y = k_y * d_time + start_y;
if (start_x > end_x && start_y > end_y) {
if (now->x <= end_x) {
now->x = end_x;
}
if (now->y <= end_y) {
now->y = end_y;
}
}
else if (start_x <= end_x && start_y > end_y) {
if (now->x >= end_x) {
now->x = end_x;
}
if (now->y <= end_y) {
now->y = end_y;
}
}
else if (start_x > end_x && start_y <= end_y) {
if (now->x <= end_x) {
now->x = end_x;
}
if (now->y >= end_y) {
now->y = end_y;
}
}
else if (start_x <= end_x && start_y <= end_y) {
if (now->x >= end_x) {
now->x = end_x;
}
if (now->y >= end_y) {
now->y = end_y;
}
}
}
void lsx::autoSearch::AutoStarFindController::gotoControl() {
int dec_direction = 0, ra_direction = 0;
double find_radius = 20; double ra_runtime_ms = 0, dec_runtime_ms = 0;
double ra_angle = 0, dec_angle = 0, dec_angle_part = 0;
bool show_warning = false; bool arrive_the_target = false; bool choose_target = false; bool touch_target = false;
bool get_end_target = false; bool back_origin_position = false;
char choose_choose = 'n';
std::string inputTargetName;
cv::Mat star_image; cv::Point now_position;
std::clock_t start_time, end_time;
lsx::astronomy::ObservationTarget mouse_touch_target;//鼠标触摸到的目标
double now_run_time = 0; double start_x = 0, start_y = 0, end_x = 0, end_y = 0;
double width = goto_image_width, heigth = goto_image_height;
std::string win_name = "Shixuan Liu - Auto Star Search", _EQ = "my EQ";
std::string show_target_name = " Name: ";
char show_ra[50] = { 0 }, show_dec[50] = { 0 }, show_my_equ[90] = { 0 }, show_ele[50] = { 0 }, show_azi[50] = { 0 };
double elevation_2_deg_min_sec[3] = { 0 }, azimuth_2_deg_min_sec[3] = { 0 };
cv::namedWindow(win_name, cv::WINDOW_AUTOSIZE);
//cv::setWindowProperty(win_name, cv::WND_PROP_FULLSCREEN, cv::WINDOW_FULLSCREEN);
cv::setMouseCallback(win_name, autoStarSearch_mouse_callback);
mouse_get_coondinate = false;
goto_origin_position = false;
deal_mouse_event = true;
star_image = this->targetTable.getTargetTableImage();
/*----------------------------------------------------目标天体输入---------------------------------------------------------*/
if (noTarget) {
this->zero2star = true;
}
/*----------------------------------------------------当前天体输入------------------------------------------------------------*/
if (noTarget && !after_guide) {//从零位开始,没有经过导星
this->start.RA_angle = this->ra_in_region_0_360(local_sidreal_time_degree() + 90.0);
this->start.DEC_angle = 90.0;
this->start.DEC_degree = 90.0;
this->start.name = "零位";
this->start.number = "0";
this->start.ShowName = "E0";
lsx::astronomy::degree2ra(this->start.RA_angle, &this->start.RA_hour, &this->start.RA_min, &this->start.RA_second);
}
else if (noTarget && after_guide) {//从零位模式开始,经过导星
if (this->targetTable.tatgetInTable(this_target_name)) {
this->start = this->targetTable.findTarget(this_target_name);
}
else {
this->start = this->targetTable.findTarget(this_target_number);
}
}
else {
if (!(this_target_name == "零位" || this_target_number == "0")) {
if (this->targetTable.tatgetInTable(this_target_name)) {
this->start = this->targetTable.findTarget(this_target_name);
}
else {
this->start = this->targetTable.findTarget(this_target_number);
}
}
else {
this->start.RA_angle = this->ra_in_region_0_360(local_sidreal_time_degree() + 90.0);
this->start.DEC_angle = 90.0;
this->start.DEC_degree = 90.0;
this->start.name = "零位";
this->start.number = "0";
lsx::astronomy::degree2ra(this->start.RA_angle, &this->start.RA_hour, &this->start.RA_min, &this->start.RA_second);
}
}
/*---------------------------------------------------------目标天体输入---------------------------------------------------*/
get_end_target = false;
while (!get_end_target) {
/*-------------对生成图像进行初始化的代码段-------------------*/
star_image = this->targetTable.getTargetTableImage();
if (this->zero2star) {
cv::putText(star_image, "Select a star with the mouse to calibrate the '0' position.", cv::Point(0 + double(heigth) / 200.0, 0 + double(heigth) / 50.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.6, show_state_1_color, 1, cv::LINE_AA);
}
else {
cv::putText(star_image, "Select a observed object with the mouse.", cv::Point(0 + double(heigth) / 200.0, 0 + double(heigth) / 50.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.6, show_state_1_color, 1, cv::LINE_AA);
}
this->targetTable.get_image_x_y(this->start.RA_angle, this->start.DEC_angle, &this->start.position_in_image_x, &this->start.position_in_image_y);
lsx::starProcessing::DrawRegularTriangle(star_image, this->start.position_in_image_x, this->start.position_in_image_y, my_equatorial_instrument_color, double(heigth) / 100.0);
cv::circle(star_image, cv::Point(this->start.position_in_image_x, this->start.position_in_image_y), double(heigth) / 80.0, my_equatorial_instrument_color, 1, cv::LINE_AA);
cv::putText(star_image, _EQ, cv::Point(this->start.position_in_image_x + double(heigth) / 60.0, this->start.position_in_image_y - double(heigth) / 60.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, my_equatorial_instrument_color, 1, cv::LINE_AA);
/*---------------------*/
if (mouse_touch_target.position_in_image_x > 0 && mouse_touch_target.position_in_image_y > 0) {//鼠标触摸显示
lsx::astronomy::Equ2EleAzi(&mouse_touch_target);
lsx::astronomy::degree_2_deg_min_sec(mouse_touch_target.elevation, &elevation_2_deg_min_sec[0], &elevation_2_deg_min_sec[1], &elevation_2_deg_min_sec[2]);
lsx::astronomy::degree_2_deg_min_sec(mouse_touch_target.azimuth, &azimuth_2_deg_min_sec[0], &azimuth_2_deg_min_sec[1], &azimuth_2_deg_min_sec[2]);
sprintf_s(show_ra, " RA: %d hour %d min %d sec", int(mouse_touch_target.RA_hour), int(mouse_touch_target.RA_min), int(mouse_touch_target.RA_second));
sprintf_s(show_dec, " Dec: %d d %d m %d s", int(mouse_touch_target.DEC_degree), int(fabs(mouse_touch_target.DEC_min)), int(fabs(mouse_touch_target.DEC_second)));
sprintf_s(show_ele, " Ele: %d d %d m %d.%d s", int(elevation_2_deg_min_sec[0]), abs(int(elevation_2_deg_min_sec[1])), abs(int(elevation_2_deg_min_sec[2])), int(100.0 * (elevation_2_deg_min_sec[2] - floor(elevation_2_deg_min_sec[2]))));
sprintf_s(show_azi, " Azi: %d d %d m %d.%d s", int(azimuth_2_deg_min_sec[0]), int(azimuth_2_deg_min_sec[1]), int(azimuth_2_deg_min_sec[2]), int(100.0 * (azimuth_2_deg_min_sec[2] - floor(azimuth_2_deg_min_sec[2]))));
if (mouse_touch_target.elevation < 0 || (noTarget && !mouse_touch_target.isStar)) {
if (mouse_touch_target.elevation < 0) {
cv::putText(star_image, "this target is below the horizon!", cv::Point(mouse_touch_target.position_in_image_x - double(heigth) / 20.0, mouse_touch_target.position_in_image_y - double(heigth) / 25.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
cv::circle(star_image, cv::Point(mouse_touch_target.position_in_image_x, mouse_touch_target.position_in_image_y), double(heigth) / 50.0, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
}
else if (noTarget && !mouse_touch_target.isStar) {
cv::putText(star_image, "please select a star!", cv::Point(mouse_touch_target.position_in_image_x - double(heigth) / 20.0, mouse_touch_target.position_in_image_y - double(heigth) / 25.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
cv::circle(star_image, cv::Point(mouse_touch_target.position_in_image_x, mouse_touch_target.position_in_image_y), double(heigth) / 50.0, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
}
}
else {
cv::putText(star_image, "choosable star", cv::Point(mouse_touch_target.position_in_image_x - double(heigth) / 20.0, mouse_touch_target.position_in_image_y - double(heigth) / 25.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.5, optional_target_color, 1, cv::LINE_AA);
cv::circle(star_image, cv::Point(mouse_touch_target.position_in_image_x, mouse_touch_target.position_in_image_y), double(heigth) / 50.0, optional_target_color, 1, cv::LINE_AA);
}
if (!mouse_touch_target.isStar) {
cv::putText(star_image, show_target_name + mouse_touch_target.name, cv::Point(mouse_touch_target.position_in_image_x + double(heigth) / 50.0 + 3, mouse_touch_target.position_in_image_y + double(heigth) / 50.0 + 10), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, coordinate_words, 1, cv::LINE_AA);
}
else {
cv::putText(star_image, show_target_name + mouse_touch_target.ShowName, cv::Point(mouse_touch_target.position_in_image_x + double(heigth) / 50.0 + 3, mouse_touch_target.position_in_image_y + double(heigth) / 50.0 + 10), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, coordinate_words, 1, cv::LINE_AA);
}
cv::putText(star_image, show_ra, cv::Point(mouse_touch_target.position_in_image_x + double(heigth) / 50.0 + 3, mouse_touch_target.position_in_image_y + 20 + double(heigth) / 50.0 + 10), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, coordinate_words, 1, cv::LINE_AA);
cv::putText(star_image, show_dec, cv::Point(mouse_touch_target.position_in_image_x + double(heigth) / 50.0 + 3, mouse_touch_target.position_in_image_y + 40 + double(heigth) / 50.0 + 10), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, coordinate_words, 1, cv::LINE_AA);
cv::putText(star_image, show_ele, cv::Point(mouse_touch_target.position_in_image_x + double(heigth) / 50.0 + 3, mouse_touch_target.position_in_image_y + 60 + double(heigth) / 50.0 + 10), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, coordinate_words, 1, cv::LINE_AA);
cv::putText(star_image, show_azi, cv::Point(mouse_touch_target.position_in_image_x + double(heigth) / 50.0 + 3, mouse_touch_target.position_in_image_y + 80 + double(heigth) / 50.0 + 10), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, coordinate_words, 1, cv::LINE_AA);
}
/*-------------------------------------*/
cv::imshow(win_name, star_image);
cv::waitKey(50);
if (mouse_get_coondinate) {//鼠标按下显示判断语句
/*---------------对生成的图像进行初始化的代码段-----------------*/
star_image = this->targetTable.getTargetTableImage();
if (this->zero2star) {
cv::putText(star_image, "Select a star with the mouse to calibrate the '0' position.", cv::Point(0 + double(heigth) / 200.0, 0 + double(heigth) / 50.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.6, show_state_1_color, 1, cv::LINE_AA);
}
else {
cv::putText(star_image, "Select a observed object with the mouse.", cv::Point(0 + double(heigth) / 200.0, 0 + double(heigth) / 50.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.6, show_state_1_color, 1, cv::LINE_AA);
}
this->targetTable.get_image_x_y(this->start.RA_angle, this->start.DEC_angle, &this->start.position_in_image_x, &this->start.position_in_image_y);
lsx::starProcessing::DrawRegularTriangle(star_image, this->start.position_in_image_x, this->start.position_in_image_y, my_equatorial_instrument_color, double(heigth) / 100.0);
cv::circle(star_image, cv::Point(this->start.position_in_image_x, this->start.position_in_image_y), double(heigth) / 80.0, my_equatorial_instrument_color, 1, cv::LINE_AA);
cv::putText(star_image, _EQ, cv::Point(this->start.position_in_image_x + double(heigth) / 60.0, this->start.position_in_image_y - double(heigth) / 60.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, my_equatorial_instrument_color, 1, cv::LINE_AA);
/*---------------------*/
deal_mouse_event = false;//没有处理,则回调函数不接受鼠标事件
if (!goto_origin_position) {//按下左键
choose_target = false;
this->targetTable.findCloseTarget(mouse_botton_x, mouse_botton_y, find_radius, &choose_target);
if (choose_target) {
this->end = this->targetTable.findCloseTarget(mouse_botton_x, mouse_botton_y, find_radius, &choose_target);
lsx::astronomy::Equ2EleAzi(&this->end);
if (this->end.elevation < 0 || (noTarget && !this->end.isStar)) {
if (this->end.elevation < 0) {
cv::putText(star_image, "this target is below the horizon!", cv::Point(this->end.position_in_image_x - double(heigth) / 20.0, this->end.position_in_image_y - double(heigth) / 25.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
cv::circle(star_image, cv::Point(this->end.position_in_image_x, this->end.position_in_image_y), double(heigth) / 50.0, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
}
else if (noTarget && !this->end.isStar) {
cv::putText(star_image, "please select a star!", cv::Point(this->end.position_in_image_x - double(heigth) / 20.0, this->end.position_in_image_y - double(heigth) / 25.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
cv::circle(star_image, cv::Point(this->end.position_in_image_x, this->end.position_in_image_y), double(heigth) / 50.0, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
}
mouse_get_coondinate = false;
cv::imshow(win_name, star_image);
cv::waitKey(60);
}
else {
cv::putText(star_image, "selected successfully!", cv::Point(this->end.position_in_image_x - double(heigth) / 20.0, this->end.position_in_image_y - double(heigth) / 25.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.5, optional_target_color, 1, cv::LINE_AA);
cv::circle(star_image, cv::Point(this->end.position_in_image_x, this->end.position_in_image_y), double(heigth) / 50.0, optional_target_color, 2, cv::LINE_AA);
mouse_get_coondinate = false;
cv::imshow(win_name, star_image);
noTarget = false; after_guide = false;
get_end_target = true;
cv::waitKey(200);
}
}
else {
mouse_get_coondinate = false;
}
}
else {//按下右键
if (noTarget == false) {
this->targetTable.get_ra_dec(mouse_botton_x, mouse_botton_y, &this->end.RA_angle, &this->end.DEC_angle);
lsx::astronomy::Equ2EleAzi(&this->end);
if (this->end.elevation < 0) {
this->end.RA_angle = this->ra_in_region_0_360(local_sidreal_time_degree() + 90.0);
this->end.DEC_angle = 90.0;
this->end.DEC_degree = 90.0;
this->end.name = "零位";
this->end.number = "0";
lsx::astronomy::degree2ra(this->end.RA_angle, &this->end.RA_hour, &this->end.RA_min, &this->end.RA_second);
get_end_target = true;
back_origin_position = true;
}
else {
mouse_get_coondinate = false;
}
}
else {
mouse_get_coondinate = false;
goto_origin_position = false;
}
}
deal_mouse_event = true;
}
this->targetTable.findCloseTarget(mouse_touch_x, mouse_touch_y, find_radius, &touch_target);
if (touch_target) {
mouse_touch_target = this->targetTable.findCloseTarget(mouse_touch_x, mouse_touch_y, find_radius, &touch_target);
}
else {
mouse_touch_target.position_in_image_x = -1;
mouse_touch_target.position_in_image_y = -1;
}
}
this_target_name = this->end.name;
this_target_number = this->end.number;
this->pointTarget = this->end;
if (this->start.name != this->end.name) {
/*----------------------------------------------------判断语句---------------------------------------------------------*/
if (this->passZenith(this->start) && this->passZenith(this->end)) {//左左
//std::cout << "LL" << std::endl;
if (DEC_side == DEC_IS_ON_THE_RIGHT) {//异常情况处理
DEC_side = DEC_IS_ON_THE_LEFT;
ra_angle = 180.0 + this->ra_minAngle(lsx::astronomy::GetZenith(), this->start) - this->ra_minAngle(lsx::astronomy::GetZenith(), this->end);
dec_angle = 180.0 - this->start.DEC_angle - this->end.DEC_angle;
ra_direction = RA_DIR_BACKWARD;
dec_angle = DEC_DIR_UP_WHEN_RIGHT;
}
else {
ra_angle = this->ra_minAngle(lsx::astronomy::GetZenith(), this->start) - this->ra_minAngle(lsx::astronomy::GetZenith(), this->end);
dec_angle = this->end.DEC_angle - this->start.DEC_angle;
if (ra_angle > 0) {
ra_direction = RA_DIR_BACKWARD;
}
else {
ra_direction = RA_DIR_FORWARD;
}
if (dec_angle > 0) {
dec_direction = DEC_DIR_UP_WHEN_LEFT;
}
else {
dec_direction = DEC_DIR_DOWN_WHEN_LEFT;
}
}
}
else if (this->passZenith(this->start) && !this->passZenith(this->end)) {//左右
//std::cout << "LR" << std::endl;
if (DEC_side == DEC_IS_ON_THE_RIGHT) {//异常情况处理
ra_angle = this->ra_minAngle(lsx::astronomy::GetZenith(), this->start) + this->ra_minAngle(lsx::astronomy::GetZenith(), this->end);
dec_angle = this->end.DEC_angle - this->start.DEC_angle;
ra_direction = RA_DIR_BACKWARD;
if (dec_angle > 0) {
dec_direction = DEC_DIR_UP_WHEN_RIGHT;
}
else {
dec_direction = DEC_DIR_DOWN_WHEN_RIGHT;
}
}
else {
DEC_side = DEC_IS_ON_THE_RIGHT;
ra_angle = 180.0 - this->ra_minAngle(lsx::astronomy::GetZenith(), this->end) - this->ra_minAngle(lsx::astronomy::GetZenith(), this->start);
dec_angle = 180.0 - this->end.DEC_angle - this->start.DEC_angle;
dec_direction = DEC_DIR_UP_WHEN_LEFT;
if (ra_angle > 0) {
ra_direction = RA_DIR_FORWARD;
}
else {
ra_direction = RA_DIR_BACKWARD;
}
}
}
else if (!this->passZenith(this->start) && this->passZenith(this->end)) {//右左
//std::cout << "RL" << std::endl;
if (DEC_side == DEC_IS_ON_THE_LEFT) {
ra_angle = this->ra_minAngle(lsx::astronomy::GetZenith(), this->start) + this->ra_minAngle(lsx::astronomy::GetZenith(), this->end);
dec_angle = this->end.DEC_angle - this->start.DEC_angle;
ra_direction = RA_DIR_FORWARD;
if (dec_angle > 0) {
dec_direction = DEC_DIR_UP_WHEN_LEFT;
}
else {
dec_direction = DEC_DIR_DOWN_WHEN_LEFT;
}
}
else {
DEC_side = DEC_IS_ON_THE_LEFT;
ra_angle = 180.0 - this->ra_minAngle(lsx::astronomy::GetZenith(), this->end) - this->ra_minAngle(lsx::astronomy::GetZenith(), this->start);
dec_angle = 180.0 - this->end.DEC_angle - this->start.DEC_angle;
dec_direction = DEC_DIR_UP_WHEN_RIGHT;
if (ra_angle > 0) {
ra_direction = RA_DIR_BACKWARD;
}
else {
ra_direction = RA_DIR_FORWARD;
}
}
}
else if (!this->passZenith(this->start) && !this->passZenith(this->end)) {//右右
//std::cout << "RR" << std::endl;
if (DEC_side == DEC_IS_ON_THE_LEFT) {
DEC_side = DEC_IS_ON_THE_RIGHT;
ra_angle = 180.0 - this->ra_minAngle(lsx::astronomy::GetZenith(), this->end) + this->ra_minAngle(lsx::astronomy::GetZenith(), this->start);
dec_angle = 180.0 - this->end.DEC_angle - this->start.DEC_angle;
ra_direction = RA_DIR_FORWARD;
dec_direction = DEC_DIR_UP_WHEN_LEFT;
}
else {
ra_angle = this->ra_minAngle(lsx::astronomy::GetZenith(), this->end) - this->ra_minAngle(lsx::astronomy::GetZenith(), this->start);
dec_angle = this->end.DEC_angle - this->start.DEC_angle;
if (ra_angle > 0) {
ra_direction = RA_DIR_BACKWARD;
}
else {
ra_direction = RA_DIR_FORWARD;
}
if (dec_angle > 0) {
dec_direction = DEC_DIR_UP_WHEN_RIGHT;
}
else {
dec_direction = DEC_DIR_DOWN_WHEN_RIGHT;
}
}
}
/*----------------------------------------------------角度修正与信号发出---------------------------------------------------------*/
if (fabs(dec_angle) > 254.0) {//角度超过串口发送极限
dec_angle_part = fabs(dec_angle) - 254.0;
dec_angle = 254.0;
lsx::control::dec_goto_motion(dec_direction, dec_angle_part);
Sleep(lsx::control::EquatorialRunTime_ms(dec_angle_part, DEC_STEPMOTOR, RA_WAIT_MODE_NORMAL) + 500);
}
lsx::control::dec_goto_motion(dec_direction, dec_angle);
dec_runtime_ms = lsx::control::EquatorialRunTime_ms(dec_angle, DEC_STEPMOTOR, RA_WAIT_MODE_NORMAL);
Sleep(2);
if (!back_origin_position) {//考虑赤道仪的速度和地球速度,补偿赤道仪运行角度
ra_angle = lsx::control::get_ra_goto_correct_angle(ra_angle, ra_direction);
}
lsx::control::ra_goto_motion(ra_direction, ra_angle);
ra_runtime_ms = lsx::control::EquatorialRunTime_ms(ra_angle, RA_STEPMOTOR, RA_WAIT_MODE_NORMAL);
/*---------------------------------------------------图像显示------------------------------------------------------*/
this->targetTable.get_image_x_y(this->start.RA_angle, this->start.DEC_angle, &this->start.position_in_image_x, &this->start.position_in_image_y);
this->targetTable.get_image_x_y(this->end.RA_angle, this->end.DEC_angle, &this->end.position_in_image_x, &this->end.position_in_image_y);
start_time = std::clock();
this->ra_arrival = false; this->dec_arrival = false;
while (!arrive_the_target) {
star_image = this->targetTable.getTargetTableImage();
end_time = std::clock();
now_run_time = double(end_time) - double(start_time);
if (now_run_time > lsx::math::Max(ra_runtime_ms, dec_runtime_ms)) {
cv::circle(star_image, cv::Point(this->end.position_in_image_x, this->end.position_in_image_y), double(heigth) / 50.0, optional_target_color, 2, cv::LINE_AA);
lsx::starProcessing::DrawRegularTriangle(star_image, now_position.x, now_position.y, my_equatorial_instrument_color, double(heigth) / 100.0);
cv::circle(star_image, now_position, double(heigth) / 80.0, my_equatorial_instrument_color, 1, cv::LINE_AA);
cv::putText(star_image, "EQ arrival!", cv::Point(0 + double(heigth) / 200.0, 0 + double(heigth) / 50.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
cv::imshow(win_name, star_image);
cv::waitKey(700);
arrive_the_target = true;
break;
}
if (now_run_time < ra_runtime_ms && now_run_time < dec_runtime_ms) {
sprintf_s(show_my_equ, "my EQ(RA:%d ms, DEC:%d ms)", int(ra_runtime_ms - now_run_time), int(dec_runtime_ms - now_run_time));
}
else if (now_run_time >= ra_runtime_ms && now_run_time < dec_runtime_ms) {
sprintf_s(show_my_equ, "my EQ(RA arrive, DEC:%d ms)", int(dec_runtime_ms - now_run_time));
}
else if (now_run_time < ra_runtime_ms && now_run_time >= dec_runtime_ms) {
sprintf_s(show_my_equ, "my EQ(RA:%d ms, DEC arrive)", int(ra_runtime_ms - now_run_time));
}
else {
sprintf_s(show_my_equ, "my EQ(RA arrive, DEC arrive)");
}
this->get_image_position(this->start.position_in_image_x, this->start.position_in_image_y, \
this->end.position_in_image_x, this->end.position_in_image_y, ra_runtime_ms, dec_runtime_ms, start_time, end_time, &now_position);
cv::circle(star_image, cv::Point(this->end.position_in_image_x, this->end.position_in_image_y), double(heigth) / 50.0, optional_target_color, 2, cv::LINE_AA);
if (!back_origin_position) {
cv::putText(star_image, "EQ on the move...", cv::Point(0 + double(heigth) / 200.0, 0 + double(heigth) / 50.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
}
else {
cv::putText(star_image, "EQ on the move(return to '0' position)...", cv::Point(0 + double(heigth) / 200.0, 0 + double(heigth) / 50.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
}
lsx::starProcessing::DrawRegularTriangle(star_image, now_position.x, now_position.y, my_equatorial_instrument_color, double(heigth) / 100.0);
cv::circle(star_image, now_position, double(heigth) / 80.0, my_equatorial_instrument_color, 1, cv::LINE_AA);
//cv::line(star_image, cv::Point(now_position.x + double(heigth) / 80.0, now_position.y), cv::Point(star_image.cols, now_position.y), my_equatorial_instrument_color, 1, cv::LINE_AA);//右侧线
//cv::line(star_image, cv::Point(now_position.x - double(heigth) / 80.0, now_position.y), cv::Point(0, now_position.y), my_equatorial_instrument_color, 1, cv::LINE_AA);//左侧线
//cv::line(star_image, cv::Point(now_position.x, now_position.y - double(heigth) / 80.0), cv::Point(now_position.x, 0), my_equatorial_instrument_color, 1, cv::LINE_AA);//上侧线
//cv::line(star_image, cv::Point(now_position.x, now_position.y + double(heigth) / 80.0), cv::Point(now_position.x, star_image.rows), my_equatorial_instrument_color, 1, cv::LINE_AA);//下侧线
cv::line(star_image, cv::Point(now_position.x + double(heigth) / 80.0, now_position.y), cv::Point(now_position.x + 6.0 * double(heigth) / 80.0, now_position.y), my_equatorial_instrument_line_color, 1, cv::LINE_AA);//右侧线
cv::line(star_image, cv::Point(now_position.x - double(heigth) / 80.0, now_position.y), cv::Point(now_position.x - 6.0 * double(heigth) / 80.0, now_position.y), my_equatorial_instrument_line_color, 1, cv::LINE_AA);//左侧线
cv::line(star_image, cv::Point(now_position.x, now_position.y - double(heigth) / 80.0), cv::Point(now_position.x, now_position.y - 6.0 * double(heigth) / 80.0), my_equatorial_instrument_line_color, 1, cv::LINE_AA);//上侧线
cv::line(star_image, cv::Point(now_position.x, now_position.y + double(heigth) / 80.0), cv::Point(now_position.x, now_position.y + 6.0 * double(heigth) / 80.0), my_equatorial_instrument_line_color, 1, cv::LINE_AA);//下侧线
cv::putText(star_image, show_my_equ, cv::Point(now_position.x + double(heigth) / 60.0, now_position.y - double(heigth) / 60.0), \
cv::FONT_HERSHEY_SIMPLEX, 0.4, my_equatorial_instrument_color, 1, cv::LINE_AA);
cv::imshow(win_name, star_image);
cv::waitKey(20);
}
cv::destroyAllWindows();
system("cls");
if (this->end.isStar && !this->zero2star) {
std::cout << std::endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
std::cout << "请将 <" << this->pointTarget.name << "> 放置于视场中心。" << std::endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
std::cout << std::endl;
lsx::control::kbControl(CONTROL_RA_DEC);
}
if (this->zero2star) {
this->zero2star = false;
std::cout << std::endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
std::cout << "为了校准零位,请将 <" << this->pointTarget.name << "> 放置于视场中心。" << std::endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
std::cout << std::endl;
lsx::control::kbControl(CONTROL_RA_DEC);
}
}
else {
cv::destroyAllWindows();
system("cls");
}
}
void lsx::autoSearch::AutoStarFindController::preSet(std::string targetName, std::string targetNumber, int decSide) {
this_target_name = targetName;
this_target_number = targetNumber;
DEC_side = decSide;
noTarget = false;
}
void lsx::autoSearch::AutoStarFindController::AutomaticStarFinding() {
this->gotoControl();
}
EquatorialControl.h
#ifndef EQUATORIAL_CONTROL_H
#define EQUATORIAL_CONTROL_H
#include<iostream>
#include<Eigen/Dense>
#include<Windows.h>
#include"windows.h"
#include"atlstr.h"
#include<string.h>
#include<TCHAR.H>
#include<conio.h>
#include<stdarg.h>
#include<vector>
#include"SerialCommunication.h"
#include"Astronomy.h"
namespace lsx {
namespace control {
#define GUIDE_ADJUST_FORWARD 11//导星过程中向正方向调整一定的角度,对RA:RA减少(天体运动)的方向;对DEC:顺时针旋转
#define GUIDE_ADJUST_BACKWARD 12//导星过程中向反方向调整一定的角度,对RA:RA增加的方向;对DEC:逆时针旋转
#define GUIDE_RA_STOP 17//导星过程中RA转轴停止
#define GUIDE_RA_ADJUST_STOP 18//导星过程中RA转轴停止,等待地球自转一定角度
#define GUIDE_RA_CONTINUE 19//导星过程中RA恢复到盲跟状态
#define GOTO_ADJUST_FORWARD 21//自动寻星过程中向正方向调整一定的角度,对RA:RA减少(天体运动)的方向;对DEC:顺时针旋转
#define GOTO_ADJUST_BACKWARD 22//自动寻星过程中向反方向调整一定的角度,对RA:RA增加的方向;对DEC:逆时针旋转
#define AUTO_ADJUST_FORWARD 31//极轴调整过程中向正方向调整一定的角度,对抬升电机:上升;对方位角电机:顺时针转动
#define AUTO_ADJUST_BACKWARD 32//极轴调整过程中向反方向调整一定的角度,对抬升电机:下降;对方位角电机:逆时针转动
#define RA_STEPMOTOR 1//赤经轴电机
#define DEC_STEPMOTOR 2//赤纬轴电机
#define AZIMUTH_STEPMOTOR 3//极轴方位角电机
#define ELEVATION_STEPMOTOR 4//极轴高度角电机
#define CONTROL_RA_DEC 1//键盘控制选择控制RA,DEC电机
#define CONTROL_ROUND_UP 2//键盘控制选择控制ROUND,UP电机
#define RA_DIR_FORWARD 1//RA减少(天体运动)的方向
#define RA_DIR_BACKWARD 2//RA增加的方向
#define DEC_DIR_FORWARD 1//DEC顺时针旋转
#define DEC_DIR_BACKWARD 2//DEC逆时针选择
#define DEC_DIR_UP_WHEN_RIGHT DEC_DIR_BACKWARD //DEC在右半盘时的DEC上升的方向
#define DEC_DIR_DOWN_WHEN_RIGHT DEC_DIR_FORWARD //DEC在右半盘时的DEC下降的方向
#define DEC_DIR_UP_WHEN_LEFT DEC_DIR_FORWARD //DEC在左半盘时的DEC上升的方向
#define DEC_DIR_DOWN_WHEN_LEFT DEC_DIR_BACKWARD //DEC在左半盘时的DEC下降的方向
#define RA_WAIT_MODE_NORMAL 0
#define RA_WAIT_MODE_WAIT_EARTH 1
/**
* @brief 赤道仪参数类
*/
class EquatorialParam {
public:
double time_clk = 84.0 * 1000000;
double ARR = 19.0;
double speed_up_1_psc_min = 38.0;
double speed_up_2_psc_min = 122.0;
double speed_up_3_psc = 500.0;
double RA_reduceRatio = 0;//RA减速比
double DEC_reduceRatio = 0;//DEC减速比
double RA_stepAngle = 0;//RA脉冲对应角距离
double DEC_stepAngle = 0;//DEC脉冲对应角距离
double RA_max_pwm_frequency = 0;//RA曲线加速1最大PWM频率
double DEC_max_pwm_frequency = 0;//DEC曲线加速1最大PWM频率
double RA_max_pwm_frequency_small = 0;//RA曲线加速2最大PWM频率
double DEC_max_pwm_frequency_small = 0;//DEC曲线加速2最大PWM频率
double RA_pwm_frequency_continue = 0;//RA匀速PWM频率
double DEC_pwm_frequency_continue = 0;//DEC匀速PWM频率
double RA_speedUpAngle = 0;//RA轴加速角度1
double DEC_speedUpAngle = 0;//DEC轴加速角度1
double RA_speedUpAngle_small = 0;//RA加速角度2
double DEC_speedUpAngle_small = 0;//DEC加速角度2
double RA_speedUp_1_time = 0;//RA加速时间1
double RA_speedUp_2_time = 0;//RA加速时间2
double DEC_speedUp_1_time = 0;//DEC加速时间1
double DEC_speedUp_2_time = 0;//DEC加速时间2
double v_RA_max = 0;//RA最大速度,单位:°/s
double v_DEC_max = 0;//DEC最大速度,单位:°/s
double v_RA_max_small = 0;//RA最大速度,单位:°/s
double v_DEC_max_small = 0;//DEC最大速度,单位:°/s
double v_RA_continue = 0;//RA匀速运动速度
double v_DEC_continue = 0;//DEC匀速运动速度
EquatorialParam();
};
/**
* @brief 控制赤道仪运行主要函数
* @param moveMode 运行模式选择
* @param moveAngle 运行角度,单位:°
* @param motorChoose 电机选择位
* @return void
*/
void EquatorialMovement(int moveMode, double moveAngle, char motorChoose);
/**
* @brief 键盘控制赤道仪
* @param modeChoose 模式选择,可选:CONTROL_RA_DEC,控制RA和DEC轴;CONTROL_ROUND_UP,控制纬度座
* @return 行向量[RA增加角度,DEC逆时针角度]
*/
Eigen::MatrixXd kbControl(int modeChoose = CONTROL_RA_DEC);
/**
* @brief 计算赤道仪运行时间
* @param inputAngle 转轴输出端运行的角度
* @param motorChoose 电机选择
* @param ra_wait_mode RA的等待模式,可选:RA_WAIT_MODE_NORMAL,RA转轴基本等待时间(自动寻星和导星基向量求解时使用);
* RA_WAIT_MODE_WAIT_EARTH,RA转轴停止等待地球自转(导星修正时使用)
* @return 赤道仪的运行时间,单位:ms
*/
int EquatorialRunTime_ms(double inputAngle, char motorChoose, char ra_wait_mode = RA_WAIT_MODE_NORMAL);
/**
* @brief RA转轴导星控制
* @param direction 运行方向,可选:RA_DIR_FORWARD,RA向天体运行的方向移动;RA_DIR_BACKWARD,RA向天体运行的反方向运动
* @param angle_degree 旋转角度,单位:°
* @param calc_vector 是否是导星基向量求解标志位,可选:true,此时RA转轴正反转正常移动;false,此时RA转轴反转等待地球自转(导星修正)
* @return void
*/
void ra_guide_motion(int direction, double angle_degree, bool calc_vector);
/**
* @brief RA转轴自动寻星控制
* @param direction 运行方向,可选:RA_DIR_FORWARD,RA向天体运行的方向移动;RA_DIR_BACKWARD,RA向天体运行的反方向运动
* @param angle_degree 旋转角度,单位:°
* @return void
*/
void ra_goto_motion(int direction, double angle_degree);
/**
* @brief DEC转轴导星控制
* @param direction 运行方向,可选:DEC_DIR_FORWARD,DEC顺时针转动;DEC_DIR_BACKWARD,DEC逆时针转动
* @param angle_degree 旋转角度,单位:°
* @return void
*/
void dec_guide_motion(int direction, double angle_degree);
/**
* @brief DEC转轴自动寻星控制
* @param direction 运行方向,可选:DEC_DIR_FORWARD,DEC顺时针转动;DEC_DIR_BACKWARD,DEC逆时针转动
* @param angle_degree 旋转角度,单位:°
* @return void
*/
void dec_goto_motion(int direction, double angle_degree);
/**
* @brief RA运动角度修正,考虑RA转轴与天球的相遇、追击问题
* @param input_angle 输入初始运行的角度
* @param direction 输入的运行方向
* @param speed_up_mode RA转轴曲线加速模式(与控制单片机结合)
* @param re_calc 如果初次求解后模式有跳变,则递归调用的标志位
* @return RA转轴运行角度
*/
double ra_goto_angle_correct(double input_angle, int direction, int speed_up_mode = 0, bool re_calc = false);
/**
* @brief (调试用)RA运动角度修正,考虑RA转轴与天球的相遇、追击问题
* @param input_angle 输入初始运行的角度
* @param direction 输入的运行方向
* @param output_speed_up_mode 修正后的赤道仪加速模式
* @return RA转轴运行角度
*/
double get_ra_goto_correct_angle(double input_angle, int direction, int* output_speed_up_mode);
/**
* @brief RA运动角度修正,考虑RA转轴与天球的相遇、追击问题
* @param input_angle 输入初始运行的角度
* @param direction 输入的运行方向
* @param output_speed_up_mode 修正后的赤道仪加速模式
* @return RA转轴运行角度
*/
double get_ra_goto_correct_angle(double input_angle, int direction);
/**
* @brief 通过鼠标点击图片控制赤道仪
* @param width 图形界面的宽度
* @param height 图形界面的高度
* @return 行向量[RA增加角度,DEC逆时针角度]
*/
Eigen::MatrixXd MouseControl(int width = 1920, int height = 1080);
}
}
#endif
EquatorialControl.cpp
#include"EquatorialControl.h"
extern CString PORTNAME;
double equ_control_mouse_touch_x = -1, equ_control_mouse_touch_y = -1, equ_control_mouse_botton_x = -1, equ_control_mouse_botton_y = -1;
int mouse_wheel_number = 0;
bool equ_control_deal_mouse_botton = true, equ_control_mouse_get_coodinate = false, equ_control_quit = false;
bool equ_control_angle_change_enable = false, equ_control_equ_ra_is_running = false, equ_control_equ_dec_is_running = false;
bool angle_reset_enable = false;
double cell_angle = 0, adjust_angle = 0;
extern int RA_reduction_ratio;
extern int DEC_reduction_ratio;
lsx::serial::serial_writer serialWriter;
bool serial_have_open = false;
lsx::control::EquatorialParam::EquatorialParam() {
this->time_clk = 84.0 * 1000000.0;//时钟
this->ARR = 19.0;
this->speed_up_1_psc_min = 38.0;
this->speed_up_2_psc_min = 122.0;
this->speed_up_3_psc = 500.0;
this->RA_reduceRatio = double(RA_reduction_ratio);//RA减速比
this->DEC_reduceRatio = double(DEC_reduction_ratio);//DEC减速比
this->RA_stepAngle = 1.8 / 256.0;//RA脉冲对应角距离
this->DEC_stepAngle = 1.8 / 256.0;//DEC脉冲对应角距离
this->RA_max_pwm_frequency = this->time_clk / ((this->ARR + 1.0) * (this->speed_up_1_psc_min + 1.0));//RA最大PWM频率
this->DEC_max_pwm_frequency = this->time_clk / ((this->ARR + 1.0) * (this->speed_up_1_psc_min + 1.0));//DEC最大PWM频率
this->RA_max_pwm_frequency_small = this->time_clk / ((this->ARR + 1.0) * (this->speed_up_2_psc_min + 1.0));//RA曲线加速2最大PWM频率
this->DEC_max_pwm_frequency_small = this->time_clk / ((this->ARR + 1.0) * (this->speed_up_2_psc_min + 1.0));//DEC曲线加速2最大PWM频率
this->RA_pwm_frequency_continue = this->time_clk / ((this->ARR + 1.0) * (this->speed_up_3_psc + 1.0));
this->DEC_pwm_frequency_continue = this->time_clk / ((this->ARR + 1.0) * (this->speed_up_3_psc + 1.0));
this->RA_speedUpAngle = 720.0 / 300.0;//RA轴加速角度
this->DEC_speedUpAngle = 720.0 / 100.0;//DEC轴加速角度
this->RA_speedUpAngle_small = 144.0 / 300.0;//RA的加速角度
this->DEC_speedUpAngle_small = 144.0 / 100.0;//DEC的加速角度
this->RA_speedUp_1_time = 2.100761904761906;
this->RA_speedUp_2_time = 1.280761904761905;
this->DEC_speedUp_1_time = 2.100761904761906;
this->DEC_speedUp_2_time = 1.280761904761905;
this->v_RA_max = RA_max_pwm_frequency * RA_stepAngle / RA_reduceRatio;
this->v_DEC_max = DEC_max_pwm_frequency * DEC_stepAngle / DEC_reduceRatio;
this->v_RA_max_small = RA_max_pwm_frequency_small * RA_stepAngle / RA_reduceRatio;
this->v_DEC_max_small = DEC_max_pwm_frequency_small * DEC_stepAngle / DEC_reduceRatio;
this->v_RA_continue = RA_pwm_frequency_continue * RA_stepAngle / RA_reduceRatio;
this->v_DEC_continue = DEC_pwm_frequency_continue * DEC_stepAngle / DEC_reduceRatio;
}
void lsx::control::EquatorialMovement(int moveMode, double moveAngle, char motorChoose) {
double degrees, mins, seconds, arcSeconds;
char dataHead = 'x', dataTail = 'y', mcuMode, mcuMoveMode;
std::vector<char> sendArray;
moveAngle = fabs(moveAngle);
if (moveAngle > 9.0 / (3600.0 * 60.0) && moveAngle < 255.0 &&
(motorChoose == 1 || motorChoose == 2 || motorChoose == 3 || motorChoose == 4)) {//角度范围限制
degrees = floor(moveAngle);
moveAngle = (moveAngle - degrees) * 60.0;
mins = floor(moveAngle);
moveAngle = (moveAngle - mins) * 60.0;
seconds = floor(moveAngle);
moveAngle = (moveAngle - seconds) * 60.0;
arcSeconds = floor(moveAngle);
mcuMode = moveMode / 10; mcuMoveMode = moveMode % 10;
sendArray.resize(8);
if (mcuMoveMode == 1 || mcuMoveMode == 2 || mcuMoveMode == 8) {
sendArray[0] = dataHead;
sendArray[1] = motorChoose;
sendArray[2] = char(moveMode);
sendArray[3] = char(degrees);
sendArray[4] = char(mins);
sendArray[5] = char(seconds);
sendArray[6] = char(arcSeconds);
sendArray[7] = dataTail;
}
else {
sendArray[0] = dataHead;
sendArray[1] = motorChoose;
sendArray[2] = char(moveMode);
sendArray[3] = 0;
sendArray[4] = 0;
sendArray[5] = 0;
sendArray[6] = 0;
sendArray[7] = dataTail;
}
if (!serial_have_open) {
serialWriter.set_serial(PORTNAME);
serial_have_open = true;
}
serialWriter.send_data(sendArray);
serialWriter.Serial_close();
}
}
Eigen::MatrixXd lsx::control::kbControl(int modeChoose) {
Eigen::MatrixXd outputMatrix(1, 2);
int keyNumber = 0, state = 0; double raAdjustAngle = 0, decAdjustAngle = 0;
double adjustAngle = 0.1; bool showAngle = false, showControlMode = false;
int signalFlag = 0;
outputMatrix *= 0;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);
std::cout << "可通过键盘控制赤道仪。RA( ↓ 向西、↑ 向东);DEC( ← 逆时针、 → 顺时针)" << std::endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
while (true){
Sleep(40);
if (_kbhit()) {
keyNumber = _getch();
}
if (keyNumber == 27) {
break;
}
else {
switch (keyNumber){
/*angle set*/
case 49:adjustAngle = 0.1; keyNumber = 0; showAngle = true; break;
case 50:adjustAngle = 0.2; keyNumber = 0; showAngle = true; break;
case 51:adjustAngle = 0.3; keyNumber = 0; showAngle = true; break;
case 52:adjustAngle = 0.4; keyNumber = 0; showAngle = true; break;
case 53:adjustAngle = 0.5; keyNumber = 0; showAngle = true; break;
case 54:adjustAngle = 0.6; keyNumber = 0; showAngle = true; break;
case 55:adjustAngle = 0.7; keyNumber = 0; showAngle = true; break;
case 56:adjustAngle = 0.8; keyNumber = 0; showAngle = true; break;
case 57:adjustAngle = 0.9; keyNumber = 0; showAngle = true; break;
case 97:adjustAngle = 0.1; keyNumber = 0; showAngle = true; break;
case 98:adjustAngle = 0.2; keyNumber = 0; showAngle = true; break;
case 99:adjustAngle = 0.3; keyNumber = 0; showAngle = true; break;
case 100:adjustAngle = 0.4; keyNumber = 0; showAngle = true; break;
case 101:adjustAngle = 0.5; keyNumber = 0; showAngle = true; break;
case 102:adjustAngle = 0.6; keyNumber = 0; showAngle = true; break;
case 103:adjustAngle = 0.7; keyNumber = 0; showAngle = true; break;
case 104:adjustAngle = 0.8; keyNumber = 0; showAngle = true; break;
case 105:adjustAngle = 0.9; keyNumber = 0; showAngle = true; break;
case 224:state = 1; keyNumber = 0; break;
/*signal send*/
case 72: {//方向键上,RA,UP
if (state == 1) {
state = 0;
keyNumber = 0;
showControlMode = true;
signalFlag = 1;
}
break;
}
case 80: {//方向键下,RA,UP
if (state == 1) {
state = 0;
keyNumber = 0;
showControlMode = true;
signalFlag = 2;
}
break;
}
case 75: {//方向键左,DEC,ROUND
if (state == 1) {
state = 0;
keyNumber = 0;
showControlMode = true;
signalFlag = 3;
}
break;
}
case 77: {//方向键右,DEC,ROUND
if (state == 1) {
state = 0;
keyNumber = 0;
showControlMode = true;
signalFlag = 4;
}
break;
}
case 32: {//空格
state = 0;
keyNumber = 0;
showAngle = true;
std::cout << "输入自定义角度: ";
std::cin >> adjustAngle;
while (std::cin.fail()){
std::cout << "error angle !" << std::endl;
std::cin >> adjustAngle;
std::cin.clear();
std::cin.ignore();
}
break;
}
}
}
if (showAngle) {
std::cout << "set adjust angle = " << adjustAngle << " °";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);
std::cout << " RA( ↓ 向西、↑ 向东);DEC( ← 逆时针、 → 顺时针)" << std::endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
showAngle = false;
}
if (showControlMode) {
adjustAngle = fabs(adjustAngle);
if (adjustAngle > 0) {
showControlMode = false;
if (modeChoose == CONTROL_RA_DEC) {
switch (signalFlag) {
case 1:lsx::control::EquatorialMovement(GOTO_ADJUST_BACKWARD, adjustAngle, RA_STEPMOTOR); outputMatrix(0, 0) += adjustAngle; std::cout << "RA<向东> " << adjustAngle << " °" << std::endl; break;
case 2:lsx::control::EquatorialMovement(GOTO_ADJUST_FORWARD, adjustAngle, RA_STEPMOTOR); outputMatrix(0, 0) -= adjustAngle; std::cout << "RA<向西> " << adjustAngle << " °" << std::endl; break;
case 3:lsx::control::EquatorialMovement(GOTO_ADJUST_BACKWARD, adjustAngle, DEC_STEPMOTOR); outputMatrix(0, 1) += adjustAngle; std::cout << "DEC<逆时针> " << adjustAngle << " °" << std::endl; break;
case 4:lsx::control::EquatorialMovement(GOTO_ADJUST_FORWARD, adjustAngle, DEC_STEPMOTOR); outputMatrix(0, 1) -= adjustAngle; std::cout << "DEC<顺时针> " << adjustAngle << " °" << std::endl; break;
}
}
else if (modeChoose == CONTROL_ROUND_UP) {
switch (signalFlag) {
case 1:lsx::control::EquatorialMovement(AUTO_ADJUST_FORWARD, adjustAngle, ELEVATION_STEPMOTOR); std::cout << "极轴仰角<上升> " << adjustAngle << " °" << std::endl; break;
case 2:lsx::control::EquatorialMovement(AUTO_ADJUST_BACKWARD, adjustAngle, ELEVATION_STEPMOTOR); std::cout << "极轴仰角<下降> " << adjustAngle << " °" << std::endl; break;
case 3:lsx::control::EquatorialMovement(AUTO_ADJUST_FORWARD, adjustAngle, AZIMUTH_STEPMOTOR); std::cout << "极轴<顺时针> " << adjustAngle << " °" << std::endl; break;
case 4:lsx::control::EquatorialMovement(AUTO_ADJUST_BACKWARD, adjustAngle, AZIMUTH_STEPMOTOR); std::cout << "极轴<逆时针> " << adjustAngle << " °" << std::endl; break;
}
}
}
}
}
system("cls");
return outputMatrix;
}
int lsx::control::EquatorialRunTime_ms(double inputAngle, char motorChoose, char ra_wait_mode) {
double outputTime = 0;
double time_speedUp = 0, time_maxSpeed = 0;
double angleRemain = 0;
lsx::control::EquatorialParam eParam;
inputAngle = fabs(inputAngle);
if (inputAngle > 0) {
switch (motorChoose) {
case RA_STEPMOTOR: {
if (ra_wait_mode == RA_WAIT_MODE_NORMAL) {
if (inputAngle > 2.0 * eParam.RA_speedUpAngle) {
angleRemain = inputAngle - 2.0 * eParam.RA_speedUpAngle;
time_speedUp = 2.0 * eParam.RA_speedUp_1_time;
time_maxSpeed = angleRemain / eParam.v_RA_max;
outputTime = time_speedUp + time_maxSpeed;
}
else if (inputAngle > 2.0 * eParam.RA_speedUpAngle_small) {
angleRemain = inputAngle - 2.0 * eParam.RA_speedUpAngle_small;
time_speedUp = 2.0 * eParam.RA_speedUp_2_time;
time_maxSpeed = angleRemain / eParam.v_RA_max_small;
outputTime = time_speedUp + time_maxSpeed;
}
else {
outputTime = inputAngle / eParam.v_RA_continue;
}
}
else if (ra_wait_mode == RA_WAIT_MODE_WAIT_EARTH) {
outputTime = lsx::astronomy::earthRotateTime(inputAngle) / 1000.0;
}
break;
}
case DEC_STEPMOTOR: {
if (inputAngle > 2.0 * eParam.DEC_speedUpAngle) {
angleRemain = inputAngle - 2.0 * eParam.DEC_speedUpAngle;
time_speedUp = 2.0 * eParam.DEC_speedUp_1_time;
time_maxSpeed = angleRemain / eParam.v_DEC_max;
outputTime = time_speedUp + time_maxSpeed;
}
else if (inputAngle > 2.0 * eParam.DEC_speedUpAngle_small) {
angleRemain = inputAngle - 2.0 * eParam.DEC_speedUpAngle_small;
time_speedUp = 2.0 * eParam.DEC_speedUp_2_time;
time_maxSpeed = angleRemain / eParam.v_DEC_max_small;
outputTime = time_speedUp + time_maxSpeed;
}
else {
outputTime = inputAngle / eParam.v_DEC_continue;
}
break;
}
}
}
outputTime *= 1000.0;
return int(outputTime);
}
void lsx::control::ra_guide_motion(int direction, double angle_degree, bool calc_vector) {
if (!calc_vector) {
if (direction == RA_DIR_FORWARD) {//ra向天体运动的方向运动
lsx::control::EquatorialMovement(GUIDE_ADJUST_FORWARD, angle_degree, RA_STEPMOTOR);
}
else if (direction == RA_DIR_BACKWARD) {//向反方向运动需要停
lsx::control::EquatorialMovement(GUIDE_RA_ADJUST_STOP, angle_degree, RA_STEPMOTOR);
}
}
else {
if (direction == RA_DIR_FORWARD) {//ra向天体运动的方向运动
lsx::control::EquatorialMovement(GUIDE_ADJUST_FORWARD, angle_degree, RA_STEPMOTOR);
}
else if (direction == RA_DIR_BACKWARD) {//在求解向量时直接向反方向运动
lsx::control::EquatorialMovement(GUIDE_ADJUST_BACKWARD, angle_degree, RA_STEPMOTOR);
}
}
}
void lsx::control::ra_goto_motion(int direction, double angle_degree) {
if (direction == RA_DIR_FORWARD) {
lsx::control::EquatorialMovement(GOTO_ADJUST_FORWARD, angle_degree, RA_STEPMOTOR);
}
else if (direction == RA_DIR_BACKWARD) {
lsx::control::EquatorialMovement(GOTO_ADJUST_BACKWARD, angle_degree, RA_STEPMOTOR);
}
}
void lsx::control::dec_guide_motion(int direction, double angle_degree) {
if (direction == DEC_DIR_FORWARD) {
lsx::control::EquatorialMovement(GUIDE_ADJUST_FORWARD, angle_degree, DEC_STEPMOTOR);
}
else if (direction == DEC_DIR_BACKWARD) {
lsx::control::EquatorialMovement(GUIDE_ADJUST_BACKWARD, angle_degree, DEC_STEPMOTOR);
}
}
void lsx::control::dec_goto_motion(int direction, double angle_degree) {
if (direction == DEC_DIR_FORWARD) {
lsx::control::EquatorialMovement(GOTO_ADJUST_FORWARD, angle_degree, DEC_STEPMOTOR);
}
else if (direction == DEC_DIR_BACKWARD) {
lsx::control::EquatorialMovement(GOTO_ADJUST_BACKWARD, angle_degree, DEC_STEPMOTOR);
}
}
/**
* @brief 赤道仪与天体运行方向相反则该函数为-1,与天体方向相同则该函数为1
*/
double dierection201(int direction) {
if (direction == RA_DIR_BACKWARD) {//向东
return -1.0;
}
else if (direction == RA_DIR_FORWARD) {//向西
return 1.0;
}
}
/**
* @brief 计算RA转轴曲线加速时的加速模式
*/
int get_ra_speed_up_mode(double input_angle) {
lsx::control::EquatorialParam eParam;
if (input_angle > eParam.RA_speedUpAngle * 2.0) {
return 1;
}
else if (input_angle > eParam.RA_speedUpAngle_small * 2.0) {
return 2;
}
else {
return 3;
}
}
double lsx::control::ra_goto_angle_correct(double input_angle, int direction, int speed_up_mode, bool re_calc) {
lsx::control::EquatorialParam eParam;
double correct_angle = 0;//预处理角度
double V_earth = 360.0 / 86164.0;//地球转速(恒星时),°/s
double V_equ = 0;
double angle_spu = 0, time_spu = 0;
int now_speed_up_mode = 0;
input_angle = fabs(input_angle);
if (input_angle > eParam.RA_speedUpAngle * 2.0 || (re_calc && speed_up_mode == 1)) {
now_speed_up_mode = 1;
angle_spu = eParam.RA_speedUpAngle;
time_spu = eParam.RA_speedUp_1_time;
V_equ = eParam.v_RA_max;
correct_angle = 2.0 * angle_spu + V_equ * ((input_angle - 2.0 * angle_spu + dierection201(direction) * 2.0 * V_earth * time_spu) / (-dierection201(direction) * V_earth + V_equ));
}
else if (input_angle > eParam.RA_speedUpAngle_small * 2.0 || (re_calc && speed_up_mode == 2)) {
now_speed_up_mode = 2;
angle_spu = eParam.RA_speedUpAngle_small;
time_spu = eParam.RA_speedUp_2_time;
V_equ = eParam.v_RA_max_small;
correct_angle = 2.0 * angle_spu + V_equ * ((input_angle - 2.0 * angle_spu + dierection201(direction) * 2.0 * V_earth * time_spu) / (-dierection201(direction) * V_earth + V_equ));
}
else if(input_angle > 0 || (re_calc && speed_up_mode == 3)){
now_speed_up_mode = 3;
angle_spu = 0;
time_spu = 0;
V_equ = eParam.v_RA_continue;
correct_angle = 2.0 * angle_spu + V_equ * ((input_angle - 2.0 * angle_spu + dierection201(direction) * 2.0 * V_earth * time_spu) / (-dierection201(direction) * V_earth + V_equ));
}
if (now_speed_up_mode == get_ra_speed_up_mode(correct_angle)) {
return correct_angle;
}
else {
lsx::control::ra_goto_angle_correct(input_angle, direction, get_ra_speed_up_mode(correct_angle), true);
}
}
double lsx::control::get_ra_goto_correct_angle(double input_angle, int direction, int* output_speed_up_mode) {
lsx::control::EquatorialParam eParam;
double correct_angle = 0;//预处理角度
double V_earth = 360.0 / 86164.0;//地球转速(恒星时),°/s
double angle_spu[3] = { eParam.RA_speedUpAngle, eParam.RA_speedUpAngle_small, 0.0 },//加速角度
time_spu[3] = { eParam.RA_speedUp_1_time, eParam.RA_speedUp_2_time, 0.0 },//加速时间
V_equ[3] = { eParam.v_RA_max, eParam.v_RA_max_small, eParam.v_RA_continue };//最大速度
int speed_up_mode[3] = { 1, 2, 3 },//加速模式
i = 0;
input_angle = fabs(input_angle);
for (i = 0; i < 3; i++) {
correct_angle = 2.0 * angle_spu[i] + V_equ[i] * ((input_angle - 2.0 * angle_spu[i] + dierection201(direction) * 2.0 * V_earth * time_spu[i]) / (-dierection201(direction) * V_earth + V_equ[i]));
if (get_ra_speed_up_mode(correct_angle) == speed_up_mode[i]) {//判断加速模式是否匹配
(*output_speed_up_mode) = speed_up_mode[i];
return correct_angle;
}
}
*output_speed_up_mode = 0;
return input_angle;
}
double lsx::control::get_ra_goto_correct_angle(double input_angle, int direction) {
lsx::control::EquatorialParam eParam;
double correct_angle = 0;//预处理角度
double V_earth = 360.0 / 86164.0;//地球转速(恒星时),°/s
double angle_spu[3] = { eParam.RA_speedUpAngle, eParam.RA_speedUpAngle_small, 0.0 },//加速角度
time_spu[3] = { eParam.RA_speedUp_1_time, eParam.RA_speedUp_2_time, 0.0 },//加速时间
V_equ[3] = { eParam.v_RA_max, eParam.v_RA_max_small, eParam.v_RA_continue };//最大速度
int speed_up_mode[3] = { 1, 2, 3 },//加速模式
i = 0;
input_angle = fabs(input_angle);
for (i = 0; i < 3; i++) {
correct_angle = 2.0 * angle_spu[i] + V_equ[i] * ((input_angle - 2.0 * angle_spu[i] + dierection201(direction) * 2.0 * V_earth * time_spu[i]) / (-dierection201(direction) * V_earth + V_equ[i]));
if (get_ra_speed_up_mode(correct_angle) == speed_up_mode[i]) {//判断加速模式是否匹配
return correct_angle;
}
}
return input_angle;
}
cv::Rect getRect(int left_top_x, int left_top_y, int width, int height, double* center_x, double* center_y) {
cv::Rect outputRect;
outputRect.x = left_top_x;
outputRect.y = left_top_y;
outputRect.width = width;
outputRect.height = height;
*center_x = double(left_top_x) + double(width) / 2.0;
*center_y = double(left_top_y) + double(height) / 2.0;
return outputRect;
}
cv::Mat getMouseControlImage(int width, int height, std::vector<cv::Rect>* image_rect) {//上左下右,从上到下x4
double control_rect_width = height * 200 / 1080, control_rect_center_x = height * 550 / 1080, control_rect_center_y = height * 550 / 1080, control_rect_radius = height * 400 / 1080;
double angle_rect_x = height * 1200 / 1080, angle_rect_height = height * 100 / 1080, angle_rect_width = height * 500 / 1080, angle_rect_origin_y = height * 400 / 1080, angle_rect_gap = height * 20 / 1080;
double center_x[5] = { 0 }, center_y[5] = { 0 };
double angle_word_x = angle_rect_x + angle_rect_width + 5, angle_word_y = angle_rect_origin_y + angle_rect_height / 2 + 15;
double Triangle_radius_ = 0.3 * double(control_rect_width);
cv::Mat control_image = cv::Mat(cv::Size(width, height), CV_8UC3, cv::Scalar(80, 0, 0));
cv::Scalar botton_color = cv::Scalar(100, 100, 100);
std::vector<cv::Rect> all_rect;
char angle_[50] = { 0 };
all_rect.push_back(getRect(control_rect_center_x - control_rect_width / 2, control_rect_center_y - control_rect_radius, control_rect_width, control_rect_width, ¢er_x[0], ¢er_y[0]));//上
all_rect.push_back(getRect(control_rect_center_x - control_rect_radius, control_rect_center_y - control_rect_width / 2, control_rect_width, control_rect_width, ¢er_x[1], ¢er_y[1]));//左
all_rect.push_back(getRect(control_rect_center_x - control_rect_width / 2, control_rect_center_y + control_rect_radius - control_rect_width, control_rect_width, control_rect_width, ¢er_x[2], ¢er_y[2]));//下
all_rect.push_back(getRect(control_rect_center_x + control_rect_radius - control_rect_width, control_rect_center_y - control_rect_width / 2, control_rect_width, control_rect_width, ¢er_x[3], ¢er_y[3]));//右
all_rect.push_back(getRect(angle_rect_x, angle_rect_origin_y, angle_rect_width, angle_rect_height, ¢er_x[4], ¢er_y[4]));//1
all_rect.push_back(getRect(angle_rect_x, angle_rect_origin_y + angle_rect_gap + angle_rect_height, angle_rect_width, angle_rect_height, ¢er_x[4], ¢er_y[4]));//2
all_rect.push_back(getRect(angle_rect_x, angle_rect_origin_y + 2 * (angle_rect_gap + angle_rect_height), angle_rect_width, angle_rect_height, ¢er_x[4], ¢er_y[4]));//3
all_rect.push_back(getRect(angle_rect_x, angle_rect_origin_y + 3 * (angle_rect_gap + angle_rect_height), angle_rect_width, angle_rect_height, ¢er_x[4], ¢er_y[4]));//4
all_rect.push_back(getRect(angle_rect_x, angle_rect_origin_y + 4 * (angle_rect_gap + angle_rect_height), angle_rect_width, angle_rect_height, ¢er_x[4], ¢er_y[4]));//4
all_rect.push_back(getRect(control_rect_center_x - control_rect_width / 2, control_rect_center_y - control_rect_width / 2, control_rect_width, control_rect_width, ¢er_x[4], ¢er_y[4]));//4
*image_rect = all_rect;
for (int i = 0; i < all_rect.size(); i++) {
cv::rectangle(control_image, all_rect[i], botton_color, -1, cv::LINE_AA);
}
cv::rectangle(control_image, all_rect[8], botton_color, -1, cv::LINE_AA);
for (int i = 0; i < 4; i++) {
lsx::starProcessing::DrawTriangle(control_image, cv::Scalar(255, 255, 255), center_x[i], center_y[i], Triangle_radius_, -i * 90.0);
}
for (int i = 0; i < 5; i++) {
if (i == 0) {
sprintf_s(angle_, "X10");
}
else if (i == 1) {
sprintf_s(angle_, "X1");
}
else if (i == 2) {
sprintf_s(angle_, "X0.1");
}
else if (i == 3) {
sprintf_s(angle_, "X0.01");
}
else {
sprintf_s(angle_, "Reset");
}
cv::putText(control_image, angle_, cv::Point(angle_word_x, angle_word_y + i * (angle_rect_gap + angle_rect_height)), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
}
cv::circle(control_image, cv::Point(control_rect_center_x, control_rect_center_y), 0.7 * Triangle_radius_, cv::Scalar(255, 255, 255), -1, cv::LINE_AA);
cv::putText(control_image, "RA East Motion", cv::Point(all_rect[0].x - 10, all_rect[0].y - 8), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
cv::putText(control_image, "RA West Motion", cv::Point(all_rect[2].x - 10, all_rect[2].y + 28 + all_rect[1].height), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
cv::putText(control_image, "DEC Anticlockwise", cv::Point(all_rect[1].x - 30, all_rect[1].y - 8), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
cv::putText(control_image, "DEC Clockwise", cv::Point(all_rect[3].x - 10, all_rect[3].y - 8), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
return control_image;
}
void equ_control_mouse_callback(int event_, int x, int y, int flags, void* userData) {
if (equ_control_deal_mouse_botton) {
if (event_ == cv::EVENT_LBUTTONDOWN) {
equ_control_mouse_botton_x = x;
equ_control_mouse_botton_y = y;
if (equ_control_angle_change_enable) {
adjust_angle += cell_angle;
if (adjust_angle > 250) {
adjust_angle = 250;
}
}
if (angle_reset_enable) {
adjust_angle = 0;
}
equ_control_mouse_get_coodinate = true;
}
else if (event_ == cv::EVENT_RBUTTONDOWN) {
if (!angle_reset_enable) {
if (!equ_control_angle_change_enable) {
equ_control_quit = true;
}
else {
adjust_angle -= cell_angle;
if (adjust_angle < 0) {
adjust_angle = 0;
}
}
}
}
}
if (event_ == cv::EVENT_MOUSEWHEEL) {
if (equ_control_angle_change_enable) {
if (cv::getMouseWheelDelta(flags) > 0) {
adjust_angle += cell_angle;
if (adjust_angle > 250) {
adjust_angle = 250;
}
}
else {
adjust_angle -= cell_angle;
if (adjust_angle < 0) {
adjust_angle = 0;
}
}
}
}
if (event_ == cv::EVENT_MOUSEMOVE) {
equ_control_mouse_touch_x = x;
equ_control_mouse_touch_y = y;
}
}
Eigen::MatrixXd lsx::control::MouseControl(int width, int height) {
Eigen::MatrixXd outputAngle(2, 1);
std::vector<cv::Rect> rect_table;
cv::Mat show_image;
std::string window_name = "Shixuan Liu - Equatorial Control";
cv::Point show_angle_position = cv::Point(height * 1200 / 1080, height * 300 / 1080);
std::clock_t ra_start_time = 0, end_time = 0, dec_start_time = 0;
char show_angle_[50] = { 0 }, show_run_state[100] = { 0 };
int keyNumber = 0, i = 0, ra_direction = 0, dec_direction = 0;
int ra_runtime = 0, dec_runtime = 0;
double ra_now_runtime = 0, dec_now_runtime = 0;
outputAngle *= 0;
cv::namedWindow(window_name, cv::WINDOW_NORMAL);
setWindowProperty(window_name, cv::WND_PROP_FULLSCREEN, cv::WINDOW_FULLSCREEN);
cv::setMouseCallback(window_name, equ_control_mouse_callback);
while (!equ_control_quit) {
show_image = getMouseControlImage(width, height, &rect_table);
if((equ_control_equ_ra_is_running || equ_control_equ_dec_is_running)){
end_time = std::clock();
ra_now_runtime = double(end_time) - double(ra_start_time);
dec_now_runtime = double(end_time) - double(dec_start_time);
if (ra_now_runtime > ra_runtime) {
equ_control_equ_ra_is_running = false;
}
if (dec_now_runtime > dec_runtime) {
equ_control_equ_dec_is_running = false;
}
if (ra_now_runtime < ra_runtime && dec_now_runtime < dec_runtime) {
sprintf_s(show_run_state, "Equatorial is running (RA: %d ms, DEC: %d ms) . . .", int(ra_runtime - ra_now_runtime), int(dec_runtime - dec_now_runtime));
}
else if (ra_now_runtime < ra_runtime && dec_now_runtime >= dec_runtime) {
sprintf_s(show_run_state, "Equatorial is running (RA: %d ms, DEC ready) . . .", int(ra_runtime - ra_now_runtime));
}
else if(ra_now_runtime >= ra_runtime && dec_now_runtime < dec_runtime){
sprintf_s(show_run_state, "Equatorial is running (RA ready, DEC: %d ms) . . .", int(dec_runtime - dec_now_runtime));
}
cv::putText(show_image, show_run_state, cv::Point(5, 25), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
}
else {
cv::putText(show_image, "Equatorial ready !", cv::Point(5, 25), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
}
for (i = 0; i < rect_table.size(); i++) {
if (lsx::math::PointInRect(equ_control_mouse_touch_x, equ_control_mouse_touch_y, rect_table[i])) {
cv::rectangle(show_image, rect_table[i], cv::Scalar(255, 255, 255), 3, cv::LINE_AA);
if (i >= 4 && i <= 8) {
if (i == 4) { cell_angle = 10.0; }
else if (i == 5) { cell_angle = 1.0; }
else if (i == 6) { cell_angle = 0.1; }
else if (i == 7) { cell_angle = 0.01; }
equ_control_angle_change_enable = true;
if (i == 8) {
angle_reset_enable = true;
equ_control_angle_change_enable = false;
}
}
break;
}
else {
equ_control_angle_change_enable = false;
angle_reset_enable = false;
}
}
if (equ_control_mouse_get_coodinate) {
equ_control_mouse_get_coodinate = false;
equ_control_deal_mouse_botton = false;
for (i = 0; i < rect_table.size(); i++) {
if (lsx::math::PointInRect(equ_control_mouse_touch_x, equ_control_mouse_touch_y, rect_table[i])) {
if (i == 0) {
if (!equ_control_equ_ra_is_running) {
lsx::control::ra_goto_motion(RA_DIR_BACKWARD, adjust_angle);
ra_start_time = std::clock();
ra_runtime = lsx::control::EquatorialRunTime_ms(adjust_angle, RA_STEPMOTOR, RA_WAIT_MODE_NORMAL);
equ_control_equ_ra_is_running = true;
}
}
else if (i == 1) {
if (!equ_control_equ_dec_is_running) {
lsx::control::dec_goto_motion(DEC_DIR_BACKWARD, adjust_angle);
dec_start_time = std::clock();
dec_runtime = lsx::control::EquatorialRunTime_ms(adjust_angle, DEC_STEPMOTOR, RA_WAIT_MODE_NORMAL);
equ_control_equ_dec_is_running = true;
}
}
else if (i == 2) {
if (!equ_control_equ_ra_is_running) {
lsx::control::ra_goto_motion(RA_DIR_FORWARD, adjust_angle);
ra_start_time = std::clock();
ra_runtime = lsx::control::EquatorialRunTime_ms(adjust_angle, RA_STEPMOTOR, RA_WAIT_MODE_NORMAL);
equ_control_equ_ra_is_running = true;
}
}
else if (i == 3) {
if (!equ_control_equ_dec_is_running) {
lsx::control::dec_goto_motion(DEC_DIR_FORWARD, adjust_angle);
dec_start_time = std::clock();
dec_runtime = lsx::control::EquatorialRunTime_ms(adjust_angle, DEC_STEPMOTOR, RA_WAIT_MODE_NORMAL);
equ_control_equ_dec_is_running = true;
}
}
break;
}
}
equ_control_deal_mouse_botton = true;
}
sprintf_s(show_angle_, "Angle setting: %d.%d degree", int(floor(adjust_angle)), int((100.0 * (adjust_angle - floor(adjust_angle)))));
cv::putText(show_image, show_angle_, show_angle_position, cv::FONT_HERSHEY_SIMPLEX, 1.4, cv::Scalar(255, 255, 255), 2, cv::LINE_AA);
cv::imshow(window_name, show_image);
cv::waitKey(20);
}
cv::destroyAllWindows();
return outputAngle;
}
Global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include<string.h>
#include"LsxMath.h"
#include<ctime>
#include<Windows.h>
#include <stdio.h>
#include<time.h>
#include <chrono>
#include"Astronomy.h"
#define DEC_IS_ON_THE_RIGHT 0//赤纬在右半盘位置
#define DEC_IS_ON_THE_LEFT 1//赤纬在左半盘位置
/**
* @brief 得到当地恒星时的函数
* @param none
* @return 当地恒星时,单位:°
*/
double local_sidreal_time_degree();
#endif
Global.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Global.h"
/*--------------------------------------观测地设置------------------------------------------------*/
double global_latitude = 26.653;//观测地纬度,单位:°
double global_longitude = 102.240;//观测地经度,单位:°
/*--------------------------------------串口------------------------------------------------*/
CString PORTNAME = "COM4";//连接赤道仪的串口号
/*-------------------------------------------星点识别参数-----------------------------------------------*/
double contrastIndex_log_gamma = 50;//灰度图像对比度前乘系数
double contrastIndex_gamma = 0.4;//在对比度gamma变换时的幂指数
int erodeSize = 3;//图像腐蚀卷积核大小
int dilateSize = 11;//图像膨胀卷积核大小
double imageThreshold = 45;//图像二值化阈值
int maxStarNumber = 70;//函数寻找的最多星点
int maxSize_contours = 1000;//轮廓上边界
int minSize_contours = 12;//轮廓下边界
int fitEllipseRegion = 60;//使用椭圆拟合时矩形方框与图像边界的最小距离
cv::Scalar star_frame_color = cv::Scalar(0, 255, 0);//星点外框的颜色(适用于矩形外框、圆形外框)
cv::Scalar star_size_brightness_word_color = cv::Scalar(220, 184, 190);//表示字体的颜色
cv::Scalar star_number_word_color = cv::Scalar(0, 255, 255);//表示字体的颜色
/*--------------------------------------赤道仪参数------------------------------------------------*/
int RA_reduction_ratio = 300;
int DEC_reduction_ratio = 100;
int RA_teeth_number = 202;//赤经轴输出端的齿数,最后一级输出的齿数,对于100:1的谐波减速机,其钢轮齿数为2*100+2=202
double RA_teeth_period = 86164.0 / double(RA_teeth_number);//赤经轴齿轮大周期,谐波减速机每一个齿经过的时间
/*--------------------------------------电子极轴镜参数、电子极轴镜类参数------------------------------------------------*/
double PIXEL_SIZE_POLAR_MIRROR_um = 3.75;//极轴相机像元大小 2.9
double FOCAL_LENGTH_POLAR_MIRROR_mm = 25.5;//极轴相机焦距 51.5803
double pixel_per_degree_polar_mirror = (PI * FOCAL_LENGTH_POLAR_MIRROR_mm * 1000.0) / (180.0 * PIXEL_SIZE_POLAR_MIRROR_um);//像素/度,电子极轴镜的分辨系数
double emirror_frame_width_pixel = 1280;//电子极轴镜图像宽度 1920 6248
double emirror_frame_height_pixel = 960;//电子极轴镜图像高度 1080 4176
double emirror_angle_to_dec_axis_degree = 0;//电子极轴镜CMOS正方向与DEC轴的偏转角,在这款电子极轴镜中为45°
/**
* opencv曝光参数于输入参数对应表:
* exposure = -1: 曝光时间:640ms 1
* exposure = -2: 曝光时间:320ms 2
* exposure = -3: 曝光时间:160ms 4
* exposure = -4: 曝光时间:80ms 8
* exposure = -5: 曝光时间:40ms 16
* exposure = -6: 曝光时间:20ms
* exposure = -7: 曝光时间:10ms
* exposure = -8: 曝光时间:5ms
* exposure = -9: 曝光时间:2.5ms
* exposure = -10: 曝光时间:1.25ms
* exposure = -11: 曝光时间:0.625ms
* exposure = -12: 曝光时间:0.3125ms
* exposure = -13: 曝光时间:0.15625ms
* exposure = -14: 曝光时间:0.078125ms
*/
double emirror_exposure = -4;//极轴相机曝光,640ms
int emirror_frame_sum_number = 6;//叠加图像张数
double emirror_exposure_when_calc_ra = -5;//当RA运行时的极轴相机曝光,160ms
double emirror_brightness = 10;//极轴相机的亮度
double emirror_gain = 0;//极轴相机的ISO(增益)
cv::Scalar e_polar_color = cv::Scalar(255, 255, 0);//赤道仪极轴绘制颜色
cv::Scalar ncp_polar_color = cv::Scalar(0, 0, 255);//北天极绘制颜色
double error_amplification_factor = 4.0;//极轴误差放大倍数
double max_calc_angle_region = 40.0;//求解赤道仪极轴时的移动角度,单位:°
double step_angle_calc_e_polar = 2;//求解赤道仪极轴时的最小移动角度,单位:°
int ncp_position_data_set_size = 3;//调整时北天极位置更新数据集的大小
int polarMirrorAdjustImageSize = 800;//放大图的大小
double one_frame_radius = 12.0 * emirror_frame_height_pixel / 1080.0;//星点框半径
/*--------------------------------------导星镜参数------------------------------------------------*/
double PIXEL_SIZE_GUIDE_MIRROR_um = 2.9;//导星相机像元大小,单位:um
double FOCAL_LENGTH_GUIDE_MIRROR_mm = 180.0;//导星相机焦距,单位:mm
double pixel_per_degree_guide_mirror = (PI * FOCAL_LENGTH_GUIDE_MIRROR_mm * 1000.0) / (180.0 * PIXEL_SIZE_GUIDE_MIRROR_um);//像素/度,导星镜的分辨系数
double guide_mirror_frame_width_pixel = 1920;//导星镜图像宽度
double guide_mirror_frame_height_pixel = 1080;//导星镜图像高度
double guide_mirror_view_angle_width = 2.0 * atan(guide_mirror_frame_width_pixel * PIXEL_SIZE_GUIDE_MIRROR_um / (1000.0 * 2.0 * FOCAL_LENGTH_GUIDE_MIRROR_mm)) / PI * 180.0;//横向视角大小
double guide_mirror_view_angle_height = 2.0 * atan(guide_mirror_frame_height_pixel * PIXEL_SIZE_GUIDE_MIRROR_um / (1000.0 * 2.0 * FOCAL_LENGTH_GUIDE_MIRROR_mm)) / PI * 180.0;//纵向视角大小
/**
* opencv曝光参数于输入参数对应表:
* exposure = -1: 曝光时间:640ms 1
* exposure = -2: 曝光时间:320ms 2
* exposure = -3: 曝光时间:160ms 4
* exposure = -4: 曝光时间:80ms 8
* exposure = -5: 曝光时间:40ms 16
* exposure = -6: 曝光时间:20ms
* exposure = -7: 曝光时间:10ms
* exposure = -8: 曝光时间:5ms
* exposure = -9: 曝光时间:2.5ms
* exposure = -10: 曝光时间:1.25ms
* exposure = -11: 曝光时间:0.625ms
* exposure = -12: 曝光时间:0.3125ms
* exposure = -13: 曝光时间:0.15625ms
* exposure = -14: 曝光时间:0.078125ms
*/
double guide_mirror_exposure = -4;//导星相机曝光,320ms
int guide_mirror_frame_sum_number = 12;//叠加图像张数
double guide_mirror_brightness = 30;//导星相机的亮度
double guide_mirror_gain = 2.0;//导星相机的ISO(增益)
/*--------------------------------------相机ID参数------------------------------------------------*/
int video_id = 0;//相机ID选择
int api_preference = cv::CAP_DSHOW;//相机编码方式选择
/*--------------------------------------自动寻星控制器------------------------------------------------*/
int DEC_side = DEC_IS_ON_THE_RIGHT;//赤道仪DEC的位置
std::string this_target_name = "empty";//当前目标名称
std::string this_target_number = "empty";//当前观测目标编号(如M42等)
bool noTarget = true;//是否是第一次观测的标志
bool after_guide = false;//是否是在导星之后进入自动寻星
int zenith_line_color[3] = { 150, 150, 150 };//地平线颜色
cv::Scalar zenith_str_line(238, 104, 123);//中天直线颜色
cv::Scalar background(0, 0, 0);//背景颜色
cv::Scalar background_line(50, 50, 50);//刻度线颜色
cv::Scalar star_color(133, 217, 253);//恒星颜色
cv::Scalar not_star_color(254, 235, 233);//天体颜色
cv::Scalar big_word(238, 104, 123);//图样范围字符颜色
cv::Scalar coordinate_words(159, 255, 84);//鼠标触摸到天体后显示坐标的颜色
cv::Scalar show_state_1_color(255, 255, 255);//Select a star with the mouse to calibrate the '0' position.提示符颜色
cv::Scalar my_equatorial_instrument_color(238, 104, 123);//赤道仪图像显示的颜色
cv::Scalar my_equatorial_instrument_line_color(238, 104, 123);//赤道仪移动线颜色
cv::Scalar optional_target_color(159, 255, 84);//可选天体的图像显示颜色
int goto_image_width = 1600, goto_image_height = 800;//自动寻星的图像大小
/*-------------------------------------------星点跟踪参数-----------------------------------------------*/
double maxField = 50;//最大求解像素区域
double maxFieldIndex = 0.8;//求解指数
/*-------------------------------------------导星控制器参数-----------------------------------------------*/
int guide_period_ms = 800;//导星周期期望值,当实际周期大于该值时无效
double adjust_threhold = 0.3;//调整阈值,当误差绝对值大于该值时进行调整
double force_adjust_threshold = 1.5;//强制调整阈值,大于该值时必须调整
double guide_kd_adjust_threshold = 0.8;//当误差变化量大于该值时,启用d控制分量
double LPF_index = 0.4;//低通滤波器保留波比例
double error_track_threhold = 60;//错误阈值,当超过此值后认为跟踪错误
double guide_kp = 0.8;//导星PI控制中的P系数
double guide_ki = 0.3;//导星PI控制中的I系数
double guide_kd = 0.5;//导星控制中的D系数
double guide_ki_long = 0.05;//导星第二I系数
double guide_kp_dec = 0.8;//P系数
double guide_ki_dec = 0.3;//I系数
double guide_kd_dec = 0.3;//导星控制中的D系数
double guide_ki_dec_long = 0.05;//导星第二I系数
double differential_coefficient_region = 1.5;//在频谱分析模块中,如果当前误差的导数和预测误差的导数值差距小于该值时,认为正确预测
double guide_star_max_predict_control = 2.0;//导星控制器预测调整的最大值
double GPR_run_index = 0.08;//为了减少导星控制器的计算,当导星控制器高斯过程回归预测模块开始求解后,在下一次求解之前需要检测到预备数据集刷新GPR_run_index * GPR_sample_number次
double Spectral_analysis_run_index = 0;//为了减少导星控制器的计算,当导星控制器高斯过程回归预测模块开始求解后,在下一次求解之前需要检测到预备数据集刷新GPR_run_index * GPR_sample_number次
int harmonic_number = 50;//频谱分析预测模块预测的周期函数数量
int sum_error_number = 5;//误差累计范围
int sum_error_number_long = 10;//误差长时间累计范围
int guide_median_filter_length_RA = 7;//RA中值滤波窗口大小
int guide_median_filter_length_DEC = 7;//DEC中值滤波窗口大小
int guide_error_vector_sum_number = 3;//导星过程中对偏移向量进行求和平均值的数量
int error_frame_width = 1550, error_frame_height = 750, error_frame_scatter_width = 749;//导星控制器图像显示大小
cv::Scalar ra_error_line_color = cv::Scalar(255, 164, 30);//RA轴相对误差曲线颜色
cv::Scalar dec_error_line_color = cv::Scalar(0, 0, 255);//DEC轴相对误差曲线颜色
cv::Scalar ra_control_line_color = cv::Scalar(100, 24, 0);//RA轴控制量直线颜色
cv::Scalar dec_control_line_color = cv::Scalar(0, 0, 80);//DEC轴控制量直线颜色
cv::Scalar guide_image_background = cv::Scalar(0, 0, 0);//控制器背景颜色
cv::Scalar guide_image_scale = cv::Scalar(100, 100, 100);//控制器横向刻度颜色
cv::Scalar scatter_point_color = cv::Scalar(205, 38, 125);//散点颜色
int scatter_point_radius = 2;//散点图点半径
double guide_star_image_max_error = 4.0;//导星控制器显示的最大误差
char file_saving_path_E_RA[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\E_RA.xlsx";//真周期误差文件保存路径
char file_saving_path_e_RA[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\e_RA_.xlsx";//相对误差文件保存路径
char file_saving_path_u_RA[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\u_RA.xlsx";//控制量文件保存路径
char file_saving_path_E_DEC[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\E_DEC.xlsx";//真周期误差文件保存路径
char file_saving_path_e_DEC[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\e_DEC_.xlsx";//相对误差文件保存路径
char file_saving_path_u_DEC[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\u_DEC.xlsx";//控制量文件保存路径
char guide_time_saving_path[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\guide_time.xlsx";//控制量文件保存路径
char error_scatter_image_saving_path[] = "C:\\Users\\Administrator\\Desktop\\Guide Star Output\\Guide Data\\guide_star_drift_scatter_image.jpg";//控制量文件保存路径
/*--------------------------------------当地恒星时函数------------------------------------------------*/
lsx::astronomy::AstroTimer global_astro_timer;//恒星时计算器,确定天体运行规律
double local_sidreal_time_degree() {
return global_astro_timer.get_local_sidereal_time();
}
SerialCommunication.h
#ifndef SERIALCOMMUNICATION_H
#define SERIALCOMMUNICATION_H
#include<iostream>
#include<Eigen/Dense>
#include<Windows.h>
#include<cmath>
#include"windows.h"
#include"atlstr.h"
#include<string.h>
#include<TCHAR.H>
#include<conio.h>
#include<stdarg.h>
#include<vector>
/*串口通信及赤道仪运行控制*/
namespace lsx {
namespace serial {
class serial_writer {
public:
bool have_open = false;
/**
* @brief 设置串口参数。
* @param port_name 串口名称,请打开<设备管理器>查找电脑连接单片机的串口,如令port_name = "COM5";
* @param baud_rate 波特率。
* @return void
*/
void set_serial(CString port_name, int baud_rate = 9600);
/**
* @brief 发送单字节数据,调用该函数立即发送
* @param input_data_1_byte 字符型(8位)数据。
* @return void
*/
void send_data(char input_data_1_byte);
/**
* @brief 发送一个数据包,调用该函数立即发送,从input_data[0]开始发送。
* @param input_data 待发送的字符容器
* @return void
*/
void send_data(std::vector<char> input_data);
/**
* @brief 关闭串口
* @param none
* @return void
*/
void Serial_close();
private:
LPCWSTR COM_port;
HANDLE hCom;
int baud_rate = 9600;
int serial_open(LPCWSTR COMx, int BaudRate);
int serial_write(char lpOutBuffer[]);
};
int serial_open(LPCWSTR COMx);
/**
* @brief 寻找赤道仪端口,并将全局变量置位
*/
void FindEquatorial();
}
}
#endif
SerialCommunication.cpp
#include"SerialCommunication.h"
extern CString PORTNAME;
void lsx::serial::serial_writer::set_serial(CString port_name, int baud_rate) {
this->COM_port = port_name.AllocSysString();
this->baud_rate = baud_rate;
}
void lsx::serial::serial_writer::send_data(char input_data_1_byte) {
bool serial_open = false;
serial_open = this->serial_open(this->COM_port, this->baud_rate);
if (serial_open) {
this->serial_write(&input_data_1_byte);
}
}
void lsx::serial::serial_writer::send_data(std::vector<char> input_data) {
bool serial_open = false;
int i;
serial_open = this->serial_open(this->COM_port, this->baud_rate);
if (serial_open) {
for (i = 0; i < input_data.size(); i++) {
this->serial_write(&input_data[i]);
}
}
}
int lsx::serial::serial_writer::serial_open(LPCWSTR COMx, int BaudRate) {
this->hCom = CreateFile(COMx, //COMx口
GENERIC_READ | GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
0, //重叠方式FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED (同步方式设置为0)
NULL);
if (this->hCom == INVALID_HANDLE_VALUE)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);
std::cout << "没有连接赤道仪!" << std::endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
this->have_open = false;
return false;
}
SetupComm(this->hCom, 1024, 1024); //输入缓冲区和输出缓冲区的大小都是1024
//设定读写超时
/*COMMTIMEOUTS TimeOuts;
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=500;
TimeOuts.ReadTotalTimeoutConstant=5000; //设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=500;
TimeOuts.WriteTotalTimeoutConstant = 2000;
SetCommTimeouts(hCom, &TimeOuts); //设置超时
*/
DCB dcb;
GetCommState(this->hCom, &dcb);
dcb.BaudRate = BaudRate; //设置波特率为BaudRate
dcb.ByteSize = 8; //每个字节有8位
dcb.Parity = NOPARITY; //无奇偶校验位
dcb.StopBits = ONESTOPBIT; //一个停止位
SetCommState(this->hCom, &dcb); //设置参数到hCom
PurgeComm(this->hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);//清空缓存区 //PURGE_TXABORT 中断所有写操作并立即返回,即使写操作还没有完成。
//PURGE_RXABORT 中断所有读操作并立即返回,即使读操作还没有完成。
//PURGE_TXCLEAR 清除输出缓冲区
//PURGE_RXCLEAR 清除输入缓冲区
this->have_open = true;
return true;
}
int lsx::serial::serial_writer::serial_write(char lpOutBuffer[]) {//同步写串口
DWORD dwBytesWrite = sizeof(lpOutBuffer);
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(this->hCom, &dwErrorFlags, &ComStat);
bWriteStat = WriteFile(this->hCom, lpOutBuffer, dwBytesWrite, &dwBytesWrite, NULL);
if (!bWriteStat)
{
//printf("写串口失败!\n");
this->have_open = false;
return false;
}
PurgeComm(this->hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
return true;
}
void lsx::serial::serial_writer::Serial_close() {//关闭串口
CloseHandle(this->hCom);
}
int lsx::serial::serial_open(LPCWSTR COMx) {
HANDLE hCom;
bool output;
hCom = CreateFile(COMx, //COMx口
GENERIC_READ | GENERIC_WRITE, //允许读和写
0, //独占方式
0,
OPEN_EXISTING, //打开而不是创建
FILE_ATTRIBUTE_NORMAL, //重叠方式FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED (同步方式设置为0)
0);
if (hCom == INVALID_HANDLE_VALUE){
CloseHandle(hCom);
return false;
}
CloseHandle(hCom);
return true;
}
CString PORTNAME_3 = "COM3";
CString PORTNAME_4 = "COM4";
CString PORTNAME_5 = "COM5";
void lsx::serial::FindEquatorial() {
int i;
CString CcomArray[3] = { "COM3" ,"COM4" ,"COM5" };
/*LPCWSTR comArray[3] = {_T("COM3") ,_T("COM4") ,_T("COM5") };*/
for (i = 0; i < 3; i++) {
if (lsx::serial::serial_open(CcomArray[i].AllocSysString())) {
//PORTNAME = CcomArray[i];
std::cout << "COM" << i + 3 << std::endl;
switch (i + 3) {
case 3:PORTNAME = PORTNAME_3;
case 4:PORTNAME = PORTNAME_4;
case 5:PORTNAME = PORTNAME_5;
}
break;
}
}
}