RIT VEXU Core API
Loading...
Searching...
No Matches
spline_path.h
1#pragma once
2
3#include <algorithm>
4#include <functional>
5#include <memory>
6#include <vector>
7
8#include "core/math/spline/cubic_hermite_spline.h"
9#include "core/math/spline/quintic_hermite_spline.h"
10
15 public:
17 enum class Order {
18 Cubic = 3,
19 Quintic = 5,
20 };
21
23 SplinePath() = default;
24
33 const std::vector<HermitePoint>& points,
34 std::function<std::unique_ptr<SplineBase>(const HermitePoint&, const HermitePoint&, double)>
35 factory,
36 double max_err = 1e-4) {
37 SplinePath path;
38 if (points.size() < 2 || !factory) {
39 return path;
40 }
41
42 path.segments_.reserve(points.size() - 1);
43 path.segment_starts_.reserve(points.size() - 1);
44
45 double accum = 0.0;
46 for (size_t i = 0; i + 1 < points.size(); ++i) {
47 std::unique_ptr<SplineBase> segment = factory(points[i], points[i + 1], max_err);
48 if (!segment) continue;
49
50 path.segment_starts_.push_back(accum);
51 accum += segment->length();
52 path.segments_.push_back(std::move(segment));
53 }
54 path.total_length_ = accum;
55 return path;
56 }
57
66 static SplinePath from_hermite(const std::vector<HermitePoint>& points,
67 Order order = Order::Quintic, double max_err = 1e-4) {
68 return from_waypoints(
69 points,
70 [order](const HermitePoint& start, const HermitePoint& end,
71 double max_err) -> std::unique_ptr<SplineBase> {
72 if (order == Order::Cubic) {
73 return std::unique_ptr<SplineBase>(new CubicHermiteSpline(start, end, max_err));
74 } else {
75 return std::unique_ptr<SplineBase>(new QuinticHermiteSpline(start, end, max_err));
76 }
77 },
78 max_err);
79 }
80
82 bool empty() const { return segments_.empty(); }
83
85 size_t segment_count() const { return segments_.size(); }
86
88 double length() const { return total_length_; }
89
96 SplineSample sample_by_s(double s) const {
97 if (segments_.empty()) {
98 return {};
99 }
100 if (s <= 0.0) {
101 SplineSample out = segments_.front()->sample_by_s(0.0);
102 out.s = 0.0;
103 return out;
104 }
105 if (s >= total_length_) {
106 SplineSample out = segments_.back()->sample_by_s(segments_.back()->length());
107 out.s = total_length_;
108 return out;
109 }
110
111 const size_t idx = segment_index_for_s(s);
112 const double local_s = s - segment_starts_[idx];
113 SplineSample out = segments_[idx]->sample_by_s(local_s);
114 out.s = s;
115 return out;
116 }
117
123 std::vector<Translation2d> sample_by_spacing(double ds) const {
124 std::vector<Translation2d> points;
125 if (segments_.empty() || ds <= 0.0) {
126 return points;
127 }
128 for (double s = 0.0; s < total_length_; s += ds) {
129 points.push_back(sample_by_s(s).position);
130 }
131 points.push_back(sample_by_s(total_length_).position);
132 return points;
133 }
134
140 std::vector<Translation2d> sample_by_segment_steps(double steps_per_segment) const {
141 std::vector<Translation2d> points;
142 if (segments_.empty() || steps_per_segment <= 0.0) {
143 return points;
144 }
145
146 const int sample_count = static_cast<int>(steps_per_segment);
147 if (sample_count <= 0) {
148 return points;
149 }
150
151 for (size_t i = 0; i < segments_.size(); ++i) {
152 for (int step = 0; step < sample_count; ++step) {
153 const double u = static_cast<double>(step) / static_cast<double>(sample_count);
154 points.push_back(segments_[i]->position(u));
155 }
156 }
157 points.push_back(segments_.back()->position(1.0));
158 return points;
159 }
160
161 private:
162 size_t segment_index_for_s(double s) const {
163 auto upper = std::upper_bound(segment_starts_.begin(), segment_starts_.end(), s);
164 if (upper == segment_starts_.begin()) {
165 return 0;
166 }
167 size_t idx = static_cast<size_t>((upper - segment_starts_.begin()) - 1);
168 if (idx >= segments_.size()) {
169 idx = segments_.size() - 1;
170 }
171 return idx;
172 }
173
174 std::vector<std::unique_ptr<SplineBase>> segments_;
175 std::vector<double> segment_starts_;
176 double total_length_ = 0.0;
177};
CubicHermiteSpline()=default
Default constructor.
QuinticHermiteSpline()=default
Default constructor.
static SplinePath from_hermite(const std::vector< HermitePoint > &points, Order order=Order::Quintic, double max_err=1e-4)
Constructs a multi-segment path from a vector of Hermite waypoints.
Definition spline_path.h:66
SplinePath()=default
Default constructor.
double length() const
Definition spline_path.h:88
bool empty() const
Definition spline_path.h:82
static SplinePath from_waypoints(const std::vector< HermitePoint > &points, std::function< std::unique_ptr< SplineBase >(const HermitePoint &, const HermitePoint &, double)> factory, double max_err=1e-4)
Constructs a multi-segment path using a custom Spline factory.
Definition spline_path.h:32
std::vector< Translation2d > sample_by_spacing(double ds) const
Samples 2D positions uniformly spaced by distance ds along the path.
Definition spline_path.h:123
SplineSample sample_by_s(double s) const
Samples complete state at arc distance s along the multi-segment path.
Definition spline_path.h:96
std::vector< Translation2d > sample_by_segment_steps(double steps_per_segment) const
Samples 2D positions with fixed number of steps per spline segment.
Definition spline_path.h:140
Order
Order of spline polynomials used per segment.
Definition spline_path.h:17
@ Quintic
Quintic Hermite splines (C2 continuity).
Definition spline_path.h:19
@ Cubic
Cubic Hermite splines (C1 continuity).
Definition spline_path.h:18
size_t segment_count() const
Definition spline_path.h:85
Represents a boundary point along a Hermite spline.
Definition hermite_point.h:16
Evaluated state sample at a specific parameter u or distance s along a spline.
Definition spline_base.h:14
double s
Arc length along spline from start in inches.
Definition spline_base.h:16