| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909 |
- //##########################################################################
- //# #
- //# 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: EDF R&D / TELECOM ParisTech (ENST-TSI) #
- //# #
- //##########################################################################
- #include "ccClippingBoxTool.h"
- //Local
- #include "ccBoundingBoxEditorDlg.h"
- #include "ccClippingBoxRepeatDlg.h"
- #include "ccContourLinesGenerator.h"
- #include "ccCropTool.h"
- #include "ccGLWindowInterface.h"
- #include "ccReservedIDs.h"
- #include "mainwindow.h"
- #include "db_tree/ccDBRoot.h"
- //qCC_db
- #include <ccClipBox.h>
- #include <ccPointCloud.h>
- #include <ccProgressDialog.h>
- #include <ccRasterGrid.h>
- //Qt
- #include <QMessageBox>
- namespace
- {
- //Last envelope or contour unique ID
- std::vector<unsigned> s_lastContourUniqueIDs;
-
- //Envelope extraction parameters (global)
- double s_maxEnvelopeEdgeLength = -1.0;
- //Meta-data key: origin entity UUID
- constexpr char s_originEntityUUID[] = "OriginEntityUUID";
- //Meta-data key: slice (unique) ID
- constexpr char s_sliceID[] = "SliceID";
- }
- // persistent map of the previous box used for each entity
- struct ccClipBoxParams
- {
- ccBBox box;
- ccGLMatrix trans;
- };
- static QMap< unsigned, ccClipBoxParams > s_lastBoxParams;
- ccClippingBoxTool::ccClippingBoxTool(QWidget* parent)
- : ccOverlayDialog(parent)
- , Ui::ClippingBoxDlg()
- , m_clipBox(nullptr)
- {
- setupUi(this);
- connect(editBoxToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::editBox);
- connect(extractContourToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::extractContour);
- connect(removeLastContourToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::removeLastContour);
- connect(exportButton, &QToolButton::clicked, this, &ccClippingBoxTool::exportSlice);
- connect(exportMultButton, &QToolButton::clicked, this, &ccClippingBoxTool::exportMultSlices);
- connect(resetButton, &QToolButton::clicked, this, &ccClippingBoxTool::reset);
- connect(restoreToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::restoreLastBox);
- connect(closeButton, &QToolButton::clicked, this, &ccClippingBoxTool::closeDialog);
- connect(showBoxToolButton, &QToolButton::toggled, this, &ccClippingBoxTool::toggleBox);
- connect(showInteractorsToolButton, &QToolButton::toggled, this, &ccClippingBoxTool::toggleInteractors);
- connect(thickXDoubleSpinBox, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccClippingBoxTool::thicknessChanged);
- connect(thickYDoubleSpinBox, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccClippingBoxTool::thicknessChanged);
- connect(thickZDoubleSpinBox, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &ccClippingBoxTool::thicknessChanged);
- connect(minusXShiftToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::shiftXMinus);
- connect(plusXShiftToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::shiftXPlus);
- connect(minusYShiftToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::shiftYMinus);
- connect(plusYShiftToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::shiftYPlus);
- connect(minusZShiftToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::shiftZMinus);
- connect(plusZShiftToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::shiftZPlus);
- viewButtonsFrame->setEnabled(true);
- connect(viewUpToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::setTopView);
- connect(viewDownToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::setBottomView);
- connect(viewFrontToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::setFrontView);
- connect(viewBackToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::setBackView);
- connect(viewLeftToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::setLeftView);
- connect(viewRightToolButton, &QToolButton::clicked, this, &ccClippingBoxTool::setRightView);
- s_maxEnvelopeEdgeLength = -1.0;
- //s_lastContourUniqueIDs.clear();
- removeLastContourToolButton->setEnabled(false);
- }
- ccClippingBoxTool::~ccClippingBoxTool()
- {
- if (m_clipBox)
- delete m_clipBox;
- m_clipBox = nullptr;
- }
- void ccClippingBoxTool::editBox()
- {
- if (!m_clipBox)
- return;
- ccBBox box;
- ccGLMatrix transformation;
- m_clipBox->get(box, transformation);
- //shift the box to its real center
- {
- CCVector3 C = box.getCenter();
- CCVector3 realC = transformation * C;
- box += (realC - C);
- ccGLMatrix transMat;
- transMat.setTranslation(-realC);
- transformation.clearTranslation();
- transMat = transformation * transMat;
- transMat.setTranslation(transMat.getTranslationAsVec3D() + realC);
- transformation = transMat;
- }
- ccBoundingBoxEditorDlg bbeDlg(true, false, this); //show the box 'axes' (orientation)
- bbeDlg.setBaseBBox(box, false);
- bbeDlg.showInclusionWarning(false);
- bbeDlg.setWindowTitle("Edit clipping box");
-
- //transformation.invert();
- bbeDlg.setBoxAxes( transformation.getColumnAsVec3D(0),
- transformation.getColumnAsVec3D(1),
- transformation.getColumnAsVec3D(2) );
- if (!bbeDlg.exec())
- return;
- box = bbeDlg.getBox();
- //construct the local box orientation matrix
- {
- CCVector3d X;
- CCVector3d Y;
- CCVector3d Z;
- bbeDlg.getBoxAxes(X, Y, Z);
- //make sure the vectors define an orthogonal basis
- Z = X.cross(Y);
- Y = Z.cross(X);
- X.normalize();
- Y.normalize();
- Z.normalize();
- ccGLMatrixd rotMat;
- rotMat.setColumn(0, X);
- rotMat.setColumn(1, Y);
- rotMat.setColumn(2, Z);
- CCVector3 C = box.getCenter();
- ccGLMatrixd transMat;
- transMat.setTranslation(-C);
- transMat = rotMat * transMat;
- transMat.setTranslation(transMat.getTranslationAsVec3D() + C);
- m_clipBox->setGLTransformation(ccGLMatrix(transMat.data()));
- }
- m_clipBox->setBox(box);
- //onBoxModified(&box); //DGM: automatically called by 'm_clipBox'
- if (m_associatedWin)
- {
- m_associatedWin->redraw();
- }
- }
- void ccClippingBoxTool::toggleInteractors(bool state)
- {
- if (m_clipBox)
- m_clipBox->setSelected(state);
- if (m_associatedWin)
- m_associatedWin->redraw();
- }
- void ccClippingBoxTool::toggleBox(bool state)
- {
- if (m_clipBox)
- m_clipBox->showBox(state);
- if (m_associatedWin)
- m_associatedWin->redraw();
- }
- bool ccClippingBoxTool::addAssociatedEntity(ccHObject* entity)
- {
- if (!entity)
- {
- assert(false);
- return false;
- }
-
- //special case
- if (entity->isGroup())
- {
- for (unsigned i = 0; i < entity->getChildrenNumber(); ++i)
- {
- if (!addAssociatedEntity(entity->getChild(i)))
- {
- return false;
- }
- }
- return true;
- }
- if (!m_associatedWin || !m_clipBox)
- {
- ccLog::Error(QString("[Clipping box] No associated 3D view or no valid clipping box!"));
- return false;
- }
-
- //we don't handle entities associated to another context
- if (entity->getDisplay() != m_associatedWin)
- {
- ccLog::Warning(QString("[Clipping box] Can't use entity '%1' cause it's not displayed in the active 3D view!").arg(entity->getName()));
- return false;
- }
- bool firstEntity = (m_clipBox && m_clipBox->getContainer().getChildrenNumber() == 0);
- if (firstEntity)
- {
- restoreToolButton->setEnabled(false);
- contourGroupBox->setEnabled(false);
- }
- if (!m_clipBox->addAssociatedEntity(entity))
- {
- //error message already issued
- ccLog::Error("An error occurred (see Console)");
- return false;
- }
- if (s_lastBoxParams.contains(entity->getUniqueID()))
- {
- restoreToolButton->setEnabled(true);
- }
- if (entity->isKindOf(CC_TYPES::POINT_CLOUD))
- {
- contourGroupBox->setEnabled(true);
- }
- //force visibility
- entity->setVisible(true);
- entity->setEnabled(true);
- if (m_associatedWin)
- {
- m_associatedWin->redraw();
- }
- //set proper "steps" value for slice thickness editors
- {
- CCVector3 diag = m_clipBox->getBox().getDiagVec();
- thickXDoubleSpinBox->setSingleStep(diag.x / 100.0);
- thickYDoubleSpinBox->setSingleStep(diag.y / 100.0);
- thickZDoubleSpinBox->setSingleStep(diag.z / 100.0);
- }
- s_maxEnvelopeEdgeLength = -1.0;
- s_lastContourUniqueIDs.resize(0);
- removeLastContourToolButton->setEnabled(false);
- return true;
- }
- unsigned ccClippingBoxTool::getNumberOfAssociatedEntity() const
- {
- return m_clipBox ? m_clipBox->getContainer().getChildrenNumber() : 0;
- }
- bool ccClippingBoxTool::linkWith(ccGLWindowInterface* win)
- {
- if (m_associatedWin && m_clipBox)
- {
- // restore the the clipping planes
- m_associatedWin->setClippingPlanesEnabled(true);
- //remove clipping box from previous window
- m_associatedWin->removeFromOwnDB(m_clipBox);
- m_clipBox->disconnect(this);
- delete m_clipBox;
- m_clipBox = nullptr;
- m_associatedWin->redraw();
- }
- if (!ccOverlayDialog::linkWith(win))
- {
- return false;
- }
- if (win)
- {
- if (!m_clipBox)
- {
- m_clipBox = new ccClipBox(QString(), static_cast<unsigned>(ReservedIDs::CLIPPING_BOX));
- m_clipBox->setVisible(true);
- m_clipBox->setEnabled(true);
- m_clipBox->setSelected(showInteractorsToolButton->isChecked());
- connect(m_clipBox, &ccClipBox::boxModified, this, &ccClippingBoxTool::onBoxModified);
- }
- // the clipping box tool doesn't tak the clipping planes into account
- // so we'll disable them temporarily
- m_associatedWin->setClippingPlanesEnabled(false);
- m_associatedWin->addToOwnDB(m_clipBox);
- }
-
- return true;
- }
- bool ccClippingBoxTool::start()
- {
- assert(!m_processing);
- assert(m_associatedWin);
- if (!m_associatedWin || !m_clipBox)
- return false;
- m_clipBox->reset();
- //the user must not close this window!
- m_associatedWin->setUnclosable(true);
- //m_associatedWin->displayNewMessage(QString(), ccGLWindowInterface::UPPER_CENTER_MESSAGE); //clear the area
- //m_associatedWin->displayNewMessage("[Rotation/Translation mode]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
- m_associatedWin->redraw();
- return ccOverlayDialog::start();
- }
- void ccClippingBoxTool::stop(bool state)
- {
- if (m_clipBox)
- {
- if (state && m_clipBox->getContainer().getChildrenNumber())
- {
- //save clip box parameters
- ccClipBoxParams params;
- m_clipBox->get(params.box, params.trans);
- for (unsigned ci = 0; ci != m_clipBox->getContainer().getChildrenNumber(); ++ci)
- {
- s_lastBoxParams[m_clipBox->getContainer().getChild(ci)->getUniqueID()] = params;
- }
- }
- m_clipBox->releaseAssociatedEntities();
- }
- if (m_associatedWin)
- {
- m_associatedWin->setUnclosable(false);
- //m_associatedWin->displayNewMessage("[Rotation/Translation mode OFF]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 2, ccGLWindowInterface::MANUAL_TRANSFORMATION_MESSAGE);
- m_associatedWin->redraw();
- }
- ccOverlayDialog::stop(state);
- }
- void ccClippingBoxTool::removeLastContour()
- {
- if (s_lastContourUniqueIDs.empty())
- return;
- MainWindow* mainWindow = MainWindow::TheInstance();
- if (mainWindow)
- {
- for (size_t i = 0; i < s_lastContourUniqueIDs.size(); ++i)
- {
- ccHObject* obj = mainWindow->db()->find(s_lastContourUniqueIDs[i]);
- if (obj)
- {
- //obj->prepareDisplayForRefresh();
- mainWindow->removeFromDB(obj);
- ccGLWindowInterface* win = mainWindow->getActiveGLWindow();
- if (win)
- win->redraw();
- }
- }
- }
- s_lastContourUniqueIDs.resize(0);
- removeLastContourToolButton->setEnabled(false);
- }
- ccHObject* GetSlice(ccHObject* obj, ccClipBox* clipBox, bool silent)
- {
- assert(clipBox);
- if (!obj)
- {
- assert(false);
- return nullptr;
- }
- if (obj->isKindOf(CC_TYPES::POINT_CLOUD))
- {
- ccGenericPointCloud* inputCloud = ccHObjectCaster::ToGenericPointCloud(obj);
- ccGenericPointCloud::VisibilityTableType selectionTable;
- try
- {
- selectionTable.resize(inputCloud->size());
- }
- catch (const std::bad_alloc&)
- {
- if (!silent)
- {
- ccLog::Error("Not enough memory!");
- }
- return nullptr;
- }
- clipBox->flagPointsInside(inputCloud, &selectionTable);
-
- ccGenericPointCloud* sliceCloud = inputCloud->createNewCloudFromVisibilitySelection(false, &selectionTable, nullptr, true);
- // specific case: all points were selected
- if (sliceCloud == inputCloud)
- {
- sliceCloud = inputCloud->clone();
- }
- if (!sliceCloud)
- {
- if (!silent)
- ccLog::Error("Not enough memory!");
- }
- else if (sliceCloud->size() == 0)
- {
- //ccLog::Warning("Empty slice"); // too many logs
- delete sliceCloud;
- sliceCloud = nullptr;
- }
- return sliceCloud;
- }
- else if (obj->isKindOf(CC_TYPES::MESH))
- {
- const ccGLMatrix* _transformation = nullptr;
- ccGLMatrix transformation;
- if (clipBox->isGLTransEnabled())
- {
- transformation = clipBox->getGLTransformation().inverse();
- _transformation = &transformation;
- }
- const ccBBox& cropBox = clipBox->getBox();
- ccHObject* mesh = ccCropTool::Crop(obj, cropBox, true, _transformation);
- if (!mesh)
- {
- if (!silent)
- ccLog::Error("Failed to segment the mesh!");
- return nullptr;
- }
- return mesh;
- }
- return nullptr;
- }
- void ccClippingBoxTool::exportSlice()
- {
- if (!m_clipBox || !MainWindow::TheInstance())
- return;
- for (unsigned ci = 0; ci != m_clipBox->getContainer().getChildrenNumber(); ++ci)
- {
- ccHObject* obj = m_clipBox->getContainer().getChild(ci);
- if (!obj)
- {
- assert(false);
- continue;
- }
- ccHObject* result = GetSlice(obj, m_clipBox, false);
- if (result)
- {
- result->setName(obj->getName() + QString(".section"));
- result->setDisplay(obj->getDisplay());
- result->prepareDisplayForRefresh();
- if (obj->getParent())
- obj->getParent()->addChild(result);
- MainWindow::TheInstance()->addToDB(result);
- }
- }
- }
- void ccClippingBoxTool::extractContour()
- {
- extractSlicesAndContours(/*singleSliceMode=*/true);
- }
- void ccClippingBoxTool::exportMultSlices()
- {
- extractSlicesAndContours(/*singleSliceMode=*/false);
- }
- static unsigned ComputeGridDimensions( const ccBBox& localBox,
- const bool processDim[3],
- int indexMins[3],
- int indexMaxs[3],
- int gridDim[3],
- const CCVector3& gridOrigin,
- const CCVector3& cellSizePlusGap)
- {
- //compute 'grid' extents in the local clipping box ref.
- for (int i = 0; i < 3; ++i)
- {
- indexMins[i] = 0;
- indexMaxs[i] = 0;
- gridDim[i] = 1;
- }
- unsigned cellCount = 1;
- for (unsigned char d = 0; d < 3; ++d)
- {
- if (processDim[d])
- {
- if (CCCoreLib::LessThanEpsilon(cellSizePlusGap.u[d]))
- {
- ccLog::Error("Box size (plus gap) is null! Can't apply repetitive process!");
- return 0;
- }
- PointCoordinateType a = (localBox.minCorner().u[d] - gridOrigin.u[d]) / cellSizePlusGap.u[d]; //don't forget the user defined gap between 'cells'
- PointCoordinateType b = (localBox.maxCorner().u[d] - gridOrigin.u[d]) / cellSizePlusGap.u[d];
- indexMins[d] = static_cast<int>(floor(a + static_cast<PointCoordinateType>(1.0e-6)));
- indexMaxs[d] = static_cast<int>(ceil(b - static_cast<PointCoordinateType>(1.0e-6))) - 1;
- assert(indexMaxs[d] >= indexMins[d]);
- gridDim[d] = std::max(indexMaxs[d] - indexMins[d] + 1, 1);
- cellCount *= static_cast<unsigned>(gridDim[d]);
- }
- }
- return cellCount;
- }
- bool ccClippingBoxTool::ExtractSlicesAndContours
- (
- const std::vector<ccGenericPointCloud*>& clouds,
- const std::vector<ccGenericMesh*>& meshes,
- ccClipBox& clipBox,
- bool singleSliceMode,
- bool repeatDimensions[3],
- std::vector<ccHObject*>& outputSlices,
- bool extractEnvelopes,
- PointCoordinateType maxEdgeLength,
- ccEnvelopeExtractor::EnvelopeType envelopeType,
- std::vector<ccPolyline*>& outputEnvelopes,
- bool extractLevelSet,
- double levelSetGridStep,
- int levelSetMinVertCount,
- std::vector<ccPolyline*>& levelSet,
- PointCoordinateType gap/*=0*/,
- bool multiPass/*=false*/,
- bool splitEnvelopes/*=false*/,
- bool projectOnBestFitPlane/*=false*/,
- bool visualDebugMode/*=false*/,
- bool generateRandomColors/*=false*/,
- ccProgressDialog* progressDialog/*=nullptr*/)
- {
- //check input
- if (clouds.empty() && meshes.empty())
- {
- assert(false);
- return false;
- }
- //repeat dimensions
- int repeatDimensionsSum = static_cast<int>(repeatDimensions[0])
- + static_cast<int>(repeatDimensions[1])
- + static_cast<int>(repeatDimensions[2]);
- if (!singleSliceMode && repeatDimensionsSum == 0)
- {
- assert(false);
- ccLog::Error("No dimension selected to repeat the segmentation process?!");
- return false;
- }
- if (extractLevelSet && repeatDimensionsSum != 1)
- {
- assert(false);
- ccLog::Error("Only one repeat/flat dimension should be defined for level set extraction");
- extractLevelSet = false;
- }
- //compute the cloud bounding box in the local clipping box ref.
- ccGLMatrix localTrans;
- {
- if (clipBox.isGLTransEnabled())
- localTrans = clipBox.getGLTransformation().inverse();
- else
- localTrans.toIdentity();
- }
- CCVector3 gridOrigin = clipBox.getOwnBB().minCorner();
- CCVector3 cellSize = clipBox.getOwnBB().getDiagVec();
- CCVector3 cellSizePlusGap = cellSize + CCVector3(gap, gap, gap);
- //apply process
- try
- {
- bool error = false;
- bool warningsIssued = false;
- size_t cloudSliceCount = 0;
- if (singleSliceMode)
- {
- //single slice: easy
- outputSlices.reserve(clouds.size());
- for (size_t ci = 0; ci != clouds.size(); ++ci)
- {
- ccHObject* slice = GetSlice(clouds[ci], &clipBox, false);
- if (slice)
- {
- slice->setName(clouds[ci]->getName() + QString(".slice"));
-
- //set meta-data
- slice->setMetaData(s_originEntityUUID, clouds[ci]->getUniqueID());
- slice->setMetaData(s_sliceID, "slice");
- if (slice->isKindOf(CC_TYPES::POINT_CLOUD))
- {
- slice->setMetaData("slice.origin.dim(0)", gridOrigin.x);
- slice->setMetaData("slice.origin.dim(1)", gridOrigin.y);
- slice->setMetaData("slice.origin.dim(2)", gridOrigin.z);
- }
- outputSlices.push_back(slice);
- }
- }
- if (outputSlices.empty())
- {
- //error message already issued
- return false;
- }
- cloudSliceCount = outputSlices.size();
- }
- else //repeat mode
- {
- if (!clouds.empty()) //extract sections from clouds
- {
- //compute 'grid' extents in the local clipping box ref.
- ccBBox localBox;
- for (ccGenericPointCloud* cloud : clouds)
- {
- for (unsigned i = 0; i < cloud->size(); ++i)
- {
- CCVector3 P = *cloud->getPoint(i);
- localTrans.apply(P);
- localBox.add(P);
- }
- }
- int indexMins[3]{ 0, 0, 0 };
- int indexMaxs[3]{ 0, 0, 0 };
- int gridDim[3]{ 0, 0, 0 };
- unsigned cellCount = ComputeGridDimensions(localBox, repeatDimensions, indexMins, indexMaxs, gridDim, gridOrigin, cellSizePlusGap);
- //we'll potentially create up to one (ref.) cloud per input loud and per cell
- std::vector<CCCoreLib::ReferenceCloud*> refClouds;
- refClouds.resize(cellCount * clouds.size(), nullptr);
- if (progressDialog)
- {
- progressDialog->setWindowTitle(tr("Preparing extraction"));
- progressDialog->start();
- progressDialog->show();
- progressDialog->setAutoClose(false);
- }
- unsigned subCloudsCount = 0;
- //project points into grid
- for (size_t ci = 0; ci != clouds.size(); ++ci)
- {
- ccGenericPointCloud* cloud = clouds[ci];
- unsigned pointCount = cloud->size();
- QString infos = tr("Cloud '%1").arg(cloud->getName());
- infos += tr("Points: %L1").arg( pointCount );
- if (progressDialog)
- {
- progressDialog->setInfo(infos);
- }
- QApplication::processEvents();
- CCCoreLib::NormalizedProgress nProgress(progressDialog, pointCount);
- for (unsigned i = 0; i < pointCount; ++i)
- {
- CCVector3 P = *cloud->getPoint(i);
- localTrans.apply(P);
- //relative coordinates (between 0 and 1)
- P -= gridOrigin;
- P.x /= cellSizePlusGap.x;
- P.y /= cellSizePlusGap.y;
- P.z /= cellSizePlusGap.z;
- int xi = static_cast<int>(floor(P.x));
- xi = std::min(std::max(xi, indexMins[0]), indexMaxs[0]);
- int yi = static_cast<int>(floor(P.y));
- yi = std::min(std::max(yi, indexMins[1]), indexMaxs[1]);
- int zi = static_cast<int>(floor(P.z));
- zi = std::min(std::max(zi, indexMins[2]), indexMaxs[2]);
- if (gap == 0 ||
- ( (P.x - static_cast<PointCoordinateType>(xi))*cellSizePlusGap.x <= cellSize.x
- && (P.y - static_cast<PointCoordinateType>(yi))*cellSizePlusGap.y <= cellSize.y
- && (P.z - static_cast<PointCoordinateType>(zi))*cellSizePlusGap.z <= cellSize.z))
- {
- int cloudIndex = ((zi - indexMins[2]) * static_cast<int>(gridDim[1]) + (yi - indexMins[1])) * static_cast<int>(gridDim[0]) + (xi - indexMins[0]);
- assert(cloudIndex >= 0 && static_cast<size_t>(cloudIndex)* clouds.size() + ci < refClouds.size());
- CCCoreLib::ReferenceCloud*& destCloud = refClouds[cloudIndex * clouds.size() + ci];
- if (!destCloud)
- {
- destCloud = new CCCoreLib::ReferenceCloud(cloud);
- ++subCloudsCount;
- }
- if (!destCloud->addPointIndex(i))
- {
- ccLog::Error("Not enough memory!");
- error = true;
- break;
- }
- }
- }
- if (!nProgress.oneStep())
- {
- // sadly, we can't cancel in the middle of this process!
- }
- } //project points into grid
- if (progressDialog)
- {
- progressDialog->setWindowTitle(QObject::tr("Section extraction"));
- progressDialog->setInfo(QObject::tr("Section(s): %L1").arg(subCloudsCount));
- progressDialog->setMaximum(static_cast<int>(subCloudsCount));
- progressDialog->setValue(0);
- QApplication::processEvents();
- }
- //reset count
- subCloudsCount = 0;
- //now create the real clouds
- for (int i = indexMins[0]; i <= indexMaxs[0]; ++i)
- {
- for (int j = indexMins[1]; j <= indexMaxs[1]; ++j)
- {
- for (int k = indexMins[2]; k <= indexMaxs[2]; ++k)
- {
- int cloudIndex = ((k - indexMins[2]) * static_cast<int>(gridDim[1]) + (j - indexMins[1])) * static_cast<int>(gridDim[0]) + (i - indexMins[0]);
- assert(cloudIndex >= 0 && static_cast<size_t>(cloudIndex)* clouds.size() < refClouds.size());
- for (size_t ci = 0; ci != clouds.size(); ++ci)
- {
- ccGenericPointCloud* cloud = clouds[ci];
- CCCoreLib::ReferenceCloud* destCloud = refClouds[cloudIndex * clouds.size() + ci];
- if (destCloud) //some slices can be empty!
- {
- //generate slice from previous selection
- int warnings = 0;
- ccPointCloud* sliceCloud = cloud->isA(CC_TYPES::POINT_CLOUD) ? static_cast<ccPointCloud*>(cloud)->partialClone(destCloud, &warnings) : ccPointCloud::From(destCloud, cloud);
- warningsIssued |= (warnings != 0);
- if (sliceCloud)
- {
- if (generateRandomColors)
- {
- ccColor::Rgb col = ccColor::Generator::Random();
- if (!sliceCloud->setColor(col))
- {
- ccLog::Error("Not enough memory!");
- error = true;
- i = indexMaxs[0];
- j = indexMaxs[1];
- k = indexMaxs[2];
- }
- sliceCloud->showColors(true);
- }
- sliceCloud->setEnabled(true);
- sliceCloud->setVisible(true);
- sliceCloud->setDisplay(cloud->getDisplay());
- CCVector3 cellOrigin( gridOrigin.x + i * cellSizePlusGap.x,
- gridOrigin.y + j * cellSizePlusGap.y,
- gridOrigin.z + k * cellSizePlusGap.z);
- QString slicePosStr = QString("(%1 ; %2 ; %3)").arg(cellOrigin.x).arg(cellOrigin.y).arg(cellOrigin.z);
- sliceCloud->setName(cloud->getName() + QString(".slice @ ") + slicePosStr);
- //set meta-data
- sliceCloud->setMetaData(s_originEntityUUID, cloud->getUniqueID());
- sliceCloud->setMetaData(s_sliceID, slicePosStr);
- sliceCloud->setMetaData("slice.origin.dim(0)", cellOrigin.x);
- sliceCloud->setMetaData("slice.origin.dim(1)", cellOrigin.y);
- sliceCloud->setMetaData("slice.origin.dim(2)", cellOrigin.z);
- //add slice to group
- outputSlices.push_back(sliceCloud);
- ++subCloudsCount;
- if (progressDialog)
- {
- progressDialog->setValue(static_cast<int>(subCloudsCount));
- }
- }
- if (progressDialog && progressDialog->wasCanceled())
- {
- error = true;
- ccLog::Warning(QString("[ExtractSlicesAndContours] Process canceled by user"));
- //early stop
- i = indexMaxs[0];
- j = indexMaxs[1];
- k = indexMaxs[2];
- break;
- }
- }
- }
- }
- }
- } //now create the real clouds
- //release memory
- {
- for (size_t i = 0; i < refClouds.size(); ++i)
- if (refClouds[i])
- delete refClouds[i];
- refClouds.clear();
- }
- cloudSliceCount = outputSlices.size();
- } //extract sections from clouds
- if (!meshes.empty()) //extract sections from meshes
- {
- //compute 'grid' extents in the local clipping box ref.
- ccBBox localBox;
- for (ccGenericMesh* mesh : meshes)
- {
- ccGenericPointCloud* cloud = mesh->getAssociatedCloud();
- for (unsigned i = 0; i < cloud->size(); ++i)
- {
- CCVector3 P = *cloud->getPoint(i);
- localTrans.apply(P);
- localBox.add(P);
- }
- }
- int indexMins[3]{ 0, 0, 0 };
- int indexMaxs[3]{ 0, 0, 0 };
- int gridDim[3]{ 0, 0, 0 };
- unsigned cellCount = ComputeGridDimensions(localBox, repeatDimensions, indexMins, indexMaxs, gridDim, gridOrigin, cellSizePlusGap);
- const ccGLMatrix* _transformation = nullptr;
- ccGLMatrix transformation;
- if (clipBox.isGLTransEnabled())
- {
- transformation = clipBox.getGLTransformation().inverse();
- _transformation = &transformation;
- }
- if (progressDialog)
- {
- progressDialog->setWindowTitle("Section extraction");
- progressDialog->setInfo(QObject::tr("Up to (%1 x %2 x %3) = %4 section(s)").arg(gridDim[0]).arg(gridDim[1]).arg(gridDim[2]).arg(cellCount));
- progressDialog->setMaximum(static_cast<int>(cellCount * meshes.size()));
- progressDialog->show();
- QApplication::processEvents();
- }
- //now extract the slices
- for (int i = indexMins[0]; i <= indexMaxs[0]; ++i)
- {
- for (int j = indexMins[1]; j <= indexMaxs[1]; ++j)
- {
- for (int k = indexMins[2]; k <= indexMaxs[2]; ++k)
- {
- int sliceIndex = ((k - indexMins[2]) * static_cast<int>(gridDim[1]) + (j - indexMins[1])) * static_cast<int>(gridDim[0]) + (i - indexMins[0]);
- CCVector3 C = gridOrigin + CCVector3(i*cellSizePlusGap.x, j*cellSizePlusGap.y, k*cellSizePlusGap.z);
- ccBBox cropBox(C, C + cellSize, true);
- for (size_t mi = 0; mi != meshes.size(); ++mi)
- {
- ccGenericMesh* mesh = meshes[mi];
- ccHObject* croppedEnt = ccCropTool::Crop(mesh, cropBox, true, _transformation);
- if (croppedEnt)
- {
- if (generateRandomColors)
- {
- ccPointCloud* croppedVertices = ccHObjectCaster::ToPointCloud(mesh->getAssociatedCloud());
- if (croppedVertices)
- {
- ccColor::Rgb col = ccColor::Generator::Random();
- if (!croppedVertices->setColor(col))
- {
- ccLog::Error("Not enough memory!");
- error = true;
- i = indexMaxs[0];
- j = indexMaxs[1];
- k = indexMaxs[2];
- }
- croppedVertices->showColors(true);
- mesh->showColors(true);
- }
- }
- croppedEnt->setEnabled(true);
- croppedEnt->setVisible(true);
- croppedEnt->setDisplay(mesh->getDisplay());
- QString slicePosStr = QString("(%1 ; %2 ; %3)").arg(C.x).arg(C.y).arg(C.z);
- croppedEnt->setName(mesh->getName() + QString(".slice @ ") + slicePosStr);
- //set meta-data
- croppedEnt->setMetaData(s_originEntityUUID, mesh->getUniqueID());
- croppedEnt->setMetaData(s_sliceID, slicePosStr);
- croppedEnt->setMetaData("slice.origin.dim(0)", C.x);
- croppedEnt->setMetaData("slice.origin.dim(1)", C.y);
- croppedEnt->setMetaData("slice.origin.dim(2)", C.z);
- //add slice to group
- outputSlices.push_back(croppedEnt);
- }
- if (progressDialog)
- {
- if (progressDialog->wasCanceled())
- {
- error = true;
- ccLog::Warning(QString("[ExtractSlicesAndContours] Process canceled by user"));
- //early stop
- i = indexMaxs[0];
- j = indexMaxs[1];
- k = indexMaxs[2];
- break;
- }
- progressDialog->setValue(sliceIndex * static_cast<int>(meshes.size()) + static_cast<int>(mi));
- }
- }
- }
- }
- }
- } //extract sections from meshes
- } //repeat mode
- //extract level set (optionaly)
- if (!error && extractLevelSet && cloudSliceCount != 0)
- {
- for (int iteration = 0; iteration < 1; ++iteration) //fake loop for easy break
- {
- if (progressDialog)
- {
- progressDialog->setWindowTitle("Level set extraction");
- progressDialog->setInfo(QObject::tr("Level(s): %L1").arg(cloudSliceCount));
- progressDialog->setMaximum(static_cast<int>(cloudSliceCount));
- progressDialog->show();
- QApplication::processEvents();
- }
- int Z = 2;
- assert(repeatDimensionsSum == 1);
- {
- for (int i = 0; i < 3; ++i)
- {
- if (repeatDimensions[i])
- {
- Z = i;
- break;
- }
- }
- }
- int X = (Z == 2 ? 0 : Z + 1);
- int Y = (X == 2 ? 0 : X + 1);
- CCVector3 gridOrigin = clipBox.getOwnBB().minCorner();
- CCVector3 gridSize = clipBox.getOwnBB().getDiagVec();
- ccGLMatrix globalTrans = localTrans.inverse();
- assert(false == CCCoreLib::LessThanEpsilon(levelSetGridStep));
- unsigned gridWidth = 1 + static_cast<unsigned>(gridSize.u[X] / levelSetGridStep + 0.5);
- unsigned gridHeight = 1 + static_cast<unsigned>(gridSize.u[Y] / levelSetGridStep + 0.5);
- //add a margin to avoid issues in the level set generation
- gridWidth += 2;
- gridHeight += 2;
- gridOrigin.u[X] -= levelSetGridStep;
- gridOrigin.u[Y] -= levelSetGridStep;
- ccRasterGrid grid;
- if (!grid.init(gridWidth, gridHeight, levelSetGridStep, CCVector3d(0, 0, 0)))
- {
- ccLog::Error("Not enough memory!");
- error = true;
- break;
- }
- //process all the slices originating from point clouds
- assert(cloudSliceCount <= outputSlices.size());
- for (size_t i = 0; i < cloudSliceCount; ++i)
- {
- ccPointCloud* sliceCloud = ccHObjectCaster::ToPointCloud(outputSlices[i]);
- assert(sliceCloud);
- double sliceZ = sliceCloud->getMetaData(QString("slice.origin.dim(%1)").arg(Z)).toDouble();
- sliceZ += gridSize.u[Z] / 2;
- //grid.reset();
- for (ccRasterGrid::Row& row : grid.rows)
- {
- for (ccRasterCell& cell : row)
- {
- cell.h = 0.0;
- cell.nbPoints = 0;
- }
- }
- //project the slice in 2D
- for (unsigned pi = 0; pi != sliceCloud->size(); ++pi)
- {
- CCVector3 relativePos = *sliceCloud->getPoint(pi);
- localTrans.apply(relativePos);
- relativePos -= gridOrigin;
- int i = static_cast<int>(relativePos.u[X] / levelSetGridStep + 0.5);
- int j = static_cast<int>(relativePos.u[Y] / levelSetGridStep + 0.5);
- //we skip points that fall outside of the grid!
- if ( i < 0 || i >= static_cast<int>(gridWidth)
- || j < 0 || j >= static_cast<int>(gridHeight))
- {
- //there shouldn't be any actually
- assert(false);
- continue;
- }
- ccRasterCell& cell = grid.rows[j][i];
- cell.h = 1.0;
- ++cell.nbPoints;
- }
- grid.updateNonEmptyCellCount();
- grid.updateCellStats();
- grid.setValid(true);
- //now extract the contour lines
- ccContourLinesGenerator::Parameters params;
- params.emptyCellsValue = std::numeric_limits<double>::quiet_NaN();
- params.minVertexCount = levelSetMinVertCount;
- params.parentWidget = progressDialog->parentWidget();
- params.startAltitude = 0.0;
- params.maxAltitude = 1.0;
- params.step = 1.0;
- std::vector<ccPolyline*> contours;
- if (ccContourLinesGenerator::GenerateContourLines(&grid, CCVector2d(gridOrigin.u[X], gridOrigin.u[Y]), params, contours))
- {
- for (size_t k = 0; k < contours.size(); ++k)
- {
- ccPolyline* poly = contours[k];
- CCCoreLib::GenericIndexedCloudPersist* vertices = poly->getAssociatedCloud();
- for (unsigned pi = 0; pi < vertices->size(); ++pi)
- {
- //convert the vertices from the local coordinate system to the global one
- const CCVector3* Pconst = vertices->getPoint(pi);
- CCVector3 P;
- P.u[X] = Pconst->x;
- P.u[Y] = Pconst->y;
- P.u[Z] = sliceZ;
- *const_cast<CCVector3*>(Pconst) = globalTrans * P;
- }
- static char s_dimNames[3] = { 'X', 'Y', 'Z' };
- poly->setName(QString("Contour line %1=%2 (#%3)").arg(s_dimNames[Z]).arg(sliceZ).arg(k + 1));
- poly->copyGlobalShiftAndScale(*sliceCloud);
- poly->setMetaData(ccPolyline::MetaKeyConstAltitude(), QVariant(sliceZ)); //replace the 'altitude' meta-data by the right value
- //set meta-data
- poly->setMetaData(s_originEntityUUID, sliceCloud->getMetaData(s_originEntityUUID));
- poly->setMetaData(s_sliceID, sliceCloud->getMetaData(s_sliceID));
- poly->setMetaData("slice.origin.dim(0)", sliceCloud->getMetaData("slice.origin.dim(0)"));
- poly->setMetaData("slice.origin.dim(1)", sliceCloud->getMetaData("slice.origin.dim(1)"));
- poly->setMetaData("slice.origin.dim(2)", sliceCloud->getMetaData("slice.origin.dim(2)"));
- levelSet.push_back(poly);
- }
- }
- else
- {
- ccLog::Warning(tr("Failed to generate contour lines for cloud #%1").arg(i + 1));
- }
- if (progressDialog)
- {
- if (progressDialog->wasCanceled())
- {
- error = true;
- ccLog::Warning(tr("[ExtractSlicesAndContours] Process canceled by user"));
- break;
- }
- progressDialog->setValue(static_cast<int>(i) + 1);
- }
- }
- }
- }
- //extract envelopes as polylines (optionaly)
- if (!error && extractEnvelopes && cloudSliceCount != 0)
- {
- if (progressDialog)
- {
- progressDialog->setWindowTitle(tr("Envelope extraction"));
- progressDialog->setInfo(tr("Envelope(s): %L1").arg(cloudSliceCount));
- progressDialog->setMaximum(static_cast<int>(cloudSliceCount));
- if (!visualDebugMode)
- {
- progressDialog->show();
- QApplication::processEvents();
- }
- }
- //preferred dimension?
- PointCoordinateType* preferredNormDir = nullptr;
- PointCoordinateType* preferredUpDir = nullptr;
- if (repeatDimensionsSum == 1)
- {
- for (int i = 0; i < 3; ++i)
- {
- if (repeatDimensions[i])
- {
- ccGLMatrix invLocalTrans = localTrans.inverse();
- if (!projectOnBestFitPlane) //otherwise the normal will be automatically computed
- preferredNormDir = invLocalTrans.getColumn(i);
- preferredUpDir = invLocalTrans.getColumn(i < 2 ? 2 : 0);
- break;
- }
- }
- }
- assert(cloudSliceCount <= outputSlices.size());
- //process all the slices originating from point clouds
- for (size_t i = 0; i < cloudSliceCount; ++i)
- {
- ccPointCloud* sliceCloud = ccHObjectCaster::ToPointCloud(outputSlices[i]);
- assert(sliceCloud);
- std::vector<ccPolyline*> polys;
- if (ccEnvelopeExtractor::ExtractFlatEnvelope(sliceCloud,
- multiPass,
- maxEdgeLength,
- polys,
- envelopeType,
- splitEnvelopes,
- preferredNormDir,
- preferredUpDir,
- visualDebugMode))
- {
- if (!polys.empty())
- {
- for (size_t p = 0; p < polys.size(); ++p)
- {
- ccPolyline* poly = polys[p];
- poly->setColor(ccColor::green);
- poly->showColors(true);
- poly->setGlobalScale(sliceCloud->getGlobalScale());
- poly->setGlobalShift(sliceCloud->getGlobalShift());
- QString envelopeName = sliceCloud->getName();
- envelopeName.replace("slice", "envelope");
- if (polys.size() > 1)
- {
- envelopeName += QString(" (part %1)").arg(p + 1);
- }
- poly->setName(envelopeName);
- //set meta-data
- poly->setMetaData(s_originEntityUUID, sliceCloud->getMetaData(s_originEntityUUID));
- poly->setMetaData(s_sliceID, sliceCloud->getMetaData(s_sliceID));
- poly->setMetaData("slice.origin.dim(0)", sliceCloud->getMetaData("slice.origin.dim(0)"));
- poly->setMetaData("slice.origin.dim(1)", sliceCloud->getMetaData("slice.origin.dim(1)"));
- poly->setMetaData("slice.origin.dim(2)", sliceCloud->getMetaData("slice.origin.dim(2)"));
- outputEnvelopes.push_back(poly);
- }
- }
- else
- {
- ccLog::Warning(tr("%1: points are too far from each other! Increase the max edge length").arg(sliceCloud->getName()));
- warningsIssued = true;
- }
- }
- else
- {
- ccLog::Warning(tr("%1: envelope extraction failed!").arg(sliceCloud->getName()));
- warningsIssued = true;
- }
- if (progressDialog && !visualDebugMode)
- {
- if (progressDialog->wasCanceled())
- {
- error = true;
- ccLog::Warning(tr("[ExtractSlicesAndContours] Process canceled by user"));
- //early stop
- break;
- }
- progressDialog->setValue(static_cast<int>(i));
- }
- }
- } //extract envelope polylines
- //release memory
- if (error)
- {
- for (ccHObject* slice : outputSlices)
- {
- delete slice;
- }
- outputSlices.resize(0);
- for (ccPolyline* poly : outputEnvelopes)
- {
- delete poly;
- }
- return false;
- }
- else if (warningsIssued)
- {
- ccLog::Warning(tr("[ExtractSlicesAndContours] Warnings were issued during the process! (result may be incomplete)"));
- }
- }
- catch (const std::bad_alloc&)
- {
- ccLog::Error(tr("Not enough memory!"));
- return false;
- }
- return true;
- }
- static ccHObject* FindOrCreateChildren(ccHObject* parent, QString name)
- {
- assert(parent && !name.isEmpty());
- for (unsigned i = 0; i < parent->getChildrenNumber(); ++i)
- {
- ccHObject* child = parent->getChild(i);
- if (child->getName() == name)
- {
- return child;
- }
- }
- ccHObject* child = new ccHObject(name);
- parent->addChild(child);
- return child;
- }
- void ccClippingBoxTool::extractSlicesAndContours(bool singleSliceMode)
- {
- if (!m_clipBox || m_clipBox->getContainer().getChildrenNumber() == 0)
- {
- assert(false);
- return;
- }
- std::vector<ccGenericPointCloud*> clouds;
- std::vector<ccGenericMesh*> meshes;
- try
- {
- for (unsigned ci = 0; ci != m_clipBox->getContainer().getChildrenNumber(); ++ci)
- {
- ccHObject* obj = m_clipBox->getContainer().getChild(ci);
- if (obj->isKindOf(CC_TYPES::POINT_CLOUD))
- {
- ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(obj);
- clouds.push_back(cloud);
- }
- else if (obj->isKindOf(CC_TYPES::MESH))
- {
- ccGenericMesh* mesh = ccHObjectCaster::ToGenericMesh(obj);
- meshes.push_back(mesh);
- }
- }
- }
- catch (const std::bad_alloc&)
- {
- ccLog::Warning("Not enough memory");
- return;
- }
- if (clouds.empty() && meshes.empty())
- {
- ccLog::Warning("Only works with point clouds or meshes!");
- return;
- }
- ccClippingBoxRepeatDlg repeatDlg(singleSliceMode, MainWindow::TheInstance());
- repeatDlg.extractEnvelopesGroupBox->setEnabled(!clouds.empty());
- repeatDlg.extractLevelSetGroupBox->setEnabled(!clouds.empty());
- //by default we set the 'flat/repeat' dimension to the smallest box dimension
- {
- CCVector3 diagVec = m_clipBox->getOwnBB().getDiagVec();
- unsigned char flatDim = 0;
- if (diagVec.y < diagVec.x)
- flatDim = 1;
- if (diagVec.z < diagVec.u[flatDim])
- flatDim = 2;
- if (singleSliceMode)
- repeatDlg.setFlatDim(flatDim);
- else
- repeatDlg.setRepeatDim(flatDim);
- }
-
- //random colors is only useful for mutliple slices mode
- repeatDlg.randomColorCheckBox->setEnabled(!singleSliceMode);
- //Semi persistent parameters
- static bool s_extractSliceCloudsOrMeshes = true;
- static bool s_generateRandomColors = false;
- static bool s_extractEnvelopes = false;
- static int s_envelopeTypeIndex = 2; //full
- static bool s_multiPassEnvelope = false;
- static bool s_envProjectPointsOnBestFitPlane = false;
- static bool s_splitEnvelopes = false;
- static bool s_envelopeDebugMode = false;
- static bool s_extractLevelSet = false;
- static double s_levelSetGridStep = 0.0;
- static int s_levelSetMinVertCount = 3;
- static double s_defaultGap = 0.0;
- static int s_groupByIndex = 0;
- //set default max edge length
- if (s_maxEnvelopeEdgeLength < 0)
- s_maxEnvelopeEdgeLength = m_clipBox->getBox().getDiagNorm() / 100.0;
- if (s_levelSetGridStep <= 0.0)
- s_levelSetGridStep = m_clipBox->getBox().getDiagNorm() / 300.0;
- //Extract slice cloud(s) or mesh(es)
- repeatDlg.extractSliceEntitiesGroupBox->setChecked(s_extractSliceCloudsOrMeshes);
- repeatDlg.randomColorCheckBox->setChecked(s_generateRandomColors);
- //Extract envelope(s)
- repeatDlg.extractEnvelopesGroupBox->setChecked(s_extractEnvelopes);
- repeatDlg.envelopeTypeComboBox->setCurrentIndex(s_envelopeTypeIndex);
- repeatDlg.maxEnvelopeEdgeLengthDoubleSpinBox->setValue(s_maxEnvelopeEdgeLength);
- repeatDlg.multiPassEnvelopeCheckBox->setChecked(s_multiPassEnvelope);
- repeatDlg.envProjectPointsOnBestFitCheckBox->setChecked(s_envProjectPointsOnBestFitPlane);
- repeatDlg.splitEnvelopeCheckBox->setChecked(s_splitEnvelopes);
- repeatDlg.envDebugModeCheckBox->setChecked(s_envelopeDebugMode);
- //Extract contours
- repeatDlg.extractLevelSetGroupBox->setChecked(s_extractLevelSet);
- repeatDlg.lsGridStepDoubleSpinBox->setValue(s_levelSetGridStep);
- repeatDlg.minLSVertexCountSpinBox->setValue(s_levelSetMinVertCount);
- //Other options
- repeatDlg.gapDoubleSpinBox->setValue(s_defaultGap);
- repeatDlg.groupByTypeComboBox->setCurrentIndex(s_groupByIndex);
-
- if (!repeatDlg.exec())
- {
- //cancelled by user
- return;
- }
- //repeat dimensions
- bool processDim[3] = { repeatDlg.xRepeatCheckBox->isChecked(),
- repeatDlg.yRepeatCheckBox->isChecked(),
- repeatDlg.zRepeatCheckBox->isChecked() };
- //whether to use random colors for (multiple) generated slices
- s_extractSliceCloudsOrMeshes = repeatDlg.extractSliceEntitiesGroupBox->isChecked();
- s_generateRandomColors = repeatDlg.randomColorCheckBox->isChecked();
- s_extractEnvelopes = repeatDlg.extractEnvelopesGroupBox->isChecked();
- s_envelopeTypeIndex = repeatDlg.envelopeTypeComboBox->currentIndex();
- s_maxEnvelopeEdgeLength = repeatDlg.maxEnvelopeEdgeLengthDoubleSpinBox->value();
- s_multiPassEnvelope = repeatDlg.multiPassEnvelopeCheckBox->isChecked();
- s_envProjectPointsOnBestFitPlane = repeatDlg.envProjectPointsOnBestFitCheckBox->isChecked();
- s_splitEnvelopes = repeatDlg.splitEnvelopeCheckBox->isChecked();
- s_envelopeDebugMode = repeatDlg.envDebugModeCheckBox->isChecked();
- s_extractLevelSet = repeatDlg.extractLevelSetGroupBox->isChecked();
- s_levelSetGridStep = repeatDlg.lsGridStepDoubleSpinBox->value();
- s_levelSetMinVertCount = repeatDlg.minLSVertexCountSpinBox->value();
- s_defaultGap = repeatDlg.gapDoubleSpinBox->value();
- s_groupByIndex = repeatDlg.groupByTypeComboBox->currentIndex();
- ccEnvelopeExtractor::EnvelopeType envelopeType = ccEnvelopeExtractor::EnvelopeType::FULL;
- switch (s_envelopeTypeIndex)
- {
- case 0:
- envelopeType = ccEnvelopeExtractor::EnvelopeType::LOWER;
- break;
- case 1:
- envelopeType = ccEnvelopeExtractor::EnvelopeType::UPPER;
- break;
- case 2:
- envelopeType = ccEnvelopeExtractor::EnvelopeType::FULL;
- break;
- default:
- assert(false);
- ccLog::Warning("Internal error: unhandled envelope type");
- break;
- }
- ccProgressDialog pDlg(false, this);
- std::vector<ccHObject*> outputSlices;
- std::vector<ccPolyline*> outputEnvelopes;
- std::vector<ccPolyline*> outputLevelSet;
- QElapsedTimer eTimer;
- eTimer.start();
- if (!ExtractSlicesAndContours( clouds,
- meshes,
- *m_clipBox,
- singleSliceMode,
- processDim,
- outputSlices,
- s_extractEnvelopes,
- static_cast<PointCoordinateType>(s_maxEnvelopeEdgeLength),
- envelopeType,
- outputEnvelopes,
- s_extractLevelSet,
- s_levelSetGridStep,
- s_levelSetMinVertCount,
- outputLevelSet,
- static_cast<PointCoordinateType>(s_defaultGap),
- s_multiPassEnvelope,
- s_splitEnvelopes,
- s_envProjectPointsOnBestFitPlane,
- s_envelopeDebugMode,
- s_generateRandomColors,
- &pDlg
- ))
- {
- //process failed (error message has already been issued)
- return;
- }
- ccLog::Print("[ccClippingBoxTool] Processed finished in %.2f s.", eTimer.elapsed() / 1.0e3);
- //possible outputs
- ccHObject* sliceGroup = nullptr;
- ccHObject* envelopeGroup = nullptr;
- ccHObject* levelSetGroup = nullptr;
- QMap<QString, ccHObject*> perSliceGroups;
- QMap<unsigned, ccHObject*> perEntityGroups;
- QMap<unsigned, QString> perEntityGroupNames;
- ccHObject* garbageGroup = new ccHObject("Extracted entities");
- enum OutputFormat { BY_TYPE = 0,
- BY_ENTITY = 1,
- BY_SLICE = 2,
- BY_ENTITY_THEN_SLICE = 3,
- BY_SLICE_THEN_ENTITY = 4,
- };
- if ( s_groupByIndex == OutputFormat::BY_ENTITY
- || s_groupByIndex == OutputFormat::BY_ENTITY_THEN_SLICE
- || s_groupByIndex == OutputFormat::BY_SLICE_THEN_ENTITY
- )
- {
- for (const ccGenericPointCloud* cloud : clouds)
- {
- QString name = cloud->getName() + ".slices";
- perEntityGroupNames[cloud->getUniqueID()] = name;
- if (s_groupByIndex != OutputFormat::BY_SLICE_THEN_ENTITY)
- {
- perEntityGroups[cloud->getUniqueID()] = new ccHObject(name);
- }
- }
- for (const ccGenericMesh* mesh : meshes)
- {
- QString name = mesh->getName() + ".slices";
- perEntityGroupNames[mesh->getUniqueID()] = name;
- if (s_groupByIndex != OutputFormat::BY_SLICE_THEN_ENTITY)
- {
- perEntityGroups[mesh->getUniqueID()] = new ccHObject(name);
- }
- }
- }
- if (s_groupByIndex == OutputFormat::BY_SLICE)
- {
- for (const ccHObject* slice : outputSlices)
- {
- QString sliceID = slice->getMetaData(s_sliceID).toString();
- perSliceGroups[sliceID] = new ccHObject(sliceID);
- }
- }
- auto dispatchEntity = [&](ccHObject* entity, ccHObject* sliceGroup)
- {
- if (entity == nullptr)
- {
- assert(false);
- return;
- }
- ccHObject* destGroup = nullptr;
- switch (s_groupByIndex)
- {
- case OutputFormat::BY_TYPE:
- {
- destGroup = sliceGroup;
- }
- break;
- case OutputFormat::BY_ENTITY:
- case OutputFormat::BY_ENTITY_THEN_SLICE:
- {
- //first level: entity
- unsigned entityUUID = entity->getMetaData(s_originEntityUUID).toUInt();
- if (perEntityGroups.contains(entityUUID))
- {
- destGroup = perEntityGroups[entityUUID];
- }
- else
- {
- assert(false);
- destGroup = garbageGroup;
- }
- if (s_groupByIndex == OutputFormat::BY_ENTITY_THEN_SLICE)
- {
- //second level: slice
- QString sliceID = entity->getMetaData(s_sliceID).toString();
- destGroup = FindOrCreateChildren(destGroup, sliceID);
- }
-
- destGroup->addChild(entity);
- }
- break;
- case OutputFormat::BY_SLICE:
- case OutputFormat::BY_SLICE_THEN_ENTITY:
- {
- //first level: slice
- QString sliceID = entity->getMetaData(s_sliceID).toString();
- if (perSliceGroups.contains(sliceID))
- {
- destGroup = perSliceGroups[sliceID];
- }
- else
- {
- assert(false);
- destGroup = garbageGroup;
- }
-
- if (s_groupByIndex == OutputFormat::BY_SLICE_THEN_ENTITY)
- {
- //second level: entity
- unsigned entityUUID = entity->getMetaData(s_originEntityUUID).toUInt();
- if (perEntityGroupNames.contains(entityUUID))
- {
- destGroup = FindOrCreateChildren(destGroup, perEntityGroupNames[entityUUID]);
- }
- }
- }
- break;
- default:
- assert(false);
- return;
- }
- if (destGroup)
- {
- destGroup->addChild(entity);
- }
- else
- {
- assert(false);
- }
- };
- //get the default output display
- ccGenericGLDisplay* defaultDisplay = nullptr;
- if (m_clipBox->getContainer().getFirstChild())
- {
- defaultDisplay = m_clipBox->getContainer().getFirstChild()->getDisplay();
- }
- //base name
- QString baseName;
- if (m_clipBox->getContainer().getChildrenNumber() == 1)
- {
- baseName = m_clipBox->getContainer().getFirstChild()->getName();
- }
- //slices (clouds or meshes)
- size_t sliceCount = outputSlices.size();
- if (sliceCount)
- {
- if (s_extractSliceCloudsOrMeshes)
- {
- if (s_groupByIndex == OutputFormat::BY_TYPE)
- {
- //we have to create the destination group
- sliceGroup = new ccHObject(baseName.isEmpty() ? QString("Slices") : baseName + QString(".slices"));
- }
- for (ccHObject* slice : outputSlices)
- {
- dispatchEntity(slice, sliceGroup);
- }
- }
- else
- {
- for (ccHObject* slice : outputSlices)
- {
- delete slice;
- }
- outputSlices.clear();
- }
- }
- if (!outputEnvelopes.empty() || !outputLevelSet.empty())
- {
- s_lastContourUniqueIDs.clear();
- }
- //envelopes
- if (!outputEnvelopes.empty())
- {
- if (s_groupByIndex == OutputFormat::BY_TYPE)
- {
- //we have to create the destination group
- envelopeGroup = new ccHObject(baseName.isEmpty() ? QString("Envelopes") : baseName + QString(".envelopes"));
- }
- for (ccPolyline* poly : outputEnvelopes)
- {
- dispatchEntity(poly, envelopeGroup);
- s_lastContourUniqueIDs.push_back(poly->getUniqueID());
- }
- if (envelopeGroup)
- {
- s_lastContourUniqueIDs.push_back(envelopeGroup->getUniqueID());
- }
- }
- //level set
- if (!outputLevelSet.empty())
- {
- if (s_groupByIndex == OutputFormat::BY_TYPE)
- {
- //we have to create the destination group
- levelSetGroup = new ccHObject(baseName.isEmpty() ? QString("Level set") : baseName + QString(".levelSet"));
- }
- for (ccPolyline* poly : outputLevelSet)
- {
- dispatchEntity(poly, levelSetGroup);
- s_lastContourUniqueIDs.push_back(poly->getUniqueID());
- }
- if (levelSetGroup)
- {
- s_lastContourUniqueIDs.push_back(levelSetGroup->getUniqueID());
- }
- }
- removeLastContourToolButton->setEnabled(!s_lastContourUniqueIDs.empty());
- //now take care of the 'output' groups
- {
- if (sliceGroup)
- {
- sliceGroup->setDisplay_recursive(defaultDisplay);
- MainWindow::TheInstance()->addToDB(sliceGroup);
- }
-
- if (envelopeGroup)
- {
- envelopeGroup->setDisplay_recursive(defaultDisplay);
- MainWindow::TheInstance()->addToDB(envelopeGroup);
- }
- if (levelSetGroup)
- {
- levelSetGroup->setDisplay_recursive(defaultDisplay);
- MainWindow::TheInstance()->addToDB(levelSetGroup);
- }
- for (ccHObject* group : perSliceGroups)
- {
- group->setDisplay_recursive(defaultDisplay);
- MainWindow::TheInstance()->addToDB(group);
- }
- for (ccHObject* group : perEntityGroups)
- {
- group->setDisplay_recursive(defaultDisplay);
- MainWindow::TheInstance()->addToDB(group);
- }
- //don't forget the 'garbage' group (just in case)
- if (garbageGroup)
- {
- if (garbageGroup->getChildrenNumber() != 0)
- {
- garbageGroup->setDisplay_recursive(defaultDisplay);
- MainWindow::TheInstance()->addToDB(garbageGroup);
- }
- else
- {
- delete garbageGroup;
- garbageGroup = nullptr;
- }
- }
- }
- if (m_associatedWin)
- {
- m_associatedWin->redraw();
- }
- if (sliceCount != 0)
- {
- QMessageBox::warning(nullptr, tr("Process finished"), tr("%1 slices have been generated.\n(you may have to close the tool and hide the initial cloud to see them...)").arg(sliceCount));
- }
- else if (s_extractSliceCloudsOrMeshes)
- {
- QMessageBox::warning(nullptr, tr("Process finished"), tr("The process has generated no output"));
- }
- }
- void ccClippingBoxTool::onBoxModified(const ccBBox* box)
- {
- if (box && box->isValid())
- {
- CCVector3 dd = box->maxCorner() - box->minCorner();
- thickXDoubleSpinBox->setValue(dd.x);
- thickYDoubleSpinBox->setValue(dd.y);
- thickZDoubleSpinBox->setValue(dd.z);
- thicknessGroupBox->setEnabled(true);
- }
- else
- {
- thicknessGroupBox->setEnabled(false);
- }
- }
- void ccClippingBoxTool::thicknessChanged(double)
- {
- if (!m_clipBox || !m_clipBox->getBox().isValid())
- return;
- CCVector3 th(static_cast<PointCoordinateType>(thickXDoubleSpinBox->value()),
- static_cast<PointCoordinateType>(thickYDoubleSpinBox->value()),
- static_cast<PointCoordinateType>(thickZDoubleSpinBox->value()));
- ccBBox box = m_clipBox->getBox();
- CCVector3 boxCenter = (box.maxCorner() + box.minCorner()) / 2;
- box.minCorner() = boxCenter - th/2;
- box.maxCorner() = boxCenter + th/2;
- m_clipBox->setBox(box);
- if (m_associatedWin)
- m_associatedWin->redraw();
- }
- void ccClippingBoxTool::shiftBox(unsigned char dim, bool minus)
- {
- if (!m_clipBox || !m_clipBox->getBox().isValid())
- return;
- assert(dim<3);
- PointCoordinateType width = (m_clipBox->getBox().maxCorner() - m_clipBox->getBox().minCorner()).u[dim];
- CCVector3 shiftVec(0, 0, 0);
- shiftVec.u[dim] = (minus ? -width : width);
- m_clipBox->shift(shiftVec);
- if (m_associatedWin)
- m_associatedWin->redraw();
- }
- void ccClippingBoxTool::reset()
- {
- if (m_clipBox)
- m_clipBox->reset();
- if (m_associatedWin)
- m_associatedWin->redraw();
- }
- void ccClippingBoxTool::restoreLastBox()
- {
- if (!m_clipBox || m_clipBox->getContainer().getChildrenNumber() == 0)
- {
- assert(false);
- return;
- }
-
- unsigned uniqueID = m_clipBox->getContainer().getFirstChild()->getUniqueID();
- if (!s_lastBoxParams.contains(uniqueID))
- {
- assert(false);
- return;
- }
- const ccClipBoxParams& params = s_lastBoxParams[uniqueID];
- m_clipBox->set(params.box, params.trans);
- }
- void ccClippingBoxTool::closeDialog()
- {
- stop(true);
- }
- void ccClippingBoxTool::setTopView()
- {
- setView(CC_TOP_VIEW);
- }
- void ccClippingBoxTool::setBottomView()
- {
- setView(CC_BOTTOM_VIEW);
- }
- void ccClippingBoxTool::setFrontView()
- {
- setView(CC_FRONT_VIEW);
- }
- void ccClippingBoxTool::setBackView()
- {
- setView(CC_BACK_VIEW);
- }
- void ccClippingBoxTool::setLeftView()
- {
- setView(CC_LEFT_VIEW);
- }
- void ccClippingBoxTool::setRightView()
- {
- setView(CC_RIGHT_VIEW);
- }
- void ccClippingBoxTool::setView(CC_VIEW_ORIENTATION orientation)
- {
- if (!m_associatedWin)
- return;
- //m_associatedWin->blockSignals(true);
- m_associatedWin->setView(orientation,false);
- if (m_clipBox && m_clipBox->isGLTransEnabled())
- {
- ccViewportParameters params = m_associatedWin->getViewportParameters();
- const ccGLMatrix& glMat = m_clipBox->getGLTransformation();
- ccGLMatrixd rotMat(glMat.data()); rotMat.clearTranslation();
- params.viewMat = params.viewMat * rotMat.inverse();
- m_associatedWin->setViewportParameters(params);
- }
- //m_associatedWin->blockSignals(false);
- m_associatedWin->redraw();
- }
|