File indexing completed on 2024-05-19 04:26:11

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Cyrille Berger <cberger@cberger.net>
0003  *  SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #ifndef _KIS_DISTANCE_INFORMATION_H_
0009 #define _KIS_DISTANCE_INFORMATION_H_
0010 
0011 #include <QPointF>
0012 #include <QVector2D>
0013 #include <QDomDocument>
0014 #include <QDomElement>
0015 #include "kritaimage_export.h"
0016 #include <boost/optional.hpp>
0017 #include <boost/operators.hpp>
0018 
0019 class KisPaintInformation;
0020 class KisSpacingInformation;
0021 class KisTimingInformation;
0022 class KisDistanceInformation;
0023 
0024 /**
0025  * Represents some information that can be used to initialize a KisDistanceInformation object. The
0026  * main purpose of this class is to allow serialization of KisDistanceInformation initial settings
0027  * to XML.
0028  */
0029 class KRITAIMAGE_EXPORT KisDistanceInitInfo : boost::equality_comparable<KisDistanceInitInfo> {
0030 
0031 public:
0032 
0033     /**
0034      * Creates a KisDistanceInitInfo with no initial last dab information, and spacing and timing
0035      * update intervals set to LONG_TIME.
0036      */
0037     explicit KisDistanceInitInfo();
0038 
0039     /**
0040      * Creates a KisDistanceInitInfo with no initial last dab information, and the specified spacing
0041      * and timing update intervals.
0042      */
0043     explicit KisDistanceInitInfo(qreal spacingUpdateInterval, qreal timingUpdateInterval, int currentDabSeqNo);
0044 
0045     /**
0046      * Creates a KisDistanceInitInfo with the specified last dab information, and spacing and timing
0047      * update intervals set to LONG_TIME.
0048      */
0049     explicit KisDistanceInitInfo(const QPointF &lastPosition, qreal lastAngle, int currentDabSeqNo);
0050 
0051     /**
0052      * Creates a KisDistanceInitInfo with the specified last dab information and spacing and timing
0053      * update intervals.
0054      */
0055     explicit KisDistanceInitInfo(const QPointF &lastPosition, qreal lastAngle,
0056                                  qreal spacingUpdateInterval, qreal timingUpdateInterval, int currentDabSeqNo);
0057 
0058     KisDistanceInitInfo(const KisDistanceInitInfo &rhs);
0059 
0060     ~KisDistanceInitInfo();
0061 
0062     bool operator==(const KisDistanceInitInfo &other) const;
0063 
0064     KisDistanceInitInfo &operator=(const KisDistanceInitInfo &rhs);
0065 
0066     /**
0067      * Constructs a KisDistanceInformation with initial settings based on this object.
0068      */
0069     KisDistanceInformation makeDistInfo();
0070 
0071     void toXML(QDomDocument &doc, QDomElement &elt) const;
0072 
0073     static KisDistanceInitInfo fromXML(const QDomElement &elt);
0074 
0075 private:
0076     struct Private;
0077     Private * const m_d;
0078 };
0079 
0080 /**
0081  * This structure keeps track of distance and timing information during a stroke, e.g. the time or
0082  * distance moved since the last dab.
0083  */
0084 class KRITAIMAGE_EXPORT KisDistanceInformation {
0085 public:
0086     KisDistanceInformation();
0087     KisDistanceInformation(qreal spacingUpdateInterval, qreal timingUpdateInterval, int currentDabSeqNo = 0);
0088     KisDistanceInformation(const QPointF &lastPosition, qreal lastAngle);
0089     /**
0090      * @param spacingUpdateInterval The amount of time allowed between spacing updates, in
0091      *                              milliseconds. Use LONG_TIME to only allow spacing updates when a
0092      *                              dab is painted.
0093      * @param timingUpdateInterval The amount of time allowed between time-based spacing updates, in
0094      *                             milliseconds. Use LONG_TIME to only allow timing updates when a
0095      *                             dab is painted.
0096      */
0097     KisDistanceInformation(const QPointF &lastPosition, qreal lastAngle,
0098                            qreal spacingUpdateInterval, qreal timingUpdateInterval, int currentDabSeqNo);
0099     KisDistanceInformation(const KisDistanceInformation &rhs);
0100     KisDistanceInformation(const KisDistanceInformation &rhs, int levelOfDetail);
0101     KisDistanceInformation& operator=(const KisDistanceInformation &rhs);
0102 
0103     ~KisDistanceInformation();
0104 
0105     const KisSpacingInformation& currentSpacing() const;
0106     void updateSpacing(const KisSpacingInformation &spacing);
0107     /**
0108      * Returns true if this KisDistanceInformation should have its spacing information updated
0109      * immediately (regardless of whether a dab is ready to be painted).
0110      */
0111     bool needsSpacingUpdate() const;
0112 
0113     const KisTimingInformation &currentTiming() const;
0114     void updateTiming(const KisTimingInformation &timing);
0115     /**
0116      * Returns true if this KisDistanceInformation should have its timing information updated
0117      * immediately (regardless of whether a dab is ready to be painted).
0118      */
0119     bool needsTimingUpdate() const;
0120 
0121     bool hasLastDabInformation() const;
0122     QPointF lastPosition() const;
0123     qreal lastDrawingAngle() const;
0124 
0125     bool hasLastPaintInformation() const;
0126     const KisPaintInformation& lastPaintInformation() const;
0127 
0128     int currentDabSeqNo() const;
0129 
0130     qreal maxPressure() const;
0131 
0132     /**
0133      * @param spacing The new effective spacing after the dab. (Painting a dab is always supposed to
0134      *                cause a spacing update.)
0135      * @param timing The new effective timing after the dab. (Painting a dab is always supposed to
0136      *               cause a timing update.)
0137      */
0138     void registerPaintedDab(const KisPaintInformation &info,
0139                             const KisSpacingInformation &spacing,
0140                             const KisTimingInformation &timing);
0141 
0142     qreal getNextPointPosition(const QPointF &start,
0143                                const QPointF &end,
0144                                qreal startTime,
0145                                qreal endTime);
0146 
0147     qreal getSpacingInterval() const;
0148     qreal getTimingUpdateInterval() const;
0149 
0150     /**
0151      * \return true if at least one dab has been painted with this
0152      *         distance information
0153      */
0154     bool isStarted() const;
0155 
0156     boost::optional<qreal> lockedDrawingAngleOptional() const;
0157 
0158     /**
0159      * Lock current drawing angle for the rest of the stroke. The new value is blended
0160      * into the result proportional to the length of the stroke.
0161      */
0162     void lockCurrentDrawingAngle(const KisPaintInformation &info) const;
0163 
0164     qreal scalarDistanceApprox() const;
0165 
0166     void overrideLastValues(const QPointF &lastPosition, qreal lastAngle);
0167 
0168 private:
0169     qreal getNextPointPositionIsotropic(const QPointF &start,
0170                                         const QPointF &end);
0171     qreal getNextPointPositionAnisotropic(const QPointF &start,
0172                                           const QPointF &end);
0173     qreal getNextPointPositionTimed(qreal startTime,
0174                                     qreal endTime);
0175     void resetAccumulators();
0176 
0177 private:
0178     struct Private;
0179     Private * const m_d;
0180 };
0181 
0182 #endif