forked from NatronGitHub/Natron
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBezier.h
677 lines (542 loc) · 27.4 KB
/
Bezier.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
/* ***** BEGIN LICENSE BLOCK *****
* This file is part of Natron <https://natrongithub.github.io/>,
* (C) 2018-2021 The Natron developers
* (C) 2013-2018 INRIA and Alexandre Gauthier-Foichat
*
* Natron is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Natron is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Natron. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
* ***** END LICENSE BLOCK ***** */
#ifndef Engine_Bezier_h
#define Engine_Bezier_h
// ***** BEGIN PYTHON BLOCK *****
// from <https://docs.python.org/3/c-api/intro.html#include-files>:
// "Since Python may define some pre-processor definitions which affect the standard headers on some systems, you must include Python.h before any standard headers are included."
#include <Python.h>
// ***** END PYTHON BLOCK *****
#include "Global/Macros.h"
#include <list>
#include <set>
#include <string>
#include <utility>
#if !defined(Q_MOC_RUN) && !defined(SBK_RUN)
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#endif
CLANG_DIAG_OFF(deprecated-declarations)
#include <QtCore/QObject>
CLANG_DIAG_ON(deprecated-declarations)
#include "Global/GlobalDefines.h"
#include "Engine/RotoDrawableItem.h"
#include "Engine/ViewIdx.h"
#include "Engine/EngineFwd.h"
#define ROTO_BEZIER_EVAL_ITERATIVE
NATRON_NAMESPACE_ENTER
/**
* @class A base class for all items made by the roto context
**/
/**
* @class This class represents a bezier curve.
* Note that the bezier also supports feather points.
* This class is MT-safe
*
* The curve supports animation, and by default once the first control point is added the curve
* has at least a minimum of 1 keyframe.
**/
struct ParametricPoint
{
double x,y,t;
};
struct BezierPrivate;
class Bezier
: public RotoDrawableItem
{
GCC_DIAG_SUGGEST_OVERRIDE_OFF
Q_OBJECT
GCC_DIAG_SUGGEST_OVERRIDE_ON
public:
Bezier(const RotoContextPtr& context,
const std::string & name,
const RotoLayerPtr& parent,
bool isOpenBezier);
Bezier(const Bezier & other,
const RotoLayerPtr& parent);
virtual ~Bezier();
static
double bezierEval(double p0,
double p1,
double p2,
double p3,
double t);
static void bezierFullPoint(const Point & p0,
const Point & p1,
const Point & p2,
const Point & p3,
double t,
Point *p0p1,
Point *p1p2,
Point *p2p3,
Point *p0p1_p1p2,
Point *p1p2_p2p3,
Point *dest);
static void bezierPoint(const Point & p0,
const Point & p1,
const Point & p2,
const Point & p3,
double t,
Point *dest);
static void bezierPointBboxUpdate(const Point & p0,
const Point & p1,
const Point & p2,
const Point & p3,
RectD *bbox);
bool isOpenBezier() const;
/**
* @brief Used to differentiate real shapes with feather of paint strokes which does not have a feather
**/
virtual bool useFeatherPoints() const { return true; }
virtual void clone(const RotoItem* other) OVERRIDE;
void clearAllPoints();
/**
* @brief Adds a new control point to the curve. A feather point will be added, at the same position.
* If auto keying is enabled and this is the first point and there's no keyframe a new keyframe will be set at the current time.
*
* This function can only be called when the curved is not yet "finished". Once setCurveFinished has
* been called you can no longer call this function either. The only way to make it finished again
* is to call setCurveFinished. You can then add points normally with addControlPointAfterIndex
* This function is used to build-up the curve as opposed to addControlPointAfterIndex which is there to
* edit an already fully shaped spline.
**/
BezierCPPtr addControlPoint(double x, double y, double time);
/**
* @brief Adds a new control point to the curve after the control point at the given index.
* A feather point will be added, at the same position.
* If auto keying is enabled, and there's no keyframe a new keyframe will be set at the current time.
*
* If index is -1 then the point will be added as the first point of the curve.
* If index is invalid an invalid argument exception will be thrown.
**/
BezierCPPtr addControlPointAfterIndex(int index, double t);
/**
* @brief Returns the number of control points of the bezier
**/
int getControlPointsCount() const;
/**
* @brief Given the (x,y) coordinates of a point, this function returns whether a point lies on
* the cubic bezier curve of the feather points or of the control points or not.
* @returns The index of the starting control point (P0) of the bezier segment on which the given
* point lies. If the point doesn't belong to any bezier segment of this curve then it will return -1.
**/
int isPointOnCurve(double x, double y, double acceptance, double *t, bool* feather) const;
/**
* @brief Set whether the curve is finished or not. A finished curve will have an arc between the first
* and the last control point.
**/
void setCurveFinished(bool finished);
bool isCurveFinished() const;
/**
* @brief Removes the control point at the given index if any. The feather point will also be removed , at the same position.
* If auto keying is enabled, and there's no keyframe a new keyframe will be set at the current time.
**/
void removeControlPointByIndex(int index);
/**
* @brief Move the control point at the given index by the given dx and dy.
* If feather link is enabled, the feather point will also be moved by the same deltas.
* If there's no keyframe at the current time, a new keyframe will be added.
* This function asserts that auto-keying is enabled.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
**/
void movePointByIndex(int index, double time, double dx, double dy);
/**
* @brief Set the control point at the given index to x,y.
* If feather link is enabled, the feather point will also be moved by the same deltas.
* If there's no keyframe at the current time, a new keyframe will be added.
* This function asserts that auto-keying is enabled.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
**/
void setPointByIndex(int index, double time, double x, double y);
/**
* @brief Moves the feather point at the given index if any by the given dx and dy.
* If auto keying is enabled and there's no keyframe at the current time, a new keyframe will be added.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
**/
void moveFeatherByIndex(int index, double time, double dx, double dy);
private:
void movePointByIndexInternal(bool useGuiCurve, int index, double time, double dx, double dy, bool onlyFeather);
void setPointByIndexInternal(bool useGuiCurve, int index, double time, double dx, double dy);
public:
/**
* @brief Moves the left bezier point of the control point at the given index by the given deltas
* and at the given time.
* If auto keying is enabled and there's no keyframe at the current time, a new keyframe will be added.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
**/
void moveLeftBezierPoint(int index, double time, double dx, double dy);
/**
* @brief Moves the right bezier point of the control point at the given index by the given deltas
* and at the given time.
* If auto keying is enabled and there's no keyframe at the current time, a new keyframe will be added.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
**/
void moveRightBezierPoint(int index, double time, double dx, double dy);
private:
void moveBezierPointInternal(BezierCP* cpParam,
BezierCP* fpParam,
int index,
double time,
double lx, double ly, double rx, double ry,
double flx, double fly, double frx, double fry,
bool isLeft,
bool moveBoth,
bool breakTangents,
bool onlyFeather);
public:
/**
* @brief Transforms the given point at the given time by the given matrix.
**/
void transformPoint(const BezierCPPtr & point, double time, Transform::Matrix3x3* matrix);
/**
* @brief Provided for convenience. It set the left bezier point of the control point at the given index to
* the position given by (x,y) at the given time.
* If auto keying is enabled and there's no keyframe at the current time, a new keyframe will be added.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
* This function will also set the point of the feather point at the given x,y.
**/
void setLeftBezierPoint(int index, double time, double x, double y);
/**
* @brief Provided for convenience. It set the right bezier point of the control point at the given index to
* the position given by (x,y) at the given time.
* If auto keying is enabled and there's no keyframe at the current time, a new keyframe will be added.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
* This function will also set the point of the feather point at the given x,y.
**/
void setRightBezierPoint(int index, double time, double x, double y);
/**
* @brief This function is a combinaison of setPosition + setLeftBezierPoint / setRightBeziePoint
**/
void setPointAtIndex(bool feather, int index, double time, double x, double y, double lx, double ly, double rx, double ry);
private:
void setPointAtIndexInternal(bool setLeft, bool setRight, bool setPoint, bool feather, bool featherAndCp, int index, double time, double x, double y, double lx, double ly, double rx, double ry);
public:
/**
* @brief Set the left and right bezier point of the control point.
**/
void movePointLeftAndRightIndex(BezierCP & cp,
BezierCP & fp,
double time,
double lx, double ly, double rx, double ry,
double flx, double fly, double frx, double fry,
bool breakTangents,
bool onlyFeather);
/**
* @brief Removes the feather point at the given index by making it equal the "true" control point.
**/
void removeFeatherAtIndex(int index);
/**
* @brief Expand the feather point in the direction of the feather distance by the given distance.
**/
//void expandFeatherAtIndex(int index,double distance);
/**
* @brief Smooth the curvature of the bezier at the given index by expanding the tangents.
* This is also applied to the feather points.
* If auto keying is enabled and there's no keyframe at the current time, a new keyframe will be added.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
**/
void smoothPointAtIndex(int index, double time, const std::pair<double, double>& pixelScale);
/**
* @brief Cusps the curvature of the bezier at the given index by reducing the tangents.
* This is also applied to the feather points.
* If auto keying is enabled and there's no keyframe at the current time, a new keyframe will be added.
* If ripple edit is enabled, the point will be moved at the same location at all keyframes.
**/
void cuspPointAtIndex(int index, double time, const std::pair<double, double>& pixelScale);
void getMotionBlurSettings(const double time,
double* startTime,
double* endTime,
double* timeStep) const;
private:
void smoothOrCuspPointAtIndex(bool isSmooth, int index, double time, const std::pair<double, double>& pixelScale);
public:
/**
* @brief Set a new keyframe at the given time. If a keyframe already exists this function does nothing.
**/
void setKeyframe(double time);
/**
* @brief Removes a keyframe at the given time if any.
**/
void removeKeyframe(double time);
/**
* @brief Removes all animation
**/
void removeAnimation();
/**
* @brief Moves a keyframe
**/
void moveKeyframe(double oldTime, double newTime);
/**
* @brief Returns the number of keyframes for this spline.
**/
int getKeyframesCount() const;
static void deCastelJau(bool isOpenBezier,
bool useGuiCurves,
const std::list<BezierCPPtr>& cps, double time, unsigned int mipMapLevel,
bool finished,
int nBPointsPerSegment,
const Transform::Matrix3x3& transform,
std::list<std::list<ParametricPoint> >* points,
std::list<ParametricPoint >* pointsSingleList,
RectD* bbox);
static void point_line_intersection(const Point &p1,
const Point &p2,
const Point &pos,
int *winding);
/**
* @brief Evaluates the spline at the given time and returns the list of all the points on the curve.
* @param nbPointsPerSegment controls how many points are used to draw one Bezier segment
**/
void evaluateAtTime_DeCasteljau(bool useGuiCurves,
double time,
unsigned int mipMapLevel,
#ifdef ROTO_BEZIER_EVAL_ITERATIVE
int nbPointsPerSegment,
#else
double errorScale,
#endif
std::list<std::list<ParametricPoint> >* points,
RectD* bbox) const;
void evaluateAtTime_DeCasteljau(bool useGuiCurves,
double time,
unsigned int mipMapLevel,
#ifdef ROTO_BEZIER_EVAL_ITERATIVE
int nbPointsPerSegment,
#else
double errorScale,
#endif
std::list<ParametricPoint >* points,
RectD* bbox) const;
private:
void evaluateAtTime_DeCasteljau_internal(bool useGuiCurves,
double time,
unsigned int mipMapLevel,
#ifdef ROTO_BEZIER_EVAL_ITERATIVE
int nbPointsPerSegment,
#else
double errorScale,
#endif
std::list<std::list<ParametricPoint> >* points,
std::list<ParametricPoint >* pointsSingleList,
RectD* bbox) const;
public:
/**
* @brief Same as evaluateAtTime_DeCasteljau but nbPointsPerSegment is approximated automatically
**/
void evaluateAtTime_DeCasteljau_autoNbPoints(bool useGuiCurves,
double time,
unsigned int mipMapLevel,
std::list<std::list<ParametricPoint> >* points,
RectD* bbox) const;
/**
* @brief Evaluates the bezier formed by the feather points. Segments which are equal to the control points of the bezier
* will not be drawn.
**/
void evaluateFeatherPointsAtTime_DeCasteljau(bool useGuiCurves,
double time,
unsigned int mipMapLevel,
#ifdef ROTO_BEZIER_EVAL_ITERATIVE
int nbPointsPerSegment,
#else
double errorScale,
#endif
bool evaluateIfEqual,
std::list<std::list<ParametricPoint> >* points,
RectD* bbox) const;
void evaluateFeatherPointsAtTime_DeCasteljau(bool useGuiCurves,
double time,
unsigned int mipMapLevel,
#ifdef ROTO_BEZIER_EVAL_ITERATIVE
int nbPointsPerSegment,
#else
double errorScale,
#endif
bool evaluateIfEqual,
std::list<ParametricPoint >* points,
RectD* bbox) const;
private:
void evaluateFeatherPointsAtTime_DeCasteljau_internal(bool useGuiCurves,
double time,
unsigned int mipMapLevel,
#ifdef ROTO_BEZIER_EVAL_ITERATIVE
int nbPointsPerSegment,
#else
double errorScale,
#endif
bool evaluateIfEqual,
std::list<std::list<ParametricPoint> >* points,
std::list<ParametricPoint >* pointsSingleList,
RectD* bbox) const;
public:
/**
* @brief Returns the bounding box of the bezier. The last value computed by evaluateAtTime_DeCasteljau will be returned,
* otherwise if it has never been called, evaluateAtTime_DeCasteljau will be called to compute the bounding box.
**/
virtual RectD getBoundingBox(double time) const OVERRIDE;
static void bezierSegmentListBboxUpdate(bool useGuiCurves,
const std::list<BezierCPPtr> & points,
bool finished,
bool isOpenBezier,
double time,
ViewIdx view,
unsigned int mipMapLevel,
const Transform::Matrix3x3& transform,
RectD* bbox);
/**
* @brief Returns a const ref to the control points of the bezier curve. This can only ever be called on the main thread.
**/
const std::list<BezierCPPtr> & getControlPoints() const;
protected:
std::list<BezierCPPtr> & getControlPoints_internal();
public:
std::list<BezierCPPtr> getControlPoints_mt_safe() const;
/**
* @brief Returns a const ref to the feather points of the bezier curve. This can only ever be called on the main thread.
**/
const std::list<BezierCPPtr> & getFeatherPoints() const;
std::list<BezierCPPtr> getFeatherPoints_mt_safe() const;
enum ControlPointSelectionPrefEnum
{
eControlPointSelectionPrefFeatherFirst = 0,
eControlPointSelectionPrefControlPointFirst,
eControlPointSelectionPrefWhateverFirst
};
/**
* @brief Returns a pointer to a nearby control point if any. This function also returns the feather point
* The first member is the actual point nearby, and the second the counter part (i.e: either the feather point
* if the first is a control point, or the other way around).
**/
std::pair<BezierCPPtr, BezierCPPtr>isNearbyControlPoint(double x, double y, double acceptance, ControlPointSelectionPrefEnum pref, int* index) const;
/**
* @brief Given the control point in parameter, return its index in the curve's control points list.
* If no such control point could be found, -1 is returned.
**/
int getControlPointIndex(const BezierCPPtr & cp) const;
int getControlPointIndex(const BezierCP* cp) const;
/**
* @brief Given the feather point in parameter, return its index in the curve's feather points list.
* If no such feather point could be found, -1 is returned.
**/
int getFeatherPointIndex(const BezierCPPtr & fp) const;
/**
* @brief Returns the control point at the given index if any, NULL otherwise.
**/
BezierCPPtr getControlPointAtIndex(int index) const;
/**
* @brief Returns the feather point at the given index if any, NULL otherwise.
**/
BezierCPPtr getFeatherPointAtIndex(int index) const;
BezierCPPtr getFeatherPointForControlPoint(const BezierCPPtr & cp) const;
BezierCPPtr getControlPointForFeatherPoint(const BezierCPPtr & fp) const;
/**
* @brief Returns all the control points/feather points within the rectangle
* given by (l,r,b,t). Each control point is paired with its counter part.
* The first member is always "the selected point" and the second the counter part.
* @param mode An integer representing what the function should do.
* mode == 0: Add all the cp/fp within the rect and their counter parts in the return value
* mode == 1: Add only the cp within the rect and their respective feather points counter parts
* mode == 2: Add only the fp within the rect and their repsective control points counter parts
**/
std::list<std::pair<BezierCPPtr, BezierCPPtr> >controlPointsWithinRect(double l, double r, double b, double t, double acceptance, int mode) const;
static void leftDerivativeAtPoint(bool useGuiCurves, double time, const BezierCP & p, const BezierCP & prev, const Transform::Matrix3x3& transform, double *dx, double *dy);
static void rightDerivativeAtPoint(bool useGuiCurves, double time, const BezierCP & p, const BezierCP & next, const Transform::Matrix3x3& transform, double *dx, double *dy);
/**
* @brief Computes the location of the feather extent relative to the current feather point position and
* the given feather distance.
* In the case the control point and the feather point of the bezier are distinct, this function just makes use
* of Thales theorem.
> * If the feather point and the control point are equal then this function computes the left and right derivative
* of the bezier at that point to determine the direction in which the extent is.
* @returns The delta from the given feather point to apply to find out the extent position.
*
* Note that the delta will be applied to fp.
**/
static Point expandToFeatherDistance(bool useGuiCurve,
const Point & cp, //< the point
Point* fp, //< the feather point
double featherDistance, //< feather distance
//const std::list<Point> & featherPolygon, //< the polygon of the bezier
double time, //< time
bool clockWise, //< is the bezier clockwise oriented or not
const Transform::Matrix3x3& transform,
std::list<BezierCPPtr>::const_iterator prevFp, //< iterator pointing to the feather before curFp
std::list<BezierCPPtr>::const_iterator curFp, //< iterator pointing to fp
std::list<BezierCPPtr>::const_iterator nextFp); //< iterator pointing after curFp
enum FillRuleEnum
{
eFillRuleOddEven,
eFillRuleWinding
};
bool isFeatherPolygonClockwiseOriented(bool useGuiCurve, double time) const;
/**
* @brief Refresh the polygon orientation for a specific keyframe or for all keyframes. Auto polygon orientation must be set to true
* so make sure setAutoOrientationComputation(true) has been called before.
**/
void refreshPolygonOrientation(bool useGuiCurve, double time);
void refreshPolygonOrientation(bool useGuiCurve);
void setAutoOrientationComputation(bool autoCompute);
bool dequeueGuiActions();
private:
virtual void onTransformSet(double time) OVERRIDE FINAL;
bool isFeatherPolygonClockwiseOrientedInternal(bool useGuiCurve, double time) const;
void computePolygonOrientation(bool useGuiCurves, double time, bool isStatic) const;
/*
* @brief If the node is currently involved in a render, returns false, otherwise returns true
*/
bool canSetInternalPoints() const;
void copyInternalPointsToGuiPoints();
public:
/**
* @brief Must be implemented by the derived class to save the state into
* the serialization object.
* Derived implementations must call the parent class implementation.
**/
virtual void save(RotoItemSerialization* obj) const OVERRIDE;
/**
* @brief Must be implemented by the derived class to load the state from
* the serialization object.
* Derived implementations must call the parent class implementation.
**/
virtual void load(const RotoItemSerialization & obj) OVERRIDE;
void getKeyframeTimes(std::set<double> *times) const;
void getKeyframeTimesAndInterpolation(std::list<std::pair<double, KeyframeTypeEnum> > *keys) const;
/**
* @brief Get the nearest previous keyframe from the given time.
* If nothing was found INT_MIN is returned.
**/
int getPreviousKeyframeTime(double time) const;
/**
* @brief Get the nearest next keyframe from the given time.
* If nothing was found INT_MAX is returned.
**/
int getNextKeyframeTime(double time) const;
int getKeyFrameIndex(double time) const;
void setKeyFrameInterpolation(KeyframeTypeEnum interp, int index);
Q_SIGNALS:
void aboutToClone();
void cloned();
void keyframeSet(double time);
void keyframeRemoved(double time);
void animationRemoved();
void controlPointRemoved();
private:
boost::scoped_ptr<BezierPrivate> _imp;
};
NATRON_NAMESPACE_EXIT
#endif // Engine_Bezier_h