File indexing completed on 2025-01-19 03:58:10
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-12-01 0007 * Description : Tile index used in the tiling classes 0008 * 0009 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2009-2011 by Michael G. Hansen <mike at mghansen dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "tileindex.h" 0017 0018 // Local includes 0019 0020 #include "geoifacecommon.h" 0021 0022 namespace 0023 { 0024 static_assert (Digikam::TileIndex::Tiling == 10, 0025 "the constants below expect 10x10 tile splits"); 0026 0027 static_assert (Digikam::TileIndex::MaxLevel == 9, 0028 "the constants below expect 10x10 tile splits with max level 9"); 0029 0030 constexpr qint64 MaxLevelTileSplits = 10000000000LL; 0031 constexpr double MaxLevelTileSplitsFactor = 1.0 / static_cast<double>(MaxLevelTileSplits); 0032 } 0033 0034 0035 namespace Digikam 0036 { 0037 0038 TileIndex::TileIndex() 0039 : m_indicesCount(0) 0040 { 0041 for (int i = 0 ; i < MaxIndexCount ; ++i) 0042 { 0043 m_indices[i] = 0; 0044 } 0045 } 0046 0047 TileIndex::~TileIndex() 0048 { 0049 } 0050 0051 int TileIndex::indexCount() const 0052 { 0053 return m_indicesCount; 0054 } 0055 0056 int TileIndex::level() const 0057 { 0058 return (m_indicesCount > 0 ? m_indicesCount - 1 : 0); 0059 } 0060 0061 void TileIndex::clear() 0062 { 0063 m_indicesCount = 0; 0064 } 0065 0066 void TileIndex::appendLinearIndex(const int newIndex) 0067 { 0068 GEOIFACE_ASSERT(m_indicesCount + 1 <= MaxIndexCount); 0069 0070 m_indices[m_indicesCount] = newIndex; 0071 m_indicesCount++; 0072 } 0073 0074 int TileIndex::linearIndex(const int getLevel) const 0075 { 0076 GEOIFACE_ASSERT(getLevel<=level()); 0077 0078 return m_indices[getLevel]; 0079 } 0080 0081 int TileIndex::at(const int getLevel) const 0082 { 0083 GEOIFACE_ASSERT(getLevel<=level()); 0084 0085 return m_indices[getLevel]; 0086 } 0087 0088 int TileIndex::lastIndex() const 0089 { 0090 GEOIFACE_ASSERT(m_indicesCount>0); 0091 0092 return m_indices[m_indicesCount-1]; 0093 } 0094 0095 int TileIndex::indexLat(const int getLevel) const 0096 { 0097 return (linearIndex(getLevel) / Tiling); 0098 } 0099 0100 int TileIndex::indexLon(const int getLevel) const 0101 { 0102 return (linearIndex(getLevel) % Tiling); 0103 } 0104 0105 QPoint TileIndex::latLonIndex(const int getLevel) const 0106 { 0107 return QPoint(indexLon(getLevel), indexLat(getLevel)); 0108 } 0109 0110 void TileIndex::latLonIndex(const int getLevel, int* const latIndex, int* const lonIndex) const 0111 { 0112 GEOIFACE_ASSERT(getLevel <= level()); 0113 0114 *latIndex = indexLat(getLevel); 0115 *lonIndex = indexLon(getLevel); 0116 0117 GEOIFACE_ASSERT(*latIndex < Tiling); 0118 GEOIFACE_ASSERT(*lonIndex < Tiling); 0119 } 0120 0121 void TileIndex::appendLatLonIndex(const int latIndex, const int lonIndex) 0122 { 0123 appendLinearIndex(latIndex*Tiling + lonIndex); 0124 } 0125 0126 QIntList TileIndex::toIntList() const 0127 { 0128 QIntList result; 0129 0130 for (int i = 0 ; i < m_indicesCount ; ++i) 0131 { 0132 result << m_indices[i]; 0133 } 0134 0135 return result; 0136 } 0137 0138 TileIndex TileIndex::fromIntList(const QIntList& intList) 0139 { 0140 TileIndex result; 0141 0142 for (int i = 0 ; i < intList.count() ; ++i) 0143 { 0144 result.appendLinearIndex(intList.at(i)); 0145 } 0146 0147 return result; 0148 } 0149 0150 bool TileIndex::indicesEqual(const TileIndex& a, const TileIndex& b, const int upToLevel) 0151 { 0152 GEOIFACE_ASSERT(a.level() >= upToLevel); 0153 GEOIFACE_ASSERT(b.level() >= upToLevel); 0154 0155 for (int i = 0 ; i <= upToLevel ; ++i) 0156 { 0157 if (a.linearIndex(i) != b.linearIndex(i)) 0158 { 0159 return false; 0160 } 0161 } 0162 0163 return true; 0164 } 0165 0166 TileIndex TileIndex::mid(const int first, const int len) const 0167 { 0168 GEOIFACE_ASSERT(first+(len-1) <= m_indicesCount); 0169 0170 TileIndex result; 0171 0172 for (int i = first ; i < first + len ; ++i) 0173 { 0174 result.appendLinearIndex(m_indices[i]); 0175 } 0176 0177 return result; 0178 } 0179 0180 void TileIndex::oneUp() 0181 { 0182 GEOIFACE_ASSERT(m_indicesCount > 0); 0183 0184 m_indicesCount--; 0185 } 0186 0187 QList<QIntList> TileIndex::listToIntListList(const QList<TileIndex>& tileIndexList) 0188 { 0189 QList<QIntList> result; 0190 0191 for (int i = 0 ; i < tileIndexList.count() ; ++i) 0192 { 0193 result << tileIndexList.at(i).toIntList(); 0194 } 0195 0196 return result; 0197 } 0198 0199 TileIndex TileIndex::fromCoordinates(const Digikam::GeoCoordinates& coordinate, const int getLevel) 0200 { 0201 GEOIFACE_ASSERT(getLevel <= MaxLevel); 0202 0203 if (!coordinate.hasCoordinates()) 0204 { 0205 return TileIndex(); 0206 } 0207 0208 qint64 tileLat, tileLon; 0209 { 0210 // this is the only place where rounding happens 0211 0212 tileLat = static_cast<qint64>(((coordinate.lat() + 90.0) / 180.0) * MaxLevelTileSplits); 0213 tileLon = static_cast<qint64>(((coordinate.lon() + 180.0) / 360.0) * MaxLevelTileSplits); 0214 0215 // the very last tile includes it's upper bound 0216 0217 tileLat = std::min(tileLat, MaxLevelTileSplits-1); 0218 tileLon = std::min(tileLon, MaxLevelTileSplits-1); 0219 0220 // guard against bogus input 0221 0222 tileLat = std::max(tileLat, static_cast<qint64>(0)); 0223 tileLon = std::max(tileLon, static_cast<qint64>(0)); 0224 } 0225 0226 // every calculation below is on integers so no rounding issues 0227 0228 TileIndex tileIndex; 0229 0230 for (int i = 0 ; i <= TileIndex::MaxLevel ; ++i) 0231 { 0232 tileIndex.m_indices[TileIndex::MaxLevel-i] = (tileLat % Tiling) * Tiling + tileLon % Tiling; 0233 tileLat /= Tiling; 0234 tileLon /= Tiling; 0235 } 0236 0237 tileIndex.m_indicesCount = getLevel + 1; 0238 0239 return tileIndex; 0240 } 0241 0242 GeoCoordinates TileIndex::toCoordinates() const 0243 { 0244 return toCoordinates(CornerPosition::CornerSW); 0245 } 0246 0247 GeoCoordinates TileIndex::toCoordinates(const CornerPosition ofCorner) const 0248 { 0249 qint64 tileLat = 0; 0250 qint64 tileLon = 0; 0251 0252 for (int l = 0 ; l <= MaxLevel ; ++l) 0253 { 0254 tileLat *= Tiling; 0255 tileLon *= Tiling; 0256 0257 if (l < m_indicesCount) 0258 { 0259 tileLat += indexLat(l); 0260 tileLon += indexLon(l); 0261 } 0262 0263 if ((l + 1 == m_indicesCount) && 0264 ((ofCorner == CornerPosition::CornerNE) || 0265 (ofCorner == CornerPosition::CornerNW))) 0266 { 0267 tileLat += 1; 0268 } 0269 0270 if ((l + 1 == m_indicesCount) && 0271 ((ofCorner == CornerPosition::CornerNE) || 0272 (ofCorner == CornerPosition::CornerSE))) 0273 { 0274 tileLon += 1; 0275 } 0276 } 0277 0278 return Digikam::GeoCoordinates((tileLat - MaxLevelTileSplits / 2) * MaxLevelTileSplitsFactor * 180.0, 0279 (tileLon - MaxLevelTileSplits / 2) * MaxLevelTileSplitsFactor * 360.0); 0280 } 0281 0282 } // namespace Digikam 0283 0284 QDebug operator<<(QDebug debug, const Digikam::TileIndex& tileIndex) 0285 { 0286 debug << tileIndex.toIntList(); 0287 0288 return debug; 0289 }