From c1613c0eea25ee5db70b6f78e6dcfe67792ea03b Mon Sep 17 00:00:00 2001 From: hengli Date: Fri, 29 Oct 2010 15:36:46 +0200 Subject: [PATCH] Added new 3D terrain model feature to 3D view perspective. --- src/ui/map3D/Imagery.cc | 16 ++++--- src/ui/map3D/Imagery.h | 7 +-- src/ui/map3D/QMap3DWidget.cc | 21 +++++++-- src/ui/map3D/Texture.cc | 88 ++++++++++++++++++++++++++++++----- src/ui/map3D/Texture.h | 5 ++ src/ui/map3D/TextureCache.cc | 14 +++--- src/ui/map3D/TextureCache.h | 5 +- src/ui/map3D/WebImage.cc | 69 ++++++++++++++++++++++++++- src/ui/map3D/WebImage.h | 8 +++- src/ui/map3D/WebImageCache.cc | 22 +++++++-- src/ui/map3D/WebImageCache.h | 3 +- 11 files changed, 219 insertions(+), 39 deletions(-) diff --git a/src/ui/map3D/Imagery.cc b/src/ui/map3D/Imagery.cc index 8c2f9f3d9..1b7bacbe7 100644 --- a/src/ui/map3D/Imagery.cc +++ b/src/ui/map3D/Imagery.cc @@ -165,7 +165,7 @@ void Imagery::prefetch3D(double radius, double tileResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const QString& utmZone) + const QString& utmZone, bool useHeightModel) { int32_t minTileX, minTileY, maxTileX, maxTileY; int32_t zoomLevel; @@ -183,7 +183,7 @@ Imagery::prefetch3D(double radius, double tileResolution, { QString url = getTileLocation(c, r, zoomLevel, tileResolution); - TexturePtr t = textureCache->get(url); + TexturePtr t = textureCache->get(url, useHeightModel); } } } @@ -192,7 +192,7 @@ void Imagery::draw3D(double radius, double tileResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const QString& utmZone) + const QString& utmZone, bool useHeightModel) { int32_t minTileX, minTileY, maxTileX, maxTileY; int32_t zoomLevel; @@ -213,7 +213,7 @@ Imagery::draw3D(double radius, double tileResolution, double x1, y1, x2, y2, x3, y3, x4, y4; imageBounds(c, r, tileResolution, x1, y1, x2, y2, x3, y3, x4, y4); - TexturePtr t = textureCache->get(tileURL); + TexturePtr t = textureCache->get(tileURL, useHeightModel); if (!t.isNull()) { @@ -257,7 +257,8 @@ Imagery::imageBounds(int32_t tileX, int32_t tileY, double tileResolution, LLtoUTM(lat2, lon2, x3, y3, utmZone); LLtoUTM(lat2, lon1, x4, y4, utmZone); } - else if (currentImageryType == SWISSTOPO_SATELLITE) + else if (currentImageryType == SWISSTOPO_SATELLITE || + currentImageryType == SWISSTOPO_SATELLITE_3D) { double utmMultiplier = tileResolution * 200.0; double minX = tileX * utmMultiplier; @@ -294,7 +295,8 @@ Imagery::tileBounds(double tileResolution, UTMtoTile(maxUtmX, maxUtmY, utmZone, tileResolution, maxTileX, minTileY, zoomLevel); } - else if (currentImageryType == SWISSTOPO_SATELLITE) + else if (currentImageryType == SWISSTOPO_SATELLITE || + currentImageryType == SWISSTOPO_SATELLITE_3D) { double utmMultiplier = tileResolution * 200; @@ -570,7 +572,7 @@ Imagery::getTileLocation(int32_t tileX, int32_t tileY, int32_t zoomLevel, oss << "http://khm.google.com/vt/lbw/lyrs=y&x=" << tileX << "&y=" << tileY << "&z=" << zoomLevel; break; - case SWISSTOPO_SATELLITE: + case SWISSTOPO_SATELLITE: case SWISSTOPO_SATELLITE_3D: oss << "../map/eth_zurich_swissimage_025/200/color/" << tileY << "/tile-"; if (tileResolution < 1.0) diff --git a/src/ui/map3D/Imagery.h b/src/ui/map3D/Imagery.h index 22008e072..e0d8d3b3e 100644 --- a/src/ui/map3D/Imagery.h +++ b/src/ui/map3D/Imagery.h @@ -45,7 +45,8 @@ public: { GOOGLE_MAP = 0, GOOGLE_SATELLITE = 1, - SWISSTOPO_SATELLITE = 2 + SWISSTOPO_SATELLITE = 2, + SWISSTOPO_SATELLITE_3D = 3 }; void setImageryType(ImageryType type); @@ -63,11 +64,11 @@ public: void prefetch3D(double radius, double tileResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const QString& utmZone); + const QString& utmZone, bool useHeightModel); void draw3D(double radius, double tileResolution, double xOrigin, double yOrigin, double viewXOffset, double viewYOffset, - const QString& utmZone); + const QString& utmZone, bool useHeightModel); bool update(void); diff --git a/src/ui/map3D/QMap3DWidget.cc b/src/ui/map3D/QMap3DWidget.cc index 51ed0739f..0e9387550 100644 --- a/src/ui/map3D/QMap3DWidget.cc +++ b/src/ui/map3D/QMap3DWidget.cc @@ -96,6 +96,7 @@ QMap3DWidget::buildLayout(void) imageryComboBox->addItem("Map (Google)"); imageryComboBox->addItem("Satellite (Google)"); imageryComboBox->addItem("Satellite (Swisstopo)"); + imageryComboBox->addItem("3D Satellite (Swisstopo)"); QPushButton* recenterButton = new QPushButton(this); recenterButton->setText("Recenter Camera"); @@ -547,6 +548,10 @@ QMap3DWidget::showImagery(const QString& text) { imagery->setImageryType(Imagery::SWISSTOPO_SATELLITE); } + else if (text.compare("3D Satellite (Swisstopo)") == 0) + { + imagery->setImageryType(Imagery::SWISSTOPO_SATELLITE_3D); + } displayImagery = true; } } @@ -678,6 +683,7 @@ QMap3DWidget::drawImagery(double originX, double originY, double originZ, double minResolution = 0.25; double centerResolution = cameraPose.distance / 100.0; double maxResolution = 1048576.0; + bool useHeightModel = false; if (imageryComboBox->currentText().compare("Map (Google)") == 0) { @@ -692,6 +698,12 @@ QMap3DWidget::drawImagery(double originX, double originY, double originZ, minResolution = 0.25; maxResolution = 0.25; } + else if (imageryComboBox->currentText().compare("3D Satellite (Swisstopo)") == 0) + { + minResolution = 0.25; + maxResolution = 0.25; + useHeightModel = true; + } double resolution = minResolution; while (resolution * 2.0 < centerResolution) @@ -704,7 +716,8 @@ QMap3DWidget::drawImagery(double originX, double originY, double originZ, } imagery->draw3D(viewingRadius, resolution, originX, originY, - cameraPose.xOffset, cameraPose.yOffset, zone); + cameraPose.xOffset, cameraPose.yOffset, zone, + useHeightModel); if (prefetch) { @@ -712,13 +725,15 @@ QMap3DWidget::drawImagery(double originX, double originY, double originZ, { imagery->prefetch3D(viewingRadius / 2.0, resolution / 2.0, originX, originY, - cameraPose.xOffset, cameraPose.yOffset, zone); + cameraPose.xOffset, cameraPose.yOffset, zone, + useHeightModel); } if (resolution * 2.0 <= maxResolution) { imagery->prefetch3D(viewingRadius * 2.0, resolution * 2.0, originX, originY, - cameraPose.xOffset, cameraPose.yOffset, zone); + cameraPose.xOffset, cameraPose.yOffset, zone, + useHeightModel); } } diff --git a/src/ui/map3D/Texture.cc b/src/ui/map3D/Texture.cc index 184f44fe9..8efaa5858 100644 --- a/src/ui/map3D/Texture.cc +++ b/src/ui/map3D/Texture.cc @@ -32,6 +32,7 @@ This file is part of the QGROUNDCONTROL project #include "Texture.h" Texture::Texture() + : _is3D(false) { } @@ -54,9 +55,11 @@ Texture::sync(const WebImagePtr& image) state = static_cast(image->getState()); if (image->getState() != WebImage::UNINITIALIZED && - sourceURL != image->getSourceURL()) + (sourceURL != image->getSourceURL() || + _is3D != image->is3D())) { sourceURL = image->getSourceURL(); + _is3D = image->is3D(); } if (image->getState() == WebImage::READY && image->getSyncFlag()) @@ -91,7 +94,9 @@ Texture::sync(const WebImagePtr& image) glBindTexture(GL_TEXTURE_2D, id); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageWidth, imageHeight, - GL_RGBA, GL_UNSIGNED_BYTE, image->getData()); + GL_RGBA, GL_UNSIGNED_BYTE, image->getImageData()); + + heightModel = image->getHeightModel(); } } @@ -140,18 +145,77 @@ Texture::draw(float x1, float y1, float x2, float y2, } glColor3f(1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); + if (!_is3D) + { + glBegin(GL_QUADS); + glTexCoord2f(dx, maxV - dy); + glVertex3f(x1, y1, 0.0f); + glTexCoord2f(maxU - dx, maxV - dy); + glVertex3f(x2, y2, 0.0f); + glTexCoord2f(maxU - dx, dy); + glVertex3f(x3, y3, 0.0f); + glTexCoord2f(dx, dy); + glVertex3f(x4, y4, 0.0f); + glEnd(); + } + else + { + float scaleX = 1.0f / static_cast(heightModel.size() - 1); + + for (int32_t i = 0; i < heightModel.size() - 1; ++i) + { + float scaleI = scaleX * static_cast(i); - 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); + float scaleY = + 1.0f / static_cast(heightModel[i].size() - 1); - glEnd(); + float x1i = x1 + scaleI * (x4 - x1); + float x1f = x2 + scaleI * (x3 - x2); + float x2i = x1i + scaleX * (x4 - x1); + float x2f = x1f + scaleX * (x3 - x2); + + for (int32_t j = 0; j < heightModel[i].size() - 1; ++j) + { + float scaleJ = scaleY * static_cast(j); + + float y1i = y1 + scaleJ * (y2 - y1); + float y1f = y4 + scaleJ * (y3 - y4); + float y2i = y1i + scaleY * (y2 - y1); + float y2f = y1f + scaleY * (y3 - y4); + + float nx1 = x1i + scaleJ * (x1f - x1i); + float nx2 = x1i + (scaleJ + scaleY) * (x1f - x1i); + float nx3 = x2i + (scaleJ + scaleY) * (x2f - x2i); + float nx4 = x2i + scaleJ * (x2f - x2i); + float ny1 = y1i + scaleI * (y1f - y1i); + float ny2 = y2i + scaleI * (y2f - y2i); + float ny3 = y2i + (scaleI + scaleX) * (y2f - y2i); + float ny4 = y1i + (scaleI + scaleX) * (y1f - y1i); + + glBegin(GL_QUADS); + glTexCoord2f(dx + scaleJ * (maxU - dx * 2.0f), + dy + (1.0f - scaleI) * (maxV - dy * 2.0f)); + glVertex3f(nx1, ny1, -static_cast(heightModel[i][j])); + glTexCoord2f(dx + (scaleJ + scaleY) * (maxU - dx * 2.0f), + dy + (1.0f - scaleI) * (maxV - dy * 2.0f)); + glVertex3f(nx2, ny2, -static_cast(heightModel[i][j + 1])); + glTexCoord2f(dx + (scaleJ + scaleY) * (maxU - dx * 2.0f), + dy + (1.0f - scaleI - scaleX) * (maxV - dy * 2.0f)); + glVertex3f(nx3, ny3, -static_cast(heightModel[i + 1][j + 1])); + glTexCoord2f(dx + scaleJ * (maxU - dx * 2.0f), + dy + (1.0f - scaleI - scaleX) * (maxV - dy * 2.0f)); + glVertex3f(nx4, ny4, -static_cast(heightModel[i + 1][j])); + + glEnd(); + } + } + } glDisable(GL_TEXTURE_2D); } + +bool +Texture::is3D(void) const +{ + return _is3D; +} diff --git a/src/ui/map3D/Texture.h b/src/ui/map3D/Texture.h index 4b81617c6..79dc7355c 100644 --- a/src/ui/map3D/Texture.h +++ b/src/ui/map3D/Texture.h @@ -59,6 +59,8 @@ public: float x3, float y3, float x4, float y4, bool smoothInterpolation) const; + bool is3D(void) const; + private: enum State { @@ -77,6 +79,9 @@ private: int32_t imageWidth; int32_t imageHeight; + bool _is3D; + QVector< QVector > heightModel; + float maxU; float maxV; }; diff --git a/src/ui/map3D/TextureCache.cc b/src/ui/map3D/TextureCache.cc index 477c2b7f4..8449f7404 100644 --- a/src/ui/map3D/TextureCache.cc +++ b/src/ui/map3D/TextureCache.cc @@ -52,19 +52,20 @@ TextureCache::TextureCache(uint32_t _cacheSize) } TexturePtr -TextureCache::get(const QString& tileURL) +TextureCache::get(const QString& tileURL, bool useHeightModel) { - QPair p1 = lookup(tileURL); + QPair p1 = lookup(tileURL, useHeightModel); if (!p1.first.isNull()) { return p1.first; } - QPair p2 = imageCache->lookup(tileURL); + QPair p2 = + imageCache->lookup(tileURL, useHeightModel); if (!p2.first.isNull()) { textures[p2.second]->sync(p2.first); - p1 = lookup(tileURL); + p1 = lookup(tileURL, useHeightModel); return p1.first; } @@ -85,11 +86,12 @@ TextureCache::sync(void) } QPair -TextureCache::lookup(const QString& tileURL) +TextureCache::lookup(const QString& tileURL, bool useHeightModel) { for (int32_t i = 0; i < textures.size(); ++i) { - if (textures[i]->getSourceURL() == tileURL) + if (textures[i]->getSourceURL() == tileURL && + textures[i]->is3D() == useHeightModel) { return qMakePair(textures[i], i); } diff --git a/src/ui/map3D/TextureCache.h b/src/ui/map3D/TextureCache.h index 25be665b9..ef469a124 100644 --- a/src/ui/map3D/TextureCache.h +++ b/src/ui/map3D/TextureCache.h @@ -42,12 +42,13 @@ class TextureCache public: explicit TextureCache(uint32_t cacheSize); - TexturePtr get(const QString& tileURL); + TexturePtr get(const QString& tileURL, bool useHeightModel = false); void sync(void); private: - QPair lookup(const QString& tileURL); + QPair lookup(const QString& tileURL, + bool useHeightModel); bool requireSync(void) const; diff --git a/src/ui/map3D/WebImage.cc b/src/ui/map3D/WebImage.cc index a5c1e8836..466d68795 100644 --- a/src/ui/map3D/WebImage.cc +++ b/src/ui/map3D/WebImage.cc @@ -31,6 +31,7 @@ This file is part of the QGROUNDCONTROL project #include "WebImage.h" +#include #include WebImage::WebImage() @@ -38,6 +39,7 @@ WebImage::WebImage() , sourceURL("") , image(0) , lastReference(0) + , _is3D(false) , syncFlag(false) { @@ -50,6 +52,7 @@ WebImage::clear(void) sourceURL.clear(); state = WebImage::UNINITIALIZED; lastReference = 0; + heightModel.clear(); } WebImage::State @@ -77,11 +80,17 @@ WebImage::setSourceURL(const QString& url) } const uint8_t* -WebImage::getData(void) const +WebImage::getImageData(void) const { return image->scanLine(0); } +const QVector< QVector >& +WebImage::getHeightModel(void) const +{ + return heightModel; +} + bool WebImage::setData(const QByteArray& data) { @@ -122,6 +131,58 @@ WebImage::setData(const QString& filename) } } +bool +WebImage::setData(const QString& imageFilename, const QString& heightFilename) +{ + QFile heightFile(heightFilename); + + QImage tempImage; + if (tempImage.load(imageFilename) && heightFile.open(QIODevice::ReadOnly)) + { + if (image.isNull()) + { + image.reset(new QImage); + } + *image = QGLWidget::convertToGLFormat(tempImage); + + QDataStream heightDataStream(&heightFile); + + // read in width and height values for height map + char header[8]; + heightDataStream.readRawData(header, 8); + + int32_t height = *(reinterpret_cast(header)); + int32_t width = *(reinterpret_cast(header + 4)); + + char buffer[height * width * sizeof(int32_t)]; + heightDataStream.readRawData(buffer, height * width * sizeof(int32_t)); + + heightModel.clear(); + for (int32_t i = 0; i < height; ++i) + { + QVector scanline; + for (int32_t j = 0; j < width; ++j) + { + int32_t n = *(reinterpret_cast(buffer + + (i * height + j) + * sizeof(int32_t))); + scanline.push_back(n); + } + heightModel.push_back(scanline); + } + + heightFile.close(); + + _is3D = true; + + return true; + } + else + { + return false; + } +} + int32_t WebImage::getWidth(void) const { @@ -140,6 +201,12 @@ WebImage::getByteCount(void) const return image->byteCount(); } +bool +WebImage::is3D(void) const +{ + return _is3D; +} + uint64_t WebImage::getLastReference(void) const { diff --git a/src/ui/map3D/WebImage.h b/src/ui/map3D/WebImage.h index 02321a6b6..c4dc2a1d3 100644 --- a/src/ui/map3D/WebImage.h +++ b/src/ui/map3D/WebImage.h @@ -57,14 +57,18 @@ public: const QString& getSourceURL(void) const; void setSourceURL(const QString& url); - const uint8_t* getData(void) const; + const uint8_t* getImageData(void) const; + const QVector< QVector >& getHeightModel(void) const; bool setData(const QByteArray& data); bool setData(const QString& filename); + bool setData(const QString& imageFilename, const QString& heightFilename); int32_t getWidth(void) const; int32_t getHeight(void) const; int32_t getByteCount(void) const; + bool is3D(void) const; + uint64_t getLastReference(void) const; void setLastReference(uint64_t value); @@ -75,7 +79,9 @@ private: State state; QString sourceURL; QScopedPointer image; + QVector< QVector > heightModel; uint64_t lastReference; + bool _is3D; bool syncFlag; }; diff --git a/src/ui/map3D/WebImageCache.cc b/src/ui/map3D/WebImageCache.cc index aca9e4fa4..2203f2141 100644 --- a/src/ui/map3D/WebImageCache.cc +++ b/src/ui/map3D/WebImageCache.cc @@ -52,14 +52,15 @@ WebImageCache::WebImageCache(QObject* parent, uint32_t _cacheSize) } QPair -WebImageCache::lookup(const QString& url) +WebImageCache::lookup(const QString& url, bool useHeightModel) { QPair cacheEntry; for (int32_t i = 0; i < webImages.size(); ++i) { if (webImages[i]->getState() != WebImage::UNINITIALIZED && - webImages[i]->getSourceURL() == url) + webImages[i]->getSourceURL() == url && + webImages[i]->is3D() == useHeightModel) { cacheEntry.first = webImages[i]; cacheEntry.second = i; @@ -110,7 +111,22 @@ WebImageCache::lookup(const QString& url) } else { - if (cacheEntry.first->setData(url)) + bool success; + + if (useHeightModel) + { + QString heightURL = url; + heightURL.replace("color", "dom"); + heightURL.replace(".jpg", ".txt"); + + success = cacheEntry.first->setData(url, heightURL); + } + else + { + success = cacheEntry.first->setData(url); + } + + if (success) { cacheEntry.first->setSyncFlag(true); cacheEntry.first->setState(WebImage::READY); diff --git a/src/ui/map3D/WebImageCache.h b/src/ui/map3D/WebImageCache.h index d482d717a..7b2f1ea6b 100644 --- a/src/ui/map3D/WebImageCache.h +++ b/src/ui/map3D/WebImageCache.h @@ -45,7 +45,8 @@ class WebImageCache : public QObject public: WebImageCache(QObject* parent, uint32_t cacheSize); - QPair lookup(const QString& url); + QPair lookup(const QString& url, + bool useHeightModel); WebImagePtr at(int32_t index) const; -- 2.22.0