From 420d905bcc3ccb52ca1a5d437e27ed93e808950c Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Fri, 9 May 2025 16:42:01 -0600 Subject: [PATCH 01/25] Update URL for UpdateChecker --- Studio/Interface/UpdateChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Studio/Interface/UpdateChecker.cpp b/Studio/Interface/UpdateChecker.cpp index 449af0a2ddd..ccc3bf982ef 100644 --- a/Studio/Interface/UpdateChecker.cpp +++ b/Studio/Interface/UpdateChecker.cpp @@ -50,7 +50,7 @@ void UpdateChecker::run_auto_update_check() { void UpdateChecker::run_update_check() { // check if a new version is available - QNetworkRequest request(QUrl("http://www.sci.utah.edu/~shapeworks/version.json")); + QNetworkRequest request(QUrl("https://www.sci.utah.edu/~shapeworks/version.json")); network_.get(request); } From 4b8a51c9ed16eff148dec32694b0b6a42ba965f5 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Fri, 9 May 2025 16:42:32 -0600 Subject: [PATCH 02/25] Remove debug statement --- Studio/Analysis/AnalysisTool.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp index 059759021ee..45dee04c7ab 100644 --- a/Studio/Analysis/AnalysisTool.cpp +++ b/Studio/Analysis/AnalysisTool.cpp @@ -718,7 +718,6 @@ bool AnalysisTool::compute_stats() { //----------------------------------------------------------------------------- Particles AnalysisTool::get_mean_shape_points() { if (!compute_stats()) { - std::cerr << "Non buenas, returning empty particles\n"; return Particles(); } From f85c5014c371d45dd9c261ee46b25fcdb4fc41a6 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sat, 10 May 2025 01:19:01 -0600 Subject: [PATCH 03/25] Remove assert --- Libs/Analyze/Shape.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Libs/Analyze/Shape.cpp b/Libs/Analyze/Shape.cpp index 452646a854f..08a49f17b5f 100644 --- a/Libs/Analyze/Shape.cpp +++ b/Libs/Analyze/Shape.cpp @@ -125,10 +125,8 @@ void Shape::recompute_original_surface() { original_meshes_.set_mesh(0, mesh_handle); } - //--------------------------------------------------------------------------- -void Shape::ensure_segmentation() -{ +void Shape::ensure_segmentation() { if (get_segmentation()) { return; } @@ -159,8 +157,7 @@ void Shape::ensure_segmentation() //--------------------------------------------------------------------------- MeshGroup Shape::get_groomed_meshes(bool wait) { if (!subject_) { - std::cerr << "Error: asked for groomed meshes when none are present!\n"; - assert(0); + return {}; } if (!groomed_meshes_.valid() || groomed_meshes_.meshes().size() != subject_->get_number_of_domains()) { From 5b61a5551f7a215588ceb285408c84d352fc1149 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sat, 10 May 2025 01:19:14 -0600 Subject: [PATCH 04/25] Fix libomp.dylib problem on mac arm64 --- install_shapeworks.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/install_shapeworks.sh b/install_shapeworks.sh index 6be6e0823b5..ab5c9642106 100644 --- a/install_shapeworks.sh +++ b/install_shapeworks.sh @@ -141,11 +141,14 @@ function install_conda() { if ! pip install open3d-cpu==0.17.0; then return 1; fi elif [[ "$(uname)" == "Darwin" ]]; then if ! pip install open3d==0.17.0; then return 1; fi - # fix hard-coded homebrew libomp.dylib - pushd $CONDA_PREFIX/lib/python3.9/site-packages/open3d/cpu - install_name_tool -change /opt/homebrew/opt/libomp/lib/libomp.dylib @rpath/libomp.dylib pybind.cpython-39-darwin.so - install_name_tool -add_rpath @loader_path/../../../ pybind.cpython-39-darwin.so - popd + + if [[ "$(uname -m)" == "arm64" ]]; then + pushd $CONDA_PREFIX/lib/python3.9/site-packages/open3d/cpu + install_name_tool -change /opt/homebrew/opt/libomp/lib/libomp.dylib @rpath/libomp.dylib pybind.cpython-39-darwin.so + install_name_tool -add_rpath @loader_path/../../../ pybind.cpython-39-darwin.so + popd + ln -sf "$CONDA_PREFIX/lib/libomp.dylib" "$CONDA_PREFIX/lib/python3.9/site-packages/open3d/cpu/../../../libomp.dylib" + fi else if ! pip install open3d==0.17.0; then return 1; fi fi From 3b78b5031789ca704dc80c8f001cea7451227875 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 12 May 2025 14:25:23 -0600 Subject: [PATCH 05/25] Added warning about inconsistent number of values in particle vector. Still not sure of the cause, but it should prevent the crash. --- Studio/Analysis/AnalysisTool.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp index 45dee04c7ab..474453e8fb6 100644 --- a/Studio/Analysis/AnalysisTool.cpp +++ b/Studio/Analysis/AnalysisTool.cpp @@ -2136,6 +2136,12 @@ Particles AnalysisTool::convert_from_combined(const Eigen::VectorXd& points) { int idx = 0; for (int d = 0; d < worlds.size(); d++) { Eigen::VectorXd new_world(worlds[d].size()); + + if (idx + new_world.size() > points.size()) { + SW_WARN("Inconsistent number of values in particle vector"); + return {}; + } + for (int i = 0; i < worlds[d].size(); i++) { new_world[i] = points[idx++]; } From 11e047b4a210a0846f7b011fa2c6dd5f1fc1e0f6 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 12 May 2025 14:25:40 -0600 Subject: [PATCH 06/25] Add ability to log without going to Studio log --- Libs/Common/Logging.cpp | 10 +++++++++- Libs/Common/Logging.h | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Libs/Common/Logging.cpp b/Libs/Common/Logging.cpp index 48680207658..9290819d4a8 100644 --- a/Libs/Common/Logging.cpp +++ b/Libs/Common/Logging.cpp @@ -13,11 +13,11 @@ namespace shapeworks { static std::string create_header(const int line, const char* filename, const char* function = "") { const char* name = (strrchr(filename, '/') ? strrchr(filename, '/') + 1 : filename); const char* name2 = (strrchr(name, '\\') ? strrchr(name, '\\') + 1 : name); - const char* function_name = (strrchr(function, ':') ? strrchr(function, ':') + 1 : function); if (!function) { std::string header = "[" + std::string(name2) + "|" + std::to_string(line) + "]"; return header; } else { + const char* function_name = (strrchr(function, ':') ? strrchr(function, ':') + 1 : function); std::string header = "[" + std::string(name2) + "|" + std::string(function_name) + "|" + std::to_string(line) + "]"; return header; } @@ -69,6 +69,14 @@ void Logging::log_message(const std::string& message, const int line, const char } } +//----------------------------------------------------------------------------- +void Logging::log_only(const std::string& message, const int line, const char* file) const { + spd::info(message); + if (log_open_) { + spd::get("file")->info(message); + } +} + //----------------------------------------------------------------------------- void Logging::log_stack(const std::string& message) const { spd::error(message); diff --git a/Libs/Common/Logging.h b/Libs/Common/Logging.h index 08c541a93cb..1e3961097ff 100644 --- a/Libs/Common/Logging.h +++ b/Libs/Common/Logging.h @@ -102,6 +102,9 @@ class Logging { //! Log a message, use SW_LOG macro void log_message(const std::string& message, const int line, const char* file) const; + //! Log a message, use SW_LOG_ONLY macro + void log_only(const std::string& message, const int line, const char* file) const; + //! Log a stack trace message, use SW_LOG_STACK macro void log_stack(const std::string& message) const; @@ -171,6 +174,10 @@ class Logging { #define SW_LOG(message, ...) \ shapeworks::Logging::Instance().log_message(safe_format(message, ##__VA_ARGS__), __LINE__, __FILE__); +//! Log only macro +#define SW_LOG_ONLY(message, ...) \ + shapeworks::Logging::Instance().log_only(safe_format(message, ##__VA_ARGS__), __LINE__, __FILE__); + //! Log warning macro #define SW_WARN(message, ...) \ shapeworks::Logging::Instance().log_warning(safe_format(message, ##__VA_ARGS__), __LINE__, __FILE__) From 8a1f9c1f3106b20eb4704cdbc87317f0600b54fb Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 12 May 2025 14:26:48 -0600 Subject: [PATCH 07/25] Add logging of groom and optimize parameters to file log --- Libs/Analyze/MeshGenerator.cpp | 2 ++ Libs/Groom/GroomParameters.h | 3 ++- Libs/Image/ImageUtils.cpp | 17 +++++++++++++++++ Libs/Image/ImageUtils.h | 3 +++ Libs/Optimize/OptimizeParameters.cpp | 3 +++ Libs/Optimize/OptimizeParameters.h | 2 ++ Studio/Groom/GroomTool.cpp | 12 ++++++++++++ 7 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Libs/Analyze/MeshGenerator.cpp b/Libs/Analyze/MeshGenerator.cpp index 06566ff98e2..cf9d76330eb 100644 --- a/Libs/Analyze/MeshGenerator.cpp +++ b/Libs/Analyze/MeshGenerator.cpp @@ -165,6 +165,8 @@ MeshHandle MeshGenerator::build_mesh_from_file(std::string filename, float iso_v } } else if (is_image) { try { + ImageUtils::register_itk_factories(); + // read file using ITK using ReaderType = itk::ImageFileReader; ReaderType::Pointer reader = ReaderType::New(); diff --git a/Libs/Groom/GroomParameters.h b/Libs/Groom/GroomParameters.h index a1eed6498ac..6161840de30 100644 --- a/Libs/Groom/GroomParameters.h +++ b/Libs/Groom/GroomParameters.h @@ -137,7 +137,6 @@ class GroomParameters { bool get_skip_grooming(); void set_skip_grooming(bool skip); - bool get_shared_boundary(); void set_shared_boundary(bool shared_boundary); @@ -152,6 +151,8 @@ class GroomParameters { void restore_defaults(); + Parameters get_parameters() const { return params_; } + // constants const static std::string GROOM_SMOOTH_VTK_LAPLACIAN_C; const static std::string GROOM_SMOOTH_VTK_WINDOWED_SINC_C; diff --git a/Libs/Image/ImageUtils.cpp b/Libs/Image/ImageUtils.cpp index c272c1fe60e..09c23e4d9d1 100644 --- a/Libs/Image/ImageUtils.cpp +++ b/Libs/Image/ImageUtils.cpp @@ -2,6 +2,11 @@ #include +// ITK image factories +#include +#include +#include + namespace shapeworks { PhysicalRegion ImageUtils::boundingBox(const std::vector& filenames, Image::PixelType isoValue) { @@ -39,6 +44,18 @@ PhysicalRegion ImageUtils::boundingBox(const std::vector; static TPSTransform::Pointer createWarpTransform(const std::string& source_landmarks_file, const std::string& target_landmarks_file, const int stride = 1); + + static void register_itk_factories(); + }; } // namespace shapeworks diff --git a/Libs/Optimize/OptimizeParameters.cpp b/Libs/Optimize/OptimizeParameters.cpp index d7f87860027..3c1a70d28cd 100644 --- a/Libs/Optimize/OptimizeParameters.cpp +++ b/Libs/Optimize/OptimizeParameters.cpp @@ -864,3 +864,6 @@ double OptimizeParameters::get_shared_boundary_weight() { return params_.get(Key //--------------------------------------------------------------------------- void OptimizeParameters::set_shared_boundary_weight(double value) { params_.set(Keys::shared_boundary_weight, value); } + +//--------------------------------------------------------------------------- +Parameters OptimizeParameters::get_parameters() const { return params_; } diff --git a/Libs/Optimize/OptimizeParameters.h b/Libs/Optimize/OptimizeParameters.h index 6e37f063b75..ffc85bbf9f8 100644 --- a/Libs/Optimize/OptimizeParameters.h +++ b/Libs/Optimize/OptimizeParameters.h @@ -138,6 +138,8 @@ class OptimizeParameters { double get_shared_boundary_weight(); void set_shared_boundary_weight(double value); + Parameters get_parameters() const; + private: std::string get_output_prefix(); diff --git a/Studio/Groom/GroomTool.cpp b/Studio/Groom/GroomTool.cpp index 9396a7d89b3..aca6c9f2fd2 100644 --- a/Studio/Groom/GroomTool.cpp +++ b/Studio/Groom/GroomTool.cpp @@ -591,6 +591,18 @@ void GroomTool::on_run_groom_button_clicked() { timer_.start(); SW_LOG("Please wait: running groom step..."); + + // log parameters + SW_LOG_ONLY("Grooming parameters:"); + + for (const auto& domain_name : session_->get_project()->get_domain_names()) { + auto params = GroomParameters(session_->get_project(), domain_name); + SW_LOG_ONLY("Domain: " + domain_name); + for (const auto& pair : params.get_parameters().get_map()) { + SW_LOG_ONLY(pair.first + ": " + pair.second); + } + } + Q_EMIT progress(0); groom_ = QSharedPointer(new Groom(session_->get_project())); From 467df40e6c8b5fd7479d8e67156219dc6b4484ac Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 12 May 2025 14:27:08 -0600 Subject: [PATCH 08/25] Add logging of groom and optimize parameters to file log. Fix itk image factory registration --- Libs/Image/Image.cpp | 20 +------------------- Studio/Optimize/OptimizeTool.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/Libs/Image/Image.cpp b/Libs/Image/Image.cpp index 2560d83731b..5d54699acfc 100644 --- a/Libs/Image/Image.cpp +++ b/Libs/Image/Image.cpp @@ -44,26 +44,8 @@ #include "ShapeworksUtils.h" #include "itkTPGACLevelSetImageFilter.h" // actually a shapeworks class, not itk -// ITK image factories -#include -#include -#include - namespace shapeworks { -namespace { -void register_factories() { - static bool registered = false; - if (!registered) { - // register all the factories - itk::NrrdImageIOFactory::RegisterOneFactory(); - itk::NiftiImageIOFactory::RegisterOneFactory(); - itk::MetaImageIOFactory::RegisterOneFactory(); - registered = true; - } -} -} // namespace - Image::Image(const Dims dims) : itk_image_(ImageType::New()) { ImageType::RegionType region; region.SetSize(dims); @@ -119,7 +101,7 @@ Image& Image::operator=(Image&& img) { } Image::ImageType::Pointer Image::read(const std::string& pathname) { - register_factories(); + ImageUtils::register_itk_factories(); if (pathname.empty()) { throw std::invalid_argument("Empty pathname"); diff --git a/Studio/Optimize/OptimizeTool.cpp b/Studio/Optimize/OptimizeTool.cpp index c5225f36399..19df1af12e2 100644 --- a/Studio/Optimize/OptimizeTool.cpp +++ b/Studio/Optimize/OptimizeTool.cpp @@ -222,6 +222,12 @@ void OptimizeTool::on_run_optimize_button_clicked() { optimize_parameters_->set_load_callback(std::bind(&OptimizeTool::handle_load_progress, this, std::placeholders::_1)); optimize_->SetFileOutputEnabled(false); + // log parameters + SW_LOG_ONLY("Optimization parameters:"); + for (const auto& pair : optimize_parameters_->get_parameters().get_map()) { + SW_LOG_ONLY(pair.first + ": " + pair.second); + } + ShapeworksWorker* worker = new ShapeworksWorker(ShapeworksWorker::OptimizeType, NULL, optimize_, optimize_parameters_, session_); QThread* thread = new QThread; From 9d1d88cb37de683fe9e9feff58ca1eb0e7a5492c Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 12 May 2025 14:27:28 -0600 Subject: [PATCH 09/25] Auto adjust network analysis alpha when necessary. --- Python/shapeworks/shapeworks/network_analysis.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Python/shapeworks/shapeworks/network_analysis.py b/Python/shapeworks/shapeworks/network_analysis.py index fc61d7af4f5..d5d926ba3db 100644 --- a/Python/shapeworks/shapeworks/network_analysis.py +++ b/Python/shapeworks/shapeworks/network_analysis.py @@ -297,7 +297,12 @@ def run(self): snpm = spm1d.stats.nonparam.ttest2( np.transpose(all_data[:, :, np.where(grouprs == 0)[0], :].reshape(num_pts, len(np.where(grouprs == 0)[0]))), np.transpose(all_data[:, :, np.where(grouprs == 1)[0], :].reshape(num_pts, len(np.where(grouprs == 1)[0])))) - snpmi = snpm.inference(0.05, two_tailed=True, iterations=n_iter, force_iterations=True) # assume one-sided + + alpha = 0.05 + # Specified alpha must be greater than or equal to (1/nPermTotal)=0.33333 + if (alpha < 1/n_iter): + alpha = 1/n_iter + snpmi = snpm.inference(alpha, two_tailed=True, iterations=n_iter, force_iterations=True) # assume one-sided Z = snpmi.z # flattened test statistic (i.e., t value) over only non-zero-variance nodes tradzstar = snpmi.zstar # critical test statistic (i.e., critical t value) From 9cc69afe598fadccc655490b18e4a1593a75fd18 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 12 May 2025 14:28:03 -0600 Subject: [PATCH 10/25] Set version to 6.6.1_RC1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a76740015d2..2fb9ce4b150 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ cmake_minimum_required(VERSION 3.20) ########################################### SET(SHAPEWORKS_MAJOR_VERSION 6 CACHE INTERNAL "Major version number" FORCE) SET(SHAPEWORKS_MINOR_VERSION 6 CACHE INTERNAL "Minor version number" FORCE) -SET(SHAPEWORKS_PATCH_VERSION 0 CACHE INTERNAL "Patch version number" FORCE) -SET(SHAPEWORKS_VERSION_STRING "6.6.0") +SET(SHAPEWORKS_PATCH_VERSION 1 CACHE INTERNAL "Patch version number" FORCE) +SET(SHAPEWORKS_VERSION_STRING "6.6.1_RC1") SET(SHAPEWORKS_VERSION "${SHAPEWORKS_MAJOR_VERSION}.${SHAPEWORKS_MINOR_VERSION}.${SHAPEWORKS_PATCH_VERSION}") # First, check that files were checked out properly using git-lfs From f4dd2ce9ebb0d24d012c2e3faced8c12f69c3273 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 13 May 2025 08:32:59 -0600 Subject: [PATCH 11/25] Disallow network analysis when there are no scalar features. --- Studio/Analysis/AnalysisTool.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp index 474453e8fb6..b2ba878125e 100644 --- a/Studio/Analysis/AnalysisTool.cpp +++ b/Studio/Analysis/AnalysisTool.cpp @@ -519,6 +519,11 @@ void AnalysisTool::group_p_values_clicked() { //--------------------------------------------------------------------------- void AnalysisTool::network_analysis_clicked() { + if (ui_->network_feature->currentText().isEmpty()) { + QMessageBox::warning(this, "Network Analysis", "Project must have a scalar feature for network analysis."); + //SW_WARN("Project must have a scalar features for network analysis"); + return; + } network_analysis_job_ = QSharedPointer::create(session_->get_project(), ui_->group_combo->currentText().toStdString(), ui_->network_feature->currentText().toStdString()); From a14bda333bfd16f7587569fde2b0b7a2514a18e6 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 13 May 2025 08:33:16 -0600 Subject: [PATCH 12/25] Turn off group animate checkbox when deactivating analysis. --- Studio/Analysis/AnalysisTool.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp index b2ba878125e..ebea0a249f7 100644 --- a/Studio/Analysis/AnalysisTool.cpp +++ b/Studio/Analysis/AnalysisTool.cpp @@ -380,6 +380,7 @@ void AnalysisTool::handle_analysis_options() { ui_->pcaAnimateCheckBox->setEnabled(false); ui_->pcaModeSpinBox->setEnabled(false); pca_animate_timer_.stop(); + group_animate_timer_.stop(); ui_->pcaSlider->setEnabled(false); if (ui_->singleSamplesRadio->isChecked()) { // one sample mode @@ -406,6 +407,7 @@ void AnalysisTool::handle_analysis_options() { ui_->pcaSlider->setEnabled(true); ui_->pcaAnimateCheckBox->setEnabled(true); ui_->pcaModeSpinBox->setEnabled(true); + group_animate_timer_.stop(); auto domain_names = session_->get_project()->get_domain_names(); bool multiple_domains = domain_names.size() > 1; if (multiple_domains) { @@ -422,6 +424,7 @@ void AnalysisTool::handle_analysis_options() { ui_->pcaAnimateCheckBox->setEnabled(false); ui_->pcaModeSpinBox->setEnabled(false); pca_animate_timer_.stop(); + group_animate_timer_.stop(); } update_difference_particles(); @@ -930,6 +933,7 @@ void AnalysisTool::store_settings() { //--------------------------------------------------------------------------- void AnalysisTool::shutdown() { pca_animate_timer_.stop(); + group_animate_timer_.stop(); for (const auto& worker : workers_) { if (worker) { @@ -2111,7 +2115,9 @@ void AnalysisTool::reconstruction_method_changed() { void AnalysisTool::set_active(bool active) { if (!active) { ui_->pcaAnimateCheckBox->setChecked(false); + ui_->group_animate_checkbox->setChecked(false); pca_animate_timer_.stop(); + group_animate_timer_.stop(); } else { auto features = session_->get_project()->get_feature_names(); ui_->network_feature->clear(); From 970fe16f737d91c9134cfc744fa4858ceacc68cb Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 13 May 2025 09:30:12 -0600 Subject: [PATCH 13/25] Fix crash when mesh worker runs and there are no items in the queue. This can happen when changing projects (e.g. loading another project while meshes are being created) --- Libs/Analyze/MeshWorker.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Libs/Analyze/MeshWorker.cpp b/Libs/Analyze/MeshWorker.cpp index 5832e2a7fa1..83c98e1cac2 100644 --- a/Libs/Analyze/MeshWorker.cpp +++ b/Libs/Analyze/MeshWorker.cpp @@ -19,6 +19,9 @@ void MeshWorker::run() { // build the mesh using our MeshGenerator auto item = this->queue_->get_next_work_item(); + if (!item) { + return; + } MeshHandle mesh = this->mesh_generator_->build_mesh(*item); From 55305e5b2a424cc8d5431e9c24a7866790138412 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 13 May 2025 10:25:33 -0600 Subject: [PATCH 14/25] Try fixing occasional unexplained crash regarding Apple Silicon Qt/Cursors: Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 ??? 0xbad4007 ??? 1 ImageIO 0x1a0c235f0 IIOReadPlugin::callInitialize() + 388 2 ImageIO 0x1a0c233b8 IIO_Reader::initImageAtOffset(CGImagePlugin, unsigned long, unsigned long, unsigned long) + 128 3 ImageIO 0x1a0c20d58 IIOImageSource::makeImagePlus(unsigned long, IIODictionary) + 816 4 ImageIO 0x1a0c819d8 IIOImageSource::createImageAtIndex(unsigned long, IIODictionary, int) + 108 5 ImageIO 0x1a0c2d2d8 CGImageSourceCreateImageAtIndex + 332 6 HIServices 0x19c59af8c setCursorFromBundle + 1560 7 HIServices 0x19c59a234 CoreCursorSetAndReturnSeed + 204 8 AppKit 0x199b30618 -[NSCursor _reallySet] + 612 9 AppKit 0x199b374e0 +[NSCursor _setOverrideCursor:type:] + 264 10 AppKit 0x199b36da4 -[NSWindow(NSWindowResizing) _edgeResizingCursorUpdate:atLocation:] + 208 11 AppKit 0x199b79e0c -[NSThemeFrame mouseEntered:] + 64 12 AppKit 0x199b79d60 -[NSTrackingArea _dispatchMouseEntered:] + 124 13 AppKit 0x19a0d6ff0 -[_NSTrackingAreaAKManager _routeEnterExitEvent:] + 640 14 AppKit 0x19a0d71c4 -[_NSTrackingAreaAKManager routeEnterExitEvent:] + 28 15 AppKit 0x199b0a47c -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 152 16 AppKit 0x199b0a210 -[NSWindow(NSEventRouting) sendEvent:] + 284 17 libqcocoa.dylib 0x10ae5d150 0x10ae30000 + 184656 18 AppKit 0x19a0a3100 +[_NSTrackingAreaManager routeEnterExitEvent:] + 244 19 AppKit 0x19a1d3018 -[NSApplication(NSEventRouting) sendEvent:] + 364 20 libqcocoa.dylib 0x10ae62050 0x10ae30000 + 204880 21 AppKit 0x199e21998 33-[NSApplication runModalSession:]_block_invoke_2 + 88 22 AppKit 0x199e21924 33-[NSApplication runModalSession:]_block_invoke + 112 23 AppKit 0x199c0f6b0 _NSTryRunModal + 100 24 AppKit 0x199e217f4 -[NSApplication runModalSession:] + 148 25 libqcocoa.dylib 0x10ae5f3b4 0x10ae30000 + 193460 26 dyld 0x195d13154 start + 2476 --- Studio/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Studio/main.cpp b/Studio/main.cpp index f391712c7c9..d11ed62e829 100644 --- a/Studio/main.cpp +++ b/Studio/main.cpp @@ -26,6 +26,7 @@ using namespace shapeworks; +//--------------------------------------------------------------------------- class OverrideQApplication : public QApplication { public: OverrideQApplication(int& argc, char** argv) : QApplication(argc, argv) {} @@ -47,6 +48,7 @@ class OverrideQApplication : public QApplication { QString stored_filename_; }; +//--------------------------------------------------------------------------- static void new_log() { QDateTime date_time = QDateTime::currentDateTime(); QString session_name = date_time.toString("yyyy-MM-dd_HH_mm_ss"); @@ -71,10 +73,17 @@ static void new_log() { Logging::Instance().open_file_log(logfile.toStdString()); } +//--------------------------------------------------------------------------- int main(int argc, char** argv) { // tbb::task_scheduler_init init(1); try { + +#ifdef Q_OS_MACOS + // Prevent cursor crashes on Apple Silicon + qputenv("QT_MAC_DISABLE_NATIVE_CURSORS", "1"); +#endif + // needed to ensure appropriate OpenGL context is created for VTK rendering. QSurfaceFormat format = QVTKOpenGLNativeWidget::defaultFormat(); #ifdef _WIN32 From 62f863fd962b25e256b178a4533d343e5140b5e2 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 13 May 2025 10:27:55 -0600 Subject: [PATCH 15/25] Add lock to prevent reference mesh changing while mesh warp is taking place --- Libs/Mesh/MeshWarper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Libs/Mesh/MeshWarper.cpp b/Libs/Mesh/MeshWarper.cpp index dac711b0b2d..f6eed42654d 100644 --- a/Libs/Mesh/MeshWarper.cpp +++ b/Libs/Mesh/MeshWarper.cpp @@ -56,6 +56,9 @@ vtkSmartPointer MeshWarper::build_mesh(const Eigen::MatrixXd& parti //--------------------------------------------------------------------------- void MeshWarper::set_reference_mesh(vtkSmartPointer reference_mesh, const Eigen::MatrixXd& reference_particles, const Eigen::MatrixXd& landmarks) { + // lock so that we don't swap out the reference mesh while we are using it + std::scoped_lock lock(mutex); + if (this->incoming_reference_mesh_ == reference_mesh) { if (this->reference_particles_.size() == reference_particles.size()) { if (this->reference_particles_ == reference_particles && landmarks_points_ == landmarks) { From 7c644aff89fe59124edb0e440a896b5807e5c169 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 13 May 2025 10:28:10 -0600 Subject: [PATCH 16/25] Make sure stats are recomputed when groups change. --- Studio/Analysis/AnalysisTool.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp index ebea0a249f7..8b41e1cb358 100644 --- a/Studio/Analysis/AnalysisTool.cpp +++ b/Studio/Analysis/AnalysisTool.cpp @@ -524,7 +524,7 @@ void AnalysisTool::group_p_values_clicked() { void AnalysisTool::network_analysis_clicked() { if (ui_->network_feature->currentText().isEmpty()) { QMessageBox::warning(this, "Network Analysis", "Project must have a scalar feature for network analysis."); - //SW_WARN("Project must have a scalar features for network analysis"); + // SW_WARN("Project must have a scalar features for network analysis"); return; } network_analysis_job_ = @@ -610,6 +610,7 @@ bool AnalysisTool::compute_stats() { if (particles.size() == 0) { continue; // skip any that don't have particles } + if (groups_active()) { auto group = shape->get_subject()->get_group_value(group_set); if (group == left_group) { @@ -1461,6 +1462,8 @@ void AnalysisTool::update_group_boxes() { //--------------------------------------------------------------------------- void AnalysisTool::update_group_values() { block_group_change_ = true; + stats_ready_ = false; + auto values = session_->get_project()->get_group_values(ui_->group_combo->currentText().toStdString()); if (values != current_group_values_) { From 5632974903fcef0b00140ca0b08830d2b3341c61 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 13 May 2025 10:43:31 -0600 Subject: [PATCH 17/25] Reset PCA and Group sliders --- Studio/Analysis/AnalysisTool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp index 8b41e1cb358..90aa126b183 100644 --- a/Studio/Analysis/AnalysisTool.cpp +++ b/Studio/Analysis/AnalysisTool.cpp @@ -345,6 +345,8 @@ void AnalysisTool::set_session(QSharedPointer session) { ui_->group1_button->setChecked(false); ui_->group2_button->setChecked(false); update_difference_particles(); + ui_->pcaSlider->setValue(0); + ui_->group_slider->setValue(10); ui_->show_predicted_scalar->setChecked(false); ui_->show_difference_to_predicted_scalar->setChecked(false); From e52425fc92eb8ff557ace525ca4f3d19d62b9ece Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Thu, 15 May 2025 10:15:21 -0600 Subject: [PATCH 18/25] Fix binarization for segmentations not using 0-1 --- Libs/Analyze/MeshGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Libs/Analyze/MeshGenerator.cpp b/Libs/Analyze/MeshGenerator.cpp index cf9d76330eb..4820eea9ab1 100644 --- a/Libs/Analyze/MeshGenerator.cpp +++ b/Libs/Analyze/MeshGenerator.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -16,7 +17,6 @@ #include #include -#include namespace shapeworks { @@ -101,7 +101,7 @@ MeshHandle MeshGenerator::build_mesh_from_image(ImageType::Pointer image, float // only interested in 1's and 0's Image itk_image = Image(image); if (!itk_image.isDistanceTransform()) { - itk_image.binarize(0, 1); + itk_image.binarize(); image = itk_image.getITKImage(); } From 58f208e3d5de9fca5b8bd7f784c5f08b209231c3 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Thu, 15 May 2025 10:15:35 -0600 Subject: [PATCH 19/25] Add padding to fix segmentations on the edges (studio display) --- Libs/Analyze/MeshGenerator.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Libs/Analyze/MeshGenerator.cpp b/Libs/Analyze/MeshGenerator.cpp index 4820eea9ab1..e220e8197cf 100644 --- a/Libs/Analyze/MeshGenerator.cpp +++ b/Libs/Analyze/MeshGenerator.cpp @@ -105,6 +105,20 @@ MeshHandle MeshGenerator::build_mesh_from_image(ImageType::Pointer image, float image = itk_image.getITKImage(); } + // first, pad the image in case the segmentation is on the edge + using PadFilterType = itk::ConstantPadImageFilter; + PadFilterType::Pointer pad = PadFilterType::New(); + ImageType::SizeType lower_extend_region; + ImageType::SizeType upper_extend_region; + lower_extend_region.Fill(10); + upper_extend_region.Fill(10); + pad->SetInput(image); + pad->SetPadLowerBound(lower_extend_region); + pad->SetPadUpperBound(upper_extend_region); + pad->SetConstant(0); // set to background value + pad->Update(); + image = pad->GetOutput(); + // connect to VTK vtkSmartPointer vtk_image = vtkSmartPointer::New(); itk::VTKImageExport::Pointer itk_exporter = itk::VTKImageExport::New(); From 5cc2ae9bd453cb10e337104a582ceee1f60f2823 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Thu, 15 May 2025 10:22:09 -0600 Subject: [PATCH 20/25] Use SW Image pad instead. --- Libs/Analyze/MeshGenerator.cpp | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/Libs/Analyze/MeshGenerator.cpp b/Libs/Analyze/MeshGenerator.cpp index e220e8197cf..85a0b084dd9 100644 --- a/Libs/Analyze/MeshGenerator.cpp +++ b/Libs/Analyze/MeshGenerator.cpp @@ -99,25 +99,15 @@ MeshHandle MeshGenerator::build_mesh_from_image(ImageType::Pointer image, float try { // only interested in 1's and 0's - Image itk_image = Image(image); - if (!itk_image.isDistanceTransform()) { - itk_image.binarize(); - image = itk_image.getITKImage(); + Image sw_image = Image(image); + if (!sw_image.isDistanceTransform()) { + sw_image.binarize(); + image = sw_image.getITKImage(); } - // first, pad the image in case the segmentation is on the edge - using PadFilterType = itk::ConstantPadImageFilter; - PadFilterType::Pointer pad = PadFilterType::New(); - ImageType::SizeType lower_extend_region; - ImageType::SizeType upper_extend_region; - lower_extend_region.Fill(10); - upper_extend_region.Fill(10); - pad->SetInput(image); - pad->SetPadLowerBound(lower_extend_region); - pad->SetPadUpperBound(upper_extend_region); - pad->SetConstant(0); // set to background value - pad->Update(); - image = pad->GetOutput(); + // pad the image in case the segmentation is on the edge + sw_image.pad(1); + image = sw_image.getITKImage(); // connect to VTK vtkSmartPointer vtk_image = vtkSmartPointer::New(); From 47ab31a8b2ad8ae7cd7835f7e344a748a88d4c99 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Thu, 15 May 2025 10:35:28 -0600 Subject: [PATCH 21/25] Set camera on loading images from CLI --- Studio/Interface/ShapeWorksStudioApp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Studio/Interface/ShapeWorksStudioApp.cpp b/Studio/Interface/ShapeWorksStudioApp.cpp index 9919b34536a..771c390d3d5 100644 --- a/Studio/Interface/ShapeWorksStudioApp.cpp +++ b/Studio/Interface/ShapeWorksStudioApp.cpp @@ -442,6 +442,9 @@ void ShapeWorksStudioApp::import_files(QStringList file_names) { } catch (std::runtime_error& e) { handle_error(e.what()); } + + visualizer_->reset_camera(); + handle_message("Files loaded"); handle_progress(100); } From 363b6f2c5412b8a13062d94deb31c2436f9fa9c9 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Thu, 15 May 2025 10:35:57 -0600 Subject: [PATCH 22/25] Set version to 6.6.1_RC2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fb9ce4b150..890bb2e5720 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.20) SET(SHAPEWORKS_MAJOR_VERSION 6 CACHE INTERNAL "Major version number" FORCE) SET(SHAPEWORKS_MINOR_VERSION 6 CACHE INTERNAL "Minor version number" FORCE) SET(SHAPEWORKS_PATCH_VERSION 1 CACHE INTERNAL "Patch version number" FORCE) -SET(SHAPEWORKS_VERSION_STRING "6.6.1_RC1") +SET(SHAPEWORKS_VERSION_STRING "6.6.1_RC2") SET(SHAPEWORKS_VERSION "${SHAPEWORKS_MAJOR_VERSION}.${SHAPEWORKS_MINOR_VERSION}.${SHAPEWORKS_PATCH_VERSION}") # First, check that files were checked out properly using git-lfs From bd62acb45b9c70019d378ad9bd737cccb16f3dc0 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Fri, 16 May 2025 16:22:15 -0600 Subject: [PATCH 23/25] Add Blue/Red colormap --- Studio/Visualization/ColorMap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Studio/Visualization/ColorMap.cpp b/Studio/Visualization/ColorMap.cpp index bf0b41de748..d3421d7de66 100644 --- a/Studio/Visualization/ColorMap.cpp +++ b/Studio/Visualization/ColorMap.cpp @@ -59,7 +59,7 @@ ColorMaps::ColorMaps() { add_custom_series("Rainbow", {Qt::blue, Qt::cyan, Qt::green, Qt::yellow, Qt::red}); add_custom_series("Grayscale", {Qt::black, Qt::darkGray, Qt::lightGray, Qt::white}); - add_custom_series("Blue to Red", {Qt::blue, Qt::white, Qt::red}); + add_custom_series("Blue White Red", {Qt::blue, Qt::white, Qt::red}); add_custom_series("Magenta to Green", {QColor(191, 53, 136), QColor(208, 121, 178), Qt::white, QColor(155, 196, 128), QColor(102, 167, 61)}); add_custom_series("Black-Body Radiation", {Qt::black, Qt::red, Qt::yellow, Qt::white}); @@ -78,6 +78,7 @@ ColorMaps::ColorMaps() { for (int i = vtkColorSeries::SPECTRUM; i < vtkColorSeries::CUSTOM; i++) { add_vtk_series(i); } + add_custom_series("Blue and Red", {Qt::blue, Qt::red}); } } // namespace shapeworks From 45de457f2ea5556be215929a264c02ab457bcd6f Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Fri, 16 May 2025 16:29:54 -0600 Subject: [PATCH 24/25] Update release notes for 6.6.1 --- docs/about/release-notes.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md index 4283db60158..7005c46f8fe 100644 --- a/docs/about/release-notes.md +++ b/docs/about/release-notes.md @@ -1,6 +1,25 @@ # Release Notes -## ShapeWorks 6.6.0 - 2025-03 + +## ShapeWorks 6.6.1 - 2025-05 + +### Fixes + * Fix loading of non-binary segmentations + * Add padding for visualization of segmentation surfaces + * Add Blue/Red color map for scalar visualization + * Fix PCA/Group sliders when switching projects + * Fix stats being reloaded when groups are changed + * Fix a crash that can happen when changing projects while mesh warping + * Turn off group animate checkbox when deactivating analysis module + * Disallow network analysis when there are no scalar features + * Auto adjust network analysis alpha when necessary + * Add logging of groom and optimize parameters to file log + * Fix itk image factory registration for network analysis with image based features + * Added warning about inconsistent number of values in particle vector + * Fix libomp.dylib install problem on mac arm64 + * Update URL for UpdateChecker + +## ShapeWorks 6.6.0 - 2025-05 ![](../img/about/release6.6.png) From b46d4be21ef7c03c7e01215f37c0c1157e72ac7c Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 19 May 2025 08:48:47 -0600 Subject: [PATCH 25/25] Set version to 6.6.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 890bb2e5720..f442410df7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.20) SET(SHAPEWORKS_MAJOR_VERSION 6 CACHE INTERNAL "Major version number" FORCE) SET(SHAPEWORKS_MINOR_VERSION 6 CACHE INTERNAL "Minor version number" FORCE) SET(SHAPEWORKS_PATCH_VERSION 1 CACHE INTERNAL "Patch version number" FORCE) -SET(SHAPEWORKS_VERSION_STRING "6.6.1_RC2") +SET(SHAPEWORKS_VERSION_STRING "6.6.1") SET(SHAPEWORKS_VERSION "${SHAPEWORKS_MAJOR_VERSION}.${SHAPEWORKS_MINOR_VERSION}.${SHAPEWORKS_PATCH_VERSION}") # First, check that files were checked out properly using git-lfs