/**************************************************************************** Copyright (C) 2010-2012 the Office National des Forêts (ONF), France All rights reserved. Contact : alexandre.piboule@onf.fr Developers : Alexandre PIBOULE (ONF) This file is part of PluginONF library. PluginONF is free library: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PluginONF is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PluginONF. If not, see . *****************************************************************************/ #include "onf_actionmodifydem.h" #include #include #include #include #include #include "views/actions/onf_actionmodifydemoptions.h" #include "ct_math/delaunay2d/ct_delaunaytriangulation.h" #include #include "ct_math/ct_mathpoint.h" #include "ct_iterator/ct_pointiterator.h" #include "ct_accessor/ct_pointaccessor.h" #include "ct_color.h" ONF_ActionModifyDEM::ONF_ActionModifyDEM(CT_AbstractItemDrawableWithPointCloud *scene, CT_Image2D *originalDEM, CT_Image2D *modifiedDEM, CT_AbstractImage2D *inred, CT_AbstractImage2D *ingreen, CT_AbstractImage2D *inblue) : CT_AbstractActionForGraphicsView() { _scene = scene; _originalDEM = originalDEM; _modifiedDEM = modifiedDEM; _inred = inred; _ingreen = ingreen; _inblue = inblue; m_status = 0; m_mousePressed = false; m_selectionMode = GraphicsViewInterface::SELECT_ONE_POINT; // GRAY QLinearGradient gr = QLinearGradient(0, 0, 1, 0); gr.setColorAt(0, Qt::black); gr.setColorAt(1, Qt::white); _gradientGrey.constructFromQGradient(gr); } QString ONF_ActionModifyDEM::uniqueName() const { return "ONF_ActionModifyDEM"; } QString ONF_ActionModifyDEM::title() const { return tr("DEM modification"); } QString ONF_ActionModifyDEM::description() const { return tr("DEM modification"); } QIcon ONF_ActionModifyDEM::icon() const { return QIcon(":/icons/cursor.png"); } QString ONF_ActionModifyDEM::type() const { return CT_AbstractAction::TYPE_MODIFICATION; } void ONF_ActionModifyDEM::init() { CT_AbstractActionForGraphicsView::init(); if(nOptions() == 0) { // create the option widget if it was not already created ONF_ActionModifyDEMOptions *option = new ONF_ActionModifyDEMOptions(this); // add the options to the graphics view graphicsView()->addActionOptions(option); // register the option to the superclass, so the hideOptions and showOptions // is managed automatically registerOption(option); document()->removeAllItemDrawable(); if (_scene != NULL) { document()->addItemDrawable(*_scene); } document()->redrawGraphics(DocumentInterface::RO_WaitForConversionCompleted); redraw(); if (_inred != NULL && _ingreen != NULL && _inblue != NULL) { _amplitudeRed = _inred->maxValueAsDouble() - _inred->minValueAsDouble(); _amplitudeGreen = _ingreen->maxValueAsDouble() - _ingreen->minValueAsDouble(); _amplitudeBlue = _inblue->maxValueAsDouble() - _inblue->minValueAsDouble(); option->setImageAvailable(true); } else { option->setImageAvailable(false); } connect(option, SIGNAL(levelPoints(bool,bool)), this, SLOT(levelPoints(bool,bool))); connect(option, SIGNAL(razPoints()), this, SLOT(razPoints())); connect(option, SIGNAL(smooth()), this, SLOT(smooth())); connect(option, SIGNAL(imageStateChanged()), this, SLOT(colorizePoints())); dynamic_cast(document()->views().first())->camera()->fitCameraToVisibleItems(); dynamic_cast(document()->views().first())->camera()->alignCameraToZAxis(); colorizePoints(); } } void ONF_ActionModifyDEM::colorizePoints() { GraphicsViewInterface *view = graphicsView(); ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); const CT_AbstractPointCloudIndex *pointCloudIndex = _scene->getPointCloudIndex(); Eigen::Vector3d min, max; _scene->getBoundingBox(min, max); double minZ = min(2); double maxZ = max(2); double rangeZ = maxZ - minZ; CT_PointIterator itP(pointCloudIndex); while(itP.hasNext()) { const CT_Point &point = itP.next().currentPoint(); size_t index = itP.currentGlobalIndex(); if (option->isImageSelected() && _inred != NULL && _ingreen != NULL && _inblue != NULL) { size_t imgIndex; if (_inred->indexAtCoords(point(0), point(1), imgIndex)) { double redV = _inred->valueAtIndexAsDouble(imgIndex); double greenV = _ingreen->valueAtIndexAsDouble(imgIndex); double blueV = _inblue->valueAtIndexAsDouble(imgIndex); CT_Color color; if (redV == _inred->NAAsDouble() || greenV == _ingreen->NAAsDouble() || blueV == _inblue->NAAsDouble()) { color.set(255, 255, 255, 0); } else { int red = 255*(redV / _amplitudeRed); int green = 255*(greenV / _amplitudeGreen); int blue = 255*(blueV / _amplitudeBlue); if (red < 0) {red = 0;} if (green < 0) {green = 0;} if (blue < 0) {blue = 0;} if (red > 255) {red = 255;} if (green > 255) {green = 255;} if (blue > 255) {blue = 255;} color.set(red, green, blue, 255); } view->setColorOfPoint(index, color); } } else { double ratio = (point(2) - minZ) / rangeZ; if (point(2) < minZ) {ratio = 0;} if (point(2) > maxZ) {ratio = 1;} CT_Color color(_gradientGrey.intermediateColor(ratio)); view->setColorOfPoint(index, color); } } redraw(); } void ONF_ActionModifyDEM::redraw() { setDrawing3DChanged(); document()->redrawGraphics(); graphicsView()->dirtyColorsOfItemDrawablesWithPoints(); } void ONF_ActionModifyDEM::levelPoints(bool up, bool maxed) { ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); float step = option->getStepValue(); if (!up) {step *= -1.0;} GraphicsViewInterface *view = graphicsView(); CT_SPCIR pcir = view->getSelectedPoints(); double min = std::numeric_limits::max(); double max = -std::numeric_limits::max(); if (maxed) { CT_PointIterator itp0(pcir); while (itp0.hasNext()) { const CT_Point &point = itp0.next().currentPoint(); if (point(2) < min) {min = point(2);} if (point(2) > max) {max = point(2);} } } CT_PointIterator itp(pcir); while (itp.hasNext()) { const CT_Point &point = itp.next().currentPoint(); CT_PointData &pt = itp.currentInternalPoint(); double delta = point(2) + step; float value = pt(2) + step; if (maxed && delta > max) {value = pt(2) + (max - point(2));} if (maxed && delta < min) {value = pt(2) - (point(2) - min);} pt.z() = value; _modifiedDEM->setValueAtCoords(point(0), point(1), value); } _scene->updateBoundingBox(); if (option->isImageSelected()) {colorizePoints();} else {redraw();} } void ONF_ActionModifyDEM::razPoints() { ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); GraphicsViewInterface *view = graphicsView(); CT_SPCIR pcir = view->getSelectedPoints(); CT_PointIterator itp(pcir); while (itp.hasNext()) { const CT_Point &point = itp.next().currentPoint(); CT_PointData &pt = itp.currentInternalPoint(); float value = _originalDEM->valueAtCoords(point(0), point(1)); pt.z() = pt(2) - point(2) + value; } _scene->updateBoundingBox(); if (option->isImageSelected()) {colorizePoints();} else {redraw();} } void ONF_ActionModifyDEM::smooth() { QProgressDialog progressDialog(tr("Merci de patienter pendant l'interpolation\nN.B. : en cas d'interruption, les modifications déjà effectuées ne seront PAS annulées"), tr("Interrompre l'interpolation"), 0, 100); progressDialog.setWindowTitle(tr("Interpolation")); progressDialog.setModal(true); progressDialog.setMinimumDuration(0); progressDialog.setValue(1); ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); CT_PointAccessor accessor; GraphicsViewInterface *view = graphicsView(); progressDialog.setValue(2); CT_SPCIR pcir = view->getSelectedPoints(); double minx = std::numeric_limits::max(); double maxx = -std::numeric_limits::max(); double miny = std::numeric_limits::max(); double maxy = -std::numeric_limits::max(); QList selectedPoints; QList selectedIndices; QList selectedCellIndices; CT_PointIterator itp(pcir); while (itp.hasNext()) { const CT_Point &point = itp.next().currentPoint(); size_t cellIndex; if (_originalDEM->indexAtCoords(point(0), point(1), cellIndex)) { selectedPoints.append(new Eigen::Vector3d(point(0), point(1), point(2))); selectedCellIndices.append(cellIndex); selectedIndices.append(itp.currentGlobalIndex()); if (point(0) < minx) {minx = point(0);} if (point(0) > maxx) {maxx = point(0);} if (point(1) < miny) {miny = point(1);} if (point(1) > maxy) {maxy = point(1);} } } if (selectedPoints.size() <= 0) {return;} progressDialog.setMaximum(selectedPoints.size()); QList neighborsCellIndices; for (int i = 0 ; i < selectedPoints.size() ; i++) { Eigen::Vector3d* point = selectedPoints.at(i); size_t cellIndex, col, lin; _originalDEM->indexAtCoords((*point)(0), (*point)(1), cellIndex); _originalDEM->indexToGrid(cellIndex, col, lin); size_t neighb; if (_originalDEM->index(col - 1, lin - 1, neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } if (_originalDEM->index(col - 1, lin , neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } if (_originalDEM->index(col - 1, lin + 1, neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } if (_originalDEM->index(col , lin - 1, neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } if (_originalDEM->index(col , lin + 1, neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } if (_originalDEM->index(col + 1, lin - 1, neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } if (_originalDEM->index(col + 1, lin , neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } if (_originalDEM->index(col + 1, lin + 1, neighb) && !selectedCellIndices.contains(neighb) && !neighborsCellIndices.contains(neighb)) { neighborsCellIndices.append(neighb); } } if (neighborsCellIndices.size() < 4) {qDeleteAll(selectedPoints); progressDialog.setValue(selectedPoints.size()); return;} QList neighboursPoints; for (int i = 0 ; i < neighborsCellIndices.size() ; i++) { size_t cellIndex = neighborsCellIndices.at(i); Eigen::Vector3d* neighbPt = new Eigen::Vector3d(); if (_modifiedDEM->getCellCenterCoordinates(cellIndex, *neighbPt)) { (*neighbPt)(2) = _modifiedDEM->valueAtIndex(cellIndex); neighboursPoints.append(neighbPt); if ((*neighbPt)(0) < minx) {minx = (*neighbPt)(0);} if ((*neighbPt)(0) > maxx) {maxx = (*neighbPt)(0);} if ((*neighbPt)(1) < miny) {miny = (*neighbPt)(1);} if ((*neighbPt)(1) > maxy) {maxy = (*neighbPt)(1);} } } CT_DelaunayTriangulation *delaunay = new CT_DelaunayTriangulation(); delaunay->init(minx - 1, miny - 1, maxx + 1, maxy + 1); for (int j = 0 ; j < neighboursPoints.size() ; j++) { delaunay->addVertex(neighboursPoints.at(j), false); } delaunay->doInsertion(); for (int i = 0 ; i < selectedPoints.size() ; i++) { if (progressDialog.wasCanceled()) { qDeleteAll(selectedPoints); qDeleteAll(neighboursPoints); delete delaunay; _scene->updateBoundingBox(); progressDialog.setValue(selectedPoints.size()); if (option->isImageSelected()) {colorizePoints();} else {redraw();} return; } else { if (i > 2) {progressDialog.setValue(i);} } Eigen::Vector3d* point = selectedPoints.at(i); QList voisins = delaunay->getNeighboursForCoordinates((*point)(0), (*point)(1)); double sum = 0; double sum_poids = 0; // Calcul de la somme ponderee for (int nei = 0 ; nei < voisins.size() ; nei++) { CT_DelaunayVertex* neigh = voisins.at(nei); Eigen::Vector3d* nodePt = neigh->getData(); double dx = (double)(*point)(0) - (*nodePt)(0); double dy = (double)(*point)(1) - (*nodePt)(1); double distance = sqrt(dx*dx + dy*dy); sum += (*nodePt)(2) / distance; sum_poids += 1.0 / distance; } if (sum_poids != 0) { CT_PointData &pt = accessor.internalPointAt(selectedIndices.value(i)); float val = sum / sum_poids;; pt.z() = val; _modifiedDEM->setValueAtCoords((*point)(0), (*point)(1), val); } } qDeleteAll(selectedPoints); qDeleteAll(neighboursPoints); delete delaunay; _scene->updateBoundingBox(); progressDialog.setValue(selectedPoints.size()); if (option->isImageSelected()) {colorizePoints();} else {redraw();} } bool ONF_ActionModifyDEM::mousePressEvent(QMouseEvent *e) { GraphicsViewInterface *view = graphicsView(); view->setSelectionMode(selectionMode()); GraphicsViewInterface::SelectionMode mode = selectionModeToBasic(view->selectionMode()); m_mousePressed = true; m_status = 1; m_selectionRectangle.setSize(QSize(0,0)); if(((mode == GraphicsViewInterface::SELECT_POINTS) || (mode == GraphicsViewInterface::ADD_POINTS) || (mode == GraphicsViewInterface::REMOVE_POINTS))) { m_selectionRectangle = QRect(e->pos(), e->pos()); return true; } return false; } bool ONF_ActionModifyDEM::mouseMoveEvent(QMouseEvent *e) { if(m_status > 0) { GraphicsViewInterface *view = graphicsView(); GraphicsViewInterface::SelectionMode mode = view->selectionMode(); if((mode == GraphicsViewInterface::ADD_ONE_POINT) || (mode == GraphicsViewInterface::REMOVE_ONE_POINT) || (mode == GraphicsViewInterface::SELECT_ONE_POINT)) { if (e->modifiers() == Qt::ShiftModifier && m_mousePressed) { ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); int brushSize = option->getBrushSize(); if (mode == GraphicsViewInterface::ADD_ONE_POINT) {view->setSelectionMode(GraphicsViewInterface::ADD_POINTS);} if (mode == GraphicsViewInterface::REMOVE_ONE_POINT) {view->setSelectionMode(GraphicsViewInterface::REMOVE_POINTS);} if (mode == GraphicsViewInterface::SELECT_ONE_POINT) {view->setSelectionMode(GraphicsViewInterface::ADD_POINTS);} view->setSelectRegionWidth(brushSize); view->setSelectRegionHeight(brushSize); view->select(e->pos()); view->setSelectionMode(mode); return true; } else { view->setSelectionMode(GraphicsViewInterface::NONE); m_status = 0; return false; } } if(mode != GraphicsViewInterface::NONE) { m_selectionRectangle.setBottomRight(e->pos()); document()->redrawGraphics(); return true; } } return false; } bool ONF_ActionModifyDEM::mouseReleaseEvent(QMouseEvent *e) { ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); int brushSize = option->getBrushSize(); GraphicsViewInterface *view = graphicsView(); GraphicsViewInterface::SelectionMode mode = view->selectionMode(); m_mousePressed = false; if(m_status > 0 && e->modifiers() != Qt::ShiftModifier) { m_status = 0; if(mode != GraphicsViewInterface::NONE) { if(view->mustSelectPoints()) document()->constructOctreeOfPoints(); if((mode == GraphicsViewInterface::ADD_ONE_POINT) || (mode == GraphicsViewInterface::REMOVE_ONE_POINT) || (mode == GraphicsViewInterface::SELECT_ONE_POINT)) { if (mode == GraphicsViewInterface::ADD_ONE_POINT) {view->setSelectionMode(GraphicsViewInterface::ADD_POINTS);} if (mode == GraphicsViewInterface::REMOVE_ONE_POINT) {view->setSelectionMode(GraphicsViewInterface::REMOVE_POINTS);} if (mode == GraphicsViewInterface::SELECT_ONE_POINT) {view->setSelectionMode(GraphicsViewInterface::SELECT_POINTS);} view->setSelectRegionWidth(brushSize); view->setSelectRegionHeight(brushSize); view->select(e->pos()); view->setSelectionMode(mode); } else { m_selectionRectangle = m_selectionRectangle.normalized(); // Define selection window dimensions view->setSelectRegionWidth(m_selectionRectangle.width()); view->setSelectRegionHeight(m_selectionRectangle.height()); // Compute rectangle center and perform selection view->select(m_selectionRectangle.center()); document()->redrawGraphics(); return true; } } } document()->redrawGraphics(); return false; } bool ONF_ActionModifyDEM::keyPressEvent(QKeyEvent *e) { ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); if((e->key() == Qt::Key_Control) && !e->isAutoRepeat()) { option->setMultiSelect(true); setSelectionMode(option->selectionMode()); return true; } if((e->key() == Qt::Key_Right) && !e->isAutoRepeat()) { levelPoints(true, false); return true; } if((e->key() == Qt::Key_Left) && !e->isAutoRepeat()) { levelPoints(false, false); return true; } if((e->key() == Qt::Key_Up) && !e->isAutoRepeat()) { levelPoints(true, true); return true; } if((e->key() == Qt::Key_Down) && !e->isAutoRepeat()) { levelPoints(false, true); return true; } if((e->key() == Qt::Key_Backspace) && !e->isAutoRepeat()) { razPoints(); return true; } if((e->key() == Qt::Key_Plus)) { option->changeStepValue(true); return true; } if((e->key() == Qt::Key_Minus)) { option->changeStepValue(false); return true; } return false; } bool ONF_ActionModifyDEM::keyReleaseEvent(QKeyEvent *e) { ONF_ActionModifyDEMOptions *option = (ONF_ActionModifyDEMOptions*)optionAt(0); if((e->key() == Qt::Key_Control) && !e->isAutoRepeat()) { option->setMultiSelect(false); setSelectionMode(option->selectionMode()); return true; } return false; } void ONF_ActionModifyDEM::drawOverlay(GraphicsViewInterface &view, QPainter &painter) { Q_UNUSED(view) if(m_status > 0) { painter.save(); painter.setPen(QColor(102,102,127,127)); painter.setBrush(QColor(0,0,73,73)); painter.drawRect(m_selectionRectangle); painter.restore(); } } CT_AbstractAction* ONF_ActionModifyDEM::copy() const { return new ONF_ActionModifyDEM(_scene, _originalDEM, _modifiedDEM, _inred, _ingreen, _inblue); } bool ONF_ActionModifyDEM::setSelectionMode(GraphicsViewInterface::SelectionMode mode) { if(!m_mousePressed) { m_selectionMode = mode; return true; } return false; } GraphicsViewInterface::SelectionMode ONF_ActionModifyDEM::selectionMode() const { return m_selectionMode; } GraphicsViewInterface::SelectionMode ONF_ActionModifyDEM::selectionModeToBasic(GraphicsViewInterface::SelectionMode mode) const { int m = mode; if (m == GraphicsViewInterface::REMOVE_ONE_POINT || m == GraphicsViewInterface::ADD_ONE_POINT) { m = GraphicsViewInterface::SELECT_ONE_POINT; } if (m == GraphicsViewInterface::REMOVE_POINTS || m == GraphicsViewInterface::ADD_POINTS) { m = GraphicsViewInterface::SELECT_POINTS; } return (GraphicsViewInterface::SelectionMode)m; }