Skip to content

Commit 3f9cf91

Browse files
committed
Refactor mooring viz: eliminate duplicated colormap, fix stale naming
1 parent b3207a0 commit 3f9cf91

3 files changed

Lines changed: 57 additions & 58 deletions

File tree

src/gui/vsg_gui_component.cpp

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ void HydroChronoGuiComponent::RenderMooringPanel() {
158158
}
159159

160160
ImGui::TextDisabled("Range: %.3g .. %.3g N",
161-
mooring_viz_->ScalarMin(),
162-
mooring_viz_->ScalarMax());
161+
mooring_viz_->TensionMin(),
162+
mooring_viz_->TensionMax());
163163

164164
ImGui::Unindent();
165165
}
@@ -185,31 +185,20 @@ void HydroChronoGuiComponent::RenderColorBar() {
185185
// Draw the gradient as a stack of thin horizontal strips.
186186
constexpr int kStrips = 64;
187187
const float strip_h = bar_h / kStrips;
188+
189+
auto turbo_to_im = [](float t) -> ImU32 {
190+
const auto c = MooringLinesViz::TurboColormap(t);
191+
return IM_COL32(static_cast<int>(c.r * 255),
192+
static_cast<int>(c.g * 255),
193+
static_cast<int>(c.b * 255), 255);
194+
};
195+
188196
for (int i = 0; i < kStrips; ++i) {
189197
const float t_top = 1.0f - static_cast<float>(i) / kStrips;
190198
const float t_bot = 1.0f - static_cast<float>(i + 1) / kStrips;
191199

192-
auto to_im = [](float t) -> ImU32 {
193-
t = std::clamp(t, 0.0f, 1.0f);
194-
const float r = std::clamp(
195-
0.13572138f + t * (4.61539260f + t * (-42.66032258f +
196-
t * (132.13108234f + t * (-152.54895899f + t * 59.28637943f)))),
197-
0.0f, 1.0f);
198-
const float g = std::clamp(
199-
0.09140261f + t * (2.26418794f + t * (4.11868525f +
200-
t * (-44.58319668f + t * (70.41698018f - t * 33.26974748f)))),
201-
0.0f, 1.0f);
202-
const float b = std::clamp(
203-
0.10667330f + t * (12.75191895f + t * (-60.25290628f +
204-
t * (109.04872043f + t * (-89.38040853f + t * 27.13073700f)))),
205-
0.0f, 1.0f);
206-
return IM_COL32(static_cast<int>(r * 255),
207-
static_cast<int>(g * 255),
208-
static_cast<int>(b * 255), 255);
209-
};
210-
211-
ImU32 col_top = to_im(t_top);
212-
ImU32 col_bot = to_im(t_bot);
200+
const ImU32 col_top = turbo_to_im(t_top);
201+
const ImU32 col_bot = turbo_to_im(t_bot);
213202
dl->AddRectFilledMultiColor(
214203
ImVec2(x0, y0 + i * strip_h),
215204
ImVec2(x0 + bar_w, y0 + (i + 1) * strip_h),
@@ -222,11 +211,11 @@ void HydroChronoGuiComponent::RenderColorBar() {
222211

223212
// Labels.
224213
char buf[64];
225-
std::snprintf(buf, sizeof(buf), "%.3g N", mooring_viz_->ScalarMax());
214+
std::snprintf(buf, sizeof(buf), "%.3g N", mooring_viz_->TensionMax());
226215
dl->AddText(ImVec2(x0 - label_gap - ImGui::CalcTextSize(buf).x, y0 - 2.0f),
227216
IM_COL32(220, 220, 220, 255), buf);
228217

229-
std::snprintf(buf, sizeof(buf), "%.3g N", mooring_viz_->ScalarMin());
218+
std::snprintf(buf, sizeof(buf), "%.3g N", mooring_viz_->TensionMin());
230219
dl->AddText(ImVec2(x0 - label_gap - ImGui::CalcTextSize(buf).x,
231220
y0 + bar_h - ImGui::GetTextLineHeight() + 2.0f),
232221
IM_COL32(220, 220, 220, 255), buf);

src/gui/vsg_mooring_lines.cpp

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <chrono_vsg/utils/ChShapeBuilderVSG.h>
1111

1212
#include <algorithm>
13+
#include <array>
1314
#include <cmath>
1415
#include <iostream>
1516
#include <limits>
@@ -116,9 +117,7 @@ static chrono::ChColor PointTypeColor(int point_type) {
116117
return {0.05f, 0.05f, 0.05f}; // intermediate node -- near black
117118
}
118119

119-
/// Attempt to match the Google Turbo colour map (Mikhailov, 2019).
120-
/// Input @p t is clamped to [0, 1]. Returns an opaque RGBA colour.
121-
static vsg::vec4 TurboColormap(float t) {
120+
vsg::vec4 MooringLinesViz::TurboColormap(float t) {
122121
t = std::clamp(t, 0.0f, 1.0f);
123122

124123
// Polynomial coefficients fitted to the 256-entry Turbo LUT.
@@ -174,44 +173,44 @@ void MooringLinesViz::Update(const std::vector<MooringLineVizData>& lines,
174173
if (!initialized_) return;
175174
const size_t count = std::min(lines.size(), line_meshes_.size());
176175

177-
// Adaptive range: min fixed at 0 (all fields are non-negative magnitudes),
176+
// Adaptive range: min fixed at 0 (tension magnitude is non-negative),
178177
// max uses high-water-mark behaviour -- snaps to new peaks instantly but
179178
// decays very slowly so the colour scale stays stable.
180179
if (color_enabled && !range_locked) {
181180
float frame_max = 0.0f;
182181
for (size_t li = 0; li < count; ++li) {
183-
for (double s : lines[li].node_tensions) {
184-
frame_max = std::max(frame_max, static_cast<float>(s));
182+
for (double t : lines[li].node_tensions) {
183+
frame_max = std::max(frame_max, static_cast<float>(t));
185184
}
186185
}
187186

188187
const float padded_max = frame_max * (1.0f + kRangePadding);
189188

190-
if (!adaptive_initialized_) {
191-
adaptive_max_ = std::max(padded_max, 1.0f);
192-
adaptive_initialized_ = true;
189+
if (!range_initialized_) {
190+
tension_max_ = std::max(padded_max, 1.0f);
191+
range_initialized_ = true;
193192
hold_frames_remaining_ = kRangeHoldFrames;
194-
} else if (padded_max > adaptive_max_) {
195-
adaptive_max_ = padded_max;
193+
} else if (padded_max > tension_max_) {
194+
tension_max_ = padded_max;
196195
hold_frames_remaining_ = kRangeHoldFrames;
197196
} else if (hold_frames_remaining_ > 0) {
198197
--hold_frames_remaining_;
199198
} else {
200-
adaptive_max_ += kRangeDecayAlpha * (padded_max - adaptive_max_);
199+
tension_max_ += kRangeDecayAlpha * (padded_max - tension_max_);
201200
}
202201

203-
adaptive_min_ = 0.0f;
202+
tension_min_ = 0.0f;
204203

205-
if (adaptive_max_ < 1e-6f) {
206-
adaptive_max_ = 1.0f;
204+
if (tension_max_ < 1e-6f) {
205+
tension_max_ = 1.0f;
207206
}
208207
}
209208

210209
for (size_t li = 0; li < count; ++li) {
211210
if (lines[li].node_positions.size() < 2) continue;
212211
if (!line_meshes_[li].vertices) continue;
213212
UpdateTubeMesh(lines[li], line_meshes_[li],
214-
color_enabled, adaptive_min_, adaptive_max_);
213+
color_enabled, tension_min_, tension_max_);
215214
}
216215
}
217216

@@ -391,20 +390,26 @@ void MooringLinesViz::UpdateTubeMesh(const MooringLineVizData& line_data,
391390
const size_t ring_verts = num_nodes * static_cast<size_t>(kSides);
392391
if (lm.vertices->size() < ring_verts + 2) return;
393392

394-
const bool has_scalars =
393+
const bool has_tensions =
395394
color_enabled && lm.colors &&
396395
line_data.node_tensions.size() == num_nodes;
397396
const float inv_range =
398397
(range_max - range_min > 1e-12f) ? 1.0f / (range_max - range_min)
399398
: 1.0f;
400399

401-
std::vector<double> cos_table(kSides);
402-
std::vector<double> sin_table(kSides);
403-
for (int s = 0; s < kSides; ++s) {
404-
const double angle = 2.0 * M_PI * s / kSides;
405-
cos_table[s] = std::cos(angle);
406-
sin_table[s] = std::sin(angle);
407-
}
400+
// kSides is a compile-time constant, so the trig table never changes.
401+
static const auto cos_table = [] {
402+
std::array<double, kSides> t{};
403+
for (int s = 0; s < kSides; ++s)
404+
t[s] = std::cos(2.0 * M_PI * s / kSides);
405+
return t;
406+
}();
407+
static const auto sin_table = [] {
408+
std::array<double, kSides> t{};
409+
for (int s = 0; s < kSides; ++s)
410+
t[s] = std::sin(2.0 * M_PI * s / kSides);
411+
return t;
412+
}();
408413

409414
for (size_t ni = 0; ni < num_nodes; ++ni) {
410415
const vsg::dvec3 tang = Tangent(pts, ni);
@@ -416,7 +421,7 @@ void MooringLinesViz::UpdateTubeMesh(const MooringLineVizData& line_data,
416421
const auto centre_z = static_cast<float>(pts[ni][2]);
417422

418423
vsg::vec4 col = kDefaultCableColorVec4;
419-
if (has_scalars) {
424+
if (has_tensions) {
420425
const float t =
421426
(static_cast<float>(line_data.node_tensions[ni]) - range_min)
422427
* inv_range;
@@ -467,7 +472,7 @@ void MooringLinesViz::UpdateTubeMesh(const MooringLineVizData& line_data,
467472
if (lm.colors) {
468473
vsg::vec4 cap0_col = kDefaultCableColorVec4;
469474
vsg::vec4 capN_col = kDefaultCableColorVec4;
470-
if (has_scalars) {
475+
if (has_tensions) {
471476
cap0_col = TurboColormap(
472477
(static_cast<float>(line_data.node_tensions.front()) - range_min)
473478
* inv_range);

src/gui/vsg_mooring_lines.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class MooringLinesViz {
4242
const std::vector<MooringLineVizData>& initial_lines,
4343
vsg::ref_ptr<vsg::Group> parent_group = {});
4444

45-
/// Reposition tube vertices and (optionally) recolour by scalar field.
45+
/// Reposition tube vertices and (optionally) recolour by tension.
4646
/// @param color_enabled When false, colours are reset to the default cable
4747
/// tan and the adaptive range is left untouched.
4848
/// @param range_locked When true the adaptive min/max is frozen.
@@ -54,9 +54,14 @@ class MooringLinesViz {
5454
return initialized_ && bound_vis_ == vis;
5555
}
5656

57-
/// Current adaptive scalar range (for the GUI colour bar).
58-
float ScalarMin() const { return adaptive_min_; }
59-
float ScalarMax() const { return adaptive_max_; }
57+
/// Current adaptive tension range [N] (for the GUI colour bar).
58+
float TensionMin() const { return tension_min_; }
59+
float TensionMax() const { return tension_max_; }
60+
61+
/// Evaluate the Turbo colour map at normalised parameter @p t in [0, 1].
62+
/// Exposed as a public static so the GUI colour bar can reuse the same
63+
/// polynomial without duplicating coefficients.
64+
static vsg::vec4 TurboColormap(float t);
6065

6166
private:
6267
static constexpr int kSides = 8;
@@ -104,9 +109,9 @@ class MooringLinesViz {
104109
chrono::vsg3d::ChVisualSystemVSG* bound_vis_ = nullptr;
105110
bool initialized_ = false;
106111

107-
float adaptive_min_ = 0.0f;
108-
float adaptive_max_ = 1.0f;
109-
bool adaptive_initialized_ = false;
112+
float tension_min_ = 0.0f;
113+
float tension_max_ = 1.0f;
114+
bool range_initialized_ = false;
110115
int hold_frames_remaining_ = 0;
111116
};
112117

0 commit comments

Comments
 (0)