• 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

0.0
/src/DataManager/transforms/Lines/line_point_extraction.cpp
1
#include "line_point_extraction.hpp"
2

3
#include "Lines/Line_Data.hpp"
4
#include "CoreGeometry/line_geometry.hpp"
5
#include "Points/Point_Data.hpp"
6
#include "utils/polynomial/parametric_polynomial_utils.hpp"
7
#include "utils/polynomial/polynomial_fit.hpp"
8

9

10
#include <algorithm>
11
#include <cmath>
12
#include <iostream>
13
#include <optional>
14
#include <vector>
15

16
/**
17
 * @brief Extract point using direct point selection based on distance
18
 */
19
std::optional<Point2D<float>> extract_direct_point(
×
20
        Line2D const & line,
21
        float position,
22
        bool use_interpolation) {
23
    
24
    // Use the new distance-based utility function
25
    return point_at_fractional_position(line, position, use_interpolation);
×
26
}
27

28
/**
29
 * @brief Extract point using parametric polynomial interpolation
30
 */
31
std::optional<Point2D<float>> extract_parametric_point(
×
32
        Line2D const & line,
33
        float position,
34
        int polynomial_order) {
35
    
36
    if (line.empty()) {
×
37
        return std::nullopt;
×
38
    }
39
    
40
    if (line.size() == 1) {
×
41
        return line[0];
×
42
    }
43
    
44
    // Ensure valid range
45
    position = std::max(0.0f, std::min(1.0f, position));
×
46
    
47
    // Need enough points for polynomial fitting
48
    if (line.size() < static_cast<size_t>(polynomial_order + 1)) {
×
49
        // Fall back to direct method
50
        return extract_direct_point(line, position, true);
×
51
    }
52
    
53
    // Compute t-values for the entire line
54
    std::vector<double> t_values = compute_t_values(line);
×
55
    if (t_values.empty()) {
×
56
        return extract_direct_point(line, position, true);
×
57
    }
58
    
59
    // Extract coordinates
60
    std::vector<double> x_coords, y_coords;
×
61
    x_coords.reserve(line.size());
×
62
    y_coords.reserve(line.size());
×
63
    
64
    for (auto const & point : line) {
×
65
        x_coords.push_back(static_cast<double>(point.x));
×
66
        y_coords.push_back(static_cast<double>(point.y));
×
67
    }
68
    
69
    // Fit parametric polynomials
70
    std::vector<double> x_coeffs = fit_single_dimension_polynomial_internal(x_coords, t_values, polynomial_order);
×
71
    std::vector<double> y_coeffs = fit_single_dimension_polynomial_internal(y_coords, t_values, polynomial_order);
×
72
    
73
    if (x_coeffs.empty() || y_coeffs.empty()) {
×
74
        // Fall back to direct method if fitting failed
75
        return extract_direct_point(line, position, true);
×
76
    }
77
    
78
    // Evaluate polynomials at the specified position
79
    double t_eval = static_cast<double>(position);
×
80
    double x = evaluate_polynomial(x_coeffs, t_eval);
×
81
    double y = evaluate_polynomial(y_coeffs, t_eval);
×
82
    
83
    return Point2D<float>{static_cast<float>(x), static_cast<float>(y)};
×
84
}
×
85

86
///////////////////////////////////////////////////////////////////////////////
87

88
std::shared_ptr<PointData> extract_line_point(
×
89
        LineData const * line_data,
90
        LinePointExtractionParameters const & params) {
91
    return extract_line_point(line_data, params, [](int){});
×
92
}
93

94
std::shared_ptr<PointData> extract_line_point(
×
95
        LineData const * line_data,
96
        LinePointExtractionParameters const & params,
97
        ProgressCallback progressCallback) {
98
    
99
    auto result_point_data = std::make_shared<PointData>();
×
100
    
101
    if (!line_data) {
×
102
        progressCallback(100);
×
103
        return result_point_data;
×
104
    }
105
    
106
    // Copy image size
107
    result_point_data->setImageSize(line_data->getImageSize());
×
108
    
109
    // Get all times with data for progress calculation
110
    auto times_with_data = line_data->getTimesWithData();
×
111
    if (times_with_data.empty()) {
×
112
        progressCallback(100);
×
113
        return result_point_data;
×
114
    }
115
    
116
    progressCallback(0);
×
117
    
118
    size_t processed_times = 0;
×
119
    for (auto time : times_with_data) {
×
120
        auto const & lines_at_time = line_data->getAtTime(time);
×
121
        
122
        // Process only the first line at each time point (similar to other line operations)
123
        if (!lines_at_time.empty()) {
×
124
            auto const & line = lines_at_time[0];
×
125
            
126
            if (!line.empty()) {
×
127
                std::optional<Point2D<float>> extracted_point;
×
128
                
129
                if (params.method == PointExtractionMethod::Direct) {
×
130
                    extracted_point = extract_direct_point(
×
131
                        line,
132
                        params.position,
×
133
                        params.use_interpolation
×
134
                    );
135
                } else { // Parametric
136
                    extracted_point = extract_parametric_point(
×
137
                        line,
138
                        params.position,
×
139
                        params.polynomial_order
×
140
                    );
141
                }
142
                
143
                if (extracted_point.has_value()) {
×
144
                    result_point_data->addAtTime(time, extracted_point.value(), false);
×
145
                }
146
            }
147
        }
148
        
149
        processed_times++;
×
150
        int progress = static_cast<int>(
NEW
151
            std::round(static_cast<double>(processed_times) / static_cast<double>(times_with_data.size()) * 100.0)
×
152
        );
×
153
        progressCallback(progress);
×
154
    }
155
    
156
    progressCallback(100);
×
157
    return result_point_data;
×
158
}
×
159

160
///////////////////////////////////////////////////////////////////////////////
161

162
std::string LinePointExtractionOperation::getName() const {
×
163
    return "Extract Point from Line";
×
164
}
165

166
std::type_index LinePointExtractionOperation::getTargetInputTypeIndex() const {
×
167
    return typeid(std::shared_ptr<LineData>);
×
168
}
169

170
bool LinePointExtractionOperation::canApply(DataTypeVariant const & dataVariant) const {
×
171
    if (!std::holds_alternative<std::shared_ptr<LineData>>(dataVariant)) {
×
172
        return false;
×
173
    }
174
    
175
    auto const * ptr_ptr = std::get_if<std::shared_ptr<LineData>>(&dataVariant);
×
176
    return ptr_ptr && *ptr_ptr;
×
177
}
178

179
std::unique_ptr<TransformParametersBase> LinePointExtractionOperation::getDefaultParameters() const {
×
180
    return std::make_unique<LinePointExtractionParameters>();
×
181
}
182

183
DataTypeVariant LinePointExtractionOperation::execute(DataTypeVariant const & dataVariant,
×
184
                                                     TransformParametersBase const * transformParameters) {
185
    return execute(dataVariant, transformParameters, [](int){});
×
186
}
187

188
DataTypeVariant LinePointExtractionOperation::execute(DataTypeVariant const & dataVariant,
×
189
                                                     TransformParametersBase const * transformParameters,
190
                                                     ProgressCallback progressCallback) {
191
    
192
    auto const * line_data_ptr = std::get_if<std::shared_ptr<LineData>>(&dataVariant);
×
193
    
194
    if (!line_data_ptr || !(*line_data_ptr)) {
×
195
        std::cerr << "LinePointExtractionOperation::execute called with incompatible variant type or null data." << std::endl;
×
196
        return {};
×
197
    }
198
    
199
    LineData const * input_line_data = (*line_data_ptr).get();
×
200
    
201
    LinePointExtractionParameters const * params = nullptr;
×
202
    std::unique_ptr<TransformParametersBase> default_params_owner;
×
203
    
204
    if (transformParameters) {
×
205
        params = dynamic_cast<LinePointExtractionParameters const *>(transformParameters);
×
206
        if (!params) {
×
207
            std::cerr << "LinePointExtractionOperation::execute: Invalid parameter type. Using defaults." << std::endl;
×
208
            default_params_owner = getDefaultParameters();
×
209
            params = static_cast<LinePointExtractionParameters const *>(default_params_owner.get());
×
210
        }
211
    } else {
212
        default_params_owner = getDefaultParameters();
×
213
        params = static_cast<LinePointExtractionParameters const *>(default_params_owner.get());
×
214
    }
215
    
216
    if (!params) {
×
217
        std::cerr << "LinePointExtractionOperation::execute: Failed to get parameters." << std::endl;
×
218
        return {};
×
219
    }
220
    
221
    std::shared_ptr<PointData> result = extract_line_point(input_line_data, *params, progressCallback);
×
222
    
223
    if (!result) {
×
224
        std::cerr << "LinePointExtractionOperation::execute: 'extract_line_point' failed to produce a result." << std::endl;
×
225
        return {};
×
226
    }
227
    
228
    std::cout << "LinePointExtractionOperation executed successfully." << std::endl;
×
229
    return result;
×
230
} 
×
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