18#include <QPainterPath>
24const qreal
M_PI = 3.1415927;
76 s->points.append(calligraphicPoint);
81 if (
s->points.count() == 4) {
82 s->points[0].setAngle(angle);
83 s->points[1].setAngle(angle);
84 s->points[2].setAngle(angle);
92 qreal dx = std::cos(
p.angle()) *
p.width();
93 qreal dy = std::sin(
p.angle()) *
p.width();
96 QPointF
p1 =
p.point() - QPointF(dx / 2, dy / 2);
97 QPointF
p2 =
p.point() + QPointF(dx / 2, dy / 2);
131 s->lastWasFlip =
true;
134 if (
s->lastWasFlip) {
146 s->lastWasFlip =
false;
156 if (
s->points.count() >= 4 &&
p ==
s->points[3]) {
191 }
else if (index < 1) {
203 QPointF vector = next - prev;
204 qreal dist = (QLineF(prev, next)).
length();
211 qreal dist1 = (QLineF(point, prev)).
length() * mult;
212 qreal dist2 = (QLineF(point, next)).
length() * mult;
213 QPointF vector1 = vector * dist1;
214 QPointF vector2 = vector * dist2;
215 QPointF controlPoint1 = point - vector1;
216 QPointF controlPoint2 = point + vector2;
246 return p.boundingRect().translated(
position());
257 int sum1 = std::abs(
ccw(
p1,
p2, last1) +
ccw(
p1, last2, last1));
258 int sum2 = std::abs(
ccw(
p2,
p1, last2) +
ccw(
p2, last1, last2));
260 return sum1 < 2 && sum2 < 2;
266 qreal area2 = (
p2.x() -
p1.x()) * (
p3.y() -
p1.y()) -
267 (
p2.y() -
p1.y()) * (
p3.x() -
p1.x());
270 }
else if (area2 < 0) {
288 matrix.translate(-offset.x(), -offset.y());
290 for (
int i = 0; i <
s->points.size(); ++i) {
291 s->points[i].setPoint(matrix.map(
s->points[i].point()));
298 const QPointF &point,
299 Qt::KeyboardModifiers modifiers)
302 s->points[handleId].setPoint(point);
331 if (
s->points.count() < 2) {
347 QPointF
p1 =
s->points[index1].point();
348 QPointF
p2 =
s->points[index2].point();
351 QPointF delta =
p2 -
p1;
352 if (delta.manhattanLength() < 1.0) {
356 QPointF direction = QLineF(QPointF(0, 0), delta).unitVector().p2();
357 qreal width =
s->points[index2].width();
358 QPointF
p =
p2 + direction *
s->caps * width;
362 qreal angle =
s->points[index2].angle();
367 qreal dx = std::cos(angle) * width;
368 qreal dy = std::sin(angle) * width;
383 if (
s->points.count() < 3) {
389 points.append(
p.point());
393 qreal widthChange = 0;
394 qreal directionChange = 0;
397 while (i != std::prev(
s->points.end())) {
398 QPointF point = i->point();
400 qreal width = i->width();
401 qreal prevWidth = std::prev(i)->width();
402 qreal widthDiff = width - prevWidth;
403 widthDiff /= qMax(width, prevWidth);
405 qreal directionDiff = 0;
406 if (std::next(i) !=
s->points.end()) {
407 QPointF prev = std::prev(i)->point();
408 QPointF next = std::next(i)->point();
410 directionDiff = QLineF(prev, point).angleTo(QLineF(point, next));
411 if (directionDiff > 180) {
412 directionDiff -= 360;
416 if (directionChange * directionDiff >= 0 &&
417 qAbs(directionChange + directionDiff) < 20 &&
418 widthChange * widthDiff >= 0 &&
419 qAbs(widthChange + widthDiff) < 0.1) {
421 i =
s->points.erase(i);
422 directionChange += directionDiff;
423 widthChange += widthDiff;
qreal length(const QPointF &vec)
#define KarbonCalligraphicShapeId
void karbonSimplifyPath(KoPathShape *path, qreal error)
QSharedPointer< KoShapeStrokeModel > KoShapeStrokeModelSP
QPair< int, int > KoPathPointIndex
KarbonCalligraphicShape(qreal caps=0.0)
void setSize(const QSizeF &newSize) override
Resize the shape.
KoShape * cloneShape() const override
creates a deep copy of the shape or shape's subtree
void appendPointsToPathAux(const QPointF &p1, const QPointF &p2)
void appendPoint(const QPointF &p1, qreal angle, qreal width)
~KarbonCalligraphicShape() override
const QRectF lastPieceBoundingRect()
static int ccw(const QPointF &p1, const QPointF &p2, const QPointF &p3)
void smoothPoint(const int index)
bool flipDetected(const QPointF &p1, const QPointF &p2)
void updatePath(const QSizeF &size) override
Update the path of the parameter shape.
QString pathShapeId() const override
void addCap(int index1, int index2, int pointIndex, bool inverted=false)
void appendPointToPath(const KarbonCalligraphicPoint &p)
QPointF normalize() override
Normalizes the path data.
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers=Qt::NoModifier) override
Updates the internal state of a KoParameterShape.
QSharedDataPointer< Private > s
A simple solid color shape background.
QPointF normalize() override
Normalizes the path data.
QList< QPointF > handles
the handles that the user can grab and change
void setSize(const QSizeF &size) override
reimplemented from KoShape
void setHandles(const QList< QPointF > &handles)
A KoPathPoint represents a point in a path.
void setControlPoint1(const QPointF &point)
Set the control point 1.
void setControlPoint2(const QPointF &point)
Set the control point 2.
void removeControlPoint1()
Removes the first control point.
void removeControlPoint2()
Removes the second control point.
KoPathPoint * lineTo(const QPointF &p)
Adds a new line segment.
QSizeF size() const override
reimplemented
void close()
Closes the current subpath.
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule to be used for painting the background.
KoPathPoint * moveTo(const QPointF &p)
Starts a new Subpath.
int pointCount() const
Returns the number of points in the path.
KoPathPoint * pointByIndex(const KoPathPointIndex &pointIndex) const
Returns the path point specified by a path point index.
void clear()
Removes all subpaths and their points from the path.
bool insertPoint(KoPathPoint *point, const KoPathPointIndex &pointIndex)
Inserts a new point into the given subpath at the specified position.
virtual void setStroke(KoShapeStrokeModelSP stroke)
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
virtual void setPosition(const QPointF &position)
Set the position of the shape in pt.
void setShapeId(const QString &id)
QPointF position() const
Get the position of the shape in pt.
static bool qFuzzyCompare(half p1, half p2)
Private(const Private &rhs)=default
QList< KarbonCalligraphicPoint > points