summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjuhvu <qt-info@nokia.com>2011-06-14 15:51:19 +1000
committerjuhvu <qt-info@nokia.com>2011-06-14 15:51:19 +1000
commitf9a921e84f19c52d7ea7452a47f8aa0c0417852b (patch)
tree42eb84e7f8f91269fb2f6a3a871d4c58a616c84b
parent416fdb11c2649f72a04cfe9c64d5fdc4cc175aa3 (diff)
downloadqtlocation-wip/experimental_scenegraphing.tar.gz
Map3D object visible in QML.wip/experimental_scenegraphing
-rw-r--r--src/imports/location/location.pro16
-rw-r--r--src/imports/location/qdeclarative3dgraphicsgeomap.cpp141
-rw-r--r--src/imports/location/qdeclarative3dgraphicsgeomap_p.h18
-rw-r--r--src/imports/location/tile.cpp27
-rw-r--r--src/imports/location/tile.h25
-rw-r--r--src/imports/location/tilecache.cpp142
-rw-r--r--src/imports/location/tilecache.h46
-rw-r--r--src/imports/location/tileprovider.cpp62
-rw-r--r--src/imports/location/tileprovider.h34
-rw-r--r--src/imports/location/tilespec.cpp56
-rw-r--r--src/imports/location/tilespec.h27
-rw-r--r--src/imports/location/tilesphere.cpp222
-rw-r--r--src/imports/location/tilesphere.h58
13 files changed, 845 insertions, 29 deletions
diff --git a/src/imports/location/location.pro b/src/imports/location/location.pro
index aa875d13..d625f368 100644
--- a/src/imports/location/location.pro
+++ b/src/imports/location/location.pro
@@ -7,6 +7,7 @@ TARGETPATH = Qt/location
include(../qimportbase.pri)
QT += declarative network location
+CONFIG += qt3d
DESTDIR = $$QT.location.imports/$$TARGETPATH
target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
@@ -54,7 +55,12 @@ HEADERS += qdeclarativeposition_p.h \
qdeclarativegeomaneuver_p.h \
qdeclarativegeomaprouteobject_p.h \
qdeclarativegeoboundingcircle_p.h \
- qdeclarative3dgraphicsgeomap_p.h
+ qdeclarative3dgraphicsgeomap_p.h \
+ tilecache.h \
+ tile.h \
+ tilesphere.h \
+ tileprovider.h \
+ tilespec.h
SOURCES += qdeclarativeposition.cpp \
location.cpp \
@@ -88,8 +94,12 @@ SOURCES += qdeclarativeposition.cpp \
qdeclarativegeomaneuver.cpp \
qdeclarativegeomaprouteobject.cpp \
qdeclarativegeoboundingcircle.cpp \
- qdeclarative3dgraphicsgeomap.cpp
-
+ qdeclarative3dgraphicsgeomap.cpp \
+ tilecache.cpp \
+ tile.cpp \
+ tilesphere.cpp \
+ tileprovider.cpp \
+ tilespec.cpp
# Tell qmake to create such makefile that qmldir and target (i.e. declarative_location)
# are both copied to qt/imports/QtMobility/location -directory,
diff --git a/src/imports/location/qdeclarative3dgraphicsgeomap.cpp b/src/imports/location/qdeclarative3dgraphicsgeomap.cpp
index b3cf0202..f421a591 100644
--- a/src/imports/location/qdeclarative3dgraphicsgeomap.cpp
+++ b/src/imports/location/qdeclarative3dgraphicsgeomap.cpp
@@ -45,6 +45,15 @@
#include "qdeclarativecoordinate_p.h"
#include "qdeclarativegeoserviceprovider_p.h"
#include "qdeclarativelandmark_p.h"
+#include "qglview.h"
+#include "qglsubsurface.h"
+#include "tilecache.h"
+#include "tile.h"
+#include "tilesphere.h"
+
+#include <qglscenenode.h>
+#include <qglbuilder.h>
+#include <qgeometrydata.h>
#include <qgeoserviceprovider.h>
#include <qgeomappingmanager.h>
@@ -89,7 +98,7 @@ QTM_BEGIN_NAMESPACE
Mouse handling is done by adding MapMouseArea items as children of either
MapObjects or the Map item itself.
- The Map element is part of the \bold{QtMobility.location 1.2} module.
+ The Map element is part of the \bold{Qt.location 5.0} module.
*/
QDeclarative3DGraphicsGeoMap::QDeclarative3DGraphicsGeoMap(QSGPaintedItem *parent)
: QSGPaintedItem(parent),
@@ -101,16 +110,32 @@ QDeclarative3DGraphicsGeoMap::QDeclarative3DGraphicsGeoMap(QSGPaintedItem *paren
initialCoordinate(0),
mapType_(NoMap),
connectivityMode_(NoConnectivity),
- componentCompleted_(false)
+ componentCompleted_(false),
+ activeMouseArea_(0),
+ tileCache_(0),
+ tileSphere_(0),
+ sceneNode_(0)
{
initialCoordinate = new QGeoCoordinate(-27.0, 153.0);
zoomLevel_ = 8;
size_ = QSizeF(100.0, 100.0);
- // setAcceptsHoverEvents(true);
- // setAcceptHoverEvents(true);
- //setAcceptedMouseButtons(Qt::LeftButton | Qt::MidButton | Qt::RightButton);
- //setFlag(QGraphicsItem::ItemHasNoContents, false);
- //setFlag(QGraphicsItem::ItemAcceptsInputMethod);
+ setAcceptHoverEvents(true);
+ setAcceptedMouseButtons(Qt::LeftButton | Qt::MidButton | Qt::RightButton);
+
+ setRenderTarget(QSGPaintedItem::FramebufferObject);
+ setFillColor(Qt::yellow);
+
+ tileCache_ = new TileCache();
+ tileSphere_ = new TileSphere(this, tileCache_, 4, 1.0);
+ connect(tileSphere_,
+ SIGNAL(sphereUpdated()),
+ this,
+ SLOT(update()));
+ sceneNode_ = tileSphere_->sphereSceneNode();
+ tileSphere_->setRadius(3.0);
+ tileSphere_->setZoom(5);
+ tileSphere_->limitView(26, 16, 30, 20);
+ tileSphere_->update();
}
QDeclarative3DGraphicsGeoMap::~QDeclarative3DGraphicsGeoMap()
@@ -120,7 +145,6 @@ QDeclarative3DGraphicsGeoMap::~QDeclarative3DGraphicsGeoMap()
// Remove map objects, we can't allow mapObject
// to delete the objects because they are owned
// by the declarative elements.
- //QList<QGeoMapObject*> objects = objectMap_.keys();
QList<QDeclarativeGeoMapObject*> objects = mapObjects_;
for (int i = 0; i < objects.size(); ++i) {
mapData_->removeMapObject(objects.at(i)->mapObject());
@@ -129,7 +153,6 @@ QDeclarative3DGraphicsGeoMap::~QDeclarative3DGraphicsGeoMap()
}
if (serviceProvider_)
delete serviceProvider_;
-
if (initialCoordinate) {
delete initialCoordinate;
}
@@ -138,7 +161,6 @@ QDeclarative3DGraphicsGeoMap::~QDeclarative3DGraphicsGeoMap()
void QDeclarative3DGraphicsGeoMap::componentComplete()
{
componentCompleted_ = true;
- QSGPaintedItem::componentComplete();
populateMap();
}
@@ -167,6 +189,7 @@ void QDeclarative3DGraphicsGeoMap::populateMap()
QDeclarativeGeoMapMouseArea *mouseArea
= qobject_cast<QDeclarativeGeoMapMouseArea*>(kids.at(i));
if (mouseArea) {
+ // TODO mouse areas won't work
//mouseArea->setMap(this);
//mouseAreas_.append(mouseArea);
}
@@ -180,22 +203,98 @@ void QDeclarative3DGraphicsGeoMap::setupMapView(QDeclarativeGeoMapObjectView *vi
//view->repopulate();
}
+class ViewportSubsurface : public QGLSubsurface
+{
+public:
+ ViewportSubsurface(QGLAbstractSurface *surface, const QRect &region,
+ qreal adjust)
+ : QGLSubsurface(surface, region), m_adjust(adjust) {}
+
+ qreal aspectRatio() const;
+ ~ViewportSubsurface() {}
+
+private:
+ qreal m_adjust;
+};
-//void QDeclarative3DGraphicsGeoMap::paint(QPainter *painter,
-// const QStyleOptionGraphicsItem *option,
-// QWidget * /*widget*/)
-//{
-// qDebug("-----------original paint called");
-// if (mapData_) {
-// mapData_->paint(painter, option);
-// }
-//}
+qreal ViewportSubsurface::aspectRatio() const
+{
+ return QGLSubsurface::aspectRatio() * m_adjust;
+}
void QDeclarative3DGraphicsGeoMap::paint(QPainter *painter)
{
qDebug() << __FUNCTION__ << "----------- Map3d, mapData_:" << mapData_;
- if (mapData_)
- mapData_->paint(painter, 0);
+ // to paint the old mercator projection:
+ //if (mapData_)
+ // mapData_->paint(painter, 0);
+
+ QGLPainter glPainter;
+ if (!glPainter.begin(painter)) {
+ qWarning("GL graphics system is not active; cannot use 3D items");
+ return;
+ }
+ // No stereo rendering, set the eye as neutral
+ glPainter.setEye(QGL::NoEye);
+
+ // Currently applied transforms for this Map3D element
+ QTransform transform = painter->combinedTransform();
+ // QSGItem::boundingRect() returns (top(0), left(0), width, height).
+ // Then we get the rectangle that is gotten by applying the QTransform on the rect
+ // --> this is the viewport for Map3D
+ QRect viewport = transform.mapRect(boundingRect()).toRect();
+ qDebug() << "Viewport paramteres: " << viewport.width() << viewport.height() << viewport.top() << viewport.left();
+ qreal adjust = 1.0f;
+ ViewportSubsurface surface(glPainter.currentSurface(), viewport, adjust);
+ qDebug() << "surface before: " << &surface;
+ glPainter.pushSurface(&surface);
+ qDebug() << "surface after: " << &surface;
+
+ earlyDraw(&glPainter);
+ // From QGLView
+ QGLCamera defCamera;
+ glPainter.setCamera(&defCamera);
+ paintGL(&glPainter);
+ // Draw the children items
+
+
+
+ glPainter.popSurface();
+}
+
+void QDeclarative3DGraphicsGeoMap::earlyDraw(QGLPainter *painter)
+{
+ // If we have a parent, then assume that the parent has painted
+ // the background and overpaint over the top of it. If we don't
+ // have a parent, then clear to black.
+ if (parentItem()) {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ } else {
+ painter->setClearColor(Qt::black);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+
+ // Force the effect to be updated. The GL paint engine
+ // has left the GL state in an unknown condition.
+ painter->disableEffect();
+
+#ifdef GL_RESCALE_NORMAL
+ glEnable(GL_RESCALE_NORMAL);
+#endif
+
+ // Set the default effect for the scene.
+ painter->setStandardEffect(QGL::LitMaterial);
+ painter->setFaceColor(QGL::AllFaces, Qt::white);
+}
+
+
+// Private paint
+void QDeclarative3DGraphicsGeoMap::paintGL(QGLPainter *painter)
+{
+ qDebug() << __FUNCTION__ << " of Map3D, sceneNode_: " << sceneNode_;
+ if (sceneNode_)
+ sceneNode_->draw(painter);
+ qDebug() << __FUNCTION__ << " after";
}
void QDeclarative3DGraphicsGeoMap::geometryChanged(const QRectF &newGeometry,
diff --git a/src/imports/location/qdeclarative3dgraphicsgeomap_p.h b/src/imports/location/qdeclarative3dgraphicsgeomap_p.h
index 9ea2183e..b83b4cef 100644
--- a/src/imports/location/qdeclarative3dgraphicsgeomap_p.h
+++ b/src/imports/location/qdeclarative3dgraphicsgeomap_p.h
@@ -48,6 +48,13 @@
#include <QGeoMapData>
#include "qdeclarativegeomapobject_p.h"
+class QGLPainter;
+class QGLSceneNode;
+class TileCache;
+class Tile;
+class TileSpec;
+class TileSphere;
+
QTM_BEGIN_NAMESPACE
class QGeoCoordinate;
@@ -97,11 +104,6 @@ public:
// From QDeclarativeParserStatus
virtual void componentComplete();
- // From QGraphicsItem
- //void paint(QPainter *painter,
- // const QStyleOptionGraphicsItem *option,
- // QWidget *widget);
- // From QSGPaintedItem
virtual void paint (QPainter *painter);
void setPlugin(QDeclarativeGeoServiceProvider *plugin);
@@ -201,6 +203,12 @@ private:
QDeclarativeGeoMapMouseArea* activeMouseArea_;
QList<QDeclarativeGeoMapMouseArea*> mouseAreas_;
+ void paintGL(QGLPainter *painter);
+ void earlyDraw(QGLPainter *painter);
+ TileCache *tileCache_;
+ TileSphere *tileSphere_;
+ QGLSceneNode *sceneNode_;
+
friend class QDeclarativeGeoMapObjectView;
Q_DISABLE_COPY(QDeclarative3DGraphicsGeoMap)
};
diff --git a/src/imports/location/tile.cpp b/src/imports/location/tile.cpp
new file mode 100644
index 00000000..675fc7b5
--- /dev/null
+++ b/src/imports/location/tile.cpp
@@ -0,0 +1,27 @@
+
+#include "tile.h"
+
+Tile::Tile() {}
+Tile::Tile(const TileSpec &spec, const QPixmap &pixmap)
+ : spec_(spec),
+ pixmap_(pixmap) {}
+
+void Tile::setTileSpec(const TileSpec &spec)
+{
+ spec_ = spec;
+}
+
+TileSpec Tile::tileSpec() const
+{
+ return spec_;
+}
+
+void Tile::setPixmap(const QPixmap &pixmap)
+{
+ pixmap_ = pixmap;
+}
+
+QPixmap Tile::pixmap() const
+{
+ return pixmap_;
+}
diff --git a/src/imports/location/tile.h b/src/imports/location/tile.h
new file mode 100644
index 00000000..c63360cf
--- /dev/null
+++ b/src/imports/location/tile.h
@@ -0,0 +1,25 @@
+#ifndef TILE_H
+#define TILE_H
+
+#include "tilespec.h"
+
+#include <QPixmap>
+
+class Tile
+{
+public:
+ Tile();
+ Tile(const TileSpec &spec, const QPixmap &pixmap);
+
+ void setTileSpec(const TileSpec &spec);
+ TileSpec tileSpec() const;
+
+ void setPixmap(const QPixmap &pixmap);
+ QPixmap pixmap() const;
+
+private:
+ TileSpec spec_;
+ QPixmap pixmap_;
+};
+
+#endif
diff --git a/src/imports/location/tilecache.cpp b/src/imports/location/tilecache.cpp
new file mode 100644
index 00000000..10e6ec10
--- /dev/null
+++ b/src/imports/location/tilecache.cpp
@@ -0,0 +1,142 @@
+#include "tilecache.h"
+
+#include <QDir>
+#include <QRegExp>
+
+#include <QDebug>
+
+TileCache::TileCache(const QString &directory,
+ QObject *parent)
+ : QObject(parent),
+ directory_(directory),
+ waitingForPrefetchedTiles_(false),
+ tilesOutstanding_(0)
+{
+ if (directory_.isEmpty()) {
+ QDir home = QDir::home();
+ if (!home.exists(".tilecache"))
+ home.mkdir(".tilecache");
+ directory_ = home.filePath(".tilecache");
+ }
+
+ provider_ = new TileProvider(this);
+ connect(provider_,
+ SIGNAL(tileReady(Tile)),
+ this,
+ SLOT(insert(Tile)));
+ connect(provider_,
+ SIGNAL(tileError(TileSpec)),
+ this,
+ SLOT(handleError(TileSpec)));
+ loadTiles();
+}
+
+void TileCache::prefetch(const TileSpec &spec)
+{
+ if (!cache_.contains(spec)) {
+ provider_->tileRequest(spec);
+ ++tilesOutstanding_;
+ }
+}
+
+void TileCache::waitForPrefetchedTiles()
+{
+ if (tilesOutstanding_ == 0)
+ emit prefetchingFinished();
+ else
+ waitingForPrefetchedTiles_ = true;
+}
+
+Tile TileCache::get(const TileSpec &spec) const
+{
+ return cache_.value(spec);
+}
+
+void TileCache::insert(const Tile &tile)
+{
+ QString filename = tileSpecToFilename(tile.tileSpec());
+ tile.pixmap().save(filename, "png");
+ cache_.insert(tile.tileSpec(), tile);
+
+ updateWaitingStatus();
+}
+
+void TileCache::handleError(const TileSpec &)
+{
+ updateWaitingStatus();
+}
+
+void TileCache::updateWaitingStatus()
+{
+ --tilesOutstanding_;
+
+ if (waitingForPrefetchedTiles_ && (tilesOutstanding_ == 0)) {
+ emit prefetchingFinished();
+ waitingForPrefetchedTiles_ = false;
+ }
+}
+
+void TileCache::loadTiles()
+{
+ QStringList formats;
+ formats << "*.png";
+
+ QDir dir(directory_);
+ QStringList files = dir.entryList(formats);
+
+ for (int i = 0; i < files.size(); ++i) {
+ TileSpec spec = filenameToTileSpec(files.at(i));
+ if (spec.zoom() == -1)
+ continue;
+
+ QPixmap pixmap;
+ pixmap.load(dir.filePath(files.at(i)), "png");
+ Tile tile(spec, pixmap);
+ cache_.insert(tile.tileSpec(), tile);
+ }
+}
+
+QString TileCache::tileSpecToFilename(const TileSpec &spec) const
+{
+ QString filename = QString::number(spec.zoom());
+ filename += "-";
+ filename += QString::number(spec.x());
+ filename += "-";
+ filename += QString::number(spec.y());
+ filename += ".png";
+
+ QDir dir = QDir(directory_);
+
+ return dir.filePath(filename);
+}
+
+TileSpec TileCache::filenameToTileSpec(const QString &filename) const
+{
+ TileSpec spec;
+ QRegExp r("(\\d+)-(\\d+)-(\\d+).png");
+
+ int index = r.indexIn(filename);
+ if (index != -1) {
+ bool ok = false;
+
+ int zoom = r.cap(1).toInt(&ok);
+ if (!ok)
+ return spec;
+
+ ok = false;
+ int x = r.cap(2).toInt(&ok);
+ if (!ok)
+ return spec;
+
+ ok = false;
+ int y = r.cap(3).toInt(&ok);
+ if (!ok)
+ return spec;
+
+ spec.setZoom(zoom);
+ spec.setX(x);
+ spec.setY(y);
+ }
+
+ return spec;
+}
diff --git a/src/imports/location/tilecache.h b/src/imports/location/tilecache.h
new file mode 100644
index 00000000..6efefbfa
--- /dev/null
+++ b/src/imports/location/tilecache.h
@@ -0,0 +1,46 @@
+#ifndef TILECACHE_H
+#define TILECACHE_H
+
+#include <QObject>
+#include <QMap>
+
+#include "tilespec.h"
+#include "tile.h"
+#include "tileprovider.h"
+
+class TileCache : public QObject
+{
+ Q_OBJECT
+public:
+ TileCache(const QString &directory = QString(), QObject *parent = 0);
+
+ void prefetch(const TileSpec &spec);
+ void waitForPrefetchedTiles();
+
+ Tile get(const TileSpec &spec) const;
+
+signals:
+ void prefetchingFinished();
+
+private slots:
+ void insert(const Tile &tile);
+ void handleError(const TileSpec &spec);
+
+private:
+ void loadTiles();
+
+ void updateWaitingStatus();
+
+ QString tileSpecToFilename(const TileSpec &spec) const;
+ TileSpec filenameToTileSpec(const QString &filename) const;
+
+ QString directory_;
+ TileProvider *provider_;
+
+ bool waitingForPrefetchedTiles_;
+ int tilesOutstanding_;
+
+ QMap<TileSpec, Tile> cache_;
+};
+
+#endif // TILECACHE_H
diff --git a/src/imports/location/tileprovider.cpp b/src/imports/location/tileprovider.cpp
new file mode 100644
index 00000000..03552d6f
--- /dev/null
+++ b/src/imports/location/tileprovider.cpp
@@ -0,0 +1,62 @@
+#include "tileprovider.h"
+
+#include "tile.h"
+#include "tilespec.h"
+
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QUrl>
+#include <QPixmap>
+
+TileProvider::TileProvider(QObject *parent)
+ : QObject(parent)
+{
+ nam_ = new QNetworkAccessManager(this);
+ connect(nam_,
+ SIGNAL(finished(QNetworkReply*)),
+ this,
+ SLOT(finished(QNetworkReply*)));
+}
+
+void TileProvider::tileRequest(const TileSpec &spec)
+{
+ QString url = "http://tile.openstreetmap.org/";
+ url += QString::number(spec.zoom());
+ url += "/";
+ url += QString::number(spec.x());
+ url += "/";
+ url += QString::number(spec.y());
+ url += ".png";
+
+ QNetworkRequest request = QNetworkRequest(QUrl(url));
+ QNetworkReply *reply = nam_->get(request);
+
+ map_.insert(reply, spec);
+}
+
+void TileProvider::finished(QNetworkReply *reply)
+{
+ if (!map_.contains(reply)) {
+ reply->deleteLater();
+ return;
+ }
+
+ TileSpec spec = map_.value(reply);
+
+ if (reply->error() == QNetworkReply::NoError) {
+ QByteArray bytes = reply->readAll();
+
+ QPixmap pixmap;
+ bool result = pixmap.loadFromData(bytes, "png");
+
+ if (result) {
+ Tile tile(spec, pixmap);
+ emit tileReady(tile);
+ }
+ } else {
+ emit tileError(spec);
+ }
+
+ reply->deleteLater();
+}
diff --git a/src/imports/location/tileprovider.h b/src/imports/location/tileprovider.h
new file mode 100644
index 00000000..460b425b
--- /dev/null
+++ b/src/imports/location/tileprovider.h
@@ -0,0 +1,34 @@
+#ifndef TILEPROVIDER_H
+#define TILEPROVIDER_H
+
+#include <QObject>
+#include <QHash>
+
+#include "tilespec.h"
+
+class Tile;
+class QNetworkAccessManager;
+class QNetworkReply;
+
+class TileProvider : public QObject
+{
+ Q_OBJECT
+public:
+ TileProvider(QObject *parent = 0);
+
+public slots:
+ void tileRequest(const TileSpec &spec);
+
+private slots:
+ void finished(QNetworkReply *reply);
+
+signals:
+ void tileReady(const Tile &tile);
+ void tileError(const TileSpec &spec);
+
+private:
+ QNetworkAccessManager *nam_;
+ QHash<QNetworkReply*, TileSpec> map_;
+};
+
+#endif // TILEPROVIDER_H
diff --git a/src/imports/location/tilespec.cpp b/src/imports/location/tilespec.cpp
new file mode 100644
index 00000000..5123d844
--- /dev/null
+++ b/src/imports/location/tilespec.cpp
@@ -0,0 +1,56 @@
+
+#include "tilespec.h"
+
+TileSpec::TileSpec()
+ : zoom_(-1),
+ x_(-1),
+ y_(-1) {}
+
+TileSpec::TileSpec(int zoom, int x, int y)
+ : zoom_(zoom),
+ x_(x),
+ y_(y) {}
+
+void TileSpec::setZoom(int zoom)
+{
+ zoom_ = zoom;
+}
+
+int TileSpec::zoom() const
+{
+ return zoom_;
+}
+
+void TileSpec::setX(int x)
+{
+ x_ = x;
+}
+
+int TileSpec::x() const
+{
+ return x_;
+}
+
+void TileSpec::setY(int y)
+{
+ y_ = y;
+}
+
+int TileSpec::y() const
+{
+ return y_;
+}
+
+bool TileSpec::operator < (const TileSpec &rhs) const
+{
+ if (zoom_ < rhs.zoom_)
+ return true;
+ if (zoom_ > rhs.zoom_)
+ return false;
+ if (x_ < rhs.x_)
+ return true;
+ if (x_ > rhs.x_)
+ return false;
+ return (y_ < rhs.y_);
+
+}
diff --git a/src/imports/location/tilespec.h b/src/imports/location/tilespec.h
new file mode 100644
index 00000000..bbc1edf0
--- /dev/null
+++ b/src/imports/location/tilespec.h
@@ -0,0 +1,27 @@
+#ifndef TILESPEC_H
+#define TILESPEC_H
+
+class TileSpec
+{
+public:
+ TileSpec();
+ TileSpec(int zoom, int x, int y);
+
+ void setZoom(int zoom);
+ int zoom() const;
+
+ void setX(int x);
+ int x() const;
+
+ void setY(int y);
+ int y() const;
+
+ bool operator < (const TileSpec &rhs) const;
+
+private:
+ int zoom_;
+ int x_;
+ int y_;
+};
+
+#endif
diff --git a/src/imports/location/tilesphere.cpp b/src/imports/location/tilesphere.cpp
new file mode 100644
index 00000000..79eca575
--- /dev/null
+++ b/src/imports/location/tilesphere.cpp
@@ -0,0 +1,222 @@
+#include "tilesphere.h"
+
+#include "tilecache.h"
+#include "tile.h"
+
+#include <qgeometrydata.h>
+#include <qglscenenode.h>
+#include <qglmaterial.h>
+#include <qglbuilder.h>
+
+#include <cmath>
+
+TileSphere::TileSphere(QObject *parent, TileCache *tileCache, int zoom, double radius)
+ : QObject(parent),
+ tileCache_(tileCache),
+ zoom_(zoom),
+ radius_(radius),
+ viewLimited_(false)
+{
+ viewX1_ = 0;
+ viewY1_ = 0;
+ viewX2_ = (1 << zoom_) - 1;
+ viewY2_ = (1 << zoom_) - 1;
+
+ sphereNode_ = new QGLSceneNode(this);
+ connect(tileCache_,
+ SIGNAL(prefetchingFinished()),
+ this,
+ SLOT(prefetchingFinished()));
+}
+
+void TileSphere::setZoom(int zoom)
+{
+ if (zoom_ == zoom)
+ return;
+
+ zoom_ = zoom;
+}
+
+int TileSphere::zoom() const
+{
+ return zoom_;
+}
+
+void TileSphere::setRadius(double radius)
+{
+ if (radius_ == radius)
+ return;
+
+ radius_ = radius;
+}
+
+double TileSphere::radius() const
+{
+ return radius_;
+}
+
+void TileSphere::limitView(int x1, int y1, int x2, int y2)
+{
+ viewLimited_ = true;
+ viewX1_ = x1;
+ viewY1_ = y1;
+ viewX2_ = x2;
+ viewY2_ = y2;
+}
+
+void TileSphere::clearLimit()
+{
+ if (!viewLimited_)
+ return;
+
+ viewLimited_ = false;
+ viewX1_ = 0;
+ viewY1_ = 0;
+ viewX2_ = (1 << zoom_) - 1;
+ viewY2_ = (1 << zoom_) - 1;
+}
+
+QGLSceneNode* TileSphere::sphereSceneNode() const
+{
+ return sphereNode_;
+}
+
+void TileSphere::update()
+{
+ prefetchSphere();
+ tileCache_->waitForPrefetchedTiles();
+}
+
+void TileSphere::prefetchingFinished()
+{
+ qDebug() << __FUNCTION__ << "prefetching is finished";
+ buildSphere();
+ emit sphereUpdated();
+}
+
+QGeometryData TileSphere::tileSpecToSphereQuad(int x, int y) const
+{
+ QGeometryData data;
+
+ const double pi = 3.14159265358;
+
+ double z = 1 << zoom_;
+
+ double lon1 = 2.0 * pi * x / z;
+ double lon2 = 2.0 * pi * (x + 1) / z;
+ double lat1 = pi * y / z;
+ double lat2 = pi * (y + 1) / z;
+
+ double cosLat1 = cos(lat1);
+ double cosLat2 = cos(lat2);
+ double cosLon1 = cos(pi/2 - lon1);
+ double cosLon2 = cos(pi/2 - lon2);
+
+ double sinLat1 = sin(lat1);
+ double sinLat2 = sin(lat2);
+ double sinLon1 = sin(pi/2 - lon1);
+ double sinLon2 = sin(pi/2 - lon2);
+
+ // y and z are flipped here to move from
+ // "earth" geometry to GL geometry
+ QVector3D v11 = QVector3D(cosLon1 * sinLat1,
+ cosLat1,
+ sinLon1 * sinLat1);
+
+ QVector3D v12 = QVector3D(cosLon1 * sinLat2,
+ cosLat2,
+ sinLon1 * sinLat2);
+
+ QVector3D v21 = QVector3D(cosLon2 * sinLat1,
+ cosLat1,
+ sinLon2 * sinLat1);
+
+ QVector3D v22 = QVector3D(cosLon2 * sinLat2,
+ cosLat2,
+ sinLon2 * sinLat2);
+
+
+ data.appendVertex(radius_ * v11);
+ data.appendNormal(v11);
+ data.appendTexCoord(QVector2D(0, 1));
+
+ data.appendVertex(radius_ * v12);
+ data.appendNormal(v12);
+ data.appendTexCoord(QVector2D(0, 0));
+
+ data.appendVertex(radius_ * v22);
+ data.appendNormal(v22);
+ data.appendTexCoord(QVector2D(1, 0));
+
+ data.appendVertex(radius_ * v21);
+ data.appendNormal(v21);
+ data.appendTexCoord(QVector2D(1, 1));
+
+ return data;
+}
+
+QGLSceneNode* TileSphere::tileToSceneNode(const Tile &tile) const
+{
+ if (tile.tileSpec().zoom() == -1)
+ return 0;
+
+ QGLBuilder builder;
+ builder.addQuads(tileSpecToSphereQuad(tile.tileSpec().x(), tile.tileSpec().y()));
+
+ QGLSceneNode *node = builder.finalizedSceneNode();
+
+ QGLMaterial *mat = new QGLMaterial(node);
+ QGLTexture2D *tex = new QGLTexture2D(mat);
+ tex->setPixmap(tile.pixmap());
+ mat->setTexture(tex);
+
+ node->setMaterial(mat);
+ node->setEffect(QGL::LitDecalTexture2D);
+ return node;
+}
+
+void TileSphere::prefetchSphere() const
+{
+ int z = 1 << zoom_;
+
+ int x1 = viewX1_;
+ int x2 = viewX2_;
+ if (x2 < x1)
+ x2 += z;
+
+ int y1 = viewY1_;
+ int y2 = viewY2_;
+ if (y2 < y1)
+ y2 += z;
+
+ for (int x = x1; x <= x2; ++x) {
+ for (int y = y1; y <= y2; ++y) {
+ tileCache_->prefetch(TileSpec(zoom_, x % z, y % z));
+ }
+ }
+}
+
+void TileSphere::buildSphere() const
+{
+ sphereNode_->removeNodes(sphereNode_->children());
+
+ int z = 1 << zoom_;
+
+ int x1 = viewX1_;
+ int x2 = viewX2_;
+ if (x2 < x1)
+ x2 += z;
+
+ int y1 = viewY1_;
+ int y2 = viewY2_;
+ if (y2 < y1)
+ y2 += z;
+
+ for (int x = x1; x <= x2; ++x) {
+ for (int y = y1; y <= y2; ++y) {
+ QGLSceneNode *node = tileToSceneNode(tileCache_->get(TileSpec(zoom_, x % z, y % z)));
+ if (node)
+ sphereNode_->addNode(node);
+ }
+ }
+}
diff --git a/src/imports/location/tilesphere.h b/src/imports/location/tilesphere.h
new file mode 100644
index 00000000..e3a7647a
--- /dev/null
+++ b/src/imports/location/tilesphere.h
@@ -0,0 +1,58 @@
+#ifndef TILESPHERE_H
+#define TILESPHERE_H
+
+#include <QObject>
+
+class QGLSceneNode;
+class QGeometryData;
+
+class Tile;
+class TileCache;
+
+class TileSphere : public QObject
+{
+ Q_OBJECT
+public:
+ TileSphere(QObject *parent, TileCache *tileCache, int zoom = 4, double radius = 1.0);
+
+ void setZoom(int zoom);
+ int zoom() const;
+
+ void setRadius(double radius);
+ double radius() const;
+
+ void limitView(int x1, int y1, int x2, int y2);
+ void clearLimit();
+
+ QGLSceneNode* sphereSceneNode() const;
+
+public slots:
+ void update();
+
+private slots:
+ void prefetchingFinished();
+
+signals:
+ void sphereUpdated();
+
+private:
+ QGeometryData tileSpecToSphereQuad(int x, int y) const;
+ QGLSceneNode* tileToSceneNode(const Tile &tile) const;
+
+ void prefetchSphere() const;
+ void buildSphere() const;
+
+ TileCache *tileCache_;
+ int zoom_;
+ double radius_;
+
+ bool viewLimited_;
+ int viewX1_;
+ int viewY1_;
+ int viewX2_;
+ int viewY2_;
+
+ QGLSceneNode* sphereNode_;
+};
+
+#endif // TILESPHERE_H