Skip to content

Commit cec362d

Browse files
committed
Add feature to export clipped meshes (constraints clipped) for #2436
1 parent 012940e commit cec362d

File tree

10 files changed

+84
-37
lines changed

10 files changed

+84
-37
lines changed

Libs/Analyze/Shape.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,16 @@ Constraints& Shape::get_constraints(int domain_id) {
915915
return constraints_[domain_id];
916916
}
917917

918+
//---------------------------------------------------------------------------
919+
bool Shape::has_constraints() {
920+
for (int i = 0; i < constraints_.size(); i++) {
921+
if (constraints_[i].hasConstraints()) {
922+
return true;
923+
}
924+
}
925+
return false;
926+
}
927+
918928
//---------------------------------------------------------------------------
919929
bool Shape::has_planes() {
920930
for (int i = 0; i < constraints_.size(); i++) {

Libs/Analyze/Shape.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ class Shape {
185185

186186
Constraints& get_constraints(int domain_id);
187187

188+
bool has_constraints();
189+
188190
bool has_planes();
189191

190192
std::vector<std::shared_ptr<Surface>> get_groomed_mesh_wrappers();

Studio/Data/ExportUtils.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
#include <Shape.h>
88
#include <StringUtils.h>
99
#include <Utils/StudioUtils.h>
10+
#include <Visualization/Visualizer.h>
1011
#include <vtkPointData.h>
1112
#include <vtkPolyData.h>
1213

1314
#include <QDir>
1415
#include <QFileDialog>
1516
#include <QFileInfo>
17+
#include <QObject>
1618
#include <QProgressDialog>
1719

1820
namespace shapeworks {
@@ -225,4 +227,9 @@ bool ExportUtils::write_pca_scores(ShapeWorksStudioApp* app, ParticleShapeStatis
225227
return true;
226228
}
227229

230+
//----------------------------------------------------------------------------
231+
QString ExportUtils::get_mesh_file_filter() {
232+
return QObject::tr("VTK files (*.vtk);;PLY files (*.ply);;VTP files (*.vtp);;OBJ files (*.obj);;STL files (*.stl)");
233+
}
234+
228235
} // namespace shapeworks

Studio/Data/ExportUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ class ExportUtils {
2323
static bool write_particle_scalars(ShapeWorksStudioApp* app, std::shared_ptr<Shape> shape, QString filename);
2424

2525
static bool write_pca_scores(ShapeWorksStudioApp* app, ParticleShapeStatistics* stats, QString filename);
26+
27+
static QString get_mesh_file_filter();
28+
2629
};
2730

2831
} // namespace shapeworks

Studio/Interface/ShapeWorksStudioApp.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,17 @@ ShapeWorksStudioApp::ShapeWorksStudioApp() {
241241
connect(ui_->action_export_all_subjects_particle_scalars, &QAction::triggered, this,
242242
&ShapeWorksStudioApp::action_export_all_subjects_particle_scalars_triggered);
243243

244-
connect(ui_->action_export_current_mesh, &QAction::triggered, this,
245-
&ShapeWorksStudioApp::action_export_current_mesh_triggered);
244+
connect(ui_->action_export_current_mesh, &QAction::triggered, this, [&]() {
245+
// get the first index of the visualizer (top left lightbox item)
246+
int index = visualizer_->get_lightbox()->get_start_shape();
247+
ShapeWorksStudioApp::action_export_current_mesh_triggered(index);
248+
});
249+
250+
connect(ui_->action_export_current_mesh_clipped, &QAction::triggered, this, [&]() {
251+
// get the first index of the visualizer (top left lightbox item)
252+
int index = visualizer_->get_lightbox()->get_start_shape();
253+
ShapeWorksStudioApp::action_export_current_mesh_triggered(index, true);
254+
});
246255

247256
connect(ui_->save_as_swproj, &QAction::triggered, this, &ShapeWorksStudioApp::save_as_swproj_clicked);
248257
connect(ui_->save_as_xlsx, &QAction::triggered, this, &ShapeWorksStudioApp::save_as_xlsx_clicked);
@@ -951,10 +960,15 @@ void ShapeWorksStudioApp::handle_lightbox_right_click(int index) {
951960
QMenu* menu = new QMenu(nullptr);
952961
menu->setAttribute(Qt::WA_DeleteOnClose);
953962
QAction* export_mesh_action = menu->addAction("Export Mesh");
963+
QAction* export_clipped_mesh_action = nullptr;
954964
QAction* mark_excluded_action = nullptr;
955965
QAction* unmark_excluded_action = nullptr;
956966
QAction* mark_fixed_action = nullptr;
957967
QAction* unmark_fixed_action = nullptr;
968+
969+
if (shape->has_constraints()) {
970+
export_clipped_mesh_action = menu->addAction("Export Clipped Mesh");
971+
}
958972
if (shape->is_subject() && !shape->is_excluded()) {
959973
mark_excluded_action = menu->addAction("Mark as excluded");
960974
}
@@ -971,7 +985,9 @@ void ShapeWorksStudioApp::handle_lightbox_right_click(int index) {
971985
menu->popup(QCursor::pos());
972986
connect(menu, &QMenu::triggered, menu, [=](QAction* action) {
973987
if (action == export_mesh_action) {
974-
action_export_current_mesh_triggered(index);
988+
action_export_current_mesh_triggered(index, false);
989+
} else if (action == export_clipped_mesh_action) {
990+
action_export_current_mesh_triggered(index, true);
975991
} else if (action == mark_excluded_action) {
976992
shape->get_subject()->set_excluded(true);
977993
} else if (action == unmark_excluded_action) {
@@ -1617,19 +1633,20 @@ void ShapeWorksStudioApp::on_action_preferences_triggered() {
16171633
}
16181634

16191635
//---------------------------------------------------------------------------
1620-
void ShapeWorksStudioApp::action_export_current_mesh_triggered(int index) {
1636+
void ShapeWorksStudioApp::action_export_current_mesh_triggered(int index, bool clip_constraints) {
16211637
bool single = StudioUtils::ask_multiple_domains_as_single(this, session_->get_project());
16221638

1623-
QString filename = ExportUtils::get_save_filename(this, tr("Export Mesh"), get_mesh_file_filter(), ".vtk");
1639+
QString filename =
1640+
ExportUtils::get_save_filename(this, tr("Export Mesh"), ExportUtils::get_mesh_file_filter(), ".vtk");
16241641
if (filename.isEmpty()) {
16251642
return;
16261643
}
16271644

16281645
if (single) {
1629-
StudioUtils::write_mesh(visualizer_->get_current_mesh(index), filename);
1646+
StudioUtils::write_mesh(visualizer_->get_current_mesh(index, clip_constraints), filename);
16301647
SW_MESSAGE("Wrote: " + filename.toStdString());
16311648
} else {
1632-
auto meshes = visualizer_->get_current_meshes_transformed(index);
1649+
auto meshes = visualizer_->get_current_meshes_transformed(index, clip_constraints);
16331650
auto domain_names = session_->get_project()->get_domain_names();
16341651

16351652
if (meshes.empty()) {
@@ -1756,7 +1773,7 @@ void ShapeWorksStudioApp::on_action_export_mesh_scalars_triggered() {
17561773
}
17571774

17581775
if (single) {
1759-
auto poly_data = visualizer_->get_current_mesh(0);
1776+
auto poly_data = visualizer_->get_current_mesh(0, false);
17601777
write_scalars(poly_data, filename);
17611778
} else {
17621779
auto meshes = visualizer_->get_current_meshes_transformed(0);
@@ -2092,11 +2109,6 @@ bool ShapeWorksStudioApp::write_particle_file(std::string filename, Eigen::Vecto
20922109
return true;
20932110
}
20942111

2095-
//---------------------------------------------------------------------------
2096-
QString ShapeWorksStudioApp::get_mesh_file_filter() {
2097-
return tr("VTK files (*.vtk);;PLY files (*.ply);;VTP files (*.vtp);;OBJ files (*.obj);;STL files (*.stl)");
2098-
}
2099-
21002112
//---------------------------------------------------------------------------
21012113
void ShapeWorksStudioApp::update_feature_map_selection(int index) {
21022114
QString feature_map = ui_->features->itemText(index);

Studio/Interface/ShapeWorksStudioApp.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
class Ui_ShapeWorksStudioApp;
2828

2929
namespace monailabel {
30-
class MonaiLabelTool;
30+
class MonaiLabelTool;
3131
}
3232

3333
namespace shapeworks {
@@ -89,7 +89,7 @@ class ShapeWorksStudioApp : public QMainWindow {
8989
void on_actionExport_Eigenvectors_triggered();
9090
void on_actionExport_PCA_Mode_Points_triggered();
9191
void on_action_preferences_triggered();
92-
void action_export_current_mesh_triggered(int index = 0);
92+
void action_export_current_mesh_triggered(int index = 0, bool clip_constraints = false);
9393
void on_action_export_current_particles_triggered();
9494
void on_action_export_mesh_scalars_triggered();
9595
void on_action_export_pca_scores_triggered();
@@ -162,6 +162,8 @@ class ShapeWorksStudioApp : public QMainWindow {
162162
Preferences& prefs() { return preferences_; }
163163
QSharedPointer<Session> session() { return session_; }
164164

165+
QSharedPointer<Visualizer> get_visualizer() { return visualizer_; }
166+
165167
protected:
166168
void dragEnterEvent(QDragEnterEvent* event) override;
167169
void dragLeaveEvent(QDragLeaveEvent* event) override;
@@ -180,8 +182,6 @@ class ShapeWorksStudioApp : public QMainWindow {
180182

181183
static bool write_particle_file(std::string filename, Eigen::VectorXd particles);
182184

183-
static QString get_mesh_file_filter();
184-
185185
static const std::string SETTING_ZOOM_C;
186186

187187
void set_view_combo_item_enabled(int item, bool value);

Studio/Interface/ShapeWorksStudioApp.ui

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>1243</width>
9+
<width>1310</width>
1010
<height>705</height>
1111
</rect>
1212
</property>
@@ -714,7 +714,7 @@ QToolBar QToolButton::checked {
714714
<rect>
715715
<x>0</x>
716716
<y>0</y>
717-
<width>1243</width>
717+
<width>1310</width>
718718
<height>33</height>
719719
</rect>
720720
</property>
@@ -727,6 +727,7 @@ QToolBar QToolButton::checked {
727727
<string>Export...</string>
728728
</property>
729729
<addaction name="action_export_current_mesh"/>
730+
<addaction name="action_export_current_mesh_clipped"/>
730731
<addaction name="action_export_current_particles"/>
731732
<addaction name="action_export_particle_scalars"/>
732733
<addaction name="action_export_mesh_scalars"/>
@@ -1171,16 +1172,16 @@ QToolBar QToolButton::checked {
11711172
</property>
11721173
</action>
11731174
<action name="action_monai_mode">
1174-
<property name="checkable">
1175-
<bool>true</bool>
1176-
</property>
1177-
<property name="icon">
1178-
<iconset resource="../Resources/ShapeWorksStudio.qrc">
1179-
<normaloff>:/Studio/Images/MONAI-Label.png</normaloff>:/Studio/Images/MONAI-Label.png</iconset>
1180-
</property>
1181-
<property name="text">
1182-
<string>MONAI</string>
1183-
</property>
1175+
<property name="checkable">
1176+
<bool>true</bool>
1177+
</property>
1178+
<property name="icon">
1179+
<iconset resource="../Resources/ShapeWorksStudio.qrc">
1180+
<normaloff>:/Studio/Images/MONAI-Label.png</normaloff>:/Studio/Images/MONAI-Label.png</iconset>
1181+
</property>
1182+
<property name="text">
1183+
<string>MONAI</string>
1184+
</property>
11841185
</action>
11851186
<action name="action_export_pca_montage">
11861187
<property name="text">
@@ -1220,6 +1221,11 @@ QToolBar QToolButton::checked {
12201221
<enum>QAction::ApplicationSpecificRole</enum>
12211222
</property>
12221223
</action>
1224+
<action name="action_export_current_mesh_clipped">
1225+
<property name="text">
1226+
<string>Export Current Mesh Clipped...</string>
1227+
</property>
1228+
</action>
12231229
</widget>
12241230
<customwidgets>
12251231
<customwidget>

Studio/Visualization/Lightbox.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class Lightbox : public QObject {
9494

9595
vtkRenderWindow* get_render_window();
9696

97+
int get_start_shape();
98+
9799
public Q_SLOTS:
98100
void handle_timer_callback();
99101

@@ -109,8 +111,6 @@ class Lightbox : public QObject {
109111

110112
void insert_shape_into_viewer(std::shared_ptr<Shape> shape, int position);
111113

112-
int get_start_shape();
113-
114114
vtkSmartPointer<vtkRenderer> renderer_;
115115

116116
ShapeList shapes_;

Studio/Visualization/Visualizer.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ void Visualizer::handle_new_mesh() {
152152
}
153153

154154
//-----------------------------------------------------------------------------
155-
vtkSmartPointer<vtkPolyData> Visualizer::get_current_mesh(int index) {
156-
auto meshes = get_current_meshes_transformed(index);
155+
vtkSmartPointer<vtkPolyData> Visualizer::get_current_mesh(int index, bool clip_constraints) {
156+
auto meshes = get_current_meshes_transformed(index, clip_constraints);
157157
if (meshes.empty()) {
158158
return nullptr;
159159
}
@@ -167,7 +167,7 @@ vtkSmartPointer<vtkPolyData> Visualizer::get_current_mesh(int index) {
167167
}
168168

169169
//-----------------------------------------------------------------------------
170-
std::vector<vtkSmartPointer<vtkPolyData>> Visualizer::get_current_meshes_transformed(int index) {
170+
std::vector<vtkSmartPointer<vtkPolyData>> Visualizer::get_current_meshes_transformed(int index, bool clip_constraints) {
171171
std::vector<vtkSmartPointer<vtkPolyData>> list;
172172
auto shapes = lightbox_->get_shapes();
173173
if (shapes.size() > index) {
@@ -178,10 +178,17 @@ std::vector<vtkSmartPointer<vtkPolyData>> Visualizer::get_current_meshes_transfo
178178
if (!meshes[domain]->get_poly_data()) {
179179
return list;
180180
}
181+
182+
Mesh mesh(meshes[domain]->get_poly_data());
183+
if (clip_constraints) {
184+
auto constraint = shapes[index]->get_constraints(domain);
185+
constraint.clipMesh(mesh);
186+
}
187+
181188
// we have to transform each domain to its location in order to export an appended mesh
182189
auto filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
183190
filter->SetTransform(get_transform(shapes[index], get_alignment_domain(), domain));
184-
filter->SetInputData(meshes[domain]->get_poly_data());
191+
filter->SetInputData(mesh.getVTKMesh());
185192
filter->Update();
186193
list.push_back(filter->GetOutput());
187194
}

Studio/Visualization/Visualizer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ class Visualizer : public QObject {
8080
vtkSmartPointer<vtkPolyData> get_current_particle_poly_data();
8181

8282
void handle_new_mesh();
83-
vtkSmartPointer<vtkPolyData> get_current_mesh(int index);
84-
std::vector<vtkSmartPointer<vtkPolyData>> get_current_meshes_transformed(int index);
83+
vtkSmartPointer<vtkPolyData> get_current_mesh(int index, bool clip_constraints);
84+
std::vector<vtkSmartPointer<vtkPolyData>> get_current_meshes_transformed(int index, bool clip_constraints = false);
8585

8686
//! Get the currently selected feature map
8787
const std::string& get_feature_map() const;

0 commit comments

Comments
 (0)