diff --git a/Applications/shapeworks/Commands.cpp b/Applications/shapeworks/Commands.cpp
index 0dd129f7e6..90a8e320cd 100644
--- a/Applications/shapeworks/Commands.cpp
+++ b/Applications/shapeworks/Commands.cpp
@@ -41,6 +41,32 @@ bool Example::execute(const optparse::Values &options, SharedCommandData &shared
}
#endif
+static void setup_callbacks(bool show_progress, bool xml_status) {
+ if (show_progress) {
+ auto progress_callback = [](double progress, std::string message) {
+ // show status message and percentage complete
+ std::cout << fmt::format("{} ({:.1f}%) \r", message, progress);
+ std::cout.flush();
+ };
+ Logging::Instance().set_progress_callback(progress_callback);
+ }
+
+ if (xml_status) {
+ auto progress_callback = [](double progress, std::string message) {
+ // print status message and percentage complete
+ std::cout << fmt::format("{}\n", message, progress);
+ std::cout.flush();
+ };
+ Logging::Instance().set_progress_callback(progress_callback);
+
+ auto error_callback = [](std::string message) {
+ std::cout << fmt::format("{}\n", message);
+ std::cout.flush();
+ };
+ Logging::Instance().set_error_callback(error_callback);
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// Seed
///////////////////////////////////////////////////////////////////////////////
@@ -75,12 +101,16 @@ void OptimizeCommand::buildParser() {
parser.prog(prog).description(desc);
parser.add_option("--name").action("store").type("string").set_default("").help("Path to project file.");
+ parser.add_option("--progress").action("store_true").set_default(false).help("Show progress [default: false].");
+ parser.add_option("--xmlconsole").action("store_true").set_default(false).help("XML console output [default: false].");
Command::buildParser();
}
bool OptimizeCommand::execute(const optparse::Values& options, SharedCommandData& sharedData) {
const std::string& projectFile(static_cast(options.get("name")));
+ bool show_progress = static_cast(options.get("progress"));
+ bool xml_status = static_cast(options.get("xmlconsole"));
if (projectFile.length() == 0) {
std::cerr << "Must specify project name with --name \n";
@@ -90,6 +120,8 @@ bool OptimizeCommand::execute(const optparse::Values& options, SharedCommandData
bool isProject = StringUtils::hasSuffix(projectFile, "xlsx") || StringUtils::hasSuffix(projectFile, "swproj");
Optimize app;
+ setup_callbacks(show_progress, xml_status);
+
if (isProject) {
try {
// load spreadsheet project
@@ -117,7 +149,7 @@ bool OptimizeCommand::execute(const optparse::Values& options, SharedCommandData
return success;
} catch (std::exception& e) {
- std::cerr << "Error: " << e.what() << "\n";
+ SW_ERROR(e.what());
return false;
}
} else {
@@ -136,18 +168,24 @@ void GroomCommand::buildParser() {
parser.prog(prog).description(desc);
parser.add_option("--name").action("store").type("string").set_default("").help("Path to project file.");
+ parser.add_option("--progress").action("store_true").set_default(false).help("Show progress [default: false].");
+ parser.add_option("--xmlconsole").action("store_true").set_default(false).help("XML console output [default: false].");
Command::buildParser();
}
bool GroomCommand::execute(const optparse::Values& options, SharedCommandData& sharedData) {
const std::string& projectFile(static_cast(options.get("name")));
+ bool show_progress = static_cast(options.get("progress"));
+ bool xml_status = static_cast(options.get("xmlconsole"));
if (projectFile.length() == 0) {
std::cerr << "Must specify project name with --name \n";
return false;
}
+ setup_callbacks(show_progress, xml_status);
+
try {
ProjectHandle project = std::make_shared();
project->load(projectFile);
@@ -168,7 +206,7 @@ bool GroomCommand::execute(const optparse::Values& options, SharedCommandData& s
}
return success;
} catch (std::exception& e) {
- std::cerr << "Error: " << e.what() << "\n";
+ SW_ERROR(e.what());
return false;
}
}
diff --git a/Libs/Analyze/MeshGenerator.cpp b/Libs/Analyze/MeshGenerator.cpp
index 1c78007b79..fcc2cd5fd8 100644
--- a/Libs/Analyze/MeshGenerator.cpp
+++ b/Libs/Analyze/MeshGenerator.cpp
@@ -84,6 +84,8 @@ MeshHandle MeshGenerator::build_mesh_from_points(const Eigen::VectorXd& shape, i
if (!poly_data) {
std::string message = "Unable to warp mesh";
SW_ERROR(message);
+ poly_data = vtkSmartPointer::New();
+ mesh->set_poly_data(poly_data);
mesh->set_error_message(message);
return mesh;
}
@@ -122,9 +124,9 @@ MeshHandle MeshGenerator::build_mesh_from_image(ImageType::Pointer image, float
mesh->set_poly_data(Mesh(marching->GetOutput()).clean().computeNormals().getVTKMesh());
} catch (itk::ExceptionObject& excep) {
- std::cerr << "Exception caught!" << std::endl;
- std::cerr << excep << std::endl;
- mesh->set_error_message(std::string("Exception: ") + excep.what());
+ auto message = std::string("Exception: ") + excep.what();
+ SW_ERROR(message);
+ mesh->set_error_message(message);
}
return mesh;
}
diff --git a/Libs/Analyze/MeshManager.h b/Libs/Analyze/MeshManager.h
index 6353deac08..12345bcc6a 100644
--- a/Libs/Analyze/MeshManager.h
+++ b/Libs/Analyze/MeshManager.h
@@ -76,7 +76,7 @@ class MeshManager : public QObject {
void error_encountered(QString message);
void progress(int);
- void status(QString);
+ void status(std::string);
private:
std::shared_ptr reconstructors_ = std::make_shared();
diff --git a/Libs/Common/Logging.cpp b/Libs/Common/Logging.cpp
index 878f62ef9f..082c76c4f5 100644
--- a/Libs/Common/Logging.cpp
+++ b/Libs/Common/Logging.cpp
@@ -10,9 +10,9 @@ namespace spd = spdlog;
namespace shapeworks {
//-----------------------------------------------------------------------------
-static std::string create_header(const int line, const char *filename) {
- const char *name = (strrchr(filename, '/') ? strrchr(filename, '/') + 1 : filename);
- const char *name2 = (strrchr(name, '\\') ? strrchr(name, '\\') + 1 : name);
+static std::string create_header(const int line, const char* filename) {
+ const char* name = (strrchr(filename, '/') ? strrchr(filename, '/') + 1 : filename);
+ const char* name2 = (strrchr(name, '\\') ? strrchr(name, '\\') + 1 : name);
std::string header = "[" + std::string(name2) + "|" + std::to_string(line) + "]";
return header;
}
@@ -53,7 +53,7 @@ bool Logging::check_log_open() const { return log_open_; }
std::string Logging::get_log_filename() const { return log_filename_; }
//-----------------------------------------------------------------------------
-void Logging::log_message(const std::string& message, const int line, const char *file) const {
+void Logging::log_message(const std::string& message, const int line, const char* file) const {
spd::info(message);
if (log_open_) {
spd::get("file")->info(message);
@@ -72,7 +72,7 @@ void Logging::log_stack(const std::string& message) const {
}
//-----------------------------------------------------------------------------
-void Logging::log_error(const std::string& message, const int line, const char *file) const {
+void Logging::log_error(const std::string& message, const int line, const char* file) const {
spd::error(message);
if (log_open_) {
spd::get("file")->error(message);
@@ -83,7 +83,7 @@ void Logging::log_error(const std::string& message, const int line, const char *
}
//-----------------------------------------------------------------------------
-void Logging::show_message(const std::string& message, const int line, const char *file) const {
+void Logging::show_message(const std::string& message, const int line, const char* file) const {
log_message(message, line, file);
if (message_callback_) {
message_callback_(message);
@@ -91,15 +91,14 @@ void Logging::show_message(const std::string& message, const int line, const cha
}
//-----------------------------------------------------------------------------
-void Logging::show_status(const std::string& message, const int line, const char *file) const {
- log_message(message, line, file);
- if (message_callback_) {
- message_callback_(message);
+void Logging::show_status(const std::string& message, const int line, const char* file) const {
+ if (status_callback_) {
+ status_callback_(message);
}
}
//-----------------------------------------------------------------------------
-void Logging::log_debug(const std::string& message, const int line, const char *file) const {
+void Logging::log_debug(const std::string& message, const int line, const char* file) const {
std::string str = create_header(line, file) + " " + message;
spd::debug(str);
if (log_open_) {
@@ -113,7 +112,7 @@ void Logging::log_debug(const std::string& message, const int line, const char *
}
//-----------------------------------------------------------------------------
-void Logging::log_warning(const std::string& message, const int line, const char *file) const {
+void Logging::log_warning(const std::string& message, const int line, const char* file) const {
spd::warn(message);
if (log_open_) {
spd::get("file")->warn(message);
@@ -123,6 +122,13 @@ void Logging::log_warning(const std::string& message, const int line, const char
}
}
+//-----------------------------------------------------------------------------
+void Logging::show_progress(double value, const std::string& message) {
+ if (progress_callback_) {
+ progress_callback_(value, message);
+ }
+}
+
//-----------------------------------------------------------------------------
void Logging::close_log() {
if (!log_open_) {
@@ -145,4 +151,10 @@ void Logging::set_warning_callback(const std::function& callb
//-----------------------------------------------------------------------------
void Logging::set_debug_callback(const std::function& callback) { debug_callback_ = callback; }
+//-----------------------------------------------------------------------------
+void Logging::set_status_callback(const std::function& callback) { status_callback_ = callback; }
+
+//-----------------------------------------------------------------------------
+void Logging::set_progress_callback(const std::function& callback) { progress_callback_ = callback; }
+
} // namespace shapeworks
diff --git a/Libs/Common/Logging.h b/Libs/Common/Logging.h
index 6de6cace24..3b69f80f07 100644
--- a/Libs/Common/Logging.h
+++ b/Libs/Common/Logging.h
@@ -2,9 +2,8 @@
#include
-#include
-
#include
+#include
template <>
struct fmt::formatter {
@@ -102,6 +101,9 @@ class Logging {
//! Log a message, use SW_STATUS macro
void show_status(const std::string& message, const int line, const char* file) const;
+ //! Display progress (0-100)
+ void show_progress(double value, const std::string& message);
+
//! Log a debug message, use SW_DEBUG macro
void log_debug(const std::string& message, const int line, const char* file) const;
@@ -120,9 +122,15 @@ class Logging {
//! Set a warning callback function to be called whenever a warning is posted
void set_warning_callback(const std::function& callback);
- //! Set a debug messagecallback function to be called whenever a debug message is posted
+ //! Set a debug message callback function to be called whenever a debug message is posted
void set_debug_callback(const std::function& callback);
+ //! Set a status callback function to be called whenever a status message is posted
+ void set_status_callback(const std::function& callback);
+
+ //! Set a progress callback function to be called whenever a progress update is posted
+ void set_progress_callback(const std::function& callback);
+
private:
//! Constructor
Logging();
@@ -137,6 +145,10 @@ class Logging {
std::function warning_callback_;
std::function debug_callback_;
+
+ std::function status_callback_;
+
+ std::function progress_callback_;
};
//! Log stack macro
@@ -169,7 +181,19 @@ class Logging {
#define SW_STATUS(message, ...) \
shapeworks::Logging::Instance().show_status(fmt::format(message, ##__VA_ARGS__), __LINE__, __FILE__)
+#define SW_PROGRESS(value, message, ...) \
+ shapeworks::Logging::Instance().show_progress(value, fmt::format(message, ##__VA_ARGS__));
+
//! Close session macro
#define SW_CLOSE_LOG() shapeworks::Logging::Instance().close_log();
+//! Log once macro, will only log the message once
+#define SW_LOG_ONCE(message, ...) \
+{ \
+ static bool logged = false; \
+ if (!logged) { \
+ SW_LOG(message, ##__VA_ARGS__); \
+ logged = true; \
+ } \
+}
} // namespace shapeworks
diff --git a/Libs/Groom/Groom.cpp b/Libs/Groom/Groom.cpp
index 165124c8b7..42f95cf6f1 100644
--- a/Libs/Groom/Groom.cpp
+++ b/Libs/Groom/Groom.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
@@ -470,7 +471,7 @@ void Groom::increment_progress(int amount) {
std::scoped_lock lock(mutex);
this->progress_counter_ += amount;
this->progress_ = static_cast(this->progress_counter_) / static_cast(this->total_ops_) * 100.0;
- this->update_progress();
+ SW_PROGRESS(progress_, fmt::format("Grooming ({}/{} ops)", progress_counter_, total_ops_));
}
//---------------------------------------------------------------------------
diff --git a/Libs/Groom/Groom.h b/Libs/Groom/Groom.h
index 082dfddc2f..5451fbd24f 100644
--- a/Libs/Groom/Groom.h
+++ b/Libs/Groom/Groom.h
@@ -33,8 +33,6 @@ class Groom {
vtkSmartPointer target);
protected:
- //! call to be overridden by subclasses
- virtual void update_progress(){};
std::atomic progress_ = 0;
std::atomic total_ops_ = 0;
diff --git a/Libs/Mesh/MeshWarper.cpp b/Libs/Mesh/MeshWarper.cpp
index 1f39647d26..2abab322ea 100644
--- a/Libs/Mesh/MeshWarper.cpp
+++ b/Libs/Mesh/MeshWarper.cpp
@@ -45,7 +45,7 @@ vtkSmartPointer MeshWarper::build_mesh(const Eigen::MatrixXd& parti
double* p = poly_data->GetPoint(i);
if (std::isnan(p[0]) || std::isnan(p[1]) || std::isnan(p[2])) {
this->warp_available_ = false; // failed
- std::cerr << "Reconstruction Failed\n";
+ SW_ERROR("Reconstruction failed. NaN detected in mesh.");
return nullptr;
}
}
@@ -438,7 +438,7 @@ bool MeshWarper::generate_warp() {
Eigen::MatrixXd vertices = referenceMesh.points();
this->faces_ = referenceMesh.faces();
- // perform warp
+ // generate the warp
if (!MeshWarper::generate_warp_matrix(vertices, this->faces_, this->vertices_, this->warp_)) {
this->update_progress(1.0);
this->warp_available_ = false;
@@ -473,7 +473,7 @@ bool MeshWarper::generate_warp_matrix(Eigen::MatrixXd TV, Eigen::MatrixXi TF, co
// faster and looks OK
const int k = 2;
if (!igl::biharmonic_coordinates(TV, TF, S, k, W)) {
- std::cerr << "igl:biharmonic_coordinates failed\n";
+ SW_ERROR("Mesh Warp Error: igl:biharmonic_coordinates failed");
return false;
}
// Throw away interior tet-vertices, keep weights and indices of boundary
diff --git a/Libs/Optimize/Constraints.cpp b/Libs/Optimize/Constraints.cpp
index d7348d910a..a1143523f0 100644
--- a/Libs/Optimize/Constraints.cpp
+++ b/Libs/Optimize/Constraints.cpp
@@ -777,7 +777,6 @@ bool Constraints::hasConstraints() {
return true;
}
- SW_LOG("no constraints");
return false;
}
diff --git a/Libs/Optimize/Optimize.cpp b/Libs/Optimize/Optimize.cpp
index 9fb3a14c1f..892099a7f5 100644
--- a/Libs/Optimize/Optimize.cpp
+++ b/Libs/Optimize/Optimize.cpp
@@ -28,14 +28,13 @@
#include "Optimize.h"
#include "OptimizeParameterFile.h"
#include "OptimizeParameters.h"
+#include "ParticleGoodBadAssessment.h"
#include "ParticleImageDomain.h"
#include "ParticleImplicitSurfaceDomain.h"
#include "VtkMeshWrapper.h"
#include "object_reader.h"
#include "object_writer.h"
-#include "ParticleGoodBadAssessment.h"
-
// pybind
#include
#include
@@ -67,6 +66,9 @@ Optimize::Optimize() { this->m_sampler = std::make_shared(); }
//---------------------------------------------------------------------------
bool Optimize::Run() {
+ m_start_time = std::chrono::system_clock::now();
+ m_last_update_time = m_start_time;
+
// control number of threads
int num_threads = tbb::info::default_concurrency();
const char* num_threads_env = getenv("TBB_NUM_THREADS");
@@ -193,11 +195,6 @@ bool Optimize::Run() {
//---------------------------------------------------------------------------
int Optimize::SetParameters() {
- if (this->m_verbosity_level == 0) {
- std::cout << "Verbosity 0: This will be the only output on your screen, "
- "unless there are any errors. Increase the verbosity if needed.\n";
- }
-
// sanity check
if (m_domains_per_shape != m_number_of_particles.size()) {
SW_ERROR("Inconsistency in parameters... m_domains_per_shape != m_number_of_particles.size()");
@@ -967,6 +964,7 @@ void Optimize::IterateCallback(itk::Object*, const itk::EventObject&) {
}
}
}
+ UpdateProgress();
}
//---------------------------------------------------------------------------
@@ -2164,6 +2162,7 @@ void Optimize::SetSharedBoundaryEnabled(bool enabled) { m_sampler->SetSharedBoun
//---------------------------------------------------------------------------
void Optimize::SetSharedBoundaryWeight(double weight) { m_sampler->SetSharedBoundaryWeight(weight); }
+//---------------------------------------------------------------------------
void Optimize::ComputeTotalIterations() {
total_particle_iterations_ = 0;
@@ -2201,4 +2200,47 @@ void Optimize::ComputeTotalIterations() {
}
}
+//---------------------------------------------------------------------------
+void Optimize::UpdateProgress() {
+ auto now = std::chrono::system_clock::now();
+
+ if ((now - m_last_update_time) > std::chrono::milliseconds(100)) {
+ m_last_update_time = now;
+ std::chrono::duration elapsed_seconds =
+ std::chrono::duration_cast(now - m_start_time);
+ double seconds_per_iteration = elapsed_seconds.count() / current_particle_iterations_;
+ double seconds_remaining = seconds_per_iteration * (total_particle_iterations_ - current_particle_iterations_);
+ int hours = static_cast(seconds_remaining / 3600);
+ int minutes = static_cast((seconds_remaining - (hours * 3600)) / 60);
+ int seconds = static_cast(seconds_remaining - (hours * 3600) - (minutes * 60));
+
+ std::string message;
+ if (m_optimizing) {
+ message = "Optimizing";
+ } else {
+ message = "Initializing";
+ }
+
+ int stage_num_iterations = m_sampler->GetOptimizer()->GetNumberOfIterations();
+ int stage_total_iterations = m_sampler->GetOptimizer()->GetMaximumNumberOfIterations();
+ int num_particles = m_sampler->GetParticleSystem()->GetNumberOfParticles(0);
+
+ message = fmt::format("{} : Particles: {}, Iteration: {} / {}", message, num_particles, stage_num_iterations,
+ stage_total_iterations);
+
+ if ((now - m_last_remaining_update_time) > std::chrono::seconds(1)) {
+ m_remaining_time_message = fmt::format("({:02d}:{:02d}:{:02d} remaining)", hours, minutes, seconds);
+ m_last_remaining_update_time = now;
+ }
+
+ // only show the time remaining if it's been more than 3 seconds
+ if (elapsed_seconds > std::chrono::seconds(3)) {
+ message = fmt::format("{} {}", message, m_remaining_time_message);
+ }
+
+ double progress =
+ static_cast(current_particle_iterations_) * 100 / static_cast(total_particle_iterations_);
+ SW_PROGRESS(progress, message);
+ }
+}
} // namespace shapeworks
diff --git a/Libs/Optimize/Optimize.h b/Libs/Optimize/Optimize.h
index 3551eab98f..47976a97ba 100644
--- a/Libs/Optimize/Optimize.h
+++ b/Libs/Optimize/Optimize.h
@@ -302,6 +302,8 @@ class Optimize {
//! transform a point if necessary
vnl_vector_fixed TransformPoint(int domain, vnl_vector_fixed input);
+ void UpdateProgress();
+
protected:
//! Set the iteration callback. Derived classes should override to set their own callback
virtual void SetIterationCallback();
@@ -460,6 +462,12 @@ class Optimize {
shapeworks::OptimizationVisualizer visualizer_;
std::shared_ptr project_;
+
+ std::chrono::system_clock::time_point m_start_time;
+ std::chrono::system_clock::time_point m_last_update_time;
+ std::chrono::system_clock::time_point m_last_remaining_update_time;
+ std::string m_remaining_time_message;
+
};
} // namespace shapeworks
diff --git a/Libs/Project/ProjectUtils.cpp b/Libs/Project/ProjectUtils.cpp
index 4a672d3295..a6beef55b9 100644
--- a/Libs/Project/ProjectUtils.cpp
+++ b/Libs/Project/ProjectUtils.cpp
@@ -140,7 +140,7 @@ StringList ProjectUtils::get_values(StringList prefixes, StringList domain_names
for (auto& [key, value] : key_map) {
for (const auto& prefix : prefixes) {
if (key == prefix + domain) {
- values.push_back(value);
+ values.push_back(StringUtils::replace_string(value, "\\", "/"));
}
}
}
diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp
index 73b004a686..2cf773093a 100644
--- a/Studio/Analysis/AnalysisTool.cpp
+++ b/Studio/Analysis/AnalysisTool.cpp
@@ -920,17 +920,19 @@ void AnalysisTool::enable_actions(bool newly_enabled) {
update_domain_alignment_box();
}
- auto domain_types = session_->get_groomed_domain_types();
- bool image_domain = domain_types.size() > 0 && domain_types[0] == DomainType::Image;
- ui_->distance_transfom_radio_button->setEnabled(session_->particles_present() && session_->get_groomed_present() &&
- image_domain);
+ if (session_->particles_present()) {
+ auto domain_types = session_->get_groomed_domain_types();
+ bool image_domain = domain_types.size() > 0 && domain_types[0] == DomainType::Image;
+ ui_->distance_transfom_radio_button->setEnabled(session_->particles_present() && session_->get_groomed_present() &&
+ image_domain);
- ui_->mesh_warping_radio_button->setEnabled(session_->particles_present() && session_->get_groomed_present());
+ ui_->mesh_warping_radio_button->setEnabled(session_->particles_present() && session_->get_groomed_present());
- if (!ui_->mesh_warping_radio_button->isEnabled()) {
- ui_->legacy_radio_button->setChecked(true);
+ if (!ui_->mesh_warping_radio_button->isEnabled()) {
+ ui_->legacy_radio_button->setChecked(true);
+ }
+ reconstruction_method_changed();
}
- reconstruction_method_changed();
update_group_boxes();
ui_->sampleSpinBox->setMaximum(session_->get_num_shapes() - 1);
diff --git a/Studio/Analysis/AnalysisTool.ui b/Studio/Analysis/AnalysisTool.ui
index 6976368958..7eaad8b4bd 100644
--- a/Studio/Analysis/AnalysisTool.ui
+++ b/Studio/Analysis/AnalysisTool.ui
@@ -535,7 +535,7 @@ QWidget#particles_panel {
-
- 2
+ 0
@@ -603,7 +603,7 @@ QWidget#particles_panel {
-
-
+
Group slider
@@ -1059,16 +1059,10 @@ QWidget#particles_panel {
-
-
+
false
-
-
- 100
- 0
-
-
Standard deviation slider
@@ -2190,6 +2184,11 @@ Reference Domain
jkqtplotter/jkqtplotter.h
1
+
+ CustomSlider
+ QSlider
+
+
diff --git a/Studio/CMakeLists.txt b/Studio/CMakeLists.txt
index f586adb731..56b3c99924 100644
--- a/Studio/CMakeLists.txt
+++ b/Studio/CMakeLists.txt
@@ -115,11 +115,9 @@ SET(STUDIO_JOB_MOC_HDRS
SET(STUDIO_GROOM_SRCS
Groom/GroomTool.cpp
- Groom/QGroom.cpp
)
SET(STUDIO_GROOM_MOC_HDRS
Groom/GroomTool.h
- Groom/QGroom.h
)
SET(STUDIO_PYTHON_SRCS
@@ -171,6 +169,7 @@ SET(STUDIO_UTILS_MOC_HDRS
SET(STUDIO_INTERFACE_SRCS
Interface/CompareWidget.cpp
+ Interface/CustomSlider.cpp
Interface/ExportImageDialog.cpp
Interface/KeyboardShortcuts.cpp
Interface/LogWindow.cpp
@@ -184,6 +183,7 @@ SET(STUDIO_INTERFACE_SRCS
)
SET(STUDIO_INTERFACE_MOC_HDRS
Interface/CompareWidget.h
+ Interface/CustomSlider.h
Interface/ExportImageDialog.h
Interface/KeyboardShortcuts.h
Interface/LogWindow.h
diff --git a/Studio/Data/DataTool.cpp b/Studio/Data/DataTool.cpp
index 020e971c58..ed89cc1550 100644
--- a/Studio/Data/DataTool.cpp
+++ b/Studio/Data/DataTool.cpp
@@ -109,7 +109,7 @@ void DataTool::set_session(QSharedPointer session) {
connect(session.data(), &Session::ffc_changed, this, &DataTool::update_ffc_table);
landmark_table_model_->set_session(session);
- connect(ui_->ffc_brush_size_, &QSlider::valueChanged, session.data(), &Session::set_ffc_paint_size);
+ connect(ui_->ffc_brush_size_, &CustomSlider::valueChanged, session.data(), &Session::set_ffc_paint_size);
connect(ui_->ffc_included_mode_, &QRadioButton::toggled, session.data(), &Session::set_ffc_paint_mode_inclusive);
connect(ui_->ffc_active_, &QCheckBox::toggled, session.data(), &Session::set_ffc_paint_active);
diff --git a/Studio/Data/DataTool.ui b/Studio/Data/DataTool.ui
index 3b20dd691a..eaed9088c7 100644
--- a/Studio/Data/DataTool.ui
+++ b/Studio/Data/DataTool.ui
@@ -381,8 +381,8 @@ QWidget#specificity_panel {
0
0
- 470
- 340
+ 464
+ 330
@@ -848,7 +848,7 @@ QWidget#specificity_panel {
-
-
+
5
@@ -1053,7 +1053,14 @@ QWidget#specificity_panel {
-
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+hr { height: 1px; border-width: 0; }
+li.unchecked::marker { content: "\2610"; }
+li.checked::marker { content: "\2612"; }
+</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;">
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
@@ -1078,6 +1085,13 @@ QWidget#specificity_panel {
+
+
+ CustomSlider
+ QSlider
+
+
+
diff --git a/Studio/Data/PreferencesWindow.cpp b/Studio/Data/PreferencesWindow.cpp
index 3d49ea4c33..48be5ad709 100644
--- a/Studio/Data/PreferencesWindow.cpp
+++ b/Studio/Data/PreferencesWindow.cpp
@@ -46,7 +46,7 @@ PreferencesWindow::PreferencesWindow(QWidget* parent, Preferences& prefs) : pref
&PreferencesWindow::save_to_preferences);
connect(ui_->orientation_marker_corner, qOverload(&QComboBox::currentIndexChanged), this,
&PreferencesWindow::save_to_preferences);
- connect(ui_->geodesic_cache_multiplier, &QSlider::valueChanged, this, &PreferencesWindow::save_to_preferences);
+ connect(ui_->geodesic_cache_multiplier, &CustomSlider::valueChanged, this, &PreferencesWindow::save_to_preferences);
connect(ui_->color_map, qOverload(&QComboBox::currentIndexChanged), this,
&PreferencesWindow::save_to_preferences);
connect(ui_->particle_colors, qOverload(&QComboBox::currentIndexChanged), this,
diff --git a/Studio/Data/PreferencesWindow.ui b/Studio/Data/PreferencesWindow.ui
index 99781038d7..16259c0e9c 100644
--- a/Studio/Data/PreferencesWindow.ui
+++ b/Studio/Data/PreferencesWindow.ui
@@ -107,7 +107,7 @@
-
-
+
0
@@ -200,7 +200,7 @@
-
-
+
100
@@ -240,7 +240,7 @@
-
-
+
1
@@ -587,6 +587,13 @@
+
+
+ CustomSlider
+ QSlider
+
+
+
pca_range
pca_steps
diff --git a/Studio/Data/ShapeWorksWorker.cpp b/Studio/Data/ShapeWorksWorker.cpp
index 991d9118b6..8e02e6e415 100644
--- a/Studio/Data/ShapeWorksWorker.cpp
+++ b/Studio/Data/ShapeWorksWorker.cpp
@@ -2,7 +2,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -10,7 +10,7 @@
namespace shapeworks {
//---------------------------------------------------------------------------
-ShapeworksWorker::ShapeworksWorker(ThreadType type, QSharedPointer groom, QSharedPointer optimize,
+ShapeworksWorker::ShapeworksWorker(ThreadType type, QSharedPointer groom, QSharedPointer optimize,
QSharedPointer optimize_parameters,
QSharedPointer session, double maxAngle, float decimationPercent,
int numClusters)
diff --git a/Studio/Data/ShapeWorksWorker.h b/Studio/Data/ShapeWorksWorker.h
index adf9caa19a..dbf170a583 100644
--- a/Studio/Data/ShapeWorksWorker.h
+++ b/Studio/Data/ShapeWorksWorker.h
@@ -6,7 +6,7 @@
namespace shapeworks {
class Optimize;
-class QGroom;
+class Groom;
class OptimizeParameters;
class ShapeworksWorker : public QObject {
@@ -18,7 +18,7 @@ Q_OBJECT
};
ShapeworksWorker(ThreadType type,
- QSharedPointer groom,
+ QSharedPointer groom,
QSharedPointer optimize,
QSharedPointer optimize_parameters,
QSharedPointer session,
@@ -37,7 +37,7 @@ public Q_SLOTS:
private:
- QSharedPointer groom_;
+ QSharedPointer groom_;
QSharedPointer optimize_;
QSharedPointer optimize_parameters_;
QSharedPointer session_;
diff --git a/Studio/Data/Telemetry.cpp b/Studio/Data/Telemetry.cpp
index 8639d4d4d3..34138a4879 100644
--- a/Studio/Data/Telemetry.cpp
+++ b/Studio/Data/Telemetry.cpp
@@ -40,13 +40,13 @@ void Telemetry::record_event(const QString& name, const QVariantMap& params) {
QString api_secret{GA_API_SECRET};
if (measurement_id.isEmpty() || api_secret.isEmpty()) {
- SW_LOG("Telemetry disabled, no measurement id or api secret");
+ SW_LOG_ONCE("Telemetry disabled, no measurement id or api secret");
enabled_ = false;
return;
}
if (!prefs_.get_telemetry_enabled()) {
- SW_LOG("Telemetry disabled by preferences");
+ SW_LOG_ONCE("Telemetry disabled by preferences");
enabled_ = false;
return;
}
diff --git a/Studio/Groom/GroomTool.cpp b/Studio/Groom/GroomTool.cpp
index 95d445dc2f..a4b51d8a6c 100644
--- a/Studio/Groom/GroomTool.cpp
+++ b/Studio/Groom/GroomTool.cpp
@@ -73,13 +73,13 @@ GroomTool::GroomTool(Preferences& prefs, Telemetry& telemetry) : preferences_(pr
"Set the adaptivity of remeshing, higher will allocate more triangles around areas of high curvature.");
// connect percent controls
- connect(ui_->remesh_percent_slider, &QSlider::valueChanged, this,
+ connect(ui_->remesh_percent_slider, &CustomSlider::valueChanged, this,
[this](int value) { ui_->remesh_percent_spinbox->setValue(value); });
connect(ui_->remesh_percent_spinbox, qOverload(&QDoubleSpinBox::valueChanged), this,
[=](double value) { ui_->remesh_percent_slider->setValue(static_cast(value)); });
// connect gradation controls
- connect(ui_->remesh_gradation_slider, &QSlider::valueChanged, this,
+ connect(ui_->remesh_gradation_slider, &CustomSlider::valueChanged, this,
[=](int value) { ui_->remesh_gradation_spinbox->setValue(value / 50.0); });
connect(ui_->remesh_gradation_spinbox, qOverload(&QDoubleSpinBox::valueChanged), this,
[=](double value) { ui_->remesh_gradation_slider->setValue(static_cast(value * 50.0)); });
@@ -490,7 +490,7 @@ void GroomTool::on_run_groom_button_clicked() {
SW_LOG("Please wait: running groom step...");
Q_EMIT progress(0);
- groom_ = QSharedPointer(new QGroom(session_->get_project()));
+ groom_ = QSharedPointer(new Groom(session_->get_project()));
enable_actions();
@@ -500,7 +500,6 @@ void GroomTool::on_run_groom_button_clicked() {
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, &ShapeworksWorker::finished, this, &GroomTool::handle_thread_complete);
- connect(groom_.data(), &QGroom::progress, this, &GroomTool::handle_progress);
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
thread->start();
@@ -561,7 +560,7 @@ void GroomTool::skip_grooming_toggled() {
store_params();
if (ui_->skip_grooming->isChecked()) {
- groom_ = QSharedPointer(new QGroom(session_->get_project()));
+ groom_ = QSharedPointer(new Groom(session_->get_project()));
groom_->run();
SW_MESSAGE("Skipped Grooming");
Q_EMIT groom_complete();
diff --git a/Studio/Groom/GroomTool.h b/Studio/Groom/GroomTool.h
index ee325da021..6dfc1512ac 100644
--- a/Studio/Groom/GroomTool.h
+++ b/Studio/Groom/GroomTool.h
@@ -1,7 +1,7 @@
#pragma once
#include
-#include
+#include
#include
#include
@@ -97,7 +97,7 @@ class GroomTool : public QWidget {
Ui_GroomTool* ui_;
QSharedPointer session_;
- QSharedPointer groom_;
+ QSharedPointer groom_;
QElapsedTimer timer_;
diff --git a/Studio/Groom/GroomTool.ui b/Studio/Groom/GroomTool.ui
index 747718b6f6..30880f04eb 100644
--- a/Studio/Groom/GroomTool.ui
+++ b/Studio/Groom/GroomTool.ui
@@ -1607,7 +1607,7 @@ QWidget#domain_panel {
-
-
+
100
@@ -1620,7 +1620,7 @@ QWidget#domain_panel {
-
-
+
100
@@ -2013,6 +2013,13 @@ QWidget#domain_panel {
+
+
+ CustomSlider
+ QSlider
+
+
+
mesh_fill_holes
mesh_smooth
diff --git a/Studio/Groom/QGroom.cpp b/Studio/Groom/QGroom.cpp
deleted file mode 100644
index c7ad229335..0000000000
--- a/Studio/Groom/QGroom.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "QGroom.h"
-
-namespace shapeworks {
-
-//---------------------------------------------------------------------------
-void QGroom::update_progress()
-{
- Q_EMIT progress(static_cast(this->progress_));
-}
-
-//---------------------------------------------------------------------------
-QGroom::QGroom(ProjectHandle project) : Groom(project)
-{
-
-}
-}
\ No newline at end of file
diff --git a/Studio/Groom/QGroom.h b/Studio/Groom/QGroom.h
deleted file mode 100644
index 2105ad11de..0000000000
--- a/Studio/Groom/QGroom.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include
-
-#ifndef Q_MOC_RUN
-#include
-#endif
-
-namespace shapeworks {
-
-//! Qt Wrapper for Groom
-/*!
- * The QGroom class wraps the Groom class to provide a QObject with a progress signal
- *
- */
-class QGroom : public QObject, public Groom {
-
-Q_OBJECT;
-
-public:
-
- QGroom(ProjectHandle project);
-
-protected:
- // override update_progress to emit q_signal
- void update_progress();
-
-Q_SIGNALS:
- void progress(int);
-
-};
-}
diff --git a/Studio/Interface/CompareWidget.cpp b/Studio/Interface/CompareWidget.cpp
index a771dde412..f900d03f4c 100644
--- a/Studio/Interface/CompareWidget.cpp
+++ b/Studio/Interface/CompareWidget.cpp
@@ -12,7 +12,7 @@ CompareWidget::CompareWidget(QWidget *parent) : QWidget(parent), ui_(new Ui::Com
connect(ui_->original, &QCheckBox::toggled, this, &CompareWidget::settings_changed);
connect(ui_->groomed, &QCheckBox::toggled, this, &CompareWidget::settings_changed);
connect(ui_->reconstructed, &QCheckBox::toggled, this, &CompareWidget::settings_changed);
- connect(ui_->opacity, &QSlider::valueChanged, this, &CompareWidget::settings_changed);
+ connect(ui_->opacity, &CustomSlider::valueChanged, this, &CompareWidget::settings_changed);
connect(ui_->mean_shape, &QCheckBox::toggled, this, &CompareWidget::settings_changed);
}
diff --git a/Studio/Interface/CompareWidget.ui b/Studio/Interface/CompareWidget.ui
index ad60f1aa2d..e14b272c06 100644
--- a/Studio/Interface/CompareWidget.ui
+++ b/Studio/Interface/CompareWidget.ui
@@ -7,7 +7,7 @@
0
0
470
- 159
+ 172
@@ -15,7 +15,7 @@
-
-
+
100
@@ -74,6 +74,13 @@
+
+
+ CustomSlider
+ QSlider
+
+
+
diff --git a/Studio/Interface/CustomSlider.cpp b/Studio/Interface/CustomSlider.cpp
new file mode 100644
index 0000000000..49a00c0955
--- /dev/null
+++ b/Studio/Interface/CustomSlider.cpp
@@ -0,0 +1,71 @@
+
+
+#include "CustomSlider.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "math.h"
+
+CustomSlider::CustomSlider(QWidget* parent) : QSlider(parent) {
+ this->setStyleSheet(
+ "\
+ QSlider {\
+ min-height: 24px\
+ }\
+ QSlider::groove:horizontal {\
+ border: 1px solid #262626;\
+ height: 3px;\
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);\
+ margin: 0 5px;\
+ }\
+ \
+ QSlider::handle:horizontal {\
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);\
+ border: 1px solid #5c5c5c;\
+ width: 12px;\
+ margin: -8px -6px;\
+ border-radius: 3px;\
+ }\
+ ");
+};
+
+void CustomSlider::paintEvent(QPaintEvent* ev) {
+ QStylePainter p(this);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+
+ QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
+
+ // draw tick marks
+ // do this manually because they are very badly behaved with style sheets
+ int interval = tickInterval();
+ if (interval == 0) {
+ interval = pageStep();
+ }
+
+ if (tickPosition() != NoTicks) {
+ for (int i = minimum(); i <= maximum(); i += interval) {
+ int x =
+ std::round((double)((double)((double)(i - this->minimum()) / (double)(this->maximum() - this->minimum())) *
+ (double)(this->width() - handle.width()) +
+ (double)(handle.width() / 2.0))) -
+ 1;
+ int h = 4;
+ p.setPen(QColor("#a5a294"));
+ if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove) {
+ int y = this->rect().top();
+ p.drawLine(x, y, x, y + h);
+ }
+ if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow) {
+ int y = this->rect().bottom();
+ p.drawLine(x, y, x, y - h);
+ }
+ }
+ }
+
+ QSlider::paintEvent(ev);
+}
diff --git a/Studio/Interface/CustomSlider.h b/Studio/Interface/CustomSlider.h
new file mode 100644
index 0000000000..2c76041cbe
--- /dev/null
+++ b/Studio/Interface/CustomSlider.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include
+
+// adapted from:
+// https://stackoverflow.com/questions/69890284/qslider-in-qt-misbehaves-in-new-macos-monterey-v12-0-1-any-workaround/69890285#69890285
+class CustomSlider : public QSlider {
+ public:
+ explicit CustomSlider(Qt::Orientation orientation, QWidget* parent = nullptr) : QSlider(orientation, parent){};
+ explicit CustomSlider(QWidget* parent = nullptr);
+
+ protected:
+ virtual void paintEvent(QPaintEvent* ev);
+};
\ No newline at end of file
diff --git a/Studio/Interface/ShapeWorksStudioApp.cpp b/Studio/Interface/ShapeWorksStudioApp.cpp
index 9acec6b0b0..7336b5fb23 100644
--- a/Studio/Interface/ShapeWorksStudioApp.cpp
+++ b/Studio/Interface/ShapeWorksStudioApp.cpp
@@ -76,6 +76,8 @@ ShapeWorksStudioApp::ShapeWorksStudioApp() {
connect(&logger_, &StudioLogger::error, this, &ShapeWorksStudioApp::handle_error);
connect(&logger_, &StudioLogger::warning, this, &ShapeWorksStudioApp::handle_warning);
connect(&logger_, &StudioLogger::debug, this, &ShapeWorksStudioApp::handle_debug);
+ connect(&logger_, &StudioLogger::status, this, &ShapeWorksStudioApp::handle_status);
+ connect(&logger_, &StudioLogger::progress, this, &ShapeWorksStudioApp::handle_progress_with_message);
// default hide
ui_->feature_widget->hide();
@@ -655,9 +657,10 @@ void ShapeWorksStudioApp::handle_message(std::string str) {
}
//---------------------------------------------------------------------------
-void ShapeWorksStudioApp::handle_status(QString str) {
- status_bar_->set_message(MessageType::normal, str);
- current_message_ = str;
+void ShapeWorksStudioApp::handle_status(std::string str) {
+ auto qstr = QString::fromStdString(str);
+ status_bar_->set_message(MessageType::normal, qstr);
+ current_message_ = qstr;
}
//---------------------------------------------------------------------------
@@ -690,10 +693,15 @@ void ShapeWorksStudioApp::message_callback(std::string str) {
// QMetaObject::invokeMethod(this,)
}
+//---------------------------------------------------------------------------
+void ShapeWorksStudioApp::handle_progress_with_message(int value, std::string str) {
+ handle_progress(value);
+ handle_status(str);
+}
+
//---------------------------------------------------------------------------
void ShapeWorksStudioApp::handle_progress(int value) {
status_bar_->set_progress(value);
- handle_message(current_message_.toStdString());
}
//---------------------------------------------------------------------------
@@ -721,7 +729,7 @@ void ShapeWorksStudioApp::create_glyph_submenu() {
layout->addWidget(glyph_size_label_, 0, 1, 1, 1);
layout->addWidget(glyph_quality_label_, 1, 1, 1, 1);
- glyph_size_slider_ = new QSlider(widget);
+ glyph_size_slider_ = new CustomSlider(widget);
glyph_size_slider_->setOrientation(Qt::Horizontal);
glyph_size_slider_->setMinimum(1);
glyph_size_slider_->setMaximum(100);
@@ -734,7 +742,7 @@ void ShapeWorksStudioApp::create_glyph_submenu() {
glyph_arrow_scale_ = new QCheckBox("Scale arrows");
- glyph_quality_slider_ = new QSlider(widget);
+ glyph_quality_slider_ = new CustomSlider(widget);
glyph_quality_slider_->setMinimum(1);
glyph_quality_slider_->setMaximum(20);
glyph_quality_slider_->setPageStep(3);
@@ -758,8 +766,8 @@ void ShapeWorksStudioApp::create_glyph_submenu() {
glyph_quality_label_->setText(QString::number(preferences_.get_glyph_quality()));
glyph_size_label_->setText(QString::number(preferences_.get_glyph_size()));
- connect(glyph_size_slider_, &QSlider::valueChanged, this, &ShapeWorksStudioApp::handle_glyph_changed);
- connect(glyph_quality_slider_, &QSlider::valueChanged, this, &ShapeWorksStudioApp::handle_glyph_changed);
+ connect(glyph_size_slider_, &CustomSlider::valueChanged, this, &ShapeWorksStudioApp::handle_glyph_changed);
+ connect(glyph_quality_slider_, &CustomSlider::valueChanged, this, &ShapeWorksStudioApp::handle_glyph_changed);
connect(glyph_auto_size_, &QCheckBox::clicked, this, &ShapeWorksStudioApp::handle_glyph_changed);
connect(glyph_arrow_scale_, &QCheckBox::clicked, this, &ShapeWorksStudioApp::handle_glyph_changed);
@@ -821,7 +829,7 @@ void ShapeWorksStudioApp::create_iso_submenu() {
QLabel* size_label = new QLabel(text);
layout->addWidget(size_label, row, 0, 1, 1);
- QSlider* slider = new QSlider(widget);
+ CustomSlider* slider = new CustomSlider(widget);
slider->setOrientation(Qt::Horizontal);
slider->setMinimum(1);
slider->setMaximum(100);
@@ -830,7 +838,7 @@ void ShapeWorksStudioApp::create_iso_submenu() {
slider->setTickInterval(10);
slider->setValue(100);
slider->setMinimumWidth(200);
- connect(slider, &QSlider::valueChanged, this, &ShapeWorksStudioApp::handle_opacity_changed);
+ connect(slider, &CustomSlider::valueChanged, this, &ShapeWorksStudioApp::handle_opacity_changed);
layout->addWidget(slider, row, 1, 1, 1);
widget->setLayout(layout);
diff --git a/Studio/Interface/ShapeWorksStudioApp.h b/Studio/Interface/ShapeWorksStudioApp.h
index 649174cc4e..07663bde63 100644
--- a/Studio/Interface/ShapeWorksStudioApp.h
+++ b/Studio/Interface/ShapeWorksStudioApp.h
@@ -20,9 +20,9 @@
#include
#include
#include
-#include
#include
#include
+#include
// Forward Qt class declarations
class Ui_ShapeWorksStudioApp;
@@ -129,11 +129,11 @@ class ShapeWorksStudioApp : public QMainWindow {
void handle_error(std::string str);
void handle_warning(std::string str);
void handle_debug(std::string str);
+ void handle_status(std::string str);
+ void handle_progress_with_message(int amt, std::string str);
+ void handle_progress(int amt);
void message_callback(std::string str);
-
- void handle_status(QString str);
- void handle_progress(int amt);
void handle_new_mesh();
void handle_clear_cache();
void handle_compare_settings_changed();
@@ -239,8 +239,8 @@ class ShapeWorksStudioApp : public QMainWindow {
QSharedPointer wheel_event_forwarder_;
// programmatic UI elements
- QSlider* glyph_size_slider_;
- QSlider* glyph_quality_slider_;
+ CustomSlider* glyph_size_slider_;
+ CustomSlider* glyph_quality_slider_;
QLabel* glyph_size_label_;
QLabel* glyph_quality_label_;
QCheckBox* glyph_auto_size_;
@@ -250,7 +250,7 @@ class ShapeWorksStudioApp : public QMainWindow {
QPointer status_bar_;
QSharedPointer splash_screen_;
QErrorMessage error_message_dialog_;
- std::vector iso_opacity_sliders_;
+ std::vector iso_opacity_sliders_;
std::vector domain_particle_checkboxes_;
QString current_message_;
diff --git a/Studio/Interface/ShapeWorksStudioApp.ui b/Studio/Interface/ShapeWorksStudioApp.ui
index bb411e0475..4d824ebc34 100644
--- a/Studio/Interface/ShapeWorksStudioApp.ui
+++ b/Studio/Interface/ShapeWorksStudioApp.ui
@@ -368,7 +368,7 @@ QToolBar QToolButton::checked {
-
-
+
100
@@ -1215,6 +1215,11 @@ QToolBar QToolButton::checked {
+
+ CustomSlider
+ QSlider
+
+
QVTKOpenGLNativeWidget
QWidget
diff --git a/Studio/Interface/StudioLogger.cpp b/Studio/Interface/StudioLogger.cpp
index e22e4ec143..5e2af2c108 100644
--- a/Studio/Interface/StudioLogger.cpp
+++ b/Studio/Interface/StudioLogger.cpp
@@ -14,16 +14,22 @@ void StudioLogger::register_callbacks() {
Logging::Instance().set_warning_callback(warning_callback);
auto debug_callback = std::bind(&StudioLogger::handle_debug, this, std::placeholders::_1);
Logging::Instance().set_debug_callback(debug_callback);
+ auto status_callback = std::bind(&StudioLogger::handle_status, this, std::placeholders::_1);
+ Logging::Instance().set_status_callback(status_callback);
+ auto progress_callback =
+ std::bind(&StudioLogger::handle_progress, this, std::placeholders::_1, std::placeholders::_2);
+ Logging::Instance().set_progress_callback(progress_callback);
}
//---------------------------------------------------------------------------
void StudioLogger::handle_message(std::string str) { Q_EMIT message(str); }
-
//---------------------------------------------------------------------------
void StudioLogger::handle_error(std::string str) { Q_EMIT error(str); }
-
//---------------------------------------------------------------------------
void StudioLogger::handle_warning(std::string str) { Q_EMIT warning(str); }
-
//---------------------------------------------------------------------------
void StudioLogger::handle_debug(std::string str) { Q_EMIT debug(str); }
+//---------------------------------------------------------------------------
+void StudioLogger::handle_status(std::string str) { Q_EMIT status(str); }
+//---------------------------------------------------------------------------
+void StudioLogger::handle_progress(double value, std::string str) { Q_EMIT progress(static_cast(value), str); }
diff --git a/Studio/Interface/StudioLogger.h b/Studio/Interface/StudioLogger.h
index ba2e0d3df6..bc477204b4 100644
--- a/Studio/Interface/StudioLogger.h
+++ b/Studio/Interface/StudioLogger.h
@@ -17,10 +17,14 @@ class StudioLogger : public QObject {
void handle_error(std::string str);
void handle_warning(std::string str);
void handle_debug(std::string str);
+ void handle_status(std::string str);
+ void handle_progress(double value, std::string str);
Q_SIGNALS:
void message(std::string str);
void error(std::string str);
void warning(std::string str);
void debug(std::string str);
+ void status(std::string str);
+ void progress(int value, std::string str);
};
diff --git a/Studio/Interface/UpdateChecker.cpp b/Studio/Interface/UpdateChecker.cpp
index 84fc426038..41d4e9008d 100644
--- a/Studio/Interface/UpdateChecker.cpp
+++ b/Studio/Interface/UpdateChecker.cpp
@@ -58,48 +58,53 @@ void UpdateChecker::handleNetworkReply(QNetworkReply* reply) {
std::string response = QString(reply->readAll()).toStdString();
// get the json response
- auto j = json::parse(response);
-
- std::string platform = StudioUtils::get_platform_string().toStdString();
-
- int major = j[platform]["major"].get();
- int minor = j[platform]["minor"].get();
- int patch = j[platform]["patch"].get();
- QString message = QString::fromStdString(j[platform]["message"].get());
-
- bool update_available = false;
- if (major > SHAPEWORKS_MAJOR_VERSION) {
- update_available = true;
- } else if (major == SHAPEWORKS_MAJOR_VERSION && minor > SHAPEWORKS_MINOR_VERSION) {
- update_available = true;
- } else if (major == SHAPEWORKS_MAJOR_VERSION && minor == SHAPEWORKS_MINOR_VERSION &&
- patch > SHAPEWORKS_PATCH_VERSION) {
- update_available = true;
- }
+ try {
+ auto j = json::parse(response);
+ std::string platform = StudioUtils::get_platform_string().toStdString();
+
+ int major = j[platform]["major"].get();
+ int minor = j[platform]["minor"].get();
+ int patch = j[platform]["patch"].get();
+ QString message = QString::fromStdString(j[platform]["message"].get());
+
+ bool update_available = false;
+ if (major > SHAPEWORKS_MAJOR_VERSION) {
+ update_available = true;
+ } else if (major == SHAPEWORKS_MAJOR_VERSION && minor > SHAPEWORKS_MINOR_VERSION) {
+ update_available = true;
+ } else if (major == SHAPEWORKS_MAJOR_VERSION && minor == SHAPEWORKS_MINOR_VERSION &&
+ patch > SHAPEWORKS_PATCH_VERSION) {
+ update_available = true;
+ }
- if (update_available) {
- auto url = QString("https://github.com/SCIInstitute/ShapeWorks/releases/latest");
-
- auto title = QString("New version available");
- setWindowTitle(title);
- ui_->label->setTextFormat(Qt::RichText);
- ui_->label->setOpenExternalLinks(true);
- ui_->label->setTextInteractionFlags(Qt::TextBrowserInteraction);
- ui_->label->setText(QString("A new version of ShapeWorks is available.
"
- "To download the latest version, please visit:
%1
" +
- message)
- .arg(url));
-
- show();
- raise();
-
- } else {
- if (manual_trigger_) {
- // show a messagebox saying there is no update
- auto title = QString("No update available");
- auto info = QString("You are running the latest version of ShapeWorks.");
- QMessageBox::information(nullptr, title, info, QMessageBox::Ok);
+ if (update_available) {
+ auto url = QString("https://github.com/SCIInstitute/ShapeWorks/releases/latest");
+
+ auto title = QString("New version available");
+ setWindowTitle(title);
+ ui_->label->setTextFormat(Qt::RichText);
+ ui_->label->setOpenExternalLinks(true);
+ ui_->label->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ ui_->label->setText(QString("A new version of ShapeWorks is available.
"
+ "To download the latest version, please visit:
%1
" +
+ message)
+ .arg(url));
+
+ show();
+ raise();
+
+ } else {
+ if (manual_trigger_) {
+ // show a messagebox saying there is no update
+ auto title = QString("No update available");
+ auto info = QString("You are running the latest version of ShapeWorks.");
+ QMessageBox::information(nullptr, title, info, QMessageBox::Ok);
+ }
}
+
+ } catch (json::exception& e) {
+ SW_LOG("Unable to check for updates: " + std::string(e.what()));
+ return;
}
}
} // namespace shapeworks
\ No newline at end of file
diff --git a/Studio/Interface/UpdateChecker.h b/Studio/Interface/UpdateChecker.h
index 2fd6042411..0393efe353 100644
--- a/Studio/Interface/UpdateChecker.h
+++ b/Studio/Interface/UpdateChecker.h
@@ -1,10 +1,10 @@
#pragma once
+#include
+
#include
#include
-#include
-
namespace Ui {
class UpdateChecker;
}
@@ -25,7 +25,6 @@ class UpdateChecker : public QDialog {
void run_auto_update_check();
void run_manual_update_check();
-
public Q_SLOTS:
void handleNetworkReply(QNetworkReply* reply);
@@ -38,7 +37,6 @@ class UpdateChecker : public QDialog {
Ui::UpdateChecker* ui_;
Preferences& prefs_;
-
};
} // namespace shapeworks
\ No newline at end of file
diff --git a/Studio/Optimize/OptimizeTool.cpp b/Studio/Optimize/OptimizeTool.cpp
index 8a5e3fb164..7cac360c53 100644
--- a/Studio/Optimize/OptimizeTool.cpp
+++ b/Studio/Optimize/OptimizeTool.cpp
@@ -113,8 +113,8 @@ void OptimizeTool::handle_progress(int val, QString progress_message) {
return;
}
- Q_EMIT progress(val);
- Q_EMIT status(progress_message);
+ //Q_EMIT progress(val);
+ //Q_EMIT status(progress_message.toStdString());
auto particles = optimize_->GetParticles();
session_->update_particles(particles);
diff --git a/Studio/Optimize/OptimizeTool.h b/Studio/Optimize/OptimizeTool.h
index bd2d3c67bd..e62b58a896 100644
--- a/Studio/Optimize/OptimizeTool.h
+++ b/Studio/Optimize/OptimizeTool.h
@@ -68,7 +68,7 @@ public Q_SLOTS:
void optimize_complete();
void progress(int);
- void status(QString);
+ void status(std::string);
private:
diff --git a/Studio/Optimize/QOptimize.cpp b/Studio/Optimize/QOptimize.cpp
index da88c712af..4c8c49069f 100644
--- a/Studio/Optimize/QOptimize.cpp
+++ b/Studio/Optimize/QOptimize.cpp
@@ -1,137 +1,109 @@
#include "QOptimize.h"
-#include
#include
+#include
+
namespace shapeworks {
-QOptimize::QOptimize(QObject* parent) :
- QObject(parent),
- Optimize()
-{}
+QOptimize::QOptimize(QObject* parent) : QObject(parent), Optimize() {}
//---------------------------------------------------------------------------
-QOptimize::~QOptimize()
-{}
+QOptimize::~QOptimize() {}
//---------------------------------------------------------------------------
-std::vector>> QOptimize::GetLocalPoints()
-{
+std::vector>> QOptimize::GetLocalPoints() {
QMutexLocker locker(&qmutex_);
- return this->m_local_points;
+ return m_local_points;
}
//---------------------------------------------------------------------------
-std::vector>> QOptimize::GetGlobalPoints()
-{
+std::vector>> QOptimize::GetGlobalPoints() {
QMutexLocker locker(&qmutex_);
- return this->m_global_points;
+ return m_global_points;
}
//---------------------------------------------------------------------------
-void QOptimize::UpdateExportablePoints()
-{
+void QOptimize::UpdateExportablePoints() {
QMutexLocker locker(&qmutex_);
Optimize::UpdateExportablePoints();
}
//---------------------------------------------------------------------------
-void QOptimize::SetIterationCallback()
-{
- this->iterate_command_ = itk::MemberCommand::New();
- this->iterate_command_->SetCallbackFunction(this, &QOptimize::IterateCallback);
- m_sampler->GetOptimizer()->AddObserver(itk::IterationEvent(), this->iterate_command_);
+void QOptimize::SetIterationCallback() {
+ iterate_command_ = itk::MemberCommand::New();
+ iterate_command_->SetCallbackFunction(this, &QOptimize::IterateCallback);
+ m_sampler->GetOptimizer()->AddObserver(itk::IterationEvent(), iterate_command_);
}
//---------------------------------------------------------------------------
-void QOptimize::IterateCallback(itk::Object* caller, const itk::EventObject& e)
-{
-
- if (this->m_aborted) {
+void QOptimize::IterateCallback(itk::Object* caller, const itk::EventObject& e) {
+ if (m_aborted) {
return;
}
// run superclass iterateCallback
Optimize::IterateCallback(caller, e);
- auto transform = this->m_sampler->GetParticleSystem()->GetTransform();
+ auto transform = m_sampler->GetParticleSystem()->GetTransform();
if (transform(0, 0) != transform(0, 0)) {
- //throw on NaN
+ // throw on NaN
throw std::runtime_error("Optimize failed! Please try changing parameters.");
}
bool update = false;
- if (!this->time_since_last_update_.isValid()) {
+ if (!time_since_last_update_.isValid()) {
update = true;
- }
- else {
- auto time_since = this->time_since_last_update_.elapsed();
+ } else {
+ auto time_since = time_since_last_update_.elapsed();
if (time_since > 100) {
update = true;
}
}
- int stage_num_iterations = m_sampler->GetOptimizer()->GetNumberOfIterations();
- int stage_total_iterations = m_sampler->GetOptimizer()->GetMaximumNumberOfIterations();
- int num_particles = m_sampler->GetParticleSystem()->GetNumberOfParticles(0);
- QString message;
- if (this->m_optimizing) {
- message = "Optimizing: ";
- }
- else {
- message = "Initializing: ";
- }
-
- message = message + "Particles: " + QString::number(num_particles) + ", Iteration: " +
- QString::number(stage_num_iterations) + " / " + QString::number(stage_total_iterations);
-
if (update) {
- this->time_since_last_update_.start();
+ time_since_last_update_.start();
{
QMutexLocker locker(&qmutex_);
- this->m_local_points.clear();
- this->m_global_points.clear();
+ m_local_points.clear();
+ m_global_points.clear();
// copy particles
- for (size_t d = 0; d < this->m_sampler->
- GetParticleSystem()->GetNumberOfDomains(); d++) {
-
+ for (size_t d = 0; d < m_sampler->GetParticleSystem()->GetNumberOfDomains(); d++) {
// blank set of points
- this->m_local_points.push_back(std::vector>());
- this->m_global_points.push_back(std::vector>());
+ m_local_points.push_back(std::vector>());
+ m_global_points.push_back(std::vector>());
// for each particle
- for (size_t j = 0; j < this->m_sampler->
- GetParticleSystem()->GetNumberOfParticles(d); j++) {
- auto pos = this->m_sampler->GetParticleSystem()->GetPosition(j, d);
- auto pos2 = this->m_sampler->GetParticleSystem()->GetTransformedPosition(j, d);
- this->m_local_points[d].push_back(pos);
- this->m_global_points[d].push_back(pos2);
+ for (size_t j = 0; j < m_sampler->GetParticleSystem()->GetNumberOfParticles(d); j++) {
+ auto pos = m_sampler->GetParticleSystem()->GetPosition(j, d);
+ auto pos2 = m_sampler->GetParticleSystem()->GetTransformedPosition(j, d);
+ m_local_points[d].push_back(pos);
+ m_global_points[d].push_back(pos2);
}
}
}
- Q_EMIT progress(current_particle_iterations_ * 100 / total_particle_iterations_, message);
+ Q_EMIT progress(0, "");
}
}
//---------------------------------------------------------------------------
-std::vector QOptimize::GetParticles()
-{
+std::vector QOptimize::GetParticles() {
QMutexLocker locker(&qmutex_);
std::vector particles;
- int num_domains_per_subject = this->GetDomainsPerShape();
- int num_subjects = this->GetNumShapes() / num_domains_per_subject;
+ int num_domains_per_subject = GetDomainsPerShape();
+ int num_subjects = GetNumShapes() / num_domains_per_subject;
particles.resize(num_subjects);
int subject = 0;
int domain = 0;
- for (int i = 0; i < this->m_local_points.size(); i++) {
- particles[subject].set_local_particles(domain, this->m_local_points[i]);
- particles[subject].set_world_particles(domain, this->m_global_points[i]);
+ for (int i = 0; i < m_local_points.size(); i++) {
+ particles[subject].set_local_particles(domain, m_local_points[i]);
+ particles[subject].set_world_particles(domain, m_global_points[i]);
domain++;
if (domain == num_domains_per_subject) {
subject++;
@@ -143,11 +115,10 @@ std::vector QOptimize::GetParticles()
}
//---------------------------------------------------------------------------
-std::vector>> QOptimize::GetProcrustesTransforms()
-{
+std::vector>> QOptimize::GetProcrustesTransforms() {
QMutexLocker locker(&qmutex_);
auto transforms = Optimize::GetProcrustesTransforms();
return transforms;
}
-}
+} // namespace shapeworks
diff --git a/Studio/Optimize/QOptimize.h b/Studio/Optimize/QOptimize.h
index 8d913be74d..2488ca1137 100644
--- a/Studio/Optimize/QOptimize.h
+++ b/Studio/Optimize/QOptimize.h
@@ -4,17 +4,17 @@
#include
#include
#endif
-#include
-#include
#include
+#include
+#include
namespace shapeworks {
//! Wraps Optimize as a QObject
class QOptimize : public QObject, public Optimize {
-Q_OBJECT;
+ Q_OBJECT;
-public:
+ public:
QOptimize(QObject* parent = nullptr);
virtual ~QOptimize();
@@ -27,22 +27,20 @@ Q_OBJECT;
void UpdateExportablePoints() override;
-protected:
+ protected:
virtual void SetIterationCallback() override;
virtual void IterateCallback(itk::Object* caller, const itk::EventObject&) override;
-Q_SIGNALS:
+ Q_SIGNALS:
void progress(int, QString);
-private:
-
+ private:
itk::MemberCommand::Pointer iterate_command_;
// for concurrent access
QMutex qmutex_;
QElapsedTimer time_since_last_update_;
-
};
-}
+} // namespace shapeworks
diff --git a/install_shapeworks.sh b/install_shapeworks.sh
index ac6011f315..d25697bfaa 100644
--- a/install_shapeworks.sh
+++ b/install_shapeworks.sh
@@ -105,7 +105,6 @@ function install_conda() {
CONDA_PACKAGES=(python=3.9.13 \
openblas=0.3.20 \
'vtk=9.1.0=qt*' \
- scikit-learn=1.1.1 \
pip=22.1.2
)
@@ -185,6 +184,8 @@ function install_conda() {
if ! pip install SimpleITK==2.1.1.2; then return 1; fi
if ! pip install bokeh==2.4.3; then return 1; fi
if ! pip install seaborn==0.11.2; then return 1; fi
+ if ! pip install scikit-learn==1.1.1; then return 1; fi
+
if ! pip install Python/DatasetUtilsPackage; then return 1; fi # install the local GirderConnector code as a package
if ! pip install Python/DocumentationUtilsPackage; then return 1; fi # install shapeworks auto-documentation as a package
if ! pip install Python/DataAugmentationUtilsPackage; then return 1; fi # install data augmentation code as a package