Skip to content

Commit 37a6358

Browse files
authored
Merge pull request #2413 from SCIInstitute/multiple_shared_boundary
Add support for multiple shared boundaries
2 parents c2f00c9 + 7b9b565 commit 37a6358

File tree

27 files changed

+1062
-443
lines changed

27 files changed

+1062
-443
lines changed

Libs/Analyze/Shape.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ MeshGroup Shape::get_original_meshes(bool wait) {
100100
return original_meshes_;
101101
}
102102

103-
if (!original_meshes_.valid() || original_meshes_.meshes().size() != subject_->get_number_of_domains()) {
103+
if (!original_meshes_.valid() || original_meshes_.meshes().size() != subject_->get_original_filenames().size()) {
104104
original_meshes_ = MeshGroup(subject_->get_number_of_domains());
105105
generate_meshes(subject_->get_original_filenames(), original_meshes_, true, wait);
106106
}

Libs/Common/Logging.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,13 @@ void Logging::log_message(const std::string& message, const int line, const char
7070
}
7171

7272
//-----------------------------------------------------------------------------
73-
void Logging::log_only(const std::string& message, const int line, const char* file) const {
73+
void Logging::log_only(const std::string& message, const int line, const char* file, const char* function) const {
74+
if (spd::get_level() == spd::level::debug) {
75+
// when in debug mode, treat this as a debug message
76+
log_debug(message, line, file, function);
77+
return;
78+
}
79+
7480
spd::info(message);
7581
if (log_open_) {
7682
spd::get("file")->info(message);

Libs/Common/Logging.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class Logging {
103103
void log_message(const std::string& message, const int line, const char* file) const;
104104

105105
//! Log a message, use SW_LOG_ONLY macro
106-
void log_only(const std::string& message, const int line, const char* file) const;
106+
void log_only(const std::string& message, const int line, const char* file, const char *function) const;
107107

108108
//! Log a stack trace message, use SW_LOG_STACK macro
109109
void log_stack(const std::string& message) const;
@@ -176,7 +176,7 @@ class Logging {
176176

177177
//! Log only macro
178178
#define SW_LOG_ONLY(message, ...) \
179-
shapeworks::Logging::Instance().log_only(safe_format(message, ##__VA_ARGS__), __LINE__, __FILE__);
179+
shapeworks::Logging::Instance().log_only(safe_format(message, ##__VA_ARGS__), __LINE__, __FILE__, __FUNCTION__);
180180

181181
//! Log warning macro
182182
#define SW_WARN(message, ...) \

Libs/Groom/Groom.cpp

Lines changed: 326 additions & 108 deletions
Large diffs are not rendered by default.

Libs/Groom/Groom.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class Groom {
3939
std::atomic<int> progress_counter_ = 0;
4040

4141
private:
42+
enum class MeshSource { Original, Groomed };
43+
4244
//! Return the number of operations that will be performed
4345
int get_total_ops();
4446

@@ -66,6 +68,9 @@ class Groom {
6668
//! Create shared boundary surface and contour if requested
6769
bool run_shared_boundaries();
6870

71+
//! Remove all shared boundaries
72+
void clear_unused_shared_boundaries();
73+
6974
void assign_transforms(std::vector<std::vector<double>> transforms, int domain, bool global = false);
7075

7176
static std::vector<std::vector<double>> get_icp_transforms(const std::vector<Mesh> meshes, Mesh reference);
@@ -80,7 +85,8 @@ class Groom {
8085

8186
std::vector<vtkSmartPointer<vtkPoints>> get_combined_points();
8287

83-
Mesh get_mesh(int subject, int domain, bool transformed = false);
88+
Mesh get_mesh(int subject, int domain, bool transformed = false, MeshSource source = MeshSource::Original);
89+
8490

8591
vtkSmartPointer<vtkPoints> get_landmarks(int subject, int domain);
8692

Libs/Groom/GroomParameters.cpp

Lines changed: 147 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const std::string SHARED_BOUNDARY = "shared_boundary";
6262
const std::string SHARED_BOUNDARY_FIRST_DOMAIN = "shared_boundary_first_domain";
6363
const std::string SHARED_BOUNDARY_SECOND_DOMAIN = "shared_boundary_second_domain";
6464
const std::string SHARED_BOUNDARY_TOLERANCE = "shared_boundary_tolerance";
65+
const std::string SHARED_BOUNDARIES = "shared_boundaries";
6566

6667
} // namespace Keys
6768

@@ -107,59 +108,90 @@ const bool shared_boundary = false;
107108
const std::string shared_boundary_first_domain = "";
108109
const std::string shared_boundary_second_domain = "";
109110
const double shared_boundary_tolerance = 1e-1;
111+
const std::string shared_boundaries = ""; // Empty string = no boundaries
110112

111113
} // namespace Defaults
112114

115+
// Helper methods for SharedBoundary struct
116+
//---------------------------------------------------------------------------
117+
std::string GroomParameters::SharedBoundary::to_string() const {
118+
return first_domain + "|" + second_domain + "|" + std::to_string(tolerance);
119+
}
120+
121+
//---------------------------------------------------------------------------
122+
GroomParameters::SharedBoundary GroomParameters::SharedBoundary::from_string(const std::string& str) {
123+
std::vector<std::string> parts;
124+
std::stringstream ss(str);
125+
std::string item;
126+
127+
while (std::getline(ss, item, '|')) {
128+
parts.push_back(item);
129+
}
130+
131+
if (parts.size() != 3) {
132+
throw std::runtime_error("Invalid shared boundary string format");
133+
}
134+
135+
SharedBoundary boundary;
136+
boundary.first_domain = parts[0];
137+
boundary.second_domain = parts[1];
138+
boundary.tolerance = std::stod(parts[2]);
139+
return boundary;
140+
}
141+
113142
//---------------------------------------------------------------------------
114143
GroomParameters::GroomParameters(ProjectHandle project, std::string domain_name)
115144
: project_(project), domain_name_(domain_name) {
116145
params_ = project_->get_parameters(Parameters::GROOM_PARAMS, domain_name_);
117146

118-
std::vector<std::string> all_params = {Keys::CROP,
119-
Keys::REFLECT,
120-
Keys::REFLECT_COLUMN,
121-
Keys::REFLECT_CHOICE,
122-
Keys::REFLECT_AXIS,
123-
Keys::RESAMPLE,
124-
Keys::ISOTROPIC,
125-
Keys::ISO_SPACING,
126-
Keys::SPACING,
127-
Keys::CONVERT_MESH,
128-
Keys::FILL_MESH_HOLES,
129-
Keys::FILL_HOLES,
130-
Keys::ISOLATE,
131-
Keys::PAD,
132-
Keys::PAD_VALUE,
133-
Keys::ANTIALIAS,
134-
Keys::ANTIALIAS_AMOUNT,
135-
Keys::BLUR,
136-
Keys::BLUR_SIGMA,
137-
Keys::FASTMARCHING,
138-
Keys::MESH_SMOOTH,
139-
Keys::MESH_SMOOTHING_METHOD,
140-
Keys::MESH_SMOOTHING_VTK_LAPLACIAN_ITERATIONS,
141-
Keys::MESH_SMOOTHING_VTK_LAPLACIAN_RELAXATION,
142-
Keys::MESH_SMOOTHING_VTK_WINDOWED_SINC_ITERATIONS,
143-
Keys::MESH_SMOOTHING_VTK_WINDOWED_SINC_PASSBAND,
144-
Keys::ALIGNMENT_METHOD,
145-
Keys::ALIGNMENT_ENABLED,
146-
Keys::ALIGNMENT_REFERENCE,
147-
Keys::ALIGNMENT_REFERENCE_CHOSEN,
148-
Keys::ALIGNMENT_SUBSET_SIZE,
149-
Keys::GROOM_OUTPUT_PREFIX,
150-
Keys::REMESH,
151-
Keys::REMESH_PERCENT_MODE,
152-
Keys::REMESH_PERCENT,
153-
Keys::REMESH_NUM_VERTICES,
154-
Keys::REMESH_GRADATION,
155-
Keys::GROOM_ALL_DOMAINS_THE_SAME,
156-
Keys::SKIP_GROOMING,
157-
Keys::CENTER,
158-
Keys::ICP,
159-
Keys::SHARED_BOUNDARY,
160-
Keys::SHARED_BOUNDARY_FIRST_DOMAIN,
161-
Keys::SHARED_BOUNDARY_SECOND_DOMAIN,
162-
Keys::SHARED_BOUNDARY_TOLERANCE};
147+
std::vector<std::string> all_params = {
148+
Keys::CROP,
149+
Keys::REFLECT,
150+
Keys::REFLECT_COLUMN,
151+
Keys::REFLECT_CHOICE,
152+
Keys::REFLECT_AXIS,
153+
Keys::RESAMPLE,
154+
Keys::ISOTROPIC,
155+
Keys::ISO_SPACING,
156+
Keys::SPACING,
157+
Keys::CONVERT_MESH,
158+
Keys::FILL_MESH_HOLES,
159+
Keys::FILL_HOLES,
160+
Keys::ISOLATE,
161+
Keys::PAD,
162+
Keys::PAD_VALUE,
163+
Keys::ANTIALIAS,
164+
Keys::ANTIALIAS_AMOUNT,
165+
Keys::BLUR,
166+
Keys::BLUR_SIGMA,
167+
Keys::FASTMARCHING,
168+
Keys::MESH_SMOOTH,
169+
Keys::MESH_SMOOTHING_METHOD,
170+
Keys::MESH_SMOOTHING_VTK_LAPLACIAN_ITERATIONS,
171+
Keys::MESH_SMOOTHING_VTK_LAPLACIAN_RELAXATION,
172+
Keys::MESH_SMOOTHING_VTK_WINDOWED_SINC_ITERATIONS,
173+
Keys::MESH_SMOOTHING_VTK_WINDOWED_SINC_PASSBAND,
174+
Keys::ALIGNMENT_METHOD,
175+
Keys::ALIGNMENT_ENABLED,
176+
Keys::ALIGNMENT_REFERENCE,
177+
Keys::ALIGNMENT_REFERENCE_CHOSEN,
178+
Keys::ALIGNMENT_SUBSET_SIZE,
179+
Keys::GROOM_OUTPUT_PREFIX,
180+
Keys::REMESH,
181+
Keys::REMESH_PERCENT_MODE,
182+
Keys::REMESH_PERCENT,
183+
Keys::REMESH_NUM_VERTICES,
184+
Keys::REMESH_GRADATION,
185+
Keys::GROOM_ALL_DOMAINS_THE_SAME,
186+
Keys::SKIP_GROOMING,
187+
Keys::CENTER,
188+
Keys::ICP,
189+
Keys::SHARED_BOUNDARY,
190+
Keys::SHARED_BOUNDARY_FIRST_DOMAIN,
191+
Keys::SHARED_BOUNDARY_SECOND_DOMAIN,
192+
Keys::SHARED_BOUNDARY_TOLERANCE,
193+
Keys::SHARED_BOUNDARIES,
194+
};
163195

164196
std::vector<std::string> to_remove;
165197

@@ -497,40 +529,93 @@ bool GroomParameters::get_skip_grooming() { return params_.get(Keys::SKIP_GROOMI
497529
void GroomParameters::set_skip_grooming(bool skip) { params_.set(Keys::SKIP_GROOMING, skip); }
498530

499531
//---------------------------------------------------------------------------
500-
bool GroomParameters::get_shared_boundary() { return params_.get(Keys::SHARED_BOUNDARY, Defaults::shared_boundary); }
532+
bool GroomParameters::get_shared_boundaries_enabled() {
533+
return params_.get(Keys::SHARED_BOUNDARY, Defaults::shared_boundary);
534+
}
501535

502536
//---------------------------------------------------------------------------
503-
void GroomParameters::set_shared_boundary(bool shared_boundary) { params_.set(Keys::SHARED_BOUNDARY, shared_boundary); }
537+
void GroomParameters::set_shared_boundaries_enabled(bool enabled) { params_.set(Keys::SHARED_BOUNDARY, enabled); }
504538

505539
//---------------------------------------------------------------------------
506-
std::string GroomParameters::get_shared_boundary_first_domain() {
507-
return params_.get(Keys::SHARED_BOUNDARY_FIRST_DOMAIN, Defaults::shared_boundary_first_domain);
508-
}
540+
std::vector<GroomParameters::SharedBoundary> GroomParameters::get_shared_boundaries() {
541+
std::vector<SharedBoundary> boundaries;
509542

510-
//---------------------------------------------------------------------------
511-
void GroomParameters::set_shared_boundary_first_domain(const std::string& domain_name) {
512-
params_.set(Keys::SHARED_BOUNDARY_FIRST_DOMAIN, domain_name);
543+
// Try new format first
544+
if (params_.key_exists(Keys::SHARED_BOUNDARIES)) {
545+
std::string boundaries_str = params_.get(Keys::SHARED_BOUNDARIES, Defaults::shared_boundaries);
546+
if (!boundaries_str.empty()) {
547+
std::stringstream ss(boundaries_str);
548+
std::string boundary_str;
549+
550+
while (std::getline(ss, boundary_str, ';')) {
551+
if (!boundary_str.empty()) {
552+
try {
553+
boundaries.push_back(SharedBoundary::from_string(boundary_str));
554+
} catch (const std::exception& e) {
555+
SW_WARN("Failed to parse shared boundary: " + boundary_str);
556+
}
557+
}
558+
}
559+
}
560+
return boundaries;
561+
}
562+
563+
// Migration: convert old single boundary format
564+
if (params_.get(Keys::SHARED_BOUNDARY, Defaults::shared_boundary)) {
565+
SharedBoundary boundary;
566+
boundary.first_domain =
567+
std::string(params_.get(Keys::SHARED_BOUNDARY_FIRST_DOMAIN, Defaults::shared_boundary_first_domain));
568+
boundary.second_domain =
569+
std::string(params_.get(Keys::SHARED_BOUNDARY_SECOND_DOMAIN, Defaults::shared_boundary_second_domain));
570+
boundary.tolerance = params_.get(Keys::SHARED_BOUNDARY_TOLERANCE, Defaults::shared_boundary_tolerance);
571+
boundaries.push_back(boundary);
572+
573+
// Migrate to new format
574+
set_shared_boundaries(boundaries);
575+
}
576+
577+
return boundaries;
513578
}
514579

515580
//---------------------------------------------------------------------------
516-
std::string GroomParameters::get_shared_boundary_second_domain() {
517-
return params_.get(Keys::SHARED_BOUNDARY_SECOND_DOMAIN, Defaults::shared_boundary_second_domain);
581+
void GroomParameters::set_shared_boundaries(const std::vector<SharedBoundary>& boundaries) {
582+
if (boundaries.empty()) {
583+
params_.set(Keys::SHARED_BOUNDARIES, "");
584+
} else {
585+
std::string boundaries_str;
586+
for (size_t i = 0; i < boundaries.size(); ++i) {
587+
if (i > 0) boundaries_str += ";";
588+
boundaries_str += boundaries[i].to_string();
589+
}
590+
params_.set(Keys::SHARED_BOUNDARIES, boundaries_str);
591+
}
592+
593+
// Clear old format keys to avoid confusion
594+
params_.remove_entry(Keys::SHARED_BOUNDARY);
595+
params_.remove_entry(Keys::SHARED_BOUNDARY_FIRST_DOMAIN);
596+
params_.remove_entry(Keys::SHARED_BOUNDARY_SECOND_DOMAIN);
597+
params_.remove_entry(Keys::SHARED_BOUNDARY_TOLERANCE);
518598
}
519599

520600
//---------------------------------------------------------------------------
521-
void GroomParameters::set_shared_boundary_second_domain(const std::string& domain_name) {
522-
params_.set(Keys::SHARED_BOUNDARY_SECOND_DOMAIN, domain_name);
601+
void GroomParameters::add_shared_boundary(const std::string& first_domain, const std::string& second_domain,
602+
double tolerance) {
603+
auto boundaries = get_shared_boundaries();
604+
boundaries.push_back({first_domain, second_domain, tolerance});
605+
set_shared_boundaries(boundaries);
523606
}
524607

525608
//---------------------------------------------------------------------------
526-
double GroomParameters::get_shared_boundary_tolerance() {
527-
return params_.get(Keys::SHARED_BOUNDARY_TOLERANCE, Defaults::shared_boundary_tolerance);
609+
void GroomParameters::remove_shared_boundary(size_t index) {
610+
auto boundaries = get_shared_boundaries();
611+
if (index < boundaries.size()) {
612+
boundaries.erase(boundaries.begin() + index);
613+
set_shared_boundaries(boundaries);
614+
}
528615
}
529616

530617
//---------------------------------------------------------------------------
531-
void GroomParameters::set_shared_boundary_tolerance(double tolerance) {
532-
params_.set(Keys::SHARED_BOUNDARY_TOLERANCE, tolerance);
533-
}
618+
void GroomParameters::clear_shared_boundaries() { set_shared_boundaries({}); }
534619

535620
//---------------------------------------------------------------------------
536621
} // namespace shapeworks

Libs/Groom/GroomParameters.h

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ namespace shapeworks {
1111
* This class encapsulated processing of Groom parameters
1212
*/
1313
class GroomParameters {
14+
public:
15+
struct SharedBoundary {
16+
std::string first_domain;
17+
std::string second_domain;
18+
double tolerance;
19+
20+
// Helper methods for serialization
21+
std::string to_string() const;
22+
static SharedBoundary from_string(const std::string& str);
23+
};
24+
1425
enum class MeshSmoothingOption { laplacian, sinc };
1526

1627
enum class AlignmentOption { none, center, icp };
@@ -137,17 +148,14 @@ class GroomParameters {
137148
bool get_skip_grooming();
138149
void set_skip_grooming(bool skip);
139150

140-
bool get_shared_boundary();
141-
void set_shared_boundary(bool shared_boundary);
142-
143-
std::string get_shared_boundary_first_domain();
144-
void set_shared_boundary_first_domain(const std::string& domain_name);
145-
146-
std::string get_shared_boundary_second_domain();
147-
void set_shared_boundary_second_domain(const std::string& domain_name);
151+
bool get_shared_boundaries_enabled();
152+
void set_shared_boundaries_enabled(bool enabled);
148153

149-
double get_shared_boundary_tolerance();
150-
void set_shared_boundary_tolerance(double tolerance);
154+
std::vector<SharedBoundary> get_shared_boundaries();
155+
void set_shared_boundaries(const std::vector<SharedBoundary>& boundaries);
156+
void add_shared_boundary(const std::string& first_domain, const std::string& second_domain, double tolerance);
157+
void remove_shared_boundary(size_t index);
158+
void clear_shared_boundaries();
151159

152160
void restore_defaults();
153161

0 commit comments

Comments
 (0)