40 #include <QInputDialog>
42 #include <QMessageBox>
43 #include <QPushButton>
56 Ui::GraphicalSegmentationDlg(),
57 m_somethingHasChanged(false),
59 m_segmentationPoly(nullptr),
60 m_polyVertices(nullptr),
61 m_rectangularSelection(false),
62 m_deleteHiddenParts(false) {
69 connect(inButton, &QToolButton::clicked,
this,
71 connect(outButton, &QToolButton::clicked,
this,
73 connect(razButton, &QToolButton::clicked,
this,
75 connect(validButton, &QToolButton::clicked,
this,
77 connect(validAndDeleteButton, &QToolButton::clicked,
this,
79 connect(cancelButton, &QToolButton::clicked,
this,
81 connect(pauseButton, &QToolButton::toggled,
this,
85 connect(actionSetPolylineSelection, &QAction::triggered,
this,
87 connect(actionSetRectangularSelection, &QAction::triggered,
this,
90 connect(actionUseExistingPolyline, &QAction::triggered,
this,
92 connect(actionExportSegmentationPolyline, &QAction::triggered,
this,
108 QMenu* selectionModeMenu =
new QMenu(
this);
109 selectionModeMenu->addAction(actionSetPolylineSelection);
110 selectionModeMenu->addAction(actionSetRectangularSelection);
111 selectionModelButton->setDefaultAction(actionSetPolylineSelection);
112 selectionModelButton->setMenu(selectionModeMenu);
114 QMenu* importExportMenu =
new QMenu(
this);
115 importExportMenu->addAction(actionUseExistingPolyline);
116 importExportMenu->addAction(actionExportSegmentationPolyline);
117 loadSaveToolButton->setMenu(importExportMenu);
131 actionExportSegmentationPolyline->setEnabled(
true);
133 loadSaveToolButton->setDefaultAction(actionUseExistingPolyline);
134 actionExportSegmentationPolyline->setEnabled(
false);
149 pauseButton->toggle();
161 validButton->click();
164 validAndDeleteButton->click();
167 cancelButton->click();
192 SIGNAL(leftButtonClicked(
int,
int)),
this,
195 SIGNAL(rightButtonClicked(
int,
int)),
this,
198 SIGNAL(mouseMoved(
int,
int, Qt::MouseButtons)),
this,
226 ccHObject* entity,
bool unallocateVisibilityArrays) {
235 if (unallocateVisibilityArrays) {
257 associatedPolyline) {
265 for (QSet<ccHObject*>::const_iterator p =
m_toSegment.constBegin();
296 for (QSet<ccHObject*>::iterator p =
m_toSegment.begin();
298 (*p)->setRedrawFlagRecursive(state);
304 for (QSet<ccHObject*>::const_iterator p =
m_toSegment.constBegin();
319 razButton->setEnabled(
false);
320 validButton->setEnabled(
false);
321 validAndDeleteButton->setEnabled(
false);
322 loadSaveToolButton->setDefaultAction(actionUseExistingPolyline);
334 assert(
nullptr != associatedMesh);
338 "mesh associated to cloud %1 is "
353 assert(
nullptr != associatedPolyline);
357 "polyline associated to cloud %1 is "
378 "[ccGraphicalSegmentationTool] Can't segment "
387 "[ccGraphicalSegmentationTool] Can't segment "
389 "Select the parent mesh...");
424 if (!verticesCloud) {
431 if (verticesCloud &&
m_toSegment.contains(verticesCloud)) {
460 Qt::MouseButtons buttons) {
491 if (vertCount != 4) {
501 if (vertCount < 2)
return;
531 ((QApplication::keyboardModifiers() &
532 Qt::ControlModifier) == Qt::ControlModifier);
535 if (((
m_state &
RUNNING) == 0) || vertCount == 0 || ctrlKeyPressed) {
632 loadSaveToolButton->setDefaultAction(actionExportSegmentationPolyline);
670 "Define and/or close the segmentation polygon first! (right "
680 for (QSet<ccHObject*>::const_iterator p =
m_toSegment.constBegin();
687 assert(!visibilityArray.empty());
689 unsigned cloudSize = cloud->
size();
694 #pragma omp parallel for
696 for (
int i = 0; i < static_cast<int>(cloudSize); ++i) {
717 validButton->setEnabled(
true);
718 validAndDeleteButton->setEnabled(
true);
719 razButton->setEnabled(
true);
727 bool state,
bool only2D ) {
746 "Unpause to segment again",
755 "Segmentation [ON] (rectangular selection)",
759 "Left click: set opposite corners",
764 "Segmentation [ON] (polygonal selection)",
768 "Left click: add contour points / Right click: close",
775 pauseButton->blockSignals(
true);
776 pauseButton->setChecked(state);
777 pauseButton->blockSignals(
false);
787 selectionModelButton->setDefaultAction(actionSetPolylineSelection);
799 "Segmentation [ON] (polygonal selection)",
803 "Left click: add contour points / Right click: close",
813 selectionModelButton->setDefaultAction(actionSetRectangularSelection);
825 "Segmentation [ON] (rectangular selection)",
829 "Right click: set opposite corners",
850 if (!polylines.empty()) {
852 if (index < 0)
return;
853 assert(index >= 0 && index <
static_cast<int>(polylines.size()));
862 if (QMessageBox::question(
864 "Associated viewport",
865 "The selected polyline has an associated viewport: "
866 "do you want to apply it?",
868 QMessageBox::No) == QMessageBox::Yes) {
900 for (
unsigned i = 0; i < vertices->
size(); ++i) {
912 for (
unsigned j = 0; j < poly->
size(); ++j) {
923 }
else if (vertices->
size()) {
926 unsigned lastIndex = vertices->
size() - 1;
951 QMessageBox messageBox(0);
952 messageBox.setWindowTitle(
"Choose export type");
954 "Export polyline in:\n - 2D (with coordinates relative to the "
955 "screen)\n - 3D (with coordinates relative to the segmented "
957 QPushButton* button2D =
new QPushButton(
"2D");
958 QPushButton* button3D =
new QPushButton(
"3D");
959 messageBox.addButton(button2D, QMessageBox::AcceptRole);
960 messageBox.addButton(button3D, QMessageBox::AcceptRole);
961 messageBox.addButton(QMessageBox::Cancel);
962 messageBox.setDefaultButton(button3D);
964 if (messageBox.clickedButton() ==
965 messageBox.button(QMessageBox::Cancel)) {
969 mode2D = (messageBox.clickedButton() == button2D);
987 for (
unsigned i = 0; i < vertices->
size(); ++i) {
992 (
int)Pscreen->
x,
height - (
int)Pscreen->
y, Q3D);
999 "[Segmentation] Failed to convert 2D polyline to 3D! "
1000 "(internal inconsistency)");
1005 bool hasGlobalShift =
false;
1007 double globalScale = 1.0;
1009 for (QSet<ccHObject*>::const_iterator it =
1013 bool isShifted = (shifted && shifted->
isShifted());
1017 hasGlobalShift =
true;
1024 hasGlobalShift = (QMessageBox::question(
1026 "Apply Global Shift",
1027 "At least one of the segmented "
1028 "entity has been shifted. Apply the "
1029 "same shift to the polyline?",
1031 QMessageBox::No) == QMessageBox::Yes);
1034 if (hasGlobalShift) {
1040 QString polyName = QString(
"Segmentation polyline #%1")
1059 mainWindow->
addToDB(poly,
false,
false,
false);
1060 CVLog::Print(QString(
"[Segmentation] Polyline exported (%1 vertices)")
1061 .arg(poly->
size()));
1082 std::set<cc2DLabel*>& watchedLabels,
1084 const std::vector<int>& newIndexesOfRemainingPointsOrTriangles,
1091 std::set<cc2DLabel*>::iterator it = watchedLabels.begin();
1092 while (it != watchedLabels.end()) {
1095 for (
unsigned i = 0; i < label->
size(); ++i) {
1097 if (pp.
entity() == entity) {
1098 if (pp.
index < newIndexesOfRemainingPointsOrTriangles.size() &&
1099 newIndexesOfRemainingPointsOrTriangles[pp.
index] >= 0) {
1101 pp.
index = newIndexesOfRemainingPointsOrTriangles[pp.
index];
1106 bool saveContext = (labelParent != entity &&
1117 it = watchedLabels.erase(it);
1137 bool cantModifyPolylinesWarningIssued =
false;
1140 std::set<cc2DLabel*> watchedLabels;
1147 for (
ccHObject* labelEntity : loadedLabels) {
1154 for (
unsigned i = 0; i < label->
size(); ++i) {
1159 watchedLabels.insert(label);
1165 }
catch (
const std::bad_alloc&) {
1171 for (QSet<ccHObject*>::iterator p =
m_toSegment.begin();
1177 bool canModify =
true;
1181 " is locked. We won't be able to modify it");
1188 if (cloud->
size() == 0) {
1191 " is empty. We will ignore it");
1200 " seems to be the vertices of a mesh. We "
1201 "won't be able to modify it");
1206 " seems to be the vertices of a polyine. We "
1207 "won't be able to modify it");
1211 }
else if (entity->
isA(
1219 " is empty. We will ignore it");
1227 " is empty. We will ignore it");
1232 if (!cantModifyPolylinesWarningIssued) {
1234 "Can't modify polylines. A new polyline will be "
1236 cantModifyPolylinesWarningIssued =
true;
1252 bool removeSelectedElementsFromEntity =
1256 ccHObject* segmentationResult =
nullptr;
1262 std::vector<int> newIndexesOfRemainingPoints;
1265 removeSelectedElementsFromEntity,
nullptr,
1266 deleteOriginalEntity
1268 : &newIndexesOfRemainingPoints);
1269 if (segmentedCloud) {
1270 if (segmentedCloud->
size() == 0) {
1272 delete segmentedCloud;
1273 segmentedCloud =
nullptr;
1274 }
else if (segmentedCloud == cloud) {
1282 segmentationResult = segmentedCloud;
1284 deleteOriginalEntity |= (cloud->
size() == 0);
1286 if (removeSelectedElementsFromEntity &&
1287 !deleteOriginalEntity)
1292 watchedLabels, cloud,
1293 newIndexesOfRemainingPoints, app);
1300 std::vector<int> newIndexesOfRemainingTriangles;
1302 removeSelectedElementsFromEntity,
1303 deleteOriginalEntity ?
nullptr
1304 : &newIndexesOfRemainingTriangles,
1307 if (segmentatedMesh) {
1308 if (segmentatedMesh->
size() == 0) {
1310 delete segmentatedMesh;
1311 segmentatedMesh =
nullptr;
1312 }
else if (segmentatedMesh == mesh) {
1320 segmentationResult = segmentatedMesh;
1322 deleteOriginalEntity |= (mesh->
size() == 0);
1324 if (removeSelectedElementsFromEntity &&
1325 !deleteOriginalEntity) {
1328 watchedLabels, mesh,
1329 newIndexesOfRemainingTriangles, app);
1338 if (segmentationResult)
1344 SegmentationToolOptionsKey());
1345 QString segmentedSuffix =
1347 SegmentedSuffixKey(),
1350 settings.endGroup();
1352 QString resultName = entity->
getName();
1353 if (!resultName.endsWith(segmentedSuffix)) {
1354 resultName += segmentedSuffix;
1356 segmentationResult->
setName(resultName);
1365 segmentationResult);
1366 QString verticesName =
1368 if (!verticesName.endsWith(segmentedSuffix)) {
1369 verticesName += segmentedSuffix;
1375 if (removeSelectedElementsFromEntity &&
1376 !deleteOriginalEntity)
1382 SegmentationToolOptionsKey());
1383 QString remainingSuffix =
1385 RemainingSuffixKey(),
1388 settings.endGroup();
1389 if (!entity->
getName().endsWith(remainingSuffix)) {
1396 QString verticesName =
1398 if (!verticesName.endsWith(remainingSuffix)) {
1400 verticesName + remainingSuffix);
1420 while (resultParent &&
1423 resultParent = resultParent->
getParent();
1426 resultParent->
addChild(segmentationResult);
1429 app->
addToDB(segmentationResult,
false,
true,
false,
true);
1431 newEntities.push_back(segmentationResult);
1434 if (!deleteOriginalEntity) {
1439 std::set<cc2DLabel*>::iterator it = watchedLabels.begin();
1440 while (it != watchedLabels.end()) {
1443 for (
unsigned i = 0; i < label->
size(); ++i) {
1445 if (pp.
entity() == entity) {
1450 (labelParent != entity &&
1462 it = watchedLabels.erase(it);
1489 std::vector<ccPolyline*> polylines;
1493 if (polyParent) polyParent->
addChild(p);
1494 app->
addToDB(p,
false,
true,
false,
true);
1495 newEntities.push_back(p);
constexpr unsigned char POINT_VISIBLE
constexpr unsigned char POINT_HIDDEN
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
float PointCoordinateType
Type of the coordinates of a (N-D) point.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
ccHObject * dbRootObject() override
Returns DB root (as a ccHObject)
static MainWindow * TheInstance()
Returns the unique instance of this object.
void addToDB(const QStringList &filenames, QString fileFilter=QString(), bool displayDialog=true)
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
2D label (typically attached to points)
const PickedPoint & getPickedPoint(unsigned index) const
Returns a given point.
unsigned size() const
Returns current size.
const ecvViewportParameters & getParameters() const
Gets parameters.
void setParameters(const ecvViewportParameters ¶ms)
Sets perspective view state.
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
Ground-based Laser sensor.
void clearDepthBuffer()
Removes the associated depth buffer.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
static bool IsCloudVerticesOfMesh(ccGenericPointCloud *cloud, ccGenericMesh **mesh=nullptr)
Helper to determine if the input cloud acts as vertices of a mesh.
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual ccGenericPointCloud * createNewCloudFromVisibilitySelection(bool removeSelectedPoints=false, VisibilityTableType *visTable=nullptr, std::vector< int > *newIndexesOfRemainingPoints=nullptr, bool silent=false, cloudViewer::ReferenceCloud *selection=nullptr)=0
virtual VisibilityTableType & getTheVisibilityArray()
Returns associated visibility array.
virtual bool resetVisibilityArray()
Resets the associated visibility array.
std::vector< unsigned char > VisibilityTableType
Array of "visibility" information for each point.
virtual void unallocateVisibilityArray()
Erases the points visibility information.
static ccMesh * ToMesh(ccHObject *obj)
Converts current object to ccMesh (if possible)
static ccShiftedObject * ToShifted(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccShiftedObject.
static ccPolyline * ToPolyline(ccHObject *obj)
Converts current object to ccPolyline (if possible)
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
static ccGBLSensor * ToGBLSensor(ccHObject *obj)
Hierarchical CLOUDVIEWER Object.
bool isAncestorOf(const ccHObject *anObject) const
Returns true if the current object is an ancestor of the specified one.
QString getViewId() const
unsigned getChildrenNumber() const
Returns the number of children.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
void removeChild(ccHObject *child)
unsigned filterChildren(Container &filteredChildren, bool recursive=false, CV_CLASS_ENUM filter=CV_TYPES::OBJECT, bool strict=false) const
Collects the children corresponding to a certain pattern.
bool pushDisplayState() override
Pushes the current display state (overridden)
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
void popDisplayState(bool apply=true) override
Pops the last pushed display state (overridden)
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
static int SelectEntity(const ccHObject::Container &entities, int defaultSelectedIndex=0, QWidget *parent=0, QString label=QString())
Static shortcut: unique selection mode.
ccMesh * createNewMeshFromSelection(bool removeSelectedTriangles, std::vector< int > *newIndexesOfRemainingTriangles=nullptr, bool withChildEntities=false)
Creates a new mesh with the selected vertices only.
virtual unsigned size() const override
Returns the number of triangles.
virtual bool isLocked() const
Returns whether the object is locked or not.
virtual QString getName() const
Returns object name.
bool isA(CV_CLASS_ENUM type) const
virtual void setName(const QString &name)
Sets object name.
virtual void setEnabled(bool state)
Sets the "enabled" property.
bool isKindOf(CV_CLASS_ENUM type) const
Generic overlay dialog interface.
void shortcutTriggered(int key)
Signal emitted when an overridden key shortcut is pressed.
virtual void stop(bool accepted)
Stops process/dialog.
virtual bool start()
Starts process.
virtual bool linkWith(QWidget *win)
Links the overlay dialog with a MDI window.
void addOverridenShortcut(Qt::Key key)
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void invalidateBoundingBox() override
Invalidates bounding box.
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
void clear() override
Clears the entity from all its points and features.
bool resize(unsigned numberOfPoints) override
Resizes all the active features arrays.
void setForeground(bool state)
Defines if the polyline is drawn in background or foreground.
virtual void setGlobalShift(const CCVector3d &shift) override
Sets shift applied to original coordinates (information storage only)
bool createNewPolylinesFromSelection(std::vector< ccPolyline * > &output)
Creates a polyline mesh with the selected vertices only.
void set2DMode(bool state)
Defines if the polyline is considered as 2D or 3D.
bool is2DMode() const
Returns whether the polyline is considered as 2D or 3D.
static bool IsCloudVerticesOfPolyline(ccGenericPointCloud *cloud, ccPolyline **polyline=nullptr)
Helper to determine if the input cloud acts as vertices of a polyline.
virtual void setGlobalScale(double scale) override
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
Shifted entity interface.
bool isShifted() const
Returns whether the cloud is shifted or not.
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
virtual unsigned size() const =0
Returns the number of points.
A generic 3D point cloud with index-based and presistent access to points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
virtual unsigned size() const =0
Returns the number of triangles.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
const CCVector3 * getPointPersistentPtr(unsigned index) override
unsigned size() const override
const CCVector3 * getPoint(unsigned index) const override
void setClosed(bool state)
Sets whether the polyline is closed or not.
void clear(bool unusedParam=true) override
Clears the cloud.
bool isClosed() const
Returns whether the polyline is closed or not.
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
unsigned size() const override
Returns the number of points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
virtual bool resize(unsigned n)
Presets the size of the vector used to store point references.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
Main application interface (for plugins)
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual void putObjectBackIntoDBTree(ccHObject *obj, const ccHObjectContext &context)=0
Adds back object to DB tree.
virtual void addToDB(ccHObject *obj, bool updateZoom=false, bool autoExpandDBTree=true, bool checkDimensions=false, bool autoRedraw=true)=0
virtual ccHObjectContext removeObjectTemporarilyFromDBTree(ccHObject *obj)=0
Removes object temporarily from DB tree.
constexpr Rgb green(0, MAX, 0)
constexpr Rgb yellow(MAX, MAX, 0)
unsigned index
Point/triangle index.
ccHObject * entity() const
Returns the associated entity (cloud or mesh)
OpenGL camera parameters.
bool project(const CCVector3d &input3D, CCVector3d &output2D, bool *inFrustum=nullptr) const
Projects a 3D point in 2D (+ normalized 'z' coordinate)
int viewport[4]
Viewport (GL_VIEWPORT)
Backup "context" for an object.