Hi,

Am 29.10.11 14:01 schrieb(en) Oliver Eichler:
@Albrecht & Michael can one of you both test this on OS X. I would be
interested if the little obnoxious transparent problem on some OS X
based platforms can be solved by that.

Tested it on 10.5/Intel, and unfortunately it does /not/ fix the
rendering issue. Didn't test it on 10.4/PPC yet (as building takes

:( well it was worth a try. Thanks.

can you elaborate on that rendering issue?

I tried to speed up Garmin maps a bit. The results are in SVN.
Unfortunately exchanging QImage with QPixmap for line drawing did not
help. Still vector maps are rendered slow.

I recently played with another way to speed up polylines in Garmin maps: Instead of trying to make the actual drawing faster I tried to reduce the number of images to be drawn with the Douglas-Peucker algorithm. It's not uncommon to have >>10.000 QImages in the viewport, many (if not most) of them can often be eliminated without sacrificing significant map detail. In some cases the time spent in drawPolylines() is halved.

Patch (against trunk) is attached. The functionality can be switched on and off the config dialog. Currently it's also possible to directly enter the epsilon value there.

Regards,
Michael

--
Q: Does it run under windows?
A: Who cares?
        -- from the babygimp homepage
From f99f059507e6f2f8095c0c251d3605a487cb8912 Mon Sep 17 00:00:00 2001
From: Michael Klein <[email protected]>
Date: Tue, 1 Nov 2011 20:49:27 +0100
Subject: [PATCH] Simplify polylines with Douglas-Peucker to speed up drawing

---
 src/CDlgConfig.cpp |   30 +++++---
 src/CMap3D.cpp     |    4 +
 src/CMapTDB.cpp    |  197 +++++++++++++++++++++++++++++++++++++++++----------
 src/CMapTDB.h      |    2 +
 src/CResources.cpp |   19 ++++--
 src/CResources.h   |    4 +
 src/IDlgConfig.ui  |   42 ++++++++++-
 7 files changed, 238 insertions(+), 60 deletions(-)

diff --git a/src/CDlgConfig.cpp b/src/CDlgConfig.cpp
index 1514b02..8a20c1d 100644
--- a/src/CDlgConfig.cpp
+++ b/src/CDlgConfig.cpp
@@ -52,6 +52,7 @@ CDlgConfig::CDlgConfig(QWidget * parent)
     connect(checkGeoDBSaveOnExit, SIGNAL(clicked(bool)), spinGeoDBMinutes, 
SLOT(setEnabled(bool)));
 #endif
 
+    connect(checkSimplifyPolylines, SIGNAL(toggled(bool)), 
widgetPolylineSimplificationEpsilon, SLOT(setEnabled(bool)));
 }
 
 
@@ -99,7 +100,9 @@ void CDlgConfig::exec()
     spinGeoDBMinutes->setValue(resources.m_saveGeoDBMinutes);
     labelPathGeoDB->setText(resources.m_pathGeoDB.absolutePath());
 #endif
-
+    checkSimplifyPolylines->setChecked(resources.m_simplifyPolylines);
+    
spinPolylineSimplificationEpsilon->setValue(resources.m_polylineSimplificationEpsilon);
+    
spinPolylineSimplificationEpsilon->setEnabled(resources.m_simplifyPolylines);
 
     comboDevice->addItem(tr(""),"");
     comboDevice->addItem(tr("QLandkarte M"), "QLandkarteM");
@@ -173,21 +176,24 @@ void CDlgConfig::accept()
         resources.unit = new CUnitNautic(&resources);
     }
 
-    resources.m_flipMouseWheel  = checkFlipMouseWheel->isChecked();
+    resources.m_flipMouseWheel    = checkFlipMouseWheel->isChecked();
     resources.m_showTrackProfile  = checkShowProfilePreview->isChecked();
-    resources.m_showNorth       = checkShowNorth->isChecked();
-    resources.m_showScale       = checkShowScale->isChecked();
-    resources.m_showToolTip     = checkTooltip->isChecked();
-    resources.m_showZoomLevel   = checkShowZoomLevel->isChecked();
-    resources.m_playSound       = checkPlaySound->isChecked();
-    resources.m_useAntiAliasing = checkAntiAliasing->isChecked();
-    resources.m_reducePoiIcons  = checkReducePoiIcons->isChecked();
+    resources.m_showNorth         = checkShowNorth->isChecked();
+    resources.m_showScale         = checkShowScale->isChecked();
+    resources.m_showToolTip       = checkTooltip->isChecked();
+    resources.m_showZoomLevel     = checkShowZoomLevel->isChecked();
+    resources.m_playSound         = checkPlaySound->isChecked();
+    resources.m_useAntiAliasing   = checkAntiAliasing->isChecked();
+    resources.m_reducePoiIcons    = checkReducePoiIcons->isChecked();
+    resources.m_simplifyPolylines = checkSimplifyPolylines->isChecked();
+
+    resources.m_polylineSimplificationEpsilon = 
spinPolylineSimplificationEpsilon->value();
 
 #ifdef HAS_GEODB
-    resources.m_useGeoDB        = checkUseGeoDB->isChecked();
-    resources.m_saveGeoDBOnExit = checkGeoDBSaveOnExit->isChecked();
+    resources.m_useGeoDB         = checkUseGeoDB->isChecked();
+    resources.m_saveGeoDBOnExit  = checkGeoDBSaveOnExit->isChecked();
     resources.m_saveGeoDBMinutes = spinGeoDBMinutes->value();
-    resources.m_pathGeoDB       = QDir(labelPathGeoDB->text());
+    resources.m_pathGeoDB        = QDir(labelPathGeoDB->text());
 #endif
 
 
diff --git a/src/CMap3D.cpp b/src/CMap3D.cpp
index 11416b2..dddcdc9 100644
--- a/src/CMap3D.cpp
+++ b/src/CMap3D.cpp
@@ -34,7 +34,11 @@
 #include <QtGui>
 #include <QtOpenGL>
 #include <math.h>
+#if defined(Q_WS_MAC)
+#include <OpenGL/glu.h>
+#else
 #include <GL/glu.h>
+#endif
 
 #ifndef GL_CLAMP_TO_EDGE
 #define GL_CLAMP_TO_EDGE 0x812F
diff --git a/src/CMapTDB.cpp b/src/CMapTDB.cpp
index 83b6fc6..95c1bda 100644
--- a/src/CMapTDB.cpp
+++ b/src/CMapTDB.cpp
@@ -40,6 +40,8 @@
 #include <QSqlDatabase>
 #include <algorithm>
 
+#include <QElapsedTimer>
+
 //#include <sys/time.h>
 
 #ifdef WIN32
@@ -442,30 +444,11 @@ CMapTDB::~CMapTDB()
 
     if(pjsrc) pj_free(pjsrc);
 
-    if(checkPoiLabels)
-    {
-        delete checkPoiLabels;
-    }
-
-    if(checkNightView)
-    {
-        delete checkNightView;
-    }
-
-    if(comboDetails)
-    {
-        delete comboDetails;
-    }
-
-    if(comboLanguages)
-    {
-        delete comboLanguages;
-    }
-
-    if(comboTypfiles)
-    {
-        delete comboTypfiles;
-    }
+    delete checkPoiLabels;
+    delete checkNightView;
+    delete comboDetails;
+    delete comboLanguages;
+    delete comboTypfiles;
 
     qDebug() << "CMapTDB::~CMapTDB()";
 }
@@ -1933,6 +1916,108 @@ void CMapTDB::draw(QPainter& p)
 }
 
 
+void CMapTDB::simplifyPolyline(QPolygonF & line) const
+{
+    class Simplifier
+    {
+    public:
+        Simplifier(float epsilon): epsilon(epsilon) {}
+
+        void simplify(QPolygonF::iterator begin, QPolygonF::iterator end)
+        {
+            if (std::distance(begin, end) > 2)
+            {
+                const QPointF & p1 = *begin++;
+                const QPointF & p2 = *--end;
+
+                double dist, max_dist = 0.0;
+                QPolygonF::iterator pos, max_pos = end;
+
+                if (p2.x() == p1.x())
+                {
+                    double min_y = std::min(p1.y(), p2.y());
+                    double max_y = std::max(p1.y(), p2.y());
+
+                    for (pos = begin; pos != end; pos++)
+                    {
+                        const QPointF & p = *pos;
+
+                        if (p.y() < min_y)
+                        {
+                            dist = sqrt((p1.x() - p.x()) * (p1.x() - p.x()) + 
(min_y - p.y()) * (min_y - p.y()));
+                        }
+                        else if (p.y() > max_y)
+                        {
+                            dist = sqrt((p1.x() - p.x()) * (p1.x() - p.x()) + 
(max_y - p.y()) * (max_y - p.y()));
+                        }
+                        else
+                        {
+                            dist = abs(p.x() - p1.x());
+                        }
+
+                        if (dist > max_dist)
+                        {
+                            max_pos = pos;
+                            max_dist = dist;
+                        }
+                    }
+                }
+                else
+                {
+                    double m = (p2.y() - p1.y()) / (p2.x() - p1.x());
+                    double n = -1.0 / m;
+                    double c = p1.y() - m * p1.x();
+
+                    double min_x = std::min(p1.x(), p2.x());
+                    double max_x = std::max(p1.x(), p2.x());
+
+                    for (pos = begin; pos != end; pos++)
+                    {
+                        const QPointF & p = *pos;
+
+                        double d = p.y() - n * p.x();
+                        double x = (c - d) / (n - m);
+
+                        if (x >= min_x && x <= max_x)
+                        {
+                            double y = m * x + c;
+                            dist = sqrt((p.x() - x) * (p.x() - x) + (p.y() - 
y) * (p.y() - y));
+                        }
+                        else
+                        {
+                            dist = std::min(sqrt((p1.x() - p.x()) * (p1.x() - 
p.x()) + (p1.y() - p.y()) * (p1.y() - p.y())),
+                                            sqrt((p2.x() - p.x()) * (p2.x() - 
p.x()) + (p2.y() - p.y()) * (p2.y() - p.y())));
+                        }
+
+                        if (dist > max_dist)
+                        {
+                            max_pos = pos;
+                            max_dist = dist;
+                        }
+                    }
+                }
+
+                if (max_dist >= epsilon)
+                {
+                    simplify(max_pos, end);
+                    simplify(begin, max_pos + 1);
+                }
+                else
+                {
+                    std::fill(begin, end, p1);
+                }
+            }
+        }
+
+        float epsilon;
+    };
+
+    double epsilon = CResources::self().polylineSimplificationEpsilon();
+    Simplifier(epsilon).simplify(line.begin(), line.end());
+    line.resize(std::unique(line.begin(), line.end()) - line.begin());
+}
+
+
 void CMapTDB::draw(const QSize& s, bool needsRedraw, QPainter& p)
 {
     int i;
@@ -1988,6 +2073,7 @@ void CMapTDB::draw()
     fm = QFontMetrics(f);
 
     USE_ANTI_ALIASING(p,!doFastDraw && CResources::self().useAntiAliasing());
+
     p.setFont(f);
     p.setPen(Qt::black);
     p.setBrush(Qt::NoBrush);
@@ -2056,13 +2142,20 @@ void CMapTDB::draw()
 
     if(!doFastDraw)
     {
+        QElapsedTimer et;
         QVector<QRect> rectPois;
 
+        et.start();
         drawPolylines(p, polylines);
+        qDebug() << "drawPolylines: " << et.restart() << "ms";
         drawPoints(p, points, rectPois);
+        qDebug() << "drawPoints: " << et.restart() << "ms";
         drawPois(p, pois, rectPois);
+        qDebug() << "drawPois: " << et.restart() << "ms";
         drawText(p);
+        qDebug() << "drawText: " << et.restart() << "ms";
         drawLabels(p, labels);
+        qDebug() << "drawLabels: " << et.restart() << "ms";
 
     }
 
@@ -2098,6 +2191,11 @@ void CMapTDB::drawLine(QPainter& p, CGarminPolygon& l, 
const IGarminTyp::polylin
         line.append(QPointF(*u++, *v++));
     }
 
+    if (CResources::self().simplifyPolylines())
+    {
+        simplifyPolyline(line);
+    }
+
     if (zoomFactor < STREETNAME_THRESHOLD && property.labelType != 
IGarminTyp::eNone)
     {
         collectText(l, line, font, metrics, lineWidth);
@@ -2178,6 +2276,8 @@ void CMapTDB::drawPolylines(QPainter& p, polytype_t& 
lines)
     int pixmapCount = 0;
     int borderCount = 0;
     int normalCount = 0;
+    int imageCount = 0;
+    int deletedCount = 0;
 
     QHash<quint32, QList<quint32> > dict;
     for(int i = 0; i < lines.count(); ++i)
@@ -2210,9 +2310,9 @@ void CMapTDB::drawPolylines(QPainter& p, polytype_t& 
lines)
 
                     pixmapCount++;
 
-                    double * u      = item.u.data();
-                    double * v      = item.v.data();
-                    const int size  = item.u.size();
+                    double * u = item.u.data();
+                    double * v = item.v.data();
+                    int size   = item.u.size();
 
                     if(size < 2)
                     {
@@ -2221,27 +2321,39 @@ void CMapTDB::drawPolylines(QPainter& p, polytype_t& 
lines)
 
                     convertRad2Pt(u,v,size);
 
+                    int i;
+
                     line.resize(0);
                     line.reserve(size);
 
                     lengths.resize(0);
+
+                    for(i = 0; i < size; ++i)
+                    {
+                        line.append(QPointF(u[i], v[i]));
+                    }
+
+                    if (CResources::self().simplifyPolylines())
+                    {
+                        deletedCount += line.size();
+                        simplifyPolyline(line);
+                        deletedCount -= line.size();
+                        size = line.size();
+                    }
+
                     lengths.reserve(size);
 
                     double u1, u2, v1, v2;
                     QPainterPath path;
                     double segLength, totalLength = 0;
-                    int i;
 
-                    u1 = u[0];
-                    v1 = v[0];
-                    line.append(QPointF(u1,v1));
+                    u1 = line[0].x();
+                    v1 = line[0].y();
 
                     for(i = 1; i < size; ++i)
                     {
-                        u2 = u[i];
-                        v2 = v[i];
-
-                        line.append(QPointF(u2,v2));
+                        u2 = line[i].x();
+                        v2 = line[i].y();
 
                         segLength    = sqrt((u2 - u1) * (u2 - u1) + (v2 - v1) 
* (v2 - v1));
                         totalLength += segLength;
@@ -2298,6 +2410,7 @@ void CMapTDB::drawPolylines(QPainter& p, polytype_t& 
lines)
                         }
 #else
                         p.drawImage(0,-h/2, img2line(pixmap, segLength));
+                        imageCount++;
 #endif
 
                         p.restore();
@@ -2342,7 +2455,11 @@ void CMapTDB::drawPolylines(QPainter& p, polytype_t& 
lines)
         }
 
     }
-    //    fprintf(stderr, "pixmapCount: %d, borderCount: %d, normalCount: 
%d\n", pixmapCount, borderCount, normalCount);
+    qDebug() << "pixmapCount:" << pixmapCount
+        << "borderCount:" << borderCount
+        << "normalCount:" << normalCount
+        << "imageCount:" << imageCount
+        << "deletedCount:" << deletedCount;
 }
 
 
@@ -2684,7 +2801,6 @@ inline bool isCluttered(QVector<QRect>& rectPois, const 
QRect& rect)
 
 void CMapTDB::drawPoints(QPainter& p, pointtype_t& pts, QVector<QRect>& 
rectPois)
 {
-
     pointtype_t::iterator pt = pts.begin();
     while(pt != pts.end())
     {
@@ -2752,6 +2868,9 @@ void CMapTDB::drawPois(QPainter& p, pointtype_t& pts, 
QVector<QRect>& rectPois)
     IGarminTyp::label_type_e labelType = IGarminTyp::eStandard;
     bool showLabel = true;
 
+    QPixmap blueBullet(":/icons/small_bullet_blue.png");
+    QPixmap redBullet(":/icons/small_bullet_red.png");
+
     pointtype_t::iterator pt = pts.begin();
     while(pt != pts.end())
     {
@@ -2759,7 +2878,7 @@ void CMapTDB::drawPois(QPainter& p, pointtype_t& pts, 
QVector<QRect>& rectPois)
 
         if(isCluttered(rectPois, QRect(pt->lon, pt->lat,16,16)))
         {
-            p.drawPixmap(pt->lon - 4, pt->lat - 4, 
QPixmap(":/icons/small_bullet_blue.png"));
+            p.drawPixmap(pt->lon - 4, pt->lat - 4, blueBullet);
             ++pt;
             continue;
         }
@@ -2774,7 +2893,7 @@ void CMapTDB::drawPois(QPainter& p, pointtype_t& pts, 
QVector<QRect>& rectPois)
         }
         else
         {
-            p.drawPixmap(pt->lon - 4, pt->lat - 4, 
QPixmap(":/icons/small_bullet_red.png"));
+            p.drawPixmap(pt->lon - 4, pt->lat - 4, redBullet);
         }
 
         if(showLabel)
diff --git a/src/CMapTDB.h b/src/CMapTDB.h
index 1a87953..4e71639 100644
--- a/src/CMapTDB.h
+++ b/src/CMapTDB.h
@@ -137,6 +137,8 @@ class CMapTDB : public IMap
         void drawLine(QPainter& p, CGarminPolygon& l, const 
IGarminTyp::polyline_property& property, const QFontMetricsF& metrics, const 
QFont& font);
         void drawLine(QPainter& p, const CGarminPolygon& l);
 
+        void simplifyPolyline(QPolygonF & line) const;
+
         QString createLegendString(const QMap<int,QString>& strings);
 
 #pragma pack(1)
diff --git a/src/CResources.cpp b/src/CResources.cpp
index ad5f30d..e02bd58 100644
--- a/src/CResources.cpp
+++ b/src/CResources.cpp
@@ -64,6 +64,8 @@ CResources::CResources(QObject * parent)
 , m_showZoomLevel(true)
 , m_useAntiAliasing(true)
 , m_reducePoiIcons(true)
+, m_simplifyPolylines(true)
+, m_polylineSimplificationEpsilon(2.5)
 , m_WptTextColor(Qt::black)
 
 {
@@ -132,12 +134,15 @@ CResources::CResources(QObject * parent)
     }
 
     m_showTrackProfile  = 
cfg.value("environment/showTrackProfile",m_showTrackProfile).toBool();
-    m_showNorth     = cfg.value("environment/showNorth",m_showNorth).toBool();
-    m_showScale     = cfg.value("environment/showScale",m_showScale).toBool();
-    m_showToolTip   = 
cfg.value("environment/showToolTip",m_showToolTip).toBool();
-    m_showZoomLevel = 
cfg.value("environment/showZoomLevel",m_showZoomLevel).toBool();
-    m_useAntiAliasing = 
cfg.value("environment/useAntiAliasing",m_useAntiAliasing).toBool();
-    m_reducePoiIcons = 
cfg.value("environment/reducePoiIcons",m_reducePoiIcons).toBool();
+    m_showNorth         = 
cfg.value("environment/showNorth",m_showNorth).toBool();
+    m_showScale         = 
cfg.value("environment/showScale",m_showScale).toBool();
+    m_showToolTip       = 
cfg.value("environment/showToolTip",m_showToolTip).toBool();
+    m_showZoomLevel     = 
cfg.value("environment/showZoomLevel",m_showZoomLevel).toBool();
+    m_useAntiAliasing   = 
cfg.value("environment/useAntiAliasing",m_useAntiAliasing).toBool();
+    m_reducePoiIcons    = 
cfg.value("environment/reducePoiIcons",m_reducePoiIcons).toBool();
+    m_simplifyPolylines = 
cfg.value("environment/simplifyPolylines",m_simplifyPolylines).toBool();
+
+    m_polylineSimplificationEpsilon = 
cfg.value("environment/polylineSimplificationEpsilon",m_polylineSimplificationEpsilon).toDouble();
 
     m_WptTextColor = QColor(cfg.value("environment/wptTextColor", 
m_WptTextColor.name()).toString());
 
@@ -203,6 +208,8 @@ CResources::~CResources()
     cfg.setValue("environment/showZoomLevel",m_showZoomLevel);
     cfg.setValue("environment/useAntiAliasing",m_useAntiAliasing);
     cfg.setValue("environment/reducePoiIcons",m_reducePoiIcons);
+    cfg.setValue("environment/simplifyPolylines",m_simplifyPolylines);
+    
cfg.setValue("environment/polylineSimplificationEpsilon",m_polylineSimplificationEpsilon);
 
     cfg.setValue("environment/wptTextColor", m_WptTextColor.name());
 }
diff --git a/src/CResources.h b/src/CResources.h
index e25cd1b..b0e76f3 100644
--- a/src/CResources.h
+++ b/src/CResources.h
@@ -72,6 +72,8 @@ class CResources : public QObject
         bool playSound(){return m_playSound;}
         bool useAntiAliasing(){return m_useAntiAliasing;}
         bool reducePoiIcons(){return m_reducePoiIcons;}
+        bool simplifyPolylines(){return m_simplifyPolylines;}
+        double polylineSimplificationEpsilon(){return 
m_polylineSimplificationEpsilon;}
 
         QColor wptTextColor(){return m_WptTextColor;}
 
@@ -145,6 +147,8 @@ class CResources : public QObject
         bool m_showZoomLevel;
         bool m_useAntiAliasing;
         bool m_reducePoiIcons;
+        bool m_simplifyPolylines;
+        double m_polylineSimplificationEpsilon;
 
         QColor m_WptTextColor;
 
diff --git a/src/IDlgConfig.ui b/src/IDlgConfig.ui
index 34f67b6..f1b1af5 100644
--- a/src/IDlgConfig.ui
+++ b/src/IDlgConfig.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>704</width>
-    <height>569</height>
+    <width>753</width>
+    <height>590</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -17,7 +17,7 @@
    <item>
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>3</number>
+      <number>0</number>
      </property>
      <widget class="QWidget" name="tab">
       <attribute name="title">
@@ -189,6 +189,42 @@
             </property>
            </widget>
           </item>
+          <item row="4" column="0">
+           <widget class="QCheckBox" name="checkSimplifyPolylines">
+            <property name="text">
+             <string>Simplify Polylines (Garmin maps)</string>
+            </property>
+           </widget>
+          </item>
+          <item row="4" column="2">
+           <widget class="QWidget" name="widgetPolylineSimplificationEpsilon" 
native="true">
+            <layout class="QHBoxLayout" 
name="layotPolylineSimplificationEpsilon">
+             <item>
+              <widget class="QLabel" name="labelPolylineSimplificationEpsilon">
+               <property name="text">
+                <string>Epsilon</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QDoubleSpinBox" 
name="spinPolylineSimplificationEpsilon"/>
+             </item>
+             <item>
+              <spacer name="horizontalSpacer_2">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+            </layout>
+           </widget>
+          </item>
          </layout>
         </widget>
        </item>
-- 
1.7.6.1

------------------------------------------------------------------------------
RSA&#174; Conference 2012
Save $700 by Nov 18
Register now&#33;
http://p.sf.net/sfu/rsa-sfdev2dev1
_______________________________________________
Qlandkartegt-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/qlandkartegt-users

Reply via email to