1#include "color_map_legend.h"
3#include <cgv/gui/theme_info.h>
4#include <cgv/math/ftransform.h>
6#include <cgv_g2d/msdf_gl_font_renderer.h>
11color_map_legend::color_map_legend() {
16 layout.padding = padding();
17 layout.total_size =
ivec2(300, 60);
21 tick_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::rectangle);
26 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, -1);
32 tick_renderer.destruct(ctx);
41 layout.total_size.
y() = std::max(layout.total_size.
y(), 2 * layout.padding + 4 + layout.label_space);
49 num_ticks = cgv::math::clamp(num_ticks, 2u, 100u);
52 layout.title_space = title ==
"" ? 0 : 12;
53 post_recreate_layout();
56 if(m.one_of(layout.orientation, layout.label_alignment, value_range, num_ticks) || m.
member_of(label_format))
57 post_recreate_layout();
62 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
64 register_shader(
"rectangle", cgv::g2d::shaders::rectangle);
65 register_shader(
"grid", cgv::g2d::shaders::grid);
69 success &= tick_renderer.init(ctx);
78 if(ensure_layout(ctx)) {
83 float width_factor =
static_cast<float>(layout.color_map_rect.w());
84 float height_factor =
static_cast<float>(layout.color_map_rect.h());
85 background_style.texcoord_scaling =
vec2(width_factor, height_factor) / 10.0f;
94 content_canvas.enable_shader(ctx,
"rectangle");
95 content_canvas.set_style(ctx, border_style);
96 content_canvas.draw_shape(ctx, layout.color_map_rect.position - 1, layout.color_map_rect.size + 2);
99 content_canvas.enable_shader(ctx,
"grid");
100 content_canvas.set_style(ctx, background_style);
101 content_canvas.draw_shape(ctx, layout.color_map_rect);
105 content_canvas.push_modelview_matrix();
106 ivec2 pos = layout.color_map_rect.position;
107 ivec2 size = layout.color_map_rect.size;
110 if(layout.orientation == OO_VERTICAL) {
111 pos.
x() += layout.color_map_rect.size.x();
112 std::swap(size.x(), size.y());
116 content_canvas.mul_modelview_matrix(ctx, cgv::math::translate2h(pos));
117 content_canvas.mul_modelview_matrix(ctx, cgv::math::rotate2h(angle));
120 color_map_style.use_texture_alpha = show_opacity;
122 color_map_style.texcoord_offset.x() = display_range[0];
123 color_map_style.texcoord_scaling.x() = display_range[1] - display_range[0];
126 color_map_style.texcoord_scaling.x() *= -1.0f;
128 content_canvas.enable_shader(ctx,
"rectangle");
129 content_canvas.set_style(ctx, color_map_style);
131 content_canvas.draw_shape(ctx,
ivec2(0), size);
134 content_canvas.pop_modelview_matrix(ctx);
136 content_canvas.disable_current_shader(ctx);
139 tick_renderer.render(ctx, content_canvas, cgv::render::PT_POINTS, ticks, tick_style);
142 auto& font_renderer = cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx);
143 if(font_renderer.enable(ctx, content_canvas, labels, text_style)) {
144 font_renderer.draw(ctx, content_canvas, labels, 0,
static_cast<int>(num_ticks));
146 content_canvas.push_modelview_matrix();
147 content_canvas.mul_modelview_matrix(ctx, cgv::math::translate2h(layout.title_position));
148 content_canvas.mul_modelview_matrix(ctx, cgv::math::rotate2h(layout.title_angle));
150 font_renderer.draw(ctx, content_canvas, labels, num_ticks, 1);
152 content_canvas.pop_modelview_matrix(ctx);
153 font_renderer.disable(ctx, labels);
161 add_member_control(
this,
"Width", layout.total_size[0],
"value_slider",
"min=40;max=500;step=1;ticks=true");
162 add_member_control(
this,
"Height", layout.total_size[1],
"value_slider",
"min=40;max=500;step=1;ticks=true");
168 add_member_control(
this,
"Orientation", layout.orientation,
"dropdown",
"enums='Horizontal,Vertical'");
169 add_member_control(
this,
"Label Alignment", layout.label_alignment,
"dropdown",
"enums='-,Before,Inside,After'");
172 add_member_control(
this,
"Number Precision", label_format.precision,
"value",
"w=28;min=0;max=10;step=1",
" ");
174 add_member_control(
this,
"Show 0s", label_format.trailing_zeros,
"check",
"w=74",
"");
181 if(cm.has_texture_support()) {
183 filter = gl_cm_ptr->is_linear_filtering_enabled() ? cgv::render::TF_LINEAR : cgv::render::TF_NEAREST;
186 unsigned resolution = cm.get_resolution();
187 std::vector<rgb> color_data = cm.interpolate_color(
static_cast<size_t>(resolution));
188 std::vector<float> opacity_data(
static_cast<size_t>(resolution), 1.0f);
190 if(!cm.ref_opacity_points().empty())
191 opacity_data = cm.interpolate_opacity(
static_cast<size_t>(resolution));
193 std::vector<uint8_t> data_8(2 * 4 * color_data.size());
194 for(
unsigned i = 0; i < color_data.size(); ++i) {
195 rgba col = color_data[i];
196 data_8[4 * i + 0] =
static_cast<uint8_t
>(255.0f * col.R());
197 data_8[4 * i + 1] =
static_cast<uint8_t
>(255.0f * col.G());
198 data_8[4 * i + 2] =
static_cast<uint8_t
>(255.0f * col.B());
199 data_8[4 * i + 3] =
static_cast<uint8_t
>(255.0f * opacity_data[i]);
202 std::copy(data_8.begin(), data_8.begin() + 4 * resolution, data_8.begin() + 4 * resolution);
206 unsigned width = (unsigned)tex.
get_width();
208 bool replaced =
false;
212 replaced = tex.
replace(ctx, 0, 0, dv);
224void color_map_legend::set_width(
size_t w) {
225 layout.total_size.
x() = int(w);
226 on_set(&layout.total_size.
x());
229void color_map_legend::set_height(
size_t h) {
230 layout.total_size.
y() = int(h);
231 on_set(&layout.total_size.
y());
234void color_map_legend::set_title(
const std::string& t) {
239void color_map_legend::set_orientation(OrientationOption orientation) {
240 layout.orientation = orientation;
241 on_set(&layout.orientation);
244void color_map_legend::set_label_alignment(AlignmentOption alignment) {
245 layout.label_alignment = alignment;
246 on_set(&layout.label_alignment);
249void color_map_legend::set_range(
vec2 r) {
250 flip_texture = r.x() > r.y();
252 std::swap(r.x(), r.y());
258void color_map_legend::set_display_range(
vec2 r) {
263void color_map_legend::set_invert_color(
bool flag) {
268void color_map_legend::set_num_ticks(
unsigned n) {
273void color_map_legend::set_label_precision(
unsigned p) {
274 label_format.precision = p;
275 on_set(&label_format.precision);
278void color_map_legend::set_label_auto_precision(
bool f) {
279 label_format.auto_precision = f;
280 on_set(&label_format.auto_precision);
283void color_map_legend::set_label_prune_trailing_zeros(
bool f) {
284 label_format.trailing_zeros = !f;
285 on_set(&label_format.trailing_zeros);
288void color_map_legend::set_label_integer_mode(
bool enabled) {
289 label_format.integers = enabled;
290 on_set(&label_format.integers);
293void color_map_legend::set_show_opacity(
bool enabled) {
294 show_opacity = enabled;
298void color_map_legend::init_styles() {
299 auto& theme = cgv::gui::theme_info::instance();
300 rgb tick_color = theme.text();
303 tick_color = pow(
rgb(1.0f) - pow(tick_color, 2.2f), 1.0f / 2.2f);
306 border_style.feather_width = 0.0f;
307 border_style.fill_color = tick_color;
308 border_style.border_width = 0.0f;
311 background_style.fill_color =
rgb(0.9f);
312 background_style.border_color =
rgb(0.75f);
313 background_style.feather_width = 0.0f;
314 background_style.pattern = cgv::g2d::grid2d_style::GridPattern::GP_CHECKER;
317 color_map_style = border_style;
318 color_map_style.use_texture =
true;
319 color_map_style.use_texture_alpha =
true;
320 color_map_style.use_blending =
true;
323 text_style.fill_color = tick_color;
324 text_style.font_size = 12.0f;
327 tick_style.position_is_center =
true;
328 tick_style.fill_color = tick_color;
329 tick_style.feather_width = 0.0f;
336 if(layout.label_alignment == AO_FREE)
339 unsigned precision = label_format.precision;
341 if(label_format.auto_precision) {
343 const float delta = std::abs(value_range[1] - value_range[0]);
344 const unsigned max_precision = 7;
350 for(
unsigned i = 2; i <= max_precision; ++i) {
351 if(delta > limit || i == max_precision) {
360 float max_width = -1.0f;
362 std::vector<std::string> label_texts;
364 for(
size_t i = 0; i < num_ticks; ++i) {
365 float fi =
static_cast<float>(i);
366 float t = fi /
static_cast<float>(num_ticks - 1);
367 float val = cgv::math::lerp(value_range.
x(), value_range.
y(), t);
371 if(label_format.integers)
372 str = std::to_string(
static_cast<int>(round(val)));
375 if(!label_format.trailing_zeros && str.length() > 1)
379 label_texts.push_back(str);
382 label_texts.push_back(title);
384 labels.set_text_array(ctx, label_texts);
385 labels.positions.resize(label_texts.size(), { 0.0f });
389 auto& text_infos = labels.ref_text_infos();
390 for(
size_t i = 0; i < static_cast<size_t>(num_ticks); ++i)
391 max_width = std::max(max_width, text_infos[i].normalized_width);
393 if(labels.size() > 1) {
394 if(layout.orientation == OO_HORIZONTAL)
395 layout.x_label_size =
static_cast<int>(std::max(text_infos.front().normalized_width, text_infos[text_infos.size() - 2].normalized_width) * text_style.font_size);
397 layout.x_label_size =
static_cast<int>(max_width * text_style.font_size);
399 layout.x_label_size = 0;
403void color_map_legend::create_ticks() {
407 if(layout.label_alignment == AO_FREE)
410 ivec2 tick_size(1, 6);
413 int label_offset = 4;
414 AlignmentOption label_alignment = layout.label_alignment;
422 layout.title_angle = 0.0f;
424 if(layout.orientation == OO_VERTICAL) {
428 std::swap(tick_size.x(), tick_size.y());
430 if(label_alignment == AO_START) label_alignment = AO_END;
431 else if(label_alignment == AO_END) label_alignment = AO_START;
437 std::swap(title_alignment_1, title_alignment_2);
439 layout.title_angle = 90.0f;
442 ivec2 color_rect_pos = layout.color_map_rect.position;
443 ivec2 color_rect_size = layout.color_map_rect.size;
445 int length = color_rect_size[axis];
446 float step =
static_cast<float>(length + 1) /
static_cast<float>(num_ticks - 1);
448 ivec2 title_pos = color_rect_pos;
449 ivec2 tick_start = color_rect_pos;
452 title_alignment = title_alignment_1;
453 text_alignment = text_v_end;
456 switch(label_alignment) {
458 title_pos[1 - axis] -= 4;
459 tick_start[1 - axis] += color_rect_size[1 - axis] + 3;
462 title_pos[axis] += 2;
463 title_pos[1 - axis] += color_rect_size[1 - axis] - (axis ? 3 : 1);
464 tick_start[1 - axis] += 3;
468 title_alignment = title_alignment_2;
469 title_pos[1 - axis] += color_rect_size[1 - axis] + 4;
470 tick_start[1 - axis] -= 3;
471 label_offset = -label_offset;
472 text_alignment = text_v_start;
479 for(
size_t i = 0; i < num_ticks; ++i) {
480 float fi =
static_cast<float>(i);
481 int offset =
static_cast<int>(round(fi * step));
483 ivec2 tick_pos = tick_start;
484 tick_pos[axis] += offset;
486 ivec2 label_pos = tick_start;
487 label_pos[1 - axis] += label_offset;
488 label_pos[axis] += offset;
494 label_pos[axis] += 3;
496 }
else if(i == num_ticks - 1) {
497 label_pos[axis] -= 3;
502 ticks.add(tick_pos, tick_size);
504 labels.positions[i] =
vec3(label_pos, 0.0f);
505 labels.alignments[i] = alignment;
508 layout.title_position = title_pos;
510 if(labels.alignments.size() > 0)
511 labels.alignments.back() = title_alignment;
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
virtual void on_set(void *member_ptr) override
default implementation of that calls handle_member_change and afterwards upates the member in the gui...
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void handle_member_change(const cgv::utils::pointer_test &m) override
implement to handle member changes
void init_frame(cgv::render::context &ctx) override
this method is called in one pass over all drawables before the draw method
void create_gui_impl() override
virtual method to implement the derived class gui creation
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
cgv::g2d::irect get_rectangle() const
return the current rectangle area (in screen coordinates) of the overlay taking layout into account
void set_size(const ivec2 &size)
set the default size of the overlay before stretch gets applied
bool background_visible_
whether the background is visible (true by default)
void set_name(const std::string &_name)
set a new parent node
the data view gives access to a data array of one, two, three or four dimensions.
data::ref_ptr< control< T > > add_member_control(cgv::base::base *base_ptr, const std::string &label, T &value, const std::string &gui_type="", const std::string &options="", const std::string &align="\n")
add control with callback to cgv::base::on_set method on cgv::gui::control::value_change
base class for all drawables, which is independent of the used rendering API.
virtual bool is_created() const
return whether component has been created
the texture class encapsulates all functionality independent of the rendering api.
void set_mag_filter(TextureFilter _mag_filter)
set the magnification filter
bool create(const context &ctx, TextureType _tt=TT_UNDEF, unsigned width=-1, unsigned height=-1, unsigned depth=-1)
create the texture of dimension and resolution specified in the data format base class.
bool disable(const context &ctx)
disable texture and restore state from before last enable call
bool enable(const context &ctx, int tex_unit=-1)
enable this texture in the given texture unit, -1 corresponds to the current unit.
bool destruct(const context &ctx)
destruct the texture and free texture memory and handle
bool replace(const context &ctx, int x, const cgv::data::const_data_view &data, int level=-1, const std::vector< cgv::data::data_view > *palettes=0)
replace a block within a 1d texture with the given data.
void set_min_filter(TextureFilter _min_filter, float _anisotropy=2.0f)
set the minification filters, if minification is set to TF_ANISOTROP, the second floating point param...
bool member_of(const T &ref) const
Test if the stored pointer points inside the address range of the given object instance.
bool is(const void *ptr) const
Test if the stored pointer points to the given pointer address.
@ CF_RGBA
color format with components R, G and B
TextAlignment
different text alignments
@ TA_TOP
center of top edge of text bounds
@ TA_BOTTOM
center of bottom edge of text bounds
@ TA_RIGHT
center of right edge of text bounds
@ TA_BOTTOM_LEFT
bottom left corner of text bounds
@ TA_LEFT
center of left edge of text bounds
TextureFilter
different texture filter
@ TI_UINT8
signed integer stored in 64 bits
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
std::string & rtrim(std::string &str, const std::string &chars)
trim white space or other characters from end of string
cgv::media::color< float, cgv::media::RGB > rgb
declare rgb color type with 32 bit components
cgv::math::fvec< int32_t, 2 > ivec2
declare type of 2d 32 bit integer vectors
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
cgv::math::fvec< float, 3 > vec3
declare type of 3d single precision floating point vectors
Helper functions to process strings.