/***************************************************************************
skymap . cpp - Trinity Desktop Planetarium
- - - - - - - - - - - - - - - - - - -
begin : Sat Feb 10 2001
copyright : ( C ) 2001 by Jason Harris
email : jharris @ 30 doradus . 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 <tdeapplication.h>
# include <tdeconfig.h>
# include <kiconloader.h>
# include <kstatusbar.h>
# include <kmessagebox.h>
# include <tdeaction.h>
# include <kstandarddirs.h>
# include <tqmemarray.h>
# include <tqpointarray.h>
# include <tqcursor.h>
# include <tqbitmap.h>
# include <tqpainter.h>
# include <math.h>
# include <stdlib.h>
# include <unistd.h>
# include "skymap.h"
# include "Options.h"
# include "kstars.h"
# include "kstarsdata.h"
# include "imageviewer.h"
# include "infoboxes.h"
# include "detaildialog.h"
# include "addlinkdialog.h"
# include "kspopupmenu.h"
# include "simclock.h"
# include "skyobject.h"
# include "deepskyobject.h"
# include "ksmoon.h"
# include "ksasteroid.h"
# include "kscomet.h"
# include "starobject.h"
# include "customcatalog.h"
SkyMap : : SkyMap ( KStarsData * d , TQWidget * parent , const char * name )
: TQWidget ( parent , name ) , computeSkymap ( true ) , angularDistanceMode ( false ) ,
ksw ( 0 ) , data ( d ) , pmenu ( 0 ) , sky ( 0 ) , sky2 ( 0 ) , IBoxes ( 0 ) ,
ClickedObject ( 0 ) , FocusObject ( 0 ) , TransientObject ( 0 ) ,
starpix ( 0 ) , pts ( 0 ) , sp ( 0 )
{
if ( parent ) ksw = ( KStars * ) parent - > parent ( ) ;
else ksw = 0 ;
pts = new TQPointArray ( 2000 ) ; // points for milkyway and horizon
sp = new SkyPoint ( ) ; // needed by coordinate grid
ZoomRect = TQRect ( ) ;
setDefaultMouseCursor ( ) ; // set the cross cursor
// load the pixmaps of stars
starpix = new StarPixmap ( data - > colorScheme ( ) - > starColorMode ( ) , data - > colorScheme ( ) - > starColorIntensity ( ) ) ;
setBackgroundColor ( TQColor ( data - > colorScheme ( ) - > colorNamed ( " SkyColor " ) ) ) ;
setBackgroundMode ( TQWidget : : NoBackground ) ;
setFocusPolicy ( TQ_StrongFocus ) ;
setMinimumSize ( 380 , 250 ) ;
setSizePolicy ( TQSizePolicy ( TQSizePolicy : : Expanding , TQSizePolicy : : Expanding ) ) ;
setMouseTracking ( true ) ; //Generate MouseMove events!
midMouseButtonDown = false ;
mouseButtonDown = false ;
slewing = false ;
clockSlewing = false ;
ClickedObject = NULL ;
FocusObject = NULL ;
sky = new TQPixmap ( ) ;
sky2 = new TQPixmap ( ) ;
pmenu = new KSPopupMenu ( ksw ) ;
//Initialize Transient label stuff
TransientTimeout = 100 ; //fade label color every 0.2 sec
connect ( & HoverTimer , TQT_SIGNAL ( timeout ( ) ) , this , TQT_SLOT ( slotTransientLabel ( ) ) ) ;
connect ( & TransientTimer , TQT_SIGNAL ( timeout ( ) ) , this , TQT_SLOT ( slotTransientTimeout ( ) ) ) ;
IBoxes = new InfoBoxes ( Options : : windowWidth ( ) , Options : : windowHeight ( ) ,
Options : : positionTimeBox ( ) , Options : : shadeTimeBox ( ) ,
Options : : positionGeoBox ( ) , Options : : shadeGeoBox ( ) ,
Options : : positionFocusBox ( ) , Options : : shadeFocusBox ( ) ,
data - > colorScheme ( ) - > colorNamed ( " BoxTextColor " ) ,
data - > colorScheme ( ) - > colorNamed ( " BoxGrabColor " ) ,
data - > colorScheme ( ) - > colorNamed ( " BoxBGColor " ) ) ;
IBoxes - > showTimeBox ( Options : : showTimeBox ( ) ) ;
IBoxes - > showFocusBox ( Options : : showFocusBox ( ) ) ;
IBoxes - > showGeoBox ( Options : : showGeoBox ( ) ) ;
IBoxes - > timeBox ( ) - > setAnchorFlag ( Options : : stickyTimeBox ( ) ) ;
IBoxes - > geoBox ( ) - > setAnchorFlag ( Options : : stickyGeoBox ( ) ) ;
IBoxes - > focusBox ( ) - > setAnchorFlag ( Options : : stickyFocusBox ( ) ) ;
IBoxes - > geoChanged ( data - > geo ( ) ) ;
connect ( IBoxes - > timeBox ( ) , TQT_SIGNAL ( shaded ( bool ) ) , data , TQT_SLOT ( saveTimeBoxShaded ( bool ) ) ) ;
connect ( IBoxes - > geoBox ( ) , TQT_SIGNAL ( shaded ( bool ) ) , data , TQT_SLOT ( saveGeoBoxShaded ( bool ) ) ) ;
connect ( IBoxes - > focusBox ( ) , TQT_SIGNAL ( shaded ( bool ) ) , data , TQT_SLOT ( saveFocusBoxShaded ( bool ) ) ) ;
connect ( IBoxes - > timeBox ( ) , TQT_SIGNAL ( moved ( TQPoint ) ) , data , TQT_SLOT ( saveTimeBoxPos ( TQPoint ) ) ) ;
connect ( IBoxes - > geoBox ( ) , TQT_SIGNAL ( moved ( TQPoint ) ) , data , TQT_SLOT ( saveGeoBoxPos ( TQPoint ) ) ) ;
connect ( IBoxes - > focusBox ( ) , TQT_SIGNAL ( moved ( TQPoint ) ) , data , TQT_SLOT ( saveFocusBoxPos ( TQPoint ) ) ) ;
connect ( this , TQT_SIGNAL ( destinationChanged ( ) ) , this , TQT_SLOT ( slewFocus ( ) ) ) ;
//Initialize Refraction correction lookup table arrays. RefractCorr1 is for calculating
//the apparent altitude from the true altitude, and RefractCorr2 is for the reverse.
for ( unsigned int index = 0 ; index < 184 ; + + index ) {
double alt = - 1.75 + index * 0.5 ; //start at -1.75 degrees to get midpoint value for each interval.
RefractCorr1 [ index ] = 1.02 / tan ( dms : : PI * ( alt + 10.3 / ( alt + 5.11 ) ) / 180.0 ) / 60.0 ; //correction in degrees.
RefractCorr2 [ index ] = - 1.0 / tan ( dms : : PI * ( alt + 7.31 / ( alt + 4.4 ) ) / 180.0 ) / 60.0 ;
}
}
SkyMap : : ~ SkyMap ( ) {
delete starpix ;
delete pts ;
delete sp ;
delete sky ;
delete sky2 ;
delete pmenu ;
delete IBoxes ;
//Deprecated...DeepSkyObject dtor now handles this itself.
/*//delete any remaining object Image pointers
for ( DeepSkyObject * obj = data - > deepSkyListMessier . first ( ) ; obj ; obj = data - > deepSkyListMessier . next ( ) ) {
if ( obj - > image ( ) ) obj - > deleteImage ( ) ;
}
for ( DeepSkyObject * obj = data - > deepSkyListNGC . first ( ) ; obj ; obj = data - > deepSkyListNGC . next ( ) ) {
if ( obj - > image ( ) ) obj - > deleteImage ( ) ;
}
for ( DeepSkyObject * obj = data - > deepSkyListIC . first ( ) ; obj ; obj = data - > deepSkyListIC . next ( ) ) {
if ( obj - > image ( ) ) obj - > deleteImage ( ) ;
}
for ( DeepSkyObject * obj = data - > deepSkyListOther . first ( ) ; obj ; obj = data - > deepSkyListOther . next ( ) ) {
if ( obj - > image ( ) ) obj - > deleteImage ( ) ;
} */
}
void SkyMap : : setGeometry ( int x , int y , int w , int h ) {
TQWidget : : setGeometry ( x , y , w , h ) ;
sky - > resize ( w , h ) ;
sky2 - > resize ( w , h ) ;
}
void SkyMap : : setGeometry ( const TQRect & r ) {
TQWidget : : setGeometry ( r ) ;
sky - > resize ( r . width ( ) , r . height ( ) ) ;
sky2 - > resize ( r . width ( ) , r . height ( ) ) ;
}
void SkyMap : : showFocusCoords ( bool coordsOnly ) {
if ( ! coordsOnly ) {
//display object info in infoBoxes
TQString oname ;
oname = i18n ( " nothing " ) ;
if ( focusObject ( ) ! = NULL & & Options : : isTracking ( ) )
oname = focusObject ( ) - > translatedLongName ( ) ;
infoBoxes ( ) - > focusObjChanged ( oname ) ;
}
if ( Options : : useAltAz ( ) & & Options : : useRefraction ( ) ) {
SkyPoint corrFocus ( * ( focus ( ) ) ) ;
corrFocus . setAlt ( refract ( focus ( ) - > alt ( ) , false ) ) ;
corrFocus . HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
corrFocus . setAlt ( refract ( focus ( ) - > alt ( ) , true ) ) ;
infoBoxes ( ) - > focusCoordChanged ( & corrFocus ) ;
} else {
infoBoxes ( ) - > focusCoordChanged ( focus ( ) ) ;
}
}
SkyObject * SkyMap : : objectNearest ( SkyPoint * p ) {
double r0 = 200.0 / Options : : zoomFactor ( ) ; //the maximum search radius
double rmin = r0 ;
//Search stars database for nearby object.
double rstar_min = r0 ;
double starmag_min = 20.0 ; //absurd initial value
int istar_min = - 1 ;
if ( Options : : showStars ( ) ) { //Can only click on a star if it's being drawn!
//test RA and dec to see if this star is roughly nearby
for ( register unsigned int i = 0 ; i < data - > starList . count ( ) ; + + i ) {
SkyObject * test = ( SkyObject * ) data - > starList . at ( i ) ;
double dRA = test - > ra ( ) - > Hours ( ) - p - > ra ( ) - > Hours ( ) ;
double dDec = test - > dec ( ) - > Degrees ( ) - p - > dec ( ) - > Degrees ( ) ;
//determine angular distance between this object and mouse cursor
double f = 15.0 * cos ( test - > dec ( ) - > radians ( ) ) ;
double r = f * f * dRA * dRA + dDec * dDec ; //no need to take sqrt, we just want to ID smallest value.
if ( r < r0 & & test - > mag ( ) < starmag_min ) {
istar_min = i ;
rstar_min = r ;
starmag_min = test - > mag ( ) ;
}
}
}
//Next, find the nearest solar system body within r0
double r = 0.0 ;
double rsolar_min = r0 ;
SkyObject * solarminobj = NULL ;
if ( Options : : showPlanets ( ) )
solarminobj = data - > PCat - > findClosest ( p , r ) ;
if ( r < r0 ) {
rsolar_min = r ;
} else {
solarminobj = NULL ;
}
//Moon
if ( Options : : showMoon ( ) ) {
double dRA = data - > Moon - > ra ( ) - > Hours ( ) - p - > ra ( ) - > Hours ( ) ;
double dDec = data - > Moon - > dec ( ) - > Degrees ( ) - p - > dec ( ) - > Degrees ( ) ;
double f = 15.0 * cos ( data - > Moon - > dec ( ) - > radians ( ) ) ;
r = f * f * dRA * dRA + dDec * dDec ; //no need to take sqrt, we just want to ID smallest value.
if ( r < rsolar_min ) {
solarminobj = data - > Moon ;
rsolar_min = r ;
}
}
//Asteroids
if ( Options : : showAsteroids ( ) ) {
for ( KSAsteroid * ast = data - > asteroidList . first ( ) ; ast ; ast = data - > asteroidList . next ( ) ) {
//test RA and dec to see if this object is roughly nearby
double dRA = ast - > ra ( ) - > Hours ( ) - p - > ra ( ) - > Hours ( ) ;
double dDec = ast - > dec ( ) - > Degrees ( ) - p - > dec ( ) - > Degrees ( ) ;
double f = 15.0 * cos ( ast - > dec ( ) - > radians ( ) ) ;
double r = f * f * dRA * dRA + dDec * dDec ; //no need to take sqrt, we just want to ID smallest value.
if ( r < rsolar_min & & ast - > mag ( ) < Options : : magLimitAsteroid ( ) ) {
solarminobj = ast ;
rsolar_min = r ;
}
}
}
//Comets
if ( Options : : showComets ( ) ) {
for ( KSComet * com = data - > cometList . first ( ) ; com ; com = data - > cometList . next ( ) ) {
//test RA and dec to see if this object is roughly nearby
double dRA = com - > ra ( ) - > Hours ( ) - p - > ra ( ) - > Hours ( ) ;
double dDec = com - > dec ( ) - > Degrees ( ) - p - > dec ( ) - > Degrees ( ) ;
double f = 15.0 * cos ( com - > dec ( ) - > radians ( ) ) ;
double r = f * f * dRA * dRA + dDec * dDec ; //no need to take sqrt, we just want to ID smallest value.
if ( r < rsolar_min ) {
solarminobj = com ;
rsolar_min = r ;
}
}
}
//Next, search for nearest deep-sky object within r0
double rmess_min = r0 ;
double rngc_min = r0 ;
double ric_min = r0 ;
double rother_min = r0 ;
int imess_min = - 1 ;
int ingc_min = - 1 ;
int iic_min = - 1 ;
int iother_min = - 1 ;
for ( DeepSkyObject * o = data - > deepSkyList . first ( ) ; o ; o = data - > deepSkyList . next ( ) ) {
bool checkObject = false ;
if ( o - > isCatalogM ( ) & &
( Options : : showMessier ( ) | | Options : : showMessierImages ( ) ) ) checkObject = true ;
if ( o - > isCatalogNGC ( ) & & Options : : showNGC ( ) ) checkObject = true ;
if ( o - > isCatalogIC ( ) & & Options : : showIC ( ) ) checkObject = true ;
if ( o - > catalog ( ) . isEmpty ( ) & & Options : : showOther ( ) ) checkObject = true ;
if ( checkObject ) {
//test RA and dec to see if this object is roughly nearby
double dRA = o - > ra ( ) - > Hours ( ) - p - > ra ( ) - > Hours ( ) ;
double dDec = o - > dec ( ) - > Degrees ( ) - p - > dec ( ) - > Degrees ( ) ;
double f = 15.0 * cos ( o - > dec ( ) - > radians ( ) ) ;
double r = f * f * dRA * dRA + dDec * dDec ; //no need to take sqrt, we just want to ID smallest value.
if ( o - > isCatalogM ( ) & & r < rmess_min ) {
imess_min = data - > deepSkyList . at ( ) ;
rmess_min = r ;
}
if ( o - > isCatalogNGC ( ) & & r < rngc_min ) {
ingc_min = data - > deepSkyList . at ( ) ;
rngc_min = r ;
}
if ( o - > isCatalogIC ( ) & & r < ric_min ) {
iic_min = data - > deepSkyList . at ( ) ;
ric_min = r ;
}
if ( o - > catalog ( ) . isEmpty ( ) & & r < rother_min ) {
iother_min = data - > deepSkyList . at ( ) ;
rother_min = r ;
}
}
}
//Next, search for nearest object within r0 among the custom catalogs
double rcust_min = r0 ;
int icust_min = - 1 ;
int icust_cat = - 1 ;
for ( register unsigned int j = 0 ; j < data - > CustomCatalogs . count ( ) ; + + j ) {
if ( Options : : showCatalog ( ) [ j ] ) {
TQPtrList < SkyObject > catList = data - > CustomCatalogs . at ( j ) - > objList ( ) ;
for ( register unsigned int i = 0 ; i < catList . count ( ) ; + + i ) {
//test RA and dec to see if this object is roughly nearby
SkyObject * test = ( SkyObject * ) catList . at ( i ) ;
double dRA = test - > ra ( ) - > Hours ( ) - p - > ra ( ) - > Hours ( ) ;
double dDec = test - > dec ( ) - > Degrees ( ) - p - > dec ( ) - > Degrees ( ) ;
double f = 15.0 * cos ( test - > dec ( ) - > radians ( ) ) ;
double r = f * f * dRA * dRA + dDec * dDec ; //no need to take sqrt, we just want to ID smallest value.
if ( r < rcust_min ) {
icust_cat = j ;
icust_min = i ;
rcust_min = r ;
}
}
}
}
int jmin ( - 1 ) ;
int icat ( - 1 ) ;
//Among the objects selected within r0, prioritize the selection by catalog:
//Planets, Messier, NGC, IC, stars
if ( istar_min > = 0 & & rstar_min < r0 ) {
rmin = rstar_min ;
icat = 0 ; //set catalog to star
}
//IC object overrides star, unless star is twice as close as IC object
if ( iic_min > = 0 & & ric_min < r0 & & rmin > 0.5 * ric_min ) {
rmin = ric_min ;
icat = 1 ; //set catalog to Deep Sky
jmin = iic_min ;
}
//NGC object overrides previous selection, unless previous is twice as close
if ( ingc_min > = 0 & & rngc_min < r0 & & rmin > 0.5 * rngc_min ) {
rmin = rngc_min ;
icat = 1 ; //set catalog to Deep Sky
jmin = ingc_min ;
}
//"other" object overrides previous selection, unless previous is twice as close
if ( iother_min > = 0 & & rother_min < r0 & & rmin > 0.5 * rother_min ) {
rmin = rother_min ;
icat = 1 ; //set catalog to Deep Sky
jmin = iother_min ;
}
//Messier object overrides previous selection, unless previous is twice as close
if ( imess_min > = 0 & & rmess_min < r0 & & rmin > 0.5 * rmess_min ) {
rmin = rmess_min ;
icat = 1 ; //set catalog to Deep Sky
jmin = imess_min ;
}
//Custom object overrides previous selection, unless previous is twice as close
if ( icust_min > = 0 & & rcust_min < r0 & & rmin > 0.5 * rcust_min ) {
rmin = rcust_min ;
icat = 2 ; //set catalog to Custom
}
//Solar system body overrides previous selection, unless previous selection is twice as close
if ( solarminobj ! = NULL & & rmin > 0.5 * rsolar_min ) {
rmin = rsolar_min ;
icat = 3 ; //set catalog to solar system
}
TQPtrList < SkyObject > cat ;
switch ( icat ) {
case 0 : //star
return data - > starList . at ( istar_min ) ;
break ;
case 1 : //Deep-Sky Objects
return data - > deepSkyList . at ( jmin ) ;
break ;
case 2 : //Custom Catalog Object
cat = data - > CustomCatalogs . at ( icust_cat ) - > objList ( ) ;
return cat . at ( icust_min ) ;
break ;
case 3 : //solar system object
return solarminobj ;
break ;
default : //no object found
return NULL ;
break ;
}
}
void SkyMap : : slotTransientLabel ( void ) {
//This function is only called if the HoverTimer manages to timeout.
//(HoverTimer is restarted with every mouseMoveEvent; so if it times
//out, that means there was no mouse movement for HOVER_INTERVAL msec.)
//Identify the object nearest to the mouse cursor as the
//TransientObject. The TransientObject is automatically labeled
//in SkyMap::paintEvent().
//Note that when the TransientObject pointer is not NULL, the next
//mouseMoveEvent calls fadeTransientLabel(), which will fade out the
//TransientLabel and then set TransientObject to NULL.
//
//Do not show a transient label if the map is in motion, or if the mouse
//pointer is below the opaque horizon, or if the object has a permanent label
if ( ! slewing & & ! ( Options : : useAltAz ( ) & & Options : : showGround ( ) & &
mousePoint ( ) - > alt ( ) - > Degrees ( ) < 0.0 ) ) {
SkyObject * so = objectNearest ( mousePoint ( ) ) ;
if ( so & & ! isObjectLabeled ( so ) ) {
setTransientObject ( so ) ;
TransientColor = data - > colorScheme ( ) - > colorNamed ( " UserLabelColor " ) ;
if ( TransientTimer . isActive ( ) ) TransientTimer . stop ( ) ;
update ( ) ;
}
}
}
//Slots
void SkyMap : : slotTransientTimeout ( void ) {
//Don't fade label if the transientObject is now the focusObject!
if ( transientObject ( ) = = focusObject ( ) & & Options : : useAutoLabel ( ) ) {
setTransientObject ( NULL ) ;
TransientTimer . stop ( ) ;
return ;
}
//to fade the labels, we will need to smoothly transition from UserLabelColor to SkyColor.
TQColor c1 = data - > colorScheme ( ) - > colorNamed ( " UserLabelColor " ) ;
TQColor c2 = data - > colorScheme ( ) - > colorNamed ( " SkyColor " ) ;
int dRed = ( c2 . red ( ) - c1 . red ( ) ) / 20 ;
int dGreen = ( c2 . green ( ) - c1 . green ( ) ) / 20 ;
int dBlue = ( c2 . blue ( ) - c1 . blue ( ) ) / 20 ;
int newRed = TransientColor . red ( ) + dRed ;
int newGreen = TransientColor . green ( ) + dGreen ;
int newBlue = TransientColor . blue ( ) + dBlue ;
//Check to see if we have arrived at the target color (SkyColor).
//If so, point TransientObject to NULL.
if ( abs ( newRed - c2 . red ( ) ) < abs ( dRed ) | | abs ( newGreen - c2 . green ( ) ) < abs ( dGreen ) | | abs ( newBlue - c2 . blue ( ) ) < abs ( dBlue ) ) {
setTransientObject ( NULL ) ;
TransientTimer . stop ( ) ;
} else {
TransientColor . setRgb ( newRed , newGreen , newBlue ) ;
}
update ( ) ;
}
void SkyMap : : setFocusObject ( SkyObject * o ) {
FocusObject = o ;
if ( FocusObject )
Options : : setFocusObject ( FocusObject - > name ( ) ) ;
else
Options : : setFocusObject ( i18n ( " nothing " ) ) ;
}
void SkyMap : : slotCenter ( void ) {
setFocusPoint ( clickedPoint ( ) ) ;
if ( Options : : useAltAz ( ) )
focusPoint ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
//clear the planet trail of old focusObject, if it was temporary
if ( focusObject ( ) & & focusObject ( ) - > isSolarSystem ( ) & & data - > temporaryTrail ) {
( ( KSPlanetBase * ) focusObject ( ) ) - > clearTrail ( ) ;
data - > temporaryTrail = false ;
}
//If the requested object is below the opaque horizon, issue a warning message
//(unless user is already pointed below the horizon)
if ( Options : : useAltAz ( ) & & Options : : showGround ( ) & &
focus ( ) - > alt ( ) - > Degrees ( ) > - 1.0 & & focusPoint ( ) - > alt ( ) - > Degrees ( ) < - 1.0 ) {
TQString caption = i18n ( " Requested Position Below Horizon " ) ;
TQString message = i18n ( " The requested position is below the horizon. \n Would you like to go there anyway? " ) ;
if ( KMessageBox : : warningYesNo ( this , message , caption ,
i18n ( " Go Anyway " ) , i18n ( " Keep Position " ) , " dag_focus_below_horiz " ) = = KMessageBox : : No ) {
setClickedObject ( NULL ) ;
setFocusObject ( NULL ) ;
Options : : setIsTracking ( false ) ;
return ;
}
}
//set FocusObject before slewing. Otherwise, KStarsData::updateTime() can reset
//destination to previous object...
setFocusObject ( ClickedObject ) ;
Options : : setIsTracking ( true ) ;
if ( ksw ) {
ksw - > actionCollection ( ) - > action ( " track_object " ) - > setIconSet ( BarIcon ( " encrypted " ) ) ;
ksw - > toolBar ( " mainToolBar " ) - > setButtonIconSet ( 4 , BarIcon ( " encrypted " ) ) ;
ksw - > actionCollection ( ) - > action ( " track_object " ) - > setText ( i18n ( " Stop &Tracking " ) ) ;
}
//If focusObject is a SS body and doesn't already have a trail, set the temporaryTrail
if ( focusObject ( ) & & focusObject ( ) - > isSolarSystem ( )
& & Options : : useAutoTrail ( )
& & ! ( ( KSPlanetBase * ) focusObject ( ) ) - > hasTrail ( ) ) {
( ( KSPlanetBase * ) focusObject ( ) ) - > addToTrail ( ) ;
data - > temporaryTrail = true ;
}
//update the destination to the selected coordinates
if ( Options : : useAltAz ( ) ) {
if ( Options : : useRefraction ( ) )
setDestinationAltAz ( refract ( focusPoint ( ) - > alt ( ) , true ) . Degrees ( ) , focusPoint ( ) - > az ( ) - > Degrees ( ) ) ;
else
setDestinationAltAz ( focusPoint ( ) - > alt ( ) - > Degrees ( ) , focusPoint ( ) - > az ( ) - > Degrees ( ) ) ;
} else {
setDestination ( focusPoint ( ) ) ;
}
focusPoint ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
//display coordinates in statusBar
if ( ksw ) {
TQString sX = focusPoint ( ) - > az ( ) - > toDMSString ( ) ;
TQString sY = focusPoint ( ) - > alt ( ) - > toDMSString ( true ) ;
if ( Options : : useAltAz ( ) & & Options : : useRefraction ( ) )
sY = refract ( focusPoint ( ) - > alt ( ) , true ) . toDMSString ( true ) ;
TQString s = sX + " , " + sY ;
ksw - > statusBar ( ) - > changeItem ( s , 1 ) ;
s = focusPoint ( ) - > ra ( ) - > toHMSString ( ) + " , " + focusPoint ( ) - > dec ( ) - > toDMSString ( true ) ;
ksw - > statusBar ( ) - > changeItem ( s , 2 ) ;
}
showFocusCoords ( ) ; //update FocusBox
}
void SkyMap : : slotDSS ( void ) {
TQString URLprefix ( " http://archive.stsci.edu/cgi-bin/dss_search?v=1 " ) ;
TQString URLsuffix ( " &e=J2000&h=15.0&w=15.0&f=gif&c=none&fov=NONE " ) ;
dms ra ( 0.0 ) , dec ( 0.0 ) ;
TQString RAString , DecString ;
char decsgn ;
//ra and dec must be the coordinates at J2000. If we clicked on an object, just use the object's ra0, dec0 coords
//if we clicked on empty sky, we need to precess to J2000.
if ( clickedObject ( ) ) {
ra . setH ( clickedObject ( ) - > ra0 ( ) - > Hours ( ) ) ;
dec . setD ( clickedObject ( ) - > dec0 ( ) - > Degrees ( ) ) ;
} else {
//move present coords temporarily to ra0,dec0 (needed for precessToAnyEpoch)
clickedPoint ( ) - > setRA0 ( clickedPoint ( ) - > ra ( ) - > Hours ( ) ) ;
clickedPoint ( ) - > setDec0 ( clickedPoint ( ) - > dec ( ) - > Degrees ( ) ) ;
clickedPoint ( ) - > precessFromAnyEpoch ( data - > ut ( ) . djd ( ) , J2000 ) ;
ra . setH ( clickedPoint ( ) - > ra ( ) - > Hours ( ) ) ;
dec . setD ( clickedPoint ( ) - > dec ( ) - > Degrees ( ) ) ;
//restore coords from present epoch
clickedPoint ( ) - > setRA ( clickedPoint ( ) - > ra0 ( ) - > Hours ( ) ) ;
clickedPoint ( ) - > setDec ( clickedPoint ( ) - > dec0 ( ) - > Degrees ( ) ) ;
}
RAString = RAString . sprintf ( " &r=%02d+%02d+%02d " , ra . hour ( ) , ra . minute ( ) , ra . second ( ) ) ;
decsgn = ' + ' ;
if ( dec . Degrees ( ) < 0.0 ) decsgn = ' - ' ;
int dd = abs ( dec . degree ( ) ) ;
int dm = abs ( dec . arcmin ( ) ) ;
int ds = abs ( dec . arcsec ( ) ) ;
DecString = DecString . sprintf ( " &d=%c%02d+%02d+%02d " , decsgn , dd , dm , ds ) ;
//concat all the segments into the kview command line:
KURL url ( URLprefix + RAString + DecString + URLsuffix ) ;
TQString message = i18n ( " Digitized Sky Survey image provided by the Space Telescope Science Institute. " ) ;
new ImageViewer ( & url , message , this ) ;
}
void SkyMap : : slotDSS2 ( void ) {
TQString URLprefix ( " http://archive.stsci.edu/cgi-bin/dss_search?v=2r " ) ;
TQString URLsuffix ( " &e=J2000&h=15.0&w=15.0&f=gif&c=none&fov=NONE " ) ;
dms ra ( 0.0 ) , dec ( 0.0 ) ;
TQString RAString , DecString ;
char decsgn ;
//ra and dec must be the coordinates at J2000. If we clicked on an object, just use the object's ra0, dec0 coords
//if we clicked on empty sky, we need to precess to J2000.
if ( clickedObject ( ) ) {
ra . setH ( clickedObject ( ) - > ra0 ( ) - > Hours ( ) ) ;
dec . setD ( clickedObject ( ) - > dec0 ( ) - > Degrees ( ) ) ;
} else {
//move present coords temporarily to ra0,dec0 (needed for precessToAnyEpoch)
clickedPoint ( ) - > setRA0 ( clickedPoint ( ) - > ra ( ) - > Hours ( ) ) ;
clickedPoint ( ) - > setDec0 ( clickedPoint ( ) - > dec ( ) - > Degrees ( ) ) ;
clickedPoint ( ) - > precessFromAnyEpoch ( data - > ut ( ) . djd ( ) , J2000 ) ;
ra . setH ( clickedPoint ( ) - > ra ( ) - > Hours ( ) ) ;
dec . setD ( clickedPoint ( ) - > dec ( ) - > Degrees ( ) ) ;
//restore coords from present epoch
clickedPoint ( ) - > setRA ( clickedPoint ( ) - > ra0 ( ) - > Hours ( ) ) ;
clickedPoint ( ) - > setDec ( clickedPoint ( ) - > dec0 ( ) - > Degrees ( ) ) ;
}
RAString = RAString . sprintf ( " &r=%02d+%02d+%02d " , ra . hour ( ) , ra . minute ( ) , ra . second ( ) ) ;
decsgn = ' + ' ;
if ( dec . Degrees ( ) < 0.0 ) decsgn = ' - ' ;
int dd = abs ( dec . degree ( ) ) ;
int dm = abs ( dec . arcmin ( ) ) ;
int ds = abs ( dec . arcsec ( ) ) ;
DecString = DecString . sprintf ( " &d=%c%02d+%02d+%02d " , decsgn , dd , dm , ds ) ;
//concat all the segments into the kview command line:
KURL url ( URLprefix + RAString + DecString + URLsuffix ) ;
TQString message = i18n ( " Digitized Sky Survey image provided by the Space Telescope Science Institute. " ) ;
new ImageViewer ( & url , message , this ) ;
}
void SkyMap : : slotInfo ( int id ) {
TQStringList : : Iterator it = clickedObject ( ) - > InfoList . at ( id - 200 ) ;
TQString sURL = ( * it ) ;
KURL url ( sURL ) ;
if ( ! url . isEmpty ( ) )
kapp - > invokeBrowser ( sURL ) ;
}
void SkyMap : : slotBeginAngularDistance ( void ) {
setPreviousClickedPoint ( mousePoint ( ) ) ;
angularDistanceMode = true ;
beginRulerPoint = getXY ( previousClickedPoint ( ) , Options : : useAltAz ( ) , Options : : useRefraction ( ) ) ;
endRulerPoint = TQPoint ( beginRulerPoint . x ( ) , beginRulerPoint . y ( ) ) ;
}
void SkyMap : : slotEndAngularDistance ( void ) {
dms angularDistance ;
if ( angularDistanceMode ) {
if ( SkyObject * so = objectNearest ( mousePoint ( ) ) ) {
angularDistance = so - > angularDistanceTo ( previousClickedPoint ( ) ) ;
ksw - > statusBar ( ) - > changeItem ( so - > translatedLongName ( ) +
" " +
i18n ( " Angular distance: " ) +
angularDistance . toDMSString ( ) , 0 ) ;
} else {
angularDistance = mousePoint ( ) - > angularDistanceTo ( previousClickedPoint ( ) ) ;
ksw - > statusBar ( ) - > changeItem ( i18n ( " Angular distance: " ) +
angularDistance . toDMSString ( ) , 0 ) ;
}
angularDistanceMode = false ;
}
}
void SkyMap : : slotCancelAngularDistance ( void ) {
angularDistanceMode = false ;
}
void SkyMap : : slotImage ( int id ) {
TQStringList : : Iterator it = clickedObject ( ) - > ImageList . at ( id - 100 ) ;
TQStringList : : Iterator it2 = clickedObject ( ) - > ImageTitle . at ( id - 100 ) ;
TQString sURL = ( * it ) ;
TQString message = ( * it2 ) ;
KURL url ( sURL ) ;
if ( ! url . isEmpty ( ) )
new ImageViewer ( & url , clickedObject ( ) - > messageFromTitle ( message ) , this ) ;
}
bool SkyMap : : isObjectLabeled ( SkyObject * object ) {
for ( SkyObject * o = data - > ObjLabelList . first ( ) ; o ; o = data - > ObjLabelList . next ( ) ) {
if ( o = = object ) return true ;
}
return false ;
}
void SkyMap : : slotRemoveObjectLabel ( void ) {
for ( SkyObject * o = data - > ObjLabelList . first ( ) ; o ; o = data - > ObjLabelList . next ( ) ) {
if ( o = = clickedObject ( ) ) {
//remove object from list
data - > ObjLabelList . remove ( ) ;
break ;
}
}
forceUpdate ( ) ;
}
void SkyMap : : slotAddObjectLabel ( void ) {
data - > ObjLabelList . append ( clickedObject ( ) ) ;
//Since we just added a permanent label, we don't want it to fade away!
if ( transientObject ( ) = = clickedObject ( ) ) setTransientObject ( NULL ) ;
forceUpdate ( ) ;
}
void SkyMap : : slotRemovePlanetTrail ( void ) {
//probably don't need this if-statement, but just to be sure...
if ( clickedObject ( ) & & clickedObject ( ) - > isSolarSystem ( ) ) {
( ( KSPlanetBase * ) clickedObject ( ) ) - > clearTrail ( ) ;
forceUpdate ( ) ;
}
}
void SkyMap : : slotAddPlanetTrail ( void ) {
//probably don't need this if-statement, but just to be sure...
if ( clickedObject ( ) & & clickedObject ( ) - > isSolarSystem ( ) ) {
( ( KSPlanetBase * ) clickedObject ( ) ) - > addToTrail ( ) ;
forceUpdate ( ) ;
}
}
void SkyMap : : slotDetail ( void ) {
// check if object is selected
if ( ! clickedObject ( ) ) {
KMessageBox : : sorry ( this , i18n ( " No object selected. " ) , i18n ( " Object Details " ) ) ;
return ;
}
DetailDialog detail ( clickedObject ( ) , data - > ut ( ) , data - > geo ( ) , ksw ) ;
detail . exec ( ) ;
}
void SkyMap : : slotClockSlewing ( ) {
//If the current timescale exceeds slewTimeScale, set clockSlewing=true, and stop the clock.
if ( fabs ( data - > clock ( ) - > scale ( ) ) > Options : : slewTimeScale ( ) ) {
if ( ! clockSlewing ) {
clockSlewing = true ;
data - > clock ( ) - > setManualMode ( true ) ;
// don't change automatically the DST status
if ( ksw ) ksw - > updateTime ( false ) ;
}
} else {
if ( clockSlewing ) {
clockSlewing = false ;
data - > clock ( ) - > setManualMode ( false ) ;
// don't change automatically the DST status
if ( ksw ) ksw - > updateTime ( false ) ;
}
}
}
void SkyMap : : setFocus ( SkyPoint * p ) {
setFocus ( p - > ra ( ) - > Hours ( ) , p - > dec ( ) - > Degrees ( ) ) ;
}
void SkyMap : : setFocus ( const dms & ra , const dms & dec ) {
setFocus ( ra . Hours ( ) , dec . Degrees ( ) ) ;
}
void SkyMap : : setFocus ( double ra , double dec ) {
Focus . set ( ra , dec ) ;
focus ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
}
void SkyMap : : setFocusAltAz ( const dms & alt , const dms & az ) {
setFocusAltAz ( alt . Degrees ( ) , az . Degrees ( ) ) ;
}
void SkyMap : : setFocusAltAz ( double alt , double az ) {
focus ( ) - > setAlt ( alt ) ;
focus ( ) - > setAz ( az ) ;
focus ( ) - > HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
slewing = false ;
oldfocus ( ) - > set ( focus ( ) - > ra ( ) , focus ( ) - > dec ( ) ) ;
oldfocus ( ) - > setAz ( focus ( ) - > az ( ) - > Degrees ( ) ) ;
oldfocus ( ) - > setAlt ( focus ( ) - > alt ( ) - > Degrees ( ) ) ;
double dHA = data - > LST - > Hours ( ) - focus ( ) - > ra ( ) - > Hours ( ) ;
while ( dHA < 0.0 ) dHA + = 24.0 ;
data - > HourAngle - > setH ( dHA ) ;
forceUpdate ( ) ; //need a total update, or slewing with the arrow keys doesn't work.
}
void SkyMap : : setDestination ( SkyPoint * p ) {
Destination . set ( p - > ra ( ) , p - > dec ( ) ) ;
destination ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
emit destinationChanged ( ) ;
}
void SkyMap : : setDestination ( const dms & ra , const dms & dec ) {
Destination . set ( ra , dec ) ;
destination ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
emit destinationChanged ( ) ;
}
void SkyMap : : setDestination ( double ra , double dec ) {
Destination . set ( ra , dec ) ;
destination ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
emit destinationChanged ( ) ;
}
void SkyMap : : setDestinationAltAz ( const dms & alt , const dms & az ) {
destination ( ) - > setAlt ( alt ) ;
destination ( ) - > setAz ( az ) ;
destination ( ) - > HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
emit destinationChanged ( ) ;
}
void SkyMap : : setDestinationAltAz ( double alt , double az ) {
destination ( ) - > setAlt ( alt ) ;
destination ( ) - > setAz ( az ) ;
destination ( ) - > HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
emit destinationChanged ( ) ;
}
void SkyMap : : updateFocus ( ) {
if ( Options : : isTracking ( ) & & focusObject ( ) ! = NULL ) {
if ( Options : : useAltAz ( ) ) {
//Tracking any object in Alt/Az mode requires focus updates
double dAlt = focusObject ( ) - > alt ( ) - > Degrees ( ) ;
if ( Options : : useRefraction ( ) )
dAlt = refract ( focusObject ( ) - > alt ( ) , true ) . Degrees ( ) ;
setFocusAltAz ( dAlt , focusObject ( ) - > az ( ) - > Degrees ( ) ) ;
focus ( ) - > HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
setDestination ( focus ( ) ) ;
} else {
//Tracking in equatorial coords
setFocus ( focusObject ( ) ) ;
focus ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
setDestination ( focus ( ) ) ;
}
} else if ( Options : : isTracking ( ) & & focusPoint ( ) ! = NULL ) {
if ( Options : : useAltAz ( ) ) {
//Tracking on empty sky in Alt/Az mode
setFocus ( focusPoint ( ) ) ;
focus ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
setDestination ( focus ( ) ) ;
}
} else if ( ! slewing ) {
//Not tracking and not slewing, let sky drift by
if ( Options : : useAltAz ( ) ) {
focus ( ) - > setAlt ( destination ( ) - > alt ( ) - > Degrees ( ) ) ;
focus ( ) - > setAz ( destination ( ) - > az ( ) - > Degrees ( ) ) ;
focus ( ) - > HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
//destination()->HorizontalToEquatorial( data->LST, data->geo()->lat() );
} else {
focus ( ) - > setRA ( data - > LST - > Hours ( ) - data - > HourAngle - > Hours ( ) ) ;
setDestination ( focus ( ) ) ;
focus ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
destination ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
}
}
//Update the Hour Angle
data - > setHourAngle ( data - > LST - > Hours ( ) - focus ( ) - > ra ( ) - > Hours ( ) ) ;
setOldFocus ( focus ( ) ) ;
oldfocus ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
}
void SkyMap : : slewFocus ( void ) {
double dX , dY , fX , fY , r ;
double step = 1.0 ;
SkyPoint newFocus ;
//Don't slew if the mouse button is pressed
//Also, no animated slews if the Manual Clock is active
//08/2002: added possibility for one-time skipping of slew with snapNextFocus
if ( ! mouseButtonDown ) {
bool goSlew = ( Options : : useAnimatedSlewing ( ) & &
! data - > snapNextFocus ( ) ) & &
! ( data - > clock ( ) - > isManualMode ( ) & & data - > clock ( ) - > isActive ( ) ) ;
if ( goSlew ) {
if ( Options : : useAltAz ( ) ) {
dX = destination ( ) - > az ( ) - > Degrees ( ) - focus ( ) - > az ( ) - > Degrees ( ) ;
dY = destination ( ) - > alt ( ) - > Degrees ( ) - focus ( ) - > alt ( ) - > Degrees ( ) ;
} else {
dX = destination ( ) - > ra ( ) - > Degrees ( ) - focus ( ) - > ra ( ) - > Degrees ( ) ;
dY = destination ( ) - > dec ( ) - > Degrees ( ) - focus ( ) - > dec ( ) - > Degrees ( ) ;
}
//switch directions to go the short way around the celestial sphere, if necessary.
if ( dX < - 180.0 ) dX = 360.0 + dX ;
else if ( dX > 180.0 ) dX = - 360.0 + dX ;
r = sqrt ( dX * dX + dY * dY ) ;
while ( r > step ) {
fX = dX / r ;
fY = dY / r ;
if ( Options : : useAltAz ( ) ) {
focus ( ) - > setAlt ( focus ( ) - > alt ( ) - > Degrees ( ) + fY * step ) ;
focus ( ) - > setAz ( dms ( focus ( ) - > az ( ) - > Degrees ( ) + fX * step ) . reduce ( ) ) ;
focus ( ) - > HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
} else {
fX = fX / 15. ; //convert RA degrees to hours
newFocus . set ( focus ( ) - > ra ( ) - > Hours ( ) + fX * step , focus ( ) - > dec ( ) - > Degrees ( ) + fY * step ) ;
setFocus ( & newFocus ) ;
focus ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
}
slewing = true ;
//since we are slewing, fade out the transient label
if ( transientObject ( ) & & ! TransientTimer . isActive ( ) )
fadeTransientLabel ( ) ;
forceUpdate ( ) ;
kapp - > processEvents ( 10 ) ; //keep up with other stuff
if ( Options : : useAltAz ( ) ) {
dX = destination ( ) - > az ( ) - > Degrees ( ) - focus ( ) - > az ( ) - > Degrees ( ) ;
dY = destination ( ) - > alt ( ) - > Degrees ( ) - focus ( ) - > alt ( ) - > Degrees ( ) ;
} else {
dX = destination ( ) - > ra ( ) - > Degrees ( ) - focus ( ) - > ra ( ) - > Degrees ( ) ;
dY = destination ( ) - > dec ( ) - > Degrees ( ) - focus ( ) - > dec ( ) - > Degrees ( ) ;
}
//switch directions to go the short way around the celestial sphere, if necessary.
if ( dX < - 180.0 ) dX = 360.0 + dX ;
else if ( dX > 180.0 ) dX = - 360.0 + dX ;
r = sqrt ( dX * dX + dY * dY ) ;
}
}
//Either useAnimatedSlewing==false, or we have slewed, and are within one step of destination
//set focus=destination.
if ( Options : : useAltAz ( ) ) {
setFocusAltAz ( destination ( ) - > alt ( ) - > Degrees ( ) , destination ( ) - > az ( ) - > Degrees ( ) ) ;
focus ( ) - > HorizontalToEquatorial ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
} else {
setFocus ( destination ( ) ) ;
focus ( ) - > EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
}
data - > HourAngle - > setH ( data - > LST - > Hours ( ) - focus ( ) - > ra ( ) - > Hours ( ) ) ;
slewing = false ;
//Turn off snapNextFocus, we only want it to happen once
if ( data - > snapNextFocus ( ) ) {
data - > setSnapNextFocus ( false ) ;
}
//Start the HoverTimer. if the user leaves the mouse in place after a slew,
//we want to attach a label to the nearest object.
if ( Options : : useHoverLabel ( ) )
HoverTimer . start ( HOVER_INTERVAL , true ) ;
forceUpdate ( ) ;
}
}
void SkyMap : : invokeKey ( int key ) {
TQKeyEvent * e = new TQKeyEvent ( TQEvent : : KeyPress , key , 0 , 0 ) ;
keyPressEvent ( e ) ;
delete e ;
}
double SkyMap : : findPA ( SkyObject * o , int x , int y , double scale ) {
//Find position angle of North using a test point displaced to the north
//displace by 100/zoomFactor radians (so distance is always 100 pixels)
//this is 5730/zoomFactor degrees
double newDec = o - > dec ( ) - > Degrees ( ) + 5730.0 / Options : : zoomFactor ( ) ;
if ( newDec > 90.0 ) newDec = 90.0 ;
SkyPoint test ( o - > ra ( ) - > Hours ( ) , newDec ) ;
if ( Options : : useAltAz ( ) ) test . EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
TQPoint t = getXY ( & test , Options : : useAltAz ( ) , Options : : useRefraction ( ) , scale ) ;
double dx = double ( t . x ( ) - x ) ;
double dy = double ( y - t . y ( ) ) ; //backwards because TQWidget Y-axis increases to the bottom
double north ;
if ( dy ) {
north = atan ( dx / dy ) * 180.0 / dms : : PI ;
//resolve atan ambiguity:
if ( dy < 0.0 ) north + = 180.0 ;
if ( north > = 360.0 ) north - = 360. ;
} else {
north = 90.0 ;
if ( dx > 0 ) north = - 90.0 ;
}
return ( north + o - > pa ( ) ) ;
}
TQPoint SkyMap : : getXY ( SkyPoint * o , bool Horiz , bool doRefraction , double scale ) {
TQPoint p ;
double Y , dX ;
double sindX , cosdX , sinY , cosY , sinY0 , cosY0 ;
int Width = int ( width ( ) * scale ) ;
int Height = int ( height ( ) * scale ) ;
double pscale = Options : : zoomFactor ( ) * scale ;
if ( Horiz ) {
if ( doRefraction ) Y = refract ( o - > alt ( ) , true ) . radians ( ) ; //account for atmospheric refraction
else Y = o - > alt ( ) - > radians ( ) ;
if ( focus ( ) - > az ( ) - > Degrees ( ) > 270.0 & & o - > az ( ) - > Degrees ( ) < 90.0 ) {
dX = 2 * dms : : PI + focus ( ) - > az ( ) - > radians ( ) - o - > az ( ) - > radians ( ) ;
} else {
dX = focus ( ) - > az ( ) - > radians ( ) - o - > az ( ) - > radians ( ) ;
}
focus ( ) - > alt ( ) - > SinCos ( sinY0 , cosY0 ) ;
} else {
if ( focus ( ) - > ra ( ) - > Hours ( ) > 18.0 & & o - > ra ( ) - > Hours ( ) < 6.0 ) {
dX = 2 * dms : : PI + o - > ra ( ) - > radians ( ) - focus ( ) - > ra ( ) - > radians ( ) ;
} else {
dX = o - > ra ( ) - > radians ( ) - focus ( ) - > ra ( ) - > radians ( ) ;
}
Y = o - > dec ( ) - > radians ( ) ;
focus ( ) - > dec ( ) - > SinCos ( sinY0 , cosY0 ) ;
}
//Convert dX, Y coords to screen pixel coords.
# if ( __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 ) && !defined(__UCLIBC__)
//GNU version
sincos ( dX , & sindX , & cosdX ) ;
sincos ( Y , & sinY , & cosY ) ;
# else
//ANSI version
sindX = sin ( dX ) ;
cosdX = cos ( dX ) ;
sinY = sin ( Y ) ;
cosY = cos ( Y ) ;
# endif
double c = sinY0 * sinY + cosY0 * cosY * cosdX ;
if ( c < 0.0 ) { //Object is on "back side" of the celestial sphere; don't plot it.
p . setX ( - 10000000 ) ;
p . setY ( - 10000000 ) ;
return p ;
}
double k = sqrt ( 2.0 / ( 1 + c ) ) ;
p . setX ( int ( 0.5 * Width - pscale * k * cosY * sindX ) ) ;
p . setY ( int ( 0.5 * Height - pscale * k * ( cosY0 * sinY - sinY0 * cosY * cosdX ) ) ) ;
return p ;
}
SkyPoint SkyMap : : dXdYToRaDec ( double dx , double dy , bool useAltAz , dms * LST , const dms * lat , bool doRefract ) {
//Determine RA and Dec of a point, given (dx, dy): it's pixel
//coordinates in the SkyMap with the center of the map as the origin.
SkyPoint result ;
double sinDec , cosDec , sinDec0 , cosDec0 , sinc , cosc , sinlat , coslat ;
double xx , yy ;
double r = sqrt ( dx * dx + dy * dy ) ;
dms centerAngle ;
centerAngle . setRadians ( 2.0 * asin ( 0.5 * r ) ) ;
focus ( ) - > dec ( ) - > SinCos ( sinDec0 , cosDec0 ) ;
centerAngle . SinCos ( sinc , cosc ) ;
if ( useAltAz ) {
dms HA ;
dms Dec , alt , az , alt0 , az0 ;
double A ;
double sinAlt , cosAlt , sinAlt0 , cosAlt0 , sinAz , cosAz ;
// double HA0 = LST - focus.ra();
az0 = focus ( ) - > az ( ) - > Degrees ( ) ;
alt0 = focus ( ) - > alt ( ) - > Degrees ( ) ;
alt0 . SinCos ( sinAlt0 , cosAlt0 ) ;
dx = - dx ; //Flip East-west (Az goes in opposite direction of RA)
yy = dx * sinc ;
xx = r * cosAlt0 * cosc - dy * sinAlt0 * sinc ;
A = atan ( yy / xx ) ;
//resolve ambiguity of atan():
if ( xx < 0 ) A = A + dms : : PI ;
// if ( xx>0 && yy<0 ) A = A + 2.0*dms::PI;
dms deltaAz ;
deltaAz . setRadians ( A ) ;
az = focus ( ) - > az ( ) - > Degrees ( ) + deltaAz . Degrees ( ) ;
alt . setRadians ( asin ( cosc * sinAlt0 + ( dy * sinc * cosAlt0 ) / r ) ) ;
if ( doRefract ) alt . setD ( refract ( & alt , false ) . Degrees ( ) ) ; //find true altitude from apparent altitude
az . SinCos ( sinAz , cosAz ) ;
alt . SinCos ( sinAlt , cosAlt ) ;
lat - > SinCos ( sinlat , coslat ) ;
Dec . setRadians ( asin ( sinAlt * sinlat + cosAlt * coslat * cosAz ) ) ;
Dec . SinCos ( sinDec , cosDec ) ;
HA . setRadians ( acos ( ( sinAlt - sinlat * sinDec ) / ( coslat * cosDec ) ) ) ;
if ( sinAz > 0.0 ) HA . setH ( 24.0 - HA . Hours ( ) ) ;
result . setRA ( LST - > Hours ( ) - HA . Hours ( ) ) ;
result . setRA ( result . ra ( ) - > reduce ( ) ) ;
result . setDec ( Dec . Degrees ( ) ) ;
return result ;
} else {
yy = dx * sinc ;
xx = r * cosDec0 * cosc - dy * sinDec0 * sinc ;
double RARad = ( atan ( yy / xx ) ) ;
//resolve ambiguity of atan():
if ( xx < 0 ) RARad = RARad + dms : : PI ;
// if ( xx>0 && yy<0 ) RARad = RARad + 2.0*dms::PI;
dms deltaRA , Dec ;
deltaRA . setRadians ( RARad ) ;
Dec . setRadians ( asin ( cosc * sinDec0 + ( dy * sinc * cosDec0 ) / r ) ) ;
result . setRA ( focus ( ) - > ra ( ) - > Hours ( ) + deltaRA . Hours ( ) ) ;
result . setRA ( result . ra ( ) - > reduce ( ) ) ;
result . setDec ( Dec . Degrees ( ) ) ;
return result ;
}
}
dms SkyMap : : refract ( const dms * alt , bool findApparent ) {
if ( alt - > Degrees ( ) < = - 2.000 ) return dms ( alt - > Degrees ( ) ) ;
int index = int ( ( alt - > Degrees ( ) + 2.0 ) * 2. ) ; //RefractCorr arrays start at alt=-2.0 degrees.
dms result ;
//Failsafe: if the index is out of range, return the original angle
if ( index < 0 | | index > 183 ) {
return dms ( alt - > Degrees ( ) ) ;
}
if ( findApparent ) {
result . setD ( alt - > Degrees ( ) + RefractCorr1 [ index ] ) ;
} else {
result . setD ( alt - > Degrees ( ) + RefractCorr2 [ index ] ) ;
}
return result ;
}
//---------------------------------------------------------------------------
// force a new calculation of the skymap (used instead of update(), which may skip the redraw)
// if now=true, SkyMap::paintEvent() is run immediately, rather than being added to the event queue
// also, determine new coordinates of mouse cursor.
void SkyMap : : forceUpdate ( bool now )
{
TQPoint mp ( mapFromGlobal ( TQCursor : : pos ( ) ) ) ;
double dx = ( 0.5 * width ( ) - mp . x ( ) ) / Options : : zoomFactor ( ) ;
double dy = ( 0.5 * height ( ) - mp . y ( ) ) / Options : : zoomFactor ( ) ;
if ( ! unusablePoint ( dx , dy ) ) {
//determine RA, Dec of mouse pointer
setMousePoint ( dXdYToRaDec ( dx , dy , Options : : useAltAz ( ) , data - > LST , data - > geo ( ) - > lat ( ) , Options : : useRefraction ( ) ) ) ;
}
computeSkymap = true ;
if ( now ) repaint ( ) ;
else update ( ) ;
}
float SkyMap : : fov ( ) {
if ( width ( ) > = height ( ) )
return 28.65 * width ( ) / Options : : zoomFactor ( ) ;
else
return 28.65 * height ( ) / Options : : zoomFactor ( ) ;
}
bool SkyMap : : checkVisibility ( SkyPoint * p , float FOV , double XMax ) {
double dX , dY ;
bool useAltAz = Options : : useAltAz ( ) ;
//Skip objects below the horizon if:
// + usingQt::Horizontal coords,
// + the ground is drawn,
// + and either of the following is true:
// - focus is above the horizon
// - field of view is larger than 50 degrees
if ( useAltAz & & Options : : showGround ( ) & & p - > alt ( ) - > Degrees ( ) < - 2.0
& & ( focus ( ) - > alt ( ) - > Degrees ( ) > 0. | | FOV > 50. ) ) return false ;
if ( useAltAz ) {
dY = fabs ( p - > alt ( ) - > Degrees ( ) - focus ( ) - > alt ( ) - > Degrees ( ) ) ;
} else {
dY = fabs ( p - > dec ( ) - > Degrees ( ) - focus ( ) - > dec ( ) - > Degrees ( ) ) ;
}
if ( isPoleVisible ) dY * = 0.75 ; //increase effective FOV when pole visible.
if ( dY > FOV ) return false ;
if ( isPoleVisible ) return true ;
if ( useAltAz ) {
dX = fabs ( p - > az ( ) - > Degrees ( ) - focus ( ) - > az ( ) - > Degrees ( ) ) ;
} else {
dX = fabs ( p - > ra ( ) - > Degrees ( ) - focus ( ) - > ra ( ) - > Degrees ( ) ) ;
}
if ( dX > 180.0 ) dX = 360.0 - dX ; // take shorter distance around sky
if ( dX < XMax ) {
return true ;
} else {
return false ;
}
}
bool SkyMap : : unusablePoint ( double dx , double dy )
{
if ( dx > = 1.41 | | dx < = - 1.41 | | dy > = 1.41 | | dy < = - 1.41 )
return true ;
else
return false ;
}
void SkyMap : : setZoomMouseCursor ( )
{
mouseMoveCursor = false ; // no mousemove cursor
TQPainter p ;
TQPixmap cursorPix ( 32 , 32 ) ; // size 32x32 (this size is compatible to all systems)
// the center of the pixmap
int mx = cursorPix . width ( ) / 2 ;
int my = cursorPix . height ( ) / 2 ;
cursorPix . fill ( white ) ; // white background
p . begin ( & cursorPix ) ;
p . setPen ( TQPen ( black , 2 ) ) ; // black lines
p . drawEllipse ( mx - 7 , my - 7 , 14 , 14 ) ;
p . drawLine ( mx + 5 , my + 5 , mx + 11 , my + 11 ) ;
p . end ( ) ;
// create a mask to make parts of the pixmap invisible
TQBitmap mask ( 32 , 32 ) ;
mask . fill ( color0 ) ; // all is invisible
p . begin ( & mask ) ;
// paint over the parts which should be visible
p . setPen ( TQPen ( color1 , 3 ) ) ;
p . drawEllipse ( mx - 7 , my - 7 , 14 , 14 ) ;
p . drawLine ( mx + 5 , my + 5 , mx + 12 , my + 12 ) ;
p . end ( ) ;
cursorPix . setMask ( mask ) ; // set the mask
TQCursor cursor ( cursorPix ) ;
setCursor ( cursor ) ;
}
void SkyMap : : setDefaultMouseCursor ( )
{
mouseMoveCursor = false ; // no mousemove cursor
TQPainter p ;
TQPixmap cursorPix ( 32 , 32 ) ; // size 32x32 (this size is compatible to all systems)
// the center of the pixmap
int mx = cursorPix . width ( ) / 2 ;
int my = cursorPix . height ( ) / 2 ;
cursorPix . fill ( white ) ; // white background
p . begin ( & cursorPix ) ;
p . setPen ( TQPen ( black , 2 ) ) ; // black lines
// 1. diagonal
p . drawLine ( mx - 2 , my - 2 , mx - 8 , mx - 8 ) ;
p . drawLine ( mx + 2 , my + 2 , mx + 8 , mx + 8 ) ;
// 2. diagonal
p . drawLine ( mx - 2 , my + 2 , mx - 8 , mx + 8 ) ;
p . drawLine ( mx + 2 , my - 2 , mx + 8 , mx - 8 ) ;
p . end ( ) ;
// create a mask to make parts of the pixmap invisible
TQBitmap mask ( 32 , 32 ) ;
mask . fill ( color0 ) ; // all is invisible
p . begin ( & mask ) ;
// paint over the parts which should be visible
p . setPen ( TQPen ( color1 , 3 ) ) ;
// 1. diagonal
p . drawLine ( mx - 2 , my - 2 , mx - 8 , mx - 8 ) ;
p . drawLine ( mx + 2 , my + 2 , mx + 8 , mx + 8 ) ;
// 2. diagonal
p . drawLine ( mx - 2 , my + 2 , mx - 8 , mx + 8 ) ;
p . drawLine ( mx + 2 , my - 2 , mx + 8 , mx - 8 ) ;
p . end ( ) ;
cursorPix . setMask ( mask ) ; // set the mask
TQCursor cursor ( cursorPix ) ;
setCursor ( cursor ) ;
}
void SkyMap : : setMouseMoveCursor ( )
{
if ( mouseButtonDown )
{
setCursor ( 9 ) ; // cursor shape defined in qt
mouseMoveCursor = true ;
}
}
void SkyMap : : addLink ( void ) {
AddLinkDialog adialog ( this , clickedObject ( ) - > name ( ) ) ;
TQString entry ;
TQFile file ;
if ( adialog . exec ( ) = = TQDialog : : Accepted ) {
if ( adialog . isImageLink ( ) ) {
//Add link to object's ImageList, and descriptive text to its ImageTitle list
clickedObject ( ) - > ImageList . append ( adialog . url ( ) ) ;
clickedObject ( ) - > ImageTitle . append ( adialog . desc ( ) ) ;
//Also, update the user's custom image links database
//check for user's image-links database. If it doesn't exist, create it.
file . setName ( locateLocal ( " appdata " , " image_url.dat " ) ) ; //determine filename in local user KDE directory tree.
if ( ! file . open ( IO_ReadWrite | IO_Append ) ) {
TQString message = i18n ( " Custom image-links file could not be opened. \n Link cannot be recorded for future sessions. " ) ;
KMessageBox : : sorry ( 0 , message , i18n ( " Could Not Open File " ) ) ;
return ;
} else {
entry = clickedObject ( ) - > name ( ) + " : " + adialog . desc ( ) + " : " + adialog . url ( ) ;
TQTextStream stream ( & file ) ;
stream < < entry < < endl ;
file . close ( ) ;
emit linkAdded ( ) ;
}
} else {
clickedObject ( ) - > InfoList . append ( adialog . url ( ) ) ;
clickedObject ( ) - > InfoTitle . append ( adialog . desc ( ) ) ;
//check for user's image-links database. If it doesn't exist, create it.
file . setName ( locateLocal ( " appdata " , " info_url.dat " ) ) ; //determine filename in local user KDE directory tree.
if ( ! file . open ( IO_ReadWrite | IO_Append ) ) {
TQString message = i18n ( " Custom information-links file could not be opened. \n Link cannot be recorded for future sessions. " ) ; KMessageBox : : sorry ( 0 , message , i18n ( " Could not Open File " ) ) ;
return ;
} else {
entry = clickedObject ( ) - > name ( ) + " : " + adialog . desc ( ) + " : " + adialog . url ( ) ;
TQTextStream stream ( & file ) ;
stream < < entry < < endl ;
file . close ( ) ;
emit linkAdded ( ) ;
}
}
}
}
void SkyMap : : updateAngleRuler ( ) {
if ( Options : : useAltAz ( ) ) PreviousClickedPoint . EquatorialToHorizontal ( data - > LST , data - > geo ( ) - > lat ( ) ) ;
beginRulerPoint = getXY ( previousClickedPoint ( ) , Options : : useAltAz ( ) , Options : : useRefraction ( ) ) ;
// endRulerPoint = TQPoint(e->x(), e->y());
endRulerPoint = mapFromGlobal ( TQCursor : : pos ( ) ) ;
}
# include "skymap.moc"