9#define CURVE_FLATNESS Q_PI / 8
14void QTriangulatingStroker::endCapOrJoinClosed(
const qreal *
start,
const qreal *cur,
15 bool implicitClose,
bool endsAtStart)
20 }
else if (implicitClose) {
40 while ((*pts + 2) < endPts &&
float((*pts)[0]) ==
float((*pts)[2])
41 &&
float((*pts)[1]) ==
float((*pts)[3]))
60 m_width = realWidth / 2;
64 m_width = m_width * m_inv_scale;
91 if (realWidth < 2.5 && (cosmetic || m_inv_scale == 1)) {
96 m_curvyness_add = 0.5;
99 }
else if (cosmetic) {
100 m_curvyness_add = realWidth / 2;
104 m_curvyness_add = m_width;
106 m_roundness = qMax<int>(4, realWidth * m_curvyness_mul);
111 if (m_roundness > 24)
118 const qreal *startPts =
nullptr;
124 if ((pts + 2) == endPts)
129 bool endsAtStart = float(startPts[0]) == float(endPts[-2])
130 && float(startPts[1]) == float(endPts[-1]);
132 if (endsAtStart ||
path.hasImplicitClose())
141 while (pts < endPts) {
147 endCapOrJoinClosed(startPts, pts-2,
path.hasImplicitClose(), endsAtStart);
150 bool endsAtStart =
false;
152 const qreal *previousPts = pts;
153 while (pts < endPts) {
156 int end = (endPts - pts) / 2;
157 int nextMoveElement = 1;
158 bool hasValidLineSegments =
false;
160 if (!hasValidLineSegments) {
161 hasValidLineSegments =
162 float(pts[0]) != float(pts[nextMoveElement * 2]) ||
163 float(pts[1]) != float(pts[nextMoveElement * 2 + 1]);
175 if (!hasValidLineSegments) {
176 pts += 2 * nextMoveElement;
177 types += nextMoveElement;
182 endCapOrJoinClosed(startPts, previousPts,
path.hasImplicitClose(), endsAtStart);
186 if (startPts + 2 >= endPts)
189 endsAtStart = float(startPts[0]) == float(pts[nextMoveElement * 2 - 2])
190 && float(startPts[1]) == float(pts[nextMoveElement * 2 - 1]);
191 if (endsAtStart ||
path.hasImplicitClose())
202 if (
float(m_cx) !=
float(pts[0]) ||
float(m_cy) !=
float(pts[1])) {
213 if (
float(m_cx) !=
float(pts[0]) ||
float(m_cy) !=
float(pts[1])
214 ||
float(pts[0]) !=
float(pts[2]) ||
float(pts[1]) !=
float(pts[3])
215 ||
float(pts[2]) !=
float(pts[4]) ||
float(pts[3]) !=
float(pts[5]))
217 if (
float(m_cx) !=
float(pts[0]) ||
float(m_cy) !=
float(pts[1])) {
223 previousPts = pts + 4;
235 endCapOrJoinClosed(startPts, previousPts,
path.hasImplicitClose(), endsAtStart);
239void QTriangulatingStroker::moveTo(
const qreal *pts)
246 normalVector(m_cx, m_cy,
x2,
y2, &m_nvx, &m_nvy);
252 bool invisibleJump = m_vertices.
size();
254 switch (m_cap_style) {
257 m_vertices.
add(m_cx + m_nvx);
258 m_vertices.
add(m_cy + m_nvy);
262 float sx = m_cx - m_nvy;
263 float sy = m_cy + m_nvx;
265 m_vertices.
add(sx + m_nvx);
266 m_vertices.
add(sy + m_nvy);
268 emitLineSegment(sx, sy, m_nvx, m_nvy);
272 arcPoints(m_cx, m_cy, m_cx + m_nvx, m_cy + m_nvy, m_cx - m_nvx, m_cy - m_nvy,
points);
273 m_vertices.
resize(m_vertices.
size() +
points.size() + 2 *
int(invisibleJump));
277 while (front !=
end) {
295 emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
298void QTriangulatingStroker::cubicTo(
const qreal *pts)
305 int threshold = qMin<float>(64, (rad + m_curvyness_add) * m_curvyness_mul);
308 qreal threshold_minus_1 = threshold - 1;
309 float vx = 0, vy = 0;
311 float cx = m_cx, cy = m_cy;
314 for (
int i=1;
i<threshold; ++
i) {
320 normalVector(cx, cy,
x,
y, &vx, &vy);
322 emitLineSegment(
x,
y, vx, vy);
335void QTriangulatingStroker::join(
const qreal *pts)
338 normalVector(m_cx, m_cy, pts[0], pts[1], &m_nvx, &m_nvy);
340 switch (m_join_style) {
347 float prevNvx = m_vertices.
at(
count - 2) - m_cx;
348 float prevNvy = m_vertices.
at(
count - 1) - m_cy;
349 float xprod = prevNvx * m_nvy - prevNvy * m_nvx;
350 float px, py, qx, qy;
370 float pu = px * prevNvx + py * prevNvy;
371 float qv = qx * m_nvx + qy * m_nvy;
372 float ix = (m_nvy * pu - prevNvy * qv) / xprod;
373 float iy = (prevNvx * qv - m_nvx * pu) / xprod;
376 if ((ix - px) * (ix - px) + (iy - py) * (iy - py) <= m_miter_limit * m_miter_limit) {
392 float prevNvx = m_vertices.
at(
count - 2) - m_cx;
393 float prevNvy = m_vertices.
at(
count - 1) - m_cy;
394 if (m_nvx * prevNvy - m_nvy * prevNvx < 0) {
395 arcPoints(0, 0, m_nvx, m_nvy, -prevNvx, -prevNvy,
points);
396 for (
int i =
points.size() / 2;
i > 0; --
i)
397 emitLineSegment(m_cx, m_cy,
points[2 *
i - 2],
points[2 *
i - 1]);
399 arcPoints(0, 0, -prevNvx, -prevNvy, m_nvx, m_nvy,
points);
400 for (
int i = 0;
i <
points.size() / 2; ++
i)
401 emitLineSegment(m_cx, m_cy,
points[2 *
i + 0],
points[2 *
i + 1]);
407 emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
410void QTriangulatingStroker::endCap(
const qreal *)
412 switch (m_cap_style) {
416 emitLineSegment(m_cx + m_nvy, m_cy - m_nvx, m_nvx, m_nvy);
424 while (front !=
end) {
439void QTriangulatingStroker::arcPoints(
float cx,
float cy,
float fromX,
float fromY,
float toX,
float toY,
QVarLengthArray<float> &
points)
441 float dx1 = fromX - cx;
442 float dy1 = fromY - cy;
443 float dx2 = toX - cx;
444 float dy2 = toY - cy;
447 while (dx1 * dy2 - dx2 * dy1 < 0) {
448 float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
449 float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
457 while (dx1 * dx2 + dy1 * dy2 < 0) {
458 float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
459 float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
467 while (dx1 * dy2 - dx2 * dy1 > 0) {
468 float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
469 float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
497 : m_points(0), m_types(0),
498 m_dash_stroker(
nullptr), m_inv_scale(1)
513 bool implicitClose =
path.hasImplicitClose();
530 float curvynessAdd, curvynessMul;
533 if (
width < 2.5 && (cosmetic || m_inv_scale == 1)) {
536 }
else if (cosmetic) {
537 curvynessAdd=
width / 2;
540 curvynessAdd =
width * m_inv_scale;
547 bool needsClose =
false;
549 if (pts[0] != pts[
count * 2 - 2] || pts[1] != pts[
count * 2 - 1])
553 const qreal *firstPts = pts;
555 m_dash_stroker.
begin(
this);
558 m_dash_stroker.
moveTo(pts[0], pts[1]);
560 while (pts < endPts) {
561 m_dash_stroker.
lineTo(pts[0], pts[1]);
565 while (pts < endPts) {
568 m_dash_stroker.
moveTo(pts[0], pts[1]);
573 m_dash_stroker.
lineTo(pts[0], pts[1]);
580 *(((
const QPointF *) pts) + 1),
581 *(((
const QPointF *) pts) + 2));
584 int threshold = qMin<float>(64, (rad + curvynessAdd) * curvynessMul);
588 qreal threshold_minus_1 = threshold - 1;
589 for (
int i=0;
i<threshold; ++
i) {
590 QPointF pt =
b.pointAt(
i / threshold_minus_1);
591 m_dash_stroker.
lineTo(pt.
x(), pt.
y());
601 m_dash_stroker.
lineTo(firstPts[0], firstPts[1]);
603 m_dash_stroker.
end();
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
QPointF pointAt(qreal t) const
void begin(void *data) override
Prepares the stroker.
void setMiterLimit(qreal limit)
void setDashPattern(const QList< qfixed > &dashPattern)
void setStrokeWidth(qreal width)
void setDashOffset(qreal offset)
void end() override
Finishes the stroke.
void process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints)
void resize(qsizetype size)
void reserve(qsizetype size)
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
QList< qreal > dashPattern() const
Returns the dash pattern of this pen.
bool isCosmetic() const
Returns true if the pen is cosmetic; otherwise returns false.
qreal miterLimit() const
Returns the miter limit of the pen.
qreal dashOffset() const
Returns the dash offset for the pen.
\inmodule QtCore\reentrant
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
\inmodule QtCore\reentrant
constexpr qreal height() const noexcept
Returns the height of the rectangle.
constexpr qreal width() const noexcept
Returns the width of the rectangle.
void setCubicToHook(qStrokerCubicToHook cubicToHook)
void moveTo(qfixed x, qfixed y)
void setMoveToHook(qStrokerMoveToHook moveToHook)
void setLineToHook(qStrokerLineToHook lineToHook)
void setClipRect(const QRectF &clip)
void lineTo(qfixed x, qfixed y)
void process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints)
Combined button and popup list for selecting options.
bool qFuzzyIsNull(qfloat16 f) noexcept
static QT_BEGIN_NAMESPACE const qreal Q_PI
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLsizei GLenum GLenum * types
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfixed GLfixed GLint GLint GLfixed points
GLfixed GLfixed GLfixed y2
GLsizei const GLchar *const * path
qreal qpen_widthf(const QPen &p)
Qt::PenCapStyle qpen_capStyle(const QPen &p)
Qt::PenJoinStyle qpen_joinStyle(const QPen &p)
static void qdashprocessor_moveTo(qreal x, qreal y, void *data)
static void qdashprocessor_cubicTo(qreal, qreal, qreal, qreal, qreal, qreal, void *)
static void skipDuplicatePoints(const qreal **pts, const qreal *endPts)
static void qdashprocessor_lineTo(qreal x, qreal y, void *data)