// This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Copyright Liam Girdwood 2003 #include "sky_proj.hh" /*! \namespace Vega * \brief Nova Virtual Sky Engine */ namespace Vega { /*! \fn SkyProj::SkyProj() * Constructor */ SkyProj::SkyProj() { // default sky settings m_centre_ra = MAX_RA / 2; m_centre_dec = 0; m_fov = MAX_RA / 2; m_clip_mag_max = 4; m_clip_mag_min = -2; m_show_const_lines = true; m_show_const_bounds = true; m_show_const_names = true; m_show_grid = true; m_show_planets = true; m_root = root(); // canvas groups m_object_group = 0; m_grid_group = 0; m_const_group = 0; } void SkyProj::clone (SkyProj* proj) { m_centre_ra = proj->m_centre_ra; m_centre_dec = proj->m_centre_dec; m_fov = proj->m_fov; m_show_const_lines = proj->m_show_const_lines; m_show_const_bounds = proj->m_show_const_bounds; m_show_const_names = proj->m_show_const_names; m_show_grid = proj->m_show_grid; m_JD = proj->m_JD; } /*! \fn void SkyProj::show_sky() * * Create and show the sky projection. */ void SkyProj::show_sky() { set_pixels_per_unit(1); set_scroll_region(0, 0, m_canvas_width, m_canvas_height); // render sky render_background(); render_sky(FULL); } /*! \fn SkyProj::~SkyProj() * Destructor */ SkyProj::~SkyProj() { } /*! \fn void SkyProj::show_grid(bool show) * * Set whether a position marker is rendered */ void SkyProj::show_grid(bool show) { m_show_grid = show; } /*! \fn void SkyProj::show_const_lines(bool show) * * Set whether constellation outlines are rendered */ void SkyProj::show_const_lines(bool show) { m_show_const_lines = show; } /*! \fn void SkyProj::show_const_names(bool show) * * Set whether constellation names are rendered */ void SkyProj::show_const_names(bool show) { m_show_const_names = show; } /*! \fn void SkyProj::show_const_bounds(bool show) * * Set whether constellation boundaries are rendered */ void SkyProj::show_const_bounds(bool show) { m_show_const_bounds = show; } /*! \fn bool SkyProj::show_grid() * * True if position marker is rendered */ bool SkyProj::is_grid() { return m_show_grid; } /*! \fn bool SkyProj::is_const_lines() * * True if constellation outlines are rendered */ bool SkyProj::is_const_lines() { return m_show_const_lines; } /*! \fn bool SkyProj::is_const_names() * * True if constellation names are rendered */ bool SkyProj::is_const_names() { return m_show_const_names; } /*! \fn bool SkyProj::is_const_bounds() * * True if constellation boundaries are rendered */ bool SkyProj::is_const_bounds() { return m_show_const_bounds; } /*! \fn void SkyProj::set_jd (double jd) * * Set sky projection Julian day */ void SkyProj::set_jd (double jd) { m_JD = jd; } /*! \fn double SkyProj::get_jd() * * Get sky projection Julian day */ double SkyProj::get_jd() { return m_JD; } /*! \fn void SkyProj::add_bright_catalog(Pollux::Catalog* cat) * \param cat Bright object catalog * * Add a bright object catalog to the sky projection */ void SkyProj::add_bright_catalog(Pollux::Catalog* cat) { m_bright_cat = cat; } /*! \fn void SkyProj::set_size(int width, int height) * * Set the sky projection size */ void SkyProj::set_size(int width, int height) { m_canvas_height = height; m_canvas_width = width; std::cout << " height " << m_canvas_height << " width " << m_canvas_width << std::endl; calc_fov_bounds(); } /*! \fn void SkyProj::calc_fov_bounds() * * Calculate the boundaries, magnitude level and field of view for the * virtual sky projection. */ void SkyProj::calc_fov_bounds() { m_canvas_ratio = (double)m_canvas_width / (double)m_canvas_height; m_is_ra_over = false; m_is_ra_under = false; m_ra_offset = 0; m_dec_offset = 0; if (m_spherical) m_clip_ra_min = m_centre_ra - (m_fov / 2.0) * m_canvas_ratio; else m_clip_ra_min = m_centre_ra - (m_fov / 2.0); if (m_clip_ra_min < MIN_RA) { m_is_ra_under = true; m_ra_offset = m_centre_ra - (m_fov / 2.0); m_clip_ra_min = MIN_RA; } if (m_spherical) m_clip_ra_max = m_centre_ra + (m_fov / 2.0) * m_canvas_ratio; else m_clip_ra_max = m_centre_ra + (m_fov / 2.0); if (m_clip_ra_max > MAX_RA) { m_is_ra_over = true; m_ra_offset = m_centre_ra + (m_fov / 2.0); m_clip_ra_max = MAX_RA; } if (m_spherical) m_clip_dec_min = m_centre_dec - (m_fov / 2.0); else m_clip_dec_min = m_centre_dec - (m_fov / 2.0) / m_canvas_ratio; if (m_clip_dec_min <= MIN_DEC) { m_dec_offset = m_clip_dec_min - MIN_DEC; m_clip_dec_min = MIN_DEC; } if (m_spherical) m_clip_dec_max = m_centre_dec + (m_fov / 2.0); else m_clip_dec_max = m_centre_dec + (m_fov / 2.0) / m_canvas_ratio; if (m_clip_dec_max > MAX_DEC) { m_clip_dec_max = MAX_DEC; } // are we over/under lapping if (m_is_ra_over || m_is_ra_under) calc_ra_overlap(); m_ra_ppd = m_canvas_width / m_fov; m_dec_ppd = m_canvas_height / (m_fov / m_canvas_ratio); // a look up table - there must be a better way...... double mag_const = MAG_CONST; if (m_fov < 145.0 && m_fov >= 60.0) mag_const *= 1.65; else if (m_fov < 60.0 && m_fov >= 35.0) mag_const *= 2.0; else if (m_fov < 35.0 && m_fov >= 10.0) mag_const *= 2.5; else if (m_fov < 10.0 && m_fov >= 5.0) mag_const *= 3.0; else if (m_fov < 5.0 && m_fov >= 2.0) mag_const *= 4.0; else if (m_fov < 2.0) mag_const *= 5.0; m_clip_mag_max = MAG_BASE + (MAX_FOV - m_fov) * mag_const; std::cout << " mag max " << m_clip_mag_max << " fov " << m_fov << std::endl; std::cout << " min ra " << m_clip_ra_min <<" max " << m_clip_ra_max << std::endl; std::cout << " min dec " << m_clip_dec_min << " max " << m_clip_dec_max << std::endl; } /*! \fn void SkyProj::move_ra (double pixels) * \param pixels Number of pixels to move the sky projection in RA. * * Move the virtual sky east or west in RA. */ void SkyProj::move_ra (double pixels) { m_centre_ra += pixels / m_ra_ppd; // do we need to reset RA if there is a large overlap if (m_centre_ra > MAX_RA) { m_centre_ra = MIN_RA; } else if (m_centre_ra < MIN_RA) { m_centre_ra = MAX_RA; } } /*! \fn void SkyProj::move_dec (double pixels) * \param pixels Number of pixels to move the sky projection in DEC. * * Move the virtual sky north or south in DEC. */ void SkyProj::move_dec (double pixels) { // are we at the limits if ((m_centre_dec == MAX_DEC && pixels > 0) || (m_centre_dec == MIN_DEC && pixels < 0)) return; m_centre_dec += pixels / m_dec_ppd; // do we need to reset DEC if (m_centre_dec > MAX_DEC) { m_centre_dec = MAX_DEC; } else if (m_centre_dec < MIN_DEC) { m_centre_dec = MIN_DEC; } } /*! \fn bool SkyProj::zoom (double zoom) * \param zoom Zoom in/out factor * \return false if the sky cannot be zoomed. * * Zoom the sky projection in or out. */ bool SkyProj::zoom (double zoom) { // are we at the limits if (m_fov * zoom >= MAX_FOV) { m_fov = MAX_FOV; return false; } if (m_fov * zoom <= MIN_FOV) { m_fov = MIN_FOV; return false; } m_fov *= zoom; return true; } /*! \fn double SkyProj::calc_size (Castor::AstroObject* object) * \param object Astro object * \return Virtual sky canvas size in pixels. * * Calculate the sky projection canvas size of an object based * on it's visual magnitude. */ double SkyProj::calc_size (Castor::AstroObject* object) { double mag = object->get_mag(); return (m_clip_mag_max + 1) - mag; } /*! \fn void SkyProj::render_bg() * * Render the sky projection black background */ void SkyProj::render_background() { m_bg_group = Gtk::manage (new Gnome::Canvas::Group (*m_root, 0, 0)); m_bg_rect = Gtk::manage (new Gnome::Canvas::Rect(*m_bg_group, 0, 0, m_canvas_width, m_canvas_height)); *m_bg_rect << Gnome::Canvas::Properties::fill_color("black"); m_bg_rect->set_data (Glib::Quark ("background"), (gpointer)0); } /*! \fn calc_ra_overlap() * * Calculate the projection RA over/under lap size and clipping area. */ void SkyProj::calc_ra_overlap() { if (m_is_ra_under) { // we are < MIN_RA, so extra is rhs (under) OK m_clip_ra_min_overlap = MAX_RA + m_ra_offset; m_clip_ra_max_overlap = MAX_RA; m_clip_dec_min_overlap = m_clip_dec_min; m_clip_dec_max_overlap = m_clip_dec_max; } else { // we are > MIN_RA, so extra is lhs (over) OK m_clip_ra_min_overlap = MIN_RA; m_clip_ra_max_overlap = m_ra_offset - MAX_RA; m_clip_dec_min_overlap = m_clip_dec_min; m_clip_dec_max_overlap = m_clip_dec_max; } } /*! \fn void SkyProj::render_sky(Render type) * * Update the Sky projection canvas. * The update can either be for bright objects (fast) or for * faint objects and other artifacts (slower). * The fast update is used for moving and zooming around the sky. */ void SkyProj::render_sky(Render type) { Glib::TimeVal t1, t2; t1.assign_current_time(); std::cout << "Update started " << std::endl; calc_fov_bounds(); // delete existing objects if we are starting a new update if (type != FAINT) { if (m_object_group) { delete m_object_group; m_object_group = 0; } if (m_const_group) { delete m_const_group; m_const_group = 0; } if (m_grid_group) { delete m_grid_group; m_grid_group = 0; } } if (type == BRIGHT || type == FULL) { if (m_show_grid) { m_grid_group = Gtk::manage (new Gnome::Canvas::Group (*m_root, 0, 0)); render_grid(); } // render all bright objects m_object_group = Gtk::manage (new Gnome::Canvas::Group (*m_root, 0, 0)); render_planets(); render_bright_objects(type); } if (type == FAINT || type == FULL) { // do we need to render constellations boundaries/names if (m_show_const_bounds || m_show_const_names || m_show_const_lines) { m_const_group = Gtk::manage (new Gnome::Canvas::Group (*m_root, 0, 0)); m_const_group->lower_to_bottom(); m_const_group->raise(1); if (m_show_const_lines) render_const_lines(); if (m_show_const_bounds) render_const_bounds(); if (m_show_const_names) render_const_names(); } // render faint objects render_remaining_objects(); } t2.assign_current_time(); t2 = t2 - t1; std::cout << "Update Complete " << t2.as_double() << std::endl; } /*! \fn void SkyFlat::render_bright_objects(Render type) * * Render the bright objects on the * entire sky projection. */ void SkyProj::render_bright_objects(Render type) { render_basic(); render_main_sector(type); if (m_is_ra_over || m_is_ra_under) render_overlap_sector(type); update_now(); } /*! \fn void SkyFlat::render_bright_objects() * * Render the faint and other objects on the * entire sky projection. */ void SkyProj::render_remaining_objects() { render_main_sector(FAINT); if (m_is_ra_over || m_is_ra_under) render_overlap_sector(FAINT); } /*! \fn void SkyFlat::render_main_sector() * * Render objects on the sky projection * main sector. */ void SkyProj::render_main_sector(Render type) { std::vector::iterator i; std::vector object_band[OBJECT_GROUPS]; std::vector objects; double x, y, size, ra_offset; double mag_min, mag_max; int index; bool bright; // are we only rendering bright stars if (type == BRIGHT) { mag_max = m_clip_mag_max - BRIGHT_DIFF; mag_min = m_clip_mag_min; bright = true; } else { if (type == FULL) { mag_max = m_clip_mag_max - BRIGHT_DIFF; mag_min = m_clip_mag_min; bright = false; } else { mag_max = m_clip_mag_max; mag_min = m_clip_mag_max - BRIGHT_DIFF; bright = false; } } // clip the catalog m_bright_cat->clip(m_clip_ra_min, m_clip_dec_min, m_clip_ra_max , m_clip_dec_max, mag_min, mag_max); // get visible objects std::cout << " objects " << m_bright_cat->get_objects(objects) << std::endl; // sort into magnitude bands for (i = objects.begin(); i != objects.end(); i++) { index = (int)((*i)->get_mag()); object_band[index + 2].push_back(*i); } // calc offset if (m_is_ra_over) ra_offset = MIN_RA; else ra_offset = m_ra_offset; // render objects, brightest first for (int j=0; jget_equ_posn(0, x, y); transform(x, y, ra_offset); if (is_visible(x,y)) (*i)->render(x, y, m_clip_mag_max, *m_object_group, bright); } } } /*! \fn void SkyFlat::render_main_sector() * * Render objects on the sky projection * overlap sector. */ void SkyProj::render_overlap_sector(Render type) { std::vector::iterator i; std::vector object_band[OBJECT_GROUPS]; std::vector objects; double x, y, size, ra_offset; double mag_min, mag_max; int index; bool bright; // are we only rendering bright stars if (type == BRIGHT) { mag_max = m_clip_mag_max - BRIGHT_DIFF; mag_min = m_clip_mag_min; bright = true; } else { mag_max = m_clip_mag_max; mag_min = m_clip_mag_max - BRIGHT_DIFF; bright = false; } // clip the catalog m_bright_cat->clip(m_clip_ra_min_overlap, m_clip_dec_min_overlap, m_clip_ra_max_overlap , m_clip_dec_max_overlap, mag_min, mag_max); // get visible objects std::cout << " overlap objects " << m_bright_cat->get_objects(objects) << std::endl; // sort into magnitude band for (i = objects.begin(); i != objects.end(); i++) { index = (int)((*i)->get_mag()); object_band[index + 2].push_back(*i); } // get ra offset if (m_is_ra_under) ra_offset = m_ra_offset + MAX_RA; //rhs else ra_offset = -MAX_RA; //lhs // render objects, brightest first for (int j=0; jget_equ_posn(0, x, y); transform(x, y, ra_offset); if (is_visible(x,y)) (*i)->render(x, y, m_clip_mag_max, *m_object_group, bright); } } } /*! \fn double SkyProj::get_ra () * \return RA (degrees) * * Get the current sky projection centre RA. */ double SkyProj::get_ra () { return m_centre_ra; } /*! \fn double SkyProj::get_dec () * \return DEC (degrees) * * Get the current sky projection centre DEC. */ double SkyProj::get_dec () { return m_centre_dec; } /*! \fn double SkyProj::get_fov (); * \return FOV (degrees) * * Get the sky projection field of view in degrees */ double SkyProj::get_fov () { return m_fov; } /*! \fn void SkyProj::set_ra (double ra) * * Set the sky projection centre RA. */ void SkyProj::set_ra (double ra) { m_centre_ra = ra; } /*! \fn void SkyProj::set_dec (double dec) * * Set the sky projection centre DEC. */ void SkyProj::set_dec (double dec) { m_centre_dec = dec; } /*! \fn void SkyProj::set_fov (double fov) * * Set the sky projection field of view in degrees. */ void SkyProj::set_fov (double fov) { m_fov = fov; } }