src/gui/painting/qbezier.cpp File Reference

#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 Documentation

#define KAPPA   0.5522847498

Definition at line 324 of file qbezier.cpp.

Referenced by addCircle().


Enumeration Type Documentation

enum ShiftResult

Definition at line 159 of file qbezier.cpp.

00159                  {
00160     Ok,
00161     Discard,
00162     Split,
00163     Circle
00164 };


Function Documentation

static void addCircle ( const QBezier b,
qreal  offset,
QBezier o 
) [static]

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:


Generated on Thu Mar 15 13:31:42 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1