• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 15566405961

10 Jun 2025 05:39PM UTC coverage: 62.158% (+6.9%) from 55.215%
15566405961

push

github

paulmthompson
add interface for interval grouping transformation

6851 of 11022 relevant lines covered (62.16%)

605.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.83
/src/WhiskerToolbox/DataViewer/DigitalEvent/MVP_DigitalEvent.cpp
1
#include "MVP_DigitalEvent.hpp"
2

3
#include "DigitalEventSeriesDisplayOptions.hpp"
4
#include "PlottingManager/PlottingManager.hpp"
5

6
#include <algorithm>
7
#include <random>
8

9
glm::mat4 new_getEventModelMat(NewDigitalEventSeriesDisplayOptions const & display_options,
14✔
10
                               PlottingManager const & plotting_manager) {
11
    glm::mat4 Model(1.0f);
14✔
12

13
    if (display_options.plotting_mode == EventPlottingMode::FullCanvas) {
14✔
14
        // Full Canvas Mode: Events extend from top to bottom of entire plot (like digital intervals)
15
        // Events are rendered as lines spanning the full viewport height
16
        // Scale to full viewport height with margin factor
17
        float const height_scale = (plotting_manager.viewport_y_max - plotting_manager.viewport_y_min) *
4✔
18
                                   display_options.margin_factor;
4✔
19

20
        // Center events in the middle of the viewport
21
        float const center_y = (plotting_manager.viewport_y_max + plotting_manager.viewport_y_min) * 0.5f;
4✔
22

23
        // Apply scaling for full canvas height
24
        Model[1][1] = height_scale * 0.5f;// Half scale because we'll map [-1,1] to full height
4✔
25

26
        // Apply translation to center
27
        Model[3][1] = center_y;
4✔
28

29
    } else if (display_options.plotting_mode == EventPlottingMode::Stacked) {
10✔
30
        // Stacked Mode: Events are positioned within allocated space (like analog series)
31
        // Events extend within their allocated height portion
32

33
        // Scale to allocated height with margin factor
34
        float const height_scale = display_options.allocated_height * display_options.margin_factor;
10✔
35

36
        // Apply scaling for allocated height
37
        Model[1][1] = height_scale * 0.5f;// Half scale because we'll map [-1,1] to allocated height
10✔
38

39
        // Apply translation to allocated center
40
        Model[3][1] = display_options.allocated_y_center;
10✔
41
    }
42

43
    // Apply global scaling factors
44
    Model[1][1] *= display_options.global_vertical_scale * plotting_manager.global_vertical_scale;
14✔
45

46
    return Model;
14✔
47
}
48

49
glm::mat4 new_getEventViewMat(NewDigitalEventSeriesDisplayOptions const & display_options,
21✔
50
                              PlottingManager const & plotting_manager) {
51
    auto View = glm::mat4(1.0f);
21✔
52

53
    // Panning behavior depends on plotting mode
54
    if (display_options.plotting_mode == EventPlottingMode::FullCanvas) {
21✔
55
        // Full Canvas Mode: Events stay viewport-pinned (like digital intervals)
56
        // No panning applied - events remain fixed to viewport bounds
57

58
    } else if (display_options.plotting_mode == EventPlottingMode::Stacked) {
15✔
59
        // Stacked Mode: Events move with content (like analog series)
60
        // Apply global vertical panning
61
        if (plotting_manager.vertical_pan_offset != 0.0f) {
15✔
62
            View = glm::translate(View, glm::vec3(0.0f, plotting_manager.vertical_pan_offset, 0.0f));
10✔
63
        }
64
    }
65

66
    return View;
21✔
67
}
68

69
glm::mat4 new_getEventProjectionMat(int start_data_index,
2✔
70
                                    int end_data_index,
71
                                    float y_min,
72
                                    float y_max,
73
                                    PlottingManager const & plotting_manager) {
74
    // Map data indices to normalized device coordinates [-1, 1]
75
    // X-axis: map [start_data_index, end_data_index] to screen width
76
    // Y-axis: map [y_min, y_max] to viewport height
77
    //
78
    // Note: Events use the same projection logic regardless of plotting mode
79
    // The mode-dependent behavior is handled in Model and View matrices
80

81
    auto const data_start = static_cast<float>(start_data_index);
2✔
82
    auto const data_end = static_cast<float>(end_data_index);
2✔
83

84
    // Create orthographic projection matrix
85
    // This maps world coordinates to normalized device coordinates [-1, 1]
86
    auto Projection = glm::ortho(data_start, data_end, y_min, y_max);
2✔
87

88
    return Projection;
2✔
89
}
90

91
// Helper functions for test data generation and intrinsic properties
92

93
std::vector<EventData> generateTestEventData(size_t num_events,
7✔
94
                                             float max_time,
95
                                             unsigned int seed) {
96
    std::mt19937 gen(seed);
7✔
97
    std::uniform_real_distribution<float> time_dist(0.0f, max_time);
7✔
98

99
    std::vector<EventData> events;
7✔
100
    events.reserve(num_events);
7✔
101

102
    for (size_t i = 0; i < num_events; ++i) {
1,007✔
103
        float event_time = time_dist(gen);
1,000✔
104
        events.emplace_back(event_time);
1,000✔
105
    }
106

107
    // Sort events by time for optimal visualization
108
    std::sort(events.begin(), events.end(),
7✔
109
              [](EventData const & a, EventData const & b) {
9,680✔
110
                  return a.time < b.time;
9,680✔
111
              });
112

113
    return events;
14✔
114
}
×
115

116
void setEventIntrinsicProperties(std::vector<EventData> const & events,
7✔
117
                                 NewDigitalEventSeriesDisplayOptions & display_options) {
118
    if (events.empty()) {
7✔
119
        return;
1✔
120
    }
121

122
    // For events, we don't need complex intrinsic properties like analog series
123
    // Events are simple vertical lines, so basic configuration is sufficient
124

125
    // Adjust alpha based on event count to prevent over-saturation
126
    if (events.size() > 100) {
6✔
127
        display_options.alpha = std::max(0.3f, display_options.alpha * 0.7f);
3✔
128
    } else if (events.size() > 50) {
3✔
129
        display_options.alpha = std::max(0.5f, display_options.alpha * 0.85f);
×
130
    }
131

132
    // For dense event series, reduce line thickness to avoid clutter
133
    if (events.size() > 200) {
6✔
134
        display_options.line_thickness = std::max(1, display_options.line_thickness - 1);
2✔
135
    }
136
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc