#include "tilesviewer.h" #include #include #include #include #include #include #include "layer_interface.h" namespace QTVOSM{ tilesviewer::tilesviewer(QWidget *parent) : QWidget(parent) { QTVOSM_DEBUG("The tilesviewer class is constructing."); this->m_dCenterX = this->m_dCenterY = 0; this->m_nLevel = 0; this->setMouseTracking(true); connect(this,&tilesviewer::_inside_do_next_evts,this,&tilesviewer::_do_next_evts,Qt::QueuedConnection); QTVOSM_DEBUG("The tilesviewer class constructed."); } tilesviewer::~tilesviewer() { //Call layers to draw images QVector slayers = layers(); foreach (layer_interface * pItem, slayers) removeLayer(pItem); } bool tilesviewer::addLayer(layer_interface * ba) { if (m_setLayers.contains(ba)==true) return false; m_listLayers.push_back(ba); m_setLayers.insert(ba); return true; } void tilesviewer::removeLayer(layer_interface * ba ) { if (m_setLayers.contains(ba)==false) return; m_listLayers.removeOne(ba); m_setLayers.remove(ba); } layer_interface * tilesviewer::layer(const QString & name) { layer_interface * res = 0; foreach (layer_interface * pItem, m_listLayers) { if (name ==pItem->get_name()) { res = pItem; break; } } return res; } bool tilesviewer::adjust_layers(layer_interface * la ) { QVector vec_layers = layers(); bool activeb = la->is_active(); bool tarExclusive = false; for (int i=0;iis_exclusive(); } if (tarExclusive && activeb) { for (int i=0;iis_exclusive()==true) vec_layers[i]->set_active(false); } } return true; } QVector tilesviewer::layers() { QVector vec_layers; //Call layers to draw images foreach (layer_interface * pItem, m_listLayers) vec_layers.push_back(pItem); return vec_layers; } QVector tilesviewer::layerNames() { QVector vec_layers; //Call layers to draw images foreach (layer_interface * pItem, m_listLayers) vec_layers.push_back(pItem->get_name()); return vec_layers; } QVector tilesviewer::layerVisibilities() { QVector vec_layers; //Call layers to draw images foreach (layer_interface * pItem, m_listLayers) vec_layers.push_back(pItem->is_visible()); return vec_layers; } QVector tilesviewer::layerActivities() { QVector vec_layers; //Call layers to draw images foreach (layer_interface * pItem, m_listLayers) vec_layers.push_back(pItem->is_active()); return vec_layers; } void tilesviewer::moveLayerUp(layer_interface * ly) { int n = m_listLayers.indexOf(ly); if (n>0 && nisEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "ALL"; map_evt["name"] = "LAYER_MOVED_UP"; map_evt["layerName"] = ly->get_name(); post_event(map_evt); } } } void tilesviewer::moveLayerDown(layer_interface * ly) { int n = m_listLayers.indexOf(ly); if (n>=0 && n + 1 < m_listLayers.size()) { m_listLayers.removeAt(n); m_listLayers.insert(n+1,ly); //! 1. source=MAIN_MAP, destin = ALL, msg = LAYER_MOVED_DOWN if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "ALL"; map_evt["name"] = "LAYER_MOVED_DOWN"; map_evt["layerName"] = ly->get_name(); post_event(map_evt); } } } void tilesviewer::moveLayerTop(layer_interface * ly) { int n = m_listLayers.indexOf(ly); if (n>0 && nisEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "ALL"; map_evt["name"] = "LAYER_MOVED_TOP"; map_evt["layerName"] = ly->get_name(); post_event(map_evt); } } } void tilesviewer::moveLayerBottom(layer_interface *ly) { int n = m_listLayers.indexOf(ly); if (n>=0 && n+1isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "ALL"; map_evt["name"] = "LAYER_MOVED_BOTTOM"; map_evt["layerName"] = ly->get_name(); post_event(map_evt); } } } void tilesviewer::updateLayerGridView() { emit cmd_update_layer_box(); } void tilesviewer::paintEvent( QPaintEvent * /*event*/ ) { QPainter painter(this); QBrush br_back(QColor(192,192,192),Qt::Dense5Pattern); painter.setBackground(br_back); painter.eraseRect(this->rect()); //Call layers to draw images foreach (layer_interface * pItem, m_listLayers) pItem->cb_paintEvent(&painter); //Draw center mark QPen pen(Qt::DotLine); pen.setColor(QColor(0,0,255,128)); painter.setPen(pen); painter.drawLine( width()/2+.5,height()/2+.5-32, width()/2+.5,height()/2+.5+32 ); painter.drawLine( width()/2+.5-32,height()/2+.5, width()/2+.5+32,height()/2+.5 ); } //public slots for resolution changed events void tilesviewer::setLevel(int n) { bool needUpdate = m_nLevel==n?false:true; if (needUpdate==false) return; this->m_nLevel = n; //Call layers foreach (layer_interface * pItem, m_listLayers) pItem->cb_levelChanged(n); update(); emit evt_level_changed(m_nLevel); //! 1. source=MAIN_MAP, destin = ALL, msg = LEVEL_CHANGED if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "ALL"; map_evt["name"] = "LEVEL_CHANGED"; map_evt["nLevel"] = n; post_event(map_evt); } } //public slots for resolution changed events void tilesviewer::setBrLevel(int n) { this->m_nLevel = n - 6; if (m_nLevel < 0) m_nLevel = 0; else { //Call layers foreach (layer_interface * pItem, m_listLayers) pItem->cb_levelChanged(n); update(); } } void tilesviewer::UpdateWindow() { update(); } void tilesviewer::mousePressEvent ( QMouseEvent * event ) { //Call layers int needUpdate = 0; foreach (layer_interface * pItem, m_listLayers) needUpdate += pItem->cb_mousePressEvent(event)==true?1:0; if (needUpdate>0) this->update(); //! 1. source=MAIN_MAP, destin = ALL, msg = MOUSE_LBUTTON_DOWN //! 2. source=MAIN_MAP, destin = ALL, msg = MOUSE_RBUTTON_DOWN //! 3. source=MAIN_MAP, destin = ALL, msg = MOUSE_MBUTTON_DOWN //! 4. source=MAIN_MAP, destin = ALL, msg = MOUSE_BUTTON_DOWN if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; if (event->buttons() & Qt::LeftButton) map_evt["name"] = "MOUSE_LBUTTON_DOWN"; else if (event->buttons() & Qt::RightButton) map_evt["name"] = "MOUSE_RBUTTON_DOWN"; else if (event->buttons() & Qt::MidButton) map_evt["name"] = "MOUSE_MBUTTON_DOWN"; else map_evt["name"] = "MOUSE_BUTTON_DOWN"; double tlat, tlon; CV_DP2LLA(event->pos().x(),event->pos().y(),&tlat,&tlon); map_evt["lat"] = tlat; map_evt["lon"] = tlon; map_evt["nLevel"] = m_nLevel; post_event(map_evt); //test coord cnt /**/ if (false) { QString strMsg; int dpx = event->pos().x(), dpy = event->pos().y(); strMsg += QString("DP(%1,%2)").arg(dpx).arg(dpy); double wdx,wdy; CV_DP2World(dpx,dpy,&wdx,&wdy); strMsg += QString("->WD(%1,%2)").arg(wdx).arg(wdy); CV_World2DP(wdx,wdy,&dpx,&dpy); strMsg += QString("->DP(%1,%2)").arg(dpx).arg(dpy); double lat,lon; CV_World2LLA(wdx,wdy,&lat,&lon); strMsg += QString("->LLA(%1,%2)").arg(lat).arg(lon); CV_LLA2World(lat,lon,&wdx,&wdy); strMsg += QString("->WD(%1,%2)").arg(wdx).arg(wdy); CV_DP2LLA(dpx,dpy,&lat,&lon); strMsg += QString("->LLA(%1,%2)").arg(lat).arg(lon); CV_LLA2DP(lat,lon,&dpx,&dpy); strMsg += QString("->DP(%1,%2)").arg(dpx).arg(dpy); double mkx,mky; CV_LLA2MK(lat,lon,&mkx,&mky); strMsg += QString("->MK(%1,%2)").arg(mkx).arg(mky); CV_MK2LLA(mkx,mky,&lat,&lon); strMsg += QString("->LLA(%1,%2)").arg(lat).arg(lon); CV_MK2World(mkx,mky,&wdx,&wdy); strMsg += QString("->WD(%1,%2)").arg(wdx).arg(wdy); CV_World2MK(wdx,wdy,&mkx,&mky); strMsg += QString("->MK(%1,%2)").arg(mkx).arg(mky); double pctx,pcty; CV_World2Pct(wdx,wdy,&pctx,&pcty); strMsg += QString("->PCT(%1,%2)").arg(pctx).arg(pcty); CV_Pct2World(pctx,pcty,&wdx,&wdy); strMsg += QString("->WD(%1,%2)").arg(wdx).arg(wdy); qDebug()<cb_resizeEvent(event); update(); //! 1. source=MAIN_MAP, destin = ALL, msg = MAP_RESIZED if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; map_evt["name"] = "MAP_RESIZED"; map_evt["width"] = event->size().width(); map_evt["height"] = event->size().height(); post_event(map_evt); } QWidget::resizeEvent(event); } void tilesviewer::mouseReleaseEvent ( QMouseEvent * event ) { //Call layers int needUpdate = 0; foreach (layer_interface * pItem, m_listLayers) needUpdate += pItem->cb_mouseReleaseEvent(event)==true?1:0; if (needUpdate>0) this->update(); //! 1. source=MAIN_MAP, destin = ALL, msg = MOUSE_LBUTTON_UP //! 2. source=MAIN_MAP, destin = ALL, msg = MOUSE_RBUTTON_UP //! 3. source=MAIN_MAP, destin = ALL, msg = MOUSE_MBUTTON_UP //! 4. source=MAIN_MAP, destin = ALL, msg = MOUSE_BUTTON_UP if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; if (event->buttons() & Qt::LeftButton) map_evt["name"] = "MOUSE_LBUTTON_UP"; else if (event->buttons() & Qt::RightButton) map_evt["name"] = "MOUSE_RBUTTON_UP"; else if (event->buttons() & Qt::MidButton) map_evt["name"] = "MOUSE_MBUTTON_UP"; else map_evt["name"] = "MOUSE_BUTTON_UP"; double tlat, tlon; CV_DP2LLA(event->pos().x(),event->pos().y(),&tlat,&tlon); map_evt["lat"] = tlat; map_evt["lon"] = tlon; map_evt["nLevel"] = m_nLevel; post_event(map_evt); } QWidget::mouseReleaseEvent(event); } void tilesviewer::mouseDoubleClickEvent(QMouseEvent * event) { //Call layers int needUpdate = false; foreach (layer_interface * pItem, m_listLayers) needUpdate += pItem->cb_mouseDoubleClickEvent(event)==true?1:0; if (needUpdate>0) this->update(); //! 1. source=MAIN_MAP, destin = ALL, msg = MOUSE_LBUTTON_DBLCLK //! 2. source=MAIN_MAP, destin = ALL, msg = MOUSE_RBUTTON_BLCLK //! 3. source=MAIN_MAP, destin = ALL, msg = MOUSE_MBUTTON_BLCLK //! 4. source=MAIN_MAP, destin = ALL, msg = MOUSE_BUTTON_BLCLK if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; if (event->buttons() & Qt::LeftButton) map_evt["name"] = "MOUSE_LBUTTON_DBLCLK"; else if (event->buttons() & Qt::RightButton) map_evt["name"] = "MOUSE_RBUTTON_BLCLK"; else if (event->buttons() & Qt::MidButton) map_evt["name"] = "MOUSE_MBUTTON_BLCLK"; else map_evt["name"] = "MOUSE_BUTTON_BLCLK"; double tlat, tlon; CV_DP2LLA(event->pos().x(),event->pos().y(),&tlat,&tlon); map_evt["lat"] = tlat; map_evt["lon"] = tlon; map_evt["nLevel"] = m_nLevel; post_event(map_evt); } QWidget::mouseDoubleClickEvent(event); } void tilesviewer::mouseMoveEvent(QMouseEvent * event) { //Call layers int needUpdate = 0; foreach (layer_interface * pItem, m_listLayers) needUpdate += pItem->cb_mouseMoveEvent(event)==true?1:0; if (needUpdate) this->update(); double lat,lon; CV_DP2LLA(event->x(),event->y(),&lat,&lon); //! 1. source=MAIN_MAP, destin = ALL, msg = MOUSE_MOVE if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; map_evt["name"] = "MOUSE_MOVE"; double tlat, tlon; CV_DP2LLA(event->pos().x(),event->pos().y(),&tlat,&tlon); map_evt["lat"] = tlat; map_evt["lon"] = tlon; map_evt["nLevel"] = m_nLevel; map_evt["mask"] = (quint32)event->buttons(); post_event(map_evt); } QWidget::mouseMoveEvent(event); } void tilesviewer::wheelEvent ( QWheelEvent * event ) { //Call layers int needUpdate = 0; foreach (layer_interface * pItem, m_listLayers) needUpdate += pItem->cb_wheelEvent(event); if (needUpdate) this->update(); //! 1. source=MAIN_MAP, destin = ALL, msg = MOUSE_WHELL if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; map_evt["name"] = "MOUSE_WHELL"; double tlat, tlon; CV_DP2LLA(event->pos().x(),event->pos().y(),&tlat,&tlon); map_evt["lat"] = tlat; map_evt["lon"] = tlon; map_evt["nLevel"] = m_nLevel; map_evt["pDeltaX"] = event->pixelDelta().x(); map_evt["pDeltaY"] = event->pixelDelta().y(); map_evt["aDeltaX"] = event->angleDelta().x(); map_evt["aDeltaY"] = event->angleDelta().y(); post_event(map_evt); } QWidget::wheelEvent(event); } void tilesviewer::DragView(int nOffsetX,int nOffsetY) { if (nOffsetX==0 && nOffsetY == 0) return; int sz_whole_idx = 1<m_dCenterX -= dx; this->m_dCenterY -= dy; while (m_dCenterX<-0.5) m_dCenterX += 1; while (m_dCenterX>0.5) m_dCenterX -= 1; if (m_dCenterY<-0.5) m_dCenterY = -0.5; if (m_dCenterY>0.5) m_dCenterY = 0.5; double lat,lon; CV_DP2LLA(width()/2,height()/2,&lat,&lon); emit evt_center_changed(lat,lon); //! 1. source=MAIN_MAP, destin = ALL, msg = CENTER_CHANGED if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; map_evt["name"] = "CENTER_CHANGED"; map_evt["lat"] = lat; map_evt["lon"] = lon; map_evt["nLevel"] = m_nLevel; post_event(map_evt); } } //set center LLA void tilesviewer::setCenterLLA(double lat, double lon) { //To Mercator Projection double dMx = cProjectionMercator(lat,lon).ToMercator().m_x; double dMy = cProjectionMercator(lat,lon).ToMercator().m_y; //Calculat the percentage pos (-0.5-0.5) of the Mercator point double dCtX = dMx/(cProjectionMercator::pi*cProjectionMercator::R*2); double dCtY = -dMy/(cProjectionMercator::pi*cProjectionMercator::R*2); while (dCtX<-0.5) dCtX += 1; while (dCtX>0.5) dCtX -= 1; if (dCtY<-0.5) dCtY = -0.5; if (dCtY>0.5) dCtY = 0.5; if (m_dCenterX != dCtX || m_dCenterY != dCtY) { this->m_dCenterX = dCtX; this->m_dCenterY = dCtY; //Call layers update(); emit evt_center_changed(lat,lon); //! 1. source=MAIN_MAP, destin = ALL, msg = CENTER_CHANGED if (this->isEnabled()) { QMap map_evt; map_evt["source"] = "MAIN_MAP"; map_evt["destin"] = "OUTER"; map_evt["name"] = "CENTER_CHANGED"; centerLLA(&lat,&lon); map_evt["lat"] = lat; map_evt["lon"] = lon; map_evt["nLevel"] = m_nLevel; post_event(map_evt); } } } //set center LLA, not emit centerChanged void tilesviewer::setBrCenterLLA(double lat, double lon) { //To Mercator Projection double dMx = cProjectionMercator(lat,lon).ToMercator().m_x; double dMy = cProjectionMercator(lat,lon).ToMercator().m_y; //Calculat the percentage pos (-0.5-0.5) of the Mercator point double dCtX = dMx/(cProjectionMercator::pi*cProjectionMercator::R*2); double dCtY = -dMy/(cProjectionMercator::pi*cProjectionMercator::R*2); while (dCtX<-0.5) dCtX += 1; while (dCtX>0.5) dCtX -= 1; if (dCtY<-0.5) dCtY = -0.5; if (dCtY>0.5) dCtY = 0.5; if (m_dCenterX != dCtX || m_dCenterY != dCtY) { this->m_dCenterX = dCtX; this->m_dCenterY = dCtY; update(); } } /*! \brief convert LLA to Device Points. Device Points is according to current viewport, point(0,0) stay at the top-left, point (width-1,height-1) in bottom-right This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_LLA2DP \param lat latitude in degree \param lon longitude in degree \param pX the pointer to hold X cood of DP \param pY the pointer to hold Y cood of DP \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_LLA2DP(double lat,double lon,qint32 * pX,qint32 *pY) { if (!pX||!pY) return false; //!1.To Mercator Projection double dMx = cProjectionMercator(lat,lon).ToMercator().m_x; double dMy = cProjectionMercator(lat,lon).ToMercator().m_y; //!2.Calculat the percentage pos (-0.5-0.5) of the Mercator point double dperx = dMx/(cProjectionMercator::pi*cProjectionMercator::R*2); double dpery = -dMy/(cProjectionMercator::pi*cProjectionMercator::R*2); double dCurrImgSize = pow(2.0,m_nLevel)*256; //!3.Calculat the World pixel coordinats double dTarX = dperx * dCurrImgSize + dCurrImgSize/2; double dTarY = dpery * dCurrImgSize + dCurrImgSize/2; //!4.Calculat the World pixel coordinats of current view-center point double dCurrX = dCurrImgSize*m_dCenterX+dCurrImgSize/2; double dCurrY = dCurrImgSize*m_dCenterY+dCurrImgSize/2; //!5.Calculat the World pixel coordinats of current view-left-top point double nOffsetLT_x = (dCurrX-width()/2.0); double nOffsetLT_y = (dCurrY-height()/2.0); //!6.Turn world coord to DP coord *pX = dTarX - nOffsetLT_x+.5; *pY = dTarY - nOffsetLT_y+.5; return true; } /*! \brief convert Device Points to LLA. Device Points is according to current viewport, point(0,0) stay at the top-left, point (width-1,height-1) in bottom-right This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_DP2LLA \param X X cood of DP \param Y Y cood of DP \param plat the pointer to hold lat in degree \param plon the pointer to hold lon in degree \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_DP2LLA(qint32 X,qint32 Y,double * plat,double * plon) { if (!plat||!plon) return false; //!1.Current World Pixel Size, connected to nLevel double dCurrImgSize = pow(2.0,m_nLevel)*256; //!2.current DP according to center double dx = X-(width()/2.0); double dy = Y-(height()/2.0); //!3.Percentage -0.5 ~ 0.5 coord double dImgX = dx/dCurrImgSize+m_dCenterX; double dImgY = dy/dCurrImgSize+m_dCenterY; //!4.to Mercator double Mercator_x = cProjectionMercator::pi*cProjectionMercator::R*2*dImgX; double Mercator_y = -cProjectionMercator::pi*cProjectionMercator::R*2*dImgY; *plat = cProjectionMercator(Mercator_y,Mercator_x).ToLatLon().m_lat; *plon = cProjectionMercator(Mercator_y,Mercator_x).ToLatLon().m_lon; return true; } /*! \brief convert Mercator to LLA.Mercator coord is a projection with ID 900913. this method is NOT Level releated. \fn tilesviewer::CV_MK2LLA \param mx Mercator x coord in meters \param my Mercator y coord in meters \param plat the pointer to hold lat in degree \param plon the pointer to hold lon in degree \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_MK2LLA(double mx, double my, double * plat, double * plon) { if (!plat||!plon) return false; *plat = cProjectionMercator(my,mx).ToLatLon().m_lat; *plon = cProjectionMercator(my,mx).ToLatLon().m_lon; return true; } /*! \brief convert LLA to Mercator .Mercator coord is a projection with ID 900913. this method is NOT Level releated. \fn tilesviewer::CV_LLA2MK \param lat latitude in degree \param lon longitude in degree \param pmx the pointer to hold Mercator x coord in meters \param pmy the pointer to hold Mercator y coord in meters \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_LLA2MK(double lat,double lon, double * pmx, double * pmy) { if (!pmx||!pmy) return false; //To Mercator Projection *pmx = cProjectionMercator(lat,lon).ToMercator().m_x; *pmy = cProjectionMercator(lat,lon).ToMercator().m_y; return true; } /*! \brief convert Mercator to World. World Points is according to current level, point(0,0) stay at the left-top, point (SZ,SZ) in bottom-right SZ = pow(2.0,m_nLevel)*256, m_nLevel between 0 and 18 This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_MK2World \param mx Mercator x in meters \param my Mercator y in meters \param px pointer to hold world x in pixel \param py pointer to hold world y in pixel \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_MK2World(double mx, double my, double * px, double * py) { if (!px||!py) return false; //!1.Calculat the percentage pos (-0.5-0.5) of the Mercator point double dperx = mx/(cProjectionMercator::pi*cProjectionMercator::R*2); double dpery = -my/(cProjectionMercator::pi*cProjectionMercator::R*2); double dCurrImgSize = pow(2.0,m_nLevel)*256; //!2.Calculat the World pixel coordinats *px = dperx * dCurrImgSize + dCurrImgSize/2; *py = dpery * dCurrImgSize + dCurrImgSize/2; return true; } /*! \brief convert World to Mercator. World Points is according to current level, point(0,0) stay at the left-top, point (SZ,SZ) in bottom-right SZ = pow(2.0,m_nLevel)*256, m_nLevel between 0 and 18 This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_World2MK \param x world x in pixel \param y world y in pixel \param pmx pointer to hold Mercator x in meters \param pmy pointer to hold Mercator y in meters \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_World2MK(double x,double y, double * pmx, double * pmy) { if (!pmx||!pmy) return false; //!1.Current World Pixel Size, connected to nLevel double dCurrImgSize = pow(2.0,m_nLevel)*256; //!2.Percentage -0.5 ~ 0.5 coord double dImgX = x/dCurrImgSize - .5; double dImgY = y/dCurrImgSize - .5; //!3.to Mercator *pmx = cProjectionMercator::pi*cProjectionMercator::R*2*dImgX; *pmy = -cProjectionMercator::pi*cProjectionMercator::R*2*dImgY; return true; } /*! \brief convert LLA to world. World Points is according to current level, point(0,0) stay at the left-top, point (SZ,SZ) in bottom-right SZ = pow(2.0,m_nLevel)*256, m_nLevel between 0 and 18 This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_LLA2World \param lat the latitude in meter \param lon the longitude in meter \param px pointer to hold world x in pixel \param py pointer to hold world y in pixel \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_LLA2World(double lat, double lon, double * px, double * py) { if (!px||!py) return false; //!1.To Mercator Projection double dMx = cProjectionMercator(lat,lon).ToMercator().m_x; double dMy = cProjectionMercator(lat,lon).ToMercator().m_y; //!2.Calculat the percentage pos (-0.5-0.5) of the Mercator point double dperx = dMx/(cProjectionMercator::pi*cProjectionMercator::R*2); double dpery = -dMy/(cProjectionMercator::pi*cProjectionMercator::R*2); double dCurrImgSize = pow(2.0,m_nLevel)*256; //!3.Calculat the World pixel coordinats *px = dperx * dCurrImgSize + dCurrImgSize/2; *py = dpery * dCurrImgSize + dCurrImgSize/2; return true; } /*! \brief convert world to LLA. World Points is according to current level, point(0,0) stay at the left-top, point (SZ,SZ) in bottom-right SZ = pow(2.0,m_nLevel)*256, m_nLevel between 0 and 18 This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_World2LLA \param x world x coord in pixels \param y world y coord in pixels \param plat pointer to hold latitude in degree \param plon pointer to hold longitude in degree \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_World2LLA(double x,double y, double * plat, double * plon) { if (!plat||!plon) return false; //!1.Current World Pixel Size, connected to nLevel double dCurrImgSize = pow(2.0,m_nLevel)*256; //!2.Percentage -0.5 ~ 0.5 coord double dImgX = x/dCurrImgSize - .5; double dImgY = y/dCurrImgSize - .5; //!3.to Mercator double mkx = cProjectionMercator::pi*cProjectionMercator::R*2*dImgX; double mky = -cProjectionMercator::pi*cProjectionMercator::R*2*dImgY; //!4.to LLA *plat = cProjectionMercator(mky,mkx).ToLatLon().m_lat; *plon = cProjectionMercator(mky,mkx).ToLatLon().m_lon; return true; } /*! \brief convert Device Points to World. Device Points is according to current viewport, point(0,0) stay at the top-left, point (width-1,height-1) in bottom-right. World Points is according to current level, point(0,0) stay at the left-top, point (SZ,SZ) in bottom-right, SZ = pow(2.0,m_nLevel)*256, m_nLevel between 0 and 18 This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_DP2World \param dX Device point X in pixel \param dY Device point Y in pixel \param px pointer to hold world x in pixel \param py pointer to hold world y in pixel \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_DP2World(qint32 dX, qint32 dY, double * px, double * py) { if (!px||!py) return false; //!1.Current World Pixel Size, connected to nLevel double dCurrImgSize = pow(2.0,m_nLevel)*256; //!2.current DP according to center double dx = dX-(width()/2.0); double dy = dY-(height()/2.0); //!3.Percentage -0.5 ~ 0.5 coord double dImgX = dx/dCurrImgSize+m_dCenterX; double dImgY = dy/dCurrImgSize+m_dCenterY; //!4.Calculat the World pixel coordinats *px = dImgX * dCurrImgSize + dCurrImgSize/2; *py = dImgY * dCurrImgSize + dCurrImgSize/2; return true; } /*! \brief convert World to Device Points. Device Points is according to current viewport, point(0,0) stay at the top-left, point (width-1,height-1) in bottom-right. World Points is according to current level, point(0,0) stay at the left-top, point (SZ,SZ) in bottom-right, SZ = pow(2.0,m_nLevel)*256, m_nLevel between 0 and 18 This approach is devided into several steps, and it is LEVEL RELATED! \fn tilesviewer::CV_World2DP \param x world x in pixel \param y world y in pixel \param pdX pointer to hold Device point X in pixel \param pdY pointer to hold Device point Y in pixel \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_World2DP(double x,double y, qint32 * pdX, qint32 * pdY) { if (!pdX||!pdY) return false; //!1.Current World Pixel Size, connected to nLevel double dCurrImgSize = pow(2.0,m_nLevel)*256; //!2.Calculat the World pixel coordinats of current view-center point double dCurrX = dCurrImgSize*m_dCenterX+dCurrImgSize/2; double dCurrY = dCurrImgSize*m_dCenterY+dCurrImgSize/2; //!3.Calculat the World pixel coordinats of current view-left-top point double nOffsetLT_x = (dCurrX-width()/2.0); double nOffsetLT_y = (dCurrY-height()/2.0); //!4.Turn world coord to DP coord *pdX = x - nOffsetLT_x+.5; *pdY = y - nOffsetLT_y+.5; return true; } /*! \brief convert percentage coord to world. World Points is according to current level, point(0,0) stay at the left-top, point (SZ,SZ) in bottom-right, SZ = pow(2.0,m_nLevel)*256, m_nLevel between 0 and 18. Percentage coord is a level-unretated coord, take a range -0.5~0.5, the world center in 0,0, -0.5.-0.5 at top-left, 0.5,0.5 at bottom-right This approach is LEVEL RELATED! \fn tilesviewer::CV_Pct2World \param px percentage coord x \param py percentage coord y \param nx pointer to hold world x in pixel \param ny pointer to hold world y in pixel \return bool will always return true except for the pointer is NULL */ bool tilesviewer::CV_Pct2World(double px,double py,double * nx,double * ny) { if (!nx || !ny) return false; //first, determine whole map size in current level int sz_whole_idx = 1<grab(); return m.save(strFm); } void tilesviewer::_do_next_evts() { QMap event; bool empty = true; m_mutex_events.lock(); if ( m_list_pendingEvts.empty()==false) { event = m_list_pendingEvts.first(); m_list_pendingEvts.pop_front(); empty = (m_list_pendingEvts.empty()); } m_mutex_events.unlock(); int st = 0; QString strDestin = event["destin"].toString(); /*! * In event/Message system, Send or Post messages between different parts are enabled.the messages will be sent/posted from source to destin. * The destin property setted to OUTER Message means this message/event is sent for OCX containers outer this instance. * The destin property setted to MAIN_MAP Message means this message/event is sent for this MAP instance. * The destin property setted to ALL Message means this message/event is sent for ALL possible recievers. * Other destin will be treated as plugin DLL names ret by get_name() */ if (strDestin!=QString("OUTER") && strDestin!=QString("MAIN_MAP")) { int needUpdate = 0; foreach (layer_interface * pItem, m_listLayers) { if (pItem->get_name()==strDestin || strDestin==QString("ALL")) { needUpdate += pItem->cb_event(event)==true?1:0; ++st; } } if (needUpdate>0) this->update(); } /*! There are 3 ways dealing with messages. * 1.cb_event callback mechanism is designed for DLL plugin system, that is Public for Qtvplugin extentions, and only take effect when destin=ALL, get_name() * 2.A C++11 functinal mechanism called "send-listen-recievt" is built for OCX internal usage, and only take effect when destin=ALL, OUTER * 3.All messages with destin setted to "MAINMAP" will be dealing in main map directly. */ if (strDestin==QString("OUTER") || strDestin==QString("ALL")) { m_mutex_listeners.lock(); foreach (auto p, m_map_listeners) p(event); st += m_map_listeners.size(); if (strDestin==QString("OUTER")) ++st; m_mutex_listeners.unlock(); } //This message/event is for this MAP itself else if (strDestin==QString("MAIN_MAP")) { ++st; } if (st==0) { qWarning()<<"EVENT/MESSAGE "<get_name() + ";"; qWarning()<<"Valid recievers:ALL;OUTER;MAIN_MAP;"< event) { if (event.contains("destin")==false ||event.contains("source")==false) return false; bool needEmit = false; m_mutex_events.lock(); m_list_pendingEvts.append(event); if (m_list_pendingEvts.size()==1) needEmit = true; m_mutex_events.unlock(); if (needEmit) emit _inside_do_next_evts(); return true; } bool tilesviewer::send_event(const QMap event) { if (event.contains("destin")==false ||event.contains("source")==false) return false; QString strDestin = event["destin"].toString(); int st = 0; /*! * In event/Message system, Send or Post messages between different parts are enabled.The messages will be sent/posted from source to destin. * The destin property setted to OUTER Message means this message/event is sent for OCX containers outer this instance. * The destin property setted to MAIN_MAP Message means this message/event is sent for this MAP instance. * The destin property setted to ALL Message means this message/event is sent for ALL possible recievers. * Other destin will be treated as plugin DLL names ret by get_name() */ if (strDestin!=QString("OUTER") && strDestin!=QString("MAIN_MAP")) { int needUpdate = 0; foreach (layer_interface * pItem, m_listLayers) { if (pItem->get_name()==strDestin||strDestin==QString("ALL")) { ++st; needUpdate += pItem->cb_event(event)==true?1:0; } } if (needUpdate>0) this->update(); } /*! There are 3 ways dealing with messages. * 1.cb_event callback mechanism is designed for DLL plugin system, that is Public for Qtvplugin extentions, and only take effect when destin=ALL, get_name() * 2.A C++11 functinal mechanism called "send-listen-recievt" is built for OCX internal usage, and only take effect when destin=ALL, OUTER * 3.All messages with destin setted to "MAINMAP" will be dealing in main map directly. */ if (strDestin==QString("OUTER") || strDestin==QString("ALL")) { foreach (auto p, m_map_listeners) p(event); st += m_map_listeners.size(); if (strDestin==QString("OUTER")) ++st; } //This message/event is for this MAP itself else if (strDestin==QString("MAIN_MAP")) { ++st; } if (st==0) { qWarning()<<"EVENT/MESSAGE DESTIN "<get_name() + ";"; qWarning()<<"Valid recievers:ALL;OUTER;MAIN_MAP;"<)> functor) { m_mutex_listeners.lock(); m_map_listeners[name] = (functor); m_mutex_listeners.unlock(); } void tilesviewer::unlisten_event(QString name) { m_mutex_listeners.lock(); m_map_listeners.remove(name); m_mutex_listeners.unlock(); } }