From 17648ed8224f2497a3fa4aa2df7c455abd566421 Mon Sep 17 00:00:00 2001 From: "P. J. Reed" Date: Mon, 18 Jul 2016 11:11:07 -0500 Subject: [PATCH] Giving `tile_map` an interface overhaul MapQuest has turned off their public API for map tiles, so this plugin needed some work. I have: - Removed the MapQuest sources - Made the interface for adding new sources more powerful - Overhauled how sources are saved and loaded under the hood - Added a button to reset the current tile cache Resolves #402 --- mapviz/launch/mapviz.launch | 2 +- tile_map/CMakeLists.txt | 13 +- tile_map/include/tile_map/image_cache.h | 1 + tile_map/include/tile_map/texture_cache.h | 2 + tile_map/include/tile_map/tile_map_plugin.h | 24 +- tile_map/include/tile_map/tile_map_view.h | 24 +- tile_map/include/tile_map/tile_source.h | 99 +++++++++ tile_map/src/image_cache.cpp | 6 + tile_map/src/texture_cache.cpp | 6 + tile_map/src/tile_map_config.ui | 213 +++++++++++++++--- tile_map/src/tile_map_plugin.cpp | 231 +++++++++++++++----- tile_map/src/tile_map_view.cpp | 101 ++++++--- tile_map/src/tile_source.cpp | 126 +++++++++++ 13 files changed, 709 insertions(+), 139 deletions(-) create mode 100644 tile_map/include/tile_map/tile_source.h create mode 100644 tile_map/src/tile_source.cpp diff --git a/mapviz/launch/mapviz.launch b/mapviz/launch/mapviz.launch index 89076c0c..224048d5 100644 --- a/mapviz/launch/mapviz.launch +++ b/mapviz/launch/mapviz.launch @@ -2,7 +2,7 @@ - + diff --git a/tile_map/CMakeLists.txt b/tile_map/CMakeLists.txt index 62825b38..c1de3542 100644 --- a/tile_map/CMakeLists.txt +++ b/tile_map/CMakeLists.txt @@ -41,15 +41,18 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) file (GLOB TILE_SRC_FILES - src/image_cache.cpp - src/texture_cache.cpp - src/tile_map_view.cpp) + src/image_cache.cpp + src/texture_cache.cpp + src/tile_map_view.cpp) QT4_WRAP_CPP(TILE_SRC_FILES include/tile_map/image_cache.h) add_library(${PROJECT_NAME} ${TILE_SRC_FILES}) target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARIES} ${GLU_LIBRARY} ${catkin_LIBRARIES}) -file (GLOB PLUGIN_SRC_FILES src/tile_map_plugin.cpp) -file (GLOB PLUGIN_UI_FILES src/*.ui) +file (GLOB PLUGIN_SRC_FILES + src/tile_map_plugin.cpp + src/tile_source.cpp) +file (GLOB PLUGIN_UI_FILES + src/tile_map_config.ui) QT4_WRAP_UI(PLUGIN_SRC_FILES ${PLUGIN_UI_FILES}) QT4_WRAP_CPP(PLUGIN_SRC_FILES include/tile_map/tile_map_plugin.h) diff --git a/tile_map/include/tile_map/image_cache.h b/tile_map/include/tile_map/image_cache.h index 932a6eb7..ba25b7e5 100644 --- a/tile_map/include/tile_map/image_cache.h +++ b/tile_map/include/tile_map/image_cache.h @@ -99,6 +99,7 @@ namespace tile_map void ProcessRequest(QString uri); void ProcessReply(QNetworkReply* reply); void NetworkError(QNetworkReply::NetworkError error); + void Clear(); private: QNetworkAccessManager network_manager_; diff --git a/tile_map/include/tile_map/texture_cache.h b/tile_map/include/tile_map/texture_cache.h index bccbcbc7..9bb4b1a1 100644 --- a/tile_map/include/tile_map/texture_cache.h +++ b/tile_map/include/tile_map/texture_cache.h @@ -56,6 +56,8 @@ namespace tile_map TexturePtr GetTexture(size_t url_hash, const std::string& url, bool& failed); void AddTexture(const TexturePtr& texture); + + void Clear(); private: QCache cache_; diff --git a/tile_map/include/tile_map/tile_map_plugin.h b/tile_map/include/tile_map/tile_map_plugin.h index 7d632a88..36ac74c2 100644 --- a/tile_map/include/tile_map/tile_map_plugin.h +++ b/tile_map/include/tile_map/tile_map_plugin.h @@ -32,6 +32,7 @@ // C++ standard libraries #include +#include // Boost libraries #include @@ -51,6 +52,8 @@ namespace tile_map { + class TileSource; + class TileMapPlugin : public mapviz::MapvizPlugin { Q_OBJECT @@ -77,9 +80,16 @@ namespace tile_map void PrintWarning(const std::string& message); protected Q_SLOTS: - void SelectSource(QString style); + void DeleteTileSource(); + void SelectSource(QString source_name); + void SaveCustomSource(); + void ResetTileCache(); private: + void selectTileSource(const TileSource& tile_source); + void startCustomEditing(); + void stopCustomEditing(); + Ui::tile_map_config ui_; QWidget* config_widget_; @@ -89,6 +99,18 @@ namespace tile_map bool transformed_; TileMapView tile_map_; + std::map tile_sources_; + + static std::string BASE_URL_KEY; + static std::string COORD_ORDER_KEY; + static std::string CUSTOM_SOURCES_KEY; + static std::string MAX_ZOOM_KEY; + static std::string NAME_KEY; + static std::string SOURCE_KEY; + static std::string SUFFIX_KEY; + static QString STAMEN_TERRAIN_NAME; + static QString STAMEN_TONER_NAME; + static QString STAMEN_WATERCOLOR_NAME; }; } diff --git a/tile_map/include/tile_map/tile_map_view.h b/tile_map/include/tile_map/tile_map_view.h index 86298e4a..c294a350 100644 --- a/tile_map/include/tile_map/tile_map_view.h +++ b/tile_map/include/tile_map/tile_map_view.h @@ -36,10 +36,14 @@ #include +#include + #include namespace tile_map { + class TileSource; + struct Tile { public: @@ -59,13 +63,11 @@ namespace tile_map { public: TileMapView(); - - void SetBaseUrl(const std::string& url); - - void SetMaxLevel(int32_t level); - - void SetExtension(const std::string& extension); - + + void ResetCache(); + + void SetTileSource(const TileSource& tile_source); + void SetTransform(const swri_transform_util::Transform& transform); void SetView( @@ -78,14 +80,10 @@ namespace tile_map void Draw(); private: - std::string base_url_; - - std::string extension_; - + TileSource tile_source_; + swri_transform_util::Transform transform_; - int32_t max_level_; - int32_t level_; int64_t center_x_; diff --git a/tile_map/include/tile_map/tile_source.h b/tile_map/include/tile_map/tile_source.h new file mode 100644 index 00000000..30fe8e2f --- /dev/null +++ b/tile_map/include/tile_map/tile_source.h @@ -0,0 +1,99 @@ +// ***************************************************************************** +// +// Copyright (c) 2015, Southwest Research Institute® (SwRI®) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Southwest Research Institute® (SwRI®) nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL Southwest Research Institute® BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// ***************************************************************************** + +#ifndef TILE_MAP_TILE_SOURCE_H +#define TILE_MAP_TILE_SOURCE_H + +#include + +namespace tile_map +{ + class TileSource + { + public: + enum COORD_ORDER + { + // The order of the listing here should match the order listed + // in the combo box in tile_map_config.ui + ZXY, + ZYX, + XYZ, + XZY, + YXZ, + YZX + }; + + TileSource(); + + TileSource(const QString& name, + const QString& base_url, + COORD_ORDER coord_order, + bool is_custom, + int32_t max_zoom, + const QString& suffix + ); + + TileSource(const TileSource& tile_source); + + const QString& getBaseUrl() const; + + void setBaseUrl(const QString& base_url); + + COORD_ORDER getCoordOrder() const; + + void setCoordOrder(COORD_ORDER coord_order); + + bool isCustom() const; + + void setCustom(bool is_custom); + + int32_t getMaxZoom() const; + + void setMaxZoom(int32_t max_zoom); + + const QString& getName() const; + + void setName(const QString& name); + + const QString& getSuffix() const; + + void setSuffix(const QString& suffix); + + private: + QString base_url_; + COORD_ORDER coord_order_; + bool is_custom_; + int32_t max_zoom_; + QString name_; + QString suffix_; + }; +} + +#endif //TILE_MAP_TILE_SOURCE_H diff --git a/tile_map/src/image_cache.cpp b/tile_map/src/image_cache.cpp index 97df0253..35b9c5f2 100644 --- a/tile_map/src/image_cache.cpp +++ b/tile_map/src/image_cache.cpp @@ -104,6 +104,12 @@ namespace tile_map delete cache_thread_; } + void ImageCache::Clear() + { + cache_.clear(); + network_manager_.cache()->clear(); + } + ImagePtr ImageCache::GetImage(size_t uri_hash, const std::string& uri, int32_t priority) { ImagePtr image; diff --git a/tile_map/src/texture_cache.cpp b/tile_map/src/texture_cache.cpp index da08eb75..da015a21 100644 --- a/tile_map/src/texture_cache.cpp +++ b/tile_map/src/texture_cache.cpp @@ -159,4 +159,10 @@ namespace tile_map cache_.insert(texture->url_hash, texture_ptr); } } + + void TextureCache::Clear() + { + image_cache_->Clear(); + cache_.clear(); + } } diff --git a/tile_map/src/tile_map_config.ui b/tile_map/src/tile_map_config.ui index a1bedc76..8d5e90af 100644 --- a/tile_map/src/tile_map_config.ui +++ b/tile_map/src/tile_map_config.ui @@ -6,8 +6,8 @@ 0 0 - 395 - 300 + 294 + 178 @@ -24,7 +24,14 @@ 2 - + + + Base URL: + + + + + Sans Serif @@ -32,55 +39,104 @@ - Status: + Source: - - - - - Sans Serif - 8 - + + + + false - - + + + 0 + 0 + + + + z/x/y + + + + + z/y/x + + + + + x/y/z + + + + + x/z/y + + + + + y/x/z + + + + + y/z/x + + + + + + - Unconfigured + Coord order: - - true + + + + + + Max Zoom: - - - - - Sans Serif - 8 - + + + + Suffix: + + + + + + + false + + + + 50 + 16777215 + - Source: + .jpg + + + 16777215 + 27 + + - true + false - MapQuest (satellite) - - - - - MapQuest (roads) + Stamen (terrain) @@ -90,16 +146,107 @@ - Stamen (terrain) + Stamen (toner) - Stamen (toner) + Custom... + + + + false + + + http://tile.stamen.com/terrain/ + + + + + + + + Sans Serif + 8 + + + + Status: + + + + + + + false + + + + 0 + 0 + + + + + 50 + 16777215 + + + + 15 + + + + + + + Reset Cache + + + + + + + + Sans Serif + 8 + + + + + + + Unconfigured + + + true + + + + + + + false + + + Save... + + + + + + + false + + + Delete + + + diff --git a/tile_map/src/tile_map_plugin.cpp b/tile_map/src/tile_map_plugin.cpp index 58325b42..8f61d4ef 100644 --- a/tile_map/src/tile_map_plugin.cpp +++ b/tile_map/src/tile_map_plugin.cpp @@ -28,9 +28,12 @@ // ***************************************************************************** #include +#include // QT libraries #include +#include +#include #include // ROS libraries @@ -46,12 +49,42 @@ PLUGINLIB_DECLARE_CLASS(mapviz_plugins, tile_map, tile_map::TileMapPlugin, mapvi namespace tile_map { + std::string TileMapPlugin::BASE_URL_KEY = "base_url"; + std::string TileMapPlugin::COORD_ORDER_KEY = "coord_order"; + std::string TileMapPlugin::CUSTOM_SOURCES_KEY = "custom_sources"; + std::string TileMapPlugin::MAX_ZOOM_KEY = "max_zoom"; + std::string TileMapPlugin::NAME_KEY = "name"; + std::string TileMapPlugin::SOURCE_KEY = "source"; + std::string TileMapPlugin::SUFFIX_KEY = "suffix"; + QString TileMapPlugin::STAMEN_TERRAIN_NAME = "Stamen (terrain)"; + QString TileMapPlugin::STAMEN_TONER_NAME = "Stamen (toner)"; + QString TileMapPlugin::STAMEN_WATERCOLOR_NAME = "Stamen (watercolor)"; + TileMapPlugin::TileMapPlugin() : config_widget_(new QWidget()), transformed_(false) { ui_.setupUi(config_widget_); + tile_sources_[STAMEN_TERRAIN_NAME] = TileSource(STAMEN_TERRAIN_NAME, + "http://tile.stamen.com/terrain/", + TileSource::ZXY, + false, + 15, + ".png"); + tile_sources_[STAMEN_TONER_NAME] = TileSource(STAMEN_TONER_NAME, + "http://tile.stamen.com/toner/", + TileSource::ZXY, + false, + 19, + ".png"); + tile_sources_[STAMEN_WATERCOLOR_NAME] = TileSource(STAMEN_WATERCOLOR_NAME, + "http://tile.stamen.com/watercolor/", + TileSource::ZXY, + false, + 19, + ".jpg"); + QPalette p(config_widget_->palette()); p.setColor(QPalette::Background, Qt::white); config_widget_->setPalette(p); @@ -61,57 +94,109 @@ namespace tile_map ui_.status->setPalette(p2); source_frame_ = swri_transform_util::_wgs84_frame; - + + QObject::connect(ui_.delete_button, SIGNAL(clicked()), this, SLOT(DeleteTileSource())); QObject::connect(ui_.source_combo, SIGNAL(activated(QString)), this, SLOT(SelectSource(QString))); + QObject::connect(ui_.save_button, SIGNAL(clicked()), this, SLOT(SaveCustomSource())); + QObject::connect(ui_.reset_cache_button, SIGNAL(clicked()), this, SLOT(ResetTileCache())); } TileMapPlugin::~TileMapPlugin() { } + void TileMapPlugin::DeleteTileSource() + { + int source_index = ui_.source_combo->currentIndex(); + QString current_name = ui_.source_combo->currentText(); + + QMessageBox mbox; + mbox.setText("Are you sure you want to delete the source \"" + current_name + "\"?"); + mbox.setIcon(QMessageBox::Warning); + mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + mbox.setDefaultButton(QMessageBox::Cancel); + int ret = mbox.exec(); + + if (ret == QMessageBox::Ok) + { + ui_.source_combo->removeItem(source_index); + tile_sources_.erase(current_name); + ui_.source_combo->setCurrentIndex(0); + SelectSource(ui_.source_combo->currentText()); + } + } + void TileMapPlugin::SelectSource(QString source) { - if (source == "MapQuest (satellite)") + if (source == STAMEN_TERRAIN_NAME || + source == STAMEN_WATERCOLOR_NAME || + source == STAMEN_TONER_NAME) { - tile_map_.SetBaseUrl("http://otile1.mqcdn.com/tiles/1.0.0/sat/"); - tile_map_.SetExtension(".jpg"); - tile_map_.SetMaxLevel(18); + stopCustomEditing(); } - else if (source == "MapQuest (roads)") + else { - tile_map_.SetBaseUrl("http://otile1.mqcdn.com/tiles/1.0.0/map/"); - tile_map_.SetExtension(".jpg"); - tile_map_.SetMaxLevel(19); + startCustomEditing(); } - else if (source == "Stamen (watercolor)") + + if (tile_sources_.find(source) != tile_sources_.end()) { - tile_map_.SetBaseUrl("http://tile.stamen.com/watercolor/"); - tile_map_.SetExtension(".jpg"); - tile_map_.SetMaxLevel(19); - + selectTileSource(tile_sources_[source]); + initialized_ = true; } - else if (source == "Stamen (terrain)") + else { - tile_map_.SetBaseUrl("http://tile.stamen.com/terrain/"); - tile_map_.SetExtension(".jpg"); - tile_map_.SetMaxLevel(15); + ui_.delete_button->setEnabled(false); } - else if (source == "Stamen (toner)") + } + + void TileMapPlugin::SaveCustomSource() + { + // If the user is editing a custom source, we want to fill in the default + // name for it with its current name. + // Otherwise, they're creating a new custom source, in which case we + // should leave the default blank. + QString current_source = ui_.source_combo->currentText(); + QString default_name = ""; + if (tile_sources_.find(current_source) != tile_sources_.end()) { - tile_map_.SetBaseUrl("http://tile.stamen.com/toner/"); - tile_map_.SetExtension(".png"); - tile_map_.SetMaxLevel(19); + if (tile_sources_[current_source].isCustom()) + { + default_name = current_source; + } } - else + bool ok; + QString name = QInputDialog::getText(config_widget_, + tr("Save New Tile Source"), + tr("Tile Source Name:"), + QLineEdit::Normal, + default_name, + &ok); + name = name.trimmed(); + if (ok && !name.isEmpty()) { - tile_map_.SetBaseUrl(source.toStdString()); - tile_map_.SetExtension(".jpg"); - tile_map_.SetMaxLevel(19); + TileSource source(name, + ui_.base_url_text->text(), + static_cast(ui_.coord_order_combo_box->currentIndex()), + true, + ui_.max_zoom_spin_box->value(), + ui_.suffix_text->text()); + int existing_index = ui_.source_combo->findText(name); + if (existing_index != -1) + { + ui_.source_combo->removeItem(existing_index); + } + tile_sources_[name] = source; + ui_.source_combo->addItem(name); + int new_index = ui_.source_combo->findText(name); + ui_.source_combo->setCurrentIndex(new_index); + SelectSource(name); } + } - initialized_ = true; - - canvas_->update(); + void TileMapPlugin::ResetTileCache() + { + tile_map_.ResetCache(); } void TileMapPlugin::PrintError(const std::string& message) @@ -161,18 +246,16 @@ namespace tile_map { canvas_ = canvas; - SelectSource("MapQuest (satellite)"); + SelectSource(STAMEN_TERRAIN_NAME); return true; } void TileMapPlugin::Draw(double x, double y, double scale) { - //ROS_ERROR("Draw(%lf, %lf, %lf)", x, y, scale); swri_transform_util::Transform to_wgs84; if (tf_manager_.GetTransform(source_frame_, target_frame_, to_wgs84)) { - //ROS_ERROR("%s -> %s", target_frame_.c_str(), source_frame_.c_str()); tf::Vector3 center(x, y, 0); center = to_wgs84 * center; tile_map_.SetView(center.y(), center.x(), scale, canvas_->width(), canvas_->height()); @@ -196,29 +279,30 @@ namespace tile_map void TileMapPlugin::LoadConfig(const YAML::Node& node, const std::string& path) { - if (swri_yaml_util::FindValue(node, "custom_sources")) + if (swri_yaml_util::FindValue(node, CUSTOM_SOURCES_KEY)) { - const YAML::Node& sources = node["custom_sources"]; - for (uint32_t i = 0; i < sources.size(); i++) + const YAML::Node& sources = node[CUSTOM_SOURCES_KEY]; + YAML::Node::const_iterator source_iter; + for (source_iter = sources.begin(); source_iter != sources.end(); source_iter++) { - std::string url; - sources[i] >> url; - ui_.source_combo->addItem(QString::fromStdString(url)); + TileSource source(QString::fromStdString(((*source_iter)[NAME_KEY]).as()), + QString::fromStdString((*source_iter)[BASE_URL_KEY].as()), + static_cast((*source_iter)[COORD_ORDER_KEY].as()), + true, + (*source_iter)[MAX_ZOOM_KEY].as(), + QString::fromStdString((*source_iter)[SUFFIX_KEY].as()) + ); + tile_sources_[source.getName()] = source; + ui_.source_combo->addItem(source.getName()); } } - if (swri_yaml_util::FindValue(node, "source")) + if (node[SOURCE_KEY]) { - std::string source; - node["source"] >> source; - + std::string source = node[SOURCE_KEY].as(); + int index = ui_.source_combo->findText(QString::fromStdString(source), Qt::MatchExactly); - if (index < 0) - { - ui_.source_combo->addItem(QString::fromStdString(source)); - index = ui_.source_combo->findText(QString::fromStdString(source), Qt::MatchExactly); - } - + if (index >= 0) { ui_.source_combo->setCurrentIndex(index); @@ -230,17 +314,54 @@ namespace tile_map void TileMapPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path) { - if (ui_.source_combo->count() > 5) + emitter << YAML::Key << CUSTOM_SOURCES_KEY << YAML::Value << YAML::BeginSeq; + + std::map::iterator iter; + for (iter = tile_sources_.begin(); iter != tile_sources_.end(); iter++) { - emitter << YAML::Key << "custom_sources" << YAML::Value << YAML::BeginSeq; - for (int32_t i = 5; i < ui_.source_combo->count(); i++) + if (iter->second.isCustom()) { - emitter << YAML::Value << ui_.source_combo->itemText(i).toStdString(); + emitter << YAML::BeginMap; + emitter << YAML::Key << BASE_URL_KEY << YAML::Value << iter->second.getBaseUrl().toStdString(); + emitter << YAML::Key << COORD_ORDER_KEY << YAML::Value << (int)iter->second.getCoordOrder(); + emitter << YAML::Key << MAX_ZOOM_KEY << YAML::Value << iter->second.getMaxZoom(); + emitter << YAML::Key << NAME_KEY << YAML::Value << iter->second.getName().toStdString(); + emitter << YAML::Key << SUFFIX_KEY << YAML::Value << iter->second.getSuffix().toStdString(); + emitter << YAML::EndMap; } - emitter << YAML::EndSeq; } - - emitter << YAML::Key << "source" << YAML::Value << boost::trim_copy(ui_.source_combo->currentText().toStdString()); + emitter << YAML::EndSeq; + + emitter << YAML::Key << SOURCE_KEY << YAML::Value << boost::trim_copy(ui_.source_combo->currentText().toStdString()); + } + + void TileMapPlugin::selectTileSource(const TileSource& tile_source) + { + tile_map_.SetTileSource(tile_source); + ui_.base_url_text->setText(tile_source.getBaseUrl()); + ui_.suffix_text->setText(tile_source.getSuffix()); + ui_.coord_order_combo_box->setCurrentIndex((int)tile_source.getCoordOrder()); + ui_.max_zoom_spin_box->setValue(tile_source.getMaxZoom()); + } + + void TileMapPlugin::startCustomEditing() + { + ui_.base_url_text->setEnabled(true); + ui_.suffix_text->setEnabled(true); + ui_.coord_order_combo_box->setEnabled(true); + ui_.delete_button->setEnabled(true); + ui_.max_zoom_spin_box->setEnabled(true); + ui_.save_button->setEnabled(true); + } + + void TileMapPlugin::stopCustomEditing() + { + ui_.base_url_text->setEnabled(false); + ui_.suffix_text->setEnabled(false); + ui_.coord_order_combo_box->setEnabled(false); + ui_.delete_button->setEnabled(false); + ui_.max_zoom_spin_box->setEnabled(false); + ui_.save_button->setEnabled(false); } } diff --git a/tile_map/src/tile_map_view.cpp b/tile_map/src/tile_map_view.cpp index 6ad4a943..1363b6de 100644 --- a/tile_map/src/tile_map_view.cpp +++ b/tile_map/src/tile_map_view.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -47,9 +48,7 @@ namespace tile_map { TileMapView::TileMapView() : - base_url_("localhost"), - extension_(".jpg"), - max_level_(19), + tile_source_("localhost", "localhost", TileSource::ZXY, true, 19, ".jpg"), level_(-1), width_(100), height_(100) @@ -57,26 +56,18 @@ namespace tile_map ImageCachePtr image_cache = boost::make_shared("/tmp/tile_map"); tile_cache_ = boost::make_shared(image_cache); } - - void TileMapView::SetMaxLevel(int32_t level) - { - max_level_ = level; - } - - void TileMapView::SetExtension(const std::string& extension) + + void TileMapView::ResetCache() { - extension_ = extension; + tile_cache_->Clear(); } - - void TileMapView::SetBaseUrl(const std::string& url) + + void TileMapView::SetTileSource(const TileSource& tile_source) { - if (base_url_ != url) - { - base_url_ = url; - level_ = -1; - } + tile_source_ = tile_source; + level_ = -1; } - + void TileMapView::SetTransform(const swri_transform_util::Transform& transform) { if (transform.GetOrigin() == transform_.GetOrigin() && @@ -126,7 +117,7 @@ namespace tile_map // double lat_circumference = swri_transform_util::_earth_equator_circumference * std::cos(lat) / scale; - int32_t level = std::min(max_level_, std::max(0, static_cast( + int32_t level = std::min(tile_source_.getMaxZoom(), std::max(0, static_cast( std::ceil(std::log(lat_circumference) / std::log(2) - 8)))); int64_t max_size = std::pow(2, level); @@ -228,8 +219,8 @@ namespace tile_map texture = tile_cache_->GetTexture(precache_[i].url_hash, precache_[i].url, failed); if (failed) { - max_level_ = std::min(max_level_, precache_[i].level - 1); - ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_); + tile_source_.setMaxZoom(std::min(tile_source_.getMaxZoom(), precache_[i].level - 1)); + ROS_WARN("===== SETTING MAX LEVEL TO %d =====", tile_source_.getMaxZoom()); } } @@ -283,8 +274,8 @@ namespace tile_map texture = tile_cache_->GetTexture(tiles_[i].url_hash, tiles_[i].url, failed); if (failed) { - max_level_ = std::min(max_level_, tiles_[i].level - 1); - ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_); + tile_source_.setMaxZoom(std::min(tile_source_.getMaxZoom(), tiles_[i].level - 1)); + ROS_WARN("===== SETTING MAX LEVEL TO %d =====", tile_source_.getMaxZoom()); } } @@ -342,11 +333,59 @@ namespace tile_map void TileMapView::InitializeTile(int32_t level, int64_t x, int64_t y, Tile& tile) { - tile.url = base_url_ + - boost::lexical_cast(level) + "/" + - boost::lexical_cast(x) + "/" + - boost::lexical_cast(y) + extension_; - + std::stringstream url; + url << tile_source_.getBaseUrl().toStdString(); + + switch (tile_source_.getCoordOrder()) + { + case TileSource::XYZ: + case TileSource::XZY: + url << boost::lexical_cast(x); + break; + case TileSource::YXZ: + case TileSource::YZX: + url << boost::lexical_cast(y); + break; + case TileSource::ZXY: + case TileSource::ZYX: + url << boost::lexical_cast(level); + break; + } + url << "/"; + switch (tile_source_.getCoordOrder()) + { + case TileSource::ZXY: + case TileSource::YXZ: + url << boost::lexical_cast(x); + break; + case TileSource::ZYX: + case TileSource::XYZ: + url << boost::lexical_cast(y); + break; + case TileSource::XZY: + case TileSource::YZX: + url << boost::lexical_cast(level); + break; + } + url << "/"; + switch (tile_source_.getCoordOrder()) + { + case TileSource::YZX: + case TileSource::ZYX: + url << boost::lexical_cast(x); + break; + case TileSource::ZXY: + case TileSource::XZY: + url << boost::lexical_cast(y); + break; + case TileSource::YXZ: + case TileSource::XYZ: + url << boost::lexical_cast(level); + break; + } + url << tile_source_.getSuffix().toStdString(); + + tile.url = url.str(); tile.url_hash = hash_function_(tile.url); @@ -356,8 +395,8 @@ namespace tile_map tile.texture = tile_cache_->GetTexture(tile.url_hash, tile.url, failed); if (failed) { - max_level_ = std::min(max_level_, level - 1); - ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_); + tile_source_.setMaxZoom(std::min(tile_source_.getMaxZoom(), level - 1)); + ROS_WARN("===== SETTING MAX LEVEL TO %d =====", tile_source_.getMaxZoom()); } int32_t subdivs = std::max(0, 4 - level); diff --git a/tile_map/src/tile_source.cpp b/tile_map/src/tile_source.cpp new file mode 100644 index 00000000..df57941d --- /dev/null +++ b/tile_map/src/tile_source.cpp @@ -0,0 +1,126 @@ +// ***************************************************************************** +// +// Copyright (c) 2015, Southwest Research Institute® (SwRI®) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Southwest Research Institute® (SwRI®) nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL Southwest Research Institute® BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// ***************************************************************************** + +#include + +namespace tile_map +{ + TileSource::TileSource() : + coord_order_(ZYX), + is_custom_(false), + max_zoom_(-1) + { + } + + TileSource::TileSource(const QString& name, + const QString& base_url, + COORD_ORDER coord_order, + bool is_custom, + int32_t max_zoom, + const QString& suffix) : + base_url_(base_url), + coord_order_(coord_order), + is_custom_(is_custom), + max_zoom_(max_zoom), + name_(name), + suffix_(suffix) + { + } + + TileSource::TileSource(const TileSource& tile_source) : + base_url_(tile_source.base_url_), + coord_order_(tile_source.coord_order_), + is_custom_(tile_source.is_custom_), + max_zoom_(tile_source.max_zoom_), + name_(tile_source.name_), + suffix_(tile_source.suffix_) + { + } + + const QString& TileSource::getBaseUrl() const + { + return base_url_; + } + + void TileSource::setBaseUrl(const QString& base_url) + { + base_url_ = base_url; + } + + TileSource::COORD_ORDER TileSource::getCoordOrder() const + { + return coord_order_; + } + + void TileSource::setCoordOrder(TileSource::COORD_ORDER coord_order) + { + coord_order_ = coord_order; + } + + bool TileSource::isCustom() const + { + return is_custom_; + } + + void TileSource::setCustom(bool is_custom) + { + is_custom_ = is_custom; + } + + int32_t TileSource::getMaxZoom() const + { + return max_zoom_; + } + + void TileSource::setMaxZoom(int32_t max_zoom) + { + max_zoom_ = max_zoom; + } + + const QString& TileSource::getName() const + { + return name_; + } + + void TileSource::setName(const QString& name) + { + name_ = name; + } + + const QString& TileSource::getSuffix() const + { + return suffix_; + } + + void TileSource::setSuffix(const QString& suffix) + { + suffix_ = suffix; + } +}