diff --git a/Map/GeoCluster.cpp b/Map/GeoCluster.cpp index 91e2078b..1b345906 100644 --- a/Map/GeoCluster.cpp +++ b/Map/GeoCluster.cpp @@ -1,198 +1,198 @@ /* Copyright (C) 2019 The KPhotoAlbum Development Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "GeoCluster.h" #include "GeoCoordinates.h" #include "Logging.h" #include #include #include #include #include #include #include #include namespace { // when the angular resolution is smaller than fineResolution, all details should be shown constexpr qreal FINE_RESOLUTION = 0.000001; // size of the markers in screen coordinates (pixel) constexpr int MARKER_SIZE_PX = 40; /** * @brief screenSize computes the screen size of a geographical region in pixels. * If one of the bounding box edges is not visible, a null QizeF is retunred. * @param viewPortParams the parameters of the current view port * @param box the geographical region * @return the size in pixels, or a null size */ QSizeF screenSize(const Marble::ViewportParams &viewPortParams, const Marble::GeoDataLatLonBox &box, bool debug = false) { - qreal NE_x; - qreal NE_y; - qreal SW_x; - qreal SW_y; + qreal east; + qreal north; + qreal west; + qreal south; // if a point is not visible on screen, screenCoordinates() returns false // the result is still usable, though - bool valid; - valid = viewPortParams.screenCoordinates(box.east(Marble::GeoDataCoordinates::Radian), - box.north(Marble::GeoDataCoordinates::Radian), - NE_x, NE_y); - valid &= viewPortParams.screenCoordinates(box.west(Marble::GeoDataCoordinates::Radian), - box.south(Marble::GeoDataCoordinates::Radian), - SW_x, SW_y); + bool onScreen; + onScreen = viewPortParams.screenCoordinates(box.east(Marble::GeoDataCoordinates::Radian), + box.north(Marble::GeoDataCoordinates::Radian), + east, north); + onScreen &= viewPortParams.screenCoordinates(box.west(Marble::GeoDataCoordinates::Radian), + box.south(Marble::GeoDataCoordinates::Radian), + west, south); if (debug) { - qCDebug(MapLog) << "coordinates" << NE_x << "-" << SW_x << "," << NE_y << "-" << SW_y << "are" << (valid ? "valid" : "invalid"); + qCDebug(MapLog) << "coordinates" << east << "-" << west << "," << north << "-" << south << "are" << (onScreen ? "on screen" : "not (fully) on screen"); } - return QSizeF { qAbs(NE_x - SW_x), qAbs(NE_y - SW_y) }; + return QSizeF { qAbs(east - west), qAbs(north - south) }; } } //namespace Marble::GeoDataLatLonAltBox Map::GeoCluster::boundingRegion() const { if (m_boundingRegion.isEmpty()) { for (const auto &subCluster : m_subClusters) { m_boundingRegion |= subCluster->boundingRegion(); } } return m_boundingRegion; } Marble::GeoDataCoordinates Map::GeoCluster::center() const { // TODO(jzarl): check how this compares to e.g. the center of all coordinates instead: return boundingRegion().center(); } void Map::GeoCluster::render(Marble::GeoPainter *painter, const Marble::ViewportParams &viewPortParams, const QPixmap &alternatePixmap, Map::MapStyle style) const { if (viewPortParams.resolves(boundingRegion(), 2 * MARKER_SIZE_PX) || size() == 1 || (viewPortParams.angularResolution() < FINE_RESOLUTION)) { // if the region takes up enough screen space, we should display the subclusters individually. // if all images have the same coordinates (null bounding region), this will never happen // -> in this case, show the images when we're zoomed in enough renderSubItems(painter, viewPortParams, alternatePixmap, style); } else { qCDebug(MapLog) << "GeoCluster has" << size() << "images."; painter->setOpacity(0.5); const QSizeF areaSizePx = screenSize(viewPortParams, boundingRegion()); // drawing a larger area gets nicer results on average: const qreal heightPx = qMax(1.2 * areaSizePx.height(), (qreal)MARKER_SIZE_PX); const qreal widthPx = qMax(1.2 * areaSizePx.width(), (qreal)MARKER_SIZE_PX); painter->drawRect(center(), heightPx, widthPx); painter->setOpacity(1); QPen pen = painter->pen(); painter->setPen(QPen(Qt::black)); painter->drawText(center(), i18nc("The number of images in an area of the map", "%1", size()), -0.5 * MARKER_SIZE_PX, 0.5 * MARKER_SIZE_PX, MARKER_SIZE_PX, MARKER_SIZE_PX, QTextOption(Qt::AlignCenter)); painter->setPen(pen); } } int Map::GeoCluster::size() const { if (m_size == 0) { for (const auto &subCluster : m_subClusters) { m_size += subCluster->size(); } } return m_size; } void Map::GeoCluster::renderSubItems(Marble::GeoPainter *painter, const Marble::ViewportParams &viewPortParams, const QPixmap &alternatePixmap, Map::MapStyle style) const { for (const auto &subCluster : m_subClusters) { subCluster->render(painter, viewPortParams, alternatePixmap, style); } } Map::GeoCluster::GeoCluster(int lvl) : m_level(lvl) { } void Map::GeoCluster::addSubCluster(const Map::GeoCluster *subCluster) { m_subClusters.append(subCluster); } Map::GeoBin::GeoBin() : GeoCluster(0) { } void Map::GeoBin::addImage(DB::ImageInfoPtr image) { m_images.append(image); extendGeoDataLatLonBox(m_boundingRegion, image->coordinates()); } Marble::GeoDataLatLonAltBox Map::GeoBin::boundingRegion() const { return m_boundingRegion; } int Map::GeoBin::size() const { return m_images.size(); } void Map::GeoBin::renderSubItems(Marble::GeoPainter *painter, const Marble::ViewportParams &viewPortParams, const QPixmap &alternatePixmap, Map::MapStyle style) const { const auto viewPort = viewPortParams.viewLatLonAltBox(); qCDebug(MapLog) << "GeoBin: drawing individual images"; for (const DB::ImageInfoPtr &image : m_images) { const Marble::GeoDataCoordinates pos(image->coordinates().lon(), image->coordinates().lat(), image->coordinates().alt(), Marble::GeoDataCoordinates::Degree); if (viewPort.contains(pos)) { if (style == MapStyle::ShowPins) { painter->drawPixmap(pos, alternatePixmap); } else { // FIXME(l3u) Maybe we should cache the scaled thumbnails? painter->drawPixmap(pos, ImageManager::ThumbnailCache::instance()->lookup(image->fileName()).scaled(QSize(MARKER_SIZE_PX, MARKER_SIZE_PX), Qt::KeepAspectRatio)); } } } } void Map::extendGeoDataLatLonBox(Marble::GeoDataLatLonBox &box, const Map::GeoCoordinates &coords) { if (box.isEmpty()) { box.setEast(coords.lon(), Marble::GeoDataCoordinates::Degree); box.setWest(coords.lon(), Marble::GeoDataCoordinates::Degree); box.setNorth(coords.lat(), Marble::GeoDataCoordinates::Degree); box.setSouth(coords.lat(), Marble::GeoDataCoordinates::Degree); } else { if (box.east(Marble::GeoDataCoordinates::Degree) < coords.lon()) { box.setEast(coords.lon(), Marble::GeoDataCoordinates::Degree); } if (box.west(Marble::GeoDataCoordinates::Degree) > coords.lon()) { box.setWest(coords.lon(), Marble::GeoDataCoordinates::Degree); } if (box.north(Marble::GeoDataCoordinates::Degree) < coords.lat()) { box.setNorth(coords.lat(), Marble::GeoDataCoordinates::Degree); } if (box.south(Marble::GeoDataCoordinates::Degree) > coords.lat()) { box.setSouth(coords.lat(), Marble::GeoDataCoordinates::Degree); } } }