aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Rauter <[email protected]>2024-01-15 16:30:01 +0100
committerMatthias Rauter <[email protected]>2024-01-17 15:36:27 +0100
commit17d94525b122acae735babd88527cf4a100d9af7 (patch)
tree56ff31abc71aaa60dfc1eae3316ba5d736149a1c
parent96bd963cb7af37fd3b20ce3a1c9fd50939bed6fc (diff)
Improve finding the fillside for horizontal lines
Finding the fillside depends on drawing an imaginary line to x = infinty and counting the intersections with the polygon. This does not work reliably if the line is horizontal. To make this work for horizontal lines, we switch x and y in the respective algorithm. Pick-to: 6.7 Change-Id: I3f625204783c7de2e822bf42d5aaaca6f321dec4 Reviewed-by: Paul Olav Tvete <[email protected]>
-rw-r--r--src/quick/scenegraph/util/qquadpath.cpp48
-rw-r--r--src/quick/scenegraph/util/qquadpath_p.h2
2 files changed, 28 insertions, 22 deletions
diff --git a/src/quick/scenegraph/util/qquadpath.cpp b/src/quick/scenegraph/util/qquadpath.cpp
index 188d53cd6a..7af89d4bca 100644
--- a/src/quick/scenegraph/util/qquadpath.cpp
+++ b/src/quick/scenegraph/util/qquadpath.cpp
@@ -248,13 +248,15 @@ float QQuadPath::Element::extent() const
// Returns the number of intersections between element and a horizontal line at y.
// The t values of max 2 intersection(s) are stored in the fractions array
-int QQuadPath::Element::intersectionsAtY(float y, float *fractions) const
+int QQuadPath::Element::intersectionsAtY(float y, float *fractions, bool swapXY) const
{
Q_ASSERT(!isLine());
- const float y0 = startPoint().y() - y;
- const float y1 = controlPoint().y() - y;
- const float y2 = endPoint().y() - y;
+ auto getY = [=](QVector2D p) -> float { return swapXY ? -p.x() : p.y(); };
+
+ const float y0 = getY(startPoint()) - y;
+ const float y1 = getY(controlPoint()) - y;
+ const float y2 = getY(endPoint()) - y;
int numRoots = 0;
const float a = y0 - (2 * y1) + y2;
@@ -372,45 +374,49 @@ QQuadPath::Element::FillSide QQuadPath::fillSideOf(int elementIdx, float element
constexpr float toleranceT = 1e-3f;
const QVector2D point = m_elements.at(elementIdx).pointAtFraction(elementT);
+ const bool swapXY = qAbs(m_elements.at(elementIdx).tangentAtFraction(elementT).x()) > qAbs(m_elements.at(elementIdx).tangentAtFraction(elementT).y());
+ auto getX = [=](QVector2D p) -> float { return swapXY ? p.y() : p.x(); };
+ auto getY = [=](QVector2D p) -> float { return swapXY ? -p.x() : p.y(); };
+
int winding_number = 0;
for (int i = 0; i < elementCount(); i++) {
const Element &e = m_elements.at(i);
- int dir = 1;
- float y1 = e.startPoint().y();
- float y2 = e.endPoint().y();
+ int dir = 1;
+ float y1 = getY(e.startPoint());
+ float y2 = getY(e.endPoint());
if (y2 < y1) {
qSwap(y1, y2);
dir = -1;
}
if (e.m_isLine) {
- if (point.y() < y1 || point.y() >= y2 || y1 == y2)
+ if (getY(point) < y1 || getY(point) >= y2 || y1 == y2)
continue;
- const float t = (point.y() - e.startPoint().y()) / (e.endPoint().y() - e.startPoint().y());
- const float x = e.startPoint().x() + t * (e.endPoint().x() - e.startPoint().x());
- if ((elementIdx != i && x <= point.x()) ||
- (elementIdx == i && x <= point.x() && qAbs(t - elementT) > toleranceT)) {
+ const float t = (getY(point) - getY(e.startPoint())) / (getY(e.endPoint()) - getY(e.startPoint()));
+ const float x = getX(e.startPoint()) + t * (getX(e.endPoint()) - getX(e.startPoint()));
+ if ((elementIdx != i && x <= getX(point)) ||
+ (elementIdx == i && x <= getX(point) && qAbs(t - elementT) > toleranceT)) {
winding_number += dir;
}
} else {
- y1 = qMin(y1, e.controlPoint().y());
- y2 = qMax(y2, e.controlPoint().y());
- if (point.y() < y1 || point.y() >= y2)
+ y1 = qMin(y1, getY(e.controlPoint()));
+ y2 = qMax(y2, getY(e.controlPoint()));
+ if (getY(point) < y1 || getY(point) >= y2)
continue;
float ts[2];
- const int numRoots = e.intersectionsAtY(point.y(), ts);
+ const int numRoots = e.intersectionsAtY(getY(point), ts, swapXY);
// Count if there is exactly one intersection to the left
bool oneHit = false;
float tForHit = -1;
for (int j = 0; j < numRoots; j++) {
- const float x = e.pointAtFraction(ts[j]).x();
- if ((elementIdx != i && x <= point.x()) ||
- (elementIdx == i && x <= point.x() && qAbs(ts[j] - elementT) > toleranceT)) {
+ const float x = getX(e.pointAtFraction(ts[j]));
+ if ((elementIdx != i && x <= getX(point)) ||
+ (elementIdx == i && x <= getX(point) && qAbs(ts[j] - elementT) > toleranceT)) {
oneHit = !oneHit;
tForHit = ts[j];
}
}
if (oneHit) {
- dir = e.tangentAtFraction(tForHit).y() < 0 ? -1 : 1;
+ dir = getY(e.tangentAtFraction(tForHit)) < 0 ? -1 : 1;
winding_number += dir;
}
}
@@ -419,7 +425,7 @@ QQuadPath::Element::FillSide QQuadPath::fillSideOf(int elementIdx, float element
int left_winding_number = winding_number;
int right_winding_number = winding_number;
- int dir = m_elements.at(elementIdx).tangentAtFraction(elementT).y() < 0 ? -1 : 1;
+ int dir = getY(m_elements.at(elementIdx).tangentAtFraction(elementT)) < 0 ? -1 : 1;
if (dir > 0) {
left_winding_number += dir;
diff --git a/src/quick/scenegraph/util/qquadpath_p.h b/src/quick/scenegraph/util/qquadpath_p.h
index 82c571eff5..f038a87130 100644
--- a/src/quick/scenegraph/util/qquadpath_p.h
+++ b/src/quick/scenegraph/util/qquadpath_p.h
@@ -168,7 +168,7 @@ public:
};
private:
- int intersectionsAtY(float y, float *fractions) const;
+ int intersectionsAtY(float y, float *fractions, bool swapXY = false) const;
QVector2D sp;
QVector2D cp;