//########################################################################## //# # //# CLOUDCOMPARE # //# # //# This program is free software; you can redistribute it and/or modify # //# it under the terms of the GNU General Public License as published by # //# the Free Software Foundation; version 2 or later of the License. # //# # //# This program 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. # //# # //# COPYRIGHT: SAGE INGENIERIE # //# # //########################################################################## #include "ccPlaneEditDlg.h" //local #include "mainwindow.h" //common #include //qCC_db #include #include //Qt #include //semi-persistent parameters static double s_dip = 0; static double s_dipDir = 0; static double s_width = 10.0; static double s_height = 10.0; static bool s_upward = true; static CCVector3d s_center(0, 0, 0); ccPlaneEditDlg::ccPlaneEditDlg(ccPickingHub* pickingHub, QWidget* parent) : QDialog(parent) , Ui::PlaneEditDlg() , m_pickingWin(nullptr) , m_associatedPlane(nullptr) , m_pickingHub(pickingHub) { assert(pickingHub); setModal(false); setupUi(this); //restore semi-persistent parameters dipDoubleSpinBox->setValue(s_dip); dipDirDoubleSpinBox->setValue(s_dipDir); upwardCheckBox->setChecked(s_upward); onDipDirChanged(0); //0 = fake argument wDoubleSpinBox->setValue(s_width); hDoubleSpinBox->setValue(s_height); cxAxisDoubleSpinBox->setValue(s_center.x); cyAxisDoubleSpinBox->setValue(s_center.y); czAxisDoubleSpinBox->setValue(s_center.z); connect(pickCenterToolButton, &QCheckBox::toggled, this, &ccPlaneEditDlg::pickPointAsCenter); connect(upwardCheckBox, &QCheckBox::toggled, this, &ccPlaneEditDlg::onDipDirModified); connect(dipDoubleSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &ccPlaneEditDlg::onDipDirChanged); connect(dipDirDoubleSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &ccPlaneEditDlg::onDipDirChanged); connect(nxDoubleSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &ccPlaneEditDlg::onNormalChanged); connect(nyDoubleSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &ccPlaneEditDlg::onNormalChanged); connect(nzDoubleSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &ccPlaneEditDlg::onNormalChanged); connect(buttonBox, &QDialogButtonBox::accepted, this, &ccPlaneEditDlg::saveParamsAndAccept); connect(buttonBox, &QDialogButtonBox::rejected, this, &ccPlaneEditDlg::deleteLater); //auto disable picking mode on quit connect(this, &QDialog::finished, [&]() { if (pickCenterToolButton->isChecked()) pickCenterToolButton->setChecked(false); } ); } ccPlaneEditDlg::~ccPlaneEditDlg() { assert(!pickCenterToolButton->isChecked()); } void ccPlaneEditDlg::saveParamsAndAccept() { //save semi-persistent parameters if (!m_associatedPlane) { s_dip = dipDoubleSpinBox->value(); s_dipDir = dipDirDoubleSpinBox->value(); s_upward = upwardCheckBox->isChecked(); s_width = wDoubleSpinBox->value(); s_height = hDoubleSpinBox->value(); s_center.x = cxAxisDoubleSpinBox->value(); s_center.y = cyAxisDoubleSpinBox->value(); s_center.z = czAxisDoubleSpinBox->value(); } //edition mode if (m_associatedPlane) { updatePlane(m_associatedPlane); if (MainWindow::TheInstance()) MainWindow::TheInstance()->updatePropertiesView(); m_associatedPlane->redrawDisplay(); } else //creation { PointCoordinateType width = static_cast(wDoubleSpinBox->value()); PointCoordinateType height = static_cast(hDoubleSpinBox->value()); ccPlane* plane = new ccPlane(width, height); updatePlane(plane); if (m_pickingWin) { plane->setDisplay(m_pickingWin); } if (MainWindow::TheInstance()) { MainWindow::TheInstance()->addToDB(plane); } else { delete plane; plane = nullptr; } } accept(); deleteLater(); } void ccPlaneEditDlg::onDipDirModified(bool) { onDipDirChanged(0); //0 = fake argument } void ccPlaneEditDlg::onDipDirChanged(double) { double dip = dipDoubleSpinBox->value(); double dipDir = dipDirDoubleSpinBox->value(); bool upward = upwardCheckBox->isChecked(); CCVector3 Nd = ccNormalVectors::ConvertDipAndDipDirToNormal(static_cast(dip), static_cast(dipDir), upward); nxDoubleSpinBox->blockSignals(true); nyDoubleSpinBox->blockSignals(true); nzDoubleSpinBox->blockSignals(true); nxDoubleSpinBox->setValue(Nd.x); nyDoubleSpinBox->setValue(Nd.y); nzDoubleSpinBox->setValue(Nd.z); nxDoubleSpinBox->blockSignals(false); nyDoubleSpinBox->blockSignals(false); nzDoubleSpinBox->blockSignals(false); } void ccPlaneEditDlg::onNormalChanged(double) { CCVector3 Nd; Nd.x = nxDoubleSpinBox->value(); Nd.y = nyDoubleSpinBox->value(); Nd.z = nzDoubleSpinBox->value(); Nd.normalize(); PointCoordinateType dip = 0; PointCoordinateType dipDir = 0; ccNormalVectors::ConvertNormalToDipAndDipDir(Nd, dip, dipDir); dipDoubleSpinBox->blockSignals(true); dipDirDoubleSpinBox->blockSignals(true); upwardCheckBox->blockSignals(true); dipDoubleSpinBox->setValue(dip); dipDirDoubleSpinBox->setValue(dipDir); upwardCheckBox->setChecked(Nd.z >= 0); dipDoubleSpinBox->blockSignals(false); dipDirDoubleSpinBox->blockSignals(false); upwardCheckBox->blockSignals(false); } void ccPlaneEditDlg::pickPointAsCenter(bool state) { if (!m_pickingHub) { return; } if (state) { if (!m_pickingHub->addListener(this, true)) { ccLog::Error("Can't start the picking process (another tool is using it)"); state = false; } } else { m_pickingHub->removeListener(this); } pickCenterToolButton->blockSignals(true); pickCenterToolButton->setChecked(state); pickCenterToolButton->blockSignals(false); } void ccPlaneEditDlg::onItemPicked(const PickedItem& pi) { if (!pi.entity) { return; } m_pickingWin = m_pickingHub->activeWindow(); cxAxisDoubleSpinBox->setValue(pi.P3D.x); cyAxisDoubleSpinBox->setValue(pi.P3D.y); czAxisDoubleSpinBox->setValue(pi.P3D.z); pickCenterToolButton->setChecked(false); } void ccPlaneEditDlg::initWithPlane(ccPlane* plane) { m_associatedPlane = plane; if (!plane) { assert(false); return; } CCVector3 N = plane->getNormal(); //init the dialog nxDoubleSpinBox->blockSignals(true); nyDoubleSpinBox->blockSignals(true); nzDoubleSpinBox->blockSignals(true); nxDoubleSpinBox->setValue(N.x); nyDoubleSpinBox->setValue(N.y); nzDoubleSpinBox->setValue(N.z); nxDoubleSpinBox->blockSignals(false); nyDoubleSpinBox->blockSignals(false); nzDoubleSpinBox->blockSignals(false); onNormalChanged(0); //PointCoordinateType dip = 0, dipDir = 0; //ccNormalVectors::ConvertNormalToDipAndDipDir(N, dip, dipDir); //dipDoubleSpinBox->setValue(dip); //dipDirDoubleSpinBox->setValue(dipDir); //upwardCheckBox->setChecked(N.z >= 0); wDoubleSpinBox->setValue(plane->getXWidth()); hDoubleSpinBox->setValue(plane->getYWidth()); CCVector3 C = plane->getCenter(); cxAxisDoubleSpinBox->setValue(C.x); cyAxisDoubleSpinBox->setValue(C.y); czAxisDoubleSpinBox->setValue(C.z); } void ccPlaneEditDlg::updatePlane(ccPlane* plane) { if (!plane) { assert(false); return; } double dip = dipDoubleSpinBox->value(); double dipDir = dipDirDoubleSpinBox->value(); bool upward = upwardCheckBox->isChecked(); PointCoordinateType width = static_cast(wDoubleSpinBox->value()); PointCoordinateType height = static_cast(hDoubleSpinBox->value()); CCVector3 Nd = ccNormalVectors::ConvertDipAndDipDirToNormal(static_cast(dip), static_cast(dipDir), upward); CCVector3 Cd { static_cast(cxAxisDoubleSpinBox->value()), static_cast(cyAxisDoubleSpinBox->value()), static_cast(czAxisDoubleSpinBox->value()) }; CCVector3 N = plane->getNormal(); CCVector3 C = plane->getCenter(); //shall we transform (translate and / or rotate) the plane? ccGLMatrix trans; bool needToApplyRot = (std::abs(N.dot(Nd) - CCCoreLib::PC_ONE) > std::numeric_limits::epsilon()); bool needToApplyTrans = (needToApplyRot || ((C - Cd).norm2d() != 0)); if (needToApplyTrans) { trans.setTranslation(-C); } if (needToApplyRot) { ccGLMatrix rotation; //special case: plane parallel to XY if (std::abs(N.z) > CCCoreLib::PC_ONE - std::numeric_limits::epsilon()) { ccGLMatrix rotX; rotX.initFromParameters( CCCoreLib::DegreesToRadians( -dip ), CCVector3(1, 0, 0), CCVector3(0, 0, 0) ); //plunge ccGLMatrix rotZ; rotZ.initFromParameters( CCCoreLib::DegreesToRadians( dipDir ), CCVector3(0, 0, -1), CCVector3(0, 0, 0) ); rotation = rotZ * rotX; } else //general case { rotation = ccGLMatrix::FromToRotation(N, Nd); } trans = rotation * trans; } if (needToApplyTrans) { trans.setTranslation(trans.getTranslationAsVec3D() + Cd); } if (needToApplyRot || needToApplyTrans) { plane->applyGLTransformation_recursive(&trans); ccLog::Print("[Plane edit] Applied transformation matrix:"); ccLog::Print(trans.toString(12, ' ')); //full precision } if ( plane->getXWidth() != width || plane->getYWidth() != height) { plane->setXWidth(width, false); plane->setYWidth(height, true); } }