7#include <QtCore/qvarlengtharray.h>
8#include <QtCore/qglobal.h>
9#include <QtCore/qpoint.h>
10#include <QtCore/qalgorithms.h>
13# include <private/qopengl_p.h>
15#include <private/qrbtree_p.h>
19#define Q_FIXED_POINT_SCALE 256
20#define Q_TRIANGULATE_END_OF_POLYGON quint32(-1
)
28inline bool operator < (
const QPoint &a,
const QPoint &b)
30 return a.y() < b.y() || (a.y() == b.y() && a.x() < b.x());
33inline bool operator > (
const QPoint &a,
const QPoint &b)
38inline bool operator <= (
const QPoint &a,
const QPoint &b)
43inline bool operator >= (
const QPoint &a,
const QPoint &b)
50inline int cross(
const QPoint &u,
const QPoint &v)
52 return u.x() * v.y() - u.y() * v.x();
55inline int dot(
const QPoint &u,
const QPoint &v)
57 return u.x() * v.x() + u.y() * v.y();
67 bool isValid()
const {
return denominator != 0; }
70 unsigned int numerator, denominator;
73inline unsigned int gcd(
unsigned int x,
unsigned int y)
85Fraction fraction(
unsigned int n,
unsigned int d) {
89 result.denominator = 1;
91 unsigned int g = gcd(n, d);
92 result.numerator = n / g;
93 result.denominator = d / g;
112struct IntersectionPoint
114 bool isValid()
const {
return x.fraction.isValid() && y.fraction.isValid(); }
115 QPoint round()
const;
116 bool isAccurate()
const {
return x.fraction.numerator == 0 && y.fraction.numerator == 0; }
122QPoint IntersectionPoint::round()
const
124 QPoint result(x.integer, y.integer);
125 if (2 * x.fraction.numerator >= x.fraction.denominator)
127 if (2 * y.fraction.numerator >= y.fraction.denominator)
135inline int pointSideOfLine(
const QPoint &p,
const QPoint &v1,
const QPoint &v2)
137 qint64 ux = qint64(v2.x()) - v1.x();
138 qint64 uy = qint64(v2.y()) - v1.y();
139 qint64 vx = qint64(p.x()) - v1.x();
140 qint64 vy = qint64(p.y()) - v1.y();
141 qint64 c = (ux * vy) - (uy * vx);
142 return (c > 0) ? 1 : (c < 0) ? -1 : 0;
145IntersectionPoint intersectionPoint(
const QPoint &u1,
const QPoint &u2,
146 const QPoint &v1,
const QPoint &v2)
148 IntersectionPoint result = {{0, {0, 0}}, {0, {0, 0}}};
152 int d1 = cross(u, v1 - u1);
153 int d2 = cross(u, v2 - u1);
155 int d3 = cross(v, u1 - v1);
159 Q_ASSERT(d4 == cross(v, u2 - v1));
181 if (d1 >= 0 || d2 <= 0 || d3 <= 0 || d4 >= 0)
190 result.x.integer = v1.x() +
int(qint64(-v.x()) * d1 / det);
191 result.x.fraction = fraction((
unsigned int)(qint64(-v.x()) * d1 % det), (
unsigned int)det);
193 result.x.integer = v2.x() +
int(qint64(-v.x()) * d2 / det);
194 result.x.fraction = fraction((
unsigned int)(qint64(-v.x()) * d2 % det), (
unsigned int)det);
198 result.y.integer = v1.y() +
int(qint64(-v.y()) * d1 / det);
199 result.y.fraction = fraction((
unsigned int)(qint64(-v.y()) * d1 % det), (
unsigned int)det);
201 result.y.integer = v2.y() +
int(qint64(-v.y()) * d2 / det);
202 result.y.fraction = fraction((
unsigned int)(qint64(-v.y()) * d2 % det), (
unsigned int)det);
205 Q_ASSERT(result.x.fraction.isValid());
206 Q_ASSERT(result.y.fraction.isValid());
217 PathSimplifier(
const QVectorPath &path, QDataBuffer<QPoint> &vertices,
218 QDataBuffer<quint32> &indices,
const QTransform &matrix);
223 class BoundingVolumeHierarchy
243 BoundingVolumeHierarchy();
244 ~BoundingVolumeHierarchy();
245 void allocate(
int nodeCount);
251 void freeNode(Node *n);
267 quint32 &upperIndex() {
return indices[pointingUp ? degree : 0]; }
268 quint32 &lowerIndex() {
return indices[pointingUp ? 0 : degree]; }
269 quint32 upperIndex()
const {
return indices[pointingUp ? degree : 0]; }
270 quint32 lowerIndex()
const {
return indices[pointingUp ? 0 : degree]; }
275 Element *next, *previous;
278 QRBTree<Element *>::Node *edgeNode;
279 BoundingVolumeHierarchy::Node *bvhNode;
284 uint originallyPointingUp : 1;
287 class ElementAllocator
292 void allocate(
int count);
293 Element *newElement();
306 enum Type { Upper, Lower };
307 bool operator < (
const Event &other)
const;
313 friend class QTypeInfo<Event>;
315 typedef QRBTree<Element *>::Node RBNode;
316 typedef BoundingVolumeHierarchy::Node BVHNode;
318 void initElements(
const QVectorPath &path,
const QTransform &matrix);
319 void removeIntersections();
320 bool connectElements();
322 BVHNode *buildTree(Element **elements,
int elementCount);
323 bool intersectNodes(QDataBuffer<Element *> &elements, BVHNode *elementNode, BVHNode *treeNode);
324 bool equalElements(
const Element *e1,
const Element *e2);
325 bool splitLineAt(QDataBuffer<Element *> &elements, BVHNode *node, quint32 pointIndex,
bool processAgain);
326 void appendSeparatingAxes(QVarLengthArray<QPoint, 12> &axes, Element *element);
327 std::pair<
int,
int> calculateSeparatingAxisRange(
const QPoint &axis, Element *element);
328 void splitCurve(QDataBuffer<Element *> &elements, BVHNode *node);
329 bool setElementToQuadratic(Element *element, quint32 pointIndex1,
const QPoint &ctrl, quint32 pointIndex2);
330 bool setElementToCubic(Element *element, quint32 pointIndex1,
const QPoint &ctrl1,
const QPoint &ctrl2, quint32 pointIndex2);
331 void setElementToCubicAndSimplify(Element *element, quint32 pointIndex1,
const QPoint &ctrl1,
const QPoint &ctrl2, quint32 pointIndex2);
332 RBNode *findElementLeftOf(
const Element *element,
const std::pair<RBNode *, RBNode *> &bounds);
333 bool elementIsLeftOf(
const Element *left,
const Element *right);
334 std::pair<RBNode *, RBNode *> outerBounds(
const QPoint &point);
335 static bool flattenQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w);
336 static bool flattenCubic(
const QPoint &u,
const QPoint &v,
const QPoint &w,
const QPoint &q);
337 static bool splitQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w, QPoint *result);
338 static bool splitCubic(
const QPoint &u,
const QPoint &v,
const QPoint &w,
const QPoint &q, QPoint *result);
339 void subDivQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w);
340 void subDivCubic(
const QPoint &u,
const QPoint &v,
const QPoint &w,
const QPoint &q);
341 static void sortEvents(Event *events,
int count);
343 ElementAllocator m_elementAllocator;
344 QDataBuffer<Element *> m_elements;
345 QDataBuffer<QPoint> *m_points;
346 BoundingVolumeHierarchy m_bvh;
347 QDataBuffer<quint32> *m_indices;
348 QRBTree<Element *> m_elementList;
356inline PathSimplifier::BoundingVolumeHierarchy::BoundingVolumeHierarchy()
364inline PathSimplifier::BoundingVolumeHierarchy::~BoundingVolumeHierarchy()
369inline void PathSimplifier::BoundingVolumeHierarchy::allocate(
int nodeCount)
371 Q_ASSERT(nodeBlock ==
nullptr);
372 Q_ASSERT(firstFree == 0);
373 nodeBlock =
new Node[blockSize = nodeCount];
376inline void PathSimplifier::BoundingVolumeHierarchy::free()
381 firstFree = blockSize = 0;
385inline PathSimplifier::BVHNode *PathSimplifier::BoundingVolumeHierarchy::newNode()
387 if (firstFree < blockSize)
388 return &nodeBlock[firstFree++];
392inline void PathSimplifier::BoundingVolumeHierarchy::freeNode(Node *n)
396 Q_ASSERT(n->type == Node::Split || n->type == Node::Leaf);
397 if (n->type == Node::Split) {
401 if (!(n >= nodeBlock && n < nodeBlock + blockSize))
405inline PathSimplifier::ElementAllocator::ElementAllocator()
410inline PathSimplifier::ElementAllocator::~ElementAllocator()
413 ElementBlock *block = blocks;
414 blocks = blocks->next;
419inline void PathSimplifier::ElementAllocator::allocate(
int count)
421 Q_ASSERT(blocks ==
nullptr);
423 blocks = (ElementBlock *)malloc(
sizeof(ElementBlock) + (count - 1) *
sizeof(Element));
424 blocks->blockSize = count;
425 blocks->next =
nullptr;
426 blocks->firstFree = 0;
429inline PathSimplifier::Element *PathSimplifier::ElementAllocator::newElement()
432 if (blocks->firstFree < blocks->blockSize)
433 return &blocks->elements[blocks->firstFree++];
434 ElementBlock *oldBlock = blocks;
435 blocks = (ElementBlock *)malloc(
sizeof(ElementBlock) + (oldBlock->blockSize - 1) *
sizeof(Element));
436 blocks->blockSize = oldBlock->blockSize;
437 blocks->next = oldBlock;
438 blocks->firstFree = 0;
439 return &blocks->elements[blocks->firstFree++];
443inline bool PathSimplifier::Event::operator < (
const Event &other)
const
445 if (point == other.point)
446 return type < other.type;
447 return other.point < point;
450inline void PathSimplifier::Element::flip()
452 for (
int i = 0; i < (degree + 1) >> 1; ++i) {
453 Q_ASSERT(degree >= Line && degree <= Cubic);
454 Q_ASSERT(i >= 0 && i < degree);
455 qSwap(indices[i], indices[degree - i]);
457 pointingUp = !pointingUp;
458 Q_ASSERT(next ==
nullptr && previous ==
nullptr);
461PathSimplifier::PathSimplifier(
const QVectorPath &path, QDataBuffer<QPoint> &vertices,
462 QDataBuffer<quint32> &indices,
const QTransform &matrix)
464 , m_points(&vertices)
465 , m_indices(&indices)
470 initElements(path, matrix);
471 if (!m_elements.isEmpty()) {
472 removeIntersections();
473 ok = connectElements();
483void PathSimplifier::initElements(
const QVectorPath &path,
const QTransform &matrix)
485 m_hints = path.hints();
486 int pathElementCount = path.elementCount();
487 if (pathElementCount == 0)
489 m_elements.reserve(2 * pathElementCount);
490 m_elementAllocator.allocate(2 * pathElementCount);
491 m_points->reserve(2 * pathElementCount);
492 const QPainterPath::ElementType *e = path.elements();
493 const qreal *p = path.points();
496 quint32 moveToIndex = 0;
497 quint32 previousIndex = 0;
498 for (
int i = 0; i < pathElementCount; ++i, ++e, p += 2) {
500 case QPainterPath::MoveToElement:
502 if (!m_points->isEmpty()) {
503 const QPoint &from = m_points->at(previousIndex);
504 const QPoint &to = m_points->at(moveToIndex);
506 Element *element = m_elementAllocator.newElement();
507 element->degree = Element::Line;
508 element->indices[0] = previousIndex;
509 element->indices[1] = moveToIndex;
510 element->middle.rx() = (from.x() + to.x()) >> 1;
511 element->middle.ry() = (from.y() + to.y()) >> 1;
512 m_elements.add(element);
515 previousIndex = moveToIndex = m_points->size();
516 matrix.map(p[0], p[1], &x, &y);
521 case QPainterPath::LineToElement:
522 Q_ASSERT(!m_points->isEmpty());
524 matrix.map(p[0], p[1], &x, &y);
526 const QPoint &from = m_points->last();
528 Element *element = m_elementAllocator.newElement();
529 element->degree = Element::Line;
530 element->indices[0] = previousIndex;
531 element->indices[1] = quint32(m_points->size());
532 element->middle.rx() = (from.x() + to.x()) >> 1;
533 element->middle.ry() = (from.y() + to.y()) >> 1;
534 m_elements.add(element);
535 previousIndex = m_points->size();
540 case QPainterPath::CurveToElement:
541 Q_ASSERT(i + 2 < pathElementCount);
542 Q_ASSERT(!m_points->isEmpty());
543 Q_ASSERT(e[1] == QPainterPath::CurveToDataElement);
544 Q_ASSERT(e[2] == QPainterPath::CurveToDataElement);
546 quint32 startPointIndex = previousIndex;
547 matrix.map(p[4], p[5], &x, &y);
549 previousIndex = m_points->size();
553 qreal x1 = p[-2] + qreal(1.5) * (p[0] - p[-2]);
554 qreal y1 = p[-1] + qreal(1.5) * (p[1] - p[-1]);
555 qreal x2 = p[4] + qreal(1.5) * (p[2] - p[4]);
556 qreal y2 = p[5] + qreal(1.5) * (p[3] - p[5]);
558 Element *element = m_elementAllocator.newElement();
559 if (qAbs(x1 - x2) < qreal(1e-3) && qAbs(y1 - y2) < qreal(1e-3)) {
561 matrix.map(x1, y1, &x, &y);
564 setElementToQuadratic(element, startPointIndex, ctrl, previousIndex);
567 matrix.map(p[0], p[1], &x, &y);
570 matrix.map(p[2], p[3], &x, &y);
573 setElementToCubicAndSimplify(element, startPointIndex, ctrl1, ctrl2,
576 m_elements.add(element);
584 Q_ASSERT_X(0,
"QSGPathSimplifier::initialize",
"Unexpected element type.");
588 if (!m_points->isEmpty()) {
589 const QPoint &from = m_points->at(previousIndex);
590 const QPoint &to = m_points->at(moveToIndex);
592 Element *element = m_elementAllocator.newElement();
593 element->degree = Element::Line;
594 element->indices[0] = previousIndex;
595 element->indices[1] = moveToIndex;
596 element->middle.rx() = (from.x() + to.x()) >> 1;
597 element->middle.ry() = (from.y() + to.y()) >> 1;
598 m_elements.add(element);
604 for (
int i = 0; i < pathElementCount; ++i, p += 2) {
605 matrix.map(p[0], p[1], &x, &y);
607 if (to != m_points->last())
611 while (!m_points->isEmpty() && m_points->last() == m_points->first())
612 m_points->pop_back();
614 if (m_points->isEmpty())
617 quint32 prev = quint32(m_points->size() - 1);
618 for (
int i = 0; i < m_points->size(); ++i) {
619 QPoint &to = m_points->at(i);
620 QPoint &from = m_points->at(prev);
621 Element *element = m_elementAllocator.newElement();
622 element->degree = Element::Line;
623 element->indices[0] = prev;
624 element->indices[1] = quint32(i);
625 element->middle.rx() = (from.x() + to.x()) >> 1;
626 element->middle.ry() = (from.y() + to.y()) >> 1;
627 m_elements.add(element);
632 for (
int i = 0; i < m_elements.size(); ++i)
633 m_elements.at(i)->processed =
false;
636void PathSimplifier::removeIntersections()
638 Q_ASSERT(!m_elements.isEmpty());
639 QDataBuffer<Element *> elements(m_elements.size());
640 for (
int i = 0; i < m_elements.size(); ++i)
641 elements.add(m_elements.at(i));
642 m_bvh.allocate(2 * m_elements.size());
643 m_bvh.root = buildTree(elements.data(), elements.size());
646 for (
int i = 0; i < m_elements.size(); ++i)
647 elements.add(m_elements.at(i));
649 while (!elements.isEmpty()) {
650 Element *element = elements.last();
652 BVHNode *node = element->bvhNode;
653 Q_ASSERT(node->type == BVHNode::Leaf);
654 Q_ASSERT(node->element == element);
655 if (!element->processed) {
656 if (!intersectNodes(elements, node, m_bvh.root))
657 element->processed =
true;
664bool PathSimplifier::connectElements()
666 Q_ASSERT(!m_elements.isEmpty());
667 QDataBuffer<Event> events(m_elements.size() * 2);
668 for (
int i = 0; i < m_elements.size(); ++i) {
669 Element *element = m_elements.at(i);
670 element->next = element->previous =
nullptr;
671 element->winding = 0;
672 element->edgeNode =
nullptr;
673 const QPoint &u = m_points->at(element->indices[0]);
674 const QPoint &v = m_points->at(element->indices[element->degree]);
676 element->pointingUp = element->originallyPointingUp = v < u;
679 event.element = element;
681 event.type = element->pointingUp ? Event::Lower : Event::Upper;
684 event.type = element->pointingUp ? Event::Upper : Event::Lower;
688 QVarLengthArray<Element *, 8> orderedElements;
689 if (!events.isEmpty())
690 sortEvents(events.data(), events.size());
691 while (!events.isEmpty()) {
692 const Event *event = &events.last();
693 QPoint eventPoint = event->point;
696 std::pair<RBNode *, RBNode *> bounds = outerBounds(eventPoint);
699 int eventCount = events.size();
700 if (event->type == Event::Lower && eventCount > 2) {
701 std::pair<RBNode *, RBNode *> range;
702 range.first = bounds.first ? m_elementList.next(bounds.first)
703 : m_elementList.front(m_elementList.root);
704 range.second = bounds.second ? m_elementList.previous(bounds.second)
705 : m_elementList.back(m_elementList.root);
707 const Event *event2 = &events.at(eventCount - 2);
708 const Event *event3 = &events.at(eventCount - 3);
709 Q_ASSERT(event2->point == eventPoint);
710 if (range.first == range.second && event2->type == Event::Upper && event3->point != eventPoint) {
711 Element *element = event->element;
712 Element *element2 = event2->element;
713 element->edgeNode->data = event2->element;
714 element2->edgeNode = element->edgeNode;
715 element->edgeNode =
nullptr;
720 if (element2->pointingUp != element->pointingUp)
722 element2->winding = element->winding;
723 int winding = element->winding;
724 if (element->originallyPointingUp)
726 if (winding == 0 || winding == 1) {
727 if (element->pointingUp) {
728 element->previous = event2->element;
729 element2->next = event->element;
731 element->next = event2->element;
732 element2->previous = event->element;
738 orderedElements.clear();
741 if (m_elementList.root) {
742 RBNode *current = bounds.first ? m_elementList.next(bounds.first)
743 : m_elementList.front(m_elementList.root);
744 while (current != bounds.second) {
745 Element *element = current->data;
746 Q_ASSERT(element->edgeNode == current);
747 int winding = element->winding;
748 if (element->originallyPointingUp)
750 const QPoint &lower = m_points->at(element->lowerIndex());
751 if (lower == eventPoint) {
752 if (winding == 0 || winding == 1)
753 orderedElements.append(current->data);
756 Q_ASSERT(m_points->at(element->upperIndex()) != eventPoint);
757 Q_ASSERT(element->degree == Element::Line);
759 Element *eventElement = event->element;
760 int indexIndex = (event->type == Event::Upper) == eventElement->pointingUp
761 ? eventElement->degree : 0;
762 quint32 pointIndex = eventElement->indices[indexIndex];
763 Q_ASSERT(eventPoint == m_points->at(pointIndex));
765 Element *upperElement = m_elementAllocator.newElement();
766 *upperElement = *element;
767 upperElement->lowerIndex() = element->upperIndex() = pointIndex;
768 upperElement->edgeNode =
nullptr;
769 element->next = element->previous =
nullptr;
770 if (upperElement->next)
771 upperElement->next->previous = upperElement;
772 else if (upperElement->previous)
773 upperElement->previous->next = upperElement;
774 if (element->pointingUp != element->originallyPointingUp)
776 if (winding == 0 || winding == 1)
777 orderedElements.append(upperElement);
778 m_elements.add(upperElement);
780 current = m_elementList.next(current);
783 while (!events.isEmpty() && events.last().point == eventPoint) {
784 event = &events.last();
785 if (event->type == Event::Upper) {
786 Q_ASSERT(event->point == m_points->at(event->element->upperIndex()));
787 RBNode *left = findElementLeftOf(event->element, bounds);
788 RBNode *node = m_elementList.newNode();
789 node->data = event->element;
790 Q_ASSERT(event->element->edgeNode ==
nullptr);
791 event->element->edgeNode = node;
792 m_elementList.attachAfter(left, node);
794 Q_ASSERT(event->type == Event::Lower);
795 Q_ASSERT(event->point == m_points->at(event->element->lowerIndex()));
796 Element *element = event->element;
797 Q_ASSERT(element->edgeNode);
798 m_elementList.deleteNode(element->edgeNode);
799 Q_ASSERT(element->edgeNode ==
nullptr);
804 if (m_elementList.root) {
805 RBNode *current = bounds.first ? m_elementList.next(bounds.first)
806 : m_elementList.front(m_elementList.root);
807 int winding = bounds.first ? bounds.first->data->winding : 0;
810 while (current != bounds.second) {
811 Element *element = current->data;
812 Q_ASSERT(element->edgeNode == current);
813 int ccw = winding & 1;
814 Q_ASSERT(element->pointingUp == element->originallyPointingUp);
815 if (element->originallyPointingUp) {
821 element->winding = winding;
824 current = m_elementList.next(current);
828 current = bounds.second ? m_elementList.previous(bounds.second)
829 : m_elementList.back(m_elementList.root);
830 while (current != bounds.first) {
831 Element *element = current->data;
832 Q_ASSERT(element->edgeNode == current);
833 Q_ASSERT(m_points->at(element->upperIndex()) == eventPoint);
834 int winding = element->winding;
835 if (element->originallyPointingUp)
837 if (winding == 0 || winding == 1)
838 orderedElements.append(current->data);
839 current = m_elementList.previous(current);
843 if (!orderedElements.isEmpty()) {
844 if (orderedElements.size() & 1)
847 Element *firstElement = orderedElements.at(0);
848 if (m_points->at(firstElement->indices[0]) != eventPoint) {
849 orderedElements.append(firstElement);
852 for (; i < orderedElements.size(); i += 2) {
853 Q_ASSERT(i + 1 < orderedElements.size());
854 Element *next = orderedElements.at(i);
855 Element *previous = orderedElements.at(i + 1);
856 Q_ASSERT(next->previous ==
nullptr);
857 Q_ASSERT(previous->next ==
nullptr);
858 next->previous = previous;
859 previous->next = next;
864 for (
int i = 0; i < m_elements.size(); ++i) {
865 const Element *element = m_elements.at(i);
866 Q_ASSERT(element->next ==
nullptr || element->next->previous == element);
867 Q_ASSERT(element->previous ==
nullptr || element->previous->next == element);
868 Q_ASSERT((element->next ==
nullptr) == (element->previous ==
nullptr));
874void PathSimplifier::fillIndices()
876 for (
int i = 0; i < m_elements.size(); ++i)
877 m_elements.at(i)->processed =
false;
878 for (
int i = 0; i < m_elements.size(); ++i) {
879 Element *element = m_elements.at(i);
880 if (element->processed || element->next ==
nullptr)
883 m_indices->add(element->indices[0]);
884 switch (element->degree) {
885 case Element::Quadratic:
888 m_points->at(element->indices[0]),
889 m_points->at(element->indices[1]),
890 m_points->at(element->indices[2])
892 subDivQuadratic(pts[0], pts[1], pts[2]);
898 m_points->at(element->indices[0]),
899 m_points->at(element->indices[1]),
900 m_points->at(element->indices[2]),
901 m_points->at(element->indices[3])
903 subDivCubic(pts[0], pts[1], pts[2], pts[3]);
909 Q_ASSERT(element->next);
910 element->processed =
true;
911 element = element->next;
912 }
while (element != m_elements.at(i));
917PathSimplifier::BVHNode *PathSimplifier::buildTree(Element **elements,
int elementCount)
919 Q_ASSERT(elementCount > 0);
920 BVHNode *node = m_bvh.newNode();
921 if (elementCount == 1) {
922 Element *element = *elements;
923 element->bvhNode = node;
924 node->type = BVHNode::Leaf;
925 node->element = element;
926 node->minimum = node->maximum = m_points->at(element->indices[0]);
927 for (
int i = 1; i <= element->degree; ++i) {
928 const QPoint &p = m_points->at(element->indices[i]);
929 node->minimum.rx() = qMin(node->minimum.x(), p.x());
930 node->minimum.ry() = qMin(node->minimum.y(), p.y());
931 node->maximum.rx() = qMax(node->maximum.x(), p.x());
932 node->maximum.ry() = qMax(node->maximum.y(), p.y());
937 node->type = BVHNode::Split;
939 QPoint minimum, maximum;
940 minimum = maximum = elements[0]->middle;
942 for (
int i = 1; i < elementCount; ++i) {
943 const QPoint &p = elements[i]->middle;
944 minimum.rx() = qMin(minimum.x(), p.x());
945 minimum.ry() = qMin(minimum.y(), p.y());
946 maximum.rx() = qMax(maximum.x(), p.x());
947 maximum.ry() = qMax(maximum.y(), p.y());
951 if (maximum.x() - minimum.x() > maximum.y() - minimum.y()) {
953 pivot = (maximum.x() + minimum.x()) >> 1;
956 pivot = (maximum.y() + minimum.y()) >> 1;
960 int hi = elementCount - 1;
962 while (lo < hi && (&elements[lo]->middle.rx())[comp] <= pivot)
964 while (lo < hi && (&elements[hi]->middle.rx())[comp] > pivot)
967 qSwap(elements[lo], elements[hi]);
970 if (lo == elementCount) {
972 Q_ASSERT(minimum.x() == maximum.x() && minimum.y() == maximum.y());
973 lo = elementCount >> 1;
976 node->left = buildTree(elements, lo);
977 node->right = buildTree(elements + lo, elementCount - lo);
979 const BVHNode *left = node->left;
980 const BVHNode *right = node->right;
981 node->minimum.rx() = qMin(left->minimum.x(), right->minimum.x());
982 node->minimum.ry() = qMin(left->minimum.y(), right->minimum.y());
983 node->maximum.rx() = qMax(left->maximum.x(), right->maximum.x());
984 node->maximum.ry() = qMax(left->maximum.y(), right->maximum.y());
989bool PathSimplifier::intersectNodes(QDataBuffer<Element *> &elements, BVHNode *elementNode,
992 if (elementNode->minimum.x() >= treeNode->maximum.x()
993 || elementNode->minimum.y() >= treeNode->maximum.y()
994 || elementNode->maximum.x() <= treeNode->minimum.x()
995 || elementNode->maximum.y() <= treeNode->minimum.y())
1000 Q_ASSERT(elementNode->type == BVHNode::Leaf);
1001 Element *element = elementNode->element;
1002 Q_ASSERT(!element->processed);
1004 if (treeNode->type == BVHNode::Leaf) {
1005 Element *nodeElement = treeNode->element;
1006 if (!nodeElement->processed)
1009 if (treeNode->element == elementNode->element)
1012 if (equalElements(treeNode->element, elementNode->element))
1015 if (element->degree == Element::Line && nodeElement->degree == Element::Line) {
1016 const QPoint &u1 = m_points->at(element->indices[0]);
1017 const QPoint &u2 = m_points->at(element->indices[1]);
1018 const QPoint &v1 = m_points->at(nodeElement->indices[0]);
1019 const QPoint &v2 = m_points->at(nodeElement->indices[1]);
1020 IntersectionPoint intersection = intersectionPoint(u1, u2, v1, v2);
1021 if (!intersection.isValid())
1024 Q_ASSERT(intersection.x.integer >= qMin(u1.x(), u2.x()));
1025 Q_ASSERT(intersection.y.integer >= qMin(u1.y(), u2.y()));
1026 Q_ASSERT(intersection.x.integer >= qMin(v1.x(), v2.x()));
1027 Q_ASSERT(intersection.y.integer >= qMin(v1.y(), v2.y()));
1029 Q_ASSERT(intersection.x.integer <= qMax(u1.x(), u2.x()));
1030 Q_ASSERT(intersection.y.integer <= qMax(u1.y(), u2.y()));
1031 Q_ASSERT(intersection.x.integer <= qMax(v1.x(), v2.x()));
1032 Q_ASSERT(intersection.y.integer <= qMax(v1.y(), v2.y()));
1034 m_points->add(intersection.round());
1035 splitLineAt(elements, treeNode, m_points->size() - 1, !intersection.isAccurate());
1036 return splitLineAt(elements, elementNode, m_points->size() - 1,
false);
1038 QVarLengthArray<QPoint, 12> axes;
1039 appendSeparatingAxes(axes, elementNode->element);
1040 appendSeparatingAxes(axes, treeNode->element);
1041 for (
int i = 0; i < axes.size(); ++i) {
1042 std::pair<
int,
int> range1 = calculateSeparatingAxisRange(axes.at(i), elementNode->element);
1043 std::pair<
int,
int> range2 = calculateSeparatingAxisRange(axes.at(i), treeNode->element);
1044 if (range1.first >= range2.second || range1.second <= range2.first) {
1049 if (nodeElement->degree > Element::Line)
1050 splitCurve(elements, treeNode);
1051 if (element->degree > Element::Line) {
1052 splitCurve(elements, elementNode);
1055 if (intersectNodes(elements, elementNode, treeNode->left))
1057 if (intersectNodes(elements, elementNode, treeNode->right))
1064 if (intersectNodes(elements, elementNode, treeNode->left))
1066 if (intersectNodes(elements, elementNode, treeNode->right))
1072bool PathSimplifier::equalElements(
const Element *e1,
const Element *e2)
1075 if (e1->degree != e2->degree)
1079 bool equalSame =
true;
1080 for (
int i = 0; i <= e1->degree; ++i)
1081 equalSame &= m_points->at(e1->indices[i]) == m_points->at(e2->indices[i]);
1084 bool equalOpposite =
true;
1085 for (
int i = 0; i <= e1->degree; ++i)
1086 equalOpposite &= m_points->at(e1->indices[e1->degree - i]) == m_points->at(e2->indices[i]);
1088 return equalSame || equalOpposite;
1091bool PathSimplifier::splitLineAt(QDataBuffer<Element *> &elements, BVHNode *node,
1092 quint32 pointIndex,
bool processAgain)
1094 Q_ASSERT(node->type == BVHNode::Leaf);
1095 Element *element = node->element;
1096 Q_ASSERT(element->degree == Element::Line);
1097 const QPoint &u = m_points->at(element->indices[0]);
1098 const QPoint &v = m_points->at(element->indices[1]);
1099 const QPoint &p = m_points->at(pointIndex);
1100 if (u == p || v == p)
1104 element->processed =
false;
1106 Element *first = node->element;
1107 Element *second = m_elementAllocator.newElement();
1109 first->indices[1] = second->indices[0] = pointIndex;
1110 first->middle.rx() = (u.x() + p.x()) >> 1;
1111 first->middle.ry() = (u.y() + p.y()) >> 1;
1112 second->middle.rx() = (v.x() + p.x()) >> 1;
1113 second->middle.ry() = (v.y() + p.y()) >> 1;
1114 m_elements.add(second);
1116 BVHNode *left = m_bvh.newNode();
1117 BVHNode *right = m_bvh.newNode();
1118 left->type = right->type = BVHNode::Leaf;
1119 left->element = first;
1120 right->element = second;
1121 left->minimum = right->minimum = node->minimum;
1122 left->maximum = right->maximum = node->maximum;
1124 left->maximum.rx() = right->minimum.rx() = p.x();
1126 left->minimum.rx() = right->maximum.rx() = p.x();
1128 left->maximum.ry() = right->minimum.ry() = p.y();
1130 left->minimum.ry() = right->maximum.ry() = p.y();
1131 left->element->bvhNode = left;
1132 right->element->bvhNode = right;
1134 node->type = BVHNode::Split;
1136 node->right = right;
1138 if (!first->processed) {
1139 elements.add(left->element);
1140 elements.add(right->element);
1145void PathSimplifier::appendSeparatingAxes(QVarLengthArray<QPoint, 12> &axes, Element *element)
1147 switch (element->degree) {
1148 case Element::Cubic:
1150 const QPoint &u = m_points->at(element->indices[0]);
1151 const QPoint &v = m_points->at(element->indices[1]);
1152 const QPoint &w = m_points->at(element->indices[2]);
1153 const QPoint &q = m_points->at(element->indices[3]);
1155 QPoint(u.y() - v.y(), v.x() - u.x()),
1156 QPoint(v.y() - w.y(), w.x() - v.x()),
1157 QPoint(w.y() - q.y(), q.x() - w.x()),
1158 QPoint(q.y() - u.y(), u.x() - q.x()),
1159 QPoint(u.y() - w.y(), w.x() - u.x()),
1160 QPoint(v.y() - q.y(), q.x() - v.x())
1162 for (
int i = 0; i < 6; ++i) {
1163 if (ns[i].x() || ns[i].y())
1168 case Element::Quadratic:
1170 const QPoint &u = m_points->at(element->indices[0]);
1171 const QPoint &v = m_points->at(element->indices[1]);
1172 const QPoint &w = m_points->at(element->indices[2]);
1174 QPoint(u.y() - v.y(), v.x() - u.x()),
1175 QPoint(v.y() - w.y(), w.x() - v.x()),
1176 QPoint(w.y() - u.y(), u.x() - w.x())
1178 for (
int i = 0; i < 3; ++i) {
1179 if (ns[i].x() || ns[i].y())
1186 const QPoint &u = m_points->at(element->indices[0]);
1187 const QPoint &v = m_points->at(element->indices[1]);
1188 QPoint n(u.y() - v.y(), v.x() - u.x());
1194 Q_ASSERT_X(0,
"QSGPathSimplifier::appendSeparatingAxes",
"Unexpected element type.");
1199std::pair<
int,
int> PathSimplifier::calculateSeparatingAxisRange(
const QPoint &axis, Element *element)
1201 std::pair<
int,
int> range(0x7fffffff, -0x7fffffff);
1202 for (
int i = 0; i <= element->degree; ++i) {
1203 const QPoint &p = m_points->at(element->indices[i]);
1204 int dist = dot(axis, p);
1205 range.first = qMin(range.first, dist);
1206 range.second = qMax(range.second, dist);
1211void PathSimplifier::splitCurve(QDataBuffer<Element *> &elements, BVHNode *node)
1213 Q_ASSERT(node->type == BVHNode::Leaf);
1215 Element *first = node->element;
1216 Element *second = m_elementAllocator.newElement();
1218 m_elements.add(second);
1219 Q_ASSERT(first->degree > Element::Line);
1221 bool accurate =
true;
1222 const QPoint &u = m_points->at(first->indices[0]);
1223 const QPoint &v = m_points->at(first->indices[1]);
1224 const QPoint &w = m_points->at(first->indices[2]);
1226 if (first->degree == Element::Quadratic) {
1228 accurate = splitQuadratic(u, v, w, pts);
1229 int pointIndex = m_points->size();
1230 m_points->add(pts[1]);
1231 accurate &= setElementToQuadratic(first, first->indices[0], pts[0], pointIndex);
1232 accurate &= setElementToQuadratic(second, pointIndex, pts[2], second->indices[2]);
1234 Q_ASSERT(first->degree == Element::Cubic);
1235 const QPoint &q = m_points->at(first->indices[3]);
1237 accurate = splitCubic(u, v, w, q, pts);
1238 int pointIndex = m_points->size();
1239 m_points->add(pts[2]);
1240 accurate &= setElementToCubic(first, first->indices[0], pts[0], pts[1], pointIndex);
1241 accurate &= setElementToCubic(second, pointIndex, pts[3], pts[4], second->indices[3]);
1245 first->processed = second->processed =
false;
1247 BVHNode *left = m_bvh.newNode();
1248 BVHNode *right = m_bvh.newNode();
1249 left->type = right->type = BVHNode::Leaf;
1250 left->element = first;
1251 right->element = second;
1253 left->minimum.rx() = left->minimum.ry() = right->minimum.rx() = right->minimum.ry() = INT_MAX;
1254 left->maximum.rx() = left->maximum.ry() = right->maximum.rx() = right->maximum.ry() = INT_MIN;
1256 for (
int i = 0; i <= first->degree; ++i) {
1257 QPoint &p = m_points->at(first->indices[i]);
1258 left->minimum.rx() = qMin(left->minimum.x(), p.x());
1259 left->minimum.ry() = qMin(left->minimum.y(), p.y());
1260 left->maximum.rx() = qMax(left->maximum.x(), p.x());
1261 left->maximum.ry() = qMax(left->maximum.y(), p.y());
1263 for (
int i = 0; i <= second->degree; ++i) {
1264 QPoint &p = m_points->at(second->indices[i]);
1265 right->minimum.rx() = qMin(right->minimum.x(), p.x());
1266 right->minimum.ry() = qMin(right->minimum.y(), p.y());
1267 right->maximum.rx() = qMax(right->maximum.x(), p.x());
1268 right->maximum.ry() = qMax(right->maximum.y(), p.y());
1270 left->element->bvhNode = left;
1271 right->element->bvhNode = right;
1273 node->type = BVHNode::Split;
1275 node->right = right;
1277 if (!first->processed) {
1278 elements.add(left->element);
1279 elements.add(right->element);
1283bool PathSimplifier::setElementToQuadratic(Element *element, quint32 pointIndex1,
1284 const QPoint &ctrl, quint32 pointIndex2)
1286 const QPoint &p1 = m_points->at(pointIndex1);
1287 const QPoint &p2 = m_points->at(pointIndex2);
1288 if (flattenQuadratic(p1, ctrl, p2)) {
1290 element->degree = Element::Line;
1291 element->indices[0] = pointIndex1;
1292 element->indices[1] = pointIndex2;
1293 element->middle.rx() = (p1.x() + p2.x()) >> 1;
1294 element->middle.ry() = (p1.y() + p2.y()) >> 1;
1298 element->degree = Element::Quadratic;
1299 element->indices[0] = pointIndex1;
1300 element->indices[1] = m_points->size();
1301 element->indices[2] = pointIndex2;
1302 element->middle.rx() = (p1.x() + ctrl.x() + p2.x()) / 3;
1303 element->middle.ry() = (p1.y() + ctrl.y() + p2.y()) / 3;
1304 m_points->add(ctrl);
1309bool PathSimplifier::setElementToCubic(Element *element, quint32 pointIndex1,
const QPoint &v,
1310 const QPoint &w, quint32 pointIndex2)
1312 const QPoint &u = m_points->at(pointIndex1);
1313 const QPoint &q = m_points->at(pointIndex2);
1314 if (flattenCubic(u, v, w, q)) {
1316 element->degree = Element::Line;
1317 element->indices[0] = pointIndex1;
1318 element->indices[1] = pointIndex2;
1319 element->middle.rx() = (u.x() + q.x()) >> 1;
1320 element->middle.ry() = (u.y() + q.y()) >> 1;
1324 element->degree = Element::Cubic;
1325 element->indices[0] = pointIndex1;
1326 element->indices[1] = m_points->size();
1327 element->indices[2] = m_points->size() + 1;
1328 element->indices[3] = pointIndex2;
1329 element->middle.rx() = (u.x() + v.x() + w.x() + q.x()) >> 2;
1330 element->middle.ry() = (u.y() + v.y() + w.y() + q.y()) >> 2;
1337void PathSimplifier::setElementToCubicAndSimplify(Element *element, quint32 pointIndex1,
1338 const QPoint &v,
const QPoint &w,
1339 quint32 pointIndex2)
1341 const QPoint &u = m_points->at(pointIndex1);
1342 const QPoint &q = m_points->at(pointIndex2);
1343 if (flattenCubic(u, v, w, q)) {
1345 element->degree = Element::Line;
1346 element->indices[0] = pointIndex1;
1347 element->indices[1] = pointIndex2;
1348 element->middle.rx() = (u.x() + q.x()) >> 1;
1349 element->middle.ry() = (u.y() + q.y()) >> 1;
1353 bool intersecting = (u == q) || intersectionPoint(u, v, w, q).isValid();
1354 if (!intersecting) {
1356 element->degree = Element::Cubic;
1357 element->indices[0] = pointIndex1;
1358 element->indices[1] = m_points->size();
1359 element->indices[2] = m_points->size() + 1;
1360 element->indices[3] = pointIndex2;
1361 element->middle.rx() = (u.x() + v.x() + w.x() + q.x()) >> 2;
1362 element->middle.ry() = (u.y() + v.y() + w.y() + q.y()) >> 2;
1369 splitCubic(u, v, w, q, pts);
1370 int pointIndex = m_points->size();
1371 m_points->add(pts[2]);
1372 Element *element2 = m_elementAllocator.newElement();
1373 m_elements.add(element2);
1374 setElementToCubicAndSimplify(element, pointIndex1, pts[0], pts[1], pointIndex);
1375 setElementToCubicAndSimplify(element2, pointIndex, pts[3], pts[4], pointIndex2);
1378PathSimplifier::RBNode *PathSimplifier::findElementLeftOf(
const Element *element,
1379 const std::pair<RBNode *, RBNode *> &bounds)
1381 if (!m_elementList.root)
1383 RBNode *current = bounds.first;
1384 Q_ASSERT(!current || !elementIsLeftOf(element, current->data));
1386 current = m_elementList.front(m_elementList.root);
1388 RBNode *result =
nullptr;
1389 while (current != bounds.second && !elementIsLeftOf(element, current->data)) {
1391 current = m_elementList.next(current);
1396bool PathSimplifier::elementIsLeftOf(
const Element *left,
const Element *right)
1398 const QPoint &leftU = m_points->at(left->upperIndex());
1399 const QPoint &leftL = m_points->at(left->lowerIndex());
1400 const QPoint &rightU = m_points->at(right->upperIndex());
1401 const QPoint &rightL = m_points->at(right->lowerIndex());
1402 Q_ASSERT(leftL >= rightU && rightL >= leftU);
1403 if (leftU.x() < qMin(rightL.x(), rightU.x()))
1405 if (leftU.x() > qMax(rightL.x(), rightU.x()))
1407 int d = pointSideOfLine(leftU, rightL, rightU);
1410 d = pointSideOfLine(leftL, rightL, rightU);
1412 if (right->degree > Element::Line) {
1413 d = pointSideOfLine(leftL, rightL, m_points->at(right->indices[1]));
1415 d = pointSideOfLine(leftL, rightL, m_points->at(right->indices[2]));
1416 }
else if (left->degree > Element::Line) {
1417 d = pointSideOfLine(m_points->at(left->indices[1]), rightL, rightU);
1419 d = pointSideOfLine(m_points->at(left->indices[2]), rightL, rightU);
1426std::pair<PathSimplifier::RBNode *, PathSimplifier::RBNode *> PathSimplifier::outerBounds(
const QPoint &point)
1428 RBNode *current = m_elementList.root;
1429 std::pair<RBNode *, RBNode *> result(
nullptr,
nullptr);
1432 const Element *element = current->data;
1433 Q_ASSERT(element->edgeNode == current);
1434 const QPoint &v1 = m_points->at(element->lowerIndex());
1435 const QPoint &v2 = m_points->at(element->upperIndex());
1436 Q_ASSERT(point >= v2 && point <= v1);
1437 if (point == v1 || point == v2)
1439 int d = pointSideOfLine(point, v1, v2);
1441 if (element->degree == Element::Line)
1443 d = pointSideOfLine(point, v1, m_points->at(element->indices[1]));
1445 d = pointSideOfLine(point, v1, m_points->at(element->indices[2]));
1449 result.second = current;
1450 current = current->left;
1452 result.first = current;
1453 current = current->right;
1460 RBNode *mid = current;
1462 current = mid->left;
1464 const Element *element = current->data;
1465 Q_ASSERT(element->edgeNode == current);
1466 const QPoint &v1 = m_points->at(element->lowerIndex());
1467 const QPoint &v2 = m_points->at(element->upperIndex());
1468 Q_ASSERT(point >= v2 && point <= v1);
1469 bool equal = (point == v1 || point == v2);
1471 int d = pointSideOfLine(point, v1, v2);
1473 equal = (d == 0 && element->degree == Element::Line);
1476 current = current->left;
1478 result.first = current;
1479 current = current->right;
1483 current = mid->right;
1485 const Element *element = current->data;
1486 Q_ASSERT(element->edgeNode == current);
1487 const QPoint &v1 = m_points->at(element->lowerIndex());
1488 const QPoint &v2 = m_points->at(element->upperIndex());
1489 Q_ASSERT(point >= v2 && point <= v1);
1490 bool equal = (point == v1 || point == v2);
1492 int d = pointSideOfLine(point, v1, v2);
1494 equal = (d == 0 && element->degree == Element::Line);
1497 current = current->right;
1499 result.second = current;
1500 current = current->left;
1507inline bool PathSimplifier::flattenQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w)
1509 QPoint deltas[2] = { v - u, w - v };
1510 int d = qAbs(cross(deltas[0], deltas[1]));
1511 int l = qAbs(deltas[0].x()) + qAbs(deltas[0].y()) + qAbs(deltas[1].x()) + qAbs(deltas[1].y());
1515inline bool PathSimplifier::flattenCubic(
const QPoint &u,
const QPoint &v,
1516 const QPoint &w,
const QPoint &q)
1518 QPoint deltas[] = { v - u, w - v, q - w, q - u };
1519 int d = qAbs(cross(deltas[0], deltas[1])) + qAbs(cross(deltas[1], deltas[2]))
1520 + qAbs(cross(deltas[0], deltas[3])) + qAbs(cross(deltas[3], deltas[2]));
1521 int l = qAbs(deltas[0].x()) + qAbs(deltas[0].y()) + qAbs(deltas[1].x()) + qAbs(deltas[1].y())
1522 + qAbs(deltas[2].x()) + qAbs(deltas[2].y());
1526inline bool PathSimplifier::splitQuadratic(
const QPoint &u,
const QPoint &v,
1527 const QPoint &w, QPoint *result)
1531 result[1] = result[0] + result[2];
1532 bool accurate = ((result[0].x() | result[0].y() | result[2].x() | result[2].y()) & 1) == 0
1533 && ((result[1].x() | result[1].y()) & 3) == 0;
1534 result[0].rx() >>= 1;
1535 result[0].ry() >>= 1;
1536 result[1].rx() >>= 2;
1537 result[1].ry() >>= 2;
1538 result[2].rx() >>= 1;
1539 result[2].ry() >>= 1;
1543inline bool PathSimplifier::splitCubic(
const QPoint &u,
const QPoint &v,
1544 const QPoint &w,
const QPoint &q, QPoint *result)
1549 result[1] = result[0] + result[2];
1550 result[3] = result[2] + result[4];
1551 result[2] = result[1] + result[3];
1552 bool accurate = ((result[0].x() | result[0].y() | result[4].x() | result[4].y()) & 1) == 0
1553 && ((result[1].x() | result[1].y() | result[3].x() | result[3].y()) & 3) == 0
1554 && ((result[2].x() | result[2].y()) & 7) == 0;
1555 result[0].rx() >>= 1;
1556 result[0].ry() >>= 1;
1557 result[1].rx() >>= 2;
1558 result[1].ry() >>= 2;
1559 result[2].rx() >>= 3;
1560 result[2].ry() >>= 3;
1561 result[3].rx() >>= 2;
1562 result[3].ry() >>= 2;
1563 result[4].rx() >>= 1;
1564 result[4].ry() >>= 1;
1568inline void PathSimplifier::subDivQuadratic(
const QPoint &u,
const QPoint &v,
const QPoint &w)
1570 if (flattenQuadratic(u, v, w))
1573 splitQuadratic(u, v, w, pts);
1574 subDivQuadratic(u, pts[0], pts[1]);
1575 m_indices->add(m_points->size());
1576 m_points->add(pts[1]);
1577 subDivQuadratic(pts[1], pts[2], w);
1580inline void PathSimplifier::subDivCubic(
const QPoint &u,
const QPoint &v,
1581 const QPoint &w,
const QPoint &q)
1583 if (flattenCubic(u, v, w, q))
1586 splitCubic(u, v, w, q, pts);
1587 subDivCubic(u, pts[0], pts[1], pts[2]);
1588 m_indices->add(m_points->size());
1589 m_points->add(pts[2]);
1590 subDivCubic(pts[2], pts[3], pts[4], q);
1593void PathSimplifier::sortEvents(Event *events,
int count)
1596 Q_ASSERT(count > 0);
1597 QDataBuffer<Event> buffer(count);
1598 buffer.resize(count);
1599 QScopedArrayPointer<
int> bins(
new int[count]);
1601 memset(counts, 0,
sizeof(counts));
1603 int minimum, maximum;
1604 minimum = maximum = events[0].point.y();
1605 for (
int i = 1; i < count; ++i) {
1606 minimum = qMin(minimum, events[i].point.y());
1607 maximum = qMax(maximum, events[i].point.y());
1610 for (
int i = 0; i < count; ++i) {
1611 bins[i] = ((maximum - events[i].point.y()) << 8) / (maximum - minimum + 1);
1612 Q_ASSERT(bins[i] >= 0 && bins[i] < 0x100);
1616 for (
int i = 1; i < 0x100; ++i)
1617 counts[i] += counts[i - 1];
1618 counts[0x100] = counts[0xff];
1619 Q_ASSERT(counts[0x100] == count);
1621 for (
int i = 0; i < count; ++i)
1622 buffer.at(--counts[bins[i]]) = events[i];
1625 for (
int i = 0; i < 0x100; ++i) {
1626 for (; j < counts[i + 1]; ++j) {
1628 while (k > 0 && (buffer.at(j) < events[k - 1])) {
1629 events[k] = events[k - 1];
1632 events[k] = buffer.at(j);
1638 QDataBuffer<quint32> &indices,
const QTransform &matrix)
1640 PathSimplifier(path, vertices, indices, matrix);
1644 QDataBuffer<quint32> &indices,
const QTransform &matrix)
1646 qSimplifyPath(qtVectorPathForPath(path), vertices, indices, matrix);
1652#undef Q_FIXED_POINT_SCALE
Combined button and popup list for selecting options.
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)