#include #include #include #include #include #include "layer_tiles.h" #include "tilesviewer.h" namespace QTVOSM{ /*! \brief in this constructor, some initial approach will be token. \fn layer_tiles::layer_tiles \param parent parent objects */ layer_tiles::layer_tiles(QObject *parent) : QObject(parent), m_nCacheExpireDays(30) { m_bActive = false; m_bVisible = false; m_pViewer = 0; //!1,Create thread object for download. download will be hold in different threads/ m_downloader = new urlDownloader(0); m_downloadThread = new QThread(this); m_downloader->moveToThread(m_downloadThread); m_downloadThread->start(); //!2,init basic cache and server site.if user does not give address, default set to "http://localhost/osm/%1/%2/%3.png" this->m_strLocalCache = "/OSMCache"; this->m_strServerURL = "http://%4.tile.openstreetmap.org/%1/%2/%3.png"; m_bconnected = false; m_propPage = 0; //!3, init the Drag position, for mouse drag and explore. this->m_nStartPosX = this->m_nStartPosY = -1; m_name = QString("%1").arg((quint64)this); } void layer_tiles::setServerUrl(QString url) { m_strServerURL = url; QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat); settings.setValue(QString("settings/ServerURL_%1").arg(get_name()),m_strServerURL); emit svrurlChanged(url); } void layer_tiles::setLocalCache(QString cache) { m_strLocalCache = cache; QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat); settings.setValue(QString("settings/LocalCache_%1").arg(get_name()), m_strLocalCache); emit cacheChanged(cache); } void layer_tiles::setCacheExpireDays(int nCacheExpireDays) { m_nCacheExpireDays = nCacheExpireDays; QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat); settings.setValue(QString("settings/CacheExpireDays_%1").arg(get_name()), m_nCacheExpireDays); emit cacheExpireChanged(m_nCacheExpireDays); } /*! \brief When the tileviewer enter its paint_event function, this callback will be called. \fn layer_tiles::cb_paintEvent \param pImage the In-mem image for paint . */ void layer_tiles::cb_paintEvent( QPainter * pPainter ) { if (!m_pViewer || m_bVisible==false) return; //!1,We should first calculate current windows' position, centerx,centery, in pixcel. double nCenter_X ,nCenter_Y; //!2,if the CV_PercentageToPixel returns true, painting will begin. if (true==m_pViewer->CV_Pct2World( m_pViewer->centerX(), m_pViewer->centerY(), &nCenter_X,&nCenter_Y)) { int sz_whole_idx = 1<level(); //!2.1 get current center tile idx, in tile count.(tile is 256x256) int nCenX = nCenter_X/256; int nCenY = nCenter_Y/256; //!2.2 calculate current left top tile idx int nCurrLeftX = floor((nCenter_X-m_pViewer->windowWidth()/2)/256.0); int nCurrTopY = floor((nCenter_Y-m_pViewer->windowHeight()/2)/256.0); //!2.3 calculate current right bottom idx int nCurrRightX = ceil((nCenter_X+m_pViewer->windowWidth()/2)/256.0); int nCurrBottomY = ceil((nCenter_Y+m_pViewer->windowHeight()/2)/256.0); //Get Aplha paraments const quint8 alphav = m_propPage->alphaValue(); QImage alphaMask(256,256,QImage::Format_Grayscale8); if (alphav!=255) alphaMask.fill(alphav); //!2.4 a repeat from tileindx left to right. for (int col = nCurrLeftX;col<=nCurrRightX;col++) { //!2.4.1 a repeat from tileindx top to bottom. for (int row = nCurrTopY;row<=nCurrBottomY;row++) { QImage image_source; int req_row = row, req_col = col; if (row<0 || row>=sz_whole_idx) continue; if (col>=sz_whole_idx) req_col = col % sz_whole_idx; if (col<0) req_col = (col + (1-col/sz_whole_idx)*sz_whole_idx) % sz_whole_idx; //!2.4.2 call getTileImage to query the image . if (true==this->getTileImage(m_pViewer->level(),req_col,req_row,image_source)) { //bitblt int nTileOffX = (col-nCenX)*256; int nTileOffY = (row-nCenY)*256; //0,0 lefttop offset int zero_offX = int(nCenter_X+0.5) % 256; int zero_offY = int(nCenter_Y+0.5) % 256; //bitblt cood int tar_x = m_pViewer->windowWidth()/2-zero_offX+nTileOffX; int tar_y = m_pViewer->windowHeight()/2-zero_offY+nTileOffY; //bitblt if (alphav!=255) image_source.setAlphaChannel(alphaMask); pPainter->drawImage(tar_x,tar_y,image_source); } } } } } layer_tiles::~layer_tiles() { m_downloadThread->quit(); m_downloadThread->wait(); m_downloader->deleteLater(); //! m_propPage is a child object of other widgets, //! it will be deleted automatically. //if (m_propPage) // m_propPage->deleteLater(); } bool layer_tiles::cb_mousePressEvent ( QMouseEvent * event ) { if (!m_pViewer || m_bVisible==false || m_bActive==false) return false; bool res = false; if (event->button()==Qt::LeftButton) { this->m_nStartPosX = event->pos().x(); this->m_nStartPosY = event->pos().y(); } return res; } bool layer_tiles::cb_mouseReleaseEvent ( QMouseEvent * event ) { if (!m_pViewer || m_bVisible==false || m_bActive==false) return false; bool res = false; if (event->button()==Qt::LeftButton) { int nOffsetX = event->pos().x()-this->m_nStartPosX; int nOffsetY = event->pos().y()-this->m_nStartPosY; if (!(nOffsetX ==0 && nOffsetY==0)) { m_pViewer->DragView(nOffsetX,nOffsetY); this->m_nStartPosX = this->m_nStartPosY = -1; res = true; } } return res; } bool layer_tiles::cb_mouseDoubleClickEvent( QMouseEvent * event ) { if (!m_pViewer || m_bVisible==false || m_bActive==false) return false; bool res = false; if (event->button()==Qt::LeftButton) { int nOffsetX = event->pos().x()-m_pViewer->windowWidth()/2; int nOffsetY = event->pos().y()-m_pViewer->windowHeight()/2; m_pViewer->DragView(-nOffsetX,-nOffsetY); res = true; } return res; } bool layer_tiles::cb_mouseMoveEvent(QMouseEvent * /*event*/) { return false; } bool layer_tiles::cb_wheelEvent ( QWheelEvent * event ) { if (!m_pViewer || m_bVisible==false || m_bActive==false) return false; int nLevel = m_pViewer->level(); if (event->delta()<0) { nLevel++; if (nLevel>20) nLevel=20; } else if (event->delta()>0) { nLevel--; if (nLevel<0) nLevel=0; } if (nLevel != m_pViewer->level()) m_pViewer->setLevel(nLevel); return true; } void layer_tiles::cb_resizeEvent ( QResizeEvent * /*event*/) { if (!m_pViewer || m_bVisible==false) return; } layer_interface * layer_tiles::load_initial_plugin(QString /*strSLibPath*/,viewer_interface * viewer) { m_pViewer = dynamic_cast(viewer); if (!m_pViewer) return 0; connect(m_downloader,SIGNAL(evt_all_taskFinished()),this,SLOT(updateViewer())); //Get Cache Address QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat); m_strServerURL = settings.value(QString("settings/ServerURL_%1").arg(m_name),"http://%4.tile.openstreetmap.org/%1/%2/%3.png").toString(); m_strLocalCache = settings.value(QString("settings/LocalCache_%1").arg(m_name), QCoreApplication::applicationDirPath() +"/OSMCache").toString(); m_nCacheExpireDays = settings.value(QString("settings/CacheExpireDays_%1").arg(m_name), 30).toInt(); return this; } void layer_tiles::updateViewer() { if (!m_pViewer) return ; m_pViewer->UpdateWindow(); } QWidget * layer_tiles::load_prop_window() { if (!m_propPage) { m_propPage = new layer_tiles_page(this,0); connect (m_downloader,&urlDownloader::evt_message,m_propPage,&layer_tiles_page::slot_message,Qt::QueuedConnection); } return m_propPage; } void layer_tiles::cb_levelChanged(int /*nLevel*/) { if (!m_pViewer || m_bVisible==false) return; } /*! \brief Get a single tile PNG from web service. return false if error occurred. \fn layer_tiles::getTileImage \param nLevel current level \param nX current col \param nY current row \param image the image object to hold the result data \return bool succeed when ok. */ bool layer_tiles::getTileImage(int nLevel,int nX,int nY,QImage & image) { if (!m_pViewer || m_bVisible==false) return true; QString strVal = m_strLocalCache; strVal += '/'; strVal += m_name; strVal += '/'; strVal += QString::number(nLevel,10); strVal += '/'; strVal += QString::number(nX,10); strVal += '/'; strVal += QString::number(nY,10); strVal += ".png"; bool res = true; bool needReg = false; if (res) { QByteArray array_out; QFile file(strVal); QFileInfo info(strVal); if (file.open(QIODevice::ReadOnly)==true) { array_out = file.readAll(); image = QImage::fromData(array_out); if (image.isNull()==true) res = false, needReg = true; else if (m_nCacheExpireDays > 0 && info.lastModified().secsTo(QDateTime::currentDateTime()) > this->m_nCacheExpireDays * 3600 * 24 ) needReg = true; } else res = false, needReg = true; } if (needReg) RegImages(nX,nY,nLevel); return res; } void layer_tiles::UpdateLayer() { m_pViewer->UpdateWindow(); } /*! \brief connectToTilesServer will set connect flag to true. notice that a connected tile means that it will try to doanload new tile images from remote server, with no swearing for succeed doanload. ther will be one event fired in this method. \fn layer_tiles::connectToTilesServer \param bconnected return current status */ void layer_tiles::connectToTilesServer(bool bconnected) { this->m_bconnected = bconnected; if (!m_pViewer) return; m_pViewer->UpdateWindow(); emit connected(m_bconnected); //! 1. source=MAIN_MAP, destin = ALL, msg = CONNECTION if (this->is_active()) { QMap map_evt; map_evt["source"] = get_name(); map_evt["destin"] = "ALL"; map_evt["name"] = "CONNECTION"; map_evt["status"] =m_bconnected?"CONNECTED":"CLOSED"; m_pViewer->post_event(map_evt); } QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat); settings.setValue(QString("settings/nAutoDownload_%1").arg(get_name()),bconnected?-1:0); } /*! \brief RegImages will download images from tile address. \fn layer_tiles::RegImages \param nX col (x) tile id og this level nLevel \param nY row (y) tile id og this level nLevel \param nLevel current level. In osm, nlevel often take 0~20 \return bool succeeded. */ bool layer_tiles::RegImages(int nX, int nY,int nLevel) { if (!m_pViewer || m_bVisible==false) return true; if (m_bconnected==false) return true; QString LFix; QString strSourceUrl, strDestinDir, strFileName; LFix += '/'; LFix += QString::number(nLevel,10); LFix += '/'; LFix += QString::number(nX,10); strDestinDir = m_strLocalCache + "/" + m_name + "/" + LFix; LFix += '/'; LFix += QString::number(nY,10); LFix += ".png"; strFileName = QString::number(nY,10); strFileName += ".png"; QChar mirr[3] = {QChar('a'),QChar('b'),QChar('c')}; if (m_strServerURL.contains("%4")) strSourceUrl = m_strServerURL.arg(nLevel).arg(nX).arg(nY).arg(mirr[nY%3]); else strSourceUrl = m_strServerURL.arg(nLevel).arg(nX).arg(nY); this->m_downloader->addDownloadUrl(strSourceUrl,strDestinDir,strFileName); return true; } }