/***************************************************************************
                          ksasteroid.cpp  -  Trinity Desktop Planetarium
                             -------------------
    begin                : Wed 19 Feb 2003
    copyright            : (C) 2001 by Jason Harris
    email                : jharris@30doradus.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <kdebug.h>

#include "ksasteroid.h"
#include "dms.h"
#include "ksnumbers.h"
#include "ksutils.h"
#include "kstarsdata.h"

KSAsteroid::KSAsteroid( KStarsData *_kd, TQString s, TQString imfile,
		long double _JD, double _a, double _e, dms _i, dms _w, dms _Node, dms _M, double _H )
 : KSPlanetBase(_kd, s, imfile), kd(_kd), JD(_JD), a(_a), e(_e), H(_H), i(_i), w(_w), M(_M), N(_Node) {

	setType( 10 ); //Asteroid
	setMag( H );
	//Compute the orbital Period from Kepler's 3rd law:
	P = 365.2568984 * pow(a, 1.5); //period in days
}

bool KSAsteroid::findGeocentricPosition( const KSNumbers *num, const KSPlanetBase *Earth ) {
	//Precess the longitude of the Ascending Node to the desired epoch:
	dms n = dms( double( N.Degrees() - 3.82394E-5 * ( num->julianDay() - J2000 )) ).reduce();

	//determine the mean anomaly for the desired date.  This is the mean anomaly for the
	//ephemeis epoch, plus the number of days between the desired date and ephemeris epoch,
	//times the asteroid's mean daily motion (360/P):
	dms m = dms( double( M.Degrees() + ( num->julianDay() - JD ) * 360.0/P ) ).reduce();
	double sinm, cosm;
	m.SinCos( sinm, cosm );

	//compute eccentric anomaly:
	double E = m.Degrees() + e*180.0/dms::PI * sinm * ( 1.0 + e*cosm );

	if ( e > 0.05 ) { //need more accurate approximation, iterate...
		double E0;
		int iter(0);
		do {
			E0 = E;
			iter++;
			E = E0 - ( E0 - e*180.0/dms::PI *sin( E0*dms::DegToRad ) - m.Degrees() )/(1 - e*cos( E0*dms::DegToRad ) );
		} while ( fabs( E - E0 ) > 0.001 && iter < 1000 );
	}

	double sinE, cosE;
	dms E1( E );
	E1.SinCos( sinE, cosE );

	double xv = a * ( cosE - e );
	double yv = a * sqrt( 1.0 - e*e ) * sinE;

	//v is the true anomaly; r is the distance from the Sun

	double v = atan( yv/xv ) / dms::DegToRad;
	//resolve atan ambiguity
	if ( xv < 0.0 ) v += 180.0;

	double r = sqrt( xv*xv + yv*yv );

	//vw is the sum of the true anomaly and the argument of perihelion
	dms vw( v + w.Degrees() );
	double sinN, cosN, sinvw, cosvw, sini, cosi;

	N.SinCos( sinN, cosN );
	vw.SinCos( sinvw, cosvw );
	i.SinCos( sini, cosi );

	//xh, yh, zh are the heliocentric cartesian coords with the ecliptic plane congruent with zh=0.
	double xh = r * ( cosN * cosvw - sinN * sinvw * cosi );
	double yh = r * ( sinN * cosvw + cosN * sinvw * cosi );
	double zh = r * ( sinvw * sini );

	//the spherical ecliptic coordinates:
	double ELongRad = atan( yh/xh );
	//resolve atan ambiguity
	if ( xh < 0.0 ) ELongRad += dms::PI;
	double ELatRad = atan( zh/r );  //(r can't possibly be negative, so no atan ambiguity)

	helEcPos.longitude.setRadians( ELongRad );
	helEcPos.latitude.setRadians( ELatRad );
	setRsun( r );

	if ( Earth ) {
		//xe, ye, ze are the Earth's heliocentric cartesian coords
		double cosBe, sinBe, cosLe, sinLe;
		Earth->ecLong()->SinCos( sinLe, cosLe );
		Earth->ecLat()->SinCos( sinBe, cosBe );
	
		double xe = Earth->rsun() * cosBe * cosLe;
		double ye = Earth->rsun() * cosBe * sinLe;
		double ze = Earth->rsun() * sinBe;
	
		//convert to geocentric ecliptic coordinates by subtracting Earth's coords:
		xh -= xe;
		yh -= ye;
		zh -= ze;
	}

	//the spherical geocentricecliptic coordinates:
	ELongRad = atan( yh/xh );
	//resolve atan ambiguity
	if ( xh < 0.0 ) ELongRad += dms::PI;

	double rr = sqrt( xh*xh + yh*yh + zh*zh );
	ELatRad = atan( zh/rr );  //(rr can't possibly be negative, so no atan ambiguity)

	ep.longitude.setRadians( ELongRad );
	ep.latitude.setRadians( ELatRad );
	if ( Earth ) setRearth( Earth );
	
	EclipticToEquatorial( num->obliquity() );
	nutate( num );
	aberrate( num );

	return true;
}

//Unused virtual function from KSPlanetBase
bool KSAsteroid::loadData() { return false; }

