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)
29 return a.y() <
b.y() || (
a.y() ==
b.y() &&
a.x() <
b.x());
51 return u.
x() *
v.y() - u.
y() *
v.x();
56 return u.
x() *
v.x() + u.
y() *
v.y();
72inline unsigned int gcd(
unsigned int x,
unsigned int y)
84Fraction fraction(
unsigned int n,
unsigned int d) {
90 unsigned int g =
gcd(
n,
d);
111struct IntersectionPoint
113 bool isValid()
const {
return x.fraction.isValid() &&
y.fraction.isValid(); }
115 bool isAccurate()
const {
return x.fraction.numerator == 0 &&
y.fraction.numerator == 0; }
121QPoint IntersectionPoint::round()
const
124 if (2 *
x.fraction.numerator >=
x.fraction.denominator)
126 if (2 *
y.fraction.numerator >=
y.fraction.denominator)
143 IntersectionPoint
result = {{0, {0, 0}}, {0, {0, 0}}};
147 int d1 = cross(u,
v1 -
u1);
148 int d2 = cross(u,
v2 -
u1);
150 int d3 = cross(
v,
u1 -
v1);
176 if (
d1 >= 0 ||
d2 <= 0 || d3 <= 0 || d4 >= 0)
186 result.x.fraction = fraction((
unsigned int)(
qint64(-
v.x()) *
d1 % det), (
unsigned int)det);
189 result.x.fraction = fraction((
unsigned int)(
qint64(-
v.x()) *
d2 % det), (
unsigned int)det);
194 result.y.fraction = fraction((
unsigned int)(
qint64(-
v.y()) *
d1 % det), (
unsigned int)det);
197 result.y.fraction = fraction((
unsigned int)(
qint64(-
v.y()) *
d2 % det), (
unsigned int)det);
218 class BoundingVolumeHierarchy
238 BoundingVolumeHierarchy();
239 ~BoundingVolumeHierarchy();
240 void allocate(
int nodeCount);
246 void freeNode(
Node *
n);
262 quint32 &upperIndex() {
return indices[pointingUp ? degree : 0]; }
263 quint32 &lowerIndex() {
return indices[pointingUp ? 0 : degree]; }
264 quint32 upperIndex()
const {
return indices[pointingUp ? degree : 0]; }
265 quint32 lowerIndex()
const {
return indices[pointingUp ? 0 : degree]; }
270 Element *
next, *previous;
274 BoundingVolumeHierarchy::Node *bvhNode;
279 uint originallyPointingUp : 1;
282 class ElementAllocator
287 void allocate(
int count);
288 Element *newElement();
311 typedef BoundingVolumeHierarchy::Node BVHNode;
314 void removeIntersections();
315 void connectElements();
317 BVHNode *buildTree(Element **
elements,
int elementCount);
319 bool equalElements(
const Element *e1,
const Element *e2);
324 bool setElementToQuadratic(Element *element,
quint32 pointIndex1,
const QPoint &ctrl,
quint32 pointIndex2);
326 void setElementToCubicAndSimplify(Element *element,
quint32 pointIndex1,
const QPoint &ctrl1,
const QPoint &ctrl2,
quint32 pointIndex2);
328 bool elementIsLeftOf(
const Element *
left,
const Element *
right);
336 static void sortEvents(
Event *events,
int count);
338 ElementAllocator m_elementAllocator;
341 BoundingVolumeHierarchy m_bvh;
351inline PathSimplifier::BoundingVolumeHierarchy::BoundingVolumeHierarchy()
359inline PathSimplifier::BoundingVolumeHierarchy::~BoundingVolumeHierarchy()
364inline void PathSimplifier::BoundingVolumeHierarchy::allocate(
int nodeCount)
371inline void PathSimplifier::BoundingVolumeHierarchy::free()
380inline PathSimplifier::BVHNode *PathSimplifier::BoundingVolumeHierarchy::newNode()
383 return &nodeBlock[firstFree++];
387inline void PathSimplifier::BoundingVolumeHierarchy::freeNode(
Node *
n)
391 Q_ASSERT(
n->type == Node::Split ||
n->type == Node::Leaf);
392 if (
n->type == Node::Split) {
396 if (!(
n >= nodeBlock &&
n < nodeBlock +
blockSize))
400inline PathSimplifier::ElementAllocator::ElementAllocator()
405inline PathSimplifier::ElementAllocator::~ElementAllocator()
408 ElementBlock *block = blocks;
409 blocks = blocks->next;
414inline void PathSimplifier::ElementAllocator::allocate(
int count)
418 blocks = (ElementBlock *)malloc(
sizeof(ElementBlock) + (
count - 1) *
sizeof(Element));
419 blocks->blockSize =
count;
420 blocks->next =
nullptr;
421 blocks->firstFree = 0;
424inline PathSimplifier::Element *PathSimplifier::ElementAllocator::newElement()
427 if (blocks->firstFree < blocks->blockSize)
428 return &blocks->elements[blocks->firstFree++];
429 ElementBlock *oldBlock = blocks;
430 blocks = (ElementBlock *)malloc(
sizeof(ElementBlock) + (oldBlock->blockSize - 1) *
sizeof(Element));
431 blocks->blockSize = oldBlock->blockSize;
432 blocks->next = oldBlock;
433 blocks->firstFree = 0;
434 return &blocks->elements[blocks->firstFree++];
438inline bool PathSimplifier::Event::operator < (
const Event &
other)
const
440 if (point ==
other.point)
442 return other.point < point;
445inline void PathSimplifier::Element::flip()
447 for (
int i = 0;
i < (degree + 1) >> 1; ++
i) {
452 pointingUp = !pointingUp;
459 , m_points(&vertices)
465 if (!m_elements.isEmpty()) {
466 removeIntersections();
474 m_hints =
path.hints();
475 int pathElementCount =
path.elementCount();
476 if (pathElementCount == 0)
478 m_elements.reserve(2 * pathElementCount);
479 m_elementAllocator.allocate(2 * pathElementCount);
480 m_points->reserve(2 * pathElementCount);
487 for (
int i = 0;
i < pathElementCount; ++
i, ++
e,
p += 2) {
491 if (!m_points->isEmpty()) {
492 const QPoint &from = m_points->at(previousIndex);
493 const QPoint &to = m_points->at(moveToIndex);
495 Element *element = m_elementAllocator.newElement();
496 element->degree = Element::Line;
497 element->indices[0] = previousIndex;
498 element->indices[1] = moveToIndex;
499 element->middle.rx() = (from.
x() + to.
x()) >> 1;
500 element->middle.ry() = (from.
y() + to.
y()) >> 1;
501 m_elements.add(element);
504 previousIndex = moveToIndex = m_points->size();
515 const QPoint &from = m_points->last();
517 Element *element = m_elementAllocator.newElement();
518 element->degree = Element::Line;
519 element->indices[0] = previousIndex;
520 element->indices[1] =
quint32(m_points->size());
521 element->middle.rx() = (from.
x() + to.
x()) >> 1;
522 element->middle.ry() = (from.
y() + to.
y()) >> 1;
523 m_elements.add(element);
524 previousIndex = m_points->size();
535 quint32 startPointIndex = previousIndex;
538 previousIndex = m_points->size();
547 Element *element = m_elementAllocator.newElement();
553 setElementToQuadratic(element, startPointIndex, ctrl, previousIndex);
562 setElementToCubicAndSimplify(element, startPointIndex, ctrl1, ctrl2,
565 m_elements.add(element);
573 Q_ASSERT_X(0,
"QSGPathSimplifier::initialize",
"Unexpected element type.");
577 if (!m_points->isEmpty()) {
578 const QPoint &from = m_points->at(previousIndex);
579 const QPoint &to = m_points->at(moveToIndex);
581 Element *element = m_elementAllocator.newElement();
582 element->degree = Element::Line;
583 element->indices[0] = previousIndex;
584 element->indices[1] = moveToIndex;
585 element->middle.rx() = (from.
x() + to.
x()) >> 1;
586 element->middle.ry() = (from.
y() + to.
y()) >> 1;
587 m_elements.add(element);
593 for (
int i = 0;
i < pathElementCount; ++
i,
p += 2) {
596 if (to != m_points->last())
600 while (!m_points->isEmpty() && m_points->last() == m_points->first())
601 m_points->pop_back();
603 if (m_points->isEmpty())
607 for (
int i = 0;
i < m_points->size(); ++
i) {
609 QPoint &from = m_points->at(prev);
610 Element *element = m_elementAllocator.newElement();
611 element->degree = Element::Line;
612 element->indices[0] = prev;
614 element->middle.rx() = (from.
x() + to.
x()) >> 1;
615 element->middle.ry() = (from.
y() + to.
y()) >> 1;
616 m_elements.add(element);
621 for (
int i = 0;
i < m_elements.size(); ++
i)
622 m_elements.at(
i)->processed =
false;
625void PathSimplifier::removeIntersections()
629 for (
int i = 0;
i < m_elements.size(); ++
i)
631 m_bvh.allocate(2 * m_elements.size());
635 for (
int i = 0;
i < m_elements.size(); ++
i)
641 BVHNode *node = element->bvhNode;
642 Q_ASSERT(node->type == BVHNode::Leaf);
644 if (!element->processed) {
645 if (!intersectNodes(
elements, node, m_bvh.root))
646 element->processed =
true;
653void PathSimplifier::connectElements()
657 for (
int i = 0;
i < m_elements.size(); ++
i) {
658 Element *element = m_elements.at(
i);
659 element->next = element->previous =
nullptr;
660 element->winding = 0;
661 element->edgeNode =
nullptr;
662 const QPoint &u = m_points->at(element->indices[0]);
663 const QPoint &
v = m_points->at(element->indices[element->degree]);
665 element->pointingUp = element->originallyPointingUp =
v < u;
668 event.element = element;
670 event.type = element->pointingUp ? Event::Lower : Event::Upper;
673 event.type = element->pointingUp ? Event::Upper : Event::Lower;
678 if (!events.isEmpty())
679 sortEvents(events.data(), events.size());
680 while (!events.isEmpty()) {
681 const Event *
event = &events.last();
682 QPoint eventPoint =
event->point;
688 int eventCount = events.size();
689 if (
event->type == Event::Lower && eventCount > 2) {
691 range.first = bounds.first ? m_elementList.next(bounds.first)
692 : m_elementList.front(m_elementList.root);
693 range.second = bounds.second ? m_elementList.previous(bounds.second)
694 : m_elementList.back(m_elementList.root);
696 const Event *event2 = &events.at(eventCount - 2);
697 const Event *event3 = &events.at(eventCount - 3);
698 Q_ASSERT(event2->point == eventPoint);
699 if (
range.first ==
range.second && event2->
type == Event::Upper && event3->point != eventPoint) {
700 Element *element =
event->element;
701 Element *element2 = event2->element;
702 element->edgeNode->data = event2->element;
703 element2->edgeNode = element->edgeNode;
704 element->edgeNode =
nullptr;
709 if (element2->pointingUp != element->pointingUp)
711 element2->winding = element->winding;
712 int winding = element->winding;
713 if (element->originallyPointingUp)
715 if (winding == 0 || winding == 1) {
716 if (element->pointingUp) {
717 element->previous = event2->element;
718 element2->next =
event->element;
720 element->next = event2->element;
721 element2->previous =
event->element;
727 orderedElements.
clear();
730 if (m_elementList.root) {
731 RBNode *current = bounds.first ? m_elementList.next(bounds.first)
732 : m_elementList.front(m_elementList.root);
733 while (current != bounds.second) {
734 Element *element = current->data;
735 Q_ASSERT(element->edgeNode == current);
736 int winding = element->winding;
737 if (element->originallyPointingUp)
739 const QPoint &lower = m_points->at(element->lowerIndex());
740 if (lower == eventPoint) {
741 if (winding == 0 || winding == 1)
742 orderedElements.
append(current->data);
745 Q_ASSERT(m_points->at(element->upperIndex()) != eventPoint);
746 Q_ASSERT(element->degree == Element::Line);
748 Element *eventElement =
event->element;
749 int indexIndex = (
event->type == Event::Upper) == eventElement->pointingUp
750 ? eventElement->degree : 0;
751 quint32 pointIndex = eventElement->indices[indexIndex];
752 Q_ASSERT(eventPoint == m_points->at(pointIndex));
754 Element *upperElement = m_elementAllocator.newElement();
755 *upperElement = *element;
756 upperElement->lowerIndex() = element->upperIndex() = pointIndex;
757 upperElement->edgeNode =
nullptr;
758 element->next = element->previous =
nullptr;
759 if (upperElement->next)
760 upperElement->next->previous = upperElement;
761 else if (upperElement->previous)
762 upperElement->previous->next = upperElement;
763 if (element->pointingUp != element->originallyPointingUp)
765 if (winding == 0 || winding == 1)
766 orderedElements.
append(upperElement);
767 m_elements.add(upperElement);
769 current = m_elementList.next(current);
772 while (!events.isEmpty() && events.last().point == eventPoint) {
773 event = &events.last();
774 if (
event->type == Event::Upper) {
776 RBNode *
left = findElementLeftOf(
event->element, bounds);
777 RBNode *node = m_elementList.newNode();
778 node->data =
event->element;
780 event->element->edgeNode = node;
781 m_elementList.attachAfter(
left, node);
785 Element *element =
event->element;
787 m_elementList.deleteNode(element->edgeNode);
788 Q_ASSERT(element->edgeNode ==
nullptr);
793 if (m_elementList.root) {
794 RBNode *current = bounds.first ? m_elementList.next(bounds.first)
795 : m_elementList.front(m_elementList.root);
796 int winding = bounds.first ? bounds.first->data->winding : 0;
799 while (current != bounds.second) {
800 Element *element = current->data;
801 Q_ASSERT(element->edgeNode == current);
802 int ccw = winding & 1;
803 Q_ASSERT(element->pointingUp == element->originallyPointingUp);
804 if (element->originallyPointingUp) {
810 element->winding = winding;
813 current = m_elementList.next(current);
817 current = bounds.second ? m_elementList.previous(bounds.second)
818 : m_elementList.back(m_elementList.root);
819 while (current != bounds.first) {
820 Element *element = current->data;
821 Q_ASSERT(element->edgeNode == current);
822 Q_ASSERT(m_points->at(element->upperIndex()) == eventPoint);
823 int winding = element->winding;
824 if (element->originallyPointingUp)
826 if (winding == 0 || winding == 1)
827 orderedElements.
append(current->data);
828 current = m_elementList.previous(current);
832 if (!orderedElements.
isEmpty()) {
835 Element *firstElement = orderedElements.
at(0);
836 if (m_points->at(firstElement->indices[0]) != eventPoint) {
837 orderedElements.
append(firstElement);
840 for (;
i < orderedElements.
size();
i += 2) {
842 Element *
next = orderedElements.
at(
i);
843 Element *previous = orderedElements.
at(
i + 1);
845 Q_ASSERT(previous->next ==
nullptr);
846 next->previous = previous;
847 previous->next =
next;
852 for (
int i = 0;
i < m_elements.size(); ++
i) {
853 const Element *element = m_elements.at(
i);
854 Q_ASSERT(element->next ==
nullptr || element->next->previous == element);
855 Q_ASSERT(element->previous ==
nullptr || element->previous->next == element);
856 Q_ASSERT((element->next ==
nullptr) == (element->previous ==
nullptr));
861void PathSimplifier::fillIndices()
863 for (
int i = 0;
i < m_elements.size(); ++
i)
864 m_elements.at(
i)->processed =
false;
865 for (
int i = 0;
i < m_elements.size(); ++
i) {
866 Element *element = m_elements.at(
i);
867 if (element->processed || element->next ==
nullptr)
870 m_indices->add(element->indices[0]);
871 switch (element->degree) {
872 case Element::Quadratic:
875 m_points->at(element->indices[0]),
876 m_points->at(element->indices[1]),
877 m_points->at(element->indices[2])
879 subDivQuadratic(pts[0], pts[1], pts[2]);
885 m_points->at(element->indices[0]),
886 m_points->at(element->indices[1]),
887 m_points->at(element->indices[2]),
888 m_points->at(element->indices[3])
890 subDivCubic(pts[0], pts[1], pts[2], pts[3]);
897 element->processed =
true;
898 element = element->next;
899 }
while (element != m_elements.at(
i));
904PathSimplifier::BVHNode *PathSimplifier::buildTree(Element **
elements,
int elementCount)
907 BVHNode *node = m_bvh.newNode();
908 if (elementCount == 1) {
910 element->bvhNode = node;
911 node->type = BVHNode::Leaf;
912 node->element = element;
913 node->minimum = node->maximum = m_points->at(element->indices[0]);
914 for (
int i = 1;
i <= element->degree; ++
i) {
915 const QPoint &
p = m_points->at(element->indices[
i]);
916 node->minimum.
rx() =
qMin(node->minimum.x(),
p.x());
917 node->minimum.ry() =
qMin(node->minimum.y(),
p.y());
918 node->maximum.rx() =
qMax(node->maximum.x(),
p.x());
919 node->maximum.ry() =
qMax(node->maximum.y(),
p.y());
924 node->type = BVHNode::Split;
929 for (
int i = 1;
i < elementCount; ++
i) {
947 int hi = elementCount - 1;
949 while (lo < hi && (&
elements[lo]->middle.rx())[comp] <= pivot)
951 while (lo < hi && (&
elements[hi]->middle.rx())[comp] > pivot)
957 if (lo == elementCount) {
960 lo = elementCount >> 1;
963 node->left = buildTree(
elements, lo);
964 node->right = buildTree(
elements + lo, elementCount - lo);
966 const BVHNode *
left = node->left;
967 const BVHNode *
right = node->right;
968 node->minimum.rx() =
qMin(
left->minimum.x(),
right->minimum.x());
969 node->minimum.ry() =
qMin(
left->minimum.y(),
right->minimum.y());
970 node->maximum.rx() =
qMax(
left->maximum.x(),
right->maximum.x());
971 node->maximum.ry() =
qMax(
left->maximum.y(),
right->maximum.y());
979 if (elementNode->minimum.x() >= treeNode->maximum.x()
980 || elementNode->minimum.y() >= treeNode->maximum.y()
981 || elementNode->maximum.x() <= treeNode->minimum.x()
982 || elementNode->maximum.y() <= treeNode->minimum.y())
987 Q_ASSERT(elementNode->type == BVHNode::Leaf);
988 Element *element = elementNode->element;
991 if (treeNode->type == BVHNode::Leaf) {
992 Element *nodeElement = treeNode->element;
993 if (!nodeElement->processed)
996 if (treeNode->element == elementNode->element)
999 if (equalElements(treeNode->element, elementNode->element))
1002 if (element->degree == Element::Line && nodeElement->degree == Element::Line) {
1003 const QPoint &
u1 = m_points->at(element->indices[0]);
1004 const QPoint &
u2 = m_points->at(element->indices[1]);
1005 const QPoint &
v1 = m_points->at(nodeElement->indices[0]);
1006 const QPoint &
v2 = m_points->at(nodeElement->indices[1]);
1007 IntersectionPoint intersection = intersectionPoint(
u1,
u2,
v1,
v2);
1008 if (!intersection.isValid())
1021 m_points->add(intersection.round());
1022 splitLineAt(
elements, treeNode, m_points->size() - 1, !intersection.isAccurate());
1023 return splitLineAt(
elements, elementNode, m_points->size() - 1,
false);
1026 appendSeparatingAxes(axes, elementNode->element);
1027 appendSeparatingAxes(axes, treeNode->element);
1028 for (
int i = 0;
i < axes.
size(); ++
i) {
1029 QPair<int, int> range1 = calculateSeparatingAxisRange(axes.
at(
i), elementNode->element);
1030 QPair<int, int> range2 = calculateSeparatingAxisRange(axes.
at(
i), treeNode->element);
1031 if (range1.first >= range2.second || range1.second <= range2.first) {
1036 if (nodeElement->degree > Element::Line)
1038 if (element->degree > Element::Line) {
1042 if (intersectNodes(
elements, elementNode, treeNode->left))
1044 if (intersectNodes(
elements, elementNode, treeNode->right))
1051 if (intersectNodes(
elements, elementNode, treeNode->left))
1053 if (intersectNodes(
elements, elementNode, treeNode->right))
1059bool PathSimplifier::equalElements(
const Element *e1,
const Element *e2)
1062 if (e1->degree != e2->degree)
1066 bool equalSame =
true;
1067 for (
int i = 0;
i <= e1->degree; ++
i)
1068 equalSame &= m_points->at(e1->indices[
i]) == m_points->at(e2->indices[
i]);
1071 bool equalOpposite =
true;
1072 for (
int i = 0;
i <= e1->degree; ++
i)
1073 equalOpposite &= m_points->at(e1->indices[e1->degree -
i]) == m_points->at(e2->indices[
i]);
1075 return equalSame || equalOpposite;
1079 quint32 pointIndex,
bool processAgain)
1081 Q_ASSERT(node->type == BVHNode::Leaf);
1082 Element *element = node->element;
1083 Q_ASSERT(element->degree == Element::Line);
1084 const QPoint &u = m_points->at(element->indices[0]);
1085 const QPoint &
v = m_points->at(element->indices[1]);
1086 const QPoint &
p = m_points->at(pointIndex);
1087 if (u ==
p ||
v ==
p)
1091 element->processed =
false;
1093 Element *
first = node->element;
1094 Element *second = m_elementAllocator.newElement();
1096 first->indices[1] = second->indices[0] = pointIndex;
1097 first->middle.rx() = (u.
x() +
p.x()) >> 1;
1098 first->middle.ry() = (u.
y() +
p.y()) >> 1;
1099 second->middle.rx() = (
v.x() +
p.x()) >> 1;
1100 second->middle.ry() = (
v.y() +
p.y()) >> 1;
1101 m_elements.add(second);
1103 BVHNode *
left = m_bvh.newNode();
1104 BVHNode *
right = m_bvh.newNode();
1105 left->type =
right->type = BVHNode::Leaf;
1107 right->element = second;
1108 left->minimum =
right->minimum = node->minimum;
1109 left->maximum =
right->maximum = node->maximum;
1111 left->maximum.rx() =
right->minimum.rx() =
p.x();
1113 left->minimum.rx() =
right->maximum.rx() =
p.x();
1115 left->maximum.ry() =
right->minimum.ry() =
p.y();
1117 left->minimum.ry() =
right->maximum.ry() =
p.y();
1121 node->type = BVHNode::Split;
1123 node->right =
right;
1125 if (!
first->processed) {
1134 switch (element->degree) {
1135 case Element::Cubic:
1137 const QPoint &u = m_points->at(element->indices[0]);
1138 const QPoint &
v = m_points->at(element->indices[1]);
1139 const QPoint &
w = m_points->at(element->indices[2]);
1140 const QPoint &
q = m_points->at(element->indices[3]);
1149 for (
int i = 0;
i < 6; ++
i) {
1155 case Element::Quadratic:
1157 const QPoint &u = m_points->at(element->indices[0]);
1158 const QPoint &
v = m_points->at(element->indices[1]);
1159 const QPoint &
w = m_points->at(element->indices[2]);
1165 for (
int i = 0;
i < 3; ++
i) {
1173 const QPoint &u = m_points->at(element->indices[0]);
1174 const QPoint &
v = m_points->at(element->indices[1]);
1181 Q_ASSERT_X(0,
"QSGPathSimplifier::appendSeparatingAxes",
"Unexpected element type.");
1189 for (
int i = 0;
i <= element->degree; ++
i) {
1190 const QPoint &
p = m_points->at(element->indices[
i]);
1200 Q_ASSERT(node->type == BVHNode::Leaf);
1202 Element *
first = node->element;
1203 Element *second = m_elementAllocator.newElement();
1205 m_elements.add(second);
1208 bool accurate =
true;
1209 const QPoint &u = m_points->at(
first->indices[0]);
1213 if (
first->degree == Element::Quadratic) {
1215 accurate = splitQuadratic(u,
v,
w, pts);
1216 int pointIndex = m_points->size();
1217 m_points->add(pts[1]);
1218 accurate &= setElementToQuadratic(
first,
first->indices[0], pts[0], pointIndex);
1219 accurate &= setElementToQuadratic(second, pointIndex, pts[2], second->indices[2]);
1225 int pointIndex = m_points->size();
1226 m_points->add(pts[2]);
1227 accurate &= setElementToCubic(
first,
first->indices[0], pts[0], pts[1], pointIndex);
1228 accurate &= setElementToCubic(second, pointIndex, pts[3], pts[4], second->indices[3]);
1232 first->processed = second->processed =
false;
1234 BVHNode *
left = m_bvh.newNode();
1235 BVHNode *
right = m_bvh.newNode();
1236 left->type =
right->type = BVHNode::Leaf;
1238 right->element = second;
1240 left->minimum.rx() =
left->minimum.ry() =
right->minimum.rx() =
right->minimum.ry() = INT_MAX;
1241 left->maximum.rx() =
left->maximum.ry() =
right->maximum.rx() =
right->maximum.ry() = INT_MIN;
1243 for (
int i = 0;
i <=
first->degree; ++
i) {
1250 for (
int i = 0;
i <= second->degree; ++
i) {
1251 QPoint &
p = m_points->at(second->indices[
i]);
1260 node->type = BVHNode::Split;
1262 node->right =
right;
1264 if (!
first->processed) {
1270bool PathSimplifier::setElementToQuadratic(Element *element,
quint32 pointIndex1,
1273 const QPoint &
p1 = m_points->at(pointIndex1);
1274 const QPoint &
p2 = m_points->at(pointIndex2);
1275 if (flattenQuadratic(
p1, ctrl,
p2)) {
1277 element->degree = Element::Line;
1278 element->indices[0] = pointIndex1;
1279 element->indices[1] = pointIndex2;
1280 element->middle.rx() = (
p1.x() +
p2.x()) >> 1;
1281 element->middle.ry() = (
p1.y() +
p2.y()) >> 1;
1285 element->degree = Element::Quadratic;
1286 element->indices[0] = pointIndex1;
1287 element->indices[1] = m_points->size();
1288 element->indices[2] = pointIndex2;
1289 element->middle.rx() = (
p1.x() + ctrl.
x() +
p2.x()) / 3;
1290 element->middle.ry() = (
p1.y() + ctrl.
y() +
p2.y()) / 3;
1291 m_points->add(ctrl);
1296bool PathSimplifier::setElementToCubic(Element *element,
quint32 pointIndex1,
const QPoint &
v,
1299 const QPoint &u = m_points->at(pointIndex1);
1300 const QPoint &
q = m_points->at(pointIndex2);
1301 if (flattenCubic(u,
v,
w,
q)) {
1303 element->degree = Element::Line;
1304 element->indices[0] = pointIndex1;
1305 element->indices[1] = pointIndex2;
1306 element->middle.rx() = (u.
x() +
q.x()) >> 1;
1307 element->middle.ry() = (u.
y() +
q.y()) >> 1;
1311 element->degree = Element::Cubic;
1312 element->indices[0] = pointIndex1;
1313 element->indices[1] = m_points->size();
1314 element->indices[2] = m_points->size() + 1;
1315 element->indices[3] = pointIndex2;
1316 element->middle.rx() = (u.
x() +
v.x() +
w.x() +
q.x()) >> 2;
1317 element->middle.ry() = (u.
y() +
v.y() +
w.y() +
q.y()) >> 2;
1324void PathSimplifier::setElementToCubicAndSimplify(Element *element,
quint32 pointIndex1,
1328 const QPoint &u = m_points->at(pointIndex1);
1329 const QPoint &
q = m_points->at(pointIndex2);
1330 if (flattenCubic(u,
v,
w,
q)) {
1332 element->degree = Element::Line;
1333 element->indices[0] = pointIndex1;
1334 element->indices[1] = pointIndex2;
1335 element->middle.rx() = (u.
x() +
q.x()) >> 1;
1336 element->middle.ry() = (u.
y() +
q.y()) >> 1;
1340 bool intersecting = (u ==
q) || intersectionPoint(u,
v,
w,
q).isValid();
1341 if (!intersecting) {
1343 element->degree = Element::Cubic;
1344 element->indices[0] = pointIndex1;
1345 element->indices[1] = m_points->size();
1346 element->indices[2] = m_points->size() + 1;
1347 element->indices[3] = pointIndex2;
1348 element->middle.rx() = (u.
x() +
v.x() +
w.x() +
q.x()) >> 2;
1349 element->middle.ry() = (u.
y() +
v.y() +
w.y() +
q.y()) >> 2;
1357 int pointIndex = m_points->size();
1358 m_points->add(pts[2]);
1359 Element *element2 = m_elementAllocator.newElement();
1360 m_elements.add(element2);
1361 setElementToCubicAndSimplify(element, pointIndex1, pts[0], pts[1], pointIndex);
1362 setElementToCubicAndSimplify(element2, pointIndex, pts[3], pts[4], pointIndex2);
1368 if (!m_elementList.root)
1370 RBNode *current = bounds.first;
1371 Q_ASSERT(!current || !elementIsLeftOf(element, current->data));
1373 current = m_elementList.front(m_elementList.root);
1375 RBNode *
result =
nullptr;
1376 while (current != bounds.second && !elementIsLeftOf(element, current->data)) {
1378 current = m_elementList.next(current);
1383bool PathSimplifier::elementIsLeftOf(
const Element *
left,
const Element *
right)
1385 const QPoint &leftU = m_points->at(
left->upperIndex());
1386 const QPoint &leftL = m_points->at(
left->lowerIndex());
1387 const QPoint &rightU = m_points->at(
right->upperIndex());
1388 const QPoint &rightL = m_points->at(
right->lowerIndex());
1389 Q_ASSERT(leftL >= rightU && rightL >= leftU);
1390 if (leftU.
x() <
qMin(rightL.
x(), rightU.
x()))
1392 if (leftU.
x() >
qMax(rightL.
x(), rightU.
x()))
1394 int d = pointDistanceFromLine(leftU, rightL, rightU);
1397 d = pointDistanceFromLine(leftL, rightL, rightU);
1399 if (
right->degree > Element::Line) {
1400 d = pointDistanceFromLine(leftL, rightL, m_points->at(
right->indices[1]));
1402 d = pointDistanceFromLine(leftL, rightL, m_points->at(
right->indices[2]));
1403 }
else if (
left->degree > Element::Line) {
1404 d = pointDistanceFromLine(m_points->at(
left->indices[1]), rightL, rightU);
1406 d = pointDistanceFromLine(m_points->at(
left->indices[2]), rightL, rightU);
1415 RBNode *current = m_elementList.root;
1419 const Element *element = current->data;
1420 Q_ASSERT(element->edgeNode == current);
1421 const QPoint &
v1 = m_points->at(element->lowerIndex());
1422 const QPoint &
v2 = m_points->at(element->upperIndex());
1424 if (point ==
v1 || point ==
v2)
1426 int d = pointDistanceFromLine(point,
v1,
v2);
1428 if (element->degree == Element::Line)
1430 d = pointDistanceFromLine(point,
v1, m_points->at(element->indices[1]));
1432 d = pointDistanceFromLine(point,
v1, m_points->at(element->indices[2]));
1437 current = current->left;
1440 current = current->right;
1447 RBNode *mid = current;
1449 current = mid->left;
1451 const Element *element = current->data;
1452 Q_ASSERT(element->edgeNode == current);
1453 const QPoint &
v1 = m_points->at(element->lowerIndex());
1454 const QPoint &
v2 = m_points->at(element->upperIndex());
1456 bool equal = (point ==
v1 || point ==
v2);
1458 int d = pointDistanceFromLine(point,
v1,
v2);
1460 equal = (
d == 0 && element->degree == Element::Line);
1463 current = current->left;
1466 current = current->right;
1470 current = mid->right;
1472 const Element *element = current->data;
1473 Q_ASSERT(element->edgeNode == current);
1474 const QPoint &
v1 = m_points->at(element->lowerIndex());
1475 const QPoint &
v2 = m_points->at(element->upperIndex());
1477 bool equal = (point ==
v1 || point ==
v2);
1479 int d = pointDistanceFromLine(point,
v1,
v2);
1481 equal = (
d == 0 && element->degree == Element::Line);
1484 current = current->right;
1487 current = current->left;
1497 int d =
qAbs(cross(deltas[0], deltas[1]));
1502inline bool PathSimplifier::flattenCubic(
const QPoint &u,
const QPoint &
v,
1506 int d =
qAbs(cross(deltas[0], deltas[1])) +
qAbs(cross(deltas[1], deltas[2]))
1507 +
qAbs(cross(deltas[0], deltas[3])) +
qAbs(cross(deltas[3], deltas[2]));
1513inline bool PathSimplifier::splitQuadratic(
const QPoint &u,
const QPoint &
v,
1530inline bool PathSimplifier::splitCubic(
const QPoint &u,
const QPoint &
v,
1557 if (flattenQuadratic(u,
v,
w))
1560 splitQuadratic(u,
v,
w, pts);
1561 subDivQuadratic(u, pts[0], pts[1]);
1562 m_indices->add(m_points->size());
1563 m_points->add(pts[1]);
1564 subDivQuadratic(pts[1], pts[2],
w);
1567inline void PathSimplifier::subDivCubic(
const QPoint &u,
const QPoint &
v,
1570 if (flattenCubic(u,
v,
w,
q))
1574 subDivCubic(u, pts[0], pts[1], pts[2]);
1575 m_indices->add(m_points->size());
1576 m_points->add(pts[2]);
1577 subDivCubic(pts[2], pts[3], pts[4],
q);
1580void PathSimplifier::sortEvents(
Event *events,
int count)
1588 memset(counts, 0,
sizeof(counts));
1603 for (
int i = 1;
i < 0x100; ++
i)
1604 counts[
i] += counts[
i - 1];
1605 counts[0x100] = counts[0xff];
1609 buffer.at(--counts[bins[
i]]) = events[
i];
1612 for (
int i = 0;
i < 0x100; ++
i) {
1613 for (;
j < counts[
i + 1]; ++
j) {
1615 while (k > 0 && (
buffer.at(
j) < events[k - 1])) {
1616 events[k] = events[k - 1];
1639#undef Q_FIXED_POINT_SCALE
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
\inmodule QtCore\reentrant
constexpr int & rx() noexcept
Returns a reference to the x coordinate of this point.
constexpr int x() const noexcept
Returns the x coordinate of this point.
constexpr int y() const noexcept
Returns the y coordinate of this point.
constexpr size_type size() const noexcept
const T & at(qsizetype idx) const
constexpr float y() const noexcept
Returns the y coordinate of this point.
constexpr float x() const noexcept
Returns the x coordinate of this point.
Combined button and popup list for selecting options.
void flip(QMatrix4x4 &matrix)
QVector3D minimum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
QVector3D maximum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
std::pair< T1, T2 > QPair
static void splitCubic(QCosmeticStroker::PointF *points)
int qRound(qfloat16 d) noexcept
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
constexpr T qAbs(const T &t)
GLint GLfloat GLfloat GLfloat v2
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
GLenum GLenum GLsizei count
GLsizei GLenum const void * indices
GLfixed GLfixed GLfixed y2
GLdouble GLdouble GLdouble GLdouble q
GLsizei const GLchar *const * path
const QVectorPath & qtVectorPathForPath(const QPainterPath &path)
static qreal dot(const QPointF &a, const QPointF &b)
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)
bool operator<(const QPoint &a, const QPoint &b)
#define Q_ASSERT_X(cond, x, msg)
static const struct TessellationWindingOrderTab ccw[]
static const QTextHtmlElement elements[Html_NumElements]
static quint64 gcd(quint64 x, quint64 y)
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
static bool equal(const QChar *a, int l, const char *b)
std::uniform_real_distribution dist(1, 2.5)
[2]