/**************************************************************************** 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 "actions/onf_actionadjustplotposition02.h" #include "ct_global/ct_context.h" #include "ct_iterator/ct_pointiterator.h" #include "ct_color.h" #include "ct_math/ct_mathpoint.h" #include #include #include #include #include #include #include #include "math.h" QColor ONF_ActionAdjustPlotPosition02::_cylinderColor = QColor(255, 255, 255); QColor ONF_ActionAdjustPlotPosition02::_highlightedCylindersColor = QColor(255, 170, 255); QColor ONF_ActionAdjustPlotPosition02::_selectedCylinderColor = QColor(255, 0, 0); QColor ONF_ActionAdjustPlotPosition02::_apexColor = QColor(0,0,0); QColor ONF_ActionAdjustPlotPosition02::_selectedApexColor = QColor(170, 85, 0); ONF_ActionAdjustPlotPosition02_dataContainer::ONF_ActionAdjustPlotPosition02_dataContainer() { _transX = 0; _transY = 0; _dtm = nullptr; } ONF_ActionAdjustPlotPosition02::ONF_ActionAdjustPlotPosition02(ONF_ActionAdjustPlotPosition02_dataContainer *dataContainer) : CT_AbstractActionForGraphicsView() { _dataContainer = dataContainer; _drawManagerCylinder = new ONF_AdjustPlotPositionCylinderDrawManager(tr("Tree")); _drawManagerDSM = new ONF_AdjustPlotPositionImage2DDrawManager(tr("DSM")); _selectedPos = nullptr; _previousSelectedPos = nullptr; _movePlot = false; _movedCylindersColor = QColor(0, 255, 100); _drawManagerCylinder->setColor(_cylinderColor); _drawManagerCylinder->setSelectionColor(_selectedCylinderColor); _drawManagerCylinder->setHighlightColor(_highlightedCylindersColor); _drawManagerCylinder->setMovedColor(_movedCylindersColor); _currentPoint(0) = std::numeric_limits::max(); _currentPoint(1) = std::numeric_limits::max(); _currentPoint(2) = std::numeric_limits::max(); _currentApex = std::numeric_limits::max(); _minZ = std::numeric_limits::max(); _maxZ = -std::numeric_limits::max(); _rangeZ = 1; _minH = std::numeric_limits::max(); _maxH = -std::numeric_limits::max(); _rangeH = 1; _minI = std::numeric_limits::max(); _maxI = -std::numeric_limits::max(); _rangeI = 1; _colorizeByIntensity = false; _mode3d = false; _apex = true; _apexSize = 0.3; _drawPlot = true; _dbhMin = 17.5; _colorBySpecies = false; // GRAY updateGradients(255, false); _currentZGradient = _gradientHot; _currentIGradient = _gradientGrey; _currentZGradientName = "hot"; _currentIGradientName = "grey"; _drawManagerDSM->setGradient(&_currentZGradient); _drawManagerDSM->setMinMax(0,100); } void ONF_ActionAdjustPlotPosition02::updateGradients(int transparency, bool invert) { QLinearGradient gr; // GREY gr = QLinearGradient(0, 0, 1, 0); if (invert) { gr.setColorAt(0, QColor(255,255,255,transparency)); gr.setColorAt(1, QColor(0,0,0,transparency)); } else { gr.setColorAt(0, QColor(0,0,0,transparency)); gr.setColorAt(1, QColor(255,255,255,transparency)); } _gradientGrey.constructFromQGradient(gr); // HOT gr = QLinearGradient(0, 0, 1, 0); if (invert) { gr.setColorAt(0, QColor(255,255,255,transparency)); gr.setColorAt(0.25, QColor(255,255,0,transparency)); gr.setColorAt(0.75, QColor(255,0,0,transparency)); gr.setColorAt(1, QColor(0,0,0,transparency)); } else { gr.setColorAt(0, QColor(0,0,0,transparency)); gr.setColorAt(0.25, QColor(255,0,0,transparency)); gr.setColorAt(0.75, QColor(255,255,0,transparency)); gr.setColorAt(1, QColor(255,255,255,transparency)); } _gradientHot.constructFromQGradient(gr); // Arcgis greenyellow - violet gr = QLinearGradient(0, 0, 1, 0); if (invert) { gr.setColorAt(0, QColor(0,0,255,transparency)); gr.setColorAt(0.333, QColor(255,0,0,transparency)); gr.setColorAt(0.666, QColor(255,255,0,transparency)); gr.setColorAt(1, QColor(0,255,0,transparency)); } else { gr.setColorAt(0, QColor(0,255,0,transparency)); gr.setColorAt(0.333, QColor(255,255,0,transparency)); gr.setColorAt(0.666, QColor(255,0,0,transparency)); gr.setColorAt(1, QColor(0,0,255,transparency)); } _gradientRainbow.constructFromQGradient(gr); // HSV gr = QLinearGradient(0, 0, 1, 0); if (invert) { gr.setColorAt(0, QColor(255,0,0,transparency)); gr.setColorAt(0.166, QColor(0,0,255,transparency)); gr.setColorAt(0.333, QColor(0,255,255,transparency)); gr.setColorAt(0.5, QColor(0,255,0,transparency)); gr.setColorAt(0.666, QColor(255,255,0,transparency)); gr.setColorAt(1, QColor(255,0,0,transparency)); } else { gr.setColorAt(0, QColor(255,0,0,transparency)); gr.setColorAt(0.166, QColor(255,255,0,transparency)); gr.setColorAt(0.333, QColor(0,255,0,transparency)); gr.setColorAt(0.5, QColor(0,255,255,transparency)); gr.setColorAt(0.666, QColor(0,0,255,transparency)); gr.setColorAt(1, QColor(255,0,0,transparency)); } _gradientHSV.constructFromQGradient(gr); // Arcgis red-yellow-cyan-blue gr = QLinearGradient(0, 0, 1, 0); if (invert) { gr.setColorAt(0, QColor(0,0,255,transparency)); gr.setColorAt(0.333, QColor(0,255,255,transparency)); gr.setColorAt(0.666, QColor(255,255,0,transparency)); gr.setColorAt(1, QColor(255,0,0,transparency)); } else { gr.setColorAt(0, QColor(255,0,0,transparency)); gr.setColorAt(0.333, QColor(255,255,0,transparency)); gr.setColorAt(0.666, QColor(0,255,255,transparency)); gr.setColorAt(1, QColor(0,0,255,transparency)); } _gradientRYCB.constructFromQGradient(gr); } ONF_ActionAdjustPlotPosition02::~ONF_ActionAdjustPlotPosition02() { document()->removeAllItemDrawable(); qDeleteAll(_cylinders); _cylinders.clear(); delete _drawManagerCylinder; delete _drawManagerDSM; } QString ONF_ActionAdjustPlotPosition02::uniqueName() const { return "ONF_ActionAdjustPlotPosition02"; } QString ONF_ActionAdjustPlotPosition02::title() const { return "Ajust Plot Position"; } QString ONF_ActionAdjustPlotPosition02::description() const { return "Ajust Plot Position"; } QIcon ONF_ActionAdjustPlotPosition02::icon() const { return QIcon(":/icons/select_rectangular.png"); } QString ONF_ActionAdjustPlotPosition02::type() const { return CT_AbstractAction::TYPE_MODIFICATION; } void ONF_ActionAdjustPlotPosition02::init() { CT_AbstractActionForGraphicsView::init(); if(nOptions() == 0) { // create the option widget if it was not already created ONF_ActionAdjustPlotPositionOptions02 *option = new ONF_ActionAdjustPlotPositionOptions02(this); // add the options to the graphics view graphicsView()->addActionOptions(option); connect(option, SIGNAL(parametersChanged(double, double, bool, bool, double, bool, bool, double, bool, double, bool)), this, SLOT(update(double, double, bool, bool, double, bool, bool, double, bool, double, bool))); connect(option, SIGNAL(colorizationChanged(bool, int, int)), this, SLOT(updateColorization(bool, int, int))); connect(option, SIGNAL(askForTranslation(bool)), this, SLOT(applyTranslation(bool))); connect(option, SIGNAL(setGradient(bool, QString, int, int)), this, SLOT(setGradient(bool, QString, int, int))); connect(option, SIGNAL(changeHighlightedNumber(int)), this, SLOT(changeHighlightedNumber(int))); connect(option, SIGNAL(selectionModeChanged(bool)), this, SLOT(changeSelectionMode(bool))); connect(option, SIGNAL(qualityChanged(int)), this, SLOT(changeQuality(int))); connect(option, SIGNAL(commentChanged(QString)), this, SLOT(changeComment(QString))); connect(option, SIGNAL(computeAutoFit()), this, SLOT(autoComputeTranslation())); // register the option to the superclass, so the hideOptions and showOptions // is managed automatically registerOption(option); option->setPlotID(_dataContainer->_idPlot); option->setColors(_cylinderColor, _highlightedCylindersColor, _selectedCylinderColor, _apexColor, _selectedApexColor); for (int i = 0 ; i < _dataContainer->_positions.size() ; i++) { ONF_CoRegistration_TreePosition* pos = _dataContainer->_positions.at(i); Eigen::Vector3d center(pos->_x, pos->_y, pos->_height / 2.0); if (_dataContainer->_dtm != nullptr) { float zbase = _dataContainer->_dtm->valueAtCoords(pos->_x + _dataContainer->_transX, pos->_y + _dataContainer->_transY); if (zbase != _dataContainer->_dtm->NA()) { center(2) += zbase; } } Eigen::Vector3d dir(0, 0, 1); CT_Cylinder* cyl = new CT_Cylinder(nullptr, nullptr, new CT_CylinderData(center, dir, pos->_dbh / 200.0, pos->_height)); cyl->setBaseDrawManager(_drawManagerCylinder); _drawManagerCylinder->addCylinderColor(cyl, pos->_color); _cylinders.append(cyl); pos->_cyl = cyl; //document()->addItemDrawable(*cyl); } qSort(_cylinders.begin(), _cylinders.end(), ONF_ActionAdjustPlotPosition02::lessThan); _minZ = std::numeric_limits::max(); _maxZ = -std::numeric_limits::max(); _minI = std::numeric_limits::max(); _maxI = -std::numeric_limits::max(); _minH = std::numeric_limits::max(); _maxH = -std::numeric_limits::max(); for (int i = 0 ; i < _dataContainer->_scenes.size() ; i++) { CT_AbstractItemDrawableWithPointCloud* scene = (CT_AbstractItemDrawableWithPointCloud*) _dataContainer->_scenes.at(i); const CT_AbstractPointCloudIndex *pointCloudIndex = scene->getPointCloudIndex(); CT_StdLASPointsAttributesContainer* LASAttributes = _dataContainer->_LASattributes.at(i); CT_PointsAttributesScalarTemplated* heightAttributes = _dataContainer->_heightAttributes.at(i); CT_AbstractPointAttributesScalar* attributeIntensity = nullptr; CT_AbstractPointCloudIndex* pointCloudIndexLAS = nullptr; CT_AbstractPointCloudIndex* heightCloudIndex = nullptr; if (LASAttributes != nullptr) { attributeIntensity = (CT_AbstractPointAttributesScalar*)LASAttributes->pointsAttributesAt(CT_LasDefine::Intensity); pointCloudIndexLAS = (CT_AbstractPointCloudIndex*) attributeIntensity->getPointCloudIndex(); } if (heightAttributes != nullptr) { heightCloudIndex = (CT_AbstractPointCloudIndex*) heightAttributes->getPointCloudIndex(); } CT_PointIterator itP(pointCloudIndex); while(itP.hasNext()) { const CT_Point &point = itP.next().currentPoint(); size_t index = itP.currentGlobalIndex(); if (point(2) > _maxZ) {_maxZ = point(2);} if (point(2) < _minZ) {_minZ = point(2);} if (heightAttributes != nullptr) { size_t localIndex = heightCloudIndex->indexOf(index); if (localIndex < heightCloudIndex->size()) { float h = heightAttributes->dValueAt(localIndex); if (h > _maxH) {_maxH = h;} if (h < _minH) {_minH = h;} } } if (LASAttributes != nullptr) { size_t localIndex = pointCloudIndexLAS->indexOf(index); if (localIndex < pointCloudIndexLAS->size()) { double intensity = attributeIntensity->dValueAt(localIndex); if (intensity > _maxI) {_maxI = intensity;} if (intensity < _minI) {_minI = intensity;} } } } _rangeZ = _maxZ - _minZ; _rangeH = _maxH - _minH; _rangeI = _maxI - _minI; _drawManagerDSM->setRefZ(_minZ); _drawManagerCylinder->setRefZ(_minZ + 0.1); document()->addItemDrawable(*scene); } GraphicsViewInterface* view = dynamic_cast(document()->views().first()); for (int i = 0 ; i < _dataContainer->_scenes.size() ; i++) { CT_AbstractItemDrawableWithPointCloud* scene = (CT_AbstractItemDrawableWithPointCloud*) _dataContainer->_scenes.at(i); _objectsModifierList.append(view->createObjectsModifierForItem(scene, GOT_PointGlobalCloud)); } document()->redrawGraphics(DocumentInterface::RO_WaitForConversionCompleted); QColor col = Qt::darkBlue; view->getOptions().setBackgroudColor(col); view->getOptions().setPointSize(10); view->validateOptions(); //view->camera()->setOrientation(0.2, 0, 0, 0.95); view->camera()->setType(CameraInterface::ORTHOGRAPHIC); view->camera()->setOrientation(0, 0, 0, 1); colorizePoints(_currentZGradient, 0, 100); view->camera()->fixCameraCenterToItemsBarycenter(); view->camera()->fitCameraToVisibleItems(); changeHighlightedNumber(6); document()->removeAllItemDrawable(); _dataContainer->_dsm->setAlternativeDrawManager(_drawManagerDSM); document()->addItemDrawable(*(_dataContainer->_dsm)); view->active2DView(true); } } void ONF_ActionAdjustPlotPosition02::updateAllCylindersPosition() { for (int i = 0 ; i < _dataContainer->_positions.size() ; i++) { updateCylinderPosition(_dataContainer->_positions.at(i)); _dataContainer->_positions.at(i)->_zPoint = -9999; } } void ONF_ActionAdjustPlotPosition02::autoComputeTranslation() { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); // list available maxima QMapIterator it(_dataContainer->_maximaPoints); QList apexCoordinates; QList apexHeights; while (it.hasNext()) { it.next(); Eigen::Vector3d coords = it.value(); double zDTM = 0; if (_dataContainer->_dtm != nullptr) { float zDTM = _dataContainer->_dtm->valueAtCoords(coords(0), coords(1)); if (qFuzzyCompare(zDTM, _dataContainer->_dtm->NA())) { zDTM = 0; } } coords(2) = coords(2) - zDTM; apexCoordinates.append(coords); apexHeights.append(_dataContainer->_dsm->valueAtCoords(coords(0), coords(1))); } QVector matched(apexCoordinates.size()); double bestError = std::numeric_limits::max(); double bestDx = 0; double bestDy = 0; double maxError = option->autoFitMaxError(); double apexRadiusSq = option->autoFitRadius()*option->autoFitRadius(); for (double dx = -maxError ; dx <= maxError ; dx += option->translationStep()) { for (double dy = -maxError ; dy <= maxError ; dy += option->translationStep()) { double dist = sqrt(dx*dx + dy*dy); if (dist <= maxError) { matched.fill(false); double caseError = 0; int nbMatches = 0; for (int cn = 0 ; cn < _cylinders.size() ; cn++) { CT_Cylinder* cyl = static_cast(_cylinders.at(cn)); const Eigen::Vector3d& cylCoord = cyl->getCenter(); double cylRadius = cyl->getRadius(); double minDistApex = std::numeric_limits::max(); int apexRank = -1; for (int an = 0 ; an < apexCoordinates.size() ; an++) { if (!matched[an]) { Eigen::Vector3d apexCoords = apexCoordinates.at(an); float h = apexHeights.at(an); double apxDist = pow(cylCoord(0) + dx - apexCoords(0), 2) + pow(cylCoord(1) + dy - apexCoords(1), 2); if (apxDist < minDistApex) { minDistApex = apxDist; apexRank = an; } } } if (minDistApex < apexRadiusSq) { caseError += minDistApex; nbMatches++; matched[apexRank] = true; } } if (nbMatches > 0) {caseError /= nbMatches;} if (caseError < bestError) { bestError = caseError; bestDx = dx; bestDy = dy; } } } } _dataContainer->_transX = bestDx; _dataContainer->_transY = bestDy; option->setTranslation(bestDx, bestDy); _drawManagerCylinder->setTranslation(bestDx, bestDy); updateAllCylindersPosition(); redrawOverlayAnd3D(); PS_LOG->addMessage(LogInterface::info, LogInterface::action, tr("AutoFit Complete")); } void ONF_ActionAdjustPlotPosition02::updateCylinderPosition(ONF_CoRegistration_TreePosition* pos) { Eigen::Vector3d newCenter(pos->_x, pos->_y, pos->_height / 2.0); if (_dataContainer->_dtm != nullptr) { float zbase = _dataContainer->_dtm->valueAtCoords(pos->_x + _dataContainer->_transX, pos->_y + _dataContainer->_transY); if (zbase != _dataContainer->_dtm->NA()) { newCenter(2) += zbase; } } CT_CylinderData* cylData = ((CT_CylinderData*) ((CT_Cylinder*)pos->_cyl)->getPointerData()); cylData->setCenter(newCenter); if (pos->_x == pos->_originalX && pos->_y == pos->_originalY) { pos->_moved = false; cylData->setCircleError(0); } else { pos->_moved = true; cylData->setCircleError(1); } } void ONF_ActionAdjustPlotPosition02::update(double x, double y, bool circles, bool fixedH, double h, bool treeMode, bool mode3d, double radiusFactor, bool apex, double apexSize, bool plot) { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); if (treeMode) { if (_selectedPos != nullptr) { _selectedPos->_x += x; _selectedPos->_y += y; _selectedPos->_zPoint = -9999; updateCylinderPosition(_selectedPos); } } else { _dataContainer->_transX += x; _dataContainer->_transY += y; _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); } _drawManagerCylinder->setParameters(circles, fixedH, h, radiusFactor); _drawManagerCylinder->setMode3D(mode3d); _cylinderColor = option->colorTree(); _highlightedCylindersColor = option->colorHighlightedTree(); _selectedCylinderColor = option->colorSelectedTree(); _apexColor = option->colorApex(); _selectedApexColor = option->colorSelectedApex(); _drawManagerCylinder->setColor(_cylinderColor); _drawManagerCylinder->setHighlightColor(_highlightedCylindersColor); _drawManagerCylinder->setSelectionColor(_selectedCylinderColor); // passage vue 2D / vue 3D _mode3d = mode3d; _apex = apex; _apexSize = apexSize; _drawPlot = plot; _dbhMin = option->dbhMin(); _colorBySpecies = option->colorBySpecies(); _drawManagerCylinder->setColorBySpecies(_colorBySpecies); document()->removeAllItemDrawable(); GraphicsViewInterface* view = dynamic_cast(document()->views().first()); if (view != nullptr) { if (!mode3d) {view->camera()->alignCameraToZAxis();} view->active2DView(!mode3d); } if (mode3d) { for (int i = 0 ; i < _dataContainer->_scenes.size() ; i++) { CT_AbstractItemDrawableWithPointCloud* scene = (CT_AbstractItemDrawableWithPointCloud*) _dataContainer->_scenes.at(i); document()->addItemDrawable(*scene); } } else { document()->addItemDrawable(*(_dataContainer->_dsm)); } updateColorization(_colorizeByIntensity, option->hsMinValue(), option->hsMaxValue()); } void ONF_ActionAdjustPlotPosition02::updateColorization(bool colorizeByIntensity, int min, int max) { if (_mode3d) { _colorizeByIntensity = colorizeByIntensity; if (_colorizeByIntensity) { colorizePoints(_currentIGradient, min, max); } else { colorizePoints(_currentZGradient, min, max); } } else { document()->removeAllItemDrawable(); _drawManagerDSM->setGradient(&_currentZGradient); _drawManagerDSM->setMinMax(min, max); document()->addItemDrawable(*(_dataContainer->_dsm)); } redrawOverlayAnd3D(); } void ONF_ActionAdjustPlotPosition02::applyTranslation(bool reset) { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); if (reset) { _dataContainer->_transX = 0; _dataContainer->_transY = 0; for (int i = 0 ; i < _dataContainer->_positions.size() ; i++) { _dataContainer->_positions.at(i)->_x = _dataContainer->_positions.at(i)->_originalX; _dataContainer->_positions.at(i)->_y = _dataContainer->_positions.at(i)->_originalY; _dataContainer->_positions.at(i)->_zPoint = -9999; updateCylinderPosition(_dataContainer->_positions.at(i)); } _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); redrawOverlayAnd3D(); } else if (_currentPoint(0) < std::numeric_limits::max() && _selectedPos != nullptr) { if (option->isTreeModeSelected()) { _selectedPos->_x = _currentPoint(0) - _dataContainer->_transX; _selectedPos->_y = _currentPoint(1) - _dataContainer->_transY; _selectedPos->_zPoint = _currentPoint(2); updateCylinderPosition(_selectedPos); } else { _dataContainer->_transX += _currentPoint(0) - (_selectedPos->_x + _dataContainer->_transX); _dataContainer->_transY += _currentPoint(1) - (_selectedPos->_y + _dataContainer->_transY); _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); } redrawOverlayAnd3D(); } } void ONF_ActionAdjustPlotPosition02::setGradient(bool intensity, QString name, int min, int max) { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); updateGradients(option->getShadeValue(), option->isInverted()); if (name == "") { if (intensity && _mode3d) { name = _currentIGradientName; } else { name = _currentZGradientName; } } if (name == "grey") { if (intensity && _mode3d) { _currentIGradient = _gradientGrey; _currentIGradientName = "grey"; } else { _currentZGradient = _gradientGrey; _currentZGradientName = "grey"; } } else if (name == "hot") { if (intensity && _mode3d) { _currentIGradient = _gradientHot; _currentIGradientName = "hot"; } else { _currentZGradient = _gradientHot; _currentZGradientName = "hot"; } } else if (name == "rainbow") { if (intensity && _mode3d) { _currentIGradient = _gradientRainbow; _currentIGradientName = "rainbow"; } else { _currentZGradient = _gradientRainbow; _currentZGradientName = "rainbow"; } } else if (name == "hsv") { if (intensity && _mode3d) { _currentIGradient = _gradientHSV; _currentIGradientName = "hsv"; } else { _currentZGradient = _gradientHSV; _currentZGradientName = "hsv"; } } else if (name == "rycb") { if (intensity && _mode3d) { _currentIGradient = _gradientRYCB; _currentIGradientName = "rycb"; } else { _currentZGradient = _gradientRYCB; _currentZGradientName = "rycb"; } } updateColorization(_colorizeByIntensity, min, max); //redrawOverlayAnd3D(); } void ONF_ActionAdjustPlotPosition02::changeHighlightedNumber(int n) { QList list; for (int i = 0 ; i < n && i < _cylinders.size(); i++) { CT_Cylinder* cyl = dynamic_cast(_cylinders.at(i)); if (cyl != nullptr) { list.append(cyl); } } _drawManagerCylinder->setHighlightedCylinder(list); redrawOverlayAnd3D(); } void ONF_ActionAdjustPlotPosition02::changeSelectionMode(bool modechange) { if (!modechange || (!_mode3d && _currentApex == std::numeric_limits::max())) { _currentPoint(0) = std::numeric_limits::max(); _currentPoint(1) = std::numeric_limits::max(); _currentPoint(2) = std::numeric_limits::max(); _currentApex = std::numeric_limits::max(); } redrawOverlayAnd3D(); } void ONF_ActionAdjustPlotPosition02::changeQuality(int quality) { _dataContainer->_quality = quality; } void ONF_ActionAdjustPlotPosition02::changeComment(QString comment) { _dataContainer->_comment = comment; } void ONF_ActionAdjustPlotPosition02::colorizePoints(ONF_ColorLinearInterpolator &gradient, int min, int max) { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); GraphicsViewInterface *view = graphicsView(); for (int i = 0 ; i < _dataContainer->_scenes.size() && _rangeZ > 0 ; i++) { CT_AbstractItemDrawableWithPointCloud* scene = (CT_AbstractItemDrawableWithPointCloud*) _dataContainer->_scenes.at(i); const CT_AbstractPointCloudIndex *pointCloudIndex = scene->getPointCloudIndex(); QSharedPointer modifier = _objectsModifierList.at(i); CT_StdLASPointsAttributesContainer* LASAttributes = _dataContainer->_LASattributes.at(i); CT_PointsAttributesScalarTemplated* heightAttributes = _dataContainer->_heightAttributes.at(i); CT_AbstractPointAttributesScalar* attributeIntensity = nullptr; CT_AbstractPointAttributesScalar* attributeR = nullptr; CT_AbstractPointAttributesScalar* attributeN = nullptr; CT_AbstractPointCloudIndex* pointCloudIndexLAS = nullptr; CT_AbstractPointCloudIndex* heightCloudIndex = nullptr; if (LASAttributes != nullptr) { attributeIntensity = (CT_AbstractPointAttributesScalar*)LASAttributes->pointsAttributesAt(CT_LasDefine::Intensity); attributeR = (CT_AbstractPointAttributesScalar*)LASAttributes->pointsAttributesAt(CT_LasDefine::Return_Number); attributeN = (CT_AbstractPointAttributesScalar*)LASAttributes->pointsAttributesAt(CT_LasDefine::Number_of_Returns); pointCloudIndexLAS = (CT_AbstractPointCloudIndex*) attributeIntensity->getPointCloudIndex(); } if (heightAttributes != nullptr) { heightCloudIndex = (CT_AbstractPointCloudIndex*) heightAttributes->getPointCloudIndex(); } double minZ = _minZ + (double)min * _rangeZ / 100.0; double maxZ = _minZ + (double)max * _rangeZ / 100.0; if (heightAttributes != nullptr) { minZ = _minH + (double)min * _rangeH / 100.0; maxZ = _minH + (double)max * _rangeH / 100.0; } if (minZ > maxZ) {minZ = maxZ;} double rangeZ = maxZ - minZ; CT_PointIterator itP(pointCloudIndex); while(itP.hasNext()) { const CT_Point &point = itP.next().currentPoint(); size_t index = itP.currentGlobalIndex(); size_t cindex = pointCloudIndex->indexOf(index); bool visible = true; double ratio = (point(2) - minZ) / rangeZ; if (point(2) < minZ) {ratio = 0;} if (point(2) > maxZ) {ratio = 1;} float h = 0; if (heightAttributes != nullptr) { size_t localIndex = heightCloudIndex->indexOf(index); h = heightAttributes->valueAt(localIndex); ratio = (h - minZ) / rangeZ; if (h < minZ) {ratio = 0;} if (h > maxZ) {ratio = 1;} } CT_Color color(gradient.intermediateColor(ratio)); if (LASAttributes != nullptr) { size_t localIndex = pointCloudIndexLAS->indexOf(index); if (localIndex < pointCloudIndexLAS->size()) { if (_colorizeByIntensity && attributeIntensity != nullptr) { double minI = _minI + (double)min * _rangeI / 100.0; double maxI = _minI + (double)max * _rangeI / 100.0; if (minI > maxI) {minI = maxI;} double rangeI = maxI - minI; double intensity = attributeIntensity->dValueAt(localIndex); ratio = (intensity - minI) / rangeI; if (intensity < minI) {ratio = 0;} if (intensity > maxI) {ratio = 1;} } } if (option->lastOnly() && attributeN != nullptr && attributeR != nullptr) { double Natt = attributeN->dValueAt(localIndex); double Ratt = attributeR->dValueAt(localIndex); if (Natt == 1 || Natt != Ratt) { visible = false; } } } if (option->hidePointsOutsideLimits() && (ratio >= 1 || ratio <= 0)) { visible = false; } float hmax = minZ + rangeZ * (option->hMaxValue() / 100.0); if (heightAttributes != nullptr && h > hmax) { visible = false; } else if (heightAttributes == nullptr && point(2) > hmax) { visible = false; } view->setColorOfPoint(index, color); if (!modifier.isNull()) { modifier->setVisible(cindex, visible); } else {qDebug() << "Problème";} } } redrawOverlayAnd3D(); view->dirtyColorsOfItemDrawablesWithPoints(); } void ONF_ActionAdjustPlotPosition02::redrawOverlay() { document()->redrawGraphics(); } void ONF_ActionAdjustPlotPosition02::redrawOverlayAnd3D() { setDrawing3DChanged(); document()->redrawGraphics(); } bool ONF_ActionAdjustPlotPosition02::mousePressEvent(QMouseEvent *e) { _lastPos = e->pos(); _buttonsPressed = e->buttons(); if (e->buttons() == Qt::LeftButton) { if (e->modifiers() & Qt::ControlModifier) { _movePlot = true; } } return false; } bool ONF_ActionAdjustPlotPosition02::mouseMoveEvent(QMouseEvent *e) { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); QPoint lastPos = _lastPos; _lastPos = e->pos(); if (e->buttons() == Qt::LeftButton) { if (e->modifiers() & Qt::ControlModifier) { double xl, yl; double x, y; if (getCoordsForMousePosition(lastPos, xl, yl) && getCoordsForMousePosition(e->pos(), x, y)) { _dataContainer->_transX += x - xl; _dataContainer->_transY += y - yl; _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); redrawOverlayAnd3D(); return true; } } else { _movePlot = false; } } else { _movePlot = false; } return false; } bool ONF_ActionAdjustPlotPosition02::mouseReleaseEvent(QMouseEvent *e) { GraphicsViewInterface *view = graphicsView(); ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); if (_movePlot) { double xl, yl; double x, y; if (getCoordsForMousePosition(_lastPos, xl, yl) && getCoordsForMousePosition(e->pos(), x, y)) { _dataContainer->_transX += x - xl; _dataContainer->_transY += y - yl; _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); redrawOverlayAnd3D(); } _movePlot = false; } _movePlot = false; QPoint dir = e->pos() - _lastPos; if (dir.manhattanLength() < 3) { if (_buttonsPressed == Qt::RightButton) { Eigen::Vector3d origin, direction; view->convertClickToLine(e->pos(), origin, direction); _selectedPos = getPositionFromDirection(origin, direction); if (_selectedPos != nullptr) { _drawManagerCylinder->setselectedCylinder(_selectedPos->_cyl); redrawOverlayAnd3D(); } else { _drawManagerCylinder->setselectedCylinder(nullptr); redrawOverlayAnd3D(); } // bool found = false; // Eigen::Vector3d point = view->pointUnderPixel(e->pos(), found); // if (found) // { // _selectedPos = getPositionFromPoint(point); // _drawManager->setselectedCylinder(_selectedPos->_cyl); // redrawOverlayAnd3D(); // } //update(); //return true; } else if (_buttonsPressed == Qt::LeftButton) { if (_apex) { Eigen::Vector3d origin, direction; view->convertClickToLine(e->pos(), origin, direction); getApexPositionFromDirection(origin, direction, _currentPoint, _currentApex); } else { view->setSelectionMode(GraphicsViewInterface::SELECT_ONE_POINT); view->setSelectRegionWidth(3); view->setSelectRegionHeight(3); view->select(e->pos()); CT_CIR pcir = view->getSelectedPoints(); CT_PointIterator it(pcir); if (it.hasNext()) { it.next(); _currentPoint = it.currentPoint(); _currentApex = std::numeric_limits::max(); } else { _currentPoint(0) = std::numeric_limits::max(); _currentPoint(1) = std::numeric_limits::max(); _currentPoint(2) = std::numeric_limits::max(); _currentApex = std::numeric_limits::max(); } } redrawOverlayAnd3D(); } } return false; } bool ONF_ActionAdjustPlotPosition02::wheelEvent(QWheelEvent *e) { Q_UNUSED(e); return false; } bool ONF_ActionAdjustPlotPosition02::keyPressEvent(QKeyEvent *e) { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); if(e->key() == Qt::Key_Up) { if(!e->isAutoRepeat()) { if (option->isTreeModeSelected()) { if (_selectedPos != nullptr) { _selectedPos->_y += option->translationIncrement(); _selectedPos->_zPoint = -9999; updateCylinderPosition(_selectedPos); redrawOverlayAnd3D(); } } else { _dataContainer->_transY += option->translationIncrement(); _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); redrawOverlayAnd3D(); } } return true; } if(e->key() == Qt::Key_Down) { if(!e->isAutoRepeat()) { if (option->isTreeModeSelected()) { if (_selectedPos != nullptr) { _selectedPos->_y -= option->translationIncrement(); _selectedPos->_zPoint = -9999; updateCylinderPosition(_selectedPos); redrawOverlayAnd3D(); } } else { _dataContainer->_transY -= option->translationIncrement(); _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); redrawOverlayAnd3D(); } } return true; } if(e->key() == Qt::Key_Left) { if(!e->isAutoRepeat()) { if (option->isTreeModeSelected()) { if (_selectedPos != nullptr) { _selectedPos->_x -= option->translationIncrement(); _selectedPos->_zPoint = -9999; updateCylinderPosition(_selectedPos); redrawOverlayAnd3D(); } } else { _dataContainer->_transX -= option->translationIncrement(); _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); redrawOverlayAnd3D(); } } return true; } if(e->key() == Qt::Key_Right) { if(!e->isAutoRepeat()) { if (option->isTreeModeSelected()) { if (_selectedPos != nullptr) { _selectedPos->_x += option->translationIncrement(); _selectedPos->_zPoint = -9999; updateCylinderPosition(_selectedPos); redrawOverlayAnd3D(); } } else { _dataContainer->_transX += option->translationIncrement(); _drawManagerCylinder->setTranslation(_dataContainer->_transX, _dataContainer->_transY); option->setTranslation(_dataContainer->_transX, _dataContainer->_transY); updateAllCylindersPosition(); redrawOverlayAnd3D(); } } return true; } return false; } bool ONF_ActionAdjustPlotPosition02::keyReleaseEvent(QKeyEvent *e) { Q_UNUSED(e); return false; } void ONF_ActionAdjustPlotPosition02::draw(GraphicsViewInterface &view, PainterInterface &painter) { QColor oldColor = painter.getColor(); if (_apex) { QMapIterator it(_dataContainer->_maximaPoints); while (it.hasNext()) { it.next(); Eigen::Vector3d maxima = it.value(); if (it.key()== _currentApex) { painter.setColor(_selectedApexColor); } else { painter.setColor(_apexColor); } if (_mode3d) { painter.drawPartOfSphere(maxima(0), maxima(1), maxima(2), _apexSize, -M_PI, M_PI, -M_PI, M_PI, true); } else { Eigen::Vector3d center(maxima(0), maxima(1), _minZ + 0.1); Eigen::Vector3d dir(0, 0, 1); painter.drawCylinder3D(center, dir, _apexSize, 0.1); } } } if (_drawPlot) { painter.setColor(Qt::white); if (_mode3d) { for (double z = _minZ ; z <= _maxZ ; z += 1.0) { Eigen::Vector3d center(_dataContainer->_xPlot + _dataContainer->_transX, _dataContainer->_yPlot + _dataContainer->_transY, z); Eigen::Vector3d dir(0, 0, 1); painter.drawCircle3D(center, dir, _dataContainer->_radiusPlot); } } else { Eigen::Vector3d center(_dataContainer->_xPlot + _dataContainer->_transX, _dataContainer->_yPlot + _dataContainer->_transY, _minZ + 0.1); Eigen::Vector3d dir(0, 0, 1); painter.drawCircle3D(center, dir, _dataContainer->_radiusPlot); } } for (int i = 0 ; i < _cylinders.size() ; i++) { CT_Cylinder* cyl = (CT_Cylinder*)_cylinders.at(i); if (cyl->getRadius()*200.0 >= _dbhMin) { cyl->draw(view, painter); } } if (_currentPoint(0) < std::numeric_limits::max() && _currentApex == std::numeric_limits::max()) { painter.setColor(_selectedApexColor); painter.drawPartOfSphere(_currentPoint(0), _currentPoint(1), _currentPoint(2),_apexSize, -M_PI, M_PI, -M_PI, M_PI, true); //painter.drawCube(_currentPoint(0) - size, _currentPoint(1) - size, _currentPoint(2) - size,_currentPoint(0) + size, _currentPoint(1) + size, _currentPoint(2) + size, GL_FRONT_AND_BACK, GL_FILL); painter.setColor(oldColor); } } void ONF_ActionAdjustPlotPosition02::drawOverlay(GraphicsViewInterface &view, QPainter &painter) { Q_UNUSED(view); ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); painter.save(); int add = painter.fontMetrics().height()+2; int y = add; QString txt; bool showLog = _previousSelectedPos != _selectedPos; _previousSelectedPos = _selectedPos; QString logMessage = ""; if (showLog && _selectedPos == nullptr) { logMessage.append("-------------------------------------
"); logMessage.append(tr("No selected Tree
")); PS_LOG->addMessage(LogInterface::info, LogInterface::action, logMessage); } if (_selectedPos != nullptr) { if (showLog) { logMessage.append("-------------------------------------
"); logMessage.append("Selected Tree informations:
"); } painter.setPen(QColor(255,255,255)); txt = QString("Selected Tree: %1").arg(_selectedPos->_idTree); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("Plot: %1").arg(_selectedPos->_idPlot); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("DBH: %1 cm").arg(_selectedPos->_dbh); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("H: %1 m").arg(_selectedPos->_height); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("Species: %1").arg(_selectedPos->_species); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("Comment: %1").arg(_selectedPos->_comment); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} } if (_currentPoint(0) < std::numeric_limits::max()) { y += add; if (showLog) {logMessage.append(QString("
"));} if (_currentApex < std::numeric_limits::max()) { txt = QString("Selected Apex:"); } else { txt = QString("Selected Point:"); } painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("X: %1").arg(QString::number(_currentPoint(0), 'f', 2)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("Y: %1").arg(QString::number(_currentPoint(1), 'f', 2)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} txt = QString("Z: %1").arg(QString::number(_currentPoint(2), 'f', 2)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} double val = _currentPoint(2); if (_dataContainer->_dtm != nullptr) { val = _dataContainer->_dtm->valueAtCoords(_currentPoint(0),_currentPoint(1)); if (val != _dataContainer->_dtm->NA()) { val = _currentPoint(2) - val; } } txt = QString("H: %1").arg(QString::number(val, 'f', 2)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} if (_selectedPos != nullptr) { y += add; if (showLog) {logMessage.append(QString("
"));} val = sqrt(pow((_selectedPos->_x + _dataContainer->_transX) - _currentPoint(0), 2) + pow((_selectedPos->_y + _dataContainer->_transY) - _currentPoint(1), 2)); txt = QString("Distance: %1 m").arg(QString::number(val, 'f', 2)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt)+2, add, QColor(0,0,0,76)); painter.drawText(2, y, txt); y += add; if (showLog) {logMessage.append(QString("%1
").arg(txt));} } } if (option->colorBySpecies()) { y += add; QMapIteratorit(_dataContainer->_spColors); while (it.hasNext()) { it.next(); txt = QString(" : %1").arg(it.key()); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().width(txt) + painter.fontMetrics().height() + 4, add, QColor(0,0,0,76)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().height(), painter.fontMetrics().height(), it.value()); painter.drawText(painter.fontMetrics().height() + 2, y, txt); y += add; } } if (showLog) { PS_LOG->addMessage(LogInterface::info, LogInterface::action, logMessage); } // if (_currentPoint(0) < std::numeric_limits::max()) // { // painter.setPen(QColor(255,255,255,127)); // QString xstr = QString::number(_currentPoint(0), 'f', 2); // QString ystr = QString::number(_currentPoint(1), 'f', 2); // txt = QString("Selected points: X=%1 ; Y=%2").arg(xstr).arg(ystr); // painter.drawText(2, y, txt); // y += add; // } painter.restore(); } CT_AbstractAction* ONF_ActionAdjustPlotPosition02::copy() const { return new ONF_ActionAdjustPlotPosition02(_dataContainer); } ONF_CoRegistration_TreePosition* ONF_ActionAdjustPlotPosition02::getPositionFromPoint(Eigen::Vector3d &point) { double minDist = std::numeric_limits::max(); ONF_CoRegistration_TreePosition* pos = nullptr; for (int i = 0 ; i < _dataContainer->_positions.size() ; i++) { ONF_CoRegistration_TreePosition* treePos = _dataContainer->_positions.at(i); double x = treePos->_x + _dataContainer->_transX; double y = treePos->_y + _dataContainer->_transY; double distance = sqrt(pow(x - point(0), 2) + pow(y - point(1), 2)); if (distance < minDist) { minDist = distance; pos = treePos; } } return pos; } ONF_CoRegistration_TreePosition* ONF_ActionAdjustPlotPosition02::getPositionFromDirection(Eigen::Vector3d &origin, Eigen::Vector3d &direction) { ONF_ActionAdjustPlotPositionOptions02 *option = (ONF_ActionAdjustPlotPositionOptions02*)optionAt(0); double minDist = std::numeric_limits::max(); ONF_CoRegistration_TreePosition* pos = nullptr; for (int i = 0 ; i < _dataContainer->_positions.size() ; i++) { ONF_CoRegistration_TreePosition* treePos = _dataContainer->_positions.at(i); double x = treePos->_x + _dataContainer->_transX; double y = treePos->_y + _dataContainer->_transY; float zbase = 0; if (_dataContainer->_dtm != nullptr) { zbase = _dataContainer->_dtm->valueAtCoords(x, y); if (zbase == _dataContainer->_dtm->NA()) { zbase = 0; } } double treeHeight = treePos->_height; if (option->isFixedHeight()) { treeHeight = option->fixedHeight(); } treeHeight += zbase; for (double h = zbase ; h < treeHeight ; h += 0.1) { Eigen::Vector3d point(x, y, h); double distance = CT_MathPoint::distancePointLine(point, direction, origin); if (distance < minDist) { minDist = distance; pos = treePos; } } } if (minDist > 5.0) {return nullptr;} return pos; } void ONF_ActionAdjustPlotPosition02::getApexPositionFromDirection(Eigen::Vector3d &origin, Eigen::Vector3d &direction, Eigen::Vector3d &apex, qint32 &apexID) { double minDist = std::numeric_limits::max(); Eigen::Vector3d selectedApex; qint32 selectedApexId = std::numeric_limits::max(); QMapIterator it(_dataContainer->_maximaPoints); while (it.hasNext()) { it.next(); Eigen::Vector3d apex = it.value(); double distance = CT_MathPoint::distancePointLine(apex, direction, origin); if (distance < minDist) { minDist = distance; selectedApex = apex; selectedApexId = it.key(); } } if (minDist > 5.0) {return;} apex = selectedApex; apexID = selectedApexId; } bool ONF_ActionAdjustPlotPosition02::getCoordsForMousePosition(QPoint p, double &x, double &y) { Eigen::Vector3d origin, direction; GraphicsViewInterface *view = graphicsView(); view->convertClickToLine(p, origin, direction); if (direction.z() == 0) {return false;} double coef = (0.0 - origin.z())/direction.z(); x = origin.x() + coef*direction.x(); y = origin.y() + coef*direction.y(); return true; }