[Kstars-devel] KDE/kdeedu/kstars/kstars
Jason Harris
kstars at 30doradus.org
Sun Jan 27 00:26:59 CET 2008
SVN commit 766933 by harris:
Cosmetic fixes for different projection schemes.
The opaque ground polygon is now well-behaved for all
projections. Fixed a crash at low zoom when using
Gnomonic projection, as reported by Mederic Boquien.
Gnomonic is a special case, because unlike the other
projections, it has an infinite "sky horizon"
boundary. i.e., the locus of points that are 90
degrees from the focus is projeced as a circle in
other systems, but these points are at infinity in
the Gnominic projection.
Also forward-porting the fix for Bug #133505 (crash
condition in SkyMap::refract()). Will backport these
changes to the 4.0 branch as well.
CCMAIL: boquien at astro.umass.edu
CCMAIL: kstars-devel at kde.org
M +67 -26 skycomponents/horizoncomponent.cpp
M +60 -7 skymap.cpp
--- trunk/KDE/kdeedu/kstars/kstars/skycomponents/horizoncomponent.cpp #766932:766933
@@ -97,8 +97,12 @@
psky.setBrush( Qt::NoBrush );
double daz = 90.;
- if ( Options::useAltAz() )
+ if ( Options::useAltAz() ) {
daz = 0.5*Width*57.3/Options::zoomFactor(); //center to edge, in degrees
+ if ( Options::projection() == SkyMap::Orthographic ) {
+ daz = daz * 1.4;
+ }
+ }
if ( daz > 90.0 ) daz = 90.0;
double az1 = map->focus()->az()->Degrees() - daz;
@@ -153,14 +157,16 @@
foreach ( SkyPoint *p, pointList() ) {
if ( p->az()->Degrees() > az1 ) {
o = map->toScreen( p, false );
- groundPoly << o;
+ if ( ! map->isPointNull( o ) ) {
+ groundPoly << o;
- //Set the anchor point if this point is onscreen
- if ( o.x() < marginRight && o.y() > marginTop && o.y() < marginBot )
- pAnchor = p;
+ //Set the anchor point if this point is onscreen
+ if ( o.x() < marginRight && o.y() > marginTop && o.y() < marginBot )
+ pAnchor = p;
- if ( o.y() > 0. ) allGround = false;
- if ( o.y() < Height ) allSky = false;
+ if ( o.y() > 0. ) allGround = false;
+ if ( o.y() < Height ) allSky = false;
+ }
}
}
az1 = 0.0;
@@ -170,14 +176,16 @@
foreach ( SkyPoint *p, pointList() ) {
if ( p->az()->Degrees() > az1 && p->az()->Degrees() < az2 ) {
o = map->toScreen( p, false );
- groundPoly << o;
+ if ( ! map->isPointNull( o ) ) {
+ groundPoly << o;
- //Set the anchor point if this point is onscreen
- if ( o.x() < marginRight && o.y() > marginTop && o.y() < marginBot )
- pAnchor = p;
+ //Set the anchor point if this point is onscreen
+ if ( o.x() < marginRight && o.y() > marginTop && o.y() < marginBot )
+ pAnchor = p;
- if ( o.y() > 0. ) allGround = false;
- if ( o.y() < Height ) allSky = false;
+ if ( o.y() > 0. ) allGround = false;
+ if ( o.y() < Height ) allSky = false;
+ }
} else if ( p->az()->Degrees() > az2 )
break;
}
@@ -188,16 +196,19 @@
foreach ( SkyPoint *p, pointList() ) {
if ( p->az()->Degrees() < az2 ) {
o = map->toScreen( p, false );
- groundPoly << o;
+ if ( ! map->isPointNull( o ) ) {
+ groundPoly << o;
- //Set the anchor point if this point is onscreen
- if ( o.x() < marginRight && o.y() > marginTop && o.y() < marginBot )
- pAnchor = p;
+ //Set the anchor point if this point is onscreen
+ if ( o.x() < marginRight && o.y() > marginTop && o.y() < marginBot )
+ pAnchor = p;
- if ( o.y() > 0. ) allGround = false;
- if ( o.y() < Height ) allSky = false;
- } else
+ if ( o.y() > 0. ) allGround = false;
+ if ( o.y() < Height ) allSky = false;
+ }
+ } else {
break;
+ }
}
}
@@ -243,19 +254,49 @@
//complete the polygon by simply adding points along thebottom edge
//of the screen. If the zoomLevel is high (daz>75.0), then we add points
//along the bottom edge of the sky circle. The sky circle has
- //a radius of 2*sin(pi/4)*ZoomFactor, and the endpoints of the current
+ //a radius determined by the projection scheme, and the endpoints of the current
//groundPoly points lie 180 degrees apart along its circumference.
//We determine the polar angles t1, t2 corresponding to these end points,
//and then step along the circumference, adding points between them.
//(In Horizontal coordinates, t1 and t2 are always 360 and 180, respectively).
} else { //Horizontal coords
- if ( daz < 75.0 ) { //can complete polygon by simply adding offscreen points
+
+ //In Gnomonic projection, or if sufficiently zoomed in, we can complete
+ //the ground polygon by simply adding offscreen points
+ if ( daz < 25.0 || Options::projection() == SkyMap::Gnomonic ) {
groundPoly << QPointF( Width + 10., groundPoly.last().y() )
<< QPointF( Width + 10., Height + 10. )
<< QPointF( -10., Height + 10. )
<< QPointF( -10., groundPoly.first().y() );
- } else { //complete polygon along bottom of sky circle
- double r0 = 2.0*map->scale()*sin(0.25*dms::PI);
+
+ //For other projections at low zoom, we complete the ground polygon by tracing
+ //along the bottom of sky's horizon circle (i.e., the locus of points that are
+ //90 degrees from the focus point)
+ } else {
+ //r0, the radius of the sky circle is determined by the projection scheme:
+ double r0 = map->scale()*Options::zoomFactor();
+ switch ( Options::projection() ) {
+ case SkyMap::Lambert:
+ //r0 * 2 * sin(PI/4) = 1.41421356
+ r0 = r0*1.41421356;
+ break;
+ case SkyMap::AzimuthalEquidistant:
+ //r0*PI/2 = 1.57079633
+ r0 = r0*1.57079633;
+ break;
+ case SkyMap::Orthographic:
+ //r0*sin(PI/2) = 1.0
+ break;
+ case SkyMap::Stereographic:
+ //r0*2*tan(PI/4) = 2.0
+ r0 = 2.0*r0;
+ break;
+ default:
+ kWarning() << i18n("Unrecognized coordinate projection: ") << Options::projection() ;
+ //default to Orthographic
+ break;
+ }
+
double t1 = 360.;
double t2 = 180.;
@@ -275,8 +316,8 @@
dms a( t );
double sa(0.), ca(0.);
a.SinCos( sa, ca );
- float xx = 0.5*Width + r0*Options::zoomFactor()*ca;
- float yy = 0.5*Height - r0*Options::zoomFactor()*sa;
+ float xx = 0.5*Width + r0*ca;
+ float yy = 0.5*Height - r0*sa;
groundPoly << QPoint( int(xx), int(yy) );
}
--- trunk/KDE/kdeedu/kstars/kstars/skymap.cpp #766932:766933
@@ -935,6 +935,22 @@
cosY = cos(Y);
#endif
+ // Reference for these map projections: Wolfram MathWorld
+ // Lambert Azimuthal Equal-Area:
+ // http://mathworld.wolfram.com/LambertAzimuthalEqual-AreaProjection.html
+ //
+ // Azimuthal Equidistant:
+ // http://mathworld.wolfram.com/AzimuthalEquidistantProjection.html
+ //
+ // Orthographic:
+ // http://mathworld.wolfram.com/OrthographicProjection.html
+ //
+ // Stereographic:
+ // http://mathworld.wolfram.com/StereographicProjection.html
+ //
+ // Gnomonic:
+ // http://mathworld.wolfram.com/GnomonicProjection.html
+
//c is the cosine of the angular distance from the center
double c = sinY0*sinY + cosY0*cosY*cosdX;
@@ -942,9 +958,12 @@
*onVisibleHemisphere = true;
}
- if ( c < 0.0 ) {
- //Object is on "back side" of the celestial sphere;
- //Set null coordinates and return
+ //If c is less than 0.0, then the "field angle" (angular distance from the focus)
+ //is more than 90 degrees. This is on the "back side" of the celestial sphere
+ //and should not be drawn.
+ //The Gnomonic projection has an infinite sky horizon, so don't allow the field
+ //angle to approach 90 degrees in thi scase (cut it off at c=0.2).
+ if ( c < 0.0 || Options::projection()==Gnomonic && c < 0.2 ) {
if (onVisibleHemisphere == NULL) {
p.setX( -10000000. );
p.setY( -10000000. );
@@ -1399,6 +1418,12 @@
if ( alt->Degrees()<x1 ) index2 = index - 1;
if ( index2 < 0 ) index2 = index + 1;
if ( index2 > 183 ) index2 = index - 1;
+
+ //Failsafe: if indices are out of range, return the input altitude
+ if ( index < 0 || index > 183 || index2 < 0 || index2 > 183 ) {
+ return dms( alt->Degrees() );
+ }
+
double x2 = 0.5*float(index2) - 1.75;
double dx = (alt->Degrees() - x1)/(x2 - x1);
@@ -1483,16 +1508,44 @@
}
}
-bool SkyMap::unusablePoint ( const QPointF &p )
+bool SkyMap::unusablePoint( const QPointF &p )
{
+ double r0 = 1.0;
+ //r0 is the angular size of the sky horizon, in radians
+ //See HorizonComponent::draw() for documentation of these values
+ switch ( Options::projection() ) {
+ case Lambert:
+ r0 = 1.41421356; break;
+ case AzimuthalEquidistant:
+ r0 = 1.57079633; break;
+ case Stereographic:
+ r0 = 2.0; break;
+ case Gnomonic:
+ r0 = 6.28318531; break; //Gnomonic has an infinite horizon; this is 2*PI
+ case Orthographic:
+ default:
+ break;
+ }
+
+ //If the zoom is high enough, all points are usable
+ //The center-to-corner distance, in radians
+ double r = 0.5*1.41421356*width() / Options::zoomFactor();
+ if ( r < r0 ) {
+ return false;
+ }
+
+ //At low zoom, we have to determine whether the point is beyond the sky horizon
//Convert pixel position to x and y offsets in radians
double dx = ( 0.5*width() - p.x() )/Options::zoomFactor();
double dy = ( 0.5*height() - p.y() )/Options::zoomFactor();
+ double rsq = ( dx*dx + dy*dy );
+ r0 = r0*r0;
- if (dx >= 1.41 || dx <= -1.41 || dy >= 1.41 || dy <= -1.41)
- return true;
- else
+ if (rsq < r0) {
return false;
+ }
+
+ return true;
}
void SkyMap::setZoomMouseCursor()
More information about the Kstars-devel
mailing list