ccGraphicalSegmentationTool.cpp 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  4. //# #
  5. //# This program is free software; you can redistribute it and/or modify #
  6. //# it under the terms of the GNU General Public License as published by #
  7. //# the Free Software Foundation; version 2 or later of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
  15. //# #
  16. //##########################################################################
  17. #include "ccGraphicalSegmentationTool.h"
  18. #include "ccGraphicalSegmentationOptionsDlg.h"
  19. //Local
  20. #include "mainwindow.h"
  21. #include "ccItemSelectionDlg.h"
  22. #include "ccReservedIDs.h"
  23. //CCCoreLib
  24. #include <ManualSegmentationTools.h>
  25. #include <SquareMatrix.h>
  26. //qCC_db
  27. #include <ccLog.h>
  28. #include <ccPolyline.h>
  29. #include <ccGenericPointCloud.h>
  30. #include <ccPointCloud.h>
  31. #include <ccMesh.h>
  32. #include <ccHObjectCaster.h>
  33. #include <cc2DViewportObject.h>
  34. //for the helper (apply)
  35. #include <cc2DLabel.h>
  36. #include <ccCameraSensor.h>
  37. #include <ccGBLSensor.h>
  38. #include <ccSubMesh.h>
  39. //qCC_gl
  40. #include <ccGLWindowInterface.h>
  41. //Qt
  42. #include <QMenu>
  43. #include <QMessageBox>
  44. #include <QPushButton>
  45. #include <QInputDialog>
  46. #include <QSettings>
  47. //System
  48. #include <assert.h>
  49. #if defined(_OPENMP)
  50. //OpenMP
  51. #include <omp.h>
  52. #endif
  53. ccGraphicalSegmentationTool::ccGraphicalSegmentationTool(QWidget* parent)
  54. : ccOverlayDialog(parent)
  55. , Ui::GraphicalSegmentationDlg()
  56. , m_somethingHasChanged(false)
  57. , m_state(0)
  58. , m_segmentationPoly(nullptr)
  59. , m_polyVertices(nullptr)
  60. , m_rectangularSelection(false)
  61. , m_deleteHiddenParts(false)
  62. {
  63. // Set QDialog background as transparent (DGM: doesn't work over an OpenGL context)
  64. //setAttribute(Qt::WA_NoSystemBackground);
  65. setupUi(this);
  66. connect(inButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::segmentIn);
  67. connect(outButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::segmentOut);
  68. connect(exportSelectionButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::exportSelection);
  69. connect(razButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::reset);
  70. connect(optionsButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::options);
  71. connect(validButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::apply);
  72. connect(validAndDeleteButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::applyAndDelete);
  73. connect(cancelButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::cancel);
  74. connect(pauseButton, &QToolButton::toggled, this, &ccGraphicalSegmentationTool::pauseSegmentationMode);
  75. connect(addClassToolButton, &QToolButton::clicked, this, &ccGraphicalSegmentationTool::setClassificationValue);
  76. //selection modes
  77. connect(actionSetPolylineSelection, &QAction::triggered, this, &ccGraphicalSegmentationTool::doSetPolylineSelection);
  78. connect(actionSetRectangularSelection, &QAction::triggered, this, &ccGraphicalSegmentationTool::doSetRectangularSelection);
  79. //import/export options
  80. connect(actionUseExistingPolyline, &QAction::triggered, this, &ccGraphicalSegmentationTool::doActionUseExistingPolyline);
  81. connect(actionExportSegmentationPolyline, &QAction::triggered, this, &ccGraphicalSegmentationTool::doExportSegmentationPolyline);
  82. //add shortcuts
  83. addOverriddenShortcut(Qt::Key_Space); //space bar for the "pause" button
  84. addOverriddenShortcut(Qt::Key_Escape); //escape key for the "cancel" button
  85. addOverriddenShortcut(Qt::Key_Return); //return key for the "apply" button
  86. addOverriddenShortcut(Qt::Key_Delete); //delete key for the "apply and delete" button
  87. addOverriddenShortcut(Qt::Key_Tab); //tab key to switch between rectangular and polygonal selection modes
  88. addOverriddenShortcut(Qt::Key_I); //'I' key for the "segment in" button
  89. addOverriddenShortcut(Qt::Key_O); //'O' key for the "segment out" button
  90. addOverriddenShortcut(Qt::Key_C); //'C' key for the "classify" button
  91. addOverriddenShortcut(Qt::Key_E); //'E' key for the "export" button
  92. connect(this, &ccOverlayDialog::shortcutTriggered, this, &ccGraphicalSegmentationTool::onShortcutTriggered);
  93. QMenu *selectionModeMenu = new QMenu(this);
  94. selectionModeMenu->addAction(actionSetPolylineSelection);
  95. selectionModeMenu->addAction(actionSetRectangularSelection);
  96. selectionModelButton->setDefaultAction(actionSetPolylineSelection);
  97. selectionModelButton->setMenu(selectionModeMenu);
  98. QMenu *importExportMenu = new QMenu(this);
  99. importExportMenu->addAction(actionUseExistingPolyline);
  100. importExportMenu->addAction(actionExportSegmentationPolyline);
  101. loadSaveToolButton->setMenu(importExportMenu);
  102. m_polyVertices = new ccPointCloud("vertices", static_cast<unsigned>(ReservedIDs::INTERACTIVE_SEGMENTATION_TOOL_POLYLINE_VERTICES));
  103. m_segmentationPoly = new ccPolyline(m_polyVertices, static_cast<unsigned>(ReservedIDs::INTERACTIVE_SEGMENTATION_TOOL_POLYLINE));
  104. m_segmentationPoly->setForeground(true);
  105. m_segmentationPoly->setColor(ccColor::green);
  106. m_segmentationPoly->showColors(true);
  107. m_segmentationPoly->set2DMode(true);
  108. allowPolylineExport(false);
  109. }
  110. void ccGraphicalSegmentationTool::allowPolylineExport(bool state)
  111. {
  112. if (state)
  113. {
  114. actionExportSegmentationPolyline->setEnabled(true);
  115. }
  116. else
  117. {
  118. loadSaveToolButton->setDefaultAction(actionUseExistingPolyline);
  119. actionExportSegmentationPolyline->setEnabled(false);
  120. }
  121. }
  122. ccGraphicalSegmentationTool::~ccGraphicalSegmentationTool()
  123. {
  124. if (m_segmentationPoly)
  125. delete m_segmentationPoly;
  126. m_segmentationPoly = nullptr;
  127. if (m_polyVertices)
  128. delete m_polyVertices;
  129. m_polyVertices = nullptr;
  130. }
  131. void ccGraphicalSegmentationTool::onShortcutTriggered(int key)
  132. {
  133. switch (key)
  134. {
  135. case Qt::Key_Space:
  136. // toggle pause mode
  137. pauseSegmentationMode(!pauseButton->isChecked());
  138. //pauseButton->toggle();
  139. return;
  140. case Qt::Key_I:
  141. segmentIn();
  142. return;
  143. case Qt::Key_O:
  144. segmentOut();
  145. return;
  146. case Qt::Key_C:
  147. setClassificationValue();
  148. return;
  149. case Qt::Key_E:
  150. exportSelection();
  151. return;
  152. case Qt::Key_Return:
  153. if (m_somethingHasChanged)
  154. apply();
  155. //validButton->click();
  156. return;
  157. case Qt::Key_Delete:
  158. if (m_somethingHasChanged)
  159. applyAndDelete();
  160. //validAndDeleteButton->click();
  161. return;
  162. case Qt::Key_Escape:
  163. cancel();
  164. //cancelButton->click();
  165. return;
  166. case Qt::Key_Tab:
  167. if (m_rectangularSelection)
  168. doSetPolylineSelection();
  169. else
  170. doSetRectangularSelection();
  171. return;
  172. default:
  173. //nothing to do
  174. break;
  175. }
  176. }
  177. bool ccGraphicalSegmentationTool::linkWith(ccGLWindowInterface *win)
  178. {
  179. assert(m_segmentationPoly);
  180. ccGLWindowInterface* oldWin = m_associatedWin;
  181. if (!ccOverlayDialog::linkWith(win))
  182. {
  183. return false;
  184. }
  185. if (oldWin)
  186. {
  187. oldWin->signalEmitter()->disconnect(this);
  188. if (m_segmentationPoly)
  189. {
  190. m_segmentationPoly->setDisplay(nullptr);
  191. }
  192. }
  193. if (m_associatedWin)
  194. {
  195. connect(m_associatedWin->signalEmitter(), &ccGLWindowSignalEmitter::leftButtonClicked, this, &ccGraphicalSegmentationTool::addPointToPolyline);
  196. connect(m_associatedWin->signalEmitter(), &ccGLWindowSignalEmitter::rightButtonClicked, this, &ccGraphicalSegmentationTool::closePolyLine);
  197. connect(m_associatedWin->signalEmitter(), &ccGLWindowSignalEmitter::mouseMoved, this, &ccGraphicalSegmentationTool::updatePolyLine);
  198. connect(m_associatedWin->signalEmitter(), &ccGLWindowSignalEmitter::buttonReleased, this, &ccGraphicalSegmentationTool::closeRectangle);
  199. if (m_segmentationPoly)
  200. {
  201. m_segmentationPoly->setDisplay(m_associatedWin);
  202. }
  203. }
  204. return true;
  205. }
  206. bool ccGraphicalSegmentationTool::start()
  207. {
  208. assert(m_polyVertices && m_segmentationPoly);
  209. if (!m_associatedWin)
  210. {
  211. ccLog::Warning("[Graphical Segmentation Tool] No associated window!");
  212. return false;
  213. }
  214. m_segmentationPoly->clear();
  215. m_polyVertices->clear();
  216. allowPolylineExport(false);
  217. //the user must not close this window!
  218. m_associatedWin->setUnclosable(true);
  219. m_associatedWin->addToOwnDB(m_segmentationPoly);
  220. m_associatedWin->setPickingMode(ccGLWindowInterface::NO_PICKING);
  221. pauseSegmentationMode(false);
  222. m_somethingHasChanged = false;
  223. reset();
  224. return ccOverlayDialog::start();
  225. }
  226. void ccGraphicalSegmentationTool::prepareEntityForRemoval(ccHObject *entity, bool unallocateVisibilityArrays)
  227. {
  228. if (!entity)
  229. {
  230. assert(false);
  231. return;
  232. }
  233. // restore the display state of the entity
  234. entity->popDisplayState();
  235. if (unallocateVisibilityArrays)
  236. {
  237. ccGenericPointCloud* asCloud = ccHObjectCaster::ToGenericPointCloud(entity);
  238. if (asCloud)
  239. {
  240. asCloud->unallocateVisibilityArray();
  241. }
  242. }
  243. // specific case: we may have automatically hidden the mesh or the polyline associated to a cloud
  244. if (entity->isKindOf(CC_TYPES::POINT_CLOUD))
  245. {
  246. ccGenericPointCloud* cloud = static_cast<ccGenericPointCloud *>(entity);
  247. ccGenericMesh* associatedMesh = nullptr;
  248. if (ccGenericMesh::IsCloudVerticesOfMesh(cloud, &associatedMesh) && associatedMesh)
  249. {
  250. associatedMesh->popDisplayState();
  251. return;
  252. }
  253. ccPolyline* associatedPolyline = nullptr;
  254. if (ccPolyline::IsCloudVerticesOfPolyline(cloud, &associatedPolyline) && associatedPolyline)
  255. {
  256. associatedPolyline->popDisplayState();
  257. return;
  258. }
  259. }
  260. }
  261. void ccGraphicalSegmentationTool::removeAllEntities()
  262. {
  263. for (QSet<ccHObject *>::const_iterator p = m_toSegment.constBegin(); p != m_toSegment.constEnd(); ++p)
  264. {
  265. ccHObject *entity = *p;
  266. prepareEntityForRemoval(entity, true);
  267. }
  268. m_toSegment.clear();
  269. }
  270. void ccGraphicalSegmentationTool::stop(bool accepted)
  271. {
  272. assert(m_segmentationPoly);
  273. if (m_associatedWin)
  274. {
  275. m_associatedWin->displayNewMessage("Segmentation [OFF]",
  276. ccGLWindowInterface::UPPER_CENTER_MESSAGE,
  277. false,
  278. 2,
  279. ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  280. m_associatedWin->setInteractionMode(ccGLWindowInterface::MODE_TRANSFORM_CAMERA);
  281. m_associatedWin->setPickingMode(ccGLWindowInterface::DEFAULT_PICKING);
  282. m_associatedWin->setUnclosable(false);
  283. m_associatedWin->removeFromOwnDB(m_segmentationPoly);
  284. }
  285. ccOverlayDialog::stop(accepted);
  286. for (auto item : m_enableOnClose) // in export mode, all parts are enabled at the close
  287. {
  288. if (item != nullptr)
  289. {
  290. item->setEnabled(true);
  291. }
  292. }
  293. m_enableOnClose.clear();
  294. for (auto item : m_disableOnClose) // in export mode, the original entities are disabled on close to make sure the newly created parts are visible
  295. {
  296. if (item != nullptr)
  297. {
  298. item->setEnabled(false);
  299. }
  300. }
  301. m_disableOnClose.clear();
  302. }
  303. void ccGraphicalSegmentationTool::reset()
  304. {
  305. if (m_somethingHasChanged)
  306. {
  307. for (QSet<ccHObject *>::const_iterator p = m_toSegment.constBegin(); p != m_toSegment.constEnd(); ++p)
  308. {
  309. ccGenericPointCloud *asCloud = ccHObjectCaster::ToGenericPointCloud(*p);
  310. if (asCloud)
  311. {
  312. asCloud->unallocateVisibilityArray();
  313. }
  314. }
  315. m_somethingHasChanged = false;
  316. }
  317. if (m_associatedWin)
  318. {
  319. m_associatedWin->redraw(false);
  320. m_associatedWin->doReleaseMouse();
  321. }
  322. razButton->setEnabled(false);
  323. validButton->setEnabled(false);
  324. validAndDeleteButton->setEnabled(false);
  325. loadSaveToolButton->setDefaultAction(actionUseExistingPolyline);
  326. }
  327. bool ccGraphicalSegmentationTool::addEntity(ccHObject *entity, bool silent/*=false*/)
  328. {
  329. if (!entity)
  330. {
  331. assert(false);
  332. return false;
  333. }
  334. if (!entity->isDisplayedIn(m_associatedWin) && !silent)
  335. {
  336. ccLog::Warning(QString("[Graphical Segmentation Tool] Entity [%1] is not visible in the active 3D view!").arg(entity->getName()));
  337. }
  338. if (entity->isKindOf(CC_TYPES::POINT_CLOUD))
  339. {
  340. ccGenericPointCloud *cloud = ccHObjectCaster::ToGenericPointCloud(entity);
  341. ccGenericMesh *associatedMesh = nullptr;
  342. if (ccGenericMesh::IsCloudVerticesOfMesh(cloud, &associatedMesh))
  343. {
  344. assert(nullptr != associatedMesh);
  345. if (m_toSegment.contains(associatedMesh))
  346. {
  347. if (!silent)
  348. {
  349. ccLog::Warning(QString("[Graphical Segmentation Tool] The mesh associated to cloud %1 is already selected").arg(cloud->getName()));
  350. }
  351. return false;
  352. }
  353. // hide the associated mesh, as it will also be (graphically) segmented
  354. associatedMesh->pushDisplayState();
  355. associatedMesh->setVisible(false);
  356. }
  357. ccPolyline *associatedPolyline = nullptr;
  358. if (ccPolyline::IsCloudVerticesOfPolyline(cloud, &associatedPolyline))
  359. {
  360. assert(nullptr != associatedPolyline);
  361. if (m_toSegment.contains(associatedPolyline))
  362. {
  363. if (!silent)
  364. {
  365. ccLog::Warning(QString("[Graphical Segmentation Tool] The polyline associated to cloud %1 is already selected").arg(cloud->getName()));
  366. }
  367. return false;
  368. }
  369. // hide the associated polyline, as it will also be (graphically) segmented
  370. associatedPolyline->pushDisplayState();
  371. associatedPolyline->setVisible(false);
  372. }
  373. m_toSegment.insert(cloud);
  374. cloud->pushDisplayState();
  375. cloud->setVisible(true);
  376. cloud->setEnabled(true);
  377. //DGM: not sure what was the idea behind the code below?
  378. //
  379. //automatically add cloud's children
  380. //for (unsigned i = 0; i < entity->getChildrenNumber(); ++i)
  381. //{
  382. // ccHObject* child = entity->getChild(i);
  383. // if (child != associatedMesh && child != associatedPolyline) // we don't add the associated mesh or polyline (if any)
  384. // {
  385. // result |= addEntity(entity->getChild(i), /*silent=*/true);
  386. // }
  387. //}
  388. return true;
  389. }
  390. else if (entity->isKindOf(CC_TYPES::MESH))
  391. {
  392. if (entity->isKindOf(CC_TYPES::PRIMITIVE))
  393. {
  394. if (!silent)
  395. {
  396. ccLog::Warning("[ccGraphicalSegmentationTool] Can't segment primitives yet! Sorry...");
  397. }
  398. return false;
  399. }
  400. if (entity->isKindOf(CC_TYPES::SUB_MESH))
  401. {
  402. if (!silent)
  403. {
  404. ccLog::Warning("[ccGraphicalSegmentationTool] Can't segment sub-meshes! Select the parent mesh...");
  405. }
  406. return false;
  407. }
  408. ccGenericMesh *mesh = ccHObjectCaster::ToGenericMesh(entity);
  409. assert(mesh);
  410. //DGM: the code below is useless since we don't allow CC_TYPES::SUB_MESH entities (see above)
  411. //
  412. // first, we must check that there's no mesh and at least one of its sub-mesh mixed in the current selection!
  413. //for (QSet<ccHObject*>::const_iterator p = m_toSegment.constBegin(); p != m_toSegment.constEnd(); ++p)
  414. //{
  415. // if ((*p)->isKindOf(CC_TYPES::MESH))
  416. // {
  417. // ccGenericMesh* otherMesh = ccHObjectCaster::ToGenericMesh(*p);
  418. // if (otherMesh->getAssociatedCloud() == mesh->getAssociatedCloud())
  419. // {
  420. // if ((otherMesh->isA(CC_TYPES::SUB_MESH) && mesh->isA(CC_TYPES::MESH))
  421. // || (otherMesh->isA(CC_TYPES::MESH) && mesh->isA(CC_TYPES::SUB_MESH)))
  422. // {
  423. // if (!silent)
  424. // {
  425. // ccLog::Warning("[Graphical Segmentation Tool] Can't mix sub-meshes with their parent mesh!");
  426. // }
  427. // return false;
  428. // }
  429. // }
  430. // }
  431. //}
  432. ccGenericPointCloud *vertices = mesh->getAssociatedCloud();
  433. if (!vertices)
  434. {
  435. assert(false);
  436. return false;
  437. }
  438. // Make sure the vertices of this mesh are not already in the 'to segment' list
  439. if (m_toSegment.contains(vertices))
  440. {
  441. //let's remove the vertices
  442. mesh->pushDisplayState(); // just in case the vertices were inserted before the mesh)
  443. vertices->popDisplayState();
  444. m_toSegment.remove(vertices);
  445. }
  446. m_toSegment.insert(mesh);
  447. mesh->pushDisplayState();
  448. mesh->setVisible(true);
  449. mesh->setEnabled(true);
  450. return true;
  451. }
  452. else if (entity->isKindOf(CC_TYPES::POLY_LINE))
  453. {
  454. ccPolyline *poly = ccHObjectCaster::ToPolyline(entity);
  455. assert(poly);
  456. ccGenericPointCloud *verticesCloud = dynamic_cast<ccGenericPointCloud *>(poly->getAssociatedCloud());
  457. if (!verticesCloud)
  458. {
  459. assert(false);
  460. return false;
  461. }
  462. // Make sure the vertices of this polyline are not already in the 'to segment' list
  463. if (verticesCloud && m_toSegment.contains(verticesCloud))
  464. {
  465. //let's remove the vertices
  466. poly->pushDisplayState(); // just in case the vertices were inserted before the polyline)
  467. verticesCloud->popDisplayState();
  468. m_toSegment.remove(verticesCloud);
  469. }
  470. m_toSegment.insert(poly);
  471. poly->pushDisplayState();
  472. poly->setVisible(true);
  473. poly->setEnabled(true);
  474. return true;
  475. }
  476. else if (entity->isA(CC_TYPES::HIERARCHY_OBJECT))
  477. {
  478. //automatically add the entities contained in the group
  479. bool result = false;
  480. for (unsigned i = 0; i < entity->getChildrenNumber(); ++i)
  481. result |= addEntity(entity->getChild(i));
  482. return result;
  483. }
  484. else
  485. {
  486. if (!silent)
  487. {
  488. ccLog::Warning("[ccGraphicalSegmentationTool] Can't segment entity " + entity->getName());
  489. }
  490. return false;
  491. }
  492. }
  493. unsigned ccGraphicalSegmentationTool::getNumberOfValidEntities() const
  494. {
  495. return static_cast<unsigned>(m_toSegment.size());
  496. }
  497. void ccGraphicalSegmentationTool::updatePolyLine(int x, int y, Qt::MouseButtons buttons)
  498. {
  499. //process not started yet?
  500. if ((m_state & RUNNING) == 0)
  501. {
  502. return;
  503. }
  504. if (!m_associatedWin)
  505. {
  506. assert(false);
  507. return;
  508. }
  509. assert(m_polyVertices);
  510. assert(m_segmentationPoly);
  511. unsigned vertCount = m_polyVertices->size();
  512. //new point (expressed relatively to the screen center)
  513. QPointF pos2D = m_associatedWin->toCenteredGLCoordinates(x, y);
  514. CCVector3 P(static_cast<PointCoordinateType>(pos2D.x()),
  515. static_cast<PointCoordinateType>(pos2D.y()),
  516. 0);
  517. if (m_state & RECTANGLE)
  518. {
  519. //we need 4 points for the rectangle!
  520. if (vertCount != 4)
  521. m_polyVertices->resize(4);
  522. const CCVector3 *A = m_polyVertices->getPointPersistentPtr(0);
  523. CCVector3 *B = const_cast<CCVector3 *>(m_polyVertices->getPointPersistentPtr(1));
  524. CCVector3 *C = const_cast<CCVector3 *>(m_polyVertices->getPointPersistentPtr(2));
  525. CCVector3 *D = const_cast<CCVector3 *>(m_polyVertices->getPointPersistentPtr(3));
  526. *B = CCVector3(A->x, P.y, 0);
  527. *C = P;
  528. *D = CCVector3(P.x, A->y, 0);
  529. if (vertCount != 4)
  530. {
  531. m_segmentationPoly->clear();
  532. if (!m_segmentationPoly->addPointIndex(0, 4))
  533. {
  534. ccLog::Error("Out of memory!");
  535. allowPolylineExport(false);
  536. return;
  537. }
  538. m_segmentationPoly->setClosed(true);
  539. }
  540. }
  541. else if (m_state & POLYLINE)
  542. {
  543. if (vertCount < 2)
  544. return;
  545. //we replace last point by the current one
  546. CCVector3 *lastP = const_cast<CCVector3 *>(m_polyVertices->getPointPersistentPtr(vertCount - 1));
  547. *lastP = P;
  548. }
  549. m_associatedWin->redraw(true, false);
  550. }
  551. void ccGraphicalSegmentationTool::addPointToPolylineExt(int x, int y, bool allowClicksOutside)
  552. {
  553. if ((m_state & STARTED) == 0)
  554. {
  555. return;
  556. }
  557. if (!m_associatedWin)
  558. {
  559. assert(false);
  560. return;
  561. }
  562. if ( !allowClicksOutside
  563. && (x < 0 || y < 0 || x >= m_associatedWin->qtWidth() || y >= m_associatedWin->qtHeight())
  564. )
  565. {
  566. //ignore clicks outside of the 3D view
  567. return;
  568. }
  569. assert(m_polyVertices);
  570. assert(m_segmentationPoly);
  571. unsigned vertCount = m_polyVertices->size();
  572. //particular case: we close the rectangular selection by a 2nd click
  573. if ( m_rectangularSelection
  574. && (vertCount == 4)
  575. && (m_state & RUNNING) )
  576. {
  577. return;
  578. }
  579. //new point
  580. QPointF pos2D = m_associatedWin->toCenteredGLCoordinates(x, y);
  581. CCVector3 P(static_cast<PointCoordinateType>(pos2D.x()),
  582. static_cast<PointCoordinateType>(pos2D.y()),
  583. 0);
  584. //CTRL key pressed at the same time?
  585. bool ctrlKeyPressed = m_rectangularSelection || ((QApplication::keyboardModifiers() & Qt::ControlModifier) == Qt::ControlModifier);
  586. //start new polyline?
  587. if (((m_state & RUNNING) == 0) || vertCount == 0 || ctrlKeyPressed)
  588. {
  589. //reset state
  590. m_state = (ctrlKeyPressed ? RECTANGLE : POLYLINE);
  591. m_state |= STARTED;
  592. run();
  593. //reset polyline
  594. m_polyVertices->clear();
  595. if (!m_polyVertices->reserve(2))
  596. {
  597. ccLog::Error("Out of memory!");
  598. allowPolylineExport(false);
  599. return;
  600. }
  601. //we add the same point twice (the last point will be used for display only)
  602. m_polyVertices->addPoint(P);
  603. m_polyVertices->addPoint(P);
  604. m_segmentationPoly->clear();
  605. if (!m_segmentationPoly->addPointIndex(0, 2))
  606. {
  607. ccLog::Error("Out of memory!");
  608. allowPolylineExport(false);
  609. return;
  610. }
  611. }
  612. else //next points in "polyline mode" only
  613. {
  614. //we were already in 'polyline' mode?
  615. if (m_state & POLYLINE)
  616. {
  617. //ALT key pressed at the same time?
  618. bool altKeyPressed = ((QApplication::keyboardModifiers() & Qt::AltModifier) == Qt::AltModifier);
  619. if (altKeyPressed)
  620. {
  621. // reverse logic: we remove the last point
  622. if (vertCount > 2)
  623. {
  624. m_polyVertices->resize(vertCount - 1);
  625. m_segmentationPoly->resize(m_segmentationPoly->size() - 1);
  626. //we replace last but one point by the current one
  627. CCVector3 *lastP = const_cast<CCVector3*>(m_polyVertices->getPointPersistentPtr(vertCount - 2));
  628. *lastP = P;
  629. m_polyVertices->invalidateBoundingBox();
  630. }
  631. else
  632. {
  633. // nothing to do
  634. }
  635. }
  636. else
  637. {
  638. if (!m_polyVertices->reserve(vertCount + 1))
  639. {
  640. ccLog::Error("Out of memory!");
  641. allowPolylineExport(false);
  642. return;
  643. }
  644. //we replace last point by the current one
  645. CCVector3 *lastP = const_cast<CCVector3*>(m_polyVertices->getPointPersistentPtr(vertCount - 1));
  646. *lastP = P;
  647. //and add a new (equivalent) one
  648. m_polyVertices->addPoint(P);
  649. if (!m_segmentationPoly->addPointIndex(vertCount))
  650. {
  651. ccLog::Error("Out of memory!");
  652. return;
  653. }
  654. m_segmentationPoly->setClosed(true);
  655. }
  656. }
  657. else //we must change mode
  658. {
  659. assert(false); //we shouldn't fall here?!
  660. stopRunning();
  661. addPointToPolylineExt(x, y, allowClicksOutside);
  662. return;
  663. }
  664. }
  665. //DGM: to increase the poll rate of the mouse movements in ccGLWindow::mouseMoveEvent
  666. //we have to completely grab the mouse focus!
  667. //(the only way to take back the control is to right-click now...)
  668. m_associatedWin->doGrabMouse();
  669. m_associatedWin->redraw(true, false);
  670. }
  671. void ccGraphicalSegmentationTool::closeRectangle()
  672. {
  673. //only for rectangle selection in RUNNING mode
  674. if ((m_state & RECTANGLE) == 0 || (m_state & RUNNING) == 0)
  675. return;
  676. assert(m_segmentationPoly);
  677. unsigned vertCount = m_segmentationPoly->size();
  678. if (vertCount < 4)
  679. {
  680. //first point only? we keep the real time update mechanism
  681. if (m_rectangularSelection)
  682. return;
  683. m_segmentationPoly->clear();
  684. m_polyVertices->clear();
  685. allowPolylineExport(false);
  686. }
  687. else
  688. {
  689. allowPolylineExport(true);
  690. }
  691. //stop
  692. stopRunning();
  693. if (m_associatedWin)
  694. {
  695. m_associatedWin->doReleaseMouse();
  696. m_associatedWin->redraw(true, false);
  697. }
  698. }
  699. void ccGraphicalSegmentationTool::closePolyLine(int, int)
  700. {
  701. //only for polyline in RUNNING mode
  702. if ((m_state & POLYLINE) == 0 || (m_state & RUNNING) == 0)
  703. return;
  704. if (m_associatedWin)
  705. {
  706. m_associatedWin->doReleaseMouse();
  707. }
  708. assert(m_segmentationPoly);
  709. unsigned vertCount = m_segmentationPoly->size();
  710. if (vertCount < 4)
  711. {
  712. m_segmentationPoly->clear();
  713. m_polyVertices->clear();
  714. }
  715. else
  716. {
  717. //remove last point!
  718. m_segmentationPoly->resize(vertCount - 1); //can't fail --> smaller
  719. m_segmentationPoly->setClosed(true);
  720. }
  721. //stop
  722. stopRunning();
  723. //set the default import/export icon to 'export' mode
  724. loadSaveToolButton->setDefaultAction(actionExportSegmentationPolyline);
  725. allowPolylineExport(m_segmentationPoly->size() > 1);
  726. if (m_associatedWin)
  727. {
  728. m_associatedWin->redraw(true, false);
  729. }
  730. }
  731. void ccGraphicalSegmentationTool::segmentIn()
  732. {
  733. segment(true);
  734. }
  735. void ccGraphicalSegmentationTool::segmentOut()
  736. {
  737. segment(false);
  738. }
  739. void ccGraphicalSegmentationTool::exportSelection()
  740. {
  741. segment(true, CCCoreLib::NAN_VALUE, true);
  742. }
  743. void ccGraphicalSegmentationTool::segment(bool keepPointsInside, ScalarType classificationValue/*=CCCoreLib::NAN_VALUE*/, bool exportSelection/*=false*/)
  744. {
  745. if (!m_associatedWin)
  746. {
  747. assert(false);
  748. return;
  749. }
  750. if (!m_segmentationPoly)
  751. {
  752. ccLog::Error("No polyline defined!");
  753. return;
  754. }
  755. if (!m_segmentationPoly->isClosed())
  756. {
  757. ccLog::Error("Define and/or close the segmentation polygon first! (right click to close)");
  758. return;
  759. }
  760. // we must close the polyline if we are in RUNNING mode
  761. if ((m_state & POLYLINE) != 0 && (m_state & RUNNING) != 0)
  762. {
  763. QPoint mousePos = m_associatedWin->doMapFromGlobal(QCursor::pos());
  764. ccLog::Warning(QString("Polyline was not closed - we'll close it with the current mouse cursor position: (%1 ; %2)").arg(mousePos.x()).arg(mousePos.y()));
  765. addPointToPolylineExt(mousePos.x(), mousePos.y(), true);
  766. closePolyLine(0, 0);
  767. }
  768. ccGLCameraParameters camera;
  769. m_associatedWin->getGLCameraParameters(camera);
  770. const double half_w = camera.viewport[2] / 2.0;
  771. const double half_h = camera.viewport[3] / 2.0;
  772. //check if the polyline is totally inside the frustum or not
  773. bool polyInsideViewport = true;
  774. {
  775. int vertexCount = static_cast<int>(m_segmentationPoly->size());
  776. for (int i = 0; i < vertexCount; ++i)
  777. {
  778. const CCVector3* P2D = m_segmentationPoly->getPoint(i);
  779. if (P2D->x < -half_w || P2D->x > half_w
  780. || P2D->y < -half_h || P2D->y > half_h)
  781. {
  782. polyInsideViewport = false;
  783. break;
  784. }
  785. }
  786. }
  787. ccLog::PrintDebug("Polyline is fully inside viewport: " + QString(polyInsideViewport ? "Yes" : "No"));
  788. bool classificationMode = CCCoreLib::ScalarField::ValidValue(classificationValue);
  789. // for each selected entity
  790. int errorCount = 0;
  791. for (QSet<ccHObject *>::const_iterator p = m_toSegment.constBegin(); p != m_toSegment.constEnd(); ++p)
  792. {
  793. ccHObject* entity = (*p);
  794. ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(*p);
  795. assert(cloud);
  796. // we enable the visibility array if not done already
  797. if (!cloud->isVisibilityTableInstantiated() && !cloud->resetVisibilityArray())
  798. {
  799. ++errorCount;
  800. continue;
  801. }
  802. ccGenericPointCloud::VisibilityTableType& visibilityArray = cloud->getTheVisibilityArray();
  803. ccGenericPointCloud::VisibilityTableType outVisibilityArray;
  804. if (exportSelection) // simply copy the current visibility array
  805. {
  806. outVisibilityArray = visibilityArray;
  807. }
  808. assert(!visibilityArray.empty());
  809. int cloudSize = static_cast<int>(cloud->size());
  810. // if a classification value is set as input, this means that we want to label the
  811. // set of points, and we don't want to segment it
  812. CCCoreLib::ScalarField* classifSF = nullptr;
  813. if (classificationMode)
  814. {
  815. ccPointCloud* pc = ccHObjectCaster::ToPointCloud(*p);
  816. if (!pc)
  817. {
  818. ccLog::Warning("Can't apply classification to entity " + (*p)->getName());
  819. continue;
  820. }
  821. // check that the 'Classification' scalar field exists
  822. int sfIdx = pc->getScalarFieldIndexByName("Classification");
  823. if (sfIdx < 0)
  824. {
  825. // create the scalar field Classification if needed
  826. sfIdx = pc->addScalarField("Classification");
  827. if (sfIdx < 0)
  828. {
  829. ccLog::Error(tr("Not enough memory"));
  830. return;
  831. }
  832. }
  833. classifSF = pc->getScalarField(sfIdx);
  834. pc->showSF(true);
  835. pc->setCurrentDisplayedScalarField(sfIdx);
  836. }
  837. // we project each point and we check if it falls inside the segmentation polyline
  838. #if defined(_OPENMP)
  839. #pragma omp parallel for num_threads(omp_get_max_threads())
  840. #endif
  841. for (int i = 0; i < cloudSize; ++i)
  842. {
  843. if (visibilityArray[i] == CCCoreLib::POINT_VISIBLE)
  844. {
  845. const CCVector3* P3D = cloud->getPoint(i);
  846. CCVector3d Q2D;
  847. bool pointInFrustum = false;
  848. camera.project(*P3D, Q2D, &pointInFrustum);
  849. bool pointInside = false;
  850. if (pointInFrustum || !polyInsideViewport) //we can only skip the test if the point is outside the viewport/frustum AND the polyline is fully inside the viewport
  851. {
  852. CCVector2 P2D( static_cast<PointCoordinateType>(Q2D.x - half_w),
  853. static_cast<PointCoordinateType>(Q2D.y - half_h));
  854. pointInside = CCCoreLib::ManualSegmentationTools::isPointInsidePoly(P2D, m_segmentationPoly);
  855. }
  856. if (classifSF) // classification mode
  857. {
  858. if (pointInside)
  859. {
  860. classifSF->setValue(i, classificationValue);
  861. }
  862. }
  863. else if (exportSelection)
  864. {
  865. // 'export inside selection' mode
  866. assert(keepPointsInside == true);
  867. visibilityArray[i] = (pointInside ? CCCoreLib::POINT_VISIBLE : CCCoreLib::POINT_HIDDEN);
  868. if (pointInside)
  869. {
  870. // (exported points or triangles will be hidden until the Segment tool is closed)
  871. outVisibilityArray[i] = CCCoreLib::POINT_HIDDEN;
  872. }
  873. }
  874. else
  875. {
  876. // standard segmentation mode
  877. visibilityArray[i] = (keepPointsInside != pointInside ? CCCoreLib::POINT_HIDDEN : CCCoreLib::POINT_VISIBLE);
  878. }
  879. }
  880. }
  881. if (classifSF)
  882. {
  883. classifSF->computeMinAndMax();
  884. }
  885. if (exportSelection)
  886. {
  887. if (entity->isKindOf(CC_TYPES::POINT_CLOUD))
  888. {
  889. ccGenericPointCloud* segmentedCloud = cloud->createNewCloudFromVisibilitySelection();
  890. if (segmentedCloud != nullptr)
  891. {
  892. if (segmentedCloud->size() != 0)
  893. {
  894. segmentedCloud->setName(cloud->getName() + ".part");
  895. MainWindow::TheInstance()->addToDB(segmentedCloud, false, true, false, false);
  896. segmentedCloud->setEnabled(false);
  897. m_enableOnClose.insert(segmentedCloud);
  898. m_disableOnClose.insert(entity);
  899. }
  900. else // empty result: we ignore it
  901. {
  902. delete segmentedCloud;
  903. segmentedCloud = nullptr;
  904. }
  905. }
  906. else
  907. {
  908. ccLog::Warning("Nothing to export, selection is empty");
  909. return;
  910. }
  911. }
  912. else if (entity->isKindOf(CC_TYPES::MESH))
  913. {
  914. ccMesh* mesh = ccHObjectCaster::ToMesh(entity);
  915. ccMesh* segmentedMesh = mesh->createNewMeshFromSelection(false);
  916. if (segmentedMesh != nullptr)
  917. {
  918. if (segmentedMesh->size() != 0)
  919. {
  920. segmentedMesh->setName(cloud->getName() + ".part");
  921. MainWindow::TheInstance()->addToDB(segmentedMesh, false, true, false, false);
  922. segmentedMesh->setEnabled(false);
  923. m_enableOnClose.insert(segmentedMesh);
  924. m_disableOnClose.insert(entity);
  925. }
  926. else // empty result: we ignore it
  927. {
  928. delete segmentedMesh;
  929. segmentedMesh = nullptr;
  930. }
  931. }
  932. else
  933. {
  934. ccLog::Warning("Nothing to export, selection is empty");
  935. return;
  936. }
  937. }
  938. else
  939. {
  940. ccLog::Warning("Entity type is not supported in 'export selection' mode, only points clouds and meshes are accepted");
  941. return;
  942. }
  943. visibilityArray = outVisibilityArray; // show only the remaining points
  944. }
  945. }
  946. if (errorCount != 0)
  947. {
  948. if (errorCount == m_toSegment.size())
  949. {
  950. ccLog::Error(tr("Not enough memory: no entity could be segmented"));
  951. }
  952. else
  953. {
  954. ccLog::Error(tr("Not enough memory: not all entities were segmented"));
  955. }
  956. }
  957. if (classificationMode || exportSelection)
  958. {
  959. m_associatedWin->redraw();
  960. }
  961. else
  962. {
  963. m_somethingHasChanged = true;
  964. validButton->setEnabled(true);
  965. validAndDeleteButton->setEnabled(true);
  966. razButton->setEnabled(true);
  967. pauseSegmentationMode(true);
  968. }
  969. }
  970. void ccGraphicalSegmentationTool::run()
  971. {
  972. m_state |= RUNNING;
  973. buttonsFrame->setEnabled(false); // we disable the buttons when running
  974. }
  975. void ccGraphicalSegmentationTool::stopRunning()
  976. {
  977. m_state &= (~RUNNING);
  978. buttonsFrame->setEnabled(true); // we restore the buttons when running is stopped
  979. }
  980. void ccGraphicalSegmentationTool::pauseSegmentationMode(bool state)
  981. {
  982. assert(m_polyVertices && m_segmentationPoly);
  983. if (!m_associatedWin)
  984. return;
  985. if (state/*=activate pause mode*/)
  986. {
  987. stopRunning();
  988. m_state = PAUSED;
  989. if (m_polyVertices->size() != 0)
  990. {
  991. m_segmentationPoly->clear();
  992. m_polyVertices->clear();
  993. allowPolylineExport(false);
  994. }
  995. if (m_associatedWin)
  996. {
  997. m_associatedWin->doReleaseMouse();
  998. }
  999. m_associatedWin->setInteractionMode(ccGLWindowInterface::MODE_TRANSFORM_CAMERA);
  1000. m_associatedWin->displayNewMessage("Segmentation [PAUSED]", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1001. m_associatedWin->displayNewMessage("Unpause to segment again", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1002. }
  1003. else
  1004. {
  1005. m_state = STARTED;
  1006. m_associatedWin->setInteractionMode(ccGLWindowInterface::INTERACT_SEND_ALL_SIGNALS);
  1007. if (m_rectangularSelection)
  1008. {
  1009. m_associatedWin->displayNewMessage("Segmentation [ON] (rectangular selection)", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1010. m_associatedWin->displayNewMessage("Left click: set opposite corners", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1011. }
  1012. else
  1013. {
  1014. m_associatedWin->displayNewMessage("Segmentation [ON] (polygonal selection)", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1015. m_associatedWin->displayNewMessage("Left click: add contour points / ALT + left click: remove last / Right click: close", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1016. }
  1017. }
  1018. //update mini-GUI
  1019. pauseButton->blockSignals(true);
  1020. pauseButton->setChecked(state);
  1021. pauseButton->blockSignals(false);
  1022. m_associatedWin->redraw(!state);
  1023. }
  1024. void ccGraphicalSegmentationTool::setClassificationValue()
  1025. {
  1026. static int s_classValue = 0;
  1027. bool ok = false;
  1028. int iValue = QInputDialog::getInt(m_associatedWin->asWidget(), QT_TR_NOOP("Classification"), QT_TR_NOOP("value"), s_classValue, -1000000, 1000000, 1, &ok);
  1029. if (!ok)
  1030. {
  1031. return;
  1032. }
  1033. s_classValue = iValue;
  1034. segment(true, static_cast<ScalarType>(s_classValue));
  1035. }
  1036. void ccGraphicalSegmentationTool::doSetPolylineSelection()
  1037. {
  1038. if (!m_rectangularSelection)
  1039. return;
  1040. selectionModelButton->setDefaultAction(actionSetPolylineSelection);
  1041. m_rectangularSelection = false;
  1042. if (m_state != PAUSED)
  1043. {
  1044. pauseSegmentationMode(true);
  1045. pauseSegmentationMode(false);
  1046. }
  1047. m_associatedWin->displayNewMessage(QString(), ccGLWindowInterface::UPPER_CENTER_MESSAGE); //clear the area
  1048. m_associatedWin->displayNewMessage("Segmentation [ON] (rectangular selection)", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1049. m_associatedWin->displayNewMessage("Right click: set opposite corners", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1050. }
  1051. void ccGraphicalSegmentationTool::doSetRectangularSelection()
  1052. {
  1053. if (m_rectangularSelection)
  1054. return;
  1055. selectionModelButton->setDefaultAction(actionSetRectangularSelection);
  1056. m_rectangularSelection=true;
  1057. if (m_state != PAUSED)
  1058. {
  1059. pauseSegmentationMode(true);
  1060. pauseSegmentationMode(false);
  1061. }
  1062. m_associatedWin->displayNewMessage(QString(), ccGLWindowInterface::UPPER_CENTER_MESSAGE); //clear the area
  1063. m_associatedWin->displayNewMessage("Segmentation [ON] (rectangular selection)", ccGLWindowInterface::UPPER_CENTER_MESSAGE, false, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1064. m_associatedWin->displayNewMessage("Right click: set opposite corners", ccGLWindowInterface::UPPER_CENTER_MESSAGE, true, 3600, ccGLWindowInterface::MANUAL_SEGMENTATION_MESSAGE);
  1065. }
  1066. void ccGraphicalSegmentationTool::doActionUseExistingPolyline()
  1067. {
  1068. if (!m_associatedWin)
  1069. {
  1070. assert(false);
  1071. return;
  1072. }
  1073. MainWindow *mainWindow = MainWindow::TheInstance();
  1074. if (mainWindow)
  1075. {
  1076. ccHObject *root = mainWindow->dbRootObject();
  1077. ccHObject::Container polylines;
  1078. if (root)
  1079. {
  1080. root->filterChildren(polylines, true, CC_TYPES::POLY_LINE);
  1081. }
  1082. if (!polylines.empty())
  1083. {
  1084. int index = ccItemSelectionDlg::SelectEntity(polylines, 0, this);
  1085. if (index < 0)
  1086. return;
  1087. assert(index >= 0 && index < static_cast<int>(polylines.size()));
  1088. assert(polylines[index]->isA(CC_TYPES::POLY_LINE));
  1089. ccPolyline* poly = static_cast<ccPolyline*>(polylines[index]);
  1090. //look for an associated viewport
  1091. ccHObject::Container viewports;
  1092. if (poly->filterChildren(viewports, false, CC_TYPES::VIEWPORT_2D_OBJECT, true) == 1)
  1093. {
  1094. //shall we apply this viewport?
  1095. if (QMessageBox::question( m_associatedWin->asWidget(),
  1096. "Associated viewport",
  1097. "The selected polyline has an associated viewport: do you want to apply it?",
  1098. QMessageBox::Yes,
  1099. QMessageBox::No) == QMessageBox::Yes)
  1100. {
  1101. m_associatedWin->setViewportParameters(static_cast<cc2DViewportObject *>(viewports.front())->getParameters());
  1102. m_associatedWin->redraw(false);
  1103. }
  1104. }
  1105. CCCoreLib::GenericIndexedCloudPersist *vertices = poly->getAssociatedCloud();
  1106. bool mode3D = !poly->is2DMode();
  1107. //viewing parameters (for conversion from 3D to 2D)
  1108. ccGLCameraParameters camera;
  1109. m_associatedWin->getGLCameraParameters(camera);
  1110. const double half_w = camera.viewport[2] / 2.0;
  1111. const double half_h = camera.viewport[3] / 2.0;
  1112. //force polygonal selection mode
  1113. doSetPolylineSelection();
  1114. m_segmentationPoly->clear();
  1115. m_polyVertices->clear();
  1116. allowPolylineExport(false);
  1117. //duplicate polyline 'a minima' (only points and indexes + closed state)
  1118. if ( m_polyVertices->reserve(vertices->size() + (poly->isClosed() ? 0 : 1))
  1119. && m_segmentationPoly->reserve(poly->size() + (poly->isClosed() ? 0 : 1)))
  1120. {
  1121. for (unsigned i = 0; i < vertices->size(); ++i)
  1122. {
  1123. CCVector3 P = *vertices->getPoint(i);
  1124. if (mode3D)
  1125. {
  1126. CCVector3d Q2D;
  1127. camera.project(P, Q2D);
  1128. P.x = static_cast<PointCoordinateType>(Q2D.x - half_w);
  1129. P.y = static_cast<PointCoordinateType>(Q2D.y - half_h);
  1130. P.z = 0;
  1131. }
  1132. m_polyVertices->addPoint(P);
  1133. }
  1134. for (unsigned j = 0; j < poly->size(); ++j)
  1135. {
  1136. m_segmentationPoly->addPointIndex(poly->getPointGlobalIndex(j));
  1137. }
  1138. m_segmentationPoly->setClosed(poly->isClosed());
  1139. if (m_segmentationPoly->isClosed())
  1140. {
  1141. //stop (but we can't call pauseSegmentationMode as it would remove the current polyline)
  1142. stopRunning();
  1143. allowPolylineExport(m_segmentationPoly->size() > 1);
  1144. }
  1145. else if (vertices->size())
  1146. {
  1147. //we make as if the segmentation was in progress
  1148. pauseSegmentationMode(false);
  1149. unsigned lastIndex = vertices->size() - 1;
  1150. m_polyVertices->addPoint(*m_polyVertices->getPoint(lastIndex));
  1151. m_segmentationPoly->addPointIndex(lastIndex + 1);
  1152. m_segmentationPoly->setClosed(true);
  1153. m_state |= POLYLINE;
  1154. run();
  1155. }
  1156. m_rectangularSelection = false;
  1157. m_associatedWin->redraw(true, false);
  1158. }
  1159. else
  1160. {
  1161. ccLog::Error("Not enough memory!");
  1162. }
  1163. }
  1164. else
  1165. {
  1166. ccLog::Error("No polyline in DB!");
  1167. }
  1168. }
  1169. }
  1170. static unsigned s_polylineExportCount = 0;
  1171. void ccGraphicalSegmentationTool::doExportSegmentationPolyline()
  1172. {
  1173. MainWindow *mainWindow = MainWindow::TheInstance();
  1174. if (mainWindow && m_segmentationPoly)
  1175. {
  1176. bool mode2D = false;
  1177. #ifdef ALLOW_2D_OR_3D_EXPORT
  1178. QMessageBox messageBox(nullptr);
  1179. messageBox.setWindowTitle("Choose export type");
  1180. messageBox.setText("Export polyline in:\n - 2D (with coordinates relative to the screen)\n - 3D (with coordinates relative to the segmented entities)");
  1181. QPushButton *button2D = new QPushButton("2D");
  1182. QPushButton *button3D = new QPushButton("3D");
  1183. messageBox.addButton(button2D,QMessageBox::AcceptRole);
  1184. messageBox.addButton(button3D,QMessageBox::AcceptRole);
  1185. messageBox.addButton(QMessageBox::Cancel);
  1186. messageBox.setDefaultButton(button3D);
  1187. messageBox.exec();
  1188. if (messageBox.clickedButton() == messageBox.button(QMessageBox::Cancel))
  1189. {
  1190. //process cancelled by user
  1191. return;
  1192. }
  1193. mode2D = (messageBox.clickedButton() == button2D);
  1194. #endif
  1195. ccPolyline *poly = new ccPolyline(*m_segmentationPoly);
  1196. //if the polyline is 2D and we export the polyline in 3D, we must project its vertices
  1197. if (!mode2D)
  1198. {
  1199. //get current display parameters
  1200. ccGLCameraParameters camera;
  1201. m_associatedWin->getGLCameraParameters(camera);
  1202. const double half_w = camera.viewport[2] / 2.0;
  1203. const double half_h = camera.viewport[3] / 2.0;
  1204. //project the 2D polyline in 3D
  1205. CCCoreLib::GenericIndexedCloudPersist *vertices = poly->getAssociatedCloud();
  1206. ccPointCloud *verticesPC = dynamic_cast<ccPointCloud *>(vertices);
  1207. if (verticesPC)
  1208. {
  1209. for (unsigned i = 0; i < vertices->size(); ++i)
  1210. {
  1211. CCVector3 *Pscreen = const_cast<CCVector3 *>(verticesPC->getPoint(i));
  1212. CCVector3d Pd(half_w + Pscreen->x, half_h + Pscreen->y, 0/*Pscreen->z*/);
  1213. CCVector3d Q3D;
  1214. camera.unproject(Pd, Q3D);
  1215. *Pscreen = Q3D.toPC();
  1216. }
  1217. verticesPC->invalidateBoundingBox();
  1218. }
  1219. else
  1220. {
  1221. assert(false);
  1222. ccLog::Warning("[Segmentation] Failed to convert 2D polyline to 3D! (internal inconsistency)");
  1223. mode2D = false;
  1224. }
  1225. //export Global Shift & Scale info (if any)
  1226. bool hasGlobalShift = false;
  1227. CCVector3d globalShift(0, 0, 0);
  1228. double globalScale = 1.0;
  1229. {
  1230. for (QSet<ccHObject *>::const_iterator it = m_toSegment.constBegin(); it != m_toSegment.constEnd(); ++it)
  1231. {
  1232. ccShiftedObject *shifted = ccHObjectCaster::ToShifted(*it);
  1233. bool isShifted = (shifted && shifted->isShifted());
  1234. if (isShifted)
  1235. {
  1236. globalShift = shifted->getGlobalShift();
  1237. globalScale = shifted->getGlobalScale();
  1238. hasGlobalShift = true;
  1239. break;
  1240. }
  1241. }
  1242. }
  1243. if (hasGlobalShift && m_toSegment.size() != 1)
  1244. {
  1245. hasGlobalShift = (QMessageBox::question(MainWindow::TheInstance(), "Apply Global Shift", "At least one of the segmented entity has been shifted. Apply the same shift to the polyline?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes);
  1246. }
  1247. if (hasGlobalShift)
  1248. {
  1249. poly->setGlobalShift(globalShift);
  1250. poly->setGlobalScale(globalScale);
  1251. }
  1252. }
  1253. QString polyName = QString("Segmentation polyline #%1").arg(++s_polylineExportCount);
  1254. poly->setName(polyName);
  1255. poly->setEnabled(false); //we don't want it to appear while the segmentation mode is enabled! (anyway it's 2D only...)
  1256. poly->set2DMode(mode2D);
  1257. poly->setColor(ccColor::yellow); //we use a different color so as to differentiate them from the active polyline!
  1258. //save associated viewport
  1259. cc2DViewportObject *viewportObject = new cc2DViewportObject(polyName + QString(" viewport"));
  1260. viewportObject->setParameters(m_associatedWin->getViewportParameters());
  1261. viewportObject->setDisplay(m_associatedWin);
  1262. poly->addChild(viewportObject);
  1263. mainWindow->addToDB(poly, false, false, false);
  1264. ccLog::Print(QString("[Segmentation] Polyline exported (%1 vertices)").arg(poly->size()));
  1265. }
  1266. }
  1267. void ccGraphicalSegmentationTool::options()
  1268. {
  1269. ccGraphicalSegmentationOptionsDlg optionsDlg("Segmentation Options", this);
  1270. if (!optionsDlg.exec())
  1271. return;
  1272. }
  1273. void ccGraphicalSegmentationTool::apply()
  1274. {
  1275. m_deleteHiddenParts = false;
  1276. stop(true);
  1277. }
  1278. void ccGraphicalSegmentationTool::applyAndDelete()
  1279. {
  1280. m_deleteHiddenParts = true;
  1281. stop(true);
  1282. }
  1283. void ccGraphicalSegmentationTool::cancel()
  1284. {
  1285. reset();
  1286. m_deleteHiddenParts = false;
  1287. stop(false);
  1288. }
  1289. static void RemoveUnusedLabelsAndUpdateTheOthers( std::set<cc2DLabel*>& watchedLabels,
  1290. ccHObject* entity,
  1291. const std::vector<int>& newIndexesOfRemainingPointsOrTriangles,
  1292. ccMainAppInterface* app )
  1293. {
  1294. if (!app)
  1295. {
  1296. assert(false);
  1297. return;
  1298. }
  1299. std::set<cc2DLabel*>::iterator it = watchedLabels.begin();
  1300. while (it != watchedLabels.end())
  1301. {
  1302. cc2DLabel* label = *it;
  1303. assert(label);
  1304. for (unsigned i = 0; i < label->size(); ++i)
  1305. {
  1306. cc2DLabel::PickedPoint& pp = label->getPickedPoint(i);
  1307. if (pp.entity() == entity)
  1308. {
  1309. if (pp.index < newIndexesOfRemainingPointsOrTriangles.size()
  1310. && newIndexesOfRemainingPointsOrTriangles[pp.index] >= 0)
  1311. {
  1312. // update the 'pointer'
  1313. pp.index = newIndexesOfRemainingPointsOrTriangles[pp.index];
  1314. }
  1315. else
  1316. {
  1317. // delete the label
  1318. ccHObject* labelParent = label->getParent();
  1319. ccMainAppInterface::ccHObjectContext parentContext;
  1320. bool saveContext = (labelParent != entity && !entity->isAncestorOf(labelParent));
  1321. if (saveContext)
  1322. parentContext = app->removeObjectTemporarilyFromDBTree(labelParent);
  1323. labelParent->removeChild(label);
  1324. if (saveContext)
  1325. app->putObjectBackIntoDBTree(labelParent, parentContext);
  1326. label = nullptr;
  1327. it = watchedLabels.erase(it);
  1328. break;
  1329. }
  1330. }
  1331. }
  1332. if (label)
  1333. {
  1334. // keep the label and move on
  1335. ++it;
  1336. }
  1337. }
  1338. }
  1339. bool ccGraphicalSegmentationTool::applySegmentation(ccMainAppInterface* app, ccHObject::Container& newEntities)
  1340. {
  1341. if (!app)
  1342. {
  1343. assert(false);
  1344. return false;
  1345. }
  1346. bool cantModifyPolylinesWarningIssued = false;
  1347. // specific case: labels
  1348. std::set<cc2DLabel*> watchedLabels;
  1349. try
  1350. {
  1351. if (app->dbRootObject())
  1352. {
  1353. ccHObject::Container loadedLabels;
  1354. app->dbRootObject()->filterChildren(loadedLabels, true, CC_TYPES::LABEL_2D);
  1355. for (ccHObject* labelEntity : loadedLabels)
  1356. {
  1357. cc2DLabel* label = static_cast<cc2DLabel*>(labelEntity);
  1358. if (!label->getParent())
  1359. {
  1360. // sanity check: should never happen
  1361. assert(false);
  1362. continue;
  1363. }
  1364. for (unsigned i = 0; i < label->size(); ++i)
  1365. {
  1366. const cc2DLabel::PickedPoint& pp = label->getPickedPoint(i);
  1367. if (m_toSegment.contains(pp.entity()))
  1368. {
  1369. // we will watch this label as it may be deprecated by the segmentation process
  1370. watchedLabels.insert(label);
  1371. break;
  1372. }
  1373. }
  1374. }
  1375. }
  1376. }
  1377. catch (const std::bad_alloc&)
  1378. {
  1379. // not enough memory
  1380. ccLog::Error(tr("Not enough memory"));
  1381. return false;
  1382. }
  1383. for (QSet<ccHObject*>::iterator p = m_toSegment.begin(); p != m_toSegment.end(); )
  1384. {
  1385. ccHObject* entity = (*p);
  1386. // check first if we can modify this entity directly or if there might be dire consequences...
  1387. bool canModify = true;
  1388. if (entity->isLocked())
  1389. {
  1390. //we can't delete this entity
  1391. ccLog::Warning("Entity " + entity->getName() + " is locked. We won't be able to modify it");
  1392. canModify = false;
  1393. }
  1394. if (entity->isKindOf(CC_TYPES::POINT_CLOUD))
  1395. {
  1396. ccGenericPointCloud* cloud = static_cast<ccGenericPointCloud*>(entity);
  1397. if (cloud->size() == 0)
  1398. {
  1399. //ignore this cloud
  1400. ccLog::Warning("Cloud " + cloud->getName() + " is empty. We will ignore it");
  1401. continue;
  1402. }
  1403. if (canModify)
  1404. {
  1405. // check that the point cloud is not the vertices of a mesh or of a polyline
  1406. if (ccGenericMesh::IsCloudVerticesOfMesh(cloud))
  1407. {
  1408. //we can't delete this cloud
  1409. ccLog::Warning("Cloud " + cloud->getName() + " seems to be the vertices of a mesh. We won't be able to modify it");
  1410. canModify = false;
  1411. }
  1412. else if (ccPolyline::IsCloudVerticesOfPolyline(cloud))
  1413. {
  1414. //we can't delete this cloud
  1415. ccLog::Warning("Cloud " + cloud->getName() + " seems to be the vertices of a polyine. We won't be able to modify it");
  1416. canModify = false;
  1417. }
  1418. }
  1419. }
  1420. else if (entity->isA(CC_TYPES::MESH)) // TODO: sub-meshes and primitives are not handled for now
  1421. {
  1422. ccGenericMesh* mesh = static_cast<ccGenericMesh*>(entity);
  1423. if (mesh->size() == 0 || mesh->getAssociatedCloud()->size() == 0)
  1424. {
  1425. //ignore this mesh
  1426. ccLog::Warning("Mesh " + mesh->getName() + " is empty. We will ignore it");
  1427. continue;
  1428. }
  1429. }
  1430. else if (entity->isKindOf(CC_TYPES::POLY_LINE))
  1431. {
  1432. ccPolyline* poly = static_cast<ccPolyline*>(entity);
  1433. if (poly->size() == 0 || poly->getAssociatedCloud()->size() == 0)
  1434. {
  1435. //ignore this polyline
  1436. ccLog::Warning("Polyline " + poly->getName() + " is empty. We will ignore it");
  1437. continue;
  1438. }
  1439. // can't modify polylines yet
  1440. if (!cantModifyPolylinesWarningIssued)
  1441. {
  1442. ccLog::Warning("Can't modify polylines. A new polyline will be created.");
  1443. cantModifyPolylinesWarningIssued = true;
  1444. }
  1445. canModify = false;
  1446. }
  1447. else
  1448. {
  1449. // can't change this entity anyway
  1450. continue;
  1451. }
  1452. if (entity->isKindOf(CC_TYPES::POINT_CLOUD) || entity->isKindOf(CC_TYPES::MESH))
  1453. {
  1454. // we temporarily detach the entity, as it may undergo
  1455. // 'severe' modifications (octree deletion, etc.) --> see ccPointCloud::createNewCloudFromVisibilitySelection
  1456. ccMainAppInterface::ccHObjectContext objContext = app->removeObjectTemporarilyFromDBTree(entity);
  1457. bool removeSelectedElementsFromEntity = (canModify && !m_deleteHiddenParts);
  1458. // apply segmentation
  1459. ccHObject* segmentationResult = nullptr;
  1460. bool deleteOriginalEntity = (canModify && m_deleteHiddenParts);
  1461. if (entity->isKindOf(CC_TYPES::POINT_CLOUD))
  1462. {
  1463. ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(entity);
  1464. std::vector<int> newIndexesOfRemainingPoints;
  1465. ccGenericPointCloud* segmentedCloud = cloud->createNewCloudFromVisibilitySelection( removeSelectedElementsFromEntity,
  1466. nullptr,
  1467. deleteOriginalEntity ? nullptr : &newIndexesOfRemainingPoints);
  1468. if (segmentedCloud)
  1469. {
  1470. if (segmentedCloud->size() == 0)
  1471. {
  1472. // empty result: we ignore it
  1473. delete segmentedCloud;
  1474. segmentedCloud = nullptr;
  1475. }
  1476. else if (segmentedCloud == cloud)
  1477. {
  1478. //specific case: all points were selected, nothing to do
  1479. app->putObjectBackIntoDBTree(entity, objContext);
  1480. ++p;
  1481. continue;
  1482. }
  1483. else // we have a new entity
  1484. {
  1485. segmentationResult = segmentedCloud;
  1486. deleteOriginalEntity |= (cloud->size() == 0);
  1487. if (removeSelectedElementsFromEntity && !deleteOriginalEntity) // if we have removed points from the original entity
  1488. {
  1489. // be smart and keep only the necessary labels
  1490. RemoveUnusedLabelsAndUpdateTheOthers(watchedLabels, cloud, newIndexesOfRemainingPoints, app);
  1491. }
  1492. }
  1493. }
  1494. }
  1495. else if (entity->isA(CC_TYPES::MESH))
  1496. {
  1497. ccMesh* mesh = ccHObjectCaster::ToMesh(entity);
  1498. std::vector<int> newIndexesOfRemainingTriangles;
  1499. ccMesh* segmentatedMesh = mesh->createNewMeshFromSelection( removeSelectedElementsFromEntity,
  1500. deleteOriginalEntity ? nullptr : &newIndexesOfRemainingTriangles,
  1501. true );
  1502. if (segmentatedMesh)
  1503. {
  1504. if (segmentatedMesh->size() == 0)
  1505. {
  1506. // empty result: we ignore it
  1507. delete segmentatedMesh;
  1508. segmentatedMesh = nullptr;
  1509. }
  1510. else if (segmentatedMesh == mesh)
  1511. {
  1512. //specific case: all triangles were selected, nothing to do
  1513. app->putObjectBackIntoDBTree(entity, objContext);
  1514. ++p;
  1515. continue;
  1516. }
  1517. else // we have a new entity
  1518. {
  1519. segmentationResult = segmentatedMesh;
  1520. deleteOriginalEntity |= (mesh->size() == 0);
  1521. if (removeSelectedElementsFromEntity && !deleteOriginalEntity)
  1522. {
  1523. // be smart and keep only the necessary labels
  1524. RemoveUnusedLabelsAndUpdateTheOthers(watchedLabels, mesh, newIndexesOfRemainingTriangles, app);
  1525. }
  1526. }
  1527. }
  1528. }
  1529. else
  1530. {
  1531. // we only expect clouds or meshes here
  1532. assert(false);
  1533. }
  1534. if (segmentationResult) //we have a result (= a new entity)
  1535. {
  1536. // update suffix
  1537. {
  1538. QSettings settings;
  1539. settings.beginGroup(ccGraphicalSegmentationOptionsDlg::SegmentationToolOptionsKey());
  1540. QString segmentedSuffix = settings.value(ccGraphicalSegmentationOptionsDlg::SegmentedSuffixKey(), ".segmented").toString();
  1541. settings.endGroup();
  1542. QString resultName = entity->getName();
  1543. if (!resultName.endsWith(segmentedSuffix))
  1544. {
  1545. resultName += segmentedSuffix;
  1546. }
  1547. segmentationResult->setName(resultName);
  1548. if (segmentationResult->isKindOf(CC_TYPES::MESH) && entity->isKindOf(CC_TYPES::MESH))
  1549. {
  1550. // update the mesh vertices as well
  1551. ccGenericMesh* mesh = ccHObjectCaster::ToGenericMesh(entity);
  1552. ccGenericMesh* resultMesh = ccHObjectCaster::ToGenericMesh(segmentationResult);
  1553. QString verticesName = mesh->getAssociatedCloud()->getName();
  1554. if (!verticesName.endsWith(segmentedSuffix))
  1555. {
  1556. verticesName += segmentedSuffix;
  1557. }
  1558. resultMesh->getAssociatedCloud()->setName(verticesName);
  1559. }
  1560. }
  1561. if (removeSelectedElementsFromEntity && !deleteOriginalEntity) // if we were able to modify the original entity
  1562. {
  1563. // update the name of the original entity
  1564. QSettings settings;
  1565. settings.beginGroup(ccGraphicalSegmentationOptionsDlg::SegmentationToolOptionsKey());
  1566. QString remainingSuffix = settings.value(ccGraphicalSegmentationOptionsDlg::RemainingSuffixKey(), ".remaining").toString();
  1567. settings.endGroup();
  1568. if (!entity->getName().endsWith(remainingSuffix))
  1569. {
  1570. entity->setName(entity->getName() + remainingSuffix);
  1571. }
  1572. if (entity->isKindOf(CC_TYPES::MESH))
  1573. {
  1574. // update the mesh vertices as well
  1575. ccGenericMesh* mesh = ccHObjectCaster::ToGenericMesh(entity);
  1576. QString verticesName = mesh->getAssociatedCloud()->getName();
  1577. if (!verticesName.endsWith(remainingSuffix))
  1578. {
  1579. mesh->getAssociatedCloud()->setName(verticesName + remainingSuffix);
  1580. }
  1581. }
  1582. //specific case: deprecate GBL sensors' depth buffer
  1583. ccHObject::Container gblSensors;
  1584. entity->filterChildren(gblSensors, false, CC_TYPES::GBL_SENSOR);
  1585. for (ccHObject* child : gblSensors)
  1586. {
  1587. ccGBLSensor* sensor = ccHObjectCaster::ToGBLSensor(child);
  1588. //clear the associated depth buffer of the original sensor (deprecated)
  1589. sensor->clearDepthBuffer();
  1590. assert(entity->isKindOf(CC_TYPES::POINT_CLOUD));
  1591. }
  1592. }
  1593. //we look for first non-mesh or non-cloud parent
  1594. ccHObject* resultParent = objContext.parent;
  1595. while (resultParent && (resultParent->isKindOf(CC_TYPES::MESH) || resultParent->isKindOf(CC_TYPES::POINT_CLOUD)))
  1596. {
  1597. resultParent = resultParent->getParent();
  1598. }
  1599. if (resultParent)
  1600. {
  1601. resultParent->addChild(segmentationResult);
  1602. }
  1603. segmentationResult->setDisplay_recursive(entity->getDisplay());
  1604. segmentationResult->prepareDisplayForRefresh_recursive();
  1605. app->addToDB(segmentationResult, false, true, false, false);
  1606. newEntities.push_back(segmentationResult);
  1607. }
  1608. if (!deleteOriginalEntity)
  1609. {
  1610. app->putObjectBackIntoDBTree(entity, objContext);
  1611. ++p;
  1612. }
  1613. else
  1614. {
  1615. // remove all labels that depend on this entity
  1616. std::set<cc2DLabel*>::iterator it = watchedLabels.begin();
  1617. while (it != watchedLabels.end())
  1618. {
  1619. cc2DLabel* label = *it;
  1620. assert(label);
  1621. for (unsigned i = 0; i < label->size(); ++i)
  1622. {
  1623. cc2DLabel::PickedPoint& pp = label->getPickedPoint(i);
  1624. if (pp.entity() == entity)
  1625. {
  1626. // delete the label
  1627. ccHObject* labelParent = label->getParent();
  1628. ccMainAppInterface::ccHObjectContext parentContext;
  1629. bool saveContext = (labelParent != entity && !entity->isAncestorOf(labelParent));
  1630. if (saveContext)
  1631. parentContext = app->removeObjectTemporarilyFromDBTree(labelParent);
  1632. labelParent->removeChild(label);
  1633. if (saveContext)
  1634. app->putObjectBackIntoDBTree(labelParent, parentContext);
  1635. label = nullptr;
  1636. it = watchedLabels.erase(it);
  1637. break;
  1638. }
  1639. }
  1640. if (label)
  1641. {
  1642. // keep the label and move on
  1643. ++it;
  1644. }
  1645. }
  1646. prepareEntityForRemoval(entity, false);
  1647. p = m_toSegment.erase(p);
  1648. delete entity; // TODO: should we wait that all entities are processed before removing it?
  1649. entity = nullptr;
  1650. }
  1651. }
  1652. else if (entity->isKindOf(CC_TYPES::POLY_LINE))
  1653. {
  1654. ccPolyline* poly = static_cast<ccPolyline*>(entity);
  1655. ccHObject* polyParent = poly->getParent();
  1656. if (!polyParent)
  1657. {
  1658. polyParent = app->dbRootObject();
  1659. }
  1660. assert(polyParent);
  1661. std::vector<ccPolyline*> polylines;
  1662. if (poly->createNewPolylinesFromSelection(polylines))
  1663. {
  1664. for (ccPolyline* p : polylines)
  1665. {
  1666. p->setDisplay_recursive(poly->getDisplay());
  1667. if (polyParent)
  1668. polyParent->addChild(p);
  1669. app->addToDB(p, false, true, false, false);
  1670. newEntities.push_back(p);
  1671. }
  1672. poly->prepareDisplayForRefresh();
  1673. }
  1674. ++p;
  1675. }
  1676. else
  1677. {
  1678. assert(false);
  1679. ++p;
  1680. }
  1681. }
  1682. removeAllEntities();
  1683. return true;
  1684. }