// 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_spherical.hh"
#include <libgnomecanvasmm/line.h>
#include <libgnomecanvasmm/bpath.h>
#include <libgnomecanvasmm/ellipse.h>
#include <math.h>

/*! \namespace Vega
* \brief Nova Virtual Sky Engine
*/
namespace Vega
{

/*! \fn SkySpherical::SkySpherical(double x_size, double y_size)
* \param x_size Virtual sky x size
* \param y_size Virtual sky y size
*
* Constructor
*/
SkySpherical::SkySpherical()
{
	m_spherical = true;
}

/*! \fn SkySpherical::~SkySpherical()
* Destructor
*/
SkySpherical::~SkySpherical()
{
}

void SkySpherical::render_planets()
{
		struct ln_equ_posn equ;
	double ra, dec;
	double ra_offset;
	
	// calc offset
	if (m_is_ra_over)
		ra_offset = MIN_RA;
	else
		ra_offset = m_ra_offset;
	
	if (m_mercury.get_mag(m_JD) < m_clip_mag_max) { 
		m_mercury.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_mercury.set_render_jd(m_JD);
		m_mercury.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd);
	}		
	
	if (m_venus.get_mag(m_JD) < m_clip_mag_max) { 
		m_venus.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_venus.set_render_jd(m_JD);
		m_venus.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
	}
	
	if (m_mars.get_mag(m_JD) < m_clip_mag_max) { 
		m_mars.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_mars.set_render_jd(m_JD);
		m_mars.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
	}
	
	if (m_jupiter.get_mag(m_JD) < m_clip_mag_max) { 
		m_jupiter.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_jupiter.set_render_jd(m_JD);
		m_jupiter.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
	}
	
	if (m_saturn.get_mag(m_JD) < m_clip_mag_max) { 
		m_saturn.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_saturn.set_render_jd(m_JD);
		m_saturn.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
	}
	
	if (m_uranus.get_mag(m_JD) < m_clip_mag_max) { 
		m_uranus.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_uranus.set_render_jd(m_JD);
		m_uranus.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
	}
	
	if (m_neptune.get_mag(m_JD) < m_clip_mag_max) { 
		m_neptune.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_neptune.set_render_jd(m_JD);
		m_neptune.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
	}
	
	if (m_pluto.get_mag(m_JD) < m_clip_mag_max) { 
		m_pluto.get_equ_posn(m_JD, ra, dec);
		transform (ra, dec, ra_offset);
		m_pluto.set_render_jd(m_JD);
		m_pluto.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd);
	}	

	if (m_is_ra_over || m_is_ra_under) {
		
		// get ra offset
		if (m_is_ra_under)
			ra_offset = m_ra_offset + MAX_RA; //rhs
		else
			ra_offset = -MAX_RA; //lhs	
		
			if (m_mercury.get_mag(m_JD) < m_clip_mag_max) { 
				m_mercury.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_mercury.set_render_jd(m_JD);
				m_mercury.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd);
			}		
			
			if (m_venus.get_mag(m_JD) < m_clip_mag_max) { 
				m_venus.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_venus.set_render_jd(m_JD);
				m_venus.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
			}
			
			if (m_mars.get_mag(m_JD) < m_clip_mag_max) { 
				m_mars.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_mars.set_render_jd(m_JD);
				m_mars.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
			}
			
			if (m_jupiter.get_mag(m_JD) < m_clip_mag_max) { 
				m_jupiter.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_jupiter.set_render_jd(m_JD);
				m_jupiter.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
			}
			
			if (m_saturn.get_mag(m_JD) < m_clip_mag_max) { 
				m_saturn.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_saturn.set_render_jd(m_JD);
				m_saturn.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
			}
			
			if (m_uranus.get_mag(m_JD) < m_clip_mag_max) { 
				m_uranus.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_uranus.set_render_jd(m_JD);
				m_uranus.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
			}
			
			if (m_neptune.get_mag(m_JD) < m_clip_mag_max) { 
				m_neptune.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_neptune.set_render_jd(m_JD);
				m_neptune.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd); 
			}
			
			if (m_pluto.get_mag(m_JD) < m_clip_mag_max) { 
				m_pluto.get_equ_posn(m_JD, ra, dec);
				transform (ra, dec, ra_offset);
				m_pluto.set_render_jd(m_JD);
				m_pluto.render (ra, dec, m_clip_mag_max, *m_object_group, false, m_ra_ppd);
			}
		}			
}

/*! \fn void SkySpherical::render_grid()
* 
* Render grid on virtual sky.
*/
void SkySpherical::render_grid()
{
	return; // for now
	
	std::vector<Grid::GridLine> ra_points, ra_overlap_points;
	std::vector<Grid::GridLine> dec_points, dec_overlap_points;
	std::vector<Grid::GridLine>::iterator ra;
	std::vector<Grid::GridLine>::iterator dec;
	double ra_offset;
	
	// clip and get lines
	m_grid.clip(m_clip_ra_min, m_clip_dec_min, m_clip_ra_max, m_clip_dec_max);
	std::cout << " bpath ra lines " << m_grid.get_ra_lines(ra_points);
	std::cout << " bpath dec lines " << m_grid.get_dec_lines(dec_points);
	
	// are we overlapping
	if (m_is_ra_over || m_is_ra_under) {
		m_grid.clip(m_clip_ra_min_overlap, m_clip_dec_min, m_clip_ra_max_overlap, m_clip_dec_max);
		m_grid.get_ra_lines(ra_overlap_points, true);
		m_grid.get_dec_lines(dec_overlap_points);
	}
	
	// calc offset
	if (m_is_ra_over)
		ra_offset = MIN_RA;
	else
		ra_offset = m_ra_offset;
	
	// now render ra grid
	for (ra = ra_points.begin(); ra != ra_points.end(); ra++) {
		double mid_x, mid_y;
		Glib::RefPtr<Gnome::Canvas::PathDef> path 
			= Gnome::Canvas::PathDef::create();

		mid_x = (*ra).x1 + (((*ra).x2 - (*ra).x1) / 2.0);
		mid_y = (*ra).y1 + (((*ra).y2 - (*ra).y1) / 2.0);
		
		transform_grid((*ra).x1, (*ra).y1, ra_offset);
		transform_grid(mid_x, mid_y, ra_offset);
		transform_grid((*ra).x2, (*ra).y2, ra_offset);
    	path->moveto((*ra).x1, (*ra).y1);
    	path->curveto((*ra).x1, (*ra).y1, mid_x, mid_y, (*ra).x2, (*ra).y2);
    
		Gnome::Canvas::Bpath* line = manage(new Gnome::Canvas::Bpath(*m_grid_group));
		line->set_bpath(path);
		line->property_outline_color () = "grey";
		line->property_width_pixels () = 1;	
	}
	
	// render dec grid
	for (dec = dec_points.begin(); dec != dec_points.end(); dec++) {
		double mid_x, mid_y;
		Glib::RefPtr<Gnome::Canvas::PathDef> path 
			= Gnome::Canvas::PathDef::create();
		
		mid_x = (*dec).x1 + (((*dec).x2 - (*dec).x1) / 2.0);
		mid_y = (*dec).y1 + (((*dec).y2 - (*dec).y1) / 2.0);

		transform_grid((*dec).x1, (*dec).y1, ra_offset);
		transform_grid(mid_x, mid_y, ra_offset);
		transform_grid((*dec).x2, (*dec).y2, ra_offset);
    	path->moveto((*dec).x1, (*dec).y1);
    	path->curveto((*dec).x1, (*dec).y1,
				mid_x, mid_y,
				(*dec).x2, (*dec).y2);
    
		Gnome::Canvas::Bpath* line = manage(new Gnome::Canvas::Bpath(*m_grid_group));
		line->set_bpath(path);
		line->property_outline_color () = "grey";
		line->property_width_pixels () = 1;	
	}
	
	if (m_is_ra_over || m_is_ra_under) {
		
		// get ra offset
		if (m_is_ra_under)
			ra_offset = m_ra_offset + MAX_RA; //rhs
		else
			ra_offset = -MAX_RA; //lhs
		
		// now render ra grid
		for (ra = ra_overlap_points.begin(); ra != ra_overlap_points.end(); ra++) {
			double mid_x, mid_y;
			Glib::RefPtr<Gnome::Canvas::PathDef> path 
				= Gnome::Canvas::PathDef::create();
	
			mid_x = (*ra).x1 + (((*ra).x2 - (*ra).x1) / 2.0);
			mid_y = (*ra).y1 + (((*ra).y2 - (*ra).y1) / 2.0);
			
			transform_grid((*ra).x1, (*ra).y1, ra_offset);
			transform_grid(mid_x, mid_y, ra_offset);
			transform_grid((*ra).x2, (*ra).y2, ra_offset);
			path->moveto((*ra).x1, (*ra).y1);
			path->curveto((*ra).x1, (*ra).y1,
					mid_x, mid_y,
					(*ra).x2, (*ra).y2);
		
			Gnome::Canvas::Bpath* line = manage(new Gnome::Canvas::Bpath(*m_grid_group));
			line->set_bpath(path);
			line->property_outline_color () = "grey";
			line->property_width_pixels () = 1;	
		}
		
		// render dec grid
		for (dec = dec_overlap_points.begin(); dec != dec_overlap_points.end(); dec++) {
			double mid_x, mid_y;
			Glib::RefPtr<Gnome::Canvas::PathDef> path 
				= Gnome::Canvas::PathDef::create();
	
			mid_x = (*dec).x1 + (((*dec).x2 - (*dec).x1) / 2.0);
			mid_y = (*dec).y1 + (((*dec).y2 - (*dec).y1) / 2.0);
			
			transform_grid((*dec).x1, (*dec).y1, ra_offset);
			transform_grid(mid_x, mid_y, ra_offset);
			transform_grid((*dec).x2, (*dec).y2, ra_offset);
			path->moveto((*dec).x1, (*dec).y1);
			path->curveto((*dec).x1, (*dec).y1,
					mid_x, mid_y,
					(*dec).x2, (*dec).y2);
		
			Gnome::Canvas::Bpath* line = manage(new Gnome::Canvas::Bpath(*m_grid_group));
			line->set_bpath(path);
			line->property_outline_color () = "grey";
			line->property_width_pixels () = 1;		
		}
	}
}

/*! \fn void SkySpherical::render_const_lines()
*
* Render virtual sky constellation lines.
*/
void SkySpherical::render_const_lines()
{
	std::vector<Constellation::ConstLine> lines, overlap_lines;
	std::vector<Constellation::ConstLine>::iterator i;
	Gnome::Canvas::Line* line;
	double ra_offset;
	
	// delete constellations
	delete m_const_group;
	m_const_group = Gtk::manage (new Gnome::Canvas::Group (*m_root, 0, 0));
	
	// clip and get lines
	m_constellation.clip(m_clip_ra_min, m_clip_dec_min, m_clip_ra_max, m_clip_dec_max);
	std::cout << " ra lines " << m_constellation.get_lines(lines);
	std::cout << " ratio " << m_canvas_ratio << std::endl;
	
	// are we overlapping
	if (m_is_ra_over || m_is_ra_under) {
		m_constellation.clip(m_clip_ra_min_overlap, m_clip_dec_min, m_clip_ra_max_overlap, m_clip_dec_max);
		m_constellation.get_lines(overlap_lines);
	}
	
	// calc offset
	if (m_is_ra_over)
		ra_offset = MIN_RA;
	else
		ra_offset = m_ra_offset;
	
	// now render each line
	for (i = lines.begin(); i != lines.end(); i++) {
		Gnome::Canvas::Points line_points;

		transform((*i).ra1, (*i).dec1, ra_offset);
		if (!is_visible((*i).ra1, (*i).dec1))
			continue;
		transform((*i).ra2, (*i).dec2, ra_offset);
		if (!is_visible((*i).ra2, (*i).dec2))
			continue;
		 
		line_points.push_back(Gnome::Art::Point((*i).ra1, (*i).dec1));
		line_points.push_back(Gnome::Art::Point((*i).ra2, (*i).dec2));
		line = Gtk::manage(new Gnome::Canvas::Line(*m_const_group, line_points));
		*line << Gnome::Canvas::Properties::fill_color("blue");		
	}
	
	if (m_is_ra_over || m_is_ra_under) {
		
		// get ra offset
		if (m_is_ra_under)
			ra_offset = m_ra_offset + MAX_RA; //rhs
		else
			ra_offset = -MAX_RA; //lhs
		
		// now render lines
		for (i = overlap_lines.begin(); i != overlap_lines.end(); i++) {
			Gnome::Canvas::Points line_points;
	
			transform((*i).ra1, (*i).dec1, ra_offset);
			if (!is_visible((*i).ra1, (*i).dec1))
				continue;
			transform((*i).ra2, (*i).dec2, ra_offset);
			if (!is_visible((*i).ra2, (*i).dec2))
				continue;
			
			line_points.push_back(Gnome::Art::Point((*i).ra1, (*i).dec1));
			line_points.push_back(Gnome::Art::Point((*i).ra2, (*i).dec2));
			line = Gtk::manage(new Gnome::Canvas::Line(*m_const_group, line_points));
			*line << Gnome::Canvas::Properties::fill_color("blue");		
		}
	}
}

/*! \fn void SkySpherical::render_const_bounds()
*
* Render virtual sky constellation boundaries
*/
void SkySpherical::render_const_bounds()
{
}

/*! \fn void SkySpherical::render_const_names()
*
* Render virtual sky constellation names.
*/
void SkySpherical::render_const_names()
{
}

/*! \fn void SkySpherical::get_position (double x, double y, double& ra, double& dec);
* \brief get sky ra,dec at x,y coordinates
*/
void SkySpherical::get_position (double x, double y, double& ra, double& dec)
{
}

/*! \fn void SkySpherical::transform_grid (double& x, double& y, double dec_offset)
* \param x X coordinate
* \param y Y coordinate
* \param object Astro object
*
* Transform the objects RA nad DEC into virtual sky coordinates.
*/
void SkySpherical::transform_grid (double& x, double& y, double ra_offset)
{
	y += m_centre_dec;
	transform(x, y, ra_offset);
}

/*! \fn void SkySpherical::transform(double& x, double& y, Castor::AstroObject* object)
* \param x X coordinate
* \param y Y coordinate
* \param object Astro object
*
* Transform the objects RA nad DEC into virtual sky coordinates.
*/
void SkySpherical::transform(double& x, double& y, double ra_offset)
{
	double xd,yd,zd;
	double ratio;
	
	// subtract centre 
	x -= m_centre_ra;
	y -= m_centre_dec;
	
	// convert to radians
	x = (x / 360.0) * 2.0 * M_PI;
	y = (y / 360.0) * 2.0 * M_PI;
	
	// project to spherical vsky
	xd = cos(y) * sin(x); 
	yd = sin(y);
	zd = cos(y) * cos(x);
	x = xd / (1.0 + zd);
	y = yd / (1.0 + zd);
	//std::cout << x << " " << y << std::endl;
	// convert back to canvas scale
	ratio = MAX_FOV / m_fov;
	x = (m_canvas_width / 2) - ((x * m_canvas_height / 2.0) * ratio);
	y = (m_canvas_height / 2) - ((y * m_canvas_height / 2.0) * ratio);
}


/*! \fn virtual bool is_visible(double x, double y) = 0;
* Is the object visible ?
*/
bool SkySpherical::is_visible(double x, double y)
{
	double dx = x - (m_canvas_width / 2);
	double dy = y - (m_canvas_height / 2);
	double dist = dx * dx + dy * dy;
	dist = sqrt (dist);

	if (dist > m_outer_size)
		return false;
	else
		return true;
}

void SkySpherical::render_basic()
{
	// delete existing
	delete m_object_group;
	m_object_group = Gtk::manage (new Gnome::Canvas::Group (*m_root, 0, 0));
	
	// render outer circle
	m_outer_size = ((m_canvas_height / 2.0) * (MAX_FOV / m_fov));
	if (m_outer_size > 1.5 * m_canvas_width)
		return;
	double xmin = m_canvas_width / 2.0 - m_outer_size;
	double xmax = m_canvas_width / 2.0 + m_outer_size;
	double ymin = m_canvas_height / 2.0 - m_outer_size;
	double ymax = m_canvas_height / 2.0 + m_outer_size;
	
	Gnome::Canvas::Ellipse * outer_bounds = manage(new Gnome::Canvas::Ellipse(*m_object_group,
		xmin, ymin, xmax, ymax));
	outer_bounds->property_outline_color () = "grey";
	outer_bounds->property_width_pixels () = 1;	
	
	std::cout <<" outer size " << m_outer_size << std::endl;
}

};


syntax highlighted by Code2HTML, v. 0.9.1