以下是赤道仪自动寻星V2.0的代码部分,自动寻星使用C++类编写,利用OpenCV编写了图形用户界面,在主函数中只调用一句话即可。请读者先阅读笔者发布的纯算法部分,以下代码均严格按照论文所述编写。需要说明的是,以下代码都使用了命名空间lsx,是笔者的姓名缩写。
本文首先介绍类AutoStarFindController的组成,这个类是自动寻星最终实现的类。为了让读者明白这个类中其他类的功能和作用,本文将从底层的类进行介绍,最后介绍类AutoStarFindController及其运行的样子。
成员 | ||
targetTable | astronomy::ObservationTable | 星表,是观测目标的集合 |
start, end | astronomy::ObservationTarget | 自动寻星的出发位置和目标位置的2个天体 |
zero2star | bool | 判断是否是从零位开始的标志位 |
ra_arrival, dec_arrival | bool | RA和DEC转轴到达目标的标志位 |
pointTarget | astronomy::ObservationTarget | 用户选择的天体 |
this_target_is_star | bool | 当前的天体为恒星的标志位,每次自动寻星都通过对准恒星进行校准 |
接口函数 | ||
AutomaticStarFinding() | void | 主函数中调用的自动寻星函数 |
preSet() | void | 提前设置自动寻星参数 |
从底层开始介绍各个类。首先介绍类:ObservationTarget,这是观测目标类,里面存放了一个观测目标的坐标名称等信息。
类ObservationTarget
Class ObservationTarget头文件:
/**
* @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:
};
对应cpp代码
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;
}
需要说明的是,命名空间astronomy不仅包含了这些类还有很多工具函数,他们都放置在了Astronomy.h和.cpp中,这个类和下面其他一些类是从命名空间astronomy中裁剪出来的。
类ObservationTable
其次将要介绍类ObservationTable,该类利用C++容器将观测目标类ObservationTarget合成了一个列表,可以理解为自定义的星表。
Class ObservationTable 头文件:
/**
* @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();
};
对应.cpp代码
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();
}
}
void lsx::astronomy::ObservationTable::input_data() {
/*-----------------------------------------------------------天体---------------------------------------------------------------*/
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M42", "M42(Great Orion Nebula)", "M42", 5.0, 36.0, 27.6, -5.0, -22.0, -58.4, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M31", "M31(Andromeda Galaxy)", "M31", 0, 44.0, 5.7, 41.0, 23.0, 37.4, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M20", "M20(Trifid Nebula)", "M20", 18.0, 3.0, 58.1, -22.0, -57.0, -55.3, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M33", "M33(Triangulum Galaxy)", "M33", 1.0, 35.0, 15.0, 30.0, 46.0, 50.9, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M45", "M45(Pleiades)", "M45", 3.0, 48.0, 22.9, 24.0, 13.0, 30.8, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("IC434", "IC434(Horsehead Nebula)", "IC434", 5.0, 42.0, 27.8, -2.0, -28.0, -55.7, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M101", "M101(Pinwheel Galaxy)", "M101", 14.0, 3.0, 55.8, 54.0, 13.0, 27.4, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M86", "M86(Markarian's Chain)", "Markarian's Chain", 12.0, 30.0, 1.8, 12.0, 57.0, 7.8, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M1", "M1(Crab Nebula)", "M1", 5.0, 35.0, 59.8, 22.0, 1.0, 56.7, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M8", "M8(Lagoon Nebula)", "M8", 18.0, 5.0, 19.7, -24.0, -21.0, -37.3, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M81", "M81(Bode's Nebula)", "M81", 9.0, 57.0, 34.9, 68.0, 56.0, 59.8, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("NGC2237", "NGC2237(Rosette Nebula)", "NGC2237", 6.0, 33.0, 10.3, 5.0, 0.0, 54.5, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M51", "M51(Whirlpool Galaxy)", "M51", 13.0, 30.0, 54.6, 47.0, 3.0, 57.7, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M106", "M106(Intermediate Spiral Seyfert 2 Galaxy)", "M106", 12.0, 20.0, 10.4, 47.0, 9.0, 57.8, false, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("NGC4217", "NGC4217(Spiral Galaxy)", "NGC4217", 12.0, 17.0, 4.2, 46.0, 57.0, 14.6, false, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M104", "M104(Sombrero Galaxy)", "M104", 12.0, 41.0, 15.1, -11.0, -45.0, -21.3, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("NGC4565", "NGC4565(Needle Galaxy)", "NGC4565", 12.0, 37.0, 33.3, 25.0, 51.0, 5.5, false));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("M4", "M4(Globular Cluster)", "M4", 16.0, 25.0, 3.1, -26.0, -34.0, -53.1, false, false));
/*-------------------------------------------------------------恒星-------------------------------------------------------------*/
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("大角星", "大角星(Arcturus)", "Da Jiao", 14.0, 16.0, 45.9, 19.0, 3.0, 12.4, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("织女星", "织女星(Vega)", "Zhi Nv", 18.0, 37.0, 43.7, 38.0, 48.0, 5.2, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("河鼓二", "河鼓二(Altair)", "He Gu 2", 19.0, 51.0, 56.0, 8.0, 55.0, 45.3, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("天津四", "天津四(Deneb)", "Tian Jin 4", 20.0, 42.0, 12.8, 45.0, 21.0, 49.3, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("心宿二", "心宿二(Antares)", "Xin Xiu 2", 16.0, 30.0, 52.4, -26.0, -29.0, -4.8, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("天狼星", "天狼星(Sirius)", "Tian Lang", 6.0, 46.0, 13.5, -16.0, -45.0, -3.7, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("角宿一", "角宿一(Spica)", "Jiao Xiu 1", 13.0, 26.0, 28.2, -11.0, -17.0, -15.2, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("参宿七", "参宿七(Rigel)", "Sen Xiu 7", 5.0, 15.0, 42.3, -8.0, -10.0, -32.2, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("参宿四", "参宿四(Betelgeuse)", "Sen Xiu 4", 5.0, 56.0, 29.3, 7.0, 24.0, 38.8, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("五车二", "五车二(Capella)", "Wu Che 2", 5.0, 18.0, 29.0, 46.0, 1.0, 27.4, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("南河三", "南河三(Procyon)", "Nan He 3", 7.0, 40.0, 34.7, 5.0, 9.0, 43.9, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("奎宿九", "奎宿九(Mirach)", "kui Xiu 9", 1.0, 11.0, 3.9, 35.0, 44.0, 58.1, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("北斗三", "北斗三(Phad)", "Bei Dou 3", 11.0, 55.0, 7.5, 53.0, 33.0, 25.5, true));
this->TargetTable.push_back(lsx::astronomy::ObservationTarget::ObservationTarget("北斗七", "北斗七(Alkaid)", "Bei Dou 7", 13.0, 48.0, 30.4, 49.0, 11.0, 15.7, true));
/*-------------------------------特殊观测目标------------------------------------*/
}
类AstroTimer
这个类使用IAU1982标准,用于计算当地恒星时,为系统系统时间坐标参数。
头文件:
/**
* @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);
};
源文件:
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;
}
命名空间astronomy中其他函数
这些函数包括论文里面将角度转换到0 - 360之间的函数,赤道坐标-地平坐标转换函数和一些角度换算函数。
头文件:
/**
* @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);
源文件:
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;
}
至此自动寻星需要的类介绍完成。
自动寻星的实现
懒得写了,这里直接介绍类AutoStarFindController。
头文件:
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);
};
源文件:
#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();
}
主函数中自动寻星的调用:
void test_goto() {
lsx::autoSearch::AutoStarFindController myAutoStarFinding;
while (true) {
myAutoStarFinding.AutomaticStarFinding();
}
}
运行后的图形用户界面:
可以通过鼠标选择天体:
当赤道仪在零位时必须选择一个恒星,之后可以选择其他的天体,当然地平线以下的也不能选择:
选择正确的天体后软件就会给赤道仪下发指令开始移动,移动方式请参考论文。