Krita Source Code Documentation
Loading...
Searching...
No Matches
KisBezierUtils::BezierSegment Class Reference

Public Member Functions

 BezierSegment (int degree=0, QPointF *p=0)
 
int degree () const
 
QPointF evaluate (qreal t, BezierSegment *left, BezierSegment *right) const
 
int isFlat (qreal tolerance) const
 
QPointF point (int index) const
 
void printDebug () const
 
QList< qreal > roots (int depth=0) const
 
void setDegree (int degree)
 
void setPoint (int index, const QPointF &p)
 

Static Public Member Functions

static uint controlPolygonZeros (const QList< QPointF > &controlPoints)
 

Private Attributes

const qreal FlatnessTolerance = ldexp(1.0,-MaxRecursionDepth-1)
 Flatness tolerance for finding root params.
 
const int MaxRecursionDepth = 64
 Maximal recursion depth for finding root params.
 
QList< QPointF > points
 

Detailed Description

Definition at line 84 of file KisBezierUtils.cpp.

Constructor & Destructor Documentation

◆ BezierSegment()

KisBezierUtils::BezierSegment::BezierSegment ( int degree = 0,
QPointF * p = 0 )
inline

Definition at line 93 of file KisBezierUtils.cpp.

94 {
95 if (degree) {
96 for (int i = 0; i <= degree; ++i)
97 points.append(p[i]);
98 }
99 }
const Params2D p

References degree(), p, and points.

Member Function Documentation

◆ controlPolygonZeros()

static uint KisBezierUtils::BezierSegment::controlPolygonZeros ( const QList< QPointF > & controlPoints)
inlinestatic

Definition at line 212 of file KisBezierUtils.cpp.

213 {
214 int controlPointCount = controlPoints.count();
215 if (controlPointCount < 2)
216 return 0;
217
218 int signChanges = 0;
219
220 int currSign = controlPoints[0].y() < 0.0 ? -1 : 1;
221 int oldSign;
222
223 for (short i = 1; i < controlPointCount; ++i) {
224 oldSign = currSign;
225 currSign = controlPoints[i].y() < 0.0 ? -1 : 1;
226
227 if (currSign != oldSign) {
228 ++signChanges;
229 }
230 }
231
232
233 return signChanges;
234 }

◆ degree()

int KisBezierUtils::BezierSegment::degree ( ) const
inline

Definition at line 110 of file KisBezierUtils.cpp.

111 {
112 return points.count() - 1;
113 }

References points.

◆ evaluate()

QPointF KisBezierUtils::BezierSegment::evaluate ( qreal t,
BezierSegment * left,
BezierSegment * right ) const
inline

Definition at line 131 of file KisBezierUtils.cpp.

132 {
133 int deg = degree();
134 if (! deg)
135 return QPointF();
136
137 QVector<QVector<QPointF> > Vtemp(deg + 1);
138 for (int i = 0; i <= deg; ++i)
139 Vtemp[i].resize(deg + 1);
140
141 /* Copy control points */
142 for (int j = 0; j <= deg; j++) {
143 Vtemp[0][j] = points[j];
144 }
145
146 /* Triangle computation */
147 for (int i = 1; i <= deg; i++) {
148 for (int j =0 ; j <= deg - i; j++) {
149 Vtemp[i][j].rx() = (1.0 - t) * Vtemp[i-1][j].x() + t * Vtemp[i-1][j+1].x();
150 Vtemp[i][j].ry() = (1.0 - t) * Vtemp[i-1][j].y() + t * Vtemp[i-1][j+1].y();
151 }
152 }
153
154 if (left) {
155 left->setDegree(deg);
156 for (int j = 0; j <= deg; j++) {
157 left->setPoint(j, Vtemp[j][0]);
158 }
159 }
160 if (right) {
161 right->setDegree(deg);
162 for (int j = 0; j <= deg; j++) {
163 right->setPoint(j, Vtemp[deg-j][j]);
164 }
165 }
166
167 return (Vtemp[deg][0]);
168 }

References degree(), points, setDegree(), and setPoint().

◆ isFlat()

int KisBezierUtils::BezierSegment::isFlat ( qreal tolerance) const
inline

Definition at line 236 of file KisBezierUtils.cpp.

237 {
238 int deg = degree();
239
240 // Find the perpendicular distance from each interior control point to
241 // the line connecting points[0] and points[degree]
242 qreal *distance = new qreal[deg + 1];
243
244 // Derive the implicit equation for line connecting first and last control points
245 qreal a = points[0].y() - points[deg].y();
246 qreal b = points[deg].x() - points[0].x();
247 qreal c = points[0].x() * points[deg].y() - points[deg].x() * points[0].y();
248
249 qreal abSquared = (a * a) + (b * b);
250
251 for (int i = 1; i < deg; i++) {
252 // Compute distance from each of the points to that line
253 distance[i] = a * points[i].x() + b * points[i].y() + c;
254 if (distance[i] > 0.0) {
255 distance[i] = (distance[i] * distance[i]) / abSquared;
256 }
257 if (distance[i] < 0.0) {
258 distance[i] = -((distance[i] * distance[i]) / abSquared);
259 }
260 }
261
262
263 // Find the largest distance
264 qreal max_distance_above = 0.0;
265 qreal max_distance_below = 0.0;
266 for (int i = 1; i < deg; i++) {
267 if (distance[i] < 0.0) {
268 max_distance_below = qMin(max_distance_below, distance[i]);
269 }
270 if (distance[i] > 0.0) {
271 max_distance_above = qMax(max_distance_above, distance[i]);
272 }
273 }
274 delete [] distance;
275
276 // Implicit equation for zero line
277 qreal a1 = 0.0;
278 qreal b1 = 1.0;
279 qreal c1 = 0.0;
280
281 // Implicit equation for "above" line
282 qreal a2 = a;
283 qreal b2 = b;
284 qreal c2 = c + max_distance_above;
285
286 qreal det = a1 * b2 - a2 * b1;
287 qreal dInv = 1.0/det;
288
289 qreal intercept_1 = (b1 * c2 - b2 * c1) * dInv;
290
291 // Implicit equation for "below" line
292 a2 = a;
293 b2 = b;
294 c2 = c + max_distance_below;
295
296 det = a1 * b2 - a2 * b1;
297 dInv = 1.0/det;
298
299 qreal intercept_2 = (b1 * c2 - b2 * c1) * dInv;
300
301 // Compute intercepts of bounding box
302 qreal left_intercept = qMin(intercept_1, intercept_2);
303 qreal right_intercept = qMax(intercept_1, intercept_2);
304
305 qreal error = 0.5 * (right_intercept-left_intercept);
306
307 return (error < tolerance);
308 }
qreal distance(const QPointF &p1, const QPointF &p2)

References degree(), distance(), and points.

◆ point()

QPointF KisBezierUtils::BezierSegment::point ( int index) const
inline

Definition at line 115 of file KisBezierUtils.cpp.

116 {
117 if (static_cast<int>(index) > degree())
118 return QPointF();
119
120 return points[index];
121 }

References degree(), and points.

◆ printDebug()

void KisBezierUtils::BezierSegment::printDebug ( ) const
inline

Definition at line 311 of file KisBezierUtils.cpp.

312 {
313 int index = 0;
314 Q_FOREACH (const QPointF &p, points) {
315 qDebug() << QString("P%1 ").arg(index++) << p;
316 }
317 }

References p, and points.

◆ roots()

QList< qreal > KisBezierUtils::BezierSegment::roots ( int depth = 0) const
inline

Definition at line 170 of file KisBezierUtils.cpp.

171 {
172 QList<qreal> rootParams;
173
174 if (! degree())
175 return rootParams;
176
177 // Calculate how often the control polygon crosses the x-axis
178 // This is the upper limit for the number of roots.
179 int xAxisCrossings = controlPolygonZeros(points);
180
181 if (! xAxisCrossings) {
182 // No solutions.
183 return rootParams;
184 }
185 else if (xAxisCrossings == 1) {
186 // Exactly one solution.
187
188 // Stop recursion when the tree is deep enough
189 if (depth >= MaxRecursionDepth) {
190 // if deep enough, return 1 solution at midpoint
191 rootParams.append((points.first().x() + points.last().x()) / 2.0);
192 return rootParams;
193 }
194 else if (isFlat(FlatnessTolerance)) {
195 // Calculate intersection of chord with x-axis.
196 QPointF chord = points.last() - points.first();
197 QPointF segStart = points.first();
198 rootParams.append((chord.x() * segStart.y() - chord.y() * segStart.x()) / - chord.y());
199 return rootParams;
200 }
201 }
202
203 // Many solutions. Do recursive midpoint subdivision.
204 BezierSegment left, right;
205 evaluate(0.5, &left, &right);
206 rootParams += left.roots(depth+1);
207 rootParams += right.roots(depth+1);
208
209 return rootParams;
210 }
int isFlat(qreal tolerance) const
const int MaxRecursionDepth
Maximal recursion depth for finding root params.
QPointF evaluate(qreal t, BezierSegment *left, BezierSegment *right) const
static uint controlPolygonZeros(const QList< QPointF > &controlPoints)
BezierSegment(int degree=0, QPointF *p=0)
const qreal FlatnessTolerance
Flatness tolerance for finding root params.

References controlPolygonZeros(), degree(), evaluate(), FlatnessTolerance, isFlat(), MaxRecursionDepth, points, and roots().

◆ setDegree()

void KisBezierUtils::BezierSegment::setDegree ( int degree)
inline

Definition at line 101 of file KisBezierUtils.cpp.

102 {
103 points.clear();
104 if (degree) {
105 for (int i = 0; i <= degree; ++i)
106 points.append(QPointF());
107 }
108 }

References degree(), and points.

◆ setPoint()

void KisBezierUtils::BezierSegment::setPoint ( int index,
const QPointF & p )
inline

Definition at line 123 of file KisBezierUtils.cpp.

124 {
125 if (static_cast<int>(index) > degree())
126 return;
127
128 points[index] = p;
129 }

References degree(), p, and points.

Member Data Documentation

◆ FlatnessTolerance

const qreal KisBezierUtils::BezierSegment::FlatnessTolerance = ldexp(1.0,-MaxRecursionDepth-1)
private

Flatness tolerance for finding root params.

Definition at line 90 of file KisBezierUtils.cpp.

◆ MaxRecursionDepth

const int KisBezierUtils::BezierSegment::MaxRecursionDepth = 64
private

Maximal recursion depth for finding root params.

Definition at line 88 of file KisBezierUtils.cpp.

◆ points

QList<QPointF> KisBezierUtils::BezierSegment::points
private

Definition at line 321 of file KisBezierUtils.cpp.


The documentation for this class was generated from the following file: