#include "qbezier_p.h"
#include <qdebug.h>
#include <qline.h>
#include <qpolygon.h>
#include <private/qnumeric_p.h>
#include <private/qmath_p.h>
Include dependency graph for qbezier.cpp:

Go to the source code of this file.
Defines | |
| #define | KAPPA 0.5522847498 |
Enumerations | |
| enum | ShiftResult |
Functions | |
| static ShiftResult | good_offset (const QBezier *b1, const QBezier *b2, qreal offset, qreal threshold) |
| static QLineF | qline_shifted (const QPointF &p1, const QPointF &p2, qreal offset) |
| static bool | qbezier_is_line (QPointF *points, int pointCount) |
| static ShiftResult | shift (const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold) |
| static void | addCircle (const QBezier *b, qreal offset, QBezier *o) |
| #define KAPPA 0.5522847498 |
| enum ShiftResult |
Definition at line 327 of file qbezier.cpp.
References b, i, KAPPA, o, Q_PI, sign(), QPointF::x(), x, QPointF::y(), and y.
Referenced by QBezier::shifted().
00328 { 00329 QPointF normals[3]; 00330 00331 normals[0] = QPointF(b->y2 - b->y1, b->x1 - b->x2); 00332 qreal dist = sqrt(normals[0].x()*normals[0].x() + normals[0].y()*normals[0].y()); 00333 if (qFuzzyCompare(dist, 0)) 00334 return; 00335 normals[0] /= dist; 00336 normals[2] = QPointF(b->y4 - b->y3, b->x3 - b->x4); 00337 dist = sqrt(normals[2].x()*normals[2].x() + normals[2].y()*normals[2].y()); 00338 if (qFuzzyCompare(dist, 0)) 00339 return; 00340 normals[2] /= dist; 00341 00342 normals[1] = QPointF(b->x1 - b->x2 - b->x3 + b->x4, b->y1 - b->y2 - b->y3 + b->y4); 00343 normals[1] /= -1*sqrt(normals[1].x()*normals[1].x() + normals[1].y()*normals[1].y()); 00344 00345 qreal angles[2]; 00346 qreal sign = 1.; 00347 for (int i = 0; i < 2; ++i) { 00348 qreal cos_a = normals[i].x()*normals[i+1].x() + normals[i].y()*normals[i+1].y(); 00349 if (cos_a > 1.) 00350 cos_a = 1.; 00351 if (cos_a < -1.) 00352 cos_a = -1; 00353 angles[i] = acos(cos_a)/Q_PI; 00354 } 00355 00356 if (angles[0] + angles[1] > 1.) { 00357 // more than 180 degrees 00358 normals[1] = -normals[1]; 00359 angles[0] = 1. - angles[0]; 00360 angles[1] = 1. - angles[1]; 00361 sign = -1.; 00362 00363 } 00364 00365 QPointF circle[3]; 00366 circle[0] = QPointF(b->x1, b->y1) + normals[0]*offset; 00367 circle[1] = QPointF(0.5*(b->x1 + b->x4), 0.5*(b->y1 + b->y4)) + normals[1]*offset; 00368 circle[2] = QPointF(b->x4, b->y4) + normals[2]*offset; 00369 00370 for (int i = 0; i < 2; ++i) { 00371 qreal kappa = 2.*KAPPA * sign * offset * angles[i]; 00372 00373 o->x1 = circle[i].x(); 00374 o->y1 = circle[i].y(); 00375 o->x2 = circle[i].x() - normals[i].y()*kappa; 00376 o->y2 = circle[i].y() + normals[i].x()*kappa; 00377 o->x3 = circle[i+1].x() + normals[i+1].y()*kappa; 00378 o->y3 = circle[i+1].y() - normals[i+1].x()*kappa; 00379 o->x4 = circle[i+1].x(); 00380 o->y4 = circle[i+1].y(); 00381 00382 ++o; 00383 } 00384 }
Here is the call graph for this function:

| static ShiftResult good_offset | ( | const QBezier * | b1, | |
| const QBezier * | b2, | |||
| qreal | offset, | |||
| qreal | threshold | |||
| ) | [static] |
Definition at line 166 of file qbezier.cpp.
References d, i, l, QBezier::normalVector(), Ok, QBezier::pointAt(), spacing, Split, QPointF::x(), and QPointF::y().
Referenced by shift().
00167 { 00168 const qreal o2 = offset*offset; 00169 const qreal max_dist_line = threshold*offset*offset; 00170 const qreal max_dist_normal = threshold*offset; 00171 const qreal spacing = 0.25; 00172 for (qreal i = spacing; i < 0.99; i += spacing) { 00173 QPointF p1 = b1->pointAt(i); 00174 QPointF p2 = b2->pointAt(i); 00175 qreal d = (p1.x() - p2.x())*(p1.x() - p2.x()) + (p1.y() - p2.y())*(p1.y() - p2.y()); 00176 if (qAbs(d - o2) > max_dist_line) 00177 return Split; 00178 00179 QPointF normalPoint = b1->normalVector(i); 00180 qreal l = qAbs(normalPoint.x()) + qAbs(normalPoint.y()); 00181 if (l != 0.) { 00182 d = qAbs( normalPoint.x()*(p1.y() - p2.y()) - normalPoint.y()*(p1.x() - p2.x()) ) / l; 00183 if (d > max_dist_normal) 00184 return Split; 00185 } 00186 } 00187 return Ok; 00188 }
Here is the call graph for this function:

| static bool qbezier_is_line | ( | QPointF * | points, | |
| int | pointCount | |||
| ) | [static] |
Definition at line 198 of file qbezier.cpp.
References QPointF::x(), and QPointF::y().
Referenced by shift().
00199 { 00200 Q_ASSERT(pointCount > 2); 00201 00202 qreal dx13 = points[2].x() - points[0].x(); 00203 qreal dy13 = points[2].y() - points[0].y(); 00204 00205 qreal dx12 = points[1].x() - points[0].x(); 00206 qreal dy12 = points[1].y() - points[0].y(); 00207 00208 if (pointCount == 3) { 00209 if (dx13 * dx12 != 0) 00210 return qFuzzyCompare(dy12 / dx12, dy13 / dx13); 00211 else 00212 return qFuzzyCompare(dx12 / dy12, dx13 / dy13); 00213 00214 } else if (pointCount == 4) { 00215 qreal dx14 = points[3].x() - points[0].x(); 00216 qreal dy14 = points[3].y() - points[0].y(); 00217 00218 if (dx14*dx13*dx12 != 0) { 00219 qreal b14 = dy14 / dx14; 00220 qreal b13 = dy13 / dx13; 00221 qreal b12 = dy12 / dx12; 00222 return qFuzzyCompare(b14, b13) && qFuzzyCompare(b14, b12); 00223 00224 } else { 00225 qreal a14 = dx14 / dy14; 00226 qreal a13 = dx13 / dy13; 00227 qreal a12 = dx12 / dy12; 00228 return qFuzzyCompare(a14, a13) && qFuzzyCompare(a14, a12); 00229 } 00230 } 00231 00232 return false; 00233 }
Here is the call graph for this function:

| static QLineF qline_shifted | ( | const QPointF & | p1, | |
| const QPointF & | p2, | |||
| qreal | offset | |||
| ) | [inline, static] |
Definition at line 190 of file qbezier.cpp.
References QLineF::dx(), QLineF::dy(), and l.
Referenced by shift().
00191 { 00192 QLineF l(p1, p2); 00193 QLineF ln = l.normalVector().unitVector(); 00194 l.translate(ln.dx() * offset, ln.dy() * offset); 00195 return l; 00196 }
Here is the call graph for this function:

| static ShiftResult shift | ( | const QBezier * | orig, | |
| QBezier * | shifted, | |||
| qreal | offset, | |||
| qreal | threshold | |||
| ) | [static] |
Definition at line 235 of file qbezier.cpp.
References b, QBezier::bounds(), Circle, Discard, QBezier::fromPoints(), good_offset(), i, l, next, QLineF::normalVector(), Ok, QLineF::p2(), qbezier_is_line(), qline_shifted(), QLineF::unitVector(), QPointF::x(), QBezier::x1, QBezier::x2, QBezier::x3, QBezier::x4, QBezier::y1, QBezier::y2, QBezier::y3, and QBezier::y4.
Referenced by checksum(), Q3TextParagraph::format(), Q3TextFormatter::formatVertically(), Q3TextParagraph::move(), Q3TextTable::pageBreak(), and QBezier::shifted().
00236 { 00237 int map[4]; 00238 bool p1_p2_equal = (orig->x1 == orig->x2 && orig->y1 == orig->y2); 00239 bool p2_p3_equal = (orig->x2 == orig->x3 && orig->y2 == orig->y3); 00240 bool p3_p4_equal = (orig->x3 == orig->x4 && orig->y3 == orig->y4); 00241 00242 QPointF points[4]; 00243 int np = 0; 00244 points[np] = QPointF(orig->x1, orig->y1); 00245 map[0] = 0; 00246 ++np; 00247 if (!p1_p2_equal) { 00248 points[np] = QPointF(orig->x2, orig->y2); 00249 ++np; 00250 } 00251 map[1] = np - 1; 00252 if (!p2_p3_equal) { 00253 points[np] = QPointF(orig->x3, orig->y3); 00254 ++np; 00255 } 00256 map[2] = np - 1; 00257 if (!p3_p4_equal) { 00258 points[np] = QPointF(orig->x4, orig->y4); 00259 ++np; 00260 } 00261 map[3] = np - 1; 00262 if (np == 1) 00263 return Discard; 00264 00265 // We need to specialcase lines of 3 or 4 points due to numerical 00266 // instability in intersections below 00267 if (np > 2 && qbezier_is_line(points, np)) { 00268 QLineF l = qline_shifted(points[0], points[np-1], offset); 00269 *shifted = QBezier::fromPoints(l.p1(), l.pointAt(0.33), l.pointAt(0.66), l.p2()); 00270 return Ok; 00271 } 00272 00273 QRectF b = orig->bounds(); 00274 if (np == 4 && b.width() < .1*offset && b.height() < .1*offset) { 00275 qreal l = (orig->x1 - orig->x2)*(orig->x1 - orig->x2) + 00276 (orig->y1 - orig->y2)*(orig->y1 - orig->y1) * 00277 (orig->x3 - orig->x4)*(orig->x3 - orig->x4) + 00278 (orig->y3 - orig->y4)*(orig->y3 - orig->y4); 00279 qreal dot = (orig->x1 - orig->x2)*(orig->x3 - orig->x4) + 00280 (orig->y1 - orig->y2)*(orig->y3 - orig->y4); 00281 if (dot < 0 && dot*dot < 0.8*l) 00282 // the points are close and reverse dirction. Approximate the whole 00283 // thing by a semi circle 00284 return Circle; 00285 } 00286 00287 QPointF points_shifted[4]; 00288 00289 QLineF prev = QLineF(QPointF(), points[1] - points[0]); 00290 QPointF prev_normal = prev.normalVector().unitVector().p2(); 00291 00292 points_shifted[0] = points[0] + offset * prev_normal; 00293 00294 for (int i = 1; i < np - 1; ++i) { 00295 QLineF next = QLineF(QPointF(), points[i + 1] - points[i]); 00296 QPointF next_normal = next.normalVector().unitVector().p2(); 00297 00298 QPointF normal_sum = prev_normal + next_normal; 00299 00300 qreal r = 1.0 + prev_normal.x() * next_normal.x() 00301 + prev_normal.y() * next_normal.y(); 00302 00303 if (qFuzzyCompare(r, (qreal)0.0)) { 00304 points_shifted[i] = points[i] + offset * prev_normal; 00305 } else { 00306 qreal k = offset / r; 00307 points_shifted[i] = points[i] + k * normal_sum; 00308 } 00309 00310 prev_normal = next_normal; 00311 } 00312 00313 points_shifted[np - 1] = points[np - 1] + offset * prev_normal; 00314 00315 *shifted = QBezier::fromPoints(points_shifted[map[0]], points_shifted[map[1]], 00316 points_shifted[map[2]], points_shifted[map[3]]); 00317 00318 return good_offset(orig, shifted, offset, threshold); 00319 }
Here is the call graph for this function:

1.5.1