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

paulmthompson / WhiskerToolbox / 17270491352

27 Aug 2025 02:57PM UTC coverage: 65.333%. Remained the same
17270491352

push

github

paulmthompson
Merge branch 'main' of https://github.com/paulmthompson/WhiskerToolbox

352 of 628 new or added lines in 92 files covered. (56.05%)

357 existing lines in 24 files now uncovered.

26429 of 40453 relevant lines covered (65.33%)

1119.34 hits per line

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

57.45
/src/DataManager/Masks/Mask_Data.cpp
1
#include "Mask_Data.hpp"
2

3
#include "utils/map_timeseries.hpp"
4

5
#include <algorithm>
6
#include <cmath>
7
#include <iostream>
8

9
// ========== Constructors ==========
10

11
// ========== Setters ==========
12

13
bool MaskData::clearAtTime(TimeFrameIndex const time, bool notify) {
16✔
14
    if (clear_at_time(time, _data)) {
16✔
15
        if (notify) {
13✔
16
            notifyObservers();
3✔
17
        }
18
        return true;
13✔
19
    }
20
    return false;
3✔
21
}
22

23
bool MaskData::clearAtTime(TimeIndexAndFrame const & time_index_and_frame, bool notify) {
×
24

25
    if (time_index_and_frame.time_frame.get() == _time_frame.get()) {
×
26
        return clearAtTime(time_index_and_frame.index, notify);
×
27
    }
28

29
    if (!time_index_and_frame.time_frame || !_time_frame.get()) {
×
30
        return false;
×
31
    }
32

33
    auto time = time_index_and_frame.time_frame->getTimeAtIndex(time_index_and_frame.index);
×
NEW
34
    auto time_index = _time_frame->getIndexAtTime(static_cast<float>(time));
×
35

36

37
    if (clear_at_time(time_index, _data)) {
×
38
        if (notify) {
×
39
            notifyObservers();
×
40
        }
41
        return true;
×
42
    }
43
    return false;
×
44
}
45

46
bool MaskData::clearAtTime(TimeFrameIndex const time, size_t const index, bool notify) {
×
47
    if (clear_at_time(time, index, _data)) {
×
48
        if (notify) {
×
49
            notifyObservers();
×
50
        }
51
        return true;
×
52
    }
53
    return false;
×
54
}
55

56
void MaskData::addAtTime(TimeFrameIndex const time,
122✔
57
                         std::vector<uint32_t> const & x,
58
                         std::vector<uint32_t> const & y,
59
                         bool notify) {
60
    auto new_mask = create_mask(x, y);
122✔
61
    add_at_time(time, std::move(new_mask), _data);
122✔
62

63
    if (notify) {
122✔
64
        notifyObservers();
118✔
65
    }
66
}
244✔
67

68
void MaskData::addAtTime(TimeFrameIndex const time,
183✔
69
                         std::vector<Point2D<uint32_t>> mask,
70
                         bool notify) {
71
    add_at_time(time, std::move(mask), _data);
183✔
72

73
    if (notify) {
183✔
74
        notifyObservers();
90✔
75
    }
76
}
183✔
77

78
void MaskData::addAtTime(TimeIndexAndFrame const & time_index_and_frame,
×
79
                         std::vector<Point2D<uint32_t>> mask,
80
                         bool notify) {
81
    if (time_index_and_frame.time_frame.get() == _time_frame.get()) {
×
82
        addAtTime(time_index_and_frame.index, std::move(mask), notify);
×
83
    }
84

85
    if (!time_index_and_frame.time_frame || !_time_frame.get()) {
×
86
        return;
×
87
    }
88

89
    auto time = time_index_and_frame.time_frame->getTimeAtIndex(time_index_and_frame.index);
×
NEW
90
    auto time_index = _time_frame->getIndexAtTime(static_cast<float>(time));
×
91

92
    add_at_time(time_index, std::move(mask), _data);
×
93
}
94

95
void MaskData::addAtTime(TimeFrameIndex const time,
×
96
                         std::vector<uint32_t> && x,
97
                         std::vector<uint32_t> && y,
98
                         bool notify) {
99
    // Create mask efficiently using move semantics
100
    auto new_mask = Mask2D{};
×
101
    new_mask.reserve(x.size());
×
102

103
    for (std::size_t i = 0; i < x.size(); i++) {
×
104
        //new_mask.emplace_back(x[i], y[i]);
105
        new_mask.push_back({x[i], y[i]});
×
106
    }
107

108
    _data[time].push_back(std::move(new_mask));
×
109

110
    if (notify) {
×
111
        notifyObservers();
×
112
    }
113
}
×
114

115
// ========== Getters ==========
116

117
std::vector<Mask2D> const & MaskData::getAtTime(TimeFrameIndex const time) const {
74✔
118
    return get_at_time(time, _data, _empty);
74✔
119
}
120

121
std::vector<Mask2D> const & MaskData::getAtTime(TimeIndexAndFrame const & time_index_and_frame) const {
×
122
    return get_at_time(time_index_and_frame.index,
×
123
                       _data,
×
124
                       _empty,
×
125
                       time_index_and_frame.time_frame.get(),
×
126
                       _time_frame.get());
×
127
}
128

129
std::vector<Mask2D> const & MaskData::getAtTime(TimeFrameIndex const time,
×
130
                                                TimeFrame const * source_timeframe,
131
                                                TimeFrame const * mask_timeframe) const {
132

133
    return get_at_time(time, _data, _empty, source_timeframe, mask_timeframe);
×
134
}
135

136
// ========== Image Size ==========
137

138
void MaskData::changeImageSize(ImageSize const & image_size) {
×
139
    if (_image_size.width == -1 || _image_size.height == -1) {
×
140
        std::cout << "No size set for current image. "
141
                  << " Please set a valid image size before trying to scale" << std::endl;
×
142
    }
143

144
    if (_image_size.width == image_size.width && _image_size.height == image_size.height) {
×
145
        std::cout << "Image size is the same. No need to scale" << std::endl;
×
146
        return;
×
147
    }
148

149
    float const scale_x = static_cast<float>(image_size.width) / static_cast<float>(_image_size.width);
×
150
    float const scale_y = static_cast<float>(image_size.height) / static_cast<float>(_image_size.height);
×
151

152
    for (auto & [time, masks]: _data) {
×
153
        for (auto & mask: masks) {
×
154
            for (auto & point: mask) {
×
155
                point.x = static_cast<uint32_t>(std::round(static_cast<float>(point.x) * scale_x));
×
156
                point.y = static_cast<uint32_t>(std::round(static_cast<float>(point.y) * scale_y));
×
157
            }
158
        }
159
    }
160
    _image_size = image_size;
×
161
}
162

163
// ========== Copy and Move ==========
164

165
std::size_t MaskData::copyTo(MaskData & target, TimeFrameInterval const & interval, bool notify) const {
9✔
166
    if (interval.start > interval.end) {
9✔
167
        std::cerr << "MaskData::copyTo: interval start (" << interval.start.getValue()
1✔
168
                  << ") must be <= interval end (" << interval.end.getValue() << ")" << std::endl;
1✔
169
        return 0;
1✔
170
    }
171

172
    // Ensure target is not the same as source
173
    if (this == &target) {
8✔
174
        std::cerr << "MaskData::copyTo: Cannot copy to self" << std::endl;
1✔
175
        return 0;
1✔
176
    }
177

178
    std::size_t total_masks_copied = 0;
7✔
179

180
    // Iterate through all times in the source data within the interval
181
    for (auto const & [time, masks]: _data) {
21✔
182
        if (time >= interval.start && time <= interval.end && !masks.empty()) {
14✔
183
            for (auto const & mask: masks) {
16✔
184
                target.addAtTime(time, mask, false);// Don't notify for each operation
9✔
185
                total_masks_copied++;
9✔
186
            }
187
        }
188
    }
189

190
    // Notify observer only once at the end if requested
191
    if (notify && total_masks_copied > 0) {
7✔
192
        target.notifyObservers();
4✔
193
    }
194

195
    return total_masks_copied;
7✔
196
}
197

198
std::size_t MaskData::copyTo(MaskData & target, std::vector<TimeFrameIndex> const & times, bool notify) const {
2✔
199
    std::size_t total_masks_copied = 0;
2✔
200

201
    // Copy masks for each specified time
202
    for (TimeFrameIndex time: times) {
8✔
203
        auto it = _data.find(time);
6✔
204
        if (it != _data.end() && !it->second.empty()) {
6✔
205
            for (auto const & mask: it->second) {
10✔
206
                target.addAtTime(time, mask, false);// Don't notify for each operation
6✔
207
                total_masks_copied++;
6✔
208
            }
209
        }
210
    }
211

212
    // Notify observer only once at the end if requested
213
    if (notify && total_masks_copied > 0) {
2✔
214
        target.notifyObservers();
2✔
215
    }
216

217
    return total_masks_copied;
2✔
218
}
219

220
std::size_t MaskData::moveTo(MaskData & target, TimeFrameInterval const & interval, bool notify) {
5✔
221
    if (interval.start > interval.end) {
5✔
222
        std::cerr << "MaskData::moveTo: interval start (" << interval.start.getValue()
×
223
                  << ") must be <= interval end (" << interval.end.getValue() << ")" << std::endl;
×
224
        return 0;
×
225
    }
226

227
    std::size_t total_masks_moved = 0;
5✔
228
    std::vector<TimeFrameIndex> times_to_clear;
5✔
229

230
    // First, copy all masks in the interval to target
231
    for (auto const & [time, masks]: _data) {
17✔
232
        if (time >= interval.start && time <= interval.end && !masks.empty()) {
12✔
233
            for (auto const & mask: masks) {
14✔
234
                target.addAtTime(time, mask, false);// Don't notify for each operation
8✔
235
                total_masks_moved++;
8✔
236
            }
237
            times_to_clear.push_back(time);
6✔
238
        }
239
    }
240

241
    // Then, clear all the times from source
242
    for (TimeFrameIndex time: times_to_clear) {
11✔
243
        (void)clearAtTime(time, false);// Don't notify for each operation
6✔
244
    }
245

246
    // Notify observers only once at the end if requested
247
    if (notify && total_masks_moved > 0) {
5✔
248
        target.notifyObservers();
3✔
249
        notifyObservers();
3✔
250
    }
251

252
    return total_masks_moved;
5✔
253
}
5✔
254

255
std::size_t MaskData::moveTo(MaskData & target, std::vector<TimeFrameIndex> const & times, bool notify) {
2✔
256
    std::size_t total_masks_moved = 0;
2✔
257
    std::vector<TimeFrameIndex> times_to_clear;
2✔
258

259
    // First, copy masks for each specified time to target
260
    for (TimeFrameIndex time: times) {
8✔
261
        auto it = _data.find(time);
6✔
262
        if (it != _data.end() && !it->second.empty()) {
6✔
263
            for (auto const & mask: it->second) {
10✔
264
                target.addAtTime(time, mask, false);// Don't notify for each operation
6✔
265
                total_masks_moved++;
6✔
266
            }
267
            times_to_clear.push_back(time);
4✔
268
        }
269
    }
270

271
    // Then, clear all the times from source
272
    for (TimeFrameIndex time: times_to_clear) {
6✔
273
        (void)clearAtTime(time, false);// Don't notify for each operation
4✔
274
    }
275

276
    // Notify observers only once at the end if requested
277
    if (notify && total_masks_moved > 0) {
2✔
278
        target.notifyObservers();
2✔
279
        notifyObservers();
2✔
280
    }
281

282
    return total_masks_moved;
2✔
283
}
2✔
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