void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold) const { QBezier beziers[32]; beziers[0] = *this; QBezier *b = beziers; while (b >= beziers) { // check if we can pop the top bezier curve from the stack qreal y4y1 = b->y4 - b->y1; qreal x4x1 = b->x4 - b->x1; qreal l = qAbs(x4x1) + qAbs(y4y1); qreal d; if (l > 1.) { d = qAbs( (x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2) ) + qAbs( (x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3) ); } else { d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) + qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); l = 1.; } if (d < bezier_flattening_threshold*l || b == beziers + 31) { // good enough, we pop it off and add the endpoint polygon->append(QPointF(b->x4, b->y4)); --b; } else { // split, second half of the polygon goes lower into the stack b->split(b+1, b); ++b; } } }
int QBezier::shifted(QBezier *curveSegments, int maxSegments, qreal offset, float threshold) const { Q_ASSERT(curveSegments); Q_ASSERT(maxSegments > 0); if (x1 == x2 && x1 == x3 && x1 == x4 && y1 == y2 && y1 == y3 && y1 == y4) return 0; --maxSegments; QBezier beziers[10]; redo: beziers[0] = *this; QBezier *b = beziers; QBezier *o = curveSegments; while (b >= beziers) { int stack_segments = b - beziers + 1; if ((stack_segments == 10) || (o - curveSegments == maxSegments - stack_segments)) { threshold *= qreal(1.5); if (threshold > qreal(2.0)) goto give_up; goto redo; } ShiftResult res = shift(b, o, offset, threshold); if (res == Discard) { --b; } else if (res == Ok) { ++o; --b; continue; } else if (res == Circle && maxSegments - (o - curveSegments) >= 2) { // add semi circle if (addCircle(b, offset, o)) o += 2; --b; } else { b->split(b+1, b); ++b; } } give_up: while (b >= beziers) { ShiftResult res = shift(b, o, offset, threshold); // if res isn't Ok or Split then *o is undefined if (res == Ok || res == Split) ++o; --b; } Q_ASSERT(o - curveSegments <= maxSegments); return o - curveSegments; }
void QBezier::addToPolygon(QDataBuffer<QPointF> &polygon, qreal bezier_flattening_threshold) const { QBezier beziers[10]; int levels[10]; beziers[0] = *this; levels[0] = 9; QBezier *b = beziers; int *lvl = levels; while (b >= beziers) { // check if we can pop the top bezier curve from the stack qreal y4y1 = b->y4 - b->y1; qreal x4x1 = b->x4 - b->x1; qreal l = qAbs(x4x1) + qAbs(y4y1); qreal d; if (l > 1.) { d = qAbs( (x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2) ) + qAbs( (x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3) ); } else { d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) + qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); l = 1.; } if (d < bezier_flattening_threshold*l || *lvl == 0) { // good enough, we pop it off and add the endpoint polygon.add(QPointF(b->x4, b->y4)); --b; --lvl; } else { // split, second half of the polygon goes lower into the stack b->split(b+1, b); lvl[1] = --lvl[0]; ++b; ++lvl; } } }