Easy3D 2.6.1
Loading...
Searching...
No Matches
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
104 template <template <size_t, class> class Point, size_t N, typename T>
105 void quadratic(const Point<N, T>& A, const Point<N, T>& B, const Point<N, T>& C,
106 std::vector<Point<N, T>>& curve, unsigned int bezier_steps = 4,
107 bool include_end = false)
108 {
109 using Point_t = Point<N, T>;
110 for (unsigned int i = 0; i <= bezier_steps; i++) { // i <= bezier_steps: to fully sample the curve
111 const T t = static_cast<T>(i) / bezier_steps;
112 const Point_t U = (1.0 - t) * A + t * B;
113 const Point_t V = (1.0 - t) * B + t * C;
114 curve.push_back((1.0 - t) * U + t * V);
115 }
116
117 if (include_end)
118 curve.push_back(C);
119 }
120
171 template <template <size_t, class> class Point, size_t N, typename T>
172 void cubic(const Point<N, T> &A, const Point<N, T> &B, const Point<N, T> &C, const Point<N, T> &D,
173 std::vector<Point<N, T>> &curve,
174 unsigned int bezier_steps = 4,
175 bool include_end = false)
176 {
177 using Point_t = Point<N, T>;
178 for (unsigned int i = 0; i <= bezier_steps; i++) { // i <= bezier_steps: to fully sample the curve
179 const T t = static_cast<T>(i) / bezier_steps;
180 const Point_t U = (1.0 - t) * A + t * B;
181 const Point_t V = (1.0 - t) * B + t * C;
182 const Point_t W = (1.0 - t) * C + t * D;
183 const Point_t P = (1.0 - t) * U + t * V;
184 const Point_t Q = (1.0 - t) * V + t * W;
185 curve.push_back((1.0 - t) * P + t * Q);
186 }
187 if (include_end)
188 curve.push_back(D);
189 }
190
191 }
192
193 // =============================================================================
194
195
206 template<template <size_t, class> class Point, size_t N, typename T>
207 class Curve {
208 public:
210 using Point_t = Point<N, T>;
211
218 virtual std::vector<Point_t> generate(const std::vector<Point_t> &control_points, size_t num_samples) const = 0;
219 };
220
237 template<template <size_t, class> class Point, size_t N, typename T>
238 class Bezier : public Curve<Point, N, T> {
239 public:
241 using Point_t = Point<N, T>;
242
244 Bezier() = default;
245
252 std::vector<Point_t> generate(const std::vector<Point_t> &control_points, size_t num_samples) const override {
253 std::vector<Point_t> curve;
254 curve.reserve(num_samples + 1); // Reserve space to avoid reallocations
255
256 for (size_t i = 0; i <= num_samples; ++i) {
257 T t = static_cast<T>(i) / num_samples;
258 curve.push_back(interpolate(control_points, t));
259 }
260 return curve;
261 }
262
263 private:
264 Point_t interpolate(const std::vector<Point_t> &control_points, T t) const {
265 std::vector<Point_t> points = control_points; // Copy control points
266 size_t n = points.size();
267 for (size_t k = 1; k < n; ++k) {
268 for (size_t i = 0; i < n - k; ++i) {
269 points[i] = points[i] * (1 - t) + points[i + 1] * t;
270 }
271 }
272 return points[0];
273 }
274 };
275
292 template<template <size_t, class> class Point, size_t N, typename T>
293 class BSpline : public Curve<Point, N, T> {
294 public:
296 using Point_t = Point<N, T>;
297
299 BSpline() = default;
300
307 std::vector<Point_t> generate(const std::vector<Point_t> &control_points, size_t num_samples) const override {
308 std::vector<Point_t> curve;
309 size_t n = control_points.size();
310 if (n < 4)
311 return curve;
312
313 curve.reserve(num_samples + 1); // Reserve space to avoid reallocations
314
315 // Sample the curve
316 for (size_t i = 0; i <= num_samples; ++i) {
317 T t = static_cast<T>(i) / num_samples * (n - 3);
318 size_t k = static_cast<size_t>(t);
319 t -= k;
320
321 // Ensure k is within the valid range
322 if (k >= n - 3) {
323 k = n - 4;
324 t = 1.0;
325 }
326
327 // Evaluate using a proper B-spline basis
328 curve.push_back(interpolate(control_points, t, k));
329 }
330 return curve;
331 }
332
333 private:
334 Point_t interpolate(const std::vector<Point_t> &control_points, T t, size_t k) const {
335 const T one_sixth = static_cast<T>(1) / 6;
336 Point_t P0 = control_points[k];
337 Point_t P1 = control_points[k + 1];
338 Point_t P2 = control_points[k + 2];
339 Point_t P3 = control_points[k + 3];
340
341 T t2 = t * t;
342 T t3 = t2 * t;
343
344 return (P0 * (-t3 + 3 * t2 - 3 * t + 1) * one_sixth) +
345 (P1 * (3 * t3 - 6 * t2 + 4) * one_sixth) +
346 (P2 * (-3 * t3 + 3 * t2 + 3 * t + 1) * one_sixth) +
347 (P3 * (t3) * one_sixth);
348 }
349 };
350
367 template<template <size_t, class> class Point, size_t N, typename T>
368 class CatmullRom : public Curve<Point, N, T> {
369 public:
371 using Point_t = Point<N, T>;
372
374 CatmullRom() = default;
375
382 std::vector<Point_t> generate(const std::vector<Point_t> &control_points, size_t num_samples) const override {
383 std::vector<Point_t> curve;
384 curve.reserve(num_samples + 1); // Reserve space to avoid reallocations
385
386 for (size_t i = 0; i <= num_samples; ++i) {
387 T t = static_cast<T>(i) / num_samples;
388 curve.push_back(interpolate(control_points, t));
389 }
390 return curve;
391 }
392
393 private:
394 Point_t interpolate(const std::vector<Point_t> &control_points, T t) const {
395 size_t n = control_points.size() - 3;
396 size_t i = std::min(static_cast<size_t>(t * n), n - 1);
397 T u = t * n - i;
398 Point_t P0 = control_points[i], P1 = control_points[i + 1], P2 = control_points[i + 2], P3 = control_points[
399 i + 3];
400 return ((P0 * (-1) + P1 * 3 - P2 * 3 + P3) * (u * u * u) / 2 +
401 (P0 * 2 - P1 * 5 + P2 * 4 - P3) * (u * u) / 2 +
402 (P0 * (-1) + P2) * u / 2 +
403 P1);
404 }
405 };
406
407} // namespace easy3d
408
409
410#endif // EASY3D_CORE_CURVE_H
Point< N, T > Point_t
The type of points.
Definition curve.h:296
BSpline()=default
Default constructor.
std::vector< Point_t > generate(const std::vector< Point_t > &control_points, size_t num_samples) const override
Generates a curve based on the given control points.
Definition curve.h:307
Bezier()=default
Default constructor.
Point< N, T > Point_t
The type of points.
Definition curve.h:241
std::vector< Point_t > generate(const std::vector< Point_t > &control_points, size_t num_samples) const override
Generates a curve based on the given control points.
Definition curve.h:252
Point< N, T > Point_t
The type of points.
Definition curve.h:371
CatmullRom()=default
Default constructor.
std::vector< Point_t > generate(const std::vector< Point_t > &control_points, size_t num_samples) const override
Generates a curve based on the given control points.
Definition curve.h:382
Abstract base class for curve fitting/interpolation.
Definition curve.h:207
Point< N, T > Point_t
The type of points.
Definition curve.h:210
virtual std::vector< Point_t > generate(const std::vector< Point_t > &control_points, size_t num_samples) const =0
Generates a curve based on the given control points.
Algorithms for evaluating curves.
void quadratic(const Point< N, T > &A, const Point< N, T > &B, const Point< N, T > &C, std::vector< Point< N, T > > &curve, unsigned int bezier_steps=4, bool include_end=false)
Computes a quadratic Bézier curve using De Casteljau’s algorithm.
Definition curve.h:105
void cubic(const Point< N, T > &A, const Point< N, T > &B, const Point< N, T > &C, const Point< N, T > &D, std::vector< Point< N, T > > &curve, unsigned int bezier_steps=4, bool include_end=false)
Evaluates a cubic Bézier curve using De Casteljau’s algorithm.
Definition curve.h:172
Definition collider.cpp:182