[Kstars-devel] KDE/kdeedu/kstars/kstars

Jason Harris kstars at 30doradus.org
Tue Jun 13 05:25:40 CEST 2006


SVN commit 550894 by harris:

Committing changes from James Bowlin to fix a rendering bug.  
Constellation lines were disappearing at high zoom when one of the 
endpoints was far off-screen.  This patch uses interpolation to truncate 
the constellation line at the edge of the visible skymap.

Thanks James!

CCMAIL: kstars-devel at kde.org


 M  +8 -17     skycomponents/constellationlinescomponent.cpp  
 M  +14 -4     skymap.cpp  
 M  +12 -2     skymap.h  
 M  +94 -0     skymapdraw.cpp  


--- trunk/KDE/kdeedu/kstars/kstars/skycomponents/constellationlinescomponent.cpp #550893:550894
@@ -42,26 +42,17 @@
 	if ( !visible() ) return;
 
 	SkyMap *map = ks->map();
-	float Width = scale * map->width();
-	float Height = scale * map->height();
 
 	//Draw Constellation Lines
 	psky.setPen( QPen( QColor( ks->data()->colorScheme()->colorNamed( "CLineColor" ) ), 1, Qt::SolidLine ) ); //change to CLine color
 //	int iLast = -1;
 
-	QPointF oStart;
-	for ( int i=0; i < pointList().size(); ++i ) {
-		QPointF o = map->toScreen( pointList().at(i), scale );
-
-		if ( ( o.x() >= -1000. && o.x() <= Width+1000. && o.y() >=-1000. && o.y() <= Height+1000. ) ) {
-			if ( oStart.x() != 0 && m_CLineModeList.at(i)=='D' ) {
-				if ( Options::useAntialias() )
-					psky.drawLine( oStart, o );
-				else
-					psky.drawLine( QPoint(int(oStart.x()),int(oStart.y())), 
-								QPoint(int(o.x()), int(o.y())) );
-			}
-			oStart = o;
-		}
-  }
+	SkyPoint *pLast = pointList().at(0);
+	for ( int i=1; i < pointList().size(); ++i ) {
+        SkyPoint *pThis = pointList().at(i);
+        if (m_CLineModeList.at(i) == 'D') {
+            map->drawClippedLine( pLast, pThis, psky, scale);
+        }
+        pLast = pThis;
+    }
 }
--- trunk/KDE/kdeedu/kstars/kstars/skymap.cpp #550893:550894
@@ -751,7 +751,8 @@
 	return ( north + o->pa() );
 }
 
-QPointF SkyMap::toScreen( SkyPoint *o, double scale, bool oRefract ) {
+QPointF SkyMap::toScreen( SkyPoint *o, double scale, bool oRefract, bool *clipped) {
+
 	QPointF p;
 	double Y, dX;
 	double sindX, cosdX, sinY, cosY, sinY0, cosY0;
@@ -813,10 +814,19 @@
 	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;
+        if ( clipped == NULL) {
+		    p.setX( -10000000. );
+		    p.setY( -10000000. );
+		    return p;
+        }
+        *clipped = true;
 	}
+    else {
+        if ( clipped != NULL ) {
+            *clipped = false;
+        }
+    }
+        
 
 	double k;
 	switch ( Options::projection() ) {
--- trunk/KDE/kdeedu/kstars/kstars/skymap.h #550893:550894
@@ -362,7 +362,16 @@
 	*@see KStars::slotPrint()
 	*/
 	void exportSkyImage( QPaintDevice *pd );
+    
+/**@short Draw a clipped line from p1 to p2
+ */
+    void SkyMap::drawClippedLine( SkyPoint *p1, SkyPoint *p2, QPainter& psky, double scale );
 
+/**ASSUMES *p1 did not clip but *p2 did.  Returns the QPointF on the line
+ * between *p1 and *p2 that just clips.
+ **/
+    QPointF SkyMap::clipLine( SkyPoint *p1, SkyPoint *p2, double scale);
+
 /**Given the coordinates of the SkyPoint argument, determine the
 	*pixel coordinates in the SkyMap.
 	*@return QPoint containing screen pixel x, y coordinates of SkyPoint.
@@ -371,8 +380,9 @@
 	*@param useRefraction true = use Options::useRefraction() value.  
 	*false = do not use refraction.  This argument is only needed 
 	*for the Horizon, which should never be refracted.
-	*/
-	QPointF toScreen( SkyPoint *o, double scale=1.0, bool useRefraction=true );
+    *@param clipped pointer to a bool indicating point is past horizon
+    **/
+	QPointF toScreen( SkyPoint *o, double scale=1.0, bool useRefraction=true, bool *clipped=NULL);
 
 /**Determine RA, Dec coordinates of the pixel at (dx, dy), which are the
 	*screen pixel coordinate offsets from the center of the Sky pixmap.
--- trunk/KDE/kdeedu/kstars/kstars/skymapdraw.cpp #550893:550894
@@ -47,6 +47,100 @@
 #include "indidevice.h"
 #include "observinglist.h"
 
+void toXYZ(SkyPoint* p, double *x, double *y, double *z) {
+    double sinRa, sinDec, cosRa, cosDec;
+
+    p->ra()->SinCos( sinRa, cosRa );
+    p->dec()->SinCos( sinDec, cosDec );
+    *x = cosDec * cosRa;
+    *y = cosDec * sinRa;
+    *z = sinDec;
+}
+
+void SkyMap::drawClippedLine( SkyPoint *p1, SkyPoint *p2, QPainter& psky, double scale )
+{
+/**
+ if both points are clipped: do nothing
+ if no   points are clipped: draw the line
+ if one    point is clipped: find approx point on edge and draw to it.
+
+We do the interpolation in x-y-z space because interpolation in [ra, dec] gives
+weird results, especially around the poles.
+**/
+    bool clipped1, clipped2;
+    QPointF o1, o2, oMid;
+    o1 = toScreen( p1, scale, Options::useRefraction(), &clipped1 );
+    o2 = toScreen( p2, scale, Options::useRefraction(), &clipped2 );
+
+    if (clipped1 && clipped2 ) {
+        return;
+    }
+    else if (! clipped1 && ! clipped2 ) {
+         psky.drawLine( o1, o2 );
+    }
+    else if (clipped2) {
+        oMid = clipLine( p1, p2, scale );
+        psky.drawLine( o1, oMid );
+    }
+    else {
+        oMid = clipLine( p2, p1, scale );
+        psky.drawLine ( o2, oMid );
+    }
+}
+
+QPointF SkyMap::clipLine( SkyPoint *p1, SkyPoint *p2, double scale )
+{
+/* ASSUMES p1 was not clipped but p2 was. 
+ * Return the QPoint that barely clips in the line twixt p1 and p2.
+ */              
+    int iteration = 15;         // For "perfect" clipping:
+                                // 2^interations should be >= max pixels/line
+    bool clipped = false;       // so we start at midpoint
+    SkyPoint mid;
+    QPointF oMid;
+    double x, y, z, dx, dy, dz, ra, dec;
+    int newx, newy, oldx, oldy;
+    oldx = oldy = -10000;        // any old value that is not the first omid
+    
+    toXYZ( p1, &x, &y, &z );
+    toXYZ( p2, &dx, &dy, &dz );
+    dx -= x;
+    dy -= y;
+    dz -= z;
+    // Successive approximation to point on line that just clips.
+    while(iteration-- > 0) {
+        dx *= .5;
+        dy *= .5;
+        dz *= .5;
+        if ( clipped ) {              // move back toward visible p1
+            x -= dx;
+            y -= dy;
+            z -= dz;
+        }
+        else {                        // move out toward clipped p2
+            x += dx;
+            y += dy;
+            z += dz;
+        }
+        // [x, y, z] => [ra, dec] 
+        ra = atan2( y, x );
+        dec = asin( z / sqrt(x*x + y*y + z*z) );
+        
+        mid = SkyPoint( ra * 12. / dms::PI, dec * 180. / dms::PI );
+        mid.EquatorialToHorizontal( data->LST, data->geo()->lat() );
+
+        oMid = toScreen( &mid, scale, Options::useRefraction(), &clipped );
+        newx = (int) oMid.x();
+        newy = (int) oMid.y();
+        if ( (oldx == newx) && (oldy == newy) ) {
+            break;
+        }
+        oldx = newx;
+        oldy = newy;
+    }
+    return  oMid;
+}
+
 void SkyMap::drawOverlays( QPixmap *pm ) {
 	if ( ks ) { //only if we are drawing in the GUI window
 		QPainter p;


More information about the Kstars-devel mailing list