File indexing completed on 2024-05-12 15:58:14

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