diff --git a/guilib/include/rtabmap/gui/DatabaseViewer.h b/guilib/include/rtabmap/gui/DatabaseViewer.h index 936c2e78..2630f6cc 100644 --- a/guilib/include/rtabmap/gui/DatabaseViewer.h +++ b/guilib/include/rtabmap/gui/DatabaseViewer.h @@ -60,6 +60,7 @@ class CloudViewer; class OctoMap; class ExportCloudsDialog; class EditDepthArea; +class EditMapArea; class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow { @@ -93,8 +94,10 @@ private Q_SLOTS: void selectEmptyColor(); void editDepthImage(); void generateGraph(); + void editSaved2DMap(); void exportSaved2DMap(); void import2DMap(); + void regenerateSavedMap(); void viewOptimizedMesh(); void exportOptimizedMesh(); void updateOptimizedMesh(); @@ -225,6 +228,8 @@ private: ExportCloudsDialog * exportDialog_; QDialog * editDepthDialog_; EditDepthArea * editDepthArea_; + QDialog * editMapDialog_; + EditMapArea * editMapArea_; bool savedMaximized_; bool firstCall_; diff --git a/guilib/include/rtabmap/gui/EditMapArea.h b/guilib/include/rtabmap/gui/EditMapArea.h new file mode 100644 index 00000000..8e777276 --- /dev/null +++ b/guilib/include/rtabmap/gui/EditMapArea.h @@ -0,0 +1,92 @@ +/* +Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Universite de Sherbrooke nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RTABMAP_EDITMAPAREA_H +#define RTABMAP_EDITMAPAREA_H + +#include "rtabmap/gui/RtabmapGuiExp.h" // DLL export/import defines + +#include +#include +#include +#include +#include +#include "rtabmap/utilite/UCv2Qt.h" + +class QMenu; +class QAction; + +namespace rtabmap { + +class RTABMAPGUI_EXP EditMapArea : public QWidget +{ + Q_OBJECT + +public: + EditMapArea(QWidget *parent = 0); + + void setMap(const cv::Mat & map); + cv::Mat getModifiedMap() const; + bool isModified() const {return modified_;} + + void setPenWidth(int newWidth); + int penWidth() const { return myPenWidth_; } + void setColorMap(uCvQtDepthColorMap type); + +public Q_SLOTS: + void resetChanges(); + +protected: + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void paintEvent(QPaintEvent *event); + virtual void resizeEvent(QResizeEvent *event); + virtual void contextMenuEvent(QContextMenuEvent * e); + +private: + void drawLineTo(const QPoint &endPoint); + void computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const; + + bool modified_; + bool scribbling_; + int myPenWidth_; + QImage map_; + cv::Mat originalMap_; + QPoint lastPoint_; + + QMenu * menu_; + QAction * resetChanges_; + QAction * setPenWidth_; + QAction * addObstacle_; + QAction * clearObstacle_; + QAction * setUnknown_; +}; + +} + +#endif diff --git a/guilib/src/CMakeLists.txt b/guilib/src/CMakeLists.txt index bf3c0147..a5a037d4 100644 --- a/guilib/src/CMakeLists.txt +++ b/guilib/src/CMakeLists.txt @@ -32,6 +32,7 @@ SET(headers_ui ../include/${PROJECT_PREFIX}/gui/TexturingState.h ../include/${PROJECT_PREFIX}/gui/RecoveryState.h ../include/${PROJECT_PREFIX}/gui/EditDepthArea.h + ../include/${PROJECT_PREFIX}/gui/EditMapArea.h ) SET(uis @@ -98,6 +99,7 @@ SET(SRC_FILES ./MapVisibilityWidget.cpp ./GraphViewer.cpp ./EditDepthArea.cpp + ./EditMapArea.cpp ./CreateSimpleCalibrationDialog.cpp ./ParametersToolBox.cpp ./DepthCalibrationDialog.cpp diff --git a/guilib/src/DatabaseViewer.cpp b/guilib/src/DatabaseViewer.cpp index d310b434..c455c87c 100644 --- a/guilib/src/DatabaseViewer.cpp +++ b/guilib/src/DatabaseViewer.cpp @@ -75,6 +75,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "rtabmap/gui/DataRecorder.h" #include "rtabmap/gui/ExportCloudsDialog.h" #include "rtabmap/gui/EditDepthArea.h" +#include "rtabmap/gui/EditMapArea.h" #include "rtabmap/core/SensorData.h" #include "rtabmap/core/GainCompensator.h" #include "rtabmap/gui/ExportDialog.h" @@ -100,6 +101,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) : octomap_(0), exportDialog_(new ExportCloudsDialog(this)), editDepthDialog_(new QDialog(this)), + editMapDialog_(new QDialog(this)), savedMaximized_(false), firstCall_(true), iniFilePath_(ini), @@ -136,6 +138,20 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) : editDepthDialog_->setLayout(vLayout); editDepthDialog_->setWindowTitle(tr("Edit Depth Image")); + editMapDialog_->resize(640, 480); + vLayout = new QVBoxLayout(editMapDialog_); + editMapArea_ = new EditMapArea(editMapDialog_); + vLayout->setContentsMargins(0,0,0,0); + vLayout->setSpacing(0); + vLayout->addWidget(editMapArea_, 1); + buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal, editMapDialog_); + vLayout->addWidget(buttonBox); + connect(buttonBox, SIGNAL(accepted()), editMapDialog_, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), editMapDialog_, SLOT(reject())); + connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), editMapArea_, SLOT(resetChanges())); + editMapDialog_->setLayout(vLayout); + editMapDialog_->setWindowTitle(tr("Edit Optimized Map")); + QString title("RTAB-Map Database Viewer[*]"); this->setWindowTitle(title); @@ -251,8 +267,10 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) : connect(ui_->actionPoses_KML, SIGNAL(triggered()), this , SLOT(exportPosesKML())); connect(ui_->actionGPS_TXT, SIGNAL(triggered()), this , SLOT(exportGPS_TXT())); connect(ui_->actionGPS_KML, SIGNAL(triggered()), this , SLOT(exportGPS_KML())); + connect(ui_->actionEdit_optimized_2D_map, SIGNAL(triggered()), this , SLOT(editSaved2DMap())); connect(ui_->actionExport_saved_2D_map, SIGNAL(triggered()), this , SLOT(exportSaved2DMap())); connect(ui_->actionImport_2D_map, SIGNAL(triggered()), this , SLOT(import2DMap())); + connect(ui_->actionRegenerate_optimized_2D_map, SIGNAL(triggered()), this , SLOT(regenerateSavedMap())); connect(ui_->actionView_optimized_mesh, SIGNAL(triggered()), this , SLOT(viewOptimizedMesh())); connect(ui_->actionExport_optimized_mesh, SIGNAL(triggered()), this , SLOT(exportOptimizedMesh())); connect(ui_->actionUpdate_optimized_mesh, SIGNAL(triggered()), this , SLOT(updateOptimizedMesh())); @@ -285,7 +303,10 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) : ui_->menuExport_poses->setEnabled(false); ui_->menuExport_GPS->setEnabled(false); ui_->actionPoses_KML->setEnabled(false); + ui_->actionEdit_optimized_2D_map->setEnabled(false); ui_->actionExport_saved_2D_map->setEnabled(false); + ui_->actionImport_2D_map->setEnabled(false); + ui_->actionRegenerate_optimized_2D_map->setEnabled(false); ui_->actionView_optimized_mesh->setEnabled(false); ui_->actionExport_optimized_mesh->setEnabled(false); ui_->actionUpdate_optimized_mesh->setEnabled(false); @@ -968,8 +989,10 @@ bool DatabaseViewer::closeDatabase() ui_->menuExport_poses->setEnabled(false); ui_->menuExport_GPS->setEnabled(false); ui_->actionPoses_KML->setEnabled(false); + ui_->actionEdit_optimized_2D_map->setEnabled(false); ui_->actionExport_saved_2D_map->setEnabled(false); ui_->actionImport_2D_map->setEnabled(false); + ui_->actionRegenerate_optimized_2D_map->setEnabled(false); ui_->actionView_optimized_mesh->setEnabled(false); ui_->actionExport_optimized_mesh->setEnabled(false); ui_->actionUpdate_optimized_mesh->setEnabled(false); @@ -1526,8 +1549,10 @@ void DatabaseViewer::updateIds() ui_->menuExport_poses->setEnabled(false); ui_->menuExport_GPS->setEnabled(false); ui_->actionPoses_KML->setEnabled(false); + ui_->actionEdit_optimized_2D_map->setEnabled(false); ui_->actionExport_saved_2D_map->setEnabled(false); ui_->actionImport_2D_map->setEnabled(false); + ui_->actionRegenerate_optimized_2D_map->setEnabled(false); ui_->actionView_optimized_mesh->setEnabled(false); ui_->actionExport_optimized_mesh->setEnabled(false); ui_->actionUpdate_optimized_mesh->setEnabled(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.13.0") >= 0); @@ -1705,8 +1730,10 @@ void DatabaseViewer::updateIds() float xMin, yMin, cellSize; bool hasMap = !dbDriver_->load2DMap(xMin, yMin, cellSize).empty(); + ui_->actionEdit_optimized_2D_map->setEnabled(hasMap); ui_->actionExport_saved_2D_map->setEnabled(hasMap); ui_->actionImport_2D_map->setEnabled(hasMap); + ui_->actionRegenerate_optimized_2D_map->setEnabled(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") >= 0); if(!dbDriver_->loadOptimizedMesh().empty()) { @@ -2425,6 +2452,74 @@ void DatabaseViewer::exportGPS(int format) } } +void DatabaseViewer::editSaved2DMap() +{ + if(!dbDriver_) + { + QMessageBox::warning(this, tr("Cannot edit 2D map"), tr("A database must must loaded first...\nUse File->Open database.")); + return; + } + + if(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") < 0) + { + QMessageBox::warning(this, tr("Cannot edit 2D map"), + tr("The database has too old version (%1) to saved " + "optimized map. Version 0.17.0 minimum required.").arg(dbDriver_->getDatabaseVersion().c_str())); + return; + } + + if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size() || generatedLocalMaps_.size()) + { + QMessageBox::warning(this, tr("Cannot edit 2D map"), + tr("The database has modified links and/or modified local " + "occupancy grids, the 2D optimized map cannot be modified.")); + return; + } + + float xMin, yMin, cellSize; + cv::Mat map = dbDriver_->load2DMap(xMin, yMin, cellSize); + if(map.empty()) + { + QMessageBox::warning(this, tr("Cannot export 2D map"), tr("The database doesn't contain a saved 2D map.")); + return; + } + + cv::Mat map8U = rtabmap::util3d::convertMap2Image8U(map, false); + cv::Mat map8UFlip, map8URotated; + cv::flip(map8U, map8UFlip, 0); + if(!ui_->graphViewer->isOrientationENU()) + { + cv::rotate(map8UFlip, map8URotated, cv::ROTATE_90_COUNTERCLOCKWISE); + } + else + { + map8URotated = map8UFlip; + } + + editMapArea_->setMap(map8URotated); + if(editMapDialog_->exec() == QDialog::Accepted && editMapArea_->isModified()) + { + cv::Mat map = editMapArea_->getModifiedMap(); + + if(!ui_->graphViewer->isOrientationENU()) + { + cv::rotate(map, map8URotated, cv::ROTATE_90_CLOCKWISE); + } + else + { + map8URotated = map; + } + cv::flip(map8URotated, map8UFlip, 0); + + UASSERT(map8UFlip.type() == map8U.type()); + UASSERT(map8UFlip.cols == map8U.cols); + UASSERT(map8UFlip.rows == map8U.rows); + + dbDriver_->save2DMap(rtabmap::util3d::convertImage8U2Map(map8UFlip, false), xMin, yMin, cellSize); + QMessageBox::information(this, tr("Edit 2D map"), tr("Map updated!")); + } +} + void DatabaseViewer::exportSaved2DMap() { if(!dbDriver_) @@ -2469,6 +2564,22 @@ void DatabaseViewer::import2DMap() return; } + if(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") < 0) + { + QMessageBox::warning(this, tr("Cannot edit 2D map"), + tr("The database has too old version (%1) to saved " + "optimized map. Version 0.17.0 minimum required.").arg(dbDriver_->getDatabaseVersion().c_str())); + return; + } + + if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size() || generatedLocalMaps_.size()) + { + QMessageBox::warning(this, tr("Cannot import 2D map"), + tr("The database has modified links and/or modified local " + "occupancy grids, the 2D optimized map cannot be modified.")); + return; + } + float xMin, yMin, cellSize; cv::Mat mapOrg = dbDriver_->load2DMap(xMin, yMin, cellSize); if(mapOrg.empty()) @@ -2500,6 +2611,64 @@ void DatabaseViewer::import2DMap() } } +void DatabaseViewer::regenerateSavedMap() +{ + if(!dbDriver_) + { + QMessageBox::warning(this, tr("Cannot import 2D map"), tr("A database must must loaded first...\nUse File->Open database.")); + return; + } + + if(uStrNumCmp(dbDriver_->getDatabaseVersion(), "0.17.0") < 0) + { + QMessageBox::warning(this, tr("Cannot edit 2D map"), + tr("The database has too old version (%1) to saved " + "optimized map. Version 0.17.0 minimum required.").arg(dbDriver_->getDatabaseVersion().c_str())); + return; + } + + if(linksAdded_.size() || linksRefined_.size() || linksRemoved_.size() || generatedLocalMaps_.size()) + { + QMessageBox::warning(this, tr("Cannot import 2D map"), + tr("The database has modified links and/or modified local " + "occupancy grids, the 2D optimized map cannot be modified.")); + return; + } + + if((int)graphes_.empty() || localMaps_.empty()) + { + QMessageBox::warning(this, tr("Cannot regenerate 2D map"), + tr("Graph is empty, make sure you opened the " + "Graph View and there is a map shown.")); + return; + } + + + //update scans + UINFO("Update local maps list..."); + OccupancyGrid grid(ui_->parameters_toolbox->getParameters()); + for(std::map, cv::Mat> >::iterator iter=localMaps_.begin(); iter!=localMaps_.end(); ++iter) + { + grid.addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second); + } + grid.update(graphes_.back()); + float xMin, yMin; + cv::Mat map = grid.getMap(xMin, yMin); + + if(map.empty()) + { + QMessageBox::information(this, tr("Regenerate 2D map"), tr("Failed to renegerate the map, resulting map is empty!")); + } + else + { + dbDriver_->save2DMap(map, xMin, yMin, grid.getCellSize()); + QMessageBox::information(this, tr("Regenerate 2D map"), tr("Map regenerated!")); + ui_->actionEdit_optimized_2D_map->setEnabled(true); + ui_->actionExport_saved_2D_map->setEnabled(true); + ui_->actionImport_2D_map->setEnabled(true); + } +} + void DatabaseViewer::viewOptimizedMesh() { if(!dbDriver_) diff --git a/guilib/src/EditMapArea.cpp b/guilib/src/EditMapArea.cpp new file mode 100644 index 00000000..d61f882c --- /dev/null +++ b/guilib/src/EditMapArea.cpp @@ -0,0 +1,248 @@ +/* +Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Universite de Sherbrooke nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include + +#include "rtabmap/gui/EditMapArea.h" +#include + +namespace rtabmap { + +EditMapArea::EditMapArea(QWidget *parent) + : QWidget(parent) +{ + setAttribute(Qt::WA_StaticContents); + modified_ = false; + scribbling_ = false; + myPenWidth_ = 3; + + menu_ = new QMenu(tr(""), this); + setPenWidth_ = menu_->addAction(tr("Set Pen Width...")); + addObstacle_ = menu_->addAction(tr("Add Obstacle")); + addObstacle_->setCheckable(true); + addObstacle_->setChecked(true); + clearObstacle_ = menu_->addAction(tr("Clear Obstacle")); + clearObstacle_->setCheckable(true); + clearObstacle_->setChecked(false); + setUnknown_ = menu_->addAction(tr("Set Unknown")); + setUnknown_->setCheckable(true); + setUnknown_->setChecked(false); + QActionGroup * group = new QActionGroup(this); + group->addAction(addObstacle_); + group->addAction(clearObstacle_); + group->addAction(setUnknown_); + resetChanges_ = menu_->addAction(tr("Reset Changes")); +} + +void EditMapArea::setMap(const cv::Mat &map) +{ + UASSERT(!map.empty()); + UASSERT(map.type() == CV_8UC1); + originalMap_ = map; + + map_ = uCvMat2QImage(map, true).convertToFormat(QImage::Format_RGB32); + + modified_ = false; + update(); +} + +cv::Mat EditMapArea::getModifiedMap() const +{ + cv::Mat modifiedMap = originalMap_.clone(); + if(modified_) + { + UASSERT(map_.width() == modifiedMap.cols && + map_.height() == modifiedMap.rows); + UASSERT(modifiedMap.type() == CV_8UC1); + for(int j=0; j(j,i) = qRed(map_.pixel(i, j)); + } + } + } + return modifiedMap; +} + +void EditMapArea::setPenWidth(int newWidth) +{ + myPenWidth_ = newWidth; +} + +void EditMapArea::resetChanges() +{ + map_ = uCvMat2QImage(originalMap_).convertToFormat(QImage::Format_RGB32); + modified_ = false; + update(); +} + +void EditMapArea::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + float scale, offsetX, offsetY; + computeScaleOffsets(rect(), scale, offsetX, offsetY); + lastPoint_.setX((event->pos().x()-offsetX)/scale); + lastPoint_.setY((event->pos().y()-offsetY)/scale); + + scribbling_ = true; + } +} + +void EditMapArea::mouseMoveEvent(QMouseEvent *event) +{ + if ((event->buttons() & Qt::LeftButton) && scribbling_) + { + float scale, offsetX, offsetY; + computeScaleOffsets(rect(), scale, offsetX, offsetY); + QPoint to; + to.setX((event->pos().x()-offsetX)/scale); + to.setY((event->pos().y()-offsetY)/scale); + drawLineTo(to); + } +} + +void EditMapArea::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton && scribbling_) { + float scale, offsetX, offsetY; + computeScaleOffsets(rect(), scale, offsetX, offsetY); + QPoint to; + to.setX((event->pos().x()-offsetX)/scale); + to.setY((event->pos().y()-offsetY)/scale); + drawLineTo(to); + scribbling_ = false; + } +} + +void EditMapArea::computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const +{ + scale = 1.0f; + offsetX = 0.0f; + offsetY = 0.0f; + + if(!map_.isNull()) + { + float w = map_.width(); + float h = map_.height(); + float widthRatio = float(targetRect.width()) / w; + float heightRatio = float(targetRect.height()) / h; + + //printf("w=%f, h=%f, wR=%f, hR=%f, sW=%d, sH=%d\n", w, h, widthRatio, heightRatio, this->rect().width(), this->rect().height()); + if(widthRatio < heightRatio) + { + scale = widthRatio; + } + else + { + scale = heightRatio; + } + + //printf("ratio=%f\n",ratio); + + w *= scale; + h *= scale; + + if(w < targetRect.width()) + { + offsetX = (targetRect.width() - w)/2.0f; + } + if(h < targetRect.height()) + { + offsetY = (targetRect.height() - h)/2.0f; + } + //printf("offsetX=%f, offsetY=%f\n",offsetX, offsetY); + } +} + +void EditMapArea::paintEvent(QPaintEvent *event) +{ + //Scale + float ratio, offsetX, offsetY; + this->computeScaleOffsets(event->rect(), ratio, offsetX, offsetY); + QPainter painter(this); + + painter.translate(offsetX, offsetY); + painter.scale(ratio, ratio); + painter.drawImage(QPoint(0,0), map_); +} + +void EditMapArea::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); +} + +void EditMapArea::contextMenuEvent(QContextMenuEvent * e) +{ + QAction * action = menu_->exec(e->globalPos()); + if(action == setPenWidth_) + { + bool ok; + int width = QInputDialog::getInt(this, tr("Set Pen Width"), tr("Width:"), penWidth(), 1, 99, 1, &ok); + if(ok) + { + myPenWidth_ = width; + } + } + else if(action == resetChanges_) + { + this->resetChanges(); + } +} + +void EditMapArea::drawLineTo(const QPoint &endPoint) +{ + QPainter painter(&map_); + QColor color; + + //base on util3d::convertMap2Image8U(); + if(addObstacle_->isChecked()) + { + color.setRgb(0,0,0); + } + else if(clearObstacle_->isChecked()) + { + color.setRgb(178,178,178); + } + else //unknown + { + color.setRgb(89,89,89); + } + painter.setPen(QPen(color, myPenWidth_, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter.drawLine(lastPoint_, endPoint); + modified_ = true; + + update(); + lastPoint_ = endPoint; +} + +} diff --git a/guilib/src/ui/DatabaseViewer.ui b/guilib/src/ui/DatabaseViewer.ui index 50b7d8a9..81210ff4 100644 --- a/guilib/src/ui/DatabaseViewer.ui +++ b/guilib/src/ui/DatabaseViewer.ui @@ -61,7 +61,7 @@ 0 0 - 398 + 413 288 @@ -287,7 +287,7 @@ 0 0 - 397 + 412 288 @@ -647,7 +647,7 @@ 0 0 1547 - 25 + 22 @@ -687,8 +687,10 @@ + + @@ -1300,7 +1302,7 @@ 0 0 318 - 219 + 197 @@ -1461,8 +1463,8 @@ 0 0 - 282 - 885 + 280 + 875 @@ -1995,8 +1997,8 @@ 0 0 - 307 - 171 + 296 + 160 @@ -2124,7 +2126,7 @@ 0 0 185 - 487 + 485 @@ -2781,12 +2783,12 @@ - Export saved 2D map... + Export optimized 2D map... - Import 2D map... + Import optimized 2D map... @@ -2822,6 +2824,16 @@ RGBD-SLAM (stamp tx ty tz qx qy qz qw) + + + Edit optimized 2D map... + + + + + Regenerate optimized 2D map... + +