[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kstars-devel
Subject:    [Kstars-devel] [patch] improve rendering time for stars by a factor
From:       Jason Harris <jharris () 30doradus ! org>
Date:       2007-12-23 6:24:04
Message-ID: 200712222324.04746.kstars () 30doradus ! org
[Download RAW message or body]

Hello,

I've attached a patch that draws stars twenty times faster than our current 
code.  The difference is made by reinstating something we had in 3.x: a cache 
of star pixmaps covering all sizes and colors, drawn on the map with 
drawPixmap(), instead of using drawEllipse().

The stellar pixmaps are stored in a static QHash in StarObject, and 
initialized once in StarComponent::init().  When a star needs to be drawn, 
the QHash key is constructed from the star's spectral type, and the int() of 
the size parameter passed by StarComponent (e.g., "K07" for a bright red 
star, or "B02" for a faint blue star).

I added timing code to StarComponent to test the time taken by the star 
catalog draw loop.  Try this test: add the timing code without changing 
anything else, then start KStars, and set both of the stars' magnitude limits 
to 10.0.  Zoom out so you can see most of the sky, then press "." to stop the 
clock and advance one time step.  Hit that a few times to get an average 
rendering time for all those stars.  On my machine it was about 7.7 seconds.

Then close Kstars, apply the rest of the patch, recompile, and run the same 
timing test.  On my machine the same rendering loops were taking 0.3 seconds!

I didn't simply apply the code, because I'm a little reluctant to introduce 
such a big change while we're frozen and a couple weeks away from a major 
release.  It appears to work beautifully, but I have not implemented 
color-switching for Star Chart and Night Vision color schemes (not hard to 
do), and there may be some issues that I'm unaware of.

So, I want people's opinion.  Should we consider this a bugfix, or at least a 
regression fix, and add it now?  Or should we hold off until trunk thaws?  
I'd really like some help testing this change if we're going to add it now.

Whatever we decide, exciting times are ahead.  With this fix, we'll be able to 
finally increase the number of stars handled by KStars well into the millions 
with no degradation in performance compared to what it does now.  And 
actually, if we're smart about ignoring faint stars at low zoom, the 
performance should be really good.

regards,
Jason

["stars_as_images.patch" (text/x-diff)]

Index: starobject.h
===================================================================
--- starobject.h	(revision 751528)
+++ starobject.h	(working copy)
@@ -283,11 +283,14 @@
     	*/
     static void updateColors( bool desaturateColors, int saturation );
 
+    static void initImages();
+
     quint64 updateID;
     quint64 updateNumID;
 
 protected:
     static QMap<QString, QColor> ColorMap;
+    static QHash<QString, QPixmap> StarImage;
 
 private:
     QString SpType;
Index: skycomponents/starcomponent.cpp
===================================================================
--- skycomponents/starcomponent.cpp	(revision 751528)
+++ skycomponents/starcomponent.cpp	(working copy)
@@ -74,6 +74,8 @@
 
     readLineNumbers();
     readData( Options::magLimitDrawStar() );
+
+    StarObject::initImages();
 }
 
 void StarComponent::update( KStarsData *data, KSNumbers *num )
@@ -212,21 +214,27 @@
     labelMagLim += ( 12.0 - labelMagLim ) * ( lgz - lgmin) / (lgmax - lgmin );
     if ( labelMagLim > 8.0 ) labelMagLim = 8.0;
 
-    //Set the brush
-    QColor fillColor( Qt::white );
-    if ( starColorMode() == 1 ) fillColor = Qt::red;
-    if ( starColorMode() == 2 ) fillColor = Qt::black;
-    psky.setBrush( QBrush( fillColor ) );
-    if ( starColorMode() > 0 )
-        psky.setPen( QPen( fillColor ) );
-    else
-        //Reset the colors before drawing the stars.
-        //Strictly speaking, we don't need to do this every time, but once per
-        //draw loop isn't too expensive.
-        StarObject::updateColors( (! Options::useAntialias() ||
-                                   map->isSlewing()), starColorIntensity() );
+//REMOVE
+//     //Set the brush
+//     QColor fillColor( Qt::white );
+//     if ( starColorMode() == 1 ) fillColor = Qt::red;
+//     if ( starColorMode() == 2 ) fillColor = Qt::black;
+//     psky.setBrush( QBrush( fillColor ) );
+//     if ( starColorMode() > 0 )
+//         psky.setPen( QPen( fillColor ) );
+//     else
+//        //Reset the colors before drawing the stars.
+//        //Strictly speaking, we don't need to do this every time, but once per
+//        //draw loop isn't too expensive.
+//        StarObject::updateColors( (! Options::useAntialias() ||
+//                                   map->isSlewing()), starColorIntensity() );
+//END_REMOVE
 
     //Loop for drawing star images
+    //DEBUG_TIME_STARS
+    QTime t;
+    t.start();
+
     MeshIterator region(m_skyMesh, DRAW_BUF);
     while ( region.hasNext() ) {
         StarList* starList = m_starIndex->at( region.next() );
@@ -258,6 +266,10 @@
             addLabel( o, curStar );
         }
     }
+
+    //DEBUG_TIME_STARS
+    kDebug() << QString("drawing stars took %1 ms").arg(t.elapsed());
+
 }
 
 void StarComponent::addLabel( const QPointF& p, StarObject *star )
Index: starobject.cpp
===================================================================
--- starobject.cpp	(revision 751528)
+++ starobject.cpp	(working copy)
@@ -32,6 +32,7 @@
 #include "skycomponents/skylabeler.h"
 
 QMap<QString, QColor> StarObject::ColorMap;
+QHash<QString, QPixmap> StarObject::StarImage;
 
 //----- Static Methods -----
 //
@@ -104,6 +105,33 @@
     updateID = updateNumID = 0;
 }
 
+void StarObject::initImages() {
+    ColorMap.insert( "O", QColor::fromRgb(   0,   0, 255 ) );
+    ColorMap.insert( "B", QColor::fromRgb(   0, 200, 255 ) );
+    ColorMap.insert( "A", QColor::fromRgb(   0, 255, 255 ) );
+    ColorMap.insert( "F", QColor::fromRgb( 200, 255, 100 ) );
+    ColorMap.insert( "G", QColor::fromRgb( 255, 255,   0 ) );
+    ColorMap.insert( "K", QColor::fromRgb( 255, 100,   0 ) );
+    ColorMap.insert( "M", QColor::fromRgb( 255,   0,   0 ) );
+
+    foreach ( QString color, ColorMap.keys() ) {
+        QString imKey = color+"10";
+        QPixmap BigImage( 10, 10 ); 
+        QPainter p;
+        p.begin( &BigImage );
+        p.setPen( QPen(ColorMap[color], 2) );
+        p.setBrush( QColor(Qt::white) );
+        p.drawEllipse( QRect( 0, 0, 10, 10 ) );
+        p.end();
+        StarImage.insert( imKey, BigImage );
+
+        for ( int size = 9; size > 0; size-- ) {
+            imKey = color+QString("0%1").arg(size);
+            StarImage.insert( imKey, BigImage.scaled( size, size, \
Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); +        }
+    }
+}
+
 void StarObject::showPopupMenu( KSPopupMenu *pmenu, const QPoint &pos ) {
     pmenu->createStarMenu( this ); pmenu->popup( pos );
 }
@@ -325,23 +353,39 @@
 void StarObject::draw( QPainter &psky, float x, float y, float size,
                        bool useRealColors, int scIntensity, bool /*showMultiple*/ ) \
{  
-    if ( useRealColors ) {
+//REMOVE
+//    if ( useRealColors ) {
         //Realistic colors
         //Stars rendered as a white core with a colored ring.
         //With antialiasing, we can just set the ring thickness to 0.1*scIntensity
         //However, this won't work without antialiasing, because the ring thickness
         //cant be <1 in this case.  So we desaturate the pen color instead
-        if ( Options::useAntialias() )
-            psky.setPen( QPen( color(), 0.1*scIntensity ) );
-        else {
-            psky.setPen( QPen( color(), 1 ) );
+
+//         if ( Options::useAntialias() )
+//             psky.setPen( QPen( color(), 0.1*scIntensity ) );
+//         else {
+//             psky.setPen( QPen( color(), 1 ) );
+//         }
+//     }
+//END_REMOVE
+
+        int isize = int(size);
+        if ( isize > 10 ) {
+            kDebug() << "Star too big: " << size << endl;
+            isize = 10;
         }
-    }
 
-    if ( Options::useAntialias() )
-        psky.drawEllipse( QRectF( x - 0.5*size, y - 0.5*size, size, size ) );
-    else
-        psky.drawEllipse( QRect( int(x - 0.5*size), int(y - 0.5*size), int(size), \
int(size) ) ); +        float offset = 0.5*float(isize);
+        QString imKey = SpType.at(0)+QString("0%1").arg(isize);
+        psky.drawPixmap( QPointF(x-offset, y-offset), StarImage[imKey] );
+
+//REMOVE
+//     if ( Options::useAntialias() )
+//         psky.drawEllipse( QRectF( x - 0.5*size, y - 0.5*size, size, size ) );
+//     else
+//         psky.drawEllipse( QRect( int(x - 0.5*size), int(y - 0.5*size), int(size), \
int(size) ) ); +//END_REMOVE
+
 }
 
 // The two routines below seem overly complicated but at least they are doing



_______________________________________________
Kstars-devel mailing list
Kstars-devel@kde.org
https://mail.kde.org/mailman/listinfo/kstars-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic