Easy3D 2.5.3
curve.h
1/********************************************************************
2 * Copyright (C) 2015 Liangliang Nan <liangliang.nan@gmail.com>
3 * https://3d.bk.tudelft.nl/liangliang/
4 *
5 * This file is part of Easy3D. If it is useful in your research/work,
6 * I would be grateful if you show your appreciation by citing it:
7 * ------------------------------------------------------------------
8 * Liangliang Nan.
9 * Easy3D: a lightweight, easy-to-use, and efficient C++ library
10 * for processing and rendering 3D data.
11 * Journal of Open Source Software, 6(64), 3255, 2021.
12 * ------------------------------------------------------------------
13 *
14 * Easy3D is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License Version 3
16 * as published by the Free Software Foundation.
17 *
18 * Easy3D is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ********************************************************************/
26
27#ifndef EASY3D_CORE_CURVE_H
28#define EASY3D_CORE_CURVE_H
29
30
31#include <vector>
32
33
34namespace easy3d {
35
40 namespace curve {
41
77 template<typename Point_t>
78 inline
79 void quadratic(const Point_t &A, const Point_t &B, const Point_t &C, std::vector<Point_t> &curve,
80 unsigned int bezier_steps = 4, bool include_end = false) {
81 typedef typename Point_t::FT FT;
82 for (unsigned int i = 0; i < bezier_steps; i++) {
83 const FT t = static_cast<FT>(i) / bezier_steps;
84 const Point_t U = (1.0 - t) * A + t * B;
85 const Point_t V = (1.0 - t) * B + t * C;
86 curve.push_back((1.0 - t) * U + t * V);
87 }
88
89 if (include_end)
90 curve.push_back(C);
91 }
92
129 template<typename Point_t>
130 inline
131 void cubic(const Point_t &A, const Point_t &B, const Point_t &C, const Point_t &D, std::vector<Point_t> &curve,
132 unsigned int bezier_steps = 4, bool include_end = false) {
133 typedef typename Point_t::FT FT;
134 for (unsigned int i = 0; i < bezier_steps; i++) {
135 const FT t = static_cast<FT>(i) / bezier_steps;
136 const Point_t U = (1.0 - t) * A + t * B;
137 const Point_t V = (1.0 - t) * B + t * C;
138 const Point_t W = (1.0 - t) * C + t * D;
139 const Point_t M = (1.0 - t) * U + t * V;
140 const Point_t N = (1.0 - t) * V + t * W;
141 curve.push_back((1.0 - t) * M + t * N);
142 }
143 if (include_end)
144 curve.push_back(D);
145 }
146
147 }
148
149
150 // =============================================================================
151
152
158 template<typename Point_t>
159 class Curve {
160 public:
162 typedef typename Point_t::FT FT;
163 public:
165 Curve() : steps_(10) {}
166
168 void set_steps(int steps) { steps_ = steps; }
169
171 void add_way_point(const Point_t &point) {
172 way_points_.push_back(point);
173 on_way_point_added();
174 }
175
177 int node_count() const { return static_cast<int>(nodes_.size()); }
178
180 const Point_t &node(int i) const { return nodes_[i]; }
181
183 FT length_from_start_point(int i) const { return distances_[i]; }
184
186 FT total_length() const {
187 assert(!distances_.empty());
188 return distances_.back();
189 }
190
192 void clear() {
193 nodes_.clear();
194 way_points_.clear();
195 distances_.clear();
196 }
197
198 protected:
199 void add_node(const Point_t &node) {
200 nodes_.push_back(node);
201 if (nodes_.size() == 1)
202 distances_.push_back(0);
203 else {
204 int new_node_index = nodes_.size() - 1;
205 FT segment_distance = distance(nodes_[new_node_index], nodes_[new_node_index - 1]);
206 distances_.push_back(segment_distance + distances_[new_node_index - 1]);
207 }
208 }
209
210 virtual void on_way_point_added() = 0;
211
212 virtual Point_t
213 interpolate(FT u, const Point_t &P0, const Point_t &P1, const Point_t &P2, const Point_t &P3) const = 0;
214
215 protected:
216 int steps_;
217 std::vector<Point_t> way_points_;
218 std::vector<Point_t> nodes_;
219 std::vector<FT> distances_;
220 };
221
236 template<typename Point_t>
237 class Bezier : public Curve<Point_t> {
238 public:
240 typedef typename Point_t::FT FT;
241 public:
243 Bezier() = default;
244
245 protected:
249
250 void on_way_point_added() override {
251 if (way_points_.size() < 4)
252 return;
253 int new_control_point_index = way_points_.size() - 1;
254 if (new_control_point_index == 3) {
255 for (int i = 0; i <= steps_; i++) {
256 FT u = (FT) i / (FT) steps_;
257 add_node(interpolate(u, way_points_[0], way_points_[1], way_points_[2], way_points_[3]));
258 }
259 } else {
260 if (new_control_point_index % 2 == 0)
261 return;
262 int pt = new_control_point_index - 2;
263 for (int i = 0; i <= steps_; i++) {
264 FT u = (FT) i / (FT) steps_;
265 Point_t point4 = 2 * way_points_[pt] - way_points_[pt - 1];
266 add_node(interpolate(u, way_points_[pt], point4, way_points_[pt + 1], way_points_[pt + 2]));
267 }
268 }
269 }
270
271 Point_t interpolate(FT u, const Point_t &P0, const Point_t &P1, const Point_t &P2,
272 const Point_t &P3) const override {
273 Point_t point;
274 point = u * u * u * ((-1) * P0 + 3 * P1 - 3 * P2 + P3);
275 point += u * u * (3 * P0 - 6 * P1 + 3 * P2);
276 point += u * ((-3) * P0 + 3 * P1);
277 point += P0;
278 return point;
279 }
280 };
281
282
297 template<typename Point_t>
298 class BSpline : public Curve<Point_t> {
299 public:
301 typedef typename Point_t::FT FT;
302 public:
304 BSpline() = default;
305
306 protected:
310
311 void on_way_point_added() override {
312 if (way_points_.size() < 4)
313 return;
314 int new_control_point_index = static_cast<int>(way_points_.size()) - 1;
315 int pt = new_control_point_index - 3;
316 for (int i = 0; i <= steps_; i++) {
317 FT u = (FT) i / (FT) steps_;
318 add_node(interpolate(u, way_points_[pt], way_points_[pt + 1], way_points_[pt + 2],
319 way_points_[pt + 3]));
320 }
321 }
322
323 Point_t interpolate(FT u, const Point_t &P0, const Point_t &P1, const Point_t &P2,
324 const Point_t &P3) const override {
325 Point_t point;
326 point = u * u * u * ((-1) * P0 + 3 * P1 - 3 * P2 + P3) / 6;
327 point += u * u * (3 * P0 - 6 * P1 + 3 * P2) / 6;
328 point += u * ((-3) * P0 + 3 * P2) / 6;
329 point += (P0 + 4 * P1 + P2) / 6;
330
331 return point;
332 }
333
334 };
335
336
351 template<typename Point_t>
352 class CatmullRom : public Curve<Point_t> {
353 public:
355 typedef typename Point_t::FT FT;
356 public:
358 CatmullRom() = default;
359
360 protected:
364
365 void on_way_point_added() override {
366 if (way_points_.size() < 4)
367 return;
368 int new_control_point_index = way_points_.size() - 1;
369 int pt = new_control_point_index - 2;
370 for (int i = 0; i <= steps_; i++) {
371 FT u = (FT) i / (FT) steps_;
372 add_node(interpolate(u, way_points_[pt - 1], way_points_[pt], way_points_[pt + 1],
373 way_points_[pt + 2]));
374 }
375 }
376
377 Point_t interpolate(FT u, const Point_t &P0, const Point_t &P1, const Point_t &P2,
378 const Point_t &P3) const override {
379 Point_t point;
380 point = u * u * u * ((-1) * P0 + 3 * P1 - 3 * P2 + P3) / 2;
381 point += u * u * (2 * P0 - 5 * P1 + 4 * P2 - P3) / 2;
382 point += u * ((-1) * P0 + P2) / 2;
383 point += P1;
384 return point;
385 }
386
387 };
388
389} // namespace easy3d
390
391
392#endif // EASY3D_CORE_CURVE_H
Class for BSpline curve fitting. Works for both 2D and 3D. Example:
Definition: curve.h:298
BSpline()=default
Default constructor.
Point_t::FT FT
The floating-point number type.
Definition: curve.h:301
Class for Bezier curve fitting. Works for both 2D and 3D. Example:
Definition: curve.h:237
Bezier()=default
Default constructor.
Point_t::FT FT
The floating-point number type.
Definition: curve.h:240
Class for CatmullRom curve interpolation. Works for both 2D and 3D. Example:
Definition: curve.h:352
CatmullRom()=default
Default constructor.
Point_t::FT FT
The floating-point number type.
Definition: curve.h:355
Base class for curve fitting/interpolation.
Definition: curve.h:159
void set_steps(int steps)
Set the number of steps.
Definition: curve.h:168
FT total_length() const
Return the total length of the curve.
Definition: curve.h:186
int node_count() const
Return the number of nodes.
Definition: curve.h:177
FT length_from_start_point(int i) const
Return the total curve length from the start point.
Definition: curve.h:183
Curve()
Default constructor.
Definition: curve.h:165
Point_t::FT FT
The floating-point number type.
Definition: curve.h:162
void add_way_point(const Point_t &point)
Add a way point.
Definition: curve.h:171
void clear()
Clear all cached values.
Definition: curve.h:192
const Point_t & node(int i) const
Return the coordinates of the i_th node.
Definition: curve.h:180
void quadratic(const Point_t &A, const Point_t &B, const Point_t &C, std::vector< Point_t > &curve, unsigned int bezier_steps=4, bool include_end=false)
De Casteljau algorithm evaluating a quadratic or conic (second degree) curve from the given control p...
Definition: curve.h:79
void cubic(const Point_t &A, const Point_t &B, const Point_t &C, const Point_t &D, std::vector< Point_t > &curve, unsigned int bezier_steps=4, bool include_end=false)
De Casteljau algorithm evaluating a cubic (third degree) curve from the given control points A,...
Definition: curve.h:131
Definition: collider.cpp:182
T distance(const Vec< N, T > &v1, const Vec< N, T > &v2)
Computes the distance between two vectors/points.
Definition: vec.h:295