File indexing completed on 2025-02-02 04:54:39
0001 // SPDX-License-Identifier: GPL-2.0-or-later 0002 // SPDX-FileCopyrightText: 2018 Kevin Ottens <ervin@kde.org> 0003 0004 #include "strokepainter.h" 0005 0006 #include <QPainter> 0007 #include <QPainterPath> 0008 #include <QVector2D> 0009 0010 #include <algorithm> 0011 #include <cmath> 0012 using namespace std; 0013 0014 #include "stroke.h" 0015 0016 StrokePainter::StrokePainter(QObject *parent) 0017 : QObject(parent) 0018 { 0019 } 0020 0021 void StrokePainter::render(const Stroke &stroke, QPainter *painter) 0022 { 0023 const auto samples = stroke.samples(); 0024 if (samples.size() < 2) 0025 return; 0026 0027 auto it = samples.cbegin(); 0028 auto lastSample = *it; 0029 ++it; 0030 0031 auto forwardPoints = QVector<QVector2D>{}; 0032 auto backwardPoints = QVector<QVector2D>{}; 0033 0034 while (it != samples.cend()) { 0035 const auto currentSample = *it; 0036 0037 const auto penWidth = currentSample.width; 0038 0039 const auto currentPos = currentSample.position; 0040 const auto lastPos = lastSample.position; 0041 0042 const auto direction = currentPos - lastPos; 0043 const auto ortho = QVector2D(direction.y(), -direction.x()).normalized(); 0044 0045 const auto p1 = (lastPos - penWidth * ortho / 2.0f); 0046 const auto p2 = (lastPos + penWidth * ortho / 2.0f); 0047 const auto p3 = (currentPos - penWidth * ortho / 2.0f); 0048 const auto p4 = (currentPos + penWidth * ortho / 2.0f); 0049 0050 int minX = (int)min({p1.x(), p2.x(), p3.x(), p4.x()}); 0051 if (!lowestX || minX < lowestX) 0052 lowestX = minX; 0053 0054 int maxX = (int)max({p1.x(), p2.x(), p3.x(), p4.x()}); 0055 if (!highestX || maxX > highestX) 0056 highestX = maxX; 0057 0058 int minY = (int)min({p1.y(), p2.y(), p3.y(), p4.y()}); 0059 if (!lowestY || minY < lowestY) 0060 lowestY = minY; 0061 0062 int maxY = (int)max({p1.y(), p2.y(), p3.y(), p4.y()}); 0063 if (!highestY || maxY > highestY) 0064 highestY = maxY; 0065 0066 forwardPoints << p1 << p3; 0067 backwardPoints << p2 << p4; 0068 0069 lastSample = currentSample; 0070 ++it; 0071 } 0072 0073 auto path = QPainterPath(); 0074 path.moveTo(static_cast<qreal>(forwardPoints[0].x()), static_cast<qreal>(forwardPoints[0].y())); 0075 for (auto it = forwardPoints.cbegin() + 1; it != forwardPoints.cend(); ++it) { 0076 path.lineTo(static_cast<qreal>(it->x()), static_cast<qreal>(it->y())); 0077 } 0078 for (auto it = backwardPoints.crbegin(); it != backwardPoints.crend(); ++it) { 0079 path.lineTo(static_cast<qreal>(it->x()), static_cast<qreal>(it->y())); 0080 } 0081 path.closeSubpath(); 0082 path.setFillRule(Qt::WindingFill); 0083 0084 painter->setPen(Qt::NoPen); 0085 painter->setBrush(stroke.color()); 0086 painter->drawPath(path); 0087 }