/**************************************************************************** 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_actionadjustplotposition02.h" #include "documentinterface.h" #include "painterinterface.h" #include "ct_log/ct_logmanager.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 #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); _saveON = false; _trunkPointsDensity = nullptr; } ONF_ActionAdjustPlotPosition02::~ONF_ActionAdjustPlotPosition02() { document()->removeAllItemDrawable(); qDeleteAll(_cylinders); _cylinders.clear(); delete _drawManagerCylinder; delete _drawManagerDSM; delete _trunkPointsDensity; } 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); } 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() { _saveON = false; 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)), this, SLOT(updateColorization(bool))); connect(option, SIGNAL(askForTranslation(bool)), this, SLOT(applyTranslation(bool))); connect(option, SIGNAL(setGradient(bool, QString)), this, SLOT(setGradient(bool, QString))); 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(autoComputeTranslationFromCrowns())); connect(option, SIGNAL(computeAutoFitTrunks()), this, SLOT(autoComputeTranslationFromTrunkPoints())); connect(option, SIGNAL(saveSettings()), this, SLOT(saveSettings())); // 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, double(pos->_height) / 2.0); if (_dataContainer->_dtm != nullptr) { float zbase = _dataContainer->_dtm->valueAtCoords(pos->_x + _dataContainer->_transX, pos->_y + _dataContainer->_transY); if (!qFuzzyCompare(zbase, _dataContainer->_dtm->NA())) { center(2) += double(zbase); } } Eigen::Vector3d dir(0, 0, 1); CT_Cylinder* cyl = new CT_Cylinder(new CT_CylinderData(center, dir, double(pos->_dbh) / 200.0, double(pos->_height))); cyl->setBaseDrawManager(_drawManagerCylinder); _drawManagerCylinder->addCylinderColor(cyl, pos->_color); _cylinders.append(cyl); pos->_cyl = cyl; //document()->addItemDrawable(*cyl); } std::sort(_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(); delete _trunkPointsDensity; _trunkPointsDensity = CT_Image2D::createImage2DFromXYCoords(_dataContainer->_dsm->minX(), _dataContainer->_dsm->minY(), _dataContainer->_dsm->maxX(), _dataContainer->_dsm->maxY(), 0.10, 0, -1, 0); for (int i = 0 ; i < _dataContainer->_scenes.size() ; i++) { CT_AbstractItemDrawableWithPointCloud* scene = static_cast(_dataContainer->_scenes.at(i)); const CT_AbstractPointCloudIndex *pointCloudIndex = scene->pointCloudIndex(); CT_StdLASPointsAttributesContainer* LASAttributes = _dataContainer->_LASattributes.at(i); CT_PointsAttributesScalarTemplated* heightAttributes = _dataContainer->_heightAttributes.at(i); CT_AbstractPointAttributesScalar* attributeIntensity = nullptr; CT_AbstractPointAttributesScalar* returnNumber = nullptr; CT_AbstractPointAttributesScalar* numberOfReturn = nullptr; if (LASAttributes != nullptr) { attributeIntensity = static_cast(LASAttributes->pointsAttributesAt(CT_LasDefine::Intensity)); returnNumber = static_cast(LASAttributes->pointsAttributesAt(CT_LasDefine::Return_Number)); numberOfReturn = static_cast(LASAttributes->pointsAttributesAt(CT_LasDefine::Number_of_Returns)); } CT_PointIterator itP(pointCloudIndex); while(itP.hasNext()) { const CT_Point &point = itP.next().currentPoint(); const size_t index = itP.currentGlobalIndex(); if (point(2) > _maxZ) {_maxZ = point(2);} if (point(2) < _minZ) {_minZ = point(2);} if (heightAttributes != nullptr) { double h = heightAttributes->scalarAsDoubleAt(index); if (h > _maxH) {_maxH = h;} if (h < _minH) {_minH = h;} if (h >= 0.5 && h <= 8.0 && (returnNumber->scalarAsDoubleAt(index) == numberOfReturn->scalarAsDoubleAt(index))) { _trunkPointsDensity->addValueAtCoords(point(0), point(1), 1); } } else { if (point(2) >= 0.5 && point(2) <= 8.0 && (returnNumber->scalarAsDoubleAt(index) == numberOfReturn->scalarAsDoubleAt(index))) { _trunkPointsDensity->addValueAtCoords(point(0), point(1), 1); } } if (LASAttributes != nullptr) { double intensity = attributeIntensity->scalarAsDoubleAt(index); if (intensity > _maxI) {_maxI = intensity;} if (intensity < _minI) {_minI = intensity;} } } if (heightAttributes == nullptr) { _minH = _minZ; _maxH = _maxZ; } _rangeZ = _maxZ - _minZ; _rangeH = _maxH - _minH; _rangeI = _maxI - _minI; _drawManagerDSM->setRefZ(_minZ); _drawManagerCylinder->setRefZ(_minZ + 0.1); document()->addItemDrawable(*scene); } _trunkPointsDensity->computeMinMax(); option->setHminHmax(_minH, _maxH); GraphicsViewInterface* view = dynamic_cast(document()->views().first()); for (int i = 0 ; i < _dataContainer->_scenes.size() ; i++) { CT_AbstractItemDrawableWithPointCloud* scene = static_cast(_dataContainer->_scenes.at(i)); _objectsModifierList.append(view->createObjectsModifierForItem(scene, GOT_PointGlobalCloud)); } document()->redrawGraphics(); GraphicsViewOptionsInterface& viewOptions = view->getOptions(); viewOptions.setPointSize(3); viewOptions.setCameraType("ORTHOGRAPHIC"); view->camera()->setOrientation(0, 0, 0, 1); colorizePoints(_currentZGradient); view->camera()->fixCameraCenterToItemsBarycenter(); view->camera()->fitCameraToVisibleItems(); changeHighlightedNumber(6); view->setOptions(&viewOptions); document()->removeAllItemDrawable(); _dataContainer->_dsm->setAlternativeDrawManager(_drawManagerDSM); document()->addItemDrawable(*(_dataContainer->_dsm)); view->active2DView(true); loadSettings(); updateColorization(option->intensitySelected()); _saveON = 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::updateCylinderPosition(ONF_CoRegistration_TreePosition* pos) { Eigen::Vector3d newCenter(pos->_x, pos->_y, double(pos->_height) / 2.0); if (_dataContainer->_dtm != nullptr) { float zbase = _dataContainer->_dtm->valueAtCoords(pos->_x + _dataContainer->_transX, pos->_y + _dataContainer->_transY); if (!qFuzzyCompare(zbase, _dataContainer->_dtm->NA())) { newCenter(2) += double(zbase); } } CT_CylinderData* cylData = const_cast(static_cast((static_cast(pos->_cyl))->getPointerData())); cylData->setCenter(newCenter); if (qFuzzyCompare(pos->_x, pos->_originalX) && qFuzzyCompare(pos->_y, pos->_originalY)) { pos->_moved = false; cylData->setCircleError(0); } else { pos->_moved = true; cylData->setCircleError(1); } } void ONF_ActionAdjustPlotPosition02::autoComputeTranslationFromCrowns() { ONF_ActionAdjustPlotPositionOptions02 *option = static_cast(optionAt(0)); double bestCorr = std::numeric_limits::max(); double bestDx = 0; double bestDy = 0; double maxError = option->autoFitMaxError(); 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) { int size = _dataContainer->_positions.size(); float sumAbsDelta = 0; float sumWeight = 0; for (int cn = 0 ; cn < size ; cn++) { ONF_CoRegistration_TreePosition* pos = _dataContainer->_positions.at(cn); Eigen::Vector2d posCoord(pos->_x, pos->_y); posCoord(0) += dx; posCoord(1) += dy; double dsmVal = _dataContainer->_dsm->valueAtCoords(posCoord(0), posCoord(1)); double mntVal = 0; if (_dataContainer->_dtm != nullptr) { mntVal = _dataContainer->_dtm->valueAtCoords(posCoord(0), posCoord(1)); if (mntVal == _dataContainer->_dtm->NA()) {mntVal = 0;} } float hVal = dsmVal - mntVal; float weight = pos->_dbh*pos->_dbh; sumAbsDelta += weight*std::fabs(hVal - pos->_height); sumWeight += weight; } if (sumWeight > 0) { double caseCorr = sumAbsDelta / sumWeight; if (caseCorr < bestCorr) { bestCorr = caseCorr; bestDx = dx; bestDy = dy; } } } } } if (bestCorr < std::numeric_limits::max()) { _dataContainer->_transX = bestDx; _dataContainer->_transY = bestDy; option->setTranslation(bestDx, bestDy); _drawManagerCylinder->setTranslation(bestDx, bestDy); updateAllCylindersPosition(); redrawOverlayAnd3D(); PS_LOG->addMessage(LogInterface::info, LogInterface::action, tr("Crown AutoFit Complete. Score = %1").arg(bestCorr)); } else { PS_LOG->addMessage(LogInterface::warning, LogInterface::action, tr("Crown AutoFit failed.")); } } void ONF_ActionAdjustPlotPosition02::autoComputeTranslationFromTrunkPoints() { ONF_ActionAdjustPlotPositionOptions02 *option = static_cast(optionAt(0)); int bestCorr = 0; double bestDx = 0; double bestDy = 0; double maxError = option->autoFitMaxError(); double radius = option->autoFitRadius(); int delta = std::ceil(radius / _trunkPointsDensity->resolution()); if (delta < 1) {delta = 1;} 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) { int size = _dataContainer->_positions.size(); int nbPts = 0; for (int cn = 0 ; cn < size ; cn++) { ONF_CoRegistration_TreePosition* pos = _dataContainer->_positions.at(cn); Eigen::Vector2d posCoord(pos->_x, pos->_y); posCoord(0) += dx; posCoord(1) += dy; size_t index; if (_trunkPointsDensity->indexAtCoords(posCoord(0), posCoord(1), index)) { int xxc, yyc; if (_trunkPointsDensity->indexToGrid(index, xxc, yyc)) { int nbPtsPos = 0; for (int xx = xxc - delta ; xx <= xxc + delta ; xx++) { for (int yy = yyc - delta ; yy <= yyc + delta ; yy++) { Eigen::Vector3d center; if (_trunkPointsDensity->getCellCenterCoordinates(xx, yy, center)) { double dist = sqrt(pow(posCoord(0) - center(0), 2) + pow(posCoord(1) - center(1), 2)); if (dist < radius) { nbPtsPos += _trunkPointsDensity->value(xx, yy); } } } } if (nbPtsPos > 10) {nbPtsPos = 10;} nbPts += nbPtsPos; } } } if (nbPts > bestCorr) { bestCorr = nbPts; bestDx = dx; bestDy = dy; } } } } if (bestCorr > 0) { _dataContainer->_transX = bestDx; _dataContainer->_transY = bestDy; option->setTranslation(bestDx, bestDy); _drawManagerCylinder->setTranslation(bestDx, bestDy); updateAllCylindersPosition(); redrawOverlayAnd3D(); PS_LOG->addMessage(LogInterface::info, LogInterface::action, tr("Trunk AutoFit Complete. Score = %1").arg(bestCorr)); } else { PS_LOG->addMessage(LogInterface::warning, LogInterface::action, tr("Trunk AutoFit failed.")); } } 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 = static_cast(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 = static_cast(_dataContainer->_scenes.at(i)); document()->addItemDrawable(*scene); } } else { document()->addItemDrawable(*(_dataContainer->_dsm)); } updateColorization(_colorizeByIntensity); } void ONF_ActionAdjustPlotPosition02::updateColorization(bool colorizeByIntensity) { if (_mode3d) { _colorizeByIntensity = colorizeByIntensity; if (_colorizeByIntensity) { colorizePoints(_currentIGradient); } else { colorizePoints(_currentZGradient); } } else { document()->removeAllItemDrawable(); _drawManagerDSM->setGradient(&_currentZGradient); document()->addItemDrawable(*(_dataContainer->_dsm)); } redrawOverlayAnd3D(); } void ONF_ActionAdjustPlotPosition02::applyTranslation(bool reset) { ONF_ActionAdjustPlotPositionOptions02 *option = static_cast(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) { ONF_ActionAdjustPlotPositionOptions02 *option = static_cast(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"; } } saveSettings(); updateColorization(_colorizeByIntensity); } 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) { ONF_ActionAdjustPlotPositionOptions02 *option = static_cast(optionAt(0)); GraphicsViewInterface *view = graphicsView(); for (int i = 0 ; i < _dataContainer->_scenes.size() && _rangeZ > 0 ; i++) { CT_AbstractItemDrawableWithPointCloud* scene = static_cast(_dataContainer->_scenes.at(i)); const CT_AbstractPointCloudIndex *pointCloudIndex = scene->pointCloudIndex(); 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; if (LASAttributes != nullptr) { attributeIntensity = static_cast(LASAttributes->pointsAttributesAt(CT_LasDefine::Intensity)); attributeR = static_cast(LASAttributes->pointsAttributesAt(CT_LasDefine::Return_Number)); attributeN = static_cast(LASAttributes->pointsAttributesAt(CT_LasDefine::Number_of_Returns)); } 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;} double h = 0; if (heightAttributes != nullptr) { h = heightAttributes->scalarAsDoubleAt(index); ratio = (h - _minH) / _rangeH; if (h < _minH) {ratio = 0;} if (h > _maxH) {ratio = 1;} } if (LASAttributes != nullptr) { if (_colorizeByIntensity && attributeIntensity != nullptr) { double minI = _minI; double maxI = _maxI; if (minI > maxI) {minI = maxI;} double rangeI = maxI - minI; double intensity = attributeIntensity->scalarAsDoubleAt(index); ratio = (intensity - minI) / rangeI; if (intensity < minI) {ratio = 0;} if (intensity > maxI) {ratio = 1;} } if (option->lastOnly() && attributeN != nullptr && attributeR != nullptr) { double Natt = attributeN->scalarAsDoubleAt(index); double Ratt = attributeR->scalarAsDoubleAt(index); if (qFuzzyCompare(Natt, 1) || !qFuzzyCompare(Natt, Ratt)) { visible = false; } } } double zmin = _minZ + option->hmin(); double zmax = _minZ + option->hmax(); if (heightAttributes != nullptr && (h > option->hmax() || h < option->hmin())) { visible = false; } else if (heightAttributes == nullptr && (point(2) > zmax || point(2) < zmin)) { visible = false; } CT_Color color(gradient.intermediateColor(ratio)); 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(); } QString ONF_ActionAdjustPlotPosition02::settingsFileName() { QString name = "AdjustPlotPosition.config"; QString currentDir = "config"; #if defined(__linux__) // Linux currentDir = QDir::homePath() + "/.computree/" + currentDir; #endif QDir dir(currentDir); if (!dir.exists()) {dir.mkpath(".");} name = currentDir + "/" + name; return name; } void ONF_ActionAdjustPlotPosition02::saveSettings() { if (_saveON) { GraphicsViewInterface* view = dynamic_cast(document()->views().first()); GraphicsViewOptionsInterface& viewOption = view->getOptions(); QFile f(settingsFileName()); QTextStream stream(&f); if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { ONF_ActionAdjustPlotPositionOptions02 *option = static_cast(optionAt(0)); QStringList settings = option->getSettings(); settings.append(_currentZGradientName); settings.append(_currentIGradientName); settings.append(QString::number(viewOption.getPointSize(), 'f', 2)); for (int i = 0 ; i < settings.size() ; i++) { stream << settings.at(i) << "\n"; } f.close(); } else { PS_LOG->addMessage(LogInterface::error, LogInterface::action, tr("Erreur : Impossible de créer le fichier de paramètres.")); } } } void ONF_ActionAdjustPlotPosition02::loadSettings() { QFile f(settingsFileName()); QTextStream stream(&f); if (f.exists()) { PS_LOG->addMessage(LogInterface::info, LogInterface::action, tr("Chargement des paramètres précédents.")); if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { GraphicsViewInterface* view = dynamic_cast(document()->views().first()); GraphicsViewOptionsInterface& viewOption = view->getOptions(); ONF_ActionAdjustPlotPositionOptions02 *option = static_cast(optionAt(0)); QStringList settings; QString line; while (!stream.atEnd()) { stream >> line; settings.append(line); } if (settings.size() >= 37) { _currentIGradientName = settings.at(34); _currentZGradientName = settings.at(35); bool ok = false; float pointSize = settings.at(36).toFloat(&ok); if (ok && pointSize > 0) { viewOption.setPointSize(pointSize); view->setOptions(&viewOption); } } option->restoreSettings(settings); f.close(); } else { PS_LOG->addMessage(LogInterface::error, LogInterface::action, tr("Erreur : fichier de paramètres non valide.")); } } } 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 = static_cast(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 = static_cast(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); QRect r(0, 0, 3, 3); r.moveCenter(e->pos()); view->select(r); 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 = static_cast(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) { Eigen::Vector3d dir(0, 0, 1); painter.drawCylinder3D(maxima, dir, _apexSize / 2.0, 0.1); //painter.drawPartOfSphere(maxima(0), maxima(1), maxima(2), _apexSize, -M_PI, M_PI, -M_PI, M_PI, true); // performance issue } 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 = static_cast(_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 = static_cast(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().horizontalAdvance(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().horizontalAdvance(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(double(_selectedPos->_dbh)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().horizontalAdvance(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(double(_selectedPos->_trueheight)); painter.fillRect(2, y - painter.fontMetrics().height(), painter.fontMetrics().horizontalAdvance(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().horizontalAdvance(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().horizontalAdvance(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().horizontalAdvance(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().horizontalAdvance(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().horizontalAdvance(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().horizontalAdvance(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 = double(_dataContainer->_dtm->valueAtCoords(_currentPoint(0),_currentPoint(1))); if (!qFuzzyCompare(val, double(_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().horizontalAdvance(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().horizontalAdvance(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().horizontalAdvance(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::createInstance() 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 = static_cast(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 (qFuzzyCompare(zbase, _dataContainer->_dtm->NA())) { zbase = 0; } } double treeHeight = double(treePos->_height); if (option->isFixedHeight()) { treeHeight = option->fixedHeight(); } treeHeight += double(zbase); for (double h = double(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 = Eigen::Vector3d(0.0, 0.0, 0.0); 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 (qFuzzyIsNull(direction.z())) {return false;} double coef = (0.0 - origin.z())/direction.z(); x = origin.x() + coef*direction.x(); y = origin.y() + coef*direction.y(); return true; }