tile_cache.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 
00030 #include <multires_image/tile_cache.h>
00031 
00032 // C++ standard libraries
00033 #include <cmath>
00034 #include <cstdlib>
00035 #include <algorithm>
00036 #include <iostream>
00037 #include <exception>
00038 
00039 // QT libraries
00040 #include <QApplication>
00041 #include <QEvent>
00042 
00043 #include <multires_image/tile_set_layer.h>
00044 
00045 namespace multires_image
00046 {
00047   TileCache::TileCache(TileSet* tileSet, QGLWidget* widget) :
00048     m_tileSet(tileSet),
00049     m_widget(widget),
00050     m_currentLayer(0),
00051     m_currentPosition(0, 0, 0),
00052     m_exit(false),
00053     m_memorySize(0),
00054     m_cacheThread(this),
00055     m_freeThread(this),
00056     m_renderRequestsLock(QMutex::Recursive),
00057     m_renderRequestSetLock(QMutex::Recursive),
00058     m_precacheRequestsLock(QMutex::Recursive),
00059     m_precacheRequestSetLock(QMutex::Recursive),
00060     m_textureLoadedLock(QMutex::Recursive)
00061   {
00062     connect(this, SIGNAL(SignalLoadTexture(Tile*)),
00063       SLOT(LoadTextureSlot(Tile*)), Qt::BlockingQueuedConnection);
00064 
00065     connect(this, SIGNAL(SignalDeleteTexture(Tile*)),
00066       SLOT(DeleteTextureSlot(Tile*)), Qt::BlockingQueuedConnection);
00067 
00068     m_cacheThread.setPriority(QThread::NormalPriority);
00069     m_cacheThread.start();
00070 
00071     m_freeThread.setPriority(QThread::LowPriority);
00072     m_freeThread.start();
00073 
00074     for (int i = 0; i < m_tileSet->LayerCount(); i++)
00075     {
00076       m_precacheRequests.push_back(std::queue<Tile*>());
00077     }
00078   }
00079 
00080   TileCache::~TileCache(void)
00081   {
00082     m_exit = true;
00083     m_cacheThread.wait();
00084     m_freeThread.wait();
00085   }
00086 
00087   void TileCache::LoadTextureSlot(Tile* tile)
00088   {
00089     tile->LoadTexture();
00090   }
00091 
00092   void TileCache::DeleteTextureSlot(Tile* tile)
00093   {
00094     tile->UnloadTexture();
00095   }
00096 
00097   void TileCache::Load(Tile* tile)
00098   {
00099     m_renderRequestsLock.lock();
00100     m_renderRequestSetLock.lock();
00101 
00102     try
00103     {
00104       if (m_renderRequestSet.count(tile->TileID()) == 0)
00105       {
00106         m_renderRequests.push(tile);
00107         m_renderRequestSet[tile->TileID()] = tile;
00108       }
00109     }
00110     catch(const std::exception& e)
00111     {
00112       std::cout << "An exception occurred queuing a tile to be cached: " << e.what() << std::endl;
00113     }
00114 
00115     m_renderRequestSetLock.unlock();
00116     m_renderRequestsLock.unlock();
00117   }
00118 
00119   void TileCache::Precache(double x, double y)
00120   {
00121     tf::Point point(x, y, 0);
00122     Precache(point);
00123   }
00124 
00125   void TileCache::Precache(const tf::Point& position)
00126   {
00127     m_currentPosition = position;
00128 
00129     int sizes[] = {3, 2, 2, 1, 1, 1};
00130 
00131     PrecacheLayer(m_currentLayer, m_currentPosition, sizes[0]);
00132 
00133     for (int i = 1; i <= 5; i++)
00134     {
00135       int layer = m_currentLayer + i;
00136       if (layer < m_tileSet->LayerCount())
00137       {
00138         PrecacheLayer(layer, m_currentPosition, sizes[i]);
00139       }
00140 
00141       layer = m_currentLayer - i;
00142       if (layer >= 0)
00143       {
00144         PrecacheLayer(layer, m_currentPosition, sizes[i]);
00145       }
00146     }
00147   }
00148 
00149   void TileCache::PrecacheLayer(int layerNum, const tf::Point& position, int size)
00150   {
00151     TileSetLayer* layer = m_tileSet->GetLayer(layerNum);
00152 
00153     int row, column;
00154     layer->GetTileIndex(position, row, column);
00155 
00156     int startRow = std::max(0, row - size);
00157     int endRow = std::min(layer->RowCount() - 1, row + size);
00158     int startColumn = std::max(0, column - size);
00159     int endColumn = std::min(layer->ColumnCount() - 1, column + size);
00160 
00161     for (int c = startColumn; c <= endColumn; c++)
00162     {
00163       for (int r = startRow; r <= endRow; r++)
00164       {
00165         Tile* tile = layer->GetTile(c, r);
00166 
00167         m_precacheRequestsLock.lock();
00168         m_precacheRequestSetLock.lock();
00169 
00170         try
00171         {
00172           if (m_precacheRequestSet.count(tile->TileID()) == 0)
00173           {
00174             m_precacheRequests[layerNum].push(tile);
00175             m_precacheRequestSet[tile->TileID()] = tile;
00176           }
00177         }
00178         catch (const std::exception& e)
00179         {
00180           std::cout << "An exception occurred queuing tiles for precaching: " << e.what() << std::endl;
00181         }
00182 
00183         m_precacheRequestSetLock.unlock();
00184         m_precacheRequestsLock.unlock();
00185       }
00186     }
00187   }
00188 
00189   void TileCache::Exit()
00190   {
00191     m_exit = true;
00192   }
00193 
00194   void TileCache::LoadTexture(Tile* tile)
00195   {
00196     Q_EMIT SignalLoadTexture(tile);
00197 
00198     m_memorySize += tile->MemorySize();
00199     Q_EMIT SignalMemorySize(m_memorySize);
00200 
00201     m_textureLoadedLock.lock();
00202 
00203     try
00204     {
00205       m_textureLoaded[tile->TileID()] = tile;
00206     }
00207     catch (const std::exception& e)
00208     {
00209       std::cout << "An exception occurred loading texture: " << e.what() << std::endl;
00210     }
00211 
00212     m_textureLoadedLock.unlock();
00213 
00214     if (tile->Layer() == m_currentLayer)
00215     {
00216       QApplication::postEvent(m_widget, new QEvent(QEvent::UpdateRequest));
00217     }
00218   }
00219 
00220   void TileCache::UnloadTexture(Tile* tile)
00221   {
00222     Q_EMIT SignalDeleteTexture(tile);
00223 
00224     m_memorySize -= tile->MemorySize();
00225     Q_EMIT SignalMemorySize(m_memorySize);
00226 
00227     m_textureLoadedLock.lock();
00228 
00229     try
00230     {
00231       m_textureLoaded.erase(tile->TileID());
00232     }
00233     catch (const std::exception& e)
00234     {
00235       std::cout << "An exception occurred unloading texture: " << e.what() << std::endl;
00236     }
00237 
00238     m_textureLoadedLock.unlock();
00239   }
00240 
00241   void TileCache::CacheThread::run()
00242   {
00243     while (!p->m_exit)
00244     {
00245       Tile* tile = NULL;
00246       p->m_renderRequestsLock.lock();
00247 
00248       if (p->m_renderRequests.size() > 0)
00249       {
00250         tile = p->m_renderRequests.top();
00251         p->m_renderRequests.pop();
00252       }
00253 
00254       p->m_renderRequestsLock.unlock();
00255 
00256       if (tile != NULL)
00257       {
00258         if (!tile->Failed())
00259         {
00260           if (tile->Layer() == p->m_currentLayer)
00261           {
00262             int row, column;
00263             p->m_tileSet->GetLayer(tile->Layer())->GetTileIndex(p->m_currentPosition, row, column);
00264 
00265             if (abs(tile->Row() - row) <= 3 || abs(tile->Column() - column) < 3)
00266             {
00267               if (!tile->TextureLoaded())
00268               {
00269                 if (tile->LoadImageToMemory() == true)
00270                 {
00271                   p->LoadTexture(tile);
00272                   tile->UnloadImage();
00273                 }
00274                 else
00275                 {
00276                   printf("failed to load image\n");
00277                 }
00278               }
00279             }
00280           }
00281           else
00282           {
00283             p->m_precacheRequests[tile->Layer()].push(tile);
00284           }
00285 
00286           p->m_renderRequestSetLock.lock();
00287           p->m_renderRequestSet.erase(tile->TileID());
00288           p->m_renderRequestSetLock.unlock();
00289         }
00290         else
00291         {
00292         }
00293       }
00294       else
00295       {
00296         p->m_precacheRequestsLock.lock();
00297 
00298         try
00299         {
00300           for (uint32_t i = 0; (i < p->m_precacheRequests.size()) && (tile == NULL); i++)
00301           {
00302             int32_t index = p->m_currentLayer + i;
00303             if ((index < (int64_t)p->m_precacheRequests.size()) &&
00304                 (p->m_precacheRequests[index].size() > 0))
00305             {
00306               tile = p->m_precacheRequests[index].front();
00307               p->m_precacheRequests[index].pop();
00308             }
00309             else if (i != 0)
00310             {
00311               index = p->m_currentLayer - i;
00312               if (index >= 0 && p->m_precacheRequests[index].size() > 0)
00313               {
00314                 tile = p->m_precacheRequests[index].front();
00315                 p->m_precacheRequests[index].pop();
00316               }
00317             }
00318           }
00319         }
00320         catch (const std::exception& e)
00321         {
00322           std::cout << "An exception occurred precaching texture: " << e.what() << std::endl;
00323         }
00324 
00325         p->m_precacheRequestsLock.unlock();
00326 
00327         if (tile != NULL && !tile->Failed() && !tile->TextureLoaded())
00328         {
00329           int row, column;
00330           p->m_tileSet->GetLayer(tile->Layer())->GetTileIndex(p->m_currentPosition, row, column);
00331           if (abs(tile->Row() - row) <= 3 || abs(tile->Column() - column) <= 3)
00332           {
00333             if (tile->LoadImageToMemory() == true)
00334             {
00335               p->LoadTexture(tile);
00336 
00337               tile->UnloadImage();
00338             }
00339             else
00340             {
00341               printf("failed to precache load image\n");
00342             }
00343           }
00344 
00345           p->m_precacheRequestSetLock.lock();
00346           p->m_precacheRequestSet.erase(tile->TileID());
00347           p->m_precacheRequestSetLock.unlock();
00348         }
00349       }
00350 
00351       if (tile == NULL)
00352       {
00353         usleep(10);
00354       }
00355     }
00356   }
00357 
00358   void TileCache::FreeThread::run()
00359   {
00360     while (!p->m_exit)
00361     {
00362       std::map<int64_t, Tile*>* tiles;
00363       p->m_textureLoadedLock.lock();
00364 
00365       tiles = new std::map<int64_t, Tile*>(p->m_textureLoaded);
00366 
00367       p->m_textureLoadedLock.unlock();
00368 
00369       std::map<int64_t, Tile*>::iterator iter;
00370 
00371       for (iter = tiles->begin(); iter != tiles->end(); ++iter)
00372       {
00373         Tile* tile = iter->second;
00374         int row, column;
00375         p->m_tileSet->GetLayer(tile->Layer())->GetTileIndex(p->m_currentPosition, row, column);
00376 
00377         if (abs(tile->Row() - row) > 6 || abs(tile->Column() - column) > 6)
00378         {
00379           p->m_renderRequestSetLock.lock();
00380           p->m_renderRequestSet.erase(tile->TileID());
00381           p->m_renderRequestSetLock.unlock();
00382 
00383           p->m_precacheRequestSetLock.lock();
00384           p->m_precacheRequestSet.erase(tile->TileID());
00385           p->m_precacheRequestSetLock.unlock();
00386 
00387           p->UnloadTexture(tile);
00388         }
00389       }
00390 
00391       delete tiles;
00392 
00393       sleep(2);
00394     }
00395   }
00396 }


multires_image
Author(s): Marc Alban
autogenerated on Thu Aug 24 2017 02:46:18