#include "tilesviewer.h" #include #include #include #include #include #include #include #include #include "layer_interface.h" #include "interface_utils.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_DBLCLK"; else if (event->buttons() & Qt::MidButton) map_evt["name"] = "MOUSE_MBUTTON_DBLCLK"; else map_evt["name"] = "MOUSE_BUTTON_DBLCLK"; 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); int nCurrImgSize = (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(); } }