/**************************************************************************** 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_actionmodifyvoxelsegmentation.h" #include "documentinterface.h" #include "painterinterface.h" #include #include #include #include #include #include "views/actions/onf_actionmodifyvoxelsegmentationoptions.h" #include "ct_math/ct_mathpoint.h" #include "ct_iterator/ct_pointiterator.h" #include "ct_color.h" ONF_ActionModifyVoxelSegmentation::ONF_ActionModifyVoxelSegmentation(const CT_AbstractItemDrawableWithPointCloud* scene, const CT_Grid3D_Points* pointGrid, const CT_Grid3D_Points* topologyGrid, CT_Grid3D_Sparse *outSegmentationGrid, QVector *validated, QMap*positionLabels) : CT_AbstractActionForGraphicsView() { _scene = scene; _pointGrid = pointGrid; _pointGrid->getIndicesWithPoints(_cellsWithPoints); _topologyGrid = topologyGrid; _outSegmentationGrid = outSegmentationGrid; _pointCloudIndex = nullptr; _validated = validated; _positionLabels = positionLabels; m_status = 0; m_mousePressed = false; m_selectionMode = GraphicsViewInterface::SELECT_ONE_POINT; _automaticColorList.append(QColor(255,255,200)); // Jaune Clair _automaticColorList.append(QColor(255,200,255)); // Magenta Clair _automaticColorList.append(QColor(200,255,255)); // Cyan Clair _automaticColorList.append(QColor(200,200,255)); // Mauve Clair _automaticColorList.append(QColor(255,200,200)); // Rouge Clair _automaticColorList.append(QColor(255,200,150)); // Orange clair _automaticColorList.append(QColor(150,200,255)); // Bleu Clair _automaticColorList.append(QColor(200,255,150)); // Vert-Jaune Clair _automaticColorList.append(QColor(150,255,200)); // Turquoise Clair _automaticColorList.append(QColor(255,150,200)); // Rose Clair _automaticColorList.append(QColor(200,150,255)); // Violet Clair _automaticColorList.append(QColor(255,0 ,255)); // Magenta _automaticColorList.append(QColor(0 ,0 ,255)); // Bleu _automaticColorList.append(QColor(0 ,0 ,255)); // Mauve _automaticColorList.append(QColor(255,150,0 )); // Orange _automaticColorList.append(QColor(0 ,255,150)); // Turquoise _automaticColorList.append(QColor(255,0 ,150)); // Rose _automaticColorList.append(QColor(150,0 ,255)); // Violet _colorA = QColor(255,255,0 ); // Jaune _colorAvalidated = QColor(190,255,0 ); // Jaune-vert _colorB = QColor(0 ,255,255); // Cyan _colorTrash = QColor(125,125,125); // Grey _validatedColor = QColor(0 ,175,0 ); // Vert } ONF_ActionModifyVoxelSegmentation::~ONF_ActionModifyVoxelSegmentation() { } QString ONF_ActionModifyVoxelSegmentation::uniqueName() const { return "ONF_ActionModifyVoxelSegmentation"; } QString ONF_ActionModifyVoxelSegmentation::title() const { return tr("Segmentation"); } QString ONF_ActionModifyVoxelSegmentation::description() const { return tr("Segmentation"); } QIcon ONF_ActionModifyVoxelSegmentation::icon() const { return QIcon(":/icons/cursor.png"); } QString ONF_ActionModifyVoxelSegmentation::type() const { return CT_AbstractAction::TYPE_SELECTION; } void ONF_ActionModifyVoxelSegmentation::init() { CT_AbstractActionForGraphicsView::init(); if(nOptions() == 0) { // create the option widget if it was not already created ONF_ActionModifyVoxelSegmentationOptions *option = new ONF_ActionModifyVoxelSegmentationOptions(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); option->selectColorA(_colorA); option->selectColorB(_colorB); document()->removeAllItemDrawable(); _lastSeedID = _outSegmentationGrid->dataMax(); _colorNum = 0; _positionsBaseColors.resize(_lastSeedID + 1); _validated->resize(_lastSeedID + 1); for (int clusterIndex = 0 ; clusterIndex <= _lastSeedID ; clusterIndex++) { _positionsBaseColors[clusterIndex] = _automaticColorList.at(_colorNum++); if (_colorNum >= _automaticColorList.size()) {_colorNum = 0;} (*_validated)[clusterIndex] = false; } _positionA = 1; _positionB = 2; if (_scene != nullptr) { document()->addItemDrawable(*const_cast(_scene)); _pointCloudIndex = _scene->pointCloudIndex(); GraphicsViewInterface* view = dynamic_cast(document()->views().first()); _objectsModifier = view->createObjectsModifier(GOT_PointGlobalCloud); } document()->redrawGraphics(); updateAllClustersColors(); redraw(true); connect(option, SIGNAL(setColorA(QColor)), this, SLOT(setColorA(QColor))); connect(option, SIGNAL(setColorB(QColor)), this, SLOT(setColorB(QColor))); connect(option, SIGNAL(selectPositionA()), this, SLOT(selectPositionA())); connect(option, SIGNAL(selectPositionB()), this, SLOT(selectPositionB())); connect(option, SIGNAL(visibilityChanged()), this, SLOT(visibilityChanged())); connect(option, SIGNAL(affectClusterToA()), this, SLOT(affectClusterToA())); connect(option, SIGNAL(affectClusterToB()), this, SLOT(affectClusterToB())); connect(option, SIGNAL(affectClusterToTrash()), this, SLOT(affectClusterToTrash())); connect(option, SIGNAL(affectClusterToNew()), this, SLOT(affectClusterToNewSeed())); connect(option, SIGNAL(extend()), this, SLOT(extend())); connect(option, SIGNAL(selectSeed()), this, SLOT(selectSeed())); connect(option, SIGNAL(validatePosition()), this, SLOT(validatePosition())); connect(option, SIGNAL(labelAChanged(QString)), this, SLOT(changeLabelA(QString))); dynamic_cast(document()->views().first())->camera()->fitCameraToVisibleItems(); } } void ONF_ActionModifyVoxelSegmentation::redraw(bool pointsUpdated) { setDrawing3DChanged(); document()->redrawGraphics(); if (pointsUpdated) { graphicsView()->dirtyColorsOfItemDrawablesWithPoints(); } } void ONF_ActionModifyVoxelSegmentation::changeLabelA(QString label) { if (_positionLabels != nullptr) { _positionLabels->insert(_positionA, label); } } void ONF_ActionModifyVoxelSegmentation::updateAllClustersColors() { if (_pointCloudIndex != nullptr) { ONF_ActionModifyVoxelSegmentationOptions *option = (ONF_ActionModifyVoxelSegmentationOptions*)optionAt(0); GraphicsViewInterface *view = graphicsView(); bool isAvisible = option->isAVisible(); bool isBvisible = option->isBVisible(); bool isValidatedvisible = option->isValidatedVisible(); bool isOthervisible = option->isOthersVisible(); bool isTrashvisible = option->isTrashVisible(); for (int i = 0 ; i < _cellsWithPoints.size() ; i++) { size_t cellIndex = _cellsWithPoints.at(i); int clusterIndex = _outSegmentationGrid->valueAtIndex(cellIndex); QColor color = QColor(255, 255, 255); bool visible = false; if (clusterIndex >= 0) { if (clusterIndex == _positionA) { if (isAvisible) { if ((*_validated)[clusterIndex]) { color = _colorAvalidated; visible = true; } else { color = _colorA; visible = true; } } } else if (clusterIndex == _positionB) { if (isBvisible) {color = _colorB; visible = true;} } else if ((*_validated)[clusterIndex]) { if (isValidatedvisible) {color = _validatedColor; visible = true;} } else if (isOthervisible) { color = _positionsBaseColors[clusterIndex]; visible = true; } } else if (isTrashvisible) { color = _colorTrash; visible = true; } CT_Color ctcolor; ctcolor.set(color.red(), color.green(), color.blue()); const QList *pointIndices = _pointGrid->getConstPointIndexList(cellIndex); for (int j = 0 ; j < pointIndices->size() ; j++) { size_t pointIndex = pointIndices->at(j); _objectsModifier->setVisible(pointIndex, visible); if (visible) { view->setColorOfPoint(pointIndex, ctcolor); } } } } } void ONF_ActionModifyVoxelSegmentation::updateColorForOneCluster(int clusterNum) { if (_pointCloudIndex != nullptr) { ONF_ActionModifyVoxelSegmentationOptions *option = (ONF_ActionModifyVoxelSegmentationOptions*)optionAt(0); GraphicsViewInterface *view = graphicsView(); bool isAvisible = option->isAVisible(); bool isBvisible = option->isBVisible(); bool isValidatedvisible = option->isValidatedVisible(); bool isOthervisible = option->isOthersVisible(); for (int i = 0 ; i < _cellsWithPoints.size() ; i++) { size_t cellIndex = _cellsWithPoints.at(i); int clusterIndex = _outSegmentationGrid->valueAtIndex(cellIndex); QColor color = QColor(255, 255, 255); unsigned char transparency = 0; if (clusterIndex == clusterNum) { if (clusterIndex == _positionA) { if (isAvisible) { if ((*_validated)[clusterIndex]) { color = _colorAvalidated; transparency = 255; } else { color = _colorA; transparency = 255; } } } else if (clusterIndex == _positionB) { if (isBvisible) {color = _colorB; transparency = 255;} } else if ((*_validated)[clusterIndex]) { if (isValidatedvisible) {color = _validatedColor; transparency = 255;} } else if (isOthervisible) { color = _positionsBaseColors[clusterIndex]; transparency = 255; } const QList *indices = _pointGrid->getConstPointIndexList(cellIndex); for (int j = 0 ; j < indices->size() ; j++) { CT_Color ctcolor; ctcolor.set(color.red(), color.green(), color.blue(), transparency); view->setColorOfPoint(indices->at(j), ctcolor); } } } } } bool ONF_ActionModifyVoxelSegmentation::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_ActionModifyVoxelSegmentation::mouseMoveEvent(QMouseEvent *e) { if(m_status > 0) { GraphicsViewInterface *view = graphicsView(); GraphicsViewInterface::SelectionMode mode = selectionModeToBasic(view->selectionMode()); if((mode == GraphicsViewInterface::ADD_ONE_POINT) || (mode == GraphicsViewInterface::REMOVE_ONE_POINT) || (mode == GraphicsViewInterface::SELECT_ONE_POINT)) { 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_ActionModifyVoxelSegmentation::mouseReleaseEvent(QMouseEvent *e) { GraphicsViewInterface *view = graphicsView(); GraphicsViewInterface::SelectionMode mode = selectionModeToBasic(view->selectionMode()); m_mousePressed = false; if(m_status > 0) { m_status = 0; if(mode != GraphicsViewInterface::NONE) { if((mode == GraphicsViewInterface::ADD_ONE_POINT) || (mode == GraphicsViewInterface::REMOVE_ONE_POINT) || (mode == GraphicsViewInterface::SELECT_ONE_POINT)) { QRect r(0, 0, 3, 3); r.moveCenter(e->pos()); view->select(r); if (e->modifiers() == Qt::ALT) { if (e->button() == Qt::LeftButton) { selectPositionA(); } else if (e->button() == Qt::RightButton) { selectPositionB(); } } } else { m_selectionRectangle = m_selectionRectangle.normalized(); QRect r(0, 0, m_selectionRectangle.width(), m_selectionRectangle.height()); r.moveCenter(m_selectionRectangle.center()); view->select(r); filterPointSelection(); document()->redrawGraphics(); return true; } } } document()->redrawGraphics(); return false; } bool ONF_ActionModifyVoxelSegmentation::isVisible(int clusterIndex) { ONF_ActionModifyVoxelSegmentationOptions *option = (ONF_ActionModifyVoxelSegmentationOptions*)optionAt(0); bool cellIsVisible = true; if (clusterIndex == _positionA) { if (!option->isAVisible()) { cellIsVisible = false; } } else if (clusterIndex == _positionB) { if (!option->isBVisible()) { cellIsVisible = false; } } else if (clusterIndex >= 0) { if (!option->isOthersVisible()) { cellIsVisible = false; } } else if (!option->isTrashVisible()) { cellIsVisible = false; } return cellIsVisible; } // TO DO, à simplifier (ne garder que la non séléction des arbres validés) après le changement de composant 3D void ONF_ActionModifyVoxelSegmentation::filterPointSelection() { ONF_ActionModifyVoxelSegmentationOptions *option = (ONF_ActionModifyVoxelSegmentationOptions*)optionAt(0); GraphicsViewInterface *view = graphicsView(); CT_SPCIR pcir = view->getSelectedPoints(); CT_PointIterator itp(pcir); while (itp.hasNext()) { itp.next(); const CT_Point &pt = itp.currentPoint(); int clusterIndex = _outSegmentationGrid->valueAtXYZ(pt(0), pt(1), pt(2)); bool pointCanBeSelected = true; if (!option->isValidatedSelectable() && (*_validated)[clusterIndex]) { pointCanBeSelected = false; } else { // To remove later pointCanBeSelected = isVisible(clusterIndex); } if (!pointCanBeSelected) { view->removePointsIDFromSelection(itp.currentGlobalIndex()); } } } bool ONF_ActionModifyVoxelSegmentation::keyPressEvent(QKeyEvent *e) { ONF_ActionModifyVoxelSegmentationOptions *option = (ONF_ActionModifyVoxelSegmentationOptions*)optionAt(0); if((e->key() == Qt::Key_Control) && !e->isAutoRepeat()) { option->setMultiSelect(true); setSelectionMode(option->selectionMode()); return true; } if((e->key() == Qt::Key_X) && !e->isAutoRepeat()) { extend(); return true; } if((e->key() == Qt::Key_A) && !e->isAutoRepeat()) { affectClusterToA(); return true; } if((e->key() == Qt::Key_Z) && !e->isAutoRepeat()) { affectClusterToB(); return true; } if((e->key() == Qt::Key_E) && !e->isAutoRepeat()) { affectClusterToNewSeed(); return true; } if((e->key() == Qt::Key_R) && !e->isAutoRepeat()) { affectClusterToTrash(); return true; } if((e->key() == Qt::Key_Space) && !e->isAutoRepeat()) { option->toggleOthersVisible(); return true; } if((e->key() == Qt::Key_V) && !e->isAutoRepeat()) { validatePosition(); return true; } return false; } bool ONF_ActionModifyVoxelSegmentation::keyReleaseEvent(QKeyEvent *e) { ONF_ActionModifyVoxelSegmentationOptions *option = (ONF_ActionModifyVoxelSegmentationOptions*)optionAt(0); if((e->key() == Qt::Key_Control) && !e->isAutoRepeat()) { option->setMultiSelect(false); setSelectionMode(option->selectionMode()); return true; } return false; } void ONF_ActionModifyVoxelSegmentation::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_ActionModifyVoxelSegmentation::createInstance() const { return new ONF_ActionModifyVoxelSegmentation(_scene, _pointGrid, _topologyGrid, _outSegmentationGrid, _validated, _positionLabels); } bool ONF_ActionModifyVoxelSegmentation::setSelectionMode(GraphicsViewInterface::SelectionMode mode) { if(!m_mousePressed) { m_selectionMode = mode; return true; } return false; } GraphicsViewInterface::SelectionMode ONF_ActionModifyVoxelSegmentation::selectionMode() const { return m_selectionMode; } void ONF_ActionModifyVoxelSegmentation::setColorA(QColor color) { _colorA = color; updateColorForOneCluster(_positionA); redraw(true); } void ONF_ActionModifyVoxelSegmentation::setColorB(QColor color) { _colorB = color; updateColorForOneCluster(_positionB); redraw(true); } void ONF_ActionModifyVoxelSegmentation::swapAandB() { int oldPositionB = _positionB; _positionB = _positionA; _positionA = oldPositionB; updateColorForOneCluster(_positionA); updateColorForOneCluster(_positionB); redraw(true); } void ONF_ActionModifyVoxelSegmentation::visibilityChanged() { updateAllClustersColors(); redraw(true); } void ONF_ActionModifyVoxelSegmentation::selectPositionA() { ONF_ActionModifyVoxelSegmentationOptions *option = (ONF_ActionModifyVoxelSegmentationOptions*)optionAt(0); CT_SPCIR pcir = graphicsView()->getSelectedPoints(); CT_PointIterator itp(pcir); while (itp.hasNext()) { itp.next(); const CT_Point &pt = itp.currentPoint(); int clusterID = _outSegmentationGrid->valueAtXYZ(pt(0), pt(1), pt(2)); if (clusterID >= 0) { if (clusterID == _positionB) { swapAandB(); } else { int oldPositionA = _positionA; _positionA = clusterID; if (_positionLabels != nullptr) { option->setLabelA(_positionLabels->value(_positionA, "")); } updateColorForOneCluster(oldPositionA); updateColorForOneCluster(_positionA); redraw(true); } return; } } } void ONF_ActionModifyVoxelSegmentation::selectPositionB() { CT_SPCIR pcir = graphicsView()->getSelectedPoints(); CT_PointIterator itp(pcir); while (itp.hasNext()) { itp.next(); const CT_Point &pt = itp.currentPoint(); int clusterID = _outSegmentationGrid->valueAtXYZ(pt(0), pt(1), pt(2)); if (clusterID >=0) { if (clusterID == _positionA) { swapAandB(); } else { int oldPositionB = _positionB; _positionB = clusterID; updateColorForOneCluster(oldPositionB); updateColorForOneCluster(_positionB); redraw(true); } return; } } } void ONF_ActionModifyVoxelSegmentation::affectClusterToA() { QList cellIndexList; getSelectedCells(cellIndexList); for (int i = 0 ; i < cellIndexList.size() ; i++) { size_t cellIndex = cellIndexList.at(i); _outSegmentationGrid->setValueAtIndex(cellIndex, _positionA); } graphicsView()->setAllPointsSelected(false); updateColorForOneCluster(_positionA); redraw(true); } void ONF_ActionModifyVoxelSegmentation::affectClusterToB() { QList cellIndexList; getSelectedCells(cellIndexList); for (int i = 0 ; i < cellIndexList.size() ; i++) { size_t cellIndex = cellIndexList.at(i); _outSegmentationGrid->setValueAtIndex(cellIndex, _positionB); } graphicsView()->setAllPointsSelected(false); updateColorForOneCluster(_positionB); redraw(true); } void ONF_ActionModifyVoxelSegmentation::affectClusterToTrash() { QList cellIndexList; getSelectedCells(cellIndexList); for (int i = 0 ; i < cellIndexList.size() ; i++) { size_t cellIndex = cellIndexList.at(i); _outSegmentationGrid->setValueAtIndex(cellIndex, -1); } graphicsView()->setAllPointsSelected(false); updateAllClustersColors(); redraw(true); } void ONF_ActionModifyVoxelSegmentation::affectClusterToNewSeed() { QList cellIndexList; getSelectedCells(cellIndexList); if (cellIndexList.size() > 0) { ++_lastSeedID; _positionsBaseColors.resize(_lastSeedID + 1); _validated->resize(_lastSeedID + 1); _positionsBaseColors[_lastSeedID] = _automaticColorList.at(_colorNum++); (*_validated)[_lastSeedID] = false; for (int i = 0 ; i < cellIndexList.size() ; i++) { size_t cellIndex = cellIndexList.at(i); _outSegmentationGrid->setValueAtIndex(cellIndex, _lastSeedID); } _positionA = _lastSeedID; graphicsView()->setAllPointsSelected(false); updateAllClustersColors(); redraw(true); } } void ONF_ActionModifyVoxelSegmentation::extend() { GraphicsViewInterface *view = graphicsView(); QList cellIndices; getSelectedCells(cellIndices); for (int i = 0; i < cellIndices.size() ; i++) { size_t cellIndex = cellIndices.at(i); int clusterIndex = _outSegmentationGrid->valueAtIndex(cellIndex); if (isVisible(clusterIndex) && (clusterIndex >= 0) && !(*_validated)[clusterIndex]) { const QList *childCells = _topologyGrid->getConstPointIndexList(cellIndex); cellIndices.append(*childCells); const QList *pointIndices = _pointGrid->getConstPointIndexList(cellIndex); for (int j = 0 ; j < pointIndices->size() ; j++) { view->addPointsIDToSelection(pointIndices->at(j)); } } } redraw(true); } void ONF_ActionModifyVoxelSegmentation::selectSeed() { GraphicsViewInterface *view = graphicsView(); QList selectedCellIndices; getSelectedCells(selectedCellIndices); QList selectedClustersIndices; for (int i = 0; i < selectedCellIndices.size() ; i++) { selectedClustersIndices.append(_outSegmentationGrid->valueAtIndex(selectedCellIndices.at(i))); } QList list; _outSegmentationGrid->getIndicesWithData(list); for (int i = 0 ; i < list.size() ; i++) { size_t cellIndex = list.at(i); int clusterIndex = _outSegmentationGrid->valueAtIndex(cellIndex); if (selectedClustersIndices.contains(clusterIndex)) { const QList *points = _pointGrid->getConstPointIndexList(cellIndex); for (int j = 0 ; j < points->size() ; j++) { view->addPointsIDToSelection(points->at(j)); } } } redraw(true); } void ONF_ActionModifyVoxelSegmentation::validatePosition() { if ((*_validated)[_positionA]) { (*_validated)[_positionA] = false; } else { (*_validated)[_positionA] = true; } updateColorForOneCluster(_positionA); redraw(true); } GraphicsViewInterface::SelectionMode ONF_ActionModifyVoxelSegmentation::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; } void ONF_ActionModifyVoxelSegmentation::getSelectedCells(QList &list) { CT_SPCIR pcir = graphicsView()->getSelectedPoints(); CT_PointIterator itp(pcir); while (itp.hasNext()) { itp.next(); const CT_Point &pt = itp.currentPoint(); size_t cellIndex; if (_outSegmentationGrid->indexAtXYZ(pt(0), pt(1), pt(2), cellIndex)) { if (!list.contains(cellIndex)) {list.append(cellIndex);} } } }