Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Libs/Analyze/Shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,16 @@ Constraints& Shape::get_constraints(int domain_id) {
return constraints_[domain_id];
}

//---------------------------------------------------------------------------
bool Shape::has_constraints() {
for (int i = 0; i < constraints_.size(); i++) {
if (constraints_[i].hasConstraints()) {
return true;
}
}
return false;
}

//---------------------------------------------------------------------------
bool Shape::has_planes() {
for (int i = 0; i < constraints_.size(); i++) {
Expand Down
2 changes: 2 additions & 0 deletions Libs/Analyze/Shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ class Shape {

Constraints& get_constraints(int domain_id);

bool has_constraints();

bool has_planes();

std::vector<std::shared_ptr<Surface>> get_groomed_mesh_wrappers();
Expand Down
7 changes: 7 additions & 0 deletions Studio/Data/ExportUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
#include <Shape.h>
#include <StringUtils.h>
#include <Utils/StudioUtils.h>
#include <Visualization/Visualizer.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>

#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QObject>
#include <QProgressDialog>

namespace shapeworks {
Expand Down Expand Up @@ -225,4 +227,9 @@ bool ExportUtils::write_pca_scores(ShapeWorksStudioApp* app, ParticleShapeStatis
return true;
}

//----------------------------------------------------------------------------
QString ExportUtils::get_mesh_file_filter() {
return QObject::tr("VTK files (*.vtk);;PLY files (*.ply);;VTP files (*.vtp);;OBJ files (*.obj);;STL files (*.stl)");
}

} // namespace shapeworks
3 changes: 3 additions & 0 deletions Studio/Data/ExportUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ExportUtils {
static bool write_particle_scalars(ShapeWorksStudioApp* app, std::shared_ptr<Shape> shape, QString filename);

static bool write_pca_scores(ShapeWorksStudioApp* app, ParticleShapeStatistics* stats, QString filename);

static QString get_mesh_file_filter();

};

} // namespace shapeworks
38 changes: 25 additions & 13 deletions Studio/Interface/ShapeWorksStudioApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,17 @@ ShapeWorksStudioApp::ShapeWorksStudioApp() {
connect(ui_->action_export_all_subjects_particle_scalars, &QAction::triggered, this,
&ShapeWorksStudioApp::action_export_all_subjects_particle_scalars_triggered);

connect(ui_->action_export_current_mesh, &QAction::triggered, this,
&ShapeWorksStudioApp::action_export_current_mesh_triggered);
connect(ui_->action_export_current_mesh, &QAction::triggered, this, [&]() {
// get the first index of the visualizer (top left lightbox item)
int index = visualizer_->get_lightbox()->get_start_shape();
ShapeWorksStudioApp::action_export_current_mesh_triggered(index);
});

connect(ui_->action_export_current_mesh_clipped, &QAction::triggered, this, [&]() {
// get the first index of the visualizer (top left lightbox item)
int index = visualizer_->get_lightbox()->get_start_shape();
ShapeWorksStudioApp::action_export_current_mesh_triggered(index, true);
});

connect(ui_->save_as_swproj, &QAction::triggered, this, &ShapeWorksStudioApp::save_as_swproj_clicked);
connect(ui_->save_as_xlsx, &QAction::triggered, this, &ShapeWorksStudioApp::save_as_xlsx_clicked);
Expand Down Expand Up @@ -951,10 +960,15 @@ void ShapeWorksStudioApp::handle_lightbox_right_click(int index) {
QMenu* menu = new QMenu(nullptr);
menu->setAttribute(Qt::WA_DeleteOnClose);
QAction* export_mesh_action = menu->addAction("Export Mesh");
QAction* export_clipped_mesh_action = nullptr;
QAction* mark_excluded_action = nullptr;
QAction* unmark_excluded_action = nullptr;
QAction* mark_fixed_action = nullptr;
QAction* unmark_fixed_action = nullptr;

if (shape->has_constraints()) {
export_clipped_mesh_action = menu->addAction("Export Clipped Mesh");
}
if (shape->is_subject() && !shape->is_excluded()) {
mark_excluded_action = menu->addAction("Mark as excluded");
}
Expand All @@ -971,7 +985,9 @@ void ShapeWorksStudioApp::handle_lightbox_right_click(int index) {
menu->popup(QCursor::pos());
connect(menu, &QMenu::triggered, menu, [=](QAction* action) {
if (action == export_mesh_action) {
action_export_current_mesh_triggered(index);
action_export_current_mesh_triggered(index, false);
} else if (action == export_clipped_mesh_action) {
action_export_current_mesh_triggered(index, true);
} else if (action == mark_excluded_action) {
shape->get_subject()->set_excluded(true);
} else if (action == unmark_excluded_action) {
Expand Down Expand Up @@ -1617,19 +1633,20 @@ void ShapeWorksStudioApp::on_action_preferences_triggered() {
}

//---------------------------------------------------------------------------
void ShapeWorksStudioApp::action_export_current_mesh_triggered(int index) {
void ShapeWorksStudioApp::action_export_current_mesh_triggered(int index, bool clip_constraints) {
bool single = StudioUtils::ask_multiple_domains_as_single(this, session_->get_project());

QString filename = ExportUtils::get_save_filename(this, tr("Export Mesh"), get_mesh_file_filter(), ".vtk");
QString filename =
ExportUtils::get_save_filename(this, tr("Export Mesh"), ExportUtils::get_mesh_file_filter(), ".vtk");
if (filename.isEmpty()) {
return;
}

if (single) {
StudioUtils::write_mesh(visualizer_->get_current_mesh(index), filename);
StudioUtils::write_mesh(visualizer_->get_current_mesh(index, clip_constraints), filename);
SW_MESSAGE("Wrote: " + filename.toStdString());
} else {
auto meshes = visualizer_->get_current_meshes_transformed(index);
auto meshes = visualizer_->get_current_meshes_transformed(index, clip_constraints);
auto domain_names = session_->get_project()->get_domain_names();

if (meshes.empty()) {
Expand Down Expand Up @@ -1756,7 +1773,7 @@ void ShapeWorksStudioApp::on_action_export_mesh_scalars_triggered() {
}

if (single) {
auto poly_data = visualizer_->get_current_mesh(0);
auto poly_data = visualizer_->get_current_mesh(0, false);
write_scalars(poly_data, filename);
} else {
auto meshes = visualizer_->get_current_meshes_transformed(0);
Expand Down Expand Up @@ -2092,11 +2109,6 @@ bool ShapeWorksStudioApp::write_particle_file(std::string filename, Eigen::Vecto
return true;
}

//---------------------------------------------------------------------------
QString ShapeWorksStudioApp::get_mesh_file_filter() {
return tr("VTK files (*.vtk);;PLY files (*.ply);;VTP files (*.vtp);;OBJ files (*.obj);;STL files (*.stl)");
}

//---------------------------------------------------------------------------
void ShapeWorksStudioApp::update_feature_map_selection(int index) {
QString feature_map = ui_->features->itemText(index);
Expand Down
8 changes: 4 additions & 4 deletions Studio/Interface/ShapeWorksStudioApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
class Ui_ShapeWorksStudioApp;

namespace monailabel {
class MonaiLabelTool;
class MonaiLabelTool;
}

namespace shapeworks {
Expand Down Expand Up @@ -89,7 +89,7 @@ class ShapeWorksStudioApp : public QMainWindow {
void on_actionExport_Eigenvectors_triggered();
void on_actionExport_PCA_Mode_Points_triggered();
void on_action_preferences_triggered();
void action_export_current_mesh_triggered(int index = 0);
void action_export_current_mesh_triggered(int index = 0, bool clip_constraints = false);
void on_action_export_current_particles_triggered();
void on_action_export_mesh_scalars_triggered();
void on_action_export_pca_scores_triggered();
Expand Down Expand Up @@ -162,6 +162,8 @@ class ShapeWorksStudioApp : public QMainWindow {
Preferences& prefs() { return preferences_; }
QSharedPointer<Session> session() { return session_; }

QSharedPointer<Visualizer> get_visualizer() { return visualizer_; }

protected:
void dragEnterEvent(QDragEnterEvent* event) override;
void dragLeaveEvent(QDragLeaveEvent* event) override;
Expand All @@ -180,8 +182,6 @@ class ShapeWorksStudioApp : public QMainWindow {

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

static QString get_mesh_file_filter();

static const std::string SETTING_ZOOM_C;

void set_view_combo_item_enabled(int item, bool value);
Expand Down
30 changes: 18 additions & 12 deletions Studio/Interface/ShapeWorksStudioApp.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1243</width>
<width>1310</width>
<height>705</height>
</rect>
</property>
Expand Down Expand Up @@ -714,7 +714,7 @@ QToolBar QToolButton::checked {
<rect>
<x>0</x>
<y>0</y>
<width>1243</width>
<width>1310</width>
<height>33</height>
</rect>
</property>
Expand All @@ -727,6 +727,7 @@ QToolBar QToolButton::checked {
<string>Export...</string>
</property>
<addaction name="action_export_current_mesh"/>
<addaction name="action_export_current_mesh_clipped"/>
<addaction name="action_export_current_particles"/>
<addaction name="action_export_particle_scalars"/>
<addaction name="action_export_mesh_scalars"/>
Expand Down Expand Up @@ -1171,16 +1172,16 @@ QToolBar QToolButton::checked {
</property>
</action>
<action name="action_monai_mode">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../Resources/ShapeWorksStudio.qrc">
<normaloff>:/Studio/Images/MONAI-Label.png</normaloff>:/Studio/Images/MONAI-Label.png</iconset>
</property>
<property name="text">
<string>MONAI</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../Resources/ShapeWorksStudio.qrc">
<normaloff>:/Studio/Images/MONAI-Label.png</normaloff>:/Studio/Images/MONAI-Label.png</iconset>
</property>
<property name="text">
<string>MONAI</string>
</property>
</action>
<action name="action_export_pca_montage">
<property name="text">
Expand Down Expand Up @@ -1220,6 +1221,11 @@ QToolBar QToolButton::checked {
<enum>QAction::ApplicationSpecificRole</enum>
</property>
</action>
<action name="action_export_current_mesh_clipped">
<property name="text">
<string>Export Current Mesh Clipped...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
Expand Down
4 changes: 2 additions & 2 deletions Studio/Visualization/Lightbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ class Lightbox : public QObject {

vtkRenderWindow* get_render_window();

int get_start_shape();

public Q_SLOTS:
void handle_timer_callback();

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

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

int get_start_shape();

vtkSmartPointer<vtkRenderer> renderer_;

ShapeList shapes_;
Expand Down
15 changes: 11 additions & 4 deletions Studio/Visualization/Visualizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ void Visualizer::handle_new_mesh() {
}

//-----------------------------------------------------------------------------
vtkSmartPointer<vtkPolyData> Visualizer::get_current_mesh(int index) {
auto meshes = get_current_meshes_transformed(index);
vtkSmartPointer<vtkPolyData> Visualizer::get_current_mesh(int index, bool clip_constraints) {
auto meshes = get_current_meshes_transformed(index, clip_constraints);
if (meshes.empty()) {
return nullptr;
}
Expand All @@ -167,7 +167,7 @@ vtkSmartPointer<vtkPolyData> Visualizer::get_current_mesh(int index) {
}

//-----------------------------------------------------------------------------
std::vector<vtkSmartPointer<vtkPolyData>> Visualizer::get_current_meshes_transformed(int index) {
std::vector<vtkSmartPointer<vtkPolyData>> Visualizer::get_current_meshes_transformed(int index, bool clip_constraints) {
std::vector<vtkSmartPointer<vtkPolyData>> list;
auto shapes = lightbox_->get_shapes();
if (shapes.size() > index) {
Expand All @@ -178,10 +178,17 @@ std::vector<vtkSmartPointer<vtkPolyData>> Visualizer::get_current_meshes_transfo
if (!meshes[domain]->get_poly_data()) {
return list;
}

Mesh mesh(meshes[domain]->get_poly_data());
if (clip_constraints) {
auto constraint = shapes[index]->get_constraints(domain);
constraint.clipMesh(mesh);
}

// we have to transform each domain to its location in order to export an appended mesh
auto filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
filter->SetTransform(get_transform(shapes[index], get_alignment_domain(), domain));
filter->SetInputData(meshes[domain]->get_poly_data());
filter->SetInputData(mesh.getVTKMesh());
filter->Update();
list.push_back(filter->GetOutput());
}
Expand Down
4 changes: 2 additions & 2 deletions Studio/Visualization/Visualizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ class Visualizer : public QObject {
vtkSmartPointer<vtkPolyData> get_current_particle_poly_data();

void handle_new_mesh();
vtkSmartPointer<vtkPolyData> get_current_mesh(int index);
std::vector<vtkSmartPointer<vtkPolyData>> get_current_meshes_transformed(int index);
vtkSmartPointer<vtkPolyData> get_current_mesh(int index, bool clip_constraints);
std::vector<vtkSmartPointer<vtkPolyData>> get_current_meshes_transformed(int index, bool clip_constraints = false);

//! Get the currently selected feature map
const std::string& get_feature_map() const;
Expand Down
Loading