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

paulmthompson / WhiskerToolbox / 15545304457

09 Jun 2025 09:44PM UTC coverage: 55.215% (+4.0%) from 51.194%
15545304457

push

github

paulmthompson
Refactor to new MVP display options system

- Replace old display options with NewAnalog/DigitalEvent/DigitalIntervalSeriesDisplayOptions
- Migrate all MVP matrix functions to new_ prefixed versions
- Add compatibility members and function overloads for smooth transition
- Fix standard deviation recalculation and canvas resize errors
- Remove legacy MVP functions and old display option structures
- Apply consistent formatting throughout codebase

All tests pass with improved coordinate handling and panning behavior.

0 of 7 new or added lines in 1 file covered. (0.0%)

13 existing lines in 5 files now uncovered.

5225 of 9463 relevant lines covered (55.22%)

770.5 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 "PlottingManager/PlottingManager.hpp"
4
#include "DisplayOptions/TimeSeriesDisplayOptions.hpp"
5

6
#include <algorithm>
7
#include <cmath>
8
#include <iostream>
9
#include <random>
10

11

12
// NEW INFRASTRUCTURE - Digital Event MVP matrix functions
13

14
glm::mat4 new_getEventModelMat(NewDigitalEventSeriesDisplayOptions const & display_options,
14✔
15
                               PlottingManager const & plotting_manager) {
16
    glm::mat4 Model(1.0f);
14✔
17

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

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

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

31
        // Apply translation to center
32
        Model[3][1] = center_y;
4✔
33

34
    } else if (display_options.plotting_mode == EventPlottingMode::Stacked) {
10✔
35
        // Stacked Mode: Events are positioned within allocated space (like analog series)
36
        // Events extend within their allocated height portion
37

38
        // Scale to allocated height with margin factor
39
        float const height_scale = display_options.allocated_height * display_options.margin_factor;
10✔
40

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

44
        // Apply translation to allocated center
45
        Model[3][1] = display_options.allocated_y_center;
10✔
46
    }
47

48
    // Apply global scaling factors
49
    Model[1][1] *= display_options.global_vertical_scale * plotting_manager.global_vertical_scale;
14✔
50

51
    return Model;
14✔
52
}
53

54
glm::mat4 new_getEventViewMat(NewDigitalEventSeriesDisplayOptions const & display_options,
21✔
55
                              PlottingManager const & plotting_manager) {
56
    auto View = glm::mat4(1.0f);
21✔
57

58
    // Panning behavior depends on plotting mode
59
    if (display_options.plotting_mode == EventPlottingMode::FullCanvas) {
21✔
60
        // Full Canvas Mode: Events stay viewport-pinned (like digital intervals)
61
        // No panning applied - events remain fixed to viewport bounds
62

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

71
    return View;
21✔
72
}
73

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

86
    auto const data_start = static_cast<float>(start_data_index);
2✔
87
    auto const data_end = static_cast<float>(end_data_index);
2✔
88

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

93
    return Projection;
2✔
94
}
95

96
// Helper functions for test data generation and intrinsic properties
97

98
std::vector<EventData> generateTestEventData(size_t num_events,
7✔
99
                                             float max_time,
100
                                             unsigned int seed) {
101
    std::mt19937 gen(seed);
7✔
102
    std::uniform_real_distribution<float> time_dist(0.0f, max_time);
7✔
103

104
    std::vector<EventData> events;
7✔
105
    events.reserve(num_events);
7✔
106

107
    for (size_t i = 0; i < num_events; ++i) {
1,007✔
108
        float event_time = time_dist(gen);
1,000✔
109
        events.emplace_back(event_time);
1,000✔
110
    }
111

112
    // Sort events by time for optimal visualization
113
    std::sort(events.begin(), events.end(),
7✔
114
              [](EventData const & a, EventData const & b) {
9,680✔
115
                  return a.time < b.time;
9,680✔
116
              });
117

118
    return events;
14✔
UNCOV
119
}
×
120

121
void setEventIntrinsicProperties(std::vector<EventData> const & events,
7✔
122
                                 NewDigitalEventSeriesDisplayOptions & display_options) {
123
    if (events.empty()) {
7✔
124
        return;
1✔
125
    }
126

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

130
    // Adjust alpha based on event count to prevent over-saturation
131
    if (events.size() > 100) {
6✔
132
        display_options.alpha = std::max(0.3f, display_options.alpha * 0.7f);
3✔
133
    } else if (events.size() > 50) {
3✔
UNCOV
134
        display_options.alpha = std::max(0.5f, display_options.alpha * 0.85f);
×
135
    }
136

137
    // For dense event series, reduce line thickness to avoid clutter
138
    if (events.size() > 200) {
6✔
139
        display_options.line_thickness = std::max(1, display_options.line_thickness - 1);
2✔
140
    }
141
}
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