/*************************************************************************** skymapdraw.cpp - Trinity Desktop Planetarium ------------------- begin : Sun Mar 2 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. * * * ***************************************************************************/ //This file contains drawing functions SkyMap class. #include // abs #include //log10() #include #include #include #include "skymap.h" #include "Options.h" #include "kstars.h" #include "kstarsdata.h" #include "ksnumbers.h" #include "skyobject.h" #include "deepskyobject.h" #include "starobject.h" #include "ksplanetbase.h" #include "ksasteroid.h" #include "kscomet.h" #include "ksmoon.h" #include "jupitermoons.h" #include "infoboxes.h" #include "simclock.h" #include "csegment.h" #include "customcatalog.h" #include "devicemanager.h" #include "indimenu.h" #include "indiproperty.h" #include "indielement.h" #include "indidevice.h" void SkyMap::drawOverlays( TQPixmap *pm ) { if ( ksw ) { //only if we are drawing in the GUI window TQPainter p; p.begin( pm ); showFocusCoords( true ); drawBoxes( p ); //draw FOV symbol ksw->data()->fovSymbol.draw( p, (float)(Options::fOVSize() * Options::zoomFactor()/57.3/60.0) ); drawTelescopeSymbols( p ); drawObservingList( p ); drawZoomBox( p ); if ( transientObject() ) drawTransientLabel( p ); if (isAngleMode()) { updateAngleRuler(); drawAngleRuler( p ); } } } void SkyMap::drawAngleRuler( TQPainter &p ) { p.setPen( TQPen( data->colorScheme()->colorNamed( "AngularRuler" ), 1, DotLine ) ); p.drawLine( beginRulerPoint, endRulerPoint ); } void SkyMap::drawZoomBox( TQPainter &p ) { //draw the manual zoom-box, if it exists if ( ZoomRect.isValid() ) { p.setPen( TQPen( "white", 1, DotLine ) ); p.drawRect( ZoomRect.x(), ZoomRect.y(), ZoomRect.width(), ZoomRect.height() ); } } void SkyMap::drawTransientLabel( TQPainter &p ) { if ( transientObject() ) { p.setPen( TransientColor ); if ( checkVisibility( transientObject(), fov(), XRange ) ) { TQPoint o = getXY( transientObject(), Options::useAltAz(), Options::useRefraction(), 1.0 ); if ( o.x() >= 0 && o.x() <= width() && o.y() >= 0 && o.y() <= height() ) { drawNameLabel( p, transientObject(), o.x(), o.y(), 1.0 ); } } } } void SkyMap::drawBoxes( TQPainter &p ) { if ( ksw ) { //only if we are drawing in the GUI window ksw->infoBoxes()->drawBoxes( p, data->colorScheme()->colorNamed( "BoxTextColor" ), data->colorScheme()->colorNamed( "BoxGrabColor" ), data->colorScheme()->colorNamed( "BoxBGColor" ), Options::boxBGMode() ); } } void SkyMap::drawObservingList( TQPainter &psky, double scale ) { psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed( "ObsListColor" ) ), 1 ) ); if ( ksw && ksw->observingList()->count() ) { for ( SkyObject* obj = ksw->observingList()->first(); obj; obj = ksw->observingList()->next() ) { if ( checkVisibility( obj, fov(), XRange ) ) { TQPoint o = getXY( obj, Options::useAltAz(), Options::useRefraction() ); // label object if it is currently on screen if (o.x() >= 0 && o.x() <= width() && o.y() >=0 && o.y() <= height() ) { if ( Options::obsListSymbol() ) { int size = int(20*scale); int x1 = o.x() - size/2; int y1 = o.y() - size/2; psky.drawArc( x1, y1, size, size, -60*16, 120*16 ); psky.drawArc( x1, y1, size, size, 120*16, 120*16 ); } if ( Options::obsListText() ) { drawNameLabel( psky, obj, o.x(), o.y(), scale ); } } } } } } void SkyMap::drawTelescopeSymbols(TQPainter &psky) { if ( ksw ) { //ksw doesn't exist in non-GUI mode! INDI_P *eqNum; INDI_P *portConnect; INDI_E *lp; INDIMenu *devMenu = ksw->getINDIMenu(); bool useJ2000 (false), useAltAz(false); SkyPoint indi_sp; if (!Options::indiCrosshairs() || devMenu == NULL) return; psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed("TargetColor" ) ) ) ); psky.setBrush( NoBrush ); int pxperdegree = int(Options::zoomFactor()/57.3); //fprintf(stderr, "in draw telescope function with mgrsize of %d\n", devMenu->mgr.size()); for (uint i=0; i < devMenu->mgr.count(); i++) { for (uint j=0; j < devMenu->mgr.at(i)->indi_dev.count(); j++) { useAltAz = false; useJ2000 = false; // make sure the dev is on first if (devMenu->mgr.at(i)->indi_dev.at(j)->isOn()) { portConnect = devMenu->mgr.at(i)->indi_dev.at(j)->findProp("CONNECTION"); if (!portConnect) return; if (portConnect->state == PS_BUSY) return; eqNum = devMenu->mgr.at(i)->indi_dev.at(j)->findProp("EQUATORIAL_EOD_COORD"); if (eqNum == NULL) { eqNum = devMenu->mgr.at(i)->indi_dev.at(j)->findProp("EQUATORIAL_COORD"); if (eqNum == NULL) { eqNum = devMenu->mgr.at(i)->indi_dev.at(j)->findProp("HORIZONTAL_COORD"); if (eqNum == NULL) continue; else useAltAz = true; } else useJ2000 = true; } // make sure it has RA and DEC properties if ( eqNum) { //fprintf(stderr, "Looking for RA label\n"); if (useAltAz) { lp = eqNum->findElement("AZ"); if (!lp) continue; dms azDMS(lp->value); lp = eqNum->findElement("ALT"); if (!lp) continue; dms altDMS(lp->value); indi_sp.setAz(azDMS); indi_sp.setAlt(altDMS); } else { lp = eqNum->findElement("RA"); if (!lp) continue; // express hours in degrees on the celestial sphere dms raDMS(lp->value); raDMS.setD ( raDMS.Degrees() * 15.0); lp = eqNum->findElement("DEC"); if (!lp) continue; dms decDMS(lp->value); //kdDebug() << "the KStars RA is " << raDMS.toHMSString() << endl; //kdDebug() << "the KStars DEC is " << decDMS.toDMSString() << "\n****************" << endl; indi_sp.setRA(raDMS); indi_sp.setDec(decDMS); if (useJ2000) { indi_sp.setRA0(raDMS); indi_sp.setDec0(decDMS); indi_sp.apparentCoord( (double) J2000, ksw->data()->ut().djd()); } if ( Options::useAltAz() ) indi_sp.EquatorialToHorizontal( ksw->LST(), ksw->geo()->lat() ); } TQPoint P = getXY( &indi_sp, Options::useAltAz(), Options::useRefraction() ); int s1 = pxperdegree/2; int s2 = pxperdegree; int s3 = 2*pxperdegree; int x0 = P.x(); int y0 = P.y(); int x1 = x0 - s1/2; int y1 = y0 - s1/2; int x2 = x0 - s2/2; int y2 = y0 - s2/2; int x3 = x0 - s3/2; int y3 = y0 - s3/2; //Draw radial lines psky.drawLine( x1, y0, x3, y0 ); psky.drawLine( x0+s2, y0, x0+s1/2, y0 ); psky.drawLine( x0, y1, x0, y3 ); psky.drawLine( x0, y0+s1/2, x0, y0+s2 ); //Draw circles at 0.5 & 1 degrees psky.drawEllipse( x1, y1, s1, s1 ); psky.drawEllipse( x2, y2, s2, s2 ); psky.drawText( x0+s2 + 2 , y0, TQString(devMenu->mgr.at(i)->indi_dev.at(j)->label) ); } } } } } } void SkyMap::drawMilkyWay( TQPainter& psky, double scale ) { int ptsCount = 0; int mwmax = int( scale * Options::zoomFactor()/100.); int Width = int( scale * width() ); int Height = int( scale * height() ); int thick(1); if ( ! Options::fillMilkyWay() ) thick=3; psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed( "MWColor" ) ), thick, SolidLine ) ); psky.setBrush( TQBrush( TQColor( data->colorScheme()->colorNamed( "MWColor" ) ) ) ); bool offscreen, lastoffscreen=false; for ( unsigned int j=0; j<11; ++j ) { if ( Options::fillMilkyWay() ) { ptsCount = 0; bool partVisible = false; TQPoint o = getXY( data->MilkyWay[j].at(0), Options::useAltAz(), Options::useRefraction(), scale ); if ( o.x() != -10000000 && o.y() != -10000000 ) pts->setPoint( ptsCount++, o.x(), o.y() ); if ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) partVisible = true; for ( SkyPoint *p = data->MilkyWay[j].first(); p; p = data->MilkyWay[j].next() ) { o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); if ( o.x() != -10000000 && o.y() != -10000000 ) pts->setPoint( ptsCount++, o.x(), o.y() ); if ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) partVisible = true; } if ( ptsCount && partVisible ) { psky.drawPolygon( ( const TQPointArray ) *pts, false, 0, ptsCount ); } } else { TQPoint o = getXY( data->MilkyWay[j].at(0), Options::useAltAz(), Options::useRefraction(), scale ); if (o.x()==-10000000 && o.y()==-10000000) offscreen = true; else offscreen = false; psky.moveTo( o.x(), o.y() ); for ( unsigned int i=1; iMilkyWay[j].count(); ++i ) { o = getXY( data->MilkyWay[j].at(i), Options::useAltAz(), Options::useRefraction(), scale ); if (o.x()==-10000000 && o.y()==-10000000) offscreen = true; else offscreen = false; //don't draw a line if the last point's getXY was (-10000000, -10000000) int dx = abs(o.x()-psky.pos().x()); int dy = abs(o.y()-psky.pos().y()); if ( (!lastoffscreen && !offscreen) && (dxcolorScheme()->colorNamed( "GridColor" ) ), 1, DotLine ) ); //change to GridColor //First, the parallels for ( double Dec=-80.; Dec<=80.; Dec += 20. ) { bool newlyVisible = false; sp->set( 0.0, Dec ); if ( Options::useAltAz() ) sp->EquatorialToHorizontal( data->LST, data->geo()->lat() ); TQPoint o = getXY( sp, Options::useAltAz(), Options::useRefraction(), scale ); TQPoint o1 = o; cur = o; psky.moveTo( o.x(), o.y() ); double dRA = 1./5.; //120 points along full circle of RA for ( double RA=dRA; RA<24.; RA+=dRA ) { sp->set( RA, Dec ); if ( Options::useAltAz() ) sp->EquatorialToHorizontal( data->LST, data->geo()->lat() ); if ( checkVisibility( sp, guideFOV, guideXRange ) ) { o = getXY( sp, Options::useAltAz(), Options::useRefraction(), scale ); //When drawing on the printer, the psky.pos() point does NOT get updated //when lineTo or moveTo are called. Grrr. Need to store current position in TQPoint cur. int dx = cur.x() - o.x(); int dy = cur.y() - o.y(); cur = o; if ( abs(dx) < guidemax*scale && abs(dy) < guidemax*scale ) { if ( newlyVisible ) { newlyVisible = false; psky.moveTo( o.x(), o.y() ); } else { psky.lineTo( o.x(), o.y() ); } } else { psky.moveTo( o.x(), o.y() ); } } } //connect the final segment int dx = psky.pos().x() - o1.x(); int dy = psky.pos().y() - o1.y(); if ( abs(dx) < guidemax*scale && abs(dy) < guidemax*scale ) { psky.lineTo( o1.x(), o1.y() ); } else { psky.moveTo( o1.x(), o1.y() ); } } //next, the meridians for ( double RA=0.; RA<24.; RA += 2. ) { bool newlyVisible = false; SkyPoint *sp1 = new SkyPoint( RA, -90. ); if ( Options::useAltAz() ) sp1->EquatorialToHorizontal( data->LST, data->geo()->lat() ); TQPoint o = getXY( sp1, Options::useAltAz(), Options::useRefraction(), scale ); cur = o; psky.moveTo( o.x(), o.y() ); double dDec = 1.; for ( double Dec=-89.; Dec<=90.; Dec+=dDec ) { sp1->set( RA, Dec ); if ( Options::useAltAz() ) sp1->EquatorialToHorizontal( data->LST, data->geo()->lat() ); if ( checkVisibility( sp1, guideFOV, guideXRange ) ) { o = getXY( sp1, Options::useAltAz(), Options::useRefraction(), scale ); //When drawing on the printer, the psky.pos() point does NOT get updated //when lineTo or moveTo are called. Grrr. Need to store current position in TQPoint cur. int dx = cur.x() - o.x(); int dy = cur.y() - o.y(); cur = o; if ( abs(dx) < guidemax*scale && abs(dy) < guidemax*scale ) { if ( newlyVisible ) { newlyVisible = false; psky.moveTo( o.x(), o.y() ); } else { psky.lineTo( o.x(), o.y() ); } } else { psky.moveTo( o.x(), o.y() ); } } } delete sp1; // avoid memory leak } } void SkyMap::drawEquator( TQPainter& psky, double scale ) { //Draw Equator (currently can't be hidden on slew) psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed( "EqColor" ) ), 1, SolidLine ) ); SkyPoint *p = data->Equator.first(); TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); TQPoint o1 = o; TQPoint last = o; TQPoint cur = o; TQPoint o2; psky.moveTo( o.x(), o.y() ); bool newlyVisible = false; //index of point near the left or top/bottom edge uint index1(0), index2(0); int xSmall(width() + 100); //ridiculous initial value //start loop at second item for ( p = data->Equator.next(); p; p = data->Equator.next() ) { if ( checkVisibility( p, guideFOV, guideXRange ) ) { o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); //first iteration for positioning the "Equator" label: //flag the onscreen equator point with the smallest positive x value //we don't draw the label while slewing if ( ! slewing && o.x() > 0 && o.x() < width() && o.y() > 0 && o.y() < height() ) { if ( o.x() < xSmall ) { xSmall = o.x(); index1 = data->Equator.at(); } } //When drawing on the printer, the psky.pos() point does NOT get updated //when lineTo or moveTo are called. Grrr. Need to store current position in TQPoint cur. int dx = cur.x() - o.x(); int dy = cur.y() - o.y(); cur = o; if ( abs(dx) < guidemax*scale && abs(dy) < guidemax*scale ) { if ( newlyVisible ) { newlyVisible = false; psky.moveTo( last.x(), last.y() ); } psky.lineTo( o.x(), o.y() ); } else { psky.moveTo( o.x(), o.y() ); } } else { newlyVisible = true; } last = o; } //connect the final segment int dx = psky.pos().x() - o1.x(); int dy = psky.pos().y() - o1.y(); if ( abs(dx) < guidemax*scale && abs(dy) < guidemax*scale ) { psky.lineTo( o1.x(), o1.y() ); } else { psky.moveTo( o1.x(), o1.y() ); } if ( ! slewing && xSmall < width() ) { //Draw the "Equator" label. We have flagged the leftmost onscreen Equator point. //If the zoom level is below 1000, simply adopt this point as the anchor for the //label. If the zoom level is 1000 or higher, we interpolate to find the exact //point at which the Equator goes offscreen, and anchor from that point. p = data->Equator.at(index1); double ra0(0.0); //the RA of our anchor point (the Dec is known to be 0.0 //since it's the Equator) if ( Options::zoomFactor() < 1000. ) { ra0 = p->ra()->Hours(); } else { //Somewhere between Equator point p and its immediate neighbor, the Equator goes //offscreen. Determine the exact point at which this happens. index2 = index1 + 1; if ( index2 >= data->Equator.count() ) index2 -= data->Equator.count(); SkyPoint *p2 = data->Equator.at(index2); o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); o2 = getXY( p2, Options::useAltAz(), Options::useRefraction(), scale ); double x1, x2; //there are 3 possibilities: (o2.x() < 0); (o2.y() < 0); (o2.y() > height()) if ( o2.x() < 0 ) { x1 = double(o.x())/double(o.x()-o2.x()); x2 = -1.0*double(o2.x())/double(o.x()-o2.x()); } else if ( o2.y() < 0 ) { x1 = double(o.y())/double(o.y()-o2.y()); x2 = -1.0*double(o2.y())/double(o.y()-o2.y()); } else if ( o2.y() > height() ) { x1 = double(height() - o.y())/double(o2.y()-o.y()); x2 = double(o2.y() - height())/double(o2.y()-o.y()); } else { //should never get here x1 = 0.0; x2 = 1.0; } //ra0 is the exact RA at which the Equator intersects a screen edge ra0 = x1*p2->ra()->Hours() + x2*p->ra()->Hours(); } //LabelPoint is the top left corner of the text label. It is //offset from the anchor point by -1.5 degree (0.1 hour) in RA //and -0.4 degree in Dec, scaled by 2000./zoomFactor so that they are //independent of zoom. SkyPoint LabelPoint( ra0 - 200./Options::zoomFactor(), -800./Options::zoomFactor() ); if ( Options::useAltAz() ) LabelPoint.EquatorialToHorizontal( data->LST, data->geo()->lat() ); //p2 is a SkyPoint offset from LabelPoint in RA by -0.1 hour/zoomFactor. //We use this point to determine the rotation angle for the text (which //we want to be parallel to the line joining LabelPoint and p2) SkyPoint p2 = LabelPoint; p2.setRA( p2.ra()->Hours() - 200./Options::zoomFactor() ); if ( Options::useAltAz() ) p2.EquatorialToHorizontal( data->LST, data->geo()->lat() ); //o and o2 are the screen coordinates of LabelPoint and p2. o = getXY( &LabelPoint, Options::useAltAz(), Options::useRefraction(), scale ); o2 = getXY( &p2, Options::useAltAz(), Options::useRefraction() ); double sx = double( o.x() - o2.x() ); double sy = double( o.y() - o2.y() ); double angle; if ( sx ) { angle = atan( sy/sx )*180.0/dms::PI; } else { angle = 90.0; if ( sy < 0 ) angle = -90.0; } //Finally, draw the "Equator" label at the determined location and angle psky.save(); psky.translate( o.x(), o.y() ); psky.rotate( double( angle ) ); //rotate the coordinate system psky.drawText( 0, 0, i18n( "Equator" ) ); psky.restore(); //reset coordinate system } } void SkyMap::drawEcliptic( TQPainter& psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); //Draw Ecliptic (currently can't be hidden on slew) psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed( "EclColor" ) ), 1, SolidLine ) ); SkyPoint *p = data->Ecliptic.first(); TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); TQPoint o2 = o; TQPoint o1 = o; TQPoint last = o; TQPoint cur = o; psky.moveTo( o.x(), o.y() ); //index of point near the right or top/bottom edge uint index1(0), index2(0); int xBig(-100); //ridiculous initial value bool newlyVisible = false; //Start loop at second item for ( p = data->Ecliptic.next(); p; p = data->Ecliptic.next() ) { if ( checkVisibility( p, guideFOV, guideXRange ) ) { o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); //first iteration for positioning the "Ecliptic" label: //flag the onscreen equator point with the largest x value //we don't draw the label while slewing if ( ! slewing && o.x() > 0 && o.x() < width() && o.y() > 0 && o.y() < height() ) { if ( o.x() > xBig ) { xBig = o.x(); index1 = data->Ecliptic.at(); } } //When drawing on the printer, the psky.pos() point does NOT get updated //when lineTo or moveTo are called. Grrr. Need to store current position in TQPoint cur. int dx = cur.x() - o.x(); int dy = cur.y() - o.y(); cur = o; if ( abs(dx) < guidemax*scale && abs(dy) < guidemax*scale ) { if ( newlyVisible ) { newlyVisible = false; psky.moveTo( last.x(), last.y() ); } psky.lineTo( o.x(), o.y() ); } else { psky.moveTo( o.x(), o.y() ); } } else { newlyVisible = true; } last = o; } //connect the final segment int dx = psky.pos().x() - o1.x(); int dy = psky.pos().y() - o1.y(); if ( abs(dx) < Width && abs(dy) < Height ) { psky.lineTo( o1.x(), o1.y() ); } else { psky.moveTo( o1.x(), o1.y() ); } if ( ! slewing && xBig > 0 ) { //Draw the "Ecliptic" label. We have flagged the rightmost onscreen Ecliptic point. //If the zoom level is below 1000, simply adopt this point as the anchor for the //label. If the zoom level is 1000 or higher, we interpolate to find the exact //point at which the Ecliptic goes offscreen, and anchor from that point. p = data->Ecliptic.at(index1); double ra0(0.0); //the ra of our anchor point double dec0(0.0); //the dec of our anchor point if ( Options::zoomFactor() < 1000. ) { ra0 = p->ra()->Hours(); dec0 = p->dec()->Degrees(); } else { //Somewhere between Ecliptic point p and its immediate neighbor, the Ecliptic goes //offscreen. Determine the exact point at which this happens. if ( index1 == 0 ) index2 = 0; else index2 = index1 - 1; SkyPoint *p2 = data->Ecliptic.at(index2); o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); o2 = getXY( p2, Options::useAltAz(), Options::useRefraction(), scale ); double x1, x2; //there are 3 possibilities: (o2.x() > width()); (o2.y() < 0); (o2.y() > height()) if ( o2.x() > width() ) { x1 = double(width()-o.x())/double(o2.x()-o.x()); x2 = double(o2.x()-width())/double(o2.x()-o.x()); } else if ( o2.y() < 0 ) { x1 = double(o.y())/double(o.y()-o2.y()); x2 = -1.0*double(o2.y())/double(o.y()-o2.y()); } else if ( o2.y() > height() ) { x1 = double(height() - o.y())/double(o2.y()-o.y()); x2 = double(o2.y() - height())/double(o2.y()-o.y()); } else { //should never get here x1 = 0.0; x2 = 1.0; } //ra0 is the exact RA at which the Ecliptic intersects a screen edge ra0 = x1*p2->ra()->Hours() + x2*p->ra()->Hours(); //dec0 is the exact Dec at which the Ecliptic intersects a screen edge dec0 = x1*p2->dec()->Degrees() + x2*p->dec()->Degrees(); } KSNumbers num( data->ut().djd() ); dms ecLong, ecLat; //LabelPoint is offset from the anchor point by +2.0 degree ecl. Long //and -0.4 degree in ecl. Lat, scaled by 2000./zoomFactor so that they are //independent of zoom. SkyPoint LabelPoint(ra0, dec0); LabelPoint.findEcliptic( num.obliquity(), ecLong, ecLat ); ecLong.setD( ecLong.Degrees() + 4000./Options::zoomFactor() ); ecLat.setD( ecLat.Degrees() - 800./Options::zoomFactor() ); LabelPoint.setFromEcliptic( num.obliquity(), &ecLong, &ecLat ); if ( Options::useAltAz() ) LabelPoint.EquatorialToHorizontal( data->LST, data->geo()->lat() ); //p2 is a SkyPoint offset from LabelPoint by -1.0 degrees of ecliptic longitude. //we use p2 to determine the onscreen rotation angle for the ecliptic label, //which we want to be parallel to the line between LabelPoint and p2. SkyPoint p2(ra0, dec0); p2.findEcliptic( num.obliquity(), ecLong, ecLat ); ecLong.setD( ecLong.Degrees() + 2000./Options::zoomFactor() ); ecLat.setD( ecLat.Degrees() - 800./Options::zoomFactor() ); p2.setFromEcliptic( num.obliquity(), &ecLong, &ecLat ); if ( Options::useAltAz() ) p2.EquatorialToHorizontal( data->LST, data->geo()->lat() ); //o and o2 are the screen positions of LabelPoint and p2. o = getXY( &LabelPoint, Options::useAltAz(), Options::useRefraction(), scale ); o2 = getXY( &p2, Options::useAltAz(), Options::useRefraction() ); double sx = double( o.x() - o2.x() ); double sy = double( o.y() - o2.y() ); double angle; if ( sx ) { angle = atan( sy/sx )*180.0/dms::PI; } else { angle = 90.0; if ( sy < 0 ) angle = -90.0; } //Finally, draw the "Ecliptic" label at the determined location and angle psky.save(); psky.translate( o.x(), o.y() ); psky.rotate( double( angle ) ); //rotate the coordinate system psky.drawText( 0, 0, i18n( "Ecliptic" ) ); psky.restore(); //reset coordinate system } } void SkyMap::drawHorizon( TQPainter& psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); TQPtrList points; points.setAutoDelete(true); TQPoint o, o2; //Draw Horizon //The horizon should not be corrected for atmospheric refraction, so getXY has doRefract=false... if (Options::showHorizon() || Options::showGround() ) { TQPoint OutLeft(0,0), OutRight(0,0); psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed( "HorzColor" ) ), 1, SolidLine ) ); psky.setBrush( TQColor ( data->colorScheme()->colorNamed( "HorzColor" ) ) ); int ptsCount = 0; int maxdist = int(Options::zoomFactor()/4); //index of point near the right or top/bottom edge uint index1(0), index2(0); int xBig(-100); //ridiculous initial value for ( SkyPoint *p = data->Horizon.first(); p; p = data->Horizon.next() ) { o = getXY( p, Options::useAltAz(), false, scale ); //false: do not refract the horizon bool found = false; //first iteration for positioning the "Horizon" label: //flag the onscreen equator point with the largest x value //we don't draw the label while slewing, or if the opaque ground is drawn if ( ! slewing && ( ! Options::showGround() || ! Options::useAltAz() ) && o.x() > 0 && o.x() < width() && o.y() > 0 && o.y() < height() ) { if ( o.x() > xBig ) { xBig = o.x(); index1 = data->Horizon.at(); } } //Use the TQPtrList of points to pre-sort visible horizon points if ( o.x() > -100 && o.x() < Width + 100 && o.y() > -100 && o.y() < Height + 100 ) { if ( Options::useAltAz() ) { unsigned int j; for ( j=0; jx() ) { found = true; break; } } if ( found ) { points.insert( j, new TQPoint(o) ); } else { points.append( new TQPoint(o) ); } } else { points.append( new TQPoint(o) ); } } else { //find the out-of-bounds points closest to the left and right borders if ( ( OutLeft.x() == 0 || o.x() > OutLeft.x() ) && o.x() < -100 ) { OutLeft.setX( o.x() ); OutLeft.setY( o.y() ); } if ( ( OutRight.x() == 0 || o.x() < OutRight.x() ) && o.x() > + 100 ) { OutRight.setX( o.x() ); OutRight.setY( o.y() ); } } } //Add left-edge and right-edge points based on interpolating the first/last onscreen points //to the nearest offscreen points. if ( Options::useAltAz() && points.count() > 0 ) { //If the edge of the visible sky circle is onscreen, then we should //interpolate the first and last horizon points to the edge of the circle. //Otherwise, interpolate to the screen edge. double dx = 0.5*double(Width)/Options::zoomFactor(); //center-to-edge ang in radians double r0 = 2.0*sin(0.25*dms::PI); if ( dx < r0 ) { //edge of visible sky circle is not visible //Interpolate from first sorted onscreen point to x=-100, //using OutLeft to determine the slope int xtotal = ( points.at( 0 )->x() - OutLeft.x() ); int xx = ( points.at( 0 )->x() + 100 ) / xtotal; int yp = xx*OutRight.y() + (1-xx)*points.at( 0 )->y(); //interpolated left-edge y value TQPoint *LeftEdge = new TQPoint( -100, yp ); points.insert( 0, LeftEdge ); //Prepend LeftEdge to the beginning of points //Interpolate from the last sorted onscreen point to ()+100, //using OutRight to determine the slope. xtotal = ( OutRight.x() - points.at( points.count() - 1 )->x() ); xx = ( Width + 100 - points.at( points.count() - 1 )->x() ) / xtotal; yp = xx*OutRight.y() + (1-xx)*points.at( points.count() - 1 )->y(); //interpolated right-edge y value TQPoint *RightEdge = new TQPoint( Width+100, yp ); points.append( RightEdge ); } //If there are no horizon points, then either the horizon doesn't pass through the screen //or we're at high zoom, and horizon points lie on either side of the screen. } else if ( Options::useAltAz() && OutLeft.y() !=0 && OutRight.y() !=0 && !( OutLeft.y() > Height + 100 && OutRight.y() > Height + 100 ) && !( OutLeft.y() < -100 && OutRight.y() < -100 ) ) { //It's possible at high zoom that /no/ horizon points are onscreen. In this case, //interpolate between OutLeft and OutRight directly to construct the horizon polygon. int xtotal = ( OutRight.x() - OutLeft.x() ); int xx = ( OutRight.x() + 100 ) / xtotal; int yp = xx*OutLeft.y() + (1-xx)*OutRight.y(); //interpolated left-edge y value // TQPoint *LeftEdge = new TQPoint( -100, yp ); points.append( new TQPoint( -100, yp ) ); xx = ( Width + 100 - OutLeft.x() ) / xtotal; yp = xx*OutRight.y() + (1-xx)*OutLeft.y(); //interpolated right-edge y value // TQPoint *RightEdge = new TQPoint( Width+100, yp ); points.append( new TQPoint( Width+100, yp ) ); } if ( points.count() ) { // Fill the pts array with sorted horizon points, Draw Horizon Line pts->setPoint( 0, points.at(0)->x(), points.at(0)->y() ); if ( Options::showHorizon() ) psky.moveTo( points.at(0)->x(), points.at(0)->y() ); for ( unsigned int i=1; isetPoint( i, points.at(i)->x(), points.at(i)->y() ); if ( Options::showHorizon() ) { if ( !Options::useAltAz() && ( abs( points.at(i)->x() - psky.pos().x() ) > maxdist || abs( points.at(i)->y() - psky.pos().y() ) > maxdist ) ) { psky.moveTo( points.at(i)->x(), points.at(i)->y() ); } else { psky.lineTo( points.at(i)->x(), points.at(i)->y() ); } } } //connect the last segment back to the beginning if ( abs( points.at(0)->x() - psky.pos().x() ) < maxdist && abs( points.at(0)->y() - psky.pos().y() ) < maxdist ) psky.lineTo( points.at(0)->x(), points.at(0)->y() ); //Finish the Ground polygon. If sky edge is visible, the //bottom edge follows the sky circle. Otherwise, we just //add a square bottom edge, offscreen if ( Options::useAltAz() ) { if ( Options::showGround() ) { ptsCount = points.count(); //center-to-edge ang in radians double dx = 0.5*double(Width)/Options::zoomFactor(); double r0 = 2.0*sin(0.25*dms::PI); // //Second TQPointsArray for blocking the region outside the sky circle // TQPointArray bpts( 100 ); //need 90 points along sky circle, plus 4 to complete polygon // uint bpCount(0); if ( dx > r0 ) { //sky edge is visible for ( double t=360.; t >= 180.; t-=2. ) { //add points along edge of circle dms a( t ); double sa(0.), ca(0.); a.SinCos( sa, ca ); int xx = Width/2 + int(r0*Options::zoomFactor()*ca); int yy = Height/2 - int(r0*Options::zoomFactor()*sa); pts->setPoint( ptsCount++, xx, yy ); // bpts.setPoint( bpCount++, xx, yy ); } // //complete the background polygon, then draw it with SkyColor // bpts.setPoint( bpCount++, -100, Height/2 ); // bpts.setPoint( bpCount++, -100, Height + 100 ); // bpts.setPoint( bpCount++, Width + 100, Height + 100 ); // bpts.setPoint( bpCount++, Width + 100, Height/2 ); // psky.setPen( TQColor ( data->colorScheme()->colorNamed( "SkyColor" ) ) ); // psky.setBrush( TQColor ( data->colorScheme()->colorNamed( "SkyColor" ) ) ); // psky.drawPolygon( bpts, false, 0, bpCount ); // //Reset colors for Horizon polygon // psky.setPen( TQColor ( data->colorScheme()->colorNamed( "HorzColor" ) ) ); // psky.setBrush( TQColor ( data->colorScheme()->colorNamed( "HorzColor" ) ) ); } else { pts->setPoint( ptsCount++, Width+100, Height+100 ); //bottom right corner pts->setPoint( ptsCount++, -100, Height+100 ); //bottom left corner } //Draw the Horizon polygon psky.drawPolygon( ( const TQPointArray ) *pts, false, 0, ptsCount ); //remove all items in points list for ( unsigned int i=0; icolorScheme()->colorNamed( "CompassColor" ) ) ); else psky.setPen( TQColor ( data->colorScheme()->colorNamed( "HorzColor" ) ) ); //North c->setAz( 359.99 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "North", "N" ) ); } //NorthEast c->setAz( 45.0 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "Northeast", "NE" ) ); } //East c->setAz( 90.0 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "East", "E" ) ); } //SouthEast c->setAz( 135.0 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "Southeast", "SE" ) ); } //South c->setAz( 179.99 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "South", "S" ) ); } //SouthWest c->setAz( 225.0 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "Southwest", "SW" ) ); } //West c->setAz( 270.0 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "West", "W" ) ); } //NorthWest c->setAz( 315.0 ); c->setAlt( 0.0 ); if ( !Options::useAltAz() ) c->HorizontalToEquatorial( data->LST, data->geo()->lat() ); cpoint = getXY( c, Options::useAltAz(), false, scale ); cpoint.setY( cpoint.y() + int(scale*20) ); if (cpoint.x() > 0 && cpoint.x() < Width && cpoint.y() > 0 && cpoint.y() < Height ) { psky.drawText( cpoint.x(), cpoint.y(), i18n( "Northwest", "NW" ) ); } delete c; } } if ( ! slewing && (! Options::showGround() || ! Options::useAltAz() ) && xBig > 0 ) { //Draw the "Horizon" label. We have flagged the rightmost onscreen Horizon point. //If the zoom level is below 1000, simply adopt this point as the anchor for the //label. If the zoom level is 1000 or higher, we interpolate to find the exact //point at which the Horizon goes offscreen, and anchor from that point. SkyPoint *p = data->Horizon.at(index1); double ra0(0.0); //the ra of our anchor point double dec0(0.0); //the dec of our anchor point if ( Options::zoomFactor() < 1000. ) { ra0 = p->ra()->Hours(); dec0 = p->dec()->Degrees(); } else { //Somewhere between Horizon point p and its immediate neighbor, the Horizon goes //offscreen. Determine the exact point at which this happens. index2 = index1 + 1; if ( data->Horizon.count() && index2 > data->Horizon.count() - 1 ) index2 -= data->Horizon.count(); SkyPoint *p2 = data->Horizon.at(index2); TQPoint o1 = getXY( p, Options::useAltAz(), false, scale ); TQPoint o2 = getXY( p2, Options::useAltAz(), false, scale ); double x1, x2; //there are 3 possibilities: (o2.x() > width()); (o2.y() < 0); (o2.y() > height()) if ( o2.x() > width() ) { x1 = double(width()-o1.x())/double(o2.x()-o1.x()); x2 = double(o2.x()-width())/double(o2.x()-o1.x()); } else if ( o2.y() < 0 ) { x1 = double(o1.y())/double(o1.y()-o2.y()); x2 = -1.0*double(o2.y())/double(o1.y()-o2.y()); } else if ( o2.y() > height() ) { x1 = double(height() - o1.y())/double(o2.y()-o1.y()); x2 = double(o2.y() - height())/double(o2.y()-o1.y()); } else { //should never get here x1 = 0.0; x2 = 1.0; } //ra0 is the exact RA at which the Horizon intersects a screen edge ra0 = x1*p2->ra()->Hours() + x2*p->ra()->Hours(); //dec0 is the exact Dec at which the Horizon intersects a screen edge dec0 = x1*p2->dec()->Degrees() + x2*p->dec()->Degrees(); } //LabelPoint is offset from the anchor point by -2.0 degrees in azimuth //and -0.4 degree altitude, scaled by 2000./zoomFactor so that they are //independent of zoom. SkyPoint LabelPoint(ra0, dec0); LabelPoint.EquatorialToHorizontal( data->LST, data->geo()->lat() ); LabelPoint.setAlt( LabelPoint.alt()->Degrees() - 800./Options::zoomFactor() ); LabelPoint.setAz( LabelPoint.az()->Degrees() - 4000./Options::zoomFactor() ); LabelPoint.HorizontalToEquatorial( data->LST, data->geo()->lat() ); o = getXY( &LabelPoint, Options::useAltAz(), false, scale ); if ( o.x() > width() || o.x() < 0 ) { //the LabelPoint is offscreen. Either we are in the Southern hemisphere, //or the sky is rotated upside-down. Use an azimuth offset of +2.0 degrees LabelPoint.setAlt( LabelPoint.alt()->Degrees() + 1600./Options::zoomFactor() ); LabelPoint.setAz( LabelPoint.az()->Degrees() + 8000./Options::zoomFactor() ); LabelPoint.HorizontalToEquatorial( data->LST, data->geo()->lat() ); o = getXY( &LabelPoint, Options::useAltAz(), false, scale ); } //p2 is a skypoint offset from LabelPoint by +/-1 degree azimuth (scaled by //2000./zoomFactor). We use p2 to determine the rotation angle for the //Horizon label, which we want to be parallel to the line between LabelPoint and p2. SkyPoint p2( LabelPoint.ra(), LabelPoint.dec() ); p2.EquatorialToHorizontal( data->LST, data->geo()->lat() ); p2.setAz( p2.az()->Degrees() + 2000./Options::zoomFactor() ); p2.HorizontalToEquatorial( data->LST, data->geo()->lat() ); //o and o2 are the screen positions of LabelPoint and p2 o = getXY( &LabelPoint, Options::useAltAz(), false, scale ); o2 = getXY( &p2, Options::useAltAz(), false, scale ); double sx = double( o.x() - o2.x() ); double sy = double( o.y() - o2.y() ); double angle; if ( sx ) { angle = atan( sy/sx )*180.0/dms::PI; } else { angle = 90.0; if ( sy < 0 ) angle = -90.0; } //Finally, draw the "Equator" label at the determined location and angle psky.save(); psky.translate( o.x(), o.y() ); psky.rotate( double( angle ) ); //rotate the coordinate system psky.drawText( 0, 0, i18n( "Horizon" ) ); psky.restore(); //reset coordinate system } } //endif drawing horizon } void SkyMap::drawConstellationLines( TQPainter& psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); //Draw Constellation Lines psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed( "CLineColor" ) ), 1, SolidLine ) ); //change to colorGrid int iLast = -1; for ( SkyPoint *p = data->clineList.first(); p; p = data->clineList.next() ) { TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= -1000 && o.x() <= Width+1000 && o.y() >=-1000 && o.y() <= Height+1000 ) ) { if ( data->clineModeList.at(data->clineList.at())->latin1()=='M' ) { psky.moveTo( o.x(), o.y() ); } else if ( data->clineModeList.at(data->clineList.at())->latin1()=='D' ) { if ( data->clineList.at()== (int)(iLast+1) ) { psky.lineTo( o.x(), o.y() ); } else { psky.moveTo( o.x(), o.y() ); } } iLast = data->clineList.at(); } } } void SkyMap::drawConstellationBoundaries( TQPainter &psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); psky.setPen( TQPen( TQColor( data->colorScheme()->colorNamed( "CBoundColor" ) ), 1, SolidLine ) ); for ( CSegment *seg = data->csegmentList.first(); seg; seg = data->csegmentList.next() ) { bool started( false ); SkyPoint *p = seg->firstNode(); TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= -1000 && o.x() <= Width+1000 && o.y() >=-1000 && o.y() <= Height+1000 ) ) { psky.moveTo( o.x(), o.y() ); started = true; } for ( p = seg->nextNode(); p; p = seg->nextNode() ) { TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= -1000 && o.x() <= Width+1000 && o.y() >=-1000 && o.y() <= Height+1000 ) ) { if ( started ) { psky.lineTo( o.x(), o.y() ); } else { psky.moveTo( o.x(), o.y() ); started = true; } } else { started = false; } } } } void SkyMap::drawConstellationNames( TQPainter& psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); //Draw Constellation Names psky.setPen( TQColor( data->colorScheme()->colorNamed( "CNameColor" ) ) ); for ( SkyObject *p = data->cnameList.first(); p; p = data->cnameList.next() ) { if ( checkVisibility( p, fov(), XRange ) ) { TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); if (o.x() >= 0 && o.x() <= Width && o.y() >=0 && o.y() <= Height ) { if ( Options::useLatinConstellNames() ) { int dx = 5*p->name().length(); psky.drawText( o.x()-dx, o.y(), p->name() ); // latin constellation names } else if ( Options::useLocalConstellNames() ) { // can't use translatedName() because we need the context string in i18n() int dx = 5*( i18n( "Constellation name (optional)", p->name().local8Bit().data() ).length() ); psky.drawText( o.x()-dx, o.y(), i18n( "Constellation name (optional)", p->name().local8Bit().data() ) ); // localized constellation names } else { int dx = 5*p->name2().length(); psky.drawText( o.x()-dx, o.y(), p->name2() ); //name2 is the IAU abbreviation } } } } } void SkyMap::drawStars( TQPainter& psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); bool checkSlewing = ( ( slewing || ( clockSlewing && data->clock()->isActive() ) ) && Options::hideOnSlew() ); //shortcuts to inform wheter to draw different objects bool hideFaintStars( checkSlewing && Options::hideStars() ); if ( Options::showStars() ) { //adjust maglimit for ZoomLevel double lgmin = log10(MINZOOM); double lgmax = log10(MAXZOOM); double lgz = log10(Options::zoomFactor()); double maglim = Options::magLimitDrawStar(); if ( lgz <= 0.75*lgmax ) maglim -= (Options::magLimitDrawStar() - Options::magLimitDrawStarZoomOut() )*(0.75*lgmax - lgz)/(0.75*lgmax - lgmin); float sizeFactor = 6.0 + (lgz - lgmin); for ( StarObject *curStar = data->starList.first(); curStar; curStar = data->starList.next() ) { // break loop if maglim is reached if ( curStar->mag() > maglim || ( hideFaintStars && curStar->mag() > Options::magLimitHideStar() ) ) break; if ( checkVisibility( curStar, fov(), XRange ) ) { TQPoint o = getXY( curStar, Options::useAltAz(), Options::useRefraction(), scale ); // draw star if currently on screen if (o.x() >= 0 && o.x() <= Width && o.y() >=0 && o.y() <= Height ) { int size = int( scale * ( sizeFactor*( maglim - curStar->mag())/maglim ) + 1 ); if ( size > 0 ) { TQChar c = curStar->color(); TQPixmap *spixmap = starpix->getPixmap( &c, size ); curStar->draw( psky, sky, spixmap, o.x(), o.y(), true, scale ); // now that we have drawn the star, we can display some extra info //don't label unnamed stars with the generic "star" name bool drawName = ( Options::showStarNames() && (curStar->name() != i18n("star") ) ); if ( !checkSlewing && (curStar->mag() <= Options::magLimitDrawStarInfo() ) && ( drawName || Options::showStarMagnitudes() ) ) { psky.setPen( TQColor( data->colorScheme()->colorNamed( "SNameColor" ) ) ); TQFont stdFont( psky.font() ); TQFont smallFont( stdFont ); smallFont.setPointSize( stdFont.pointSize() - 2 ); if ( Options::zoomFactor() < 10.*MINZOOM ) { psky.setFont( smallFont ); } else { psky.setFont( stdFont ); } curStar->drawLabel( psky, o.x(), o.y(), Options::zoomFactor(), drawName, Options::showStarMagnitudes(), scale ); //reset font psky.setFont( stdFont ); } } } } } } } void SkyMap::drawDeepSkyCatalog( TQPainter& psky, TQPtrList& catalog, TQColor& color, bool drawObject, bool drawImage, double scale ) { if ( drawObject || drawImage ) { //don't do anything if nothing is to be drawn! int Width = int( scale * width() ); int Height = int( scale * height() ); // Set color once psky.setPen( color ); psky.setBrush( NoBrush ); TQColor colorHST = data->colorScheme()->colorNamed( "HSTColor" ); double maglim = Options::magLimitDrawDeepSky(); //FIXME //disabling faint limits until the NGC/IC catalog has reasonable mags //adjust maglimit for ZoomLevel //double lgmin = log10(MINZOOM); //double lgmax = log10(MAXZOOM); //double lgz = log10(Options::zoomFactor()); //if ( lgz <= 0.75*lgmax ) maglim -= (Options::magLimitDrawDeepSky() - Options::magLimitDrawDeepSkyZoomOut() )*(0.75*lgmax - lgz)/(0.75*lgmax - lgmin); //else maglim = 40.0; //show all deep-sky objects for ( DeepSkyObject *obj = catalog.first(); obj; obj = catalog.next() ) { if ( checkVisibility( obj, fov(), XRange ) ) { float mag = obj->mag(); //only draw objects if flags set and its brighter than maglim (unless mag is undefined (=99.9) if ( mag > 90.0 || mag < (float)maglim ) { TQPoint o = getXY( obj, Options::useAltAz(), Options::useRefraction(), scale ); if ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) { double PositionAngle = findPA( obj, o.x(), o.y(), scale ); //Draw Image if ( drawImage && Options::zoomFactor() > 5.*MINZOOM ) { obj->drawImage( psky, o.x(), o.y(), PositionAngle, Options::zoomFactor(), scale ); } //Draw Symbol if ( drawObject ) { //change color if extra images are available // most objects don't have those, so we only change colors temporarily // for the few exceptions. Changing color is expensive!!! bool bColorChanged = false; if ( obj->isCatalogM() && obj->ImageList.count() > 1 ) { psky.setPen( colorHST ); bColorChanged = true; } else if ( (!obj->isCatalogM()) && obj->ImageList.count() ) { psky.setPen( colorHST ); bColorChanged = true; } obj->drawSymbol( psky, o.x(), o.y(), PositionAngle, Options::zoomFactor(), scale ); // revert temporary color change if ( bColorChanged ) { psky.setPen( color ); } } } } } else { //Object failed checkVisible(); delete it's Image pointer, if it exists. if ( obj->image() ) { obj->deleteImage(); } } } } } void SkyMap::drawDeepSkyObjects( TQPainter& psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); TQImage ScaledImage; bool checkSlewing = ( ( slewing || ( clockSlewing && data->clock()->isActive() ) ) && Options::hideOnSlew() ); //shortcuts to inform wheter to draw different objects bool drawMess( Options::showDeepSky() && ( Options::showMessier() || Options::showMessierImages() ) && !(checkSlewing && Options::hideMessier() ) ); bool drawNGC( Options::showDeepSky() && Options::showNGC() && !(checkSlewing && Options::hideNGC() ) ); bool drawOther( Options::showDeepSky() && Options::showOther() && !(checkSlewing && Options::hideOther() ) ); bool drawIC( Options::showDeepSky() && Options::showIC() && !(checkSlewing && Options::hideIC() ) ); bool drawImages( Options::showMessierImages() ); // calculate color objects once, outside the loop TQColor colorMess = data->colorScheme()->colorNamed( "MessColor" ); TQColor colorIC = data->colorScheme()->colorNamed( "ICColor" ); TQColor colorNGC = data->colorScheme()->colorNamed( "NGCColor" ); // draw Messier catalog if ( drawMess ) { drawDeepSkyCatalog( psky, data->deepSkyListMessier, colorMess, Options::showMessier(), drawImages, scale ); } // draw NGC Catalog if ( drawNGC ) { drawDeepSkyCatalog( psky, data->deepSkyListNGC, colorNGC, true, drawImages, scale ); } // draw IC catalog if ( drawIC ) { drawDeepSkyCatalog( psky, data->deepSkyListIC, colorIC, true, drawImages, scale ); } // draw the rest if ( drawOther ) { //Use NGC color for now... drawDeepSkyCatalog( psky, data->deepSkyListOther, colorNGC, true, drawImages, scale ); } //Draw Custom Catalogs for ( unsigned int i=0; iCustomCatalogs.count(); ++i ) { if ( Options::showCatalog()[i] ) { TQPtrList cat = data->CustomCatalogs.at(i)->objList(); for ( SkyObject *obj = cat.first(); obj; obj = cat.next() ) { if ( checkVisibility( obj, fov(), XRange ) ) { TQPoint o = getXY( obj, Options::useAltAz(), Options::useRefraction(), scale ); if ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) { if ( obj->type()==0 ) { StarObject *starobj = (StarObject*)obj; float zoomlim = 7.0 + ( Options::zoomFactor()/MINZOOM)/50.0; float mag = starobj->mag(); float sizeFactor = 2.0; int size = int( sizeFactor*(zoomlim - mag) ) + 1; if (size>23) size=23; if ( size > 0 ) { TQChar c = starobj->color(); TQPixmap *spixmap = starpix->getPixmap( &c, size ); // Try to paint with the selected color spixmap->fill(TQColor( data->CustomCatalogs.at(i)->color() )); starobj->draw( psky, sky, spixmap, o.x(), o.y(), true, scale ); // After drawing the star we display some extra info like // the name ... bool drawName = ( Options::showStarNames() && (starobj->name() != i18n("star") ) ); if ( !checkSlewing && (starobj->mag() <= Options::magLimitDrawStarInfo() ) && ( drawName || Options::showStarMagnitudes() ) ) { psky.setPen( TQColor( data->colorScheme()->colorNamed( "SNameColor" ) ) ); TQFont stdFont( psky.font() ); TQFont smallFont( stdFont ); smallFont.setPointSize( stdFont.pointSize() - 2 ); if ( Options::zoomFactor() < 10.*MINZOOM ) { psky.setFont( smallFont ); } else { psky.setFont( stdFont ); } starobj->drawLabel( psky, o.x(), o.y(), Options::zoomFactor(), drawName, Options::showStarMagnitudes(), scale ); //reset font psky.setFont( stdFont ); } } } else { DeepSkyObject *dso = (DeepSkyObject*)obj; double pa = findPA( dso, o.x(), o.y(), scale ); dso->drawImage( psky, o.x(), o.y(), pa, Options::zoomFactor() ); psky.setBrush( NoBrush ); psky.setPen( TQColor( data->CustomCatalogs.at(i)->color() ) ); dso->drawSymbol( psky, o.x(), o.y(), pa, Options::zoomFactor() ); } } } } } } } void SkyMap::drawAttachedLabels( TQPainter &psky, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); psky.setPen( data->colorScheme()->colorNamed( "UserLabelColor" ) ); bool checkSlewing = ( slewing || ( clockSlewing && data->clock()->isActive() ) ) && Options::hideOnSlew(); bool drawPlanets( Options::showPlanets() && !(checkSlewing && Options::hidePlanets() ) ); bool drawComets( drawPlanets && Options::showComets() ); bool drawAsteroids( drawPlanets && Options::showAsteroids() ); bool drawMessier( Options::showDeepSky() && ( Options::showMessier() || Options::showMessierImages() ) && !(checkSlewing && Options::hideMessier() ) ); bool drawNGC( Options::showDeepSky() && Options::showNGC() && !(checkSlewing && Options::hideNGC() ) ); bool drawIC( Options::showDeepSky() && Options::showIC() && !(checkSlewing && Options::hideIC() ) ); bool drawOther( Options::showDeepSky() && Options::showOther() && !(checkSlewing && Options::hideOther() ) ); bool drawSAO = ( Options::showStars() ); bool hideFaintStars( checkSlewing && Options::hideStars() ); for ( SkyObject *obj = data->ObjLabelList.first(); obj; obj = data->ObjLabelList.next() ) { //Only draw an attached label if the object is being drawn to the map //reproducing logic from other draw funcs here...not an optimal solution if ( obj->type() == SkyObject::STAR ) { if ( ! drawSAO ) return; if ( obj->mag() > Options::magLimitDrawStar() ) return; if ( hideFaintStars && obj->mag() > Options::magLimitHideStar() ) return; } if ( obj->type() == SkyObject::PLANET ) { if ( ! drawPlanets ) return; if ( obj->name() == "Sun" && ! Options::showSun() ) return; if ( obj->name() == "Mercury" && ! Options::showMercury() ) return; if ( obj->name() == "Venus" && ! Options::showVenus() ) return; if ( obj->name() == "Moon" && ! Options::showMoon() ) return; if ( obj->name() == "Mars" && ! Options::showMars() ) return; if ( obj->name() == "Jupiter" && ! Options::showJupiter() ) return; if ( obj->name() == "Saturn" && ! Options::showSaturn() ) return; if ( obj->name() == "Uranus" && ! Options::showUranus() ) return; if ( obj->name() == "Neptune" && ! Options::showNeptune() ) return; if ( obj->name() == "Pluto" && ! Options::showPluto() ) return; } if ( obj->type() >= SkyObject::OPEN_CLUSTER && obj->type() <= SkyObject::GALAXY ) { if ( ((DeepSkyObject*)obj)->isCatalogM() && ! drawMessier ) return; if ( ((DeepSkyObject*)obj)->isCatalogNGC() && ! drawNGC ) return; if ( ((DeepSkyObject*)obj)->isCatalogIC() && ! drawIC ) return; if ( ((DeepSkyObject*)obj)->isCatalogNone() && ! drawOther ) return; } if ( obj->type() == SkyObject::COMET && ! drawComets ) return; if ( obj->type() == SkyObject::ASTEROID && ! drawAsteroids ) return; if ( checkVisibility( obj, fov(), XRange ) ) { TQPoint o = getXY( obj, Options::useAltAz(), Options::useRefraction(), scale ); if ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) { drawNameLabel( psky, obj, o.x(), o.y(), scale ); } } } //Attach a label to the centered object if ( focusObject() != NULL && Options::useAutoLabel() ) { TQPoint o = getXY( focusObject(), Options::useAltAz(), Options::useRefraction(), scale ); if ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) drawNameLabel( psky, focusObject(), o.x(), o.y(), scale ); } } void SkyMap::drawNameLabel( TQPainter &psky, SkyObject *obj, int x, int y, double scale ) { int size(0); TQFont stdFont( psky.font() ); TQFont smallFont( stdFont ); smallFont.setPointSize( stdFont.pointSize() - 2 ); if ( Options::zoomFactor() < 10.*MINZOOM ) { psky.setFont( smallFont ); } else { psky.setFont( stdFont ); } //Stars if ( obj->type() == SkyObject::STAR ) { ((StarObject*)obj)->drawLabel( psky, x, y, Options::zoomFactor(), true, false, scale ); psky.setFont( stdFont ); return; //Solar system } else if ( obj->type() == SkyObject::PLANET || obj->type() == SkyObject::ASTEROID || obj->type() == SkyObject::COMET ) { KSPlanetBase *p = (KSPlanetBase*)obj; size = int( p->angSize() * scale * dms::PI * Options::zoomFactor()/10800.0 ); int minsize = 4; if ( p->type() == SkyObject::ASTEROID || p->type() == SkyObject::COMET ) minsize = 2; if ( p->name() == "Sun" || p->name() == "Moon" ) minsize = 8; if ( size < minsize ) size = minsize; if ( p->name() == "Saturn" ) size = int(2.5*size); //Other } else { //Calculate object size in pixels float majorAxis = ((DeepSkyObject*)obj)->a(); if ( majorAxis == 0.0 && obj->type() == 1 ) majorAxis = 1.0; //catalog stars size = int( majorAxis * scale * dms::PI * Options::zoomFactor()/10800.0 ); } int offset = int( ( 0.5*size + 4 ) ); psky.drawText( x+offset, y+offset, obj->translatedName() ); //Reset font psky.setFont( stdFont ); } void SkyMap::drawPlanetTrail( TQPainter& psky, KSPlanetBase *ksp, double scale ) { if ( ksp->hasTrail() ) { int Width = int( scale * width() ); int Height = int( scale * height() ); TQColor tcolor1 = TQColor( data->colorScheme()->colorNamed( "PlanetTrailColor" ) ); TQColor tcolor2 = TQColor( data->colorScheme()->colorNamed( "SkyColor" ) ); SkyPoint *p = ksp->trail()->first(); TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); TQPoint cur( o ); bool doDrawLine(false); int i = 0; int n = ksp->trail()->count(); if ( ( o.x() >= -1000 && o.x() <= Width+1000 && o.y() >=-1000 && o.y() <= Height+1000 ) ) { psky.moveTo(o.x(), o.y()); doDrawLine = true; } psky.setPen( TQPen( tcolor1, 1 ) ); for ( p = ksp->trail()->next(); p; p = ksp->trail()->next() ) { if ( Options::fadePlanetTrails() ) { //Define interpolated color TQColor tcolor = TQColor( (i*tcolor1.red() + (n-i)*tcolor2.red())/n, (i*tcolor1.green() + (n-i)*tcolor2.green())/n, (i*tcolor1.blue() + (n-i)*tcolor2.blue())/n ); ++i; psky.setPen( TQPen( tcolor, 1 ) ); } o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= -1000 && o.x() <= Width+1000 && o.y() >=-1000 && o.y() <= Height+1000 ) ) { //Want to disable line-drawing if this point and the last are both outside bounds of display. if ( ! TQT_TQRECT_OBJECT(rect()).contains( o ) && ! TQT_TQRECT_OBJECT(rect()).contains( cur ) ) doDrawLine = false; cur = o; if ( doDrawLine ) { psky.lineTo( o.x(), o.y() ); } else { psky.moveTo( o.x(), o.y() ); doDrawLine = true; } } } } } void SkyMap::drawSolarSystem( TQPainter& psky, bool drawPlanets, double scale ) { int Width = int( scale * width() ); int Height = int( scale * height() ); if ( drawPlanets ) { //Draw all trails first so they never appear "in front of" solar system bodies //draw Trail if ( Options::showSun() && data->PCat->findByName("Sun")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Sun"), scale ); if ( Options::showMercury() && data->PCat->findByName("Mercury")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Mercury"), scale ); if ( Options::showVenus() && data->PCat->findByName("Venus")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Venus"), scale ); if ( Options::showMoon() && data->Moon->hasTrail() ) drawPlanetTrail( psky, data->Moon, scale ); if ( Options::showMars() && data->PCat->findByName("Mars")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Mars"), scale ); if ( Options::showJupiter() && data->PCat->findByName("Jupiter")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Jupiter"), scale ); if ( Options::showSaturn() && data->PCat->findByName("Saturn")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Saturn"), scale ); if ( Options::showUranus() && data->PCat->findByName("Uranus")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Uranus"), scale ); if ( Options::showNeptune() && data->PCat->findByName("Neptune")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Neptune"), scale ); if ( Options::showPluto() && data->PCat->findByName("Pluto")->hasTrail() ) drawPlanetTrail( psky, data->PCat->findByName("Pluto"), scale ); if ( Options::showAsteroids() ) { for ( KSAsteroid *ast = data->asteroidList.first(); ast; ast = data->asteroidList.next() ) { if ( ast->mag() > Options::magLimitAsteroid() ) break; if ( ast->hasTrail() ) drawPlanetTrail( psky, ast, scale ); } } if ( Options::showComets() ) { for ( KSComet *com = data->cometList.first(); com; com = data->cometList.next() ) { if ( com->hasTrail() ) drawPlanetTrail( psky, com, scale ); } } //Now draw the actual solar system bodies. Draw furthest to closest. //Draw Asteroids if ( Options::showAsteroids() ) { for ( KSAsteroid *ast = data->asteroidList.first(); ast; ast = data->asteroidList.next() ) { if ( ast->mag() > Options::magLimitAsteroid() ) break; if ( checkVisibility( ast, fov(), XRange ) ) { psky.setPen( TQPen( TQColor( "gray" ) ) ); psky.setBrush( TQBrush( TQColor( "gray" ) ) ); TQPoint o = getXY( ast, Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) ) { int size = int( ast->angSize() * scale * dms::PI * Options::zoomFactor()/10800.0 ); if ( size < 1 ) size = 1; int x1 = o.x() - size/2; int y1 = o.y() - size/2; psky.drawEllipse( x1, y1, size, size ); //draw Name if ( Options::showAsteroidNames() && ast->mag() < Options::magLimitAsteroidName() ) { psky.setPen( TQColor( data->colorScheme()->colorNamed( "PNameColor" ) ) ); drawNameLabel( psky, ast, o.x(), o.y(), scale ); } } } } } //Draw Comets if ( Options::showComets() ) { for ( KSComet *com = data->cometList.first(); com; com = data->cometList.next() ) { if ( checkVisibility( com, fov(), XRange ) ) { psky.setPen( TQPen( TQColor( "cyan4" ) ) ); psky.setBrush( TQBrush( TQColor( "cyan4" ) ) ); TQPoint o = getXY( com, Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) ) { int size = int( com->angSize() * scale * dms::PI * Options::zoomFactor()/10800.0 ); if ( size < 1 ) size = 1; int x1 = o.x() - size/2; int y1 = o.y() - size/2; psky.drawEllipse( x1, y1, size, size ); //draw Name if ( Options::showCometNames() && com->rsun() < Options::maxRadCometName() ) { psky.setPen( TQColor( data->colorScheme()->colorNamed( "PNameColor" ) ) ); drawNameLabel( psky, com, o.x(), o.y(), scale ); } } } } } //Draw Pluto if ( Options::showPluto() ) { drawPlanet(psky, data->PCat->findByName("Pluto"), TQColor( "gray" ), 50.*MINZOOM, 1, scale ); } //Draw Neptune if ( Options::showNeptune() ) { drawPlanet(psky, data->PCat->findByName("Neptune"), TQColor( "SkyBlue" ), 20.*MINZOOM, 1, scale ); } //Draw Uranus if ( Options::showUranus() ) { drawPlanet(psky, data->PCat->findByName("Uranus"), TQColor( "LightSeaGreen" ), 20.*MINZOOM, 1, scale ); } //Draw Saturn if ( Options::showSaturn() ) { drawPlanet(psky, data->PCat->findByName("Saturn"), TQColor( "LightYellow2" ), 20.*MINZOOM, 2, scale ); } //Draw Jupiter and its moons. //Draw all moons first, then Jupiter, then redraw moons that are in front of Jupiter. if ( Options::showJupiter() ) { //Draw Jovian moons psky.setPen( TQPen( TQColor( "white" ) ) ); if ( Options::zoomFactor() > 10.*MINZOOM ) { for ( unsigned int i=0; i<4; ++i ) { TQPoint o = getXY( data->jmoons->pos(i), Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) ) { psky.drawEllipse( o.x()-1, o.y()-1, 2, 2 ); } } } drawPlanet(psky, data->PCat->findByName("Jupiter"), TQColor( "Goldenrod" ), 20.*MINZOOM, 1, scale ); //Re-draw Jovian moons which are in front of Jupiter, also draw all 4 moon labels. psky.setPen( TQPen( TQColor( "white" ) ) ); if ( Options::zoomFactor() > 10.*MINZOOM ) { TQFont pfont = psky.font(); TQFont moonFont = psky.font(); moonFont.setPointSize( pfont.pointSize() - 2 ); psky.setFont( moonFont ); for ( unsigned int i=0; i<4; ++i ) { TQPoint o = getXY( data->jmoons->pos(i), Options::useAltAz(), Options::useRefraction(), scale ); if ( ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) ) { if ( data->jmoons->z(i) < 0.0 ) //Moon is nearer than Jupiter psky.drawEllipse( o.x()-1, o.y()-1, 2, 2 ); //Draw Moon name labels if at high zoom if ( Options::showPlanetNames() && Options::zoomFactor() > 50.*MINZOOM ) { int offset = int(3*scale); psky.drawText( o.x() + offset, o.y() + offset, data->jmoons->name(i) ); } } } //reset font psky.setFont( pfont ); } } //Draw Mars if ( Options::showMars() ) { drawPlanet(psky, data->PCat->findByName("Mars"), TQColor( "Red" ), 20.*MINZOOM, 1, scale ); } //For the inner planets, we need to determine the distance-order //because the order can change with time double rv = data->PCat->findByName("Venus")->rearth(); double rm = data->PCat->findByName("Mercury")->rearth(); double rs = data->PCat->findByName("Sun")->rearth(); unsigned int iv(0), im(0), is(0); if ( rm > rs ) im++; if ( rm > rv ) im++; if ( rv > rs ) iv++; if ( rv > rm ) iv++; if ( rs > rm ) is++; if ( rs > rv ) is++; for ( unsigned int i=0; i<3; i++ ) { if ( i==is ) { //Draw Sun if ( Options::showSun() ) { drawPlanet(psky, data->PCat->findByName("Sun"), TQColor( "Yellow" ), MINZOOM, 1, scale ); } } else if ( i==im ) { //Draw Mercury if ( Options::showMercury() ) { drawPlanet(psky, data->PCat->findByName("Mercury"), TQColor( "SlateBlue1" ), 20.*MINZOOM, 1, scale ); } } else if ( i==iv ) { //Draw Venus if ( Options::showVenus() ) { drawPlanet(psky, data->PCat->findByName("Venus"), TQColor( "LightGreen" ), 20.*MINZOOM, 1, scale ); } } } //Draw Moon if ( Options::showMoon() ) { drawPlanet(psky, data->Moon, TQColor( "White" ), MINZOOM, 1, scale ); } } } void SkyMap::drawPlanet( TQPainter &psky, KSPlanetBase *p, TQColor c, double zoommin, int resize_mult, double scale ) { if ( checkVisibility( p, fov(), XRange ) ) { int Width = int( scale * width() ); int Height = int( scale * height() ); int sizemin = 4; if ( p->name() == "Sun" || p->name() == "Moon" ) sizemin = 8; sizemin = int( sizemin * scale ); psky.setPen( c ); psky.setBrush( c ); TQPoint o = getXY( p, Options::useAltAz(), Options::useRefraction(), scale ); //Is planet onscreen? if ( o.x() >= 0 && o.x() <= Width && o.y() >= 0 && o.y() <= Height ) { int size = int( p->angSize() * scale * dms::PI * Options::zoomFactor()/10800.0 ); if ( size < sizemin ) size = sizemin; //Draw planet image if: if ( Options::showPlanetImages() && //user wants them, int(Options::zoomFactor()) >= int(zoommin) && //zoomed in enough, !p->image()->isNull() && //image loaded ok, size < Width ) { //and size isn't too big. //Image size must be modified to account for possibility that rotated image's //size is bigger than original image size. The rotated image is a square //superscribed on the original image. The superscribed square is larger than //the original square by a factor of (cos(t) + sin(t)) where t is the angle by //which the two squares are rotated (in our case, equal to the position angle + //the north angle, reduced between 0 and 90 degrees). //The proof is left as an exercise to the student :) dms pa( findPA( p, o.x(), o.y(), scale ) ); double spa, cpa; pa.SinCos( spa, cpa ); cpa = fabs(cpa); spa = fabs(spa); size = int( size * (cpa + spa) ); //Because Saturn has rings, we inflate its image size by a factor 2.5 if ( p->name() == "Saturn" ) size = int(2.5*size); if (resize_mult != 1) { size *= resize_mult; } p->scaleRotateImage( size, pa.Degrees() ); int x1 = o.x() - p->image()->width()/2; int y1 = o.y() - p->image()->height()/2; psky.drawImage( x1, y1, *(p->image())); } else { //Otherwise, draw a simple circle. psky.drawEllipse( o.x()-size/2, o.y()-size/2, size, size ); } //draw Name if ( Options::showPlanetNames() ) { psky.setPen( TQColor( data->colorScheme()->colorNamed( "PNameColor" ) ) ); drawNameLabel( psky, p, o.x(), o.y(), scale ); } } } } void SkyMap::exportSkyImage( const TQPaintDevice *pd ) { TQPainter p; //shortcuts to inform wheter to draw different objects bool drawPlanets( Options::showPlanets() ); bool drawMW( Options::showMilkyWay() ); bool drawCNames( Options::showCNames() ); bool drawCLines( Options::showCLines() ); bool drawCBounds( Options::showCBounds() ); bool drawGrid( Options::showGrid() ); p.begin( const_cast(pd) ); TQPaintDeviceMetrics pdm( p.device() ); //scale image such that it fills 90% of the x or y dimension on the paint device double xscale = double(pdm.width()) / double(width()); double yscale = double(pdm.height()) / double(height()); double scale = (xscale < yscale) ? xscale : yscale; int pdWidth = int( scale * width() ); int pdHeight = int( scale * height() ); int x1 = int( 0.5*(pdm.width() - pdWidth) ); int y1 = int( 0.5*(pdm.height() - pdHeight) ); p.setClipRect( TQRect( x1, y1, pdWidth, pdHeight ) ); p.setClipping( true ); //Fill background with sky color p.fillRect( x1, y1, pdWidth, pdHeight, TQBrush( TQColor(data->colorScheme()->colorNamed( "SkyColor" ) )) ); if ( x1 || y1 ) p.translate( x1, y1 ); if ( drawMW ) drawMilkyWay( p, scale ); if ( drawGrid ) drawCoordinateGrid( p, scale ); if ( drawCBounds ) drawConstellationBoundaries( p, scale ); if ( drawCLines ) drawConstellationLines( p, scale ); if ( drawCNames ) drawConstellationNames( p, scale ); if ( Options::showEquator() ) drawEquator( p, scale ); if ( Options::showEcliptic() ) drawEcliptic( p, scale ); drawStars( p, scale ); drawDeepSkyObjects( p, scale ); drawSolarSystem( p, drawPlanets, scale ); drawAttachedLabels( p, scale ); drawObservingList( p, scale ); drawHorizon( p, scale ); p.end(); } void SkyMap::setMapGeometry() { guidemax = int(Options::zoomFactor()/10.0); isPoleVisible = false; if ( Options::useAltAz() ) { XRange = 1.2*fov()/cos( focus()->alt()->radians() ); Ymax = fabs( focus()->alt()->Degrees() ) + fov(); } else { XRange = 1.2*fov()/cos( focus()->dec()->radians() ); Ymax = fabs( focus()->dec()->Degrees() ) + fov(); } if ( Ymax >= 90. ) isPoleVisible = true; //at high zoom, double FOV for guide lines so they don't disappear. guideFOV = fov(); guideXRange = XRange; if ( Options::zoomFactor() > 10.*MINZOOM ) { guideFOV *= 2.0; guideXRange *= 2.0; } }