Orbiter 2022
Combinatorial Objects
parametric_curve.cpp
Go to the documentation of this file.
1/*
2 * parametric_curve.cpp
3 *
4 * Created on: Apr 16, 2020
5 * Author: betten
6 */
7
8
9
10
11#include "foundations.h"
12
13
14using namespace std;
15
16
17namespace orbiter {
18namespace layer1_foundations {
19namespace graphics {
20
21
23{
24 nb_dimensions = 0;
26 t0 = 0;
27 t1 = 0; // parameter interval
29 extra_data = 0;
30 boundary = 0;
31
32 nb_pts = 0;
33
34}
35
37{
38}
39
40void parametric_curve::init(int nb_dimensions,
41 double desired_distance,
42 double t0, double t1,
43 int (*compute_point_function)(double t, double *pt, void *extra_data, int verbose_level),
44 void *extra_data,
45 double boundary,
46 int N,
47 int verbose_level)
48{
49 int f_v = (verbose_level >= 1);
50 double t, d, dt, t_last, tf;
51 double *coords0;
52 double *coords;
53 numerics Num;
54 int f_is_valid;
55 double epsilon = 0.0001;
56
57 if (f_v) {
58 cout << "parametric_curve::init" << endl;
59 }
67 if (f_v) {
68 cout << "parametric_curve::init nb_dimensions=" << nb_dimensions << endl;
69 cout << "parametric_curve::init desired_distance=" << desired_distance << endl;
70 cout << "parametric_curve::init boundary=" << boundary << endl;
71 cout << "parametric_curve::init t0=" << t0 << endl;
72 cout << "parametric_curve::init t1=" << t1 << endl;
73 cout << "parametric_curve::init N=" << N << endl;
74 }
75 dt = (t1 - t0) / N;
76 if (f_v) {
77 cout << "parametric_curve::init dt=" << dt << endl;
78 }
79#if 0
80 if (nb_dimensions != 2) {
81 cout << "parametric_curve::init nb_dimensions != 2" << endl;
82 exit(1);
83 }
84#endif
85
86 coords = new double[nb_dimensions];
87 coords0 = new double[nb_dimensions];
88
89 t = t0;
90
91 if (f_v) {
92 cout << "parametric_curve::init computing value at t=" << setw(8) << t << endl;
93 }
94 f_is_valid = (*compute_point_function)(t, coords, extra_data, verbose_level);
95 if (f_v) {
96 cout << "parametric_curve::init computing value at t=" << setw(8) << t << " done" << endl;
97 }
98 if (f_is_valid) {
99 d = Num.distance_from_origin(coords, nb_dimensions);
100 if (f_v) {
101 cout << "created point t=" << setw(8) << t << " = (" << coords[0] << "," << coords[1] << ")" << endl;
102 }
103 }
104 else {
105 d = 0;
106 if (f_v) {
107 cout << "invalid starting point" << endl;
108 }
109 }
110
111 if (!f_is_valid || d > boundary) {
112 if (f_v) {
113 cout << "parametric_curve::init d > boundary, performing a search for the starting value of t" << endl;
114 cout << "d=" << d << endl;
115 cout << "boundary=" << boundary << endl;
116 }
117 double tl, tr, tm;
118 double epsilon = 0.0001;
119 tl = t;
120 tr = t;
121 while (TRUE) {
122 tr = tr + dt;
123
124 if (f_v) {
125 cout << "parametric_curve::init computing value at tr=" << setw(8) << tr << endl;
126 }
127 f_is_valid = (*compute_point_function)(tr, coords, extra_data, 0 /*verbose_level*/);
128 if (f_v) {
129 cout << "parametric_curve::init computing value at tr=" << setw(8) << tr << " done" << endl;
130 }
131
132 if (f_is_valid) {
133 d = Num.distance_from_origin(coords, nb_dimensions);
134 }
135 else {
136 d = 0;
137 }
138 if (f_is_valid && d < boundary) {
139 break;
140 }
141 }
142 if (f_v) {
143 cout << "performing a search for the starting value of t in the interval tl=" << tl << ", tr=" << tr << endl;
144 }
145
146 while (ABS(tr - tl) > epsilon) {
147 tm = (tl + tr) * 0.5;
148
149
150 if (f_v) {
151 cout << "parametric_curve::init computing value at tm=" << setw(8) << tm << endl;
152 }
153 f_is_valid = (*compute_point_function)(tm, coords, extra_data, 0 /*verbose_level*/);
154 if (f_v) {
155 cout << "parametric_curve::init computing value at tm=" << setw(8) << tm << " done" << endl;
156 }
157
158 if (f_is_valid) {
159 d = Num.distance_from_origin(coords, nb_dimensions);
160 }
161 else {
162 d = 0;
163 }
164 if (f_is_valid && d < boundary) {
165 tr = tm;
166 }
167 else {
168 tl = tm;
169 }
170 }
171 t = tr;
172 if (f_v) {
173 cout << "created starting value t=" << setw(8) << t << endl;
174 }
175 }
176
177 if (f_v) {
178 cout << "parametric_curve::init computing value at t=" << setw(8) << t << endl;
179 }
180 f_is_valid = (*compute_point_function)(t, coords, extra_data, 0 /*verbose_level*/);
181 if (f_v) {
182 cout << "parametric_curve::init computing value at t=" << setw(8) << t << " done" << endl;
183 }
184
185 if (f_is_valid) {
186 d = Num.distance_from_origin(coords, nb_dimensions);
187 }
188 else {
189 cout << "the initial point is invalid" << endl;
190 exit(1);
191 }
192
193 if (f_v) {
194 cout << "created point t=" << setw(8) << t << " = (" << coords[0] << "," << coords[1] << ")" << endl;
195 }
196
197
198
199 vector<parametric_curve_point> Future;
200
201 {
203 if (f_v) {
204 cout << "adding point " << Pts.size() << endl;
205 }
206 Pt.init(t, f_is_valid, coords, nb_dimensions, verbose_level);
207 Pts.push_back(Pt);
208 }
209
210 int f_success;
211
212 while (t < t1) {
213 t_last = t;
214
215 if (f_v) {
216 cout << "t_last = " << setw(8) << t_last << " Future.size() = " << Future.size() << endl;
217 }
218 if (Future.size()) {
219 f_success = FALSE;
220 while (Future.size()) {
221 if (!Future[Future.size() - 1].f_is_valid) {
222 break;
223 }
224 tf = Future[Future.size() - 1].t;
225 Future.pop_back();
226 if (tf > t_last) {
227 t = (t_last + tf) * 0.5;
228 if (f_v) {
229 cout << "t_last = " << setw(8) << t_last << " t = " << setw(8) << t << " tf=" << setw(8) << tf << endl;
230 }
231 f_success = TRUE;
232 if (f_v) {
233 cout << "t_last = " << setw(8) << t_last << " tf = " << setw(8) << tf << " t = " << setw(8) << t << " popped from Future" << endl;
234 }
235 break;
236 }
237 }
238 if (!f_success) {
239 if (f_v) {
240 cout << "no success, moving on by dt, clearing Future" << endl;
241 }
242 t += dt;
243 while (Future.size()) {
244 Future.pop_back();
245 }
246 if (f_v) {
247 cout << "t_last = " << setw(8) << t_last << " t = " << setw(8) << t << endl;
248 }
249 }
250 }
251 else {
252 t += dt;
253 f_success = TRUE;
254 }
255
256 if (ABS(t_last - t) < epsilon) {
257 cout << "t_last == t" << endl;
258 cout << "t_last = " << setw(8) << t_last << endl;
259 cout << "adding dt" << endl;
260 t += dt;
261 f_success = FALSE;
262 }
263#if 0
264 if (ABS(t - t_last) < epsilon) {
265 if (f_v) {
266 cout << "no success, ABS(t - t_last) < epsilon, ABS(t - t_last)=" << ABS(t - t_last) << endl;
267 }
268 f_success = FALSE;
269 }
270#endif
271 if (f_v) {
272 cout << "t_last = " << setw(8) << t_last << " t = " << setw(8) << t << endl;
273 cout << "t = " << setw(8) << t << " t1 = " << t1 << endl;
274 cout << "t - t_last = " << setw(8) << t - t_last << endl;
275 }
276 if (t > t1) {
277 if (f_v) {
278 cout << "t > t1, break" << endl;
279 }
280 break;
281 }
282
283 if (f_v) {
284 cout << "parametric_curve::init computing value at t=" << setw(8) << t << endl;
285 }
286 f_is_valid = (*compute_point_function)(t, coords, extra_data, 0 /*verbose_level*/);
287 if (f_v) {
288 cout << "parametric_curve::init computing value at t=" << setw(8) << t << " done" << endl;
289 }
290
291 if (f_is_valid) {
292 int h;
293
294 for (h = 0; h < nb_dimensions; h++) {
295 coords0[h] = Pts[Pts.size() - 1].coords[h];
296 }
297 if (f_v) {
298 cout << "t_last = " << setw(8) << t_last << " : (" << coords0[0] << "," << coords0[1] << ")" << endl;
299 }
300 d = Num.distance_euclidean(coords0, coords, nb_dimensions);
301 if (f_v) {
302 cout << "t = " << setw(8) << t << " d = " << d << endl;
303 }
304 }
305 if (f_success && (!f_is_valid || d > desired_distance)) {
306
307
308 if (f_v) {
309 cout << "t=" << setw(8) << t << " d > desired_distance, pushing to Future, moving back to t_last" << setw(8) << t_last << endl;
310 }
311
312 {
314 Pt.init(t, f_is_valid, coords, nb_dimensions, verbose_level);
315 if (Future.size()) {
316 cout << "top element of Future stack is t=" << setw(8) << Future[Future.size() - 1].t << " we are pushing " << t << endl;
317 }
318 Future.push_back(Pt);
319 }
320
321 t = t_last;
322
323 if ((int) Future.size() > N) {
324 if (f_v) {
325 cout << "Future.size() > N, popping stack" << endl;
326 }
327 t = Future[0].t;
328 while (Future.size() > 0) {
329 Future.pop_back();
330 }
331 cout << "after popping stack, Future.size() = " << Future.size() << ", t = " << setw(8) << t << endl;
332 if (t < t_last) {
333 t = t_last;
334 }
335 }
336
337 }
338 else {
339 if (f_v) {
340 cout << "t=" << setw(8) << t << " d < desired_distance, valid point" << endl;
341 }
342
343 d = Num.distance_from_origin(coords, nb_dimensions);
344
345 if (f_v) {
346 cout << "created point t=" << setw(8) << t << " = (" << coords[0] << "," << coords[1] << ") with distance from origin " << d << endl;
347 }
348
349 if (d < boundary) {
350 int h;
351
352 {
354 if (f_v) {
355 cout << "adding point " << Pts.size() << endl;
356 }
357 Pt.init(t, f_is_valid, coords, nb_dimensions, verbose_level);
358 Pts.push_back(Pt);
359 }
360
361 for (h = 0; h < nb_dimensions; h++) {
362 coords0[h] = Pts[Pts.size() - 1].coords[h];
363 }
364 cout << "created point " << coords0[0] << "," << coords0[1] << endl;
365 }
366 else {
367 cout << "skipping" << endl;
368 }
369 if (Future.size()) {
370 int h;
371
372 for (h = 0; h < nb_dimensions; h++) {
373 coords0[h] = Future[Future.size() - 1].coords[h];
374 }
375 d = Num.distance_euclidean(coords0, coords, nb_dimensions);
376 if (d < desired_distance) {
377 Future.pop_back();
378 }
379 }
380 }
381 }
382
383
384 delete [] coords;
385 delete [] coords0;
386
387 if (f_v) {
388 cout << "parametric_curve::init done" << endl;
389 }
390}
391
392
393}}}
394
395
an individual point on a continuous curve, sampled through parametric_curve
Definition: graphics.h:920
void init(double t, int f_is_valid, double *x, int nb_dimensions, int verbose_level)
void init(int nb_dimensions, double desired_distance, double t0, double t1, int(*compute_point_function)(double t, double *pt, void *extra_data, int verbose_level), void *extra_data, double boundary, int N, int verbose_level)
int(* compute_point_function)(double t, double *pt, void *extra_data, int verbose_level)
Definition: graphics.h:945
std::vector< parametric_curve_point > Pts
Definition: graphics.h:950
numerical functions, mostly concerned with double
Definition: globals.h:129
double distance_euclidean(double *x, double *y, int len)
Definition: numerics.cpp:984
double distance_from_origin(double x1, double x2, double x3)
Definition: numerics.cpp:998
#define ABS(x)
Definition: foundations.h:220
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
the orbiter library for the classification of combinatorial objects