6#include <QtCore/qvarlengtharray.h>
7#include <QtCore/qglobal.h>
8#include <QtCore/qpoint.h>
9#include <QtCore/qalgorithms.h>
12# include <private/qopengl_p.h>
14#include <private/qrbtree_p.h>
18#define Q_FIXED_POINT_SCALE 256
19#define Q_TRIANGULATE_END_OF_POLYGON quint32(-1
)
27inline bool operator < (
const QPoint &a,
const QPoint &b)
29 return a.y() < b.y() || (a.y() == b.y() && a.x() < b.x());
32inline bool operator > (
const QPoint &a,
const QPoint &b)
37inline bool operator <= (
const QPoint &a,
const QPoint &b)
42inline bool operator >= (
const QPoint &a,
const QPoint &b)
49inline int cross(
const QPoint &u,
const QPoint &v)
51 return u.x() * v.y() - u.y() * v.x();
54inline int dot(
const QPoint &u,
const QPoint &v)
56 return u.x() * v.x() + u.y() * v.y();
66 bool isValid()
const {
return denominator != 0; }
69 unsigned int numerator, denominator;
72inline unsigned int gcd(
unsigned int x,
unsigned int y)
84Fraction fraction(
unsigned int n,
unsigned int d) {
88 result.denominator = 1;
90 unsigned int g = gcd(n, d);
91 result.numerator = n / g;
92 result.denominator = d / g;
111struct IntersectionPoint
113 bool isValid()
const {
return x.fraction.isValid() && y.fraction.isValid(); }
114 QPoint round()
const;
115 bool isAccurate()
const {
return x.fraction.numerator == 0 && y.fraction.numerator == 0; }
121QPoint IntersectionPoint::round()
const
123 QPoint result(x.integer, y.integer);
124 if (2 * x.fraction.numerator >= x.fraction.denominator)
126 if (2 * y.fraction.numerator >= y.fraction.denominator)
134inline int pointSideOfLine(
const QPoint &p,
const QPoint &v1,
const QPoint &v2)
136 qint64 ux = qint64(v2.x()) - v1.x();
137 qint64 uy = qint64(v2.y()) - v1.y();
138 qint64 vx = qint64(p.x()) - v1.x();
139 qint64 vy = qint64(p.y()) - v1.y();
140 qint64 c = (ux * vy) - (uy * vx);
141 return (c > 0) ? 1 : (c < 0) ? -1 : 0;
144IntersectionPoint intersectionPoint(
const QPoint &u1,
const QPoint &u2,
145 const QPoint &v1,
const QPoint &v2)
147 IntersectionPoint result = {{0, {0, 0}}, {0, {0, 0}}};
151 int d1 = cross(u, v1 - u1);
152 int d2 = cross(u, v2 - u1);
154 int d3 = cross(v, u1 - v1);
158 Q_ASSERT(d4 == cross(v, u2 - v1));
180 if (d1 >= 0 || d2 <= 0 || d3 <= 0 || d4 >= 0)
189 result.x.integer = v1.x() +
int(qint64(-v.x()) * d1 / det);
190 result.x.fraction = fraction((
unsigned int)(qint64(-v.x()) * d1 % det), (
unsigned int)det);
192 result.x.integer = v2.x() +
int(qint64(-v.x()) * d2 / det);
193 result.x.fraction = fraction((
unsigned int)(qint64(-v.x()) * d2 % det), (
unsigned int)det);
197 result.y.integer = v1.y() +
int(qint64(-v.y()) * d1 / det);
198 result.y.fraction = fraction((
unsigned int)(qint64(-v.y()) * d1 % det), (
unsigned int)det);
200 result.y.integer = v2.y() +
int(qint64(-v.y()) * d2 / det);
201 result.y.fraction = fraction((
unsigned int)(qint64(-v.y()) * d2 % det), (
unsigned int)det);
204 Q_ASSERT(result.x.fraction.isValid());
205 Q_ASSERT(result.y.fraction.isValid());
216 PathSimplifier(
const QVectorPath &path, QDataBuffer<QPoint> &vertices,
217 QDataBuffer<quint32> &indices,
const QTransform &matrix);
222 class BoundingVolumeHierarchy
242 BoundingVolumeHierarchy();
243 ~BoundingVolumeHierarchy();
244 void allocate(
int nodeCount);
250 void freeNode(Node *n);
266 quint32 &upperIndex() {
return indices[pointingUp ? degree : 0]; }
267 quint32 &lowerIndex() {
return indices[pointingUp ? 0 : degree]; }
268 quint32 upperIndex()
const {
return indices[pointingUp ? degree : 0]; }
269 quint32 lowerIndex()
const {
return indices[pointingUp ? 0 : degree]; }
274 Element *next, *previous;
277 QRBTree<Element *>::Node *edgeNode;
278 BoundingVolumeHierarchy::Node *bvhNode;
283 uint originallyPointingUp : 1;
286 class ElementAllocator
291 void allocate(
int count);
292 Element *newElement();
305 enum Type { Upper, Lower };
306 bool operator < (
const Event &other)
const;
312 friend class QTypeInfo<Event>;
314 typedef QRBTree<Element *>::Node RBNode;
315 typedef BoundingVolumeHierarchy::Node BVHNode;
317 void initElements(
const QVectorPath &path,
const QTransform &matrix);
318 void removeIntersections();
319 bool connectElements();
321 BVHNode *buildTree(Element **elements,
int elementCount);
322 bool intersectNodes(QDataBuffer<Element *> &elements, BVHNode *elementNode, BVHNode *treeNode);
323 bool equalElements(
const Element *e1,
const Element *e2);
324 bool splitLineAt(QDataBuffer<Element *> &elements, BVHNode *node, quint32 pointIndex,
bool processAgain);
325 void appendSeparatingAxes(QVarLengthArray<QPoint, 12> &axes, Element *element);
326 std::pair<
int,
int> calculateSeparatingAxisRange(
const QPoint &axis, Element *element);
327 void splitCurve(QDataBuffer<Element *> &elements, BVHNode *node);
328 bool setElementToQuadratic(Element *element, quint32 pointIndex1,
const QPoint &ctrl, quint32 pointIndex2);
329 bool setElementToCubic(Element *element, quint32 pointIndex1,
const QPoint &ctrl1,
const QPoint &ctrl2, quint32 pointIndex2);
330 void setElementToCubicAndSimplify(Element *element, quint32 pointIndex1,
const QPoint &ctrl1,
const QPoint &ctrl2, quint32 pointIndex2);
331 RBNode *findElementLeftOf(
const Element *element,
const std::pair<RBNode *, RBNode *> &bounds);
332 bool elementIsLeftOf(
const Element *left,
const Element *right);
333 std::pair<RBNode *, RBNode *> outerBounds(
const QPoint &point);
334 static bool flattenQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w);
335 static bool flattenCubic(
const QPoint &u,
const QPoint &v,
const QPoint &w,
const QPoint &q);
336 static bool splitQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w, QPoint *result);
337 static bool splitCubic(
const QPoint &u,
const QPoint &v,
const QPoint &w,
const QPoint &q, QPoint *result);
338 void subDivQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w);
339 void subDivCubic(
const QPoint &u,
const QPoint &v,
const QPoint &w,
const QPoint &q);
340 static void sortEvents(Event *events,
int count);
342 ElementAllocator m_elementAllocator;
343 QDataBuffer<Element *> m_elements;
344 QDataBuffer<QPoint> *m_points;
345 BoundingVolumeHierarchy m_bvh;
346 QDataBuffer<quint32> *m_indices;
347 QRBTree<Element *> m_elementList;
355inline PathSimplifier::BoundingVolumeHierarchy::BoundingVolumeHierarchy()
363inline PathSimplifier::BoundingVolumeHierarchy::~BoundingVolumeHierarchy()
368inline void PathSimplifier::BoundingVolumeHierarchy::allocate(
int nodeCount)
370 Q_ASSERT(nodeBlock ==
nullptr);
371 Q_ASSERT(firstFree == 0);
372 nodeBlock =
new Node[blockSize = nodeCount];
375inline void PathSimplifier::BoundingVolumeHierarchy::free()
380 firstFree = blockSize = 0;
384inline PathSimplifier::BVHNode *PathSimplifier::BoundingVolumeHierarchy::newNode()
386 if (firstFree < blockSize)
387 return &nodeBlock[firstFree++];
391inline void PathSimplifier::BoundingVolumeHierarchy::freeNode(Node *n)
395 Q_ASSERT(n->type == Node::Split || n->type == Node::Leaf);
396 if (n->type == Node::Split) {
400 if (!(n >= nodeBlock && n < nodeBlock + blockSize))
404inline PathSimplifier::ElementAllocator::ElementAllocator()
409inline PathSimplifier::ElementAllocator::~ElementAllocator()
412 ElementBlock *block = blocks;
413 blocks = blocks->next;
418inline void PathSimplifier::ElementAllocator::allocate(
int count)
420 Q_ASSERT(blocks ==
nullptr);
422 blocks = (ElementBlock *)malloc(
sizeof(ElementBlock) + (count - 1) *
sizeof(Element));
423 blocks->blockSize = count;
424 blocks->next =
nullptr;
425 blocks->firstFree = 0;
428inline PathSimplifier::Element *PathSimplifier::ElementAllocator::newElement()
431 if (blocks->firstFree < blocks->blockSize)
432 return &blocks->elements[blocks->firstFree++];
433 ElementBlock *oldBlock = blocks;
434 blocks = (ElementBlock *)malloc(
sizeof(ElementBlock) + (oldBlock->blockSize - 1) *
sizeof(Element));
435 blocks->blockSize = oldBlock->blockSize;
436 blocks->next = oldBlock;
437 blocks->firstFree = 0;
438 return &blocks->elements[blocks->firstFree++];
442inline bool PathSimplifier::Event::operator < (
const Event &other)
const
444 if (point == other.point)
445 return type < other.type;
446 return other.point < point;
449inline void PathSimplifier::Element::flip()
451 for (
int i = 0; i < (degree + 1) >> 1; ++i) {
452 Q_ASSERT(degree >= Line && degree <= Cubic);
453 Q_ASSERT(i >= 0 && i < degree);
454 qSwap(indices[i], indices[degree - i]);
456 pointingUp = !pointingUp;
457 Q_ASSERT(next ==
nullptr && previous ==
nullptr);
460PathSimplifier::PathSimplifier(
const QVectorPath &path, QDataBuffer<QPoint> &vertices,
461 QDataBuffer<quint32> &indices,
const QTransform &matrix)
463 , m_points(&vertices)
464 , m_indices(&indices)
469 initElements(path, matrix);
470 if (!m_elements.isEmpty()) {
471 removeIntersections();
472 ok = connectElements();
482void PathSimplifier::initElements(
const QVectorPath &path,
const QTransform &matrix)
484 m_hints = path.hints();
485 int pathElementCount = path.elementCount();
486 if (pathElementCount == 0)
488 m_elements.reserve(2 * pathElementCount);
489 m_elementAllocator.allocate(2 * pathElementCount);
490 m_points->reserve(2 * pathElementCount);
491 const QPainterPath::ElementType *e = path.elements();
492 const qreal *p = path.points();
495 quint32 moveToIndex = 0;
496 quint32 previousIndex = 0;
497 for (
int i = 0; i < pathElementCount; ++i, ++e, p += 2) {
499 case QPainterPath::MoveToElement:
501 if (!m_points->isEmpty()) {
502 const QPoint &from = m_points->at(previousIndex);
503 const QPoint &to = m_points->at(moveToIndex);
505 Element *element = m_elementAllocator.newElement();
506 element->degree = Element::Line;
507 element->indices[0] = previousIndex;
508 element->indices[1] = moveToIndex;
509 element->middle.rx() = (from.x() + to.x()) >> 1;
510 element->middle.ry() = (from.y() + to.y()) >> 1;
511 m_elements.add(element);
514 previousIndex = moveToIndex = m_points->size();
515 matrix.map(p[0], p[1], &x, &y);
520 case QPainterPath::LineToElement:
521 Q_ASSERT(!m_points->isEmpty());
523 matrix.map(p[0], p[1], &x, &y);
525 const QPoint &from = m_points->last();
527 Element *element = m_elementAllocator.newElement();
528 element->degree = Element::Line;
529 element->indices[0] = previousIndex;
530 element->indices[1] = quint32(m_points->size());
531 element->middle.rx() = (from.x() + to.x()) >> 1;
532 element->middle.ry() = (from.y() + to.y()) >> 1;
533 m_elements.add(element);
534 previousIndex = m_points->size();
539 case QPainterPath::CurveToElement:
540 Q_ASSERT(i + 2 < pathElementCount);
541 Q_ASSERT(!m_points->isEmpty());
542 Q_ASSERT(e[1] == QPainterPath::CurveToDataElement);
543 Q_ASSERT(e[2] == QPainterPath::CurveToDataElement);
545 quint32 startPointIndex = previousIndex;
546 matrix.map(p[4], p[5], &x, &y);
548 previousIndex = m_points->size();
552 qreal x1 = p[-2] + qreal(1.5) * (p[0] - p[-2]);
553 qreal y1 = p[-1] + qreal(1.5) * (p[1] - p[-1]);
554 qreal x2 = p[4] + qreal(1.5) * (p[2] - p[4]);
555 qreal y2 = p[5] + qreal(1.5) * (p[3] - p[5]);
557 Element *element = m_elementAllocator.newElement();
558 if (qAbs(x1 - x2) < qreal(1e-3) && qAbs(y1 - y2) < qreal(1e-3)) {
560 matrix.map(x1, y1, &x, &y);
563 setElementToQuadratic(element, startPointIndex, ctrl, previousIndex);
566 matrix.map(p[0], p[1], &x, &y);
569 matrix.map(p[2], p[3], &x, &y);
572 setElementToCubicAndSimplify(element, startPointIndex, ctrl1, ctrl2,
575 m_elements.add(element);
583 Q_ASSERT_X(0,
"QSGPathSimplifier::initialize",
"Unexpected element type.");
587 if (!m_points->isEmpty()) {
588 const QPoint &from = m_points->at(previousIndex);
589 const QPoint &to = m_points->at(moveToIndex);
591 Element *element = m_elementAllocator.newElement();
592 element->degree = Element::Line;
593 element->indices[0] = previousIndex;
594 element->indices[1] = moveToIndex;
595 element->middle.rx() = (from.x() + to.x()) >> 1;
596 element->middle.ry() = (from.y() + to.y()) >> 1;
597 m_elements.add(element);
603 for (
int i = 0; i < pathElementCount; ++i, p += 2) {
604 matrix.map(p[0], p[1], &x, &y);
606 if (to != m_points->last())
610 while (!m_points->isEmpty() && m_points->last() == m_points->first())
611 m_points->pop_back();
613 if (m_points->isEmpty())
616 quint32 prev = quint32(m_points->size() - 1);
617 for (
int i = 0; i < m_points->size(); ++i) {
618 QPoint &to = m_points->at(i);
619 QPoint &from = m_points->at(prev);
620 Element *element = m_elementAllocator.newElement();
621 element->degree = Element::Line;
622 element->indices[0] = prev;
623 element->indices[1] = quint32(i);
624 element->middle.rx() = (from.x() + to.x()) >> 1;
625 element->middle.ry() = (from.y() + to.y()) >> 1;
626 m_elements.add(element);
631 for (
int i = 0; i < m_elements.size(); ++i)
632 m_elements.at(i)->processed =
false;
635void PathSimplifier::removeIntersections()
637 Q_ASSERT(!m_elements.isEmpty());
638 QDataBuffer<Element *> elements(m_elements.size());
639 for (
int i = 0; i < m_elements.size(); ++i)
640 elements.add(m_elements.at(i));
641 m_bvh.allocate(2 * m_elements.size());
642 m_bvh.root = buildTree(elements.data(), elements.size());
645 for (
int i = 0; i < m_elements.size(); ++i)
646 elements.add(m_elements.at(i));
648 while (!elements.isEmpty()) {
649 Element *element = elements.last();
651 BVHNode *node = element->bvhNode;
652 Q_ASSERT(node->type == BVHNode::Leaf);
653 Q_ASSERT(node->element == element);
654 if (!element->processed) {
655 if (!intersectNodes(elements, node, m_bvh.root))
656 element->processed =
true;
663bool PathSimplifier::connectElements()
665 Q_ASSERT(!m_elements.isEmpty());
666 QDataBuffer<Event> events(m_elements.size() * 2);
667 for (
int i = 0; i < m_elements.size(); ++i) {
668 Element *element = m_elements.at(i);
669 element->next = element->previous =
nullptr;
670 element->winding = 0;
671 element->edgeNode =
nullptr;
672 const QPoint &u = m_points->at(element->indices[0]);
673 const QPoint &v = m_points->at(element->indices[element->degree]);
675 element->pointingUp = element->originallyPointingUp = v < u;
678 event.element = element;
680 event.type = element->pointingUp ? Event::Lower : Event::Upper;
683 event.type = element->pointingUp ? Event::Upper : Event::Lower;
687 QVarLengthArray<Element *, 8> orderedElements;
688 if (!events.isEmpty())
689 sortEvents(events.data(), events.size());
690 while (!events.isEmpty()) {
691 const Event *event = &events.last();
692 QPoint eventPoint = event->point;
695 std::pair<RBNode *, RBNode *> bounds = outerBounds(eventPoint);
698 int eventCount = events.size();
699 if (event->type == Event::Lower && eventCount > 2) {
700 std::pair<RBNode *, RBNode *> range;
701 range.first = bounds.first ? m_elementList.next(bounds.first)
702 : m_elementList.front(m_elementList.root);
703 range.second = bounds.second ? m_elementList.previous(bounds.second)
704 : m_elementList.back(m_elementList.root);
706 const Event *event2 = &events.at(eventCount - 2);
707 const Event *event3 = &events.at(eventCount - 3);
708 Q_ASSERT(event2->point == eventPoint);
709 if (range.first == range.second && event2->type == Event::Upper && event3->point != eventPoint) {
710 Element *element = event->element;
711 Element *element2 = event2->element;
712 element->edgeNode->data = event2->element;
713 element2->edgeNode = element->edgeNode;
714 element->edgeNode =
nullptr;
719 if (element2->pointingUp != element->pointingUp)
721 element2->winding = element->winding;
722 int winding = element->winding;
723 if (element->originallyPointingUp)
725 if (winding == 0 || winding == 1) {
726 if (element->pointingUp) {
727 element->previous = event2->element;
728 element2->next = event->element;
730 element->next = event2->element;
731 element2->previous = event->element;
737 orderedElements.clear();
740 if (m_elementList.root) {
741 RBNode *current = bounds.first ? m_elementList.next(bounds.first)
742 : m_elementList.front(m_elementList.root);
743 while (current != bounds.second) {
744 Element *element = current->data;
745 Q_ASSERT(element->edgeNode == current);
746 int winding = element->winding;
747 if (element->originallyPointingUp)
749 const QPoint &lower = m_points->at(element->lowerIndex());
750 if (lower == eventPoint) {
751 if (winding == 0 || winding == 1)
752 orderedElements.append(current->data);
755 Q_ASSERT(m_points->at(element->upperIndex()) != eventPoint);
756 Q_ASSERT(element->degree == Element::Line);
758 Element *eventElement = event->element;
759 int indexIndex = (event->type == Event::Upper) == eventElement->pointingUp
760 ? eventElement->degree : 0;
761 quint32 pointIndex = eventElement->indices[indexIndex];
762 Q_ASSERT(eventPoint == m_points->at(pointIndex));
764 Element *upperElement = m_elementAllocator.newElement();
765 *upperElement = *element;
766 upperElement->lowerIndex() = element->upperIndex() = pointIndex;
767 upperElement->edgeNode =
nullptr;
768 element->next = element->previous =
nullptr;
769 if (upperElement->next)
770 upperElement->next->previous = upperElement;
771 else if (upperElement->previous)
772 upperElement->previous->next = upperElement;
773 if (element->pointingUp != element->originallyPointingUp)
775 if (winding == 0 || winding == 1)
776 orderedElements.append(upperElement);
777 m_elements.add(upperElement);
779 current = m_elementList.next(current);
782 while (!events.isEmpty() && events.last().point == eventPoint) {
783 event = &events.last();
784 if (event->type == Event::Upper) {
785 Q_ASSERT(event->point == m_points->at(event->element->upperIndex()));
786 RBNode *left = findElementLeftOf(event->element, bounds);
787 RBNode *node = m_elementList.newNode();
788 node->data = event->element;
789 Q_ASSERT(event->element->edgeNode ==
nullptr);
790 event->element->edgeNode = node;
791 m_elementList.attachAfter(left, node);
793 Q_ASSERT(event->type == Event::Lower);
794 Q_ASSERT(event->point == m_points->at(event->element->lowerIndex()));
795 Element *element = event->element;
796 Q_ASSERT(element->edgeNode);
797 m_elementList.deleteNode(element->edgeNode);
798 Q_ASSERT(element->edgeNode ==
nullptr);
803 if (m_elementList.root) {
804 RBNode *current = bounds.first ? m_elementList.next(bounds.first)
805 : m_elementList.front(m_elementList.root);
806 int winding = bounds.first ? bounds.first->data->winding : 0;
809 while (current != bounds.second) {
810 Element *element = current->data;
811 Q_ASSERT(element->edgeNode == current);
812 int ccw = winding & 1;
813 Q_ASSERT(element->pointingUp == element->originallyPointingUp);
814 if (element->originallyPointingUp) {
820 element->winding = winding;
823 current = m_elementList.next(current);
827 current = bounds.second ? m_elementList.previous(bounds.second)
828 : m_elementList.back(m_elementList.root);
829 while (current != bounds.first) {
830 Element *element = current->data;
831 Q_ASSERT(element->edgeNode == current);
832 Q_ASSERT(m_points->at(element->upperIndex()) == eventPoint);
833 int winding = element->winding;
834 if (element->originallyPointingUp)
836 if (winding == 0 || winding == 1)
837 orderedElements.append(current->data);
838 current = m_elementList.previous(current);
842 if (!orderedElements.isEmpty()) {
843 if (orderedElements.size() & 1)
846 Element *firstElement = orderedElements.at(0);
847 if (m_points->at(firstElement->indices[0]) != eventPoint) {
848 orderedElements.append(firstElement);
851 for (; i < orderedElements.size(); i += 2) {
852 Q_ASSERT(i + 1 < orderedElements.size());
853 Element *next = orderedElements.at(i);
854 Element *previous = orderedElements.at(i + 1);
855 Q_ASSERT(next->previous ==
nullptr);
856 Q_ASSERT(previous->next ==
nullptr);
857 next->previous = previous;
858 previous->next = next;
863 for (
int i = 0; i < m_elements.size(); ++i) {
864 const Element *element = m_elements.at(i);
865 Q_ASSERT(element->next ==
nullptr || element->next->previous == element);
866 Q_ASSERT(element->previous ==
nullptr || element->previous->next == element);
867 Q_ASSERT((element->next ==
nullptr) == (element->previous ==
nullptr));
873void PathSimplifier::fillIndices()
875 for (
int i = 0; i < m_elements.size(); ++i)
876 m_elements.at(i)->processed =
false;
877 for (
int i = 0; i < m_elements.size(); ++i) {
878 Element *element = m_elements.at(i);
879 if (element->processed || element->next ==
nullptr)
882 m_indices->add(element->indices[0]);
883 switch (element->degree) {
884 case Element::Quadratic:
887 m_points->at(element->indices[0]),
888 m_points->at(element->indices[1]),
889 m_points->at(element->indices[2])
891 subDivQuadratic(pts[0], pts[1], pts[2]);
897 m_points->at(element->indices[0]),
898 m_points->at(element->indices[1]),
899 m_points->at(element->indices[2]),
900 m_points->at(element->indices[3])
902 subDivCubic(pts[0], pts[1], pts[2], pts[3]);
908 Q_ASSERT(element->next);
909 element->processed =
true;
910 element = element->next;
911 }
while (element != m_elements.at(i));
916PathSimplifier::BVHNode *PathSimplifier::buildTree(Element **elements,
int elementCount)
918 Q_ASSERT(elementCount > 0);
919 BVHNode *node = m_bvh.newNode();
920 if (elementCount == 1) {
921 Element *element = *elements;
922 element->bvhNode = node;
923 node->type = BVHNode::Leaf;
924 node->element = element;
925 node->minimum = node->maximum = m_points->at(element->indices[0]);
926 for (
int i = 1; i <= element->degree; ++i) {
927 const QPoint &p = m_points->at(element->indices[i]);
928 node->minimum.rx() = qMin(node->minimum.x(), p.x());
929 node->minimum.ry() = qMin(node->minimum.y(), p.y());
930 node->maximum.rx() = qMax(node->maximum.x(), p.x());
931 node->maximum.ry() = qMax(node->maximum.y(), p.y());
936 node->type = BVHNode::Split;
938 QPoint minimum, maximum;
939 minimum = maximum = elements[0]->middle;
941 for (
int i = 1; i < elementCount; ++i) {
942 const QPoint &p = elements[i]->middle;
943 minimum.rx() = qMin(minimum.x(), p.x());
944 minimum.ry() = qMin(minimum.y(), p.y());
945 maximum.rx() = qMax(maximum.x(), p.x());
946 maximum.ry() = qMax(maximum.y(), p.y());
950 if (maximum.x() - minimum.x() > maximum.y() - minimum.y()) {
952 pivot = (maximum.x() + minimum.x()) >> 1;
955 pivot = (maximum.y() + minimum.y()) >> 1;
959 int hi = elementCount - 1;
961 while (lo < hi && (&elements[lo]->middle.rx())[comp] <= pivot)
963 while (lo < hi && (&elements[hi]->middle.rx())[comp] > pivot)
966 qSwap(elements[lo], elements[hi]);
969 if (lo == elementCount) {
971 Q_ASSERT(minimum.x() == maximum.x() && minimum.y() == maximum.y());
972 lo = elementCount >> 1;
975 node->left = buildTree(elements, lo);
976 node->right = buildTree(elements + lo, elementCount - lo);
978 const BVHNode *left = node->left;
979 const BVHNode *right = node->right;
980 node->minimum.rx() = qMin(left->minimum.x(), right->minimum.x());
981 node->minimum.ry() = qMin(left->minimum.y(), right->minimum.y());
982 node->maximum.rx() = qMax(left->maximum.x(), right->maximum.x());
983 node->maximum.ry() = qMax(left->maximum.y(), right->maximum.y());
988bool PathSimplifier::intersectNodes(QDataBuffer<Element *> &elements, BVHNode *elementNode,
991 if (elementNode->minimum.x() >= treeNode->maximum.x()
992 || elementNode->minimum.y() >= treeNode->maximum.y()
993 || elementNode->maximum.x() <= treeNode->minimum.x()
994 || elementNode->maximum.y() <= treeNode->minimum.y())
999 Q_ASSERT(elementNode->type == BVHNode::Leaf);
1000 Element *element = elementNode->element;
1001 Q_ASSERT(!element->processed);
1003 if (treeNode->type == BVHNode::Leaf) {
1004 Element *nodeElement = treeNode->element;
1005 if (!nodeElement->processed)
1008 if (treeNode->element == elementNode->element)
1011 if (equalElements(treeNode->element, elementNode->element))
1014 if (element->degree == Element::Line && nodeElement->degree == Element::Line) {
1015 const QPoint &u1 = m_points->at(element->indices[0]);
1016 const QPoint &u2 = m_points->at(element->indices[1]);
1017 const QPoint &v1 = m_points->at(nodeElement->indices[0]);
1018 const QPoint &v2 = m_points->at(nodeElement->indices[1]);
1019 IntersectionPoint intersection = intersectionPoint(u1, u2, v1, v2);
1020 if (!intersection.isValid())
1023 Q_ASSERT(intersection.x.integer >= qMin(u1.x(), u2.x()));
1024 Q_ASSERT(intersection.y.integer >= qMin(u1.y(), u2.y()));
1025 Q_ASSERT(intersection.x.integer >= qMin(v1.x(), v2.x()));
1026 Q_ASSERT(intersection.y.integer >= qMin(v1.y(), v2.y()));
1028 Q_ASSERT(intersection.x.integer <= qMax(u1.x(), u2.x()));
1029 Q_ASSERT(intersection.y.integer <= qMax(u1.y(), u2.y()));
1030 Q_ASSERT(intersection.x.integer <= qMax(v1.x(), v2.x()));
1031 Q_ASSERT(intersection.y.integer <= qMax(v1.y(), v2.y()));
1033 m_points->add(intersection.round());
1034 splitLineAt(elements, treeNode, m_points->size() - 1, !intersection.isAccurate());
1035 return splitLineAt(elements, elementNode, m_points->size() - 1,
false);
1037 QVarLengthArray<QPoint, 12> axes;
1038 appendSeparatingAxes(axes, elementNode->element);
1039 appendSeparatingAxes(axes, treeNode->element);
1040 for (
int i = 0; i < axes.size(); ++i) {
1041 std::pair<
int,
int> range1 = calculateSeparatingAxisRange(axes.at(i), elementNode->element);
1042 std::pair<
int,
int> range2 = calculateSeparatingAxisRange(axes.at(i), treeNode->element);
1043 if (range1.first >= range2.second || range1.second <= range2.first) {
1048 if (nodeElement->degree > Element::Line)
1049 splitCurve(elements, treeNode);
1050 if (element->degree > Element::Line) {
1051 splitCurve(elements, elementNode);
1054 if (intersectNodes(elements, elementNode, treeNode->left))
1056 if (intersectNodes(elements, elementNode, treeNode->right))
1063 if (intersectNodes(elements, elementNode, treeNode->left))
1065 if (intersectNodes(elements, elementNode, treeNode->right))
1071bool PathSimplifier::equalElements(
const Element *e1,
const Element *e2)
1074 if (e1->degree != e2->degree)
1078 bool equalSame =
true;
1079 for (
int i = 0; i <= e1->degree; ++i)
1080 equalSame &= m_points->at(e1->indices[i]) == m_points->at(e2->indices[i]);
1083 bool equalOpposite =
true;
1084 for (
int i = 0; i <= e1->degree; ++i)
1085 equalOpposite &= m_points->at(e1->indices[e1->degree - i]) == m_points->at(e2->indices[i]);
1087 return equalSame || equalOpposite;
1090bool PathSimplifier::splitLineAt(QDataBuffer<Element *> &elements, BVHNode *node,
1091 quint32 pointIndex,
bool processAgain)
1093 Q_ASSERT(node->type == BVHNode::Leaf);
1094 Element *element = node->element;
1095 Q_ASSERT(element->degree == Element::Line);
1096 const QPoint &u = m_points->at(element->indices[0]);
1097 const QPoint &v = m_points->at(element->indices[1]);
1098 const QPoint &p = m_points->at(pointIndex);
1099 if (u == p || v == p)
1103 element->processed =
false;
1105 Element *first = node->element;
1106 Element *second = m_elementAllocator.newElement();
1108 first->indices[1] = second->indices[0] = pointIndex;
1109 first->middle.rx() = (u.x() + p.x()) >> 1;
1110 first->middle.ry() = (u.y() + p.y()) >> 1;
1111 second->middle.rx() = (v.x() + p.x()) >> 1;
1112 second->middle.ry() = (v.y() + p.y()) >> 1;
1113 m_elements.add(second);
1115 BVHNode *left = m_bvh.newNode();
1116 BVHNode *right = m_bvh.newNode();
1117 left->type = right->type = BVHNode::Leaf;
1118 left->element = first;
1119 right->element = second;
1120 left->minimum = right->minimum = node->minimum;
1121 left->maximum = right->maximum = node->maximum;
1123 left->maximum.rx() = right->minimum.rx() = p.x();
1125 left->minimum.rx() = right->maximum.rx() = p.x();
1127 left->maximum.ry() = right->minimum.ry() = p.y();
1129 left->minimum.ry() = right->maximum.ry() = p.y();
1130 left->element->bvhNode = left;
1131 right->element->bvhNode = right;
1133 node->type = BVHNode::Split;
1135 node->right = right;
1137 if (!first->processed) {
1138 elements.add(left->element);
1139 elements.add(right->element);
1144void PathSimplifier::appendSeparatingAxes(QVarLengthArray<QPoint, 12> &axes, Element *element)
1146 switch (element->degree) {
1147 case Element::Cubic:
1149 const QPoint &u = m_points->at(element->indices[0]);
1150 const QPoint &v = m_points->at(element->indices[1]);
1151 const QPoint &w = m_points->at(element->indices[2]);
1152 const QPoint &q = m_points->at(element->indices[3]);
1154 QPoint(u.y() - v.y(), v.x() - u.x()),
1155 QPoint(v.y() - w.y(), w.x() - v.x()),
1156 QPoint(w.y() - q.y(), q.x() - w.x()),
1157 QPoint(q.y() - u.y(), u.x() - q.x()),
1158 QPoint(u.y() - w.y(), w.x() - u.x()),
1159 QPoint(v.y() - q.y(), q.x() - v.x())
1161 for (
int i = 0; i < 6; ++i) {
1162 if (ns[i].x() || ns[i].y())
1167 case Element::Quadratic:
1169 const QPoint &u = m_points->at(element->indices[0]);
1170 const QPoint &v = m_points->at(element->indices[1]);
1171 const QPoint &w = m_points->at(element->indices[2]);
1173 QPoint(u.y() - v.y(), v.x() - u.x()),
1174 QPoint(v.y() - w.y(), w.x() - v.x()),
1175 QPoint(w.y() - u.y(), u.x() - w.x())
1177 for (
int i = 0; i < 3; ++i) {
1178 if (ns[i].x() || ns[i].y())
1185 const QPoint &u = m_points->at(element->indices[0]);
1186 const QPoint &v = m_points->at(element->indices[1]);
1187 QPoint n(u.y() - v.y(), v.x() - u.x());
1193 Q_ASSERT_X(0,
"QSGPathSimplifier::appendSeparatingAxes",
"Unexpected element type.");
1198std::pair<
int,
int> PathSimplifier::calculateSeparatingAxisRange(
const QPoint &axis, Element *element)
1200 std::pair<
int,
int> range(0x7fffffff, -0x7fffffff);
1201 for (
int i = 0; i <= element->degree; ++i) {
1202 const QPoint &p = m_points->at(element->indices[i]);
1203 int dist = dot(axis, p);
1204 range.first = qMin(range.first, dist);
1205 range.second = qMax(range.second, dist);
1210void PathSimplifier::splitCurve(QDataBuffer<Element *> &elements, BVHNode *node)
1212 Q_ASSERT(node->type == BVHNode::Leaf);
1214 Element *first = node->element;
1215 Element *second = m_elementAllocator.newElement();
1217 m_elements.add(second);
1218 Q_ASSERT(first->degree > Element::Line);
1220 bool accurate =
true;
1221 const QPoint &u = m_points->at(first->indices[0]);
1222 const QPoint &v = m_points->at(first->indices[1]);
1223 const QPoint &w = m_points->at(first->indices[2]);
1225 if (first->degree == Element::Quadratic) {
1227 accurate = splitQuadratic(u, v, w, pts);
1228 int pointIndex = m_points->size();
1229 m_points->add(pts[1]);
1230 accurate &= setElementToQuadratic(first, first->indices[0], pts[0], pointIndex);
1231 accurate &= setElementToQuadratic(second, pointIndex, pts[2], second->indices[2]);
1233 Q_ASSERT(first->degree == Element::Cubic);
1234 const QPoint &q = m_points->at(first->indices[3]);
1236 accurate = splitCubic(u, v, w, q, pts);
1237 int pointIndex = m_points->size();
1238 m_points->add(pts[2]);
1239 accurate &= setElementToCubic(first, first->indices[0], pts[0], pts[1], pointIndex);
1240 accurate &= setElementToCubic(second, pointIndex, pts[3], pts[4], second->indices[3]);
1244 first->processed = second->processed =
false;
1246 BVHNode *left = m_bvh.newNode();
1247 BVHNode *right = m_bvh.newNode();
1248 left->type = right->type = BVHNode::Leaf;
1249 left->element = first;
1250 right->element = second;
1252 left->minimum.rx() = left->minimum.ry() = right->minimum.rx() = right->minimum.ry() = INT_MAX;
1253 left->maximum.rx() = left->maximum.ry() = right->maximum.rx() = right->maximum.ry() = INT_MIN;
1255 for (
int i = 0; i <= first->degree; ++i) {
1256 QPoint &p = m_points->at(first->indices[i]);
1257 left->minimum.rx() = qMin(left->minimum.x(), p.x());
1258 left->minimum.ry() = qMin(left->minimum.y(), p.y());
1259 left->maximum.rx() = qMax(left->maximum.x(), p.x());
1260 left->maximum.ry() = qMax(left->maximum.y(), p.y());
1262 for (
int i = 0; i <= second->degree; ++i) {
1263 QPoint &p = m_points->at(second->indices[i]);
1264 right->minimum.rx() = qMin(right->minimum.x(), p.x());
1265 right->minimum.ry() = qMin(right->minimum.y(), p.y());
1266 right->maximum.rx() = qMax(right->maximum.x(), p.x());
1267 right->maximum.ry() = qMax(right->maximum.y(), p.y());
1269 left->element->bvhNode = left;
1270 right->element->bvhNode = right;
1272 node->type = BVHNode::Split;
1274 node->right = right;
1276 if (!first->processed) {
1277 elements.add(left->element);
1278 elements.add(right->element);
1282bool PathSimplifier::setElementToQuadratic(Element *element, quint32 pointIndex1,
1283 const QPoint &ctrl, quint32 pointIndex2)
1285 const QPoint &p1 = m_points->at(pointIndex1);
1286 const QPoint &p2 = m_points->at(pointIndex2);
1287 if (flattenQuadratic(p1, ctrl, p2)) {
1289 element->degree = Element::Line;
1290 element->indices[0] = pointIndex1;
1291 element->indices[1] = pointIndex2;
1292 element->middle.rx() = (p1.x() + p2.x()) >> 1;
1293 element->middle.ry() = (p1.y() + p2.y()) >> 1;
1297 element->degree = Element::Quadratic;
1298 element->indices[0] = pointIndex1;
1299 element->indices[1] = m_points->size();
1300 element->indices[2] = pointIndex2;
1301 element->middle.rx() = (p1.x() + ctrl.x() + p2.x()) / 3;
1302 element->middle.ry() = (p1.y() + ctrl.y() + p2.y()) / 3;
1303 m_points->add(ctrl);
1308bool PathSimplifier::setElementToCubic(Element *element, quint32 pointIndex1,
const QPoint &v,
1309 const QPoint &w, quint32 pointIndex2)
1311 const QPoint &u = m_points->at(pointIndex1);
1312 const QPoint &q = m_points->at(pointIndex2);
1313 if (flattenCubic(u, v, w, q)) {
1315 element->degree = Element::Line;
1316 element->indices[0] = pointIndex1;
1317 element->indices[1] = pointIndex2;
1318 element->middle.rx() = (u.x() + q.x()) >> 1;
1319 element->middle.ry() = (u.y() + q.y()) >> 1;
1323 element->degree = Element::Cubic;
1324 element->indices[0] = pointIndex1;
1325 element->indices[1] = m_points->size();
1326 element->indices[2] = m_points->size() + 1;
1327 element->indices[3] = pointIndex2;
1328 element->middle.rx() = (u.x() + v.x() + w.x() + q.x()) >> 2;
1329 element->middle.ry() = (u.y() + v.y() + w.y() + q.y()) >> 2;
1336void PathSimplifier::setElementToCubicAndSimplify(Element *element, quint32 pointIndex1,
1337 const QPoint &v,
const QPoint &w,
1338 quint32 pointIndex2)
1340 const QPoint &u = m_points->at(pointIndex1);
1341 const QPoint &q = m_points->at(pointIndex2);
1342 if (flattenCubic(u, v, w, q)) {
1344 element->degree = Element::Line;
1345 element->indices[0] = pointIndex1;
1346 element->indices[1] = pointIndex2;
1347 element->middle.rx() = (u.x() + q.x()) >> 1;
1348 element->middle.ry() = (u.y() + q.y()) >> 1;
1352 bool intersecting = (u == q) || intersectionPoint(u, v, w, q).isValid();
1353 if (!intersecting) {
1355 element->degree = Element::Cubic;
1356 element->indices[0] = pointIndex1;
1357 element->indices[1] = m_points->size();
1358 element->indices[2] = m_points->size() + 1;
1359 element->indices[3] = pointIndex2;
1360 element->middle.rx() = (u.x() + v.x() + w.x() + q.x()) >> 2;
1361 element->middle.ry() = (u.y() + v.y() + w.y() + q.y()) >> 2;
1368 splitCubic(u, v, w, q, pts);
1369 int pointIndex = m_points->size();
1370 m_points->add(pts[2]);
1371 Element *element2 = m_elementAllocator.newElement();
1372 m_elements.add(element2);
1373 setElementToCubicAndSimplify(element, pointIndex1, pts[0], pts[1], pointIndex);
1374 setElementToCubicAndSimplify(element2, pointIndex, pts[3], pts[4], pointIndex2);
1377PathSimplifier::RBNode *PathSimplifier::findElementLeftOf(
const Element *element,
1378 const std::pair<RBNode *, RBNode *> &bounds)
1380 if (!m_elementList.root)
1382 RBNode *current = bounds.first;
1383 Q_ASSERT(!current || !elementIsLeftOf(element, current->data));
1385 current = m_elementList.front(m_elementList.root);
1387 RBNode *result =
nullptr;
1388 while (current != bounds.second && !elementIsLeftOf(element, current->data)) {
1390 current = m_elementList.next(current);
1395bool PathSimplifier::elementIsLeftOf(
const Element *left,
const Element *right)
1397 const QPoint &leftU = m_points->at(left->upperIndex());
1398 const QPoint &leftL = m_points->at(left->lowerIndex());
1399 const QPoint &rightU = m_points->at(right->upperIndex());
1400 const QPoint &rightL = m_points->at(right->lowerIndex());
1401 Q_ASSERT(leftL >= rightU && rightL >= leftU);
1402 if (leftU.x() < qMin(rightL.x(), rightU.x()))
1404 if (leftU.x() > qMax(rightL.x(), rightU.x()))
1406 int d = pointSideOfLine(leftU, rightL, rightU);
1409 d = pointSideOfLine(leftL, rightL, rightU);
1411 if (right->degree > Element::Line) {
1412 d = pointSideOfLine(leftL, rightL, m_points->at(right->indices[1]));
1414 d = pointSideOfLine(leftL, rightL, m_points->at(right->indices[2]));
1415 }
else if (left->degree > Element::Line) {
1416 d = pointSideOfLine(m_points->at(left->indices[1]), rightL, rightU);
1418 d = pointSideOfLine(m_points->at(left->indices[2]), rightL, rightU);
1425std::pair<PathSimplifier::RBNode *, PathSimplifier::RBNode *> PathSimplifier::outerBounds(
const QPoint &point)
1427 RBNode *current = m_elementList.root;
1428 std::pair<RBNode *, RBNode *> result(
nullptr,
nullptr);
1431 const Element *element = current->data;
1432 Q_ASSERT(element->edgeNode == current);
1433 const QPoint &v1 = m_points->at(element->lowerIndex());
1434 const QPoint &v2 = m_points->at(element->upperIndex());
1435 Q_ASSERT(point >= v2 && point <= v1);
1436 if (point == v1 || point == v2)
1438 int d = pointSideOfLine(point, v1, v2);
1440 if (element->degree == Element::Line)
1442 d = pointSideOfLine(point, v1, m_points->at(element->indices[1]));
1444 d = pointSideOfLine(point, v1, m_points->at(element->indices[2]));
1448 result.second = current;
1449 current = current->left;
1451 result.first = current;
1452 current = current->right;
1459 RBNode *mid = current;
1461 current = mid->left;
1463 const Element *element = current->data;
1464 Q_ASSERT(element->edgeNode == current);
1465 const QPoint &v1 = m_points->at(element->lowerIndex());
1466 const QPoint &v2 = m_points->at(element->upperIndex());
1467 Q_ASSERT(point >= v2 && point <= v1);
1468 bool equal = (point == v1 || point == v2);
1470 int d = pointSideOfLine(point, v1, v2);
1472 equal = (d == 0 && element->degree == Element::Line);
1475 current = current->left;
1477 result.first = current;
1478 current = current->right;
1482 current = mid->right;
1484 const Element *element = current->data;
1485 Q_ASSERT(element->edgeNode == current);
1486 const QPoint &v1 = m_points->at(element->lowerIndex());
1487 const QPoint &v2 = m_points->at(element->upperIndex());
1488 Q_ASSERT(point >= v2 && point <= v1);
1489 bool equal = (point == v1 || point == v2);
1491 int d = pointSideOfLine(point, v1, v2);
1493 equal = (d == 0 && element->degree == Element::Line);
1496 current = current->right;
1498 result.second = current;
1499 current = current->left;
1506inline bool PathSimplifier::flattenQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w)
1508 QPoint deltas[2] = { v - u, w - v };
1509 int d = qAbs(cross(deltas[0], deltas[1]));
1510 int l = qAbs(deltas[0].x()) + qAbs(deltas[0].y()) + qAbs(deltas[1].x()) + qAbs(deltas[1].y());
1514inline bool PathSimplifier::flattenCubic(
const QPoint &u,
const QPoint &v,
1515 const QPoint &w,
const QPoint &q)
1517 QPoint deltas[] = { v - u, w - v, q - w, q - u };
1518 int d = qAbs(cross(deltas[0], deltas[1])) + qAbs(cross(deltas[1], deltas[2]))
1519 + qAbs(cross(deltas[0], deltas[3])) + qAbs(cross(deltas[3], deltas[2]));
1520 int l = qAbs(deltas[0].x()) + qAbs(deltas[0].y()) + qAbs(deltas[1].x()) + qAbs(deltas[1].y())
1521 + qAbs(deltas[2].x()) + qAbs(deltas[2].y());
1525inline bool PathSimplifier::splitQuadratic(
const QPoint &u,
const QPoint &v,
1526 const QPoint &w, QPoint *result)
1530 result[1] = result[0] + result[2];
1531 bool accurate = ((result[0].x() | result[0].y() | result[2].x() | result[2].y()) & 1) == 0
1532 && ((result[1].x() | result[1].y()) & 3) == 0;
1533 result[0].rx() >>= 1;
1534 result[0].ry() >>= 1;
1535 result[1].rx() >>= 2;
1536 result[1].ry() >>= 2;
1537 result[2].rx() >>= 1;
1538 result[2].ry() >>= 1;
1542inline bool PathSimplifier::splitCubic(
const QPoint &u,
const QPoint &v,
1543 const QPoint &w,
const QPoint &q, QPoint *result)
1548 result[1] = result[0] + result[2];
1549 result[3] = result[2] + result[4];
1550 result[2] = result[1] + result[3];
1551 bool accurate = ((result[0].x() | result[0].y() | result[4].x() | result[4].y()) & 1) == 0
1552 && ((result[1].x() | result[1].y() | result[3].x() | result[3].y()) & 3) == 0
1553 && ((result[2].x() | result[2].y()) & 7) == 0;
1554 result[0].rx() >>= 1;
1555 result[0].ry() >>= 1;
1556 result[1].rx() >>= 2;
1557 result[1].ry() >>= 2;
1558 result[2].rx() >>= 3;
1559 result[2].ry() >>= 3;
1560 result[3].rx() >>= 2;
1561 result[3].ry() >>= 2;
1562 result[4].rx() >>= 1;
1563 result[4].ry() >>= 1;
1567inline void PathSimplifier::subDivQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w)
1569 if (flattenQuadratic(u, v, w))
1572 splitQuadratic(u, v, w, pts);
1573 subDivQuadratic(u, pts[0], pts[1]);
1574 m_indices->add(m_points->size());
1575 m_points->add(pts[1]);
1576 subDivQuadratic(pts[1], pts[2], w);
1579inline void PathSimplifier::subDivCubic(
const QPoint &u,
const QPoint &v,
1580 const QPoint &w,
const QPoint &q)
1582 if (flattenCubic(u, v, w, q))
1585 splitCubic(u, v, w, q, pts);
1586 subDivCubic(u, pts[0], pts[1], pts[2]);
1587 m_indices->add(m_points->size());
1588 m_points->add(pts[2]);
1589 subDivCubic(pts[2], pts[3], pts[4], q);
1592void PathSimplifier::sortEvents(Event *events,
int count)
1595 Q_ASSERT(count > 0);
1596 QDataBuffer<Event> buffer(count);
1597 buffer.resize(count);
1598 QScopedArrayPointer<
int> bins(
new int[count]);
1600 memset(counts, 0,
sizeof(counts));
1602 int minimum, maximum;
1603 minimum = maximum = events[0].point.y();
1604 for (
int i = 1; i < count; ++i) {
1605 minimum = qMin(minimum, events[i].point.y());
1606 maximum = qMax(maximum, events[i].point.y());
1609 for (
int i = 0; i < count; ++i) {
1610 bins[i] = ((maximum - events[i].point.y()) << 8) / (maximum - minimum + 1);
1611 Q_ASSERT(bins[i] >= 0 && bins[i] < 0x100);
1615 for (
int i = 1; i < 0x100; ++i)
1616 counts[i] += counts[i - 1];
1617 counts[0x100] = counts[0xff];
1618 Q_ASSERT(counts[0x100] == count);
1620 for (
int i = 0; i < count; ++i)
1621 buffer.at(--counts[bins[i]]) = events[i];
1624 for (
int i = 0; i < 0x100; ++i) {
1625 for (; j < counts[i + 1]; ++j) {
1627 while (k > 0 && (buffer.at(j) < events[k - 1])) {
1628 events[k] = events[k - 1];
1631 events[k] = buffer.at(j);
1637 QDataBuffer<quint32> &indices,
const QTransform &matrix)
1639 PathSimplifier(path, vertices, indices, matrix);
1643 QDataBuffer<quint32> &indices,
const QTransform &matrix)
1645 qSimplifyPath(qtVectorPathForPath(path), vertices, indices, matrix);
1651#undef Q_FIXED_POINT_SCALE
bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
void qSimplifyPath(const QVectorPath &path, QDataBuffer< QPoint > &vertices, QDataBuffer< quint32 > &indices, const QTransform &matrix)
bool operator<=(const QPoint &a, const QPoint &b)
bool operator>=(const QPoint &a, const QPoint &b)
#define Q_TRIANGULATE_END_OF_POLYGON
#define Q_FIXED_POINT_SCALE
bool operator>(const QPoint &a, const QPoint &b)
Q_DECLARE_TYPEINFO(PathSimplifier::Event, Q_PRIMITIVE_TYPE)