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

paulmthompson / WhiskerToolbox / 17846711083

19 Sep 2025 02:28AM UTC coverage: 72.02% (+0.08%) from 71.942%
17846711083

push

github

paulmthompson
event in interval computer works with entity ids

259 of 280 new or added lines in 6 files covered. (92.5%)

268 existing lines in 17 files now uncovered.

40247 of 55883 relevant lines covered (72.02%)

1227.29 hits per line

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

81.2
/src/DataManager/utils/TableView/computers/LineSamplingMultiComputer.h
1
#ifndef LINE_SAMPLING_MULTI_COMPUTER_H
2
#define LINE_SAMPLING_MULTI_COMPUTER_H
3

4
#include "utils/TableView/interfaces/IMultiColumnComputer.h"
5
#include "utils/TableView/interfaces/ILineSource.h"
6
#include "utils/TableView/interfaces/IEntityProvider.h"
7
#include "CoreGeometry/line_geometry.hpp"
8

9
#include <memory>
10
#include <string>
11
#include <vector>
12

13
/**
14
 * @brief Multi-output computer that samples x and y at equally spaced positions along a line.
15
 *
16
 * Source type: ILineSource
17
 * Selector type: Timestamp
18
 * Output type: double
19
 * 
20
 * Given a line source and a Timestamp-based ExecutionPlan, divides the [0,1] fractional
21
 * length into (segments) equal parts, yielding (segments+1) sample positions. For each
22
 * position, outputs two columns: x and y, in that order, resulting in 2*(segments+1)
23
 * outputs.
24
 */
25
class LineSamplingMultiComputer : public IMultiColumnComputer<double> {
26
public:
27
    LineSamplingMultiComputer(std::shared_ptr<ILineSource> lineSource,
33✔
28
                              std::string sourceName,
29
                              std::shared_ptr<TimeFrame> sourceTimeFrame,
30
                              int segments)
31
        : m_lineSource(std::move(lineSource)),
33✔
32
          m_sourceName(std::move(sourceName)),
33✔
33
          m_sourceTimeFrame(std::move(sourceTimeFrame)),
33✔
34
          m_segments(segments < 1 ? 1 : segments) {}
33✔
35

36
    [[nodiscard]] auto computeBatch(ExecutionPlan const & plan) const -> std::vector<std::vector<double>> override {
11✔
37
        // Determine rows: entity-expanded rows take precedence
38
        std::vector<TimeFrameIndex> indices;
11✔
39
        std::vector<std::optional<int>> entityIdx;
11✔
40
        if (!plan.getRows().empty()) {
11✔
41
            auto const& rows = plan.getRows();
9✔
42
            indices.reserve(rows.size());
9✔
43
            entityIdx.reserve(rows.size());
9✔
44
            for (auto const& r : rows) {
61✔
45
                indices.push_back(r.timeIndex);
52✔
46
                entityIdx.push_back(r.entityIndex);
52✔
47
            }
48
        } else if (plan.hasIndices()) {
2✔
49
            indices = plan.getIndices();
2✔
50
            entityIdx.resize(indices.size());
2✔
51
        } else {
52
            auto const & intervals = plan.getIntervals();
×
53
            indices.reserve(intervals.size());
×
54
            entityIdx.reserve(intervals.size());
×
55
            for (auto const & interval : intervals) {
×
56
                indices.push_back(interval.start);
×
UNCOV
57
                entityIdx.emplace_back(std::nullopt);
×
58
            }
59
        }
60

61
        size_t const rowCount = indices.size();
11✔
62
        int const positions = m_segments + 1;
11✔
63
        int const outputs = positions * 2; // x then y per position
11✔
64

65
        std::vector<std::vector<double>> results(static_cast<size_t>(outputs));
33✔
66
        for (auto & vec : results) {
77✔
67
            vec.resize(rowCount);
66✔
68
        }
69

70
        // Precompute fractional positions
71
        std::vector<float> fractions;
11✔
72
        fractions.reserve(static_cast<size_t>(positions));
11✔
73
        for (int i = 0; i <= m_segments; ++i) {
44✔
74
            fractions.push_back(static_cast<float>(i) / static_cast<float>(m_segments));
33✔
75
        }
76

77
        // For each row, obtain the representative line and sample
78
        // Use the plan's timeframe (rows are expressed in this timeframe)
79
        auto targetTF = plan.getTimeFrame().get();
11✔
80

81
        for (size_t r = 0; r < rowCount; ++r) {
69✔
82
            TimeFrameIndex const tfIndex = indices[r];
58✔
83
            // Prefer direct entity access if entity index is present
84
            Line2D const* linePtr = nullptr;
58✔
85
            if (entityIdx[r].has_value()) {
58✔
86
                linePtr = m_lineSource->getLineAt(tfIndex, *entityIdx[r]);
49✔
87
            }
88
            Line2D lineFallback;
58✔
89
            if (!linePtr) {
58✔
90
                auto lines = m_lineSource->getLinesInRange(tfIndex, tfIndex, targetTF);
9✔
91
                if (lines.empty()) {
9✔
92
                    for (int p = 0; p < positions; ++p) {
16✔
93
                        results[static_cast<size_t>(2 * p)][r] = 0.0;
12✔
94
                        results[static_cast<size_t>(2 * p + 1)][r] = 0.0;
12✔
95
                    }
96
                    continue;
4✔
97
                }
4✔
98
                lineFallback = lines.front();
5✔
99
                linePtr = &lineFallback;
5✔
100
            }
9✔
101

102
            Line2D const & line = *linePtr;
54✔
103
            for (int p = 0; p < positions; ++p) {
219✔
104
                auto optPoint = point_at_fractional_position(line, fractions[static_cast<size_t>(p)], true);
165✔
105
                if (optPoint.has_value()) {
165✔
106
                    results[static_cast<size_t>(2 * p)][r] = static_cast<double>(optPoint->x);
165✔
107
                    results[static_cast<size_t>(2 * p + 1)][r] = static_cast<double>(optPoint->y);
165✔
108
                } else {
109
                    results[static_cast<size_t>(2 * p)][r] = 0.0;
×
UNCOV
110
                    results[static_cast<size_t>(2 * p + 1)][r] = 0.0;
×
111
                }
112
            }
113
        }
58✔
114

115
        return results;
22✔
116
    }
11✔
117

118
    [[nodiscard]] auto getOutputNames() const -> std::vector<std::string> override {
33✔
119
        std::vector<std::string> suffixes;
33✔
120
        int const positions = m_segments + 1;
33✔
121
        suffixes.reserve(static_cast<size_t>(positions * 2));
33✔
122
        for (int i = 0; i <= m_segments; ++i) {
128✔
123
            double frac = static_cast<double>(i) / static_cast<double>(m_segments);
95✔
124
            // Fixed width to 3 decimals for readability
125
            char buf[32];
95✔
126
            std::snprintf(buf, sizeof(buf), "@%.3f", frac);
95✔
127
            suffixes.emplace_back(std::string{".x"} + buf);
285✔
128
            suffixes.emplace_back(std::string{".y"} + buf);
285✔
129
        }
130
        return suffixes;
33✔
UNCOV
131
    }
×
132

133
    [[nodiscard]] auto getDependencies() const -> std::vector<std::string> override {
182✔
134
        return {};
182✔
135
    }
136

137
    [[nodiscard]] auto getSourceDependency() const -> std::string override {
385✔
138
        return m_sourceName;
385✔
139
    }
140

141
    [[nodiscard]] bool hasEntityIds() const override {
12✔
142
        return true;  // LineSamplingMultiComputer can provide EntityIDs from its line source
12✔
143
    }
144

145
    [[nodiscard]] ColumnEntityIds computeColumnEntityIds(ExecutionPlan const & plan) const override {
6✔
146
        // Extract the entity IDs based on the execution plan
147
        std::vector<TimeFrameIndex> indices;
6✔
148
        std::vector<std::optional<int>> entityIdx;
6✔
149
        
150
        if (!plan.getRows().empty()) {
6✔
151
            auto const& rows = plan.getRows();
6✔
152
            indices.reserve(rows.size());
6✔
153
            entityIdx.reserve(rows.size());
6✔
154
            for (auto const& r : rows) {
36✔
155
                indices.push_back(r.timeIndex);
30✔
156
                entityIdx.push_back(r.entityIndex);
30✔
157
            }
UNCOV
158
        } else if (plan.hasIndices()) {
×
UNCOV
159
            indices = plan.getIndices();
×
UNCOV
160
            entityIdx.resize(indices.size());
×
161
        } else {
UNCOV
162
            auto const & intervals = plan.getIntervals();
×
UNCOV
163
            indices.reserve(intervals.size());
×
UNCOV
164
            entityIdx.reserve(intervals.size());
×
UNCOV
165
            for (auto const & interval : intervals) {
×
UNCOV
166
                indices.push_back(interval.start);
×
UNCOV
167
                entityIdx.emplace_back(std::nullopt);
×
168
            }
169
        }
170

171
        std::vector<EntityId> result;
6✔
172
        result.reserve(indices.size());
6✔
173

174
        // Use the plan's timeframe (rows are expressed in this timeframe)
175
        auto targetTF = plan.getTimeFrame().get();
6✔
176

177
        for (size_t r = 0; r < indices.size(); ++r) {
36✔
178
            TimeFrameIndex const tfIndex = indices[r];
30✔
179
            
180
            // Get EntityID from the line source
181
            EntityId entityId = 0;  // Default to 0 (invalid)
30✔
182
            
183
            if (entityIdx[r].has_value()) {
30✔
184
                // We have a specific entity index, get its EntityID
185
                if (auto entityProvider = std::dynamic_pointer_cast<IEntityProvider>(m_lineSource)) {
30✔
186
                    entityId = entityProvider->getEntityIdAt(tfIndex, *entityIdx[r]);
30✔
187
                }
30✔
188
            } else {
189
                // No specific entity index, try to get the first entity at this timestamp
UNCOV
190
                if (auto entityProvider = std::dynamic_pointer_cast<IEntityProvider>(m_lineSource)) {
×
UNCOV
191
                    if (entityProvider->getEntityCountAt(tfIndex) > 0) {
×
UNCOV
192
                        entityId = entityProvider->getEntityIdAt(tfIndex, 0);
×
193
                    }
UNCOV
194
                }
×
195
            }
196
            
197
            result.push_back(entityId);
30✔
198
        }
199

200
        return result;
12✔
201
    }
6✔
202

203
private:
204
    std::shared_ptr<ILineSource> m_lineSource;
205
    std::string m_sourceName;
206
    std::shared_ptr<TimeFrame> m_sourceTimeFrame;
207
    int m_segments;
208
};
209

210
#endif // LINE_SAMPLING_MULTI_COMPUTER_H
211

212

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