From af07f106f3c7f80d070f7ba213750ee5739faf81 Mon Sep 17 00:00:00 2001 From: hengli Date: Wed, 13 Oct 2010 17:39:52 +0200 Subject: [PATCH] Updated 3D imagery code. Non-working version. --- src/ui/map3D/Imagery.cc | 295 +++++++++++++++++++++++++++------- src/ui/map3D/Imagery.h | 44 ++--- src/ui/map3D/Texture.cc | 115 ++++++++++++- src/ui/map3D/Texture.h | 17 +- src/ui/map3D/TextureCache.cc | 79 +++++++++ src/ui/map3D/TextureCache.h | 29 ++++ src/ui/map3D/WebImage.cc | 84 ++++++++++ src/ui/map3D/WebImage.h | 48 ++++++ src/ui/map3D/WebImageCache.cc | 112 +++++++++++++ src/ui/map3D/WebImageCache.h | 33 ++++ 10 files changed, 776 insertions(+), 80 deletions(-) create mode 100644 src/ui/map3D/TextureCache.cc create mode 100644 src/ui/map3D/TextureCache.h create mode 100644 src/ui/map3D/WebImage.cc create mode 100644 src/ui/map3D/WebImage.h create mode 100644 src/ui/map3D/WebImageCache.cc create mode 100644 src/ui/map3D/WebImageCache.h diff --git a/src/ui/map3D/Imagery.cc b/src/ui/map3D/Imagery.cc index 39079cbbe..9b32ba5a2 100644 --- a/src/ui/map3D/Imagery.cc +++ b/src/ui/map3D/Imagery.cc @@ -2,25 +2,13 @@ #include #include -#include -#include - -//for street-maps to: -//http://mt1.google.com/mt?&x=%d&y=%d&z=%d -//for satellite-maps to: -//http://khm.google.com/kh?&x=%d&y=%d&zoom=%d -//for topographic-maps: -//http://mt.google.com/mt?v=app.81&x=%d&y=%d&zoom=%d const double WGS84_A = 6378137.0; const double WGS84_ECCSQ = 0.00669437999013; -Imagery::Imagery(QObject* parent) - : QObject(parent) - , networkManager(new QNetworkAccessManager) +Imagery::Imagery() { -// connect(networkManager.data(), SIGNAL(finished(QNetworkReply*)), -// this, SLOT(downloadFinished(QNetworkReply*))); + } void @@ -32,27 +20,22 @@ Imagery::setImageryType(ImageryType type) void Imagery::setOffset(double xOffset, double yOffset) { - -} - -void -Imagery::setUrl(std::string url) -{ - + this->xOffset = xOffset; + this->yOffset = yOffset; } void Imagery::prefetch2D(double windowWidth, double windowHeight, double zoom, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone) + const QString& utmZone) { - double x1 = xOrigin + viewXOffset - windowWidth / 2.0 / zoom; - double y1 = yOrigin + viewYOffset - windowHeight / 2.0 / zoom; - double xc = xOrigin + viewXOffset; - double yc = yOrigin + viewYOffset; - double x2 = xOrigin + viewXOffset + windowWidth / 2.0 / zoom; - double y2 = yOrigin + viewYOffset + windowHeight / 2.0 / zoom; + double minX = xOrigin + viewXOffset - windowWidth / 2.0 / zoom; + double minY = yOrigin + viewYOffset - windowHeight / 2.0 / zoom; + double centerX = xOrigin + viewXOffset; + double centerY = yOrigin + viewYOffset; + double maxX = xOrigin + viewXOffset + windowWidth / 2.0 / zoom; + double maxY = yOrigin + viewYOffset + windowHeight / 2.0 / zoom; double imageResolution; if (currentImageryType == SATELLITE) @@ -68,34 +51,192 @@ Imagery::prefetch2D(double windowWidth, double windowHeight, } } -// networkManager->get(QNetworkRequest(QUrl(""))); + int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY; + int32_t zoomLevel; + UTMtoTile(minX, minY, utmZone, imageResolution, + minTileX, maxTileY, zoomLevel); + UTMtoTile(centerX, centerY, utmZone, imageResolution, + centerTileX, centerTileY, zoomLevel); + UTMtoTile(maxX, maxY, utmZone, imageResolution, + maxTileX, minTileY, zoomLevel); + if (maxTileX - minTileX + 1 > 14) + { + minTileX = centerTileX - 7; + maxTileX = centerTileX + 6; + } + if (maxTileY - minTileY + 1 > 14) + { + minTileY = centerTileY - 7; + maxTileY = centerTileY + 6; + } + + for (int32_t r = minTileY; r <= maxTileY; ++r) + { + for (int32_t c = minTileX; c <= maxTileX; ++c) + { + QString url = getTileURL(c, r, zoomLevel); + + TexturePtr t = textureCache->get(url); + } + } } void Imagery::draw2D(double windowWidth, double windowHeight, double zoom, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone) + const QString& utmZone) { + double minX = xOrigin + viewXOffset - windowWidth / 2.0 / zoom * 1.5; + double minY = yOrigin + viewYOffset - windowHeight / 2.0 / zoom * 1.5; + double centerX = xOrigin + viewXOffset; + double centerY = yOrigin + viewYOffset; + double maxX = xOrigin + viewXOffset + windowWidth / 2.0 / zoom * 1.5; + double maxY = yOrigin + viewYOffset + windowHeight / 2.0 / zoom * 1.5; + double imageResolution; + if (currentImageryType == SATELLITE) + { + imageResolution = 1.0; + while (imageResolution * 3.0 / 2.0 < 1.0 / zoom) + { + imageResolution *= 2.0; + } + if (imageResolution > 512.0) + { + imageResolution = 512.0; + } + } + + int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY; + int32_t zoomLevel; + UTMtoTile(minX, minY, utmZone, imageResolution, + minTileX, maxTileY, zoomLevel); + UTMtoTile(centerX, centerY, utmZone, imageResolution, + centerTileX, centerTileY, zoomLevel); + UTMtoTile(maxX, maxY, utmZone, imageResolution, + maxTileX, minTileY, zoomLevel); + if (maxTileX - minTileX + 1 > 14) + { + minTileX = centerTileX - 7; + maxTileX = centerTileX + 6; + } + if (maxTileY - minTileY + 1 > 14) + { + minTileY = centerTileY - 7; + maxTileY = centerTileY + 6; + } + + for (int32_t r = minTileY; r <= maxTileY; ++r) + { + for (int32_t c = minTileX; c <= maxTileX; ++c) + { + QString tileURL = getTileURL(c, r, zoomLevel); + + double x1, y1, x2, y2, x3, y3, x4, y4; + imageBounds(c, r, imageResolution, x1, y1, x2, y2, x3, y3, x4, y4); + + TexturePtr t = textureCache->get(tileURL); + t->draw(x1 - xOrigin, y1 - yOrigin, + x2 - xOrigin, y2 - yOrigin, + x3 - xOrigin, y3 - yOrigin, + x4 - xOrigin, y4 - yOrigin, true); + } + } } void Imagery::prefetch3D(double radius, double imageResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone) + const QString& utmZone) { + double minX = xOrigin + viewXOffset - radius; + double minY = yOrigin + viewYOffset - radius; + double centerX = xOrigin + viewXOffset; + double centerY = yOrigin + viewYOffset; + double maxX = xOrigin + viewXOffset + radius; + double maxY = yOrigin + viewYOffset + radius; + + int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY; + int32_t zoomLevel; + UTMtoTile(minX, minY, utmZone, imageResolution, + minTileX, maxTileY, zoomLevel); + UTMtoTile(centerX, centerY, utmZone, imageResolution, + centerTileX, centerTileY, zoomLevel); + UTMtoTile(maxX, maxY, utmZone, imageResolution, + maxTileX, minTileY, zoomLevel); + if (maxTileX - minTileX + 1 > 14) + { + minTileX = centerTileX - 7; + maxTileX = centerTileX + 6; + } + if (maxTileY - minTileY + 1 > 14) + { + minTileY = centerTileY - 7; + maxTileY = centerTileY + 6; + } + for (int32_t r = minTileY; r <= maxTileY; ++r) + { + for (int32_t c = minTileX; c <= maxTileX; ++c) + { + QString url = getTileURL(c, r, zoomLevel); + + TexturePtr t = textureCache->get(url); + } + } } void Imagery::draw3D(double radius, double imageResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone) + const QString& utmZone) { + double minX = xOrigin + viewXOffset - radius; + double minY = yOrigin + viewYOffset - radius; + double centerX = xOrigin + viewXOffset; + double centerY = yOrigin + viewYOffset; + double maxX = xOrigin + viewXOffset + radius; + double maxY = yOrigin + viewYOffset + radius; + + int32_t minTileX, minTileY, centerTileX, centerTileY, maxTileX, maxTileY; + int32_t zoomLevel; + UTMtoTile(minX, minY, utmZone, imageResolution, + minTileX, maxTileY, zoomLevel); + UTMtoTile(centerX, centerY, utmZone, imageResolution, + centerTileX, centerTileY, zoomLevel); + UTMtoTile(maxX, maxY, utmZone, imageResolution, + maxTileX, minTileY, zoomLevel); + if (maxTileX - minTileX + 1 > 14) + { + minTileX = centerTileX - 7; + maxTileX = centerTileX + 6; + } + if (maxTileY - minTileY + 1 > 14) + { + minTileY = centerTileY - 7; + maxTileY = centerTileY + 6; + } + + for (int32_t r = minTileY; r <= maxTileY; ++r) + { + for (int32_t c = minTileX; c <= maxTileX; ++c) + { + QString tileURL = getTileURL(c, r, zoomLevel); + + double x1, y1, x2, y2, x3, y3, x4, y4; + imageBounds(c, r, imageResolution, x1, y1, x2, y2, x3, y3, x4, y4); + + TexturePtr t = textureCache->get(tileURL); + t->draw(x1 - xOrigin, y1 - yOrigin, + x2 - xOrigin, y2 - yOrigin, + x3 - xOrigin, y3 - yOrigin, + x4 - xOrigin, y4 - yOrigin, true); + } + } } bool @@ -105,24 +246,48 @@ Imagery::update(void) } void -Imagery::downloadFinished(QNetworkReply* reply) +Imagery::imageBounds(int32_t x, int32_t y, double imageResolution, + double& x1, double& y1, double& x2, double& y2, + double& x3, double& y3, double& x4, double& y4) { - if (reply->error() != QNetworkReply::NoError) { - return; - } - QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (attribute.isValid()) - { - return; - } + int32_t zoomLevel = 17 - static_cast(rint(log2(imageResolution))); + int32_t numTiles = static_cast(exp2(static_cast(zoomLevel))); + + double lon1 = 360.0 * (static_cast(x) + / static_cast(numTiles)) - 180; + double lon2 = 360.0 * ((static_cast(x + 1)) + / static_cast(numTiles)) - 180; + + double lat1 = tileYToLatitude((static_cast(y + 1) + / static_cast(numTiles)) + * 2.0 * M_PI - M_PI); + double lat2 = tileYToLatitude((static_cast(y) + / static_cast(numTiles)) + * 2.0 * M_PI - M_PI); + + QString utmZone; + LLtoUTM(lat1, lon1, y1, x1, utmZone); + LLtoUTM(lat1, lon2, y2, x2, utmZone); + LLtoUTM(lat2, lon2, y3, x3, utmZone); + LLtoUTM(lat2, lon1, y4, x4, utmZone); +} - QByteArray jpegData = reply->readAll(); - QPixmap pixmap; - pixmap.loadFromData(jpegData); +double +Imagery::tileYToLatitude(double y) +{ + double rad = 2.0 * atan(exp(y)) - M_PI / 2.0; + return -rad * 180.0 / M_PI; +} + +double +Imagery::latitudeToTileY(double latitude) +{ + double rad = latitude * M_PI / 180.0; + return -log(tan(rad) + 1.0 / cos(rad)); } void -Imagery::UTMtoTile(double northing, double easting, const std::string& utmZone, +Imagery::UTMtoTile(double northing, double easting, const QString& utmZone, double imageResolution, int32_t& tileX, int32_t& tileY, int32_t& zoomLevel) { @@ -134,14 +299,12 @@ Imagery::UTMtoTile(double northing, double easting, const std::string& utmZone, int32_t numTiles = static_cast(exp2(static_cast(zoomLevel))); double x = longitude / 180.0; - double rad = latitude * M_PI / 180.0; - double y = -log(tan(rad) + 1.0 / cos(rad)); - + double y = latitudeToTileY(latitude); tileX = static_cast((x + 1.0) / 2.0 * numTiles); tileY = static_cast((y + M_PI) / (2.0 * M_PI) * numTiles); } -char +QChar Imagery::UTMLetterDesignator(double latitude) { // This routine determines the correct UTM letter designator for the given latitude @@ -176,7 +339,7 @@ Imagery::UTMLetterDesignator(double latitude) void Imagery::LLtoUTM(const double latitude, const double longitude, - double& utmNorthing, double& utmEasting, std::string& utmZone) + double& utmNorthing, double& utmEasting, QString& utmZone) { // converts lat/long to UTM coords. Equations from USGS Bulletin 1532 // East Longitudes are positive, West longitudes are negative. @@ -214,9 +377,7 @@ Imagery::LLtoUTM(const double latitude, const double longitude, LongOriginRad = LongOrigin * M_PI / 180.0; // compute the UTM Zone from the latitude and longitude - std::ostringstream oss; - oss << ZoneNumber << UTMLetterDesignator(latitude); - utmZone = oss.str(); + utmZone = QString("%1%2").arg(ZoneNumber).arg(UTMLetterDesignator(latitude)); eccPrimeSquared = WGS84_ECCSQ / (1.0 - WGS84_ECCSQ); @@ -259,7 +420,7 @@ Imagery::LLtoUTM(const double latitude, const double longitude, void Imagery::UTMtoLL(const double utmNorthing, const double utmEasting, - const std::string& utmZone, double& latitude, double& longitude) + const QString& utmZone, double& latitude, double& longitude) { // converts UTM coords to lat/long. Equations from USGS Bulletin 1532 // East Longitudes are positive, West longitudes are negative. @@ -281,7 +442,7 @@ Imagery::UTMtoLL(const double utmNorthing, const double utmEasting, x = utmEasting - 500000.0; //remove 500,000 meter offset for longitude y = utmNorthing; - std::istringstream iss(utmZone); + std::istringstream iss(utmZone.toStdString()); iss >> ZoneNumber >> ZoneLetter; if ((ZoneLetter - 'N') >= 0) { @@ -329,3 +490,27 @@ Imagery::UTMtoLL(const double utmNorthing, const double utmEasting, * D * D * D * D * D / 120.0) / cos(phi1Rad); longitude = LongOrigin + longitude / M_PI * 180.0; } + +QString +Imagery::getTileURL(int32_t x, int32_t y, int32_t zoomLevel) +{ + std::ostringstream oss; + + switch (currentImageryType) + { + case MAP: + oss << "http://mt1.google.com/mt?&x=" << x << "&y=" << y << + "&z=" << zoomLevel; + break; + case SATELLITE: + oss << "http://khm.google.com/kh?&x=" << x << "&y=" << y << + "&zoom=" << zoomLevel; + break; + default: + {}; + } + + QString url; + + return url; +} diff --git a/src/ui/map3D/Imagery.h b/src/ui/map3D/Imagery.h index 09495c33c..67c535f0a 100644 --- a/src/ui/map3D/Imagery.h +++ b/src/ui/map3D/Imagery.h @@ -2,18 +2,13 @@ #define IMAGERY_H #include -#include -#include -#include -#include "Texture.h" +#include "TextureCache.h" -class Imagery : public QObject +class Imagery { -// Q_OBJECT - public: - explicit Imagery(QObject* parent); + Imagery(); enum ImageryType { @@ -23,49 +18,56 @@ public: void setImageryType(ImageryType type); void setOffset(double xOffset, double yOffset); - void setUrl(std::string url); void prefetch2D(double windowWidth, double windowHeight, double zoom, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone); + const QString& utmZone); void draw2D(double windowWidth, double windowHeight, double zoom, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone); + const QString& utmZone); void prefetch3D(double radius, double imageResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone); + const QString& utmZone); void draw3D(double radius, double imageResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const std::string& utmZone); + const QString& utmZone); bool update(void); -private slots: - void downloadFinished(QNetworkReply* reply); - private: - void UTMtoTile(double northing, double easting, const std::string& utmZone, + void imageBounds(int32_t x, int32_t y, double imageResolution, + double& x1, double& y1, double& x2, double& y2, + double& x3, double& y3, double& x4, double& y4); + + double tileYToLatitude(double y); + double latitudeToTileY(double latitude); + + void UTMtoTile(double northing, double easting, const QString& utmZone, double imageResolution, int32_t& tileX, int32_t& tileY, int32_t& zoomLevel); - char UTMLetterDesignator(double latitude); + QChar UTMLetterDesignator(double latitude); void LLtoUTM(const double latitude, const double longitude, double& utmNorthing, double& utmEasting, - std::string& utmZone); + QString& utmZone); void UTMtoLL(const double utmNorthing, const double utmEasting, - const std::string& utmZone, + const QString& utmZone, double& latitude, double& longitude); + QString getTileURL(int32_t x, int32_t y, int32_t zoomLevel); + ImageryType currentImageryType; - QScopedPointer networkManager; + QScopedPointer textureCache; + + double xOffset, yOffset; }; #endif // IMAGERY_H diff --git a/src/ui/map3D/Texture.cc b/src/ui/map3D/Texture.cc index 36bed2cfc..9a2fcebfd 100644 --- a/src/ui/map3D/Texture.cc +++ b/src/ui/map3D/Texture.cc @@ -5,6 +5,66 @@ Texture::Texture() } +QString +Texture::getSourceURL(void) +{ + return sourceURL; +} + +void +Texture::setID(GLuint id) +{ + this->id = id; +} + +void +Texture::sync(const WebImagePtr& image) +{ + state = static_cast(image->getState()); + + if (image->getState() != WebImage::UNINITIALIZED && + sourceURL != image->getSourceURL()) + { + sourceURL = image->getSourceURL(); + } + + if (image->getState() == WebImage::READY && image->getSyncFlag()) + { + image->setSyncFlag(false); + + if (image->getWidth() != imageWidth || + image->getHeight() != imageHeight) + { + imageWidth = image->getWidth(); + textureWidth = 32; + while (textureWidth < imageWidth) + { + textureWidth *= 2; + } + imageHeight = image->getHeight(); + textureHeight = 32; + while (textureHeight < imageHeight) + { + textureHeight *= 2; + } + + maxU = static_cast(imageWidth) + / static_cast(textureWidth); + maxV = static_cast(imageHeight) + / static_cast(textureHeight); + + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, 3, textureWidth, textureHeight, + 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } + + glBindTexture(GL_TEXTURE_2D, id); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageWidth, imageHeight, + GL_RGB, GL_UNSIGNED_BYTE, image->getData()); + + } +} + void Texture::draw(float x1, float y1, float x2, float y2, bool smoothInterpolation) const @@ -22,7 +82,7 @@ Texture::draw(float x1, float y1, float x2, float y2, } glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, textureId); + glBindTexture(GL_TEXTURE_2D, id); float dx, dy; if (smoothInterpolation) @@ -56,3 +116,56 @@ Texture::draw(float x1, float y1, float x2, float y2, glDisable(GL_TEXTURE_2D); } + +void +Texture::draw(float x1, float y1, float x2, float y2, + float x3, float y3, float x4, float y4, + bool smoothInterpolation) const +{ + if (state == REQUESTED) + { + glBegin(GL_LINE_LOOP); + glColor3f(0.0f, 0.0f, 1.0f); + glVertex2f(x1, y1); + glVertex2f(x2, y2); + glVertex2f(x3, y3); + glVertex2f(x4, y4); + glEnd(); + return; + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, id); + + float dx, dy; + if (smoothInterpolation) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + dx = 1.0f / (2.0f * textureWidth); + dy = 1.0f / (2.0f * textureHeight); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + dx = 0.0f; + dy = 0.0f; + } + + glColor3f(1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + + glTexCoord2f(dx, maxV - dy); + glVertex2f(x1, y1); + glTexCoord2f(maxU - dx, maxV - dy); + glVertex2f(x2, y2); + glTexCoord2f(maxU - dx, dy); + glVertex2f(x3, y3); + glTexCoord2f(dx, dy); + glVertex2f(x4, y4); + + glEnd(); + + glDisable(GL_TEXTURE_2D); +} diff --git a/src/ui/map3D/Texture.h b/src/ui/map3D/Texture.h index f3cc1fb83..331dd3aa7 100644 --- a/src/ui/map3D/Texture.h +++ b/src/ui/map3D/Texture.h @@ -9,13 +9,24 @@ #include #include +#include "WebImage.h" + class Texture { public: Texture(); + QString getSourceURL(void); + + void setID(GLuint id); + + void sync(const WebImagePtr& image); + void draw(float x1, float y1, float x2, float y2, bool smoothInterpolation) const; + void draw(float x1, float y1, float x2, float y2, + float x3, float y3, float x4, float y4, + bool smoothInterpolation) const; private: enum State @@ -26,8 +37,8 @@ private: }; State state; - - GLuint textureId; + QString sourceURL; + GLuint id; int32_t textureWidth; int32_t textureHeight; @@ -39,6 +50,6 @@ private: float maxV; }; -typedef struct QSharedPointer TexturePtr; +typedef QSharedPointer TexturePtr; #endif // TEXTURE_H diff --git a/src/ui/map3D/TextureCache.cc b/src/ui/map3D/TextureCache.cc new file mode 100644 index 000000000..ef0cf3819 --- /dev/null +++ b/src/ui/map3D/TextureCache.cc @@ -0,0 +1,79 @@ +#include "TextureCache.h" + +TextureCache::TextureCache(uint32_t _cacheSize) + : cacheSize(_cacheSize) + , imageCache(new WebImageCache(0, cacheSize)) +{ + textures.resize(cacheSize); + TexturePtr t; + foreach(t, textures) + { + GLuint id; + glGenTextures(1, &id); + t->setID(id); + glBindTexture(GL_TEXTURE_2D, id); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } +} + +TexturePtr +TextureCache::get(const QString& tileURL) +{ + QPair p1 = lookup(tileURL); + if (!p1.first.isNull()) + { + return p1.first; + } + + QPair p2 = imageCache->lookup(tileURL); + if (!p2.first.isNull()) + { + textures[p2.second]->sync(p2.first); + p1 = lookup(tileURL); + + return p1.first; + } + + return TexturePtr(); +} + +void +TextureCache::sync(void) +{ + if (requireSync()) + { + for (int32_t i = 0; i < textures.size(); ++i) + { + textures[i]->sync(imageCache->at(i)); + } + } +} + +QPair +TextureCache::lookup(const QString& tileURL) +{ + for (int32_t i = 0; i < textures.size(); ++i) + { + if (textures[i]->getSourceURL() == tileURL) + { + return qMakePair(textures[i], i); + } + } + + return qMakePair(TexturePtr(), -1); +} + +bool +TextureCache::requireSync(void) const +{ + for (uint32_t i = 0; i < cacheSize; ++i) + { + if (imageCache->at(i)->getSyncFlag()) + { + return true; + } + } + return false; +} diff --git a/src/ui/map3D/TextureCache.h b/src/ui/map3D/TextureCache.h new file mode 100644 index 000000000..736844178 --- /dev/null +++ b/src/ui/map3D/TextureCache.h @@ -0,0 +1,29 @@ +#ifndef TEXTURECACHE_H +#define TEXTURECACHE_H + +#include + +#include "Texture.h" +#include "WebImageCache.h" + +class TextureCache +{ +public: + explicit TextureCache(uint32_t cacheSize); + + TexturePtr get(const QString& tileURL); + + void sync(void); + +private: + QPair lookup(const QString& tileURL); + + bool requireSync(void) const; + + uint32_t cacheSize; + QVector textures; + + QScopedPointer imageCache; +}; + +#endif // TEXTURECACHE_H diff --git a/src/ui/map3D/WebImage.cc b/src/ui/map3D/WebImage.cc new file mode 100644 index 000000000..638f4684f --- /dev/null +++ b/src/ui/map3D/WebImage.cc @@ -0,0 +1,84 @@ +#include "WebImage.h" + +WebImage::WebImage() + : state(WebImage::UNINITIALIZED) + , lastReference(0) + , syncFlag(false) +{ + +} + +void +WebImage::clear(void) +{ + image.clear(); + sourceURL.clear(); + state = WebImage::UNINITIALIZED; + lastReference = 0; +} + +WebImage::State +WebImage::getState(void) const +{ + return state; +} + +void +WebImage::setState(State state) +{ + this->state = state; +} + +QString +WebImage::getSourceURL(void) const +{ + return sourceURL; +} + +void +WebImage::setSourceURL(const QString& url) +{ + sourceURL = url; +} + +const uint8_t* +WebImage::getData(void) const +{ + return image->bits(); +} + +int32_t +WebImage::getWidth(void) const +{ + return image->width(); +} + +int32_t +WebImage::getHeight(void) const +{ + return image->height(); +} + +uint64_t +WebImage::getLastReference(void) const +{ + return lastReference; +} + +void +WebImage::setLastReference(uint64_t value) +{ + lastReference = value; +} + +bool +WebImage::getSyncFlag(void) const +{ + return syncFlag; +} + +void +WebImage::setSyncFlag(bool onoff) +{ + syncFlag = onoff; +} diff --git a/src/ui/map3D/WebImage.h b/src/ui/map3D/WebImage.h new file mode 100644 index 000000000..b39919ec4 --- /dev/null +++ b/src/ui/map3D/WebImage.h @@ -0,0 +1,48 @@ +#ifndef WEBIMAGE_H +#define WEBIMAGE_H + +#include +#include +#include + +class WebImage +{ +public: + WebImage(); + + void clear(void); + + enum State + { + UNINITIALIZED = 0, + REQUESTED = 1, + READY = 2 + }; + + State getState(void) const; + void setState(State state); + + QString getSourceURL(void) const; + void setSourceURL(const QString& url); + + const uint8_t* getData(void) const; + int32_t getWidth(void) const; + int32_t getHeight(void) const; + + uint64_t getLastReference(void) const; + void setLastReference(uint64_t value); + + bool getSyncFlag(void) const; + void setSyncFlag(bool onoff); + +private: + State state; + QString sourceURL; + QSharedPointer image; + uint64_t lastReference; + bool syncFlag; +}; + +typedef QSharedPointer WebImagePtr; + +#endif // WEBIMAGE_H diff --git a/src/ui/map3D/WebImageCache.cc b/src/ui/map3D/WebImageCache.cc new file mode 100644 index 000000000..622224666 --- /dev/null +++ b/src/ui/map3D/WebImageCache.cc @@ -0,0 +1,112 @@ +#include "WebImageCache.h" + +#include +#include + +WebImageCache::WebImageCache(QObject* parent, uint32_t _cacheSize) + : QObject(parent) + , cacheSize(_cacheSize) + , currentReference(0) + , networkManager(new QNetworkAccessManager) +{ + webImages.resize(cacheSize); + + connect(networkManager.data(), SIGNAL(finished(QNetworkReply*)), + this, SLOT(downloadFinished(QNetworkReply*))); +} + +QPair +WebImageCache::lookup(const QString& url) +{ + QPair p; + for (int32_t i = 0; i < webImages.size(); ++i) + { + if (webImages[i]->getState() != WebImage::UNINITIALIZED && + webImages[i]->getSourceURL() == url) + { + p.first = webImages[i]; + p.second = i; + break; + } + } + + if (p.first.isNull()) + { + for (int32_t i = 0; i < webImages.size(); ++i) + { + // get uninitialized image + if (webImages[i]->getState() == WebImage::UNINITIALIZED) + { + p.first = webImages[i]; + p.second = i; + break; + } + // get oldest image + else if (webImages[i]->getState() == WebImage::READY && + (p.first.isNull() || + p.first->getLastReference() < p.first->getLastReference())) + { + p.first = webImages[i]; + p.second = i; + } + } + + if (p.first.isNull()) + { + return qMakePair(WebImagePtr(), -1); + } + else + { + if (p.first->getState() == WebImage::READY) + { + p.first->clear(); + } + p.first->setSourceURL(url); + p.first->setLastReference(currentReference); + ++currentReference; + p.first->setState(WebImage::REQUESTED); + + networkManager->get(QNetworkRequest(QUrl(url))); + + return p; + } + } + else + { + if (p.first->getState() == WebImage::READY) + { + p.first->setLastReference(currentReference); + ++currentReference; + return p; + } + else + { + return qMakePair(WebImagePtr(), -1); + } + } +} + +WebImagePtr +WebImageCache::at(int32_t index) const +{ + return webImages[index]; +} + +void +WebImageCache::downloadFinished(QNetworkReply* reply) +{ + if (reply->error() != QNetworkReply::NoError) { + return; + } + QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (attribute.isValid()) + { + return; + } + + QByteArray imageData = reply->readAll(); + QPixmap pixmap; + pixmap.loadFromData(imageData); + + // set image, needsSync to true, and state to READY +} diff --git a/src/ui/map3D/WebImageCache.h b/src/ui/map3D/WebImageCache.h new file mode 100644 index 000000000..5c4dd8617 --- /dev/null +++ b/src/ui/map3D/WebImageCache.h @@ -0,0 +1,33 @@ +#ifndef WEBIMAGECACHE_H +#define WEBIMAGECACHE_H + +#include +#include +#include + +#include "WebImage.h" + +class WebImageCache : public QObject +{ + Q_OBJECT + +public: + WebImageCache(QObject* parent, uint32_t cacheSize); + + QPair lookup(const QString& url); + + WebImagePtr at(int32_t index) const; + +private Q_SLOTS: + void downloadFinished(QNetworkReply* reply); + +private: + uint32_t cacheSize; + + QVector webImages; + uint64_t currentReference; + + QScopedPointer networkManager; +}; + +#endif // WEBIMAGECACHE_H -- 2.22.0