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

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_TIME_RANGE_H
0008 #define __KIS_TIME_RANGE_H
0009 
0010 #include "kritaimage_export.h"
0011 
0012 #include <algorithm>
0013 #include <limits>
0014 #include <QMetaType>
0015 #include <boost/operators.hpp>
0016 #include "kis_types.h"
0017 #include <kis_dom_utils.h>
0018 
0019 class KRITAIMAGE_EXPORT KisTimeSpan : public boost::equality_comparable<KisTimeSpan>
0020 {
0021 private:
0022     inline KisTimeSpan(int start, int end)
0023         : m_start(start),
0024           m_end(end)
0025     {
0026     }
0027 
0028 public:
0029     inline KisTimeSpan()
0030         : m_start(0),
0031           m_end(-1)
0032     {
0033     }
0034 
0035     inline int start() const {
0036         return m_start;
0037     }
0038 
0039     inline int end() const {
0040         return m_end;
0041     }
0042 
0043     inline int duration() const {
0044         return m_end >= m_start ? m_end - m_start + 1 : 0;
0045     }
0046 
0047     inline bool isInfinite() const {
0048         return m_end == std::numeric_limits<int>::min();
0049     }
0050 
0051     inline bool isValid() const {
0052         return (m_end >= m_start) || (m_end == std::numeric_limits<int>::min() && m_start >= 0);
0053     }
0054 
0055     inline bool contains(int time) const {
0056         if (m_end == std::numeric_limits<int>::min()) {
0057             return m_start <= time;
0058         }
0059 
0060         return m_start <= time && time <= m_end;
0061     }
0062 
0063     inline void include(int time) {
0064         m_start = qMin(time, m_start);
0065         m_end = qMax(time, m_end);
0066     }
0067 
0068     inline bool overlaps(const KisTimeSpan& other) const {
0069         // If either are "invalid", we should probably return false.
0070         if (!isValid() || !other.isValid()) {
0071             return false;
0072         }
0073 
0074         // Handle infinite cases...
0075         if (other.isInfinite()) {
0076             return (other.contains(start()) || other.contains(end()));
0077         } else if (isInfinite()) {
0078             return (contains(other.start()) || contains(other.end()));
0079         }
0080 
0081         const int selfMin = qMin(start(), end());
0082         const int selfMax = qMax(start(), end());
0083         const int otherMin = qMin(other.start(), other.end());
0084         const int otherMax = qMax(other.start(), other.end());
0085         return (selfMax >= otherMin) && (selfMin <= otherMax );
0086     }
0087 
0088     static inline KisTimeSpan fromTimeToTime(int start, int end) {
0089         return KisTimeSpan(start, end);
0090     }
0091 
0092     static inline KisTimeSpan fromTimeWithDuration(int start, int duration) {
0093         return KisTimeSpan( start, start + duration - 1);
0094     }
0095 
0096     static inline KisTimeSpan infinite(int start) {
0097         return KisTimeSpan(start, std::numeric_limits<int>::min());
0098     }
0099 
0100     static KisTimeSpan calculateIdenticalFramesRecursive(const KisNode *node, int time);
0101     static KisTimeSpan calculateAffectedFramesRecursive(const KisNode *node, int time);
0102 
0103     static KisTimeSpan calculateNodeIdenticalFrames(const KisNode *node, int time);
0104     static KisTimeSpan calculateNodeAffectedFrames(const KisNode *node, int time);
0105 
0106     bool operator==(const KisTimeSpan &rhs) const {
0107         return rhs.m_start == m_start && rhs.m_end == m_end;
0108     }
0109 
0110     KisTimeSpan operator|(const KisTimeSpan &rhs) const {
0111         KisTimeSpan result = *this;
0112 
0113         if (!result.isValid()) {
0114             result.m_start = rhs.start();
0115         } else if (rhs.isValid()) {
0116             result.m_start = std::min(result.m_start, rhs.start());
0117         }
0118 
0119         if (rhs.isInfinite() || result.isInfinite()) {
0120             result.m_end = std::numeric_limits<int>::min();
0121         } else if (!isValid()) {
0122             result.m_end = rhs.m_end;
0123         } else {
0124             result.m_end = std::max(m_end, rhs.m_end);
0125         }
0126 
0127         return result;
0128     }
0129 
0130     const KisTimeSpan& operator|=(const KisTimeSpan &rhs) {
0131         KisTimeSpan result = (*this | rhs);
0132         this->m_start = result.m_start;
0133         this->m_end = result.m_end;
0134         return *this;
0135     }
0136 
0137     KisTimeSpan operator&(const KisTimeSpan &rhs) const {
0138          KisTimeSpan result = *this;
0139 
0140         if (!isValid()) {
0141             return result;
0142         } else if (!rhs.isValid()) {
0143             result.m_start = rhs.start();
0144             result.m_end = rhs.m_end;
0145             return result;
0146         } else {
0147             result.m_start = std::max(result.m_start, rhs.start());
0148         }
0149 
0150         if (isInfinite()) {
0151             result.m_end = rhs.m_end;
0152         } else if (!rhs.isInfinite()) {
0153             result.m_end = std::min(result.m_end, rhs.m_end);
0154         }
0155 
0156         return result;
0157     }
0158 
0159     const KisTimeSpan& operator&=(const KisTimeSpan &rhs) {
0160         KisTimeSpan result = (*this & rhs);
0161         this->m_start = result.m_start;
0162         this->m_end = result.m_end;
0163         return *this;
0164     }
0165 
0166 private:
0167     int m_start;
0168     int m_end;
0169 };
0170 
0171 namespace KisDomUtils {
0172     void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const KisTimeSpan &range);
0173     bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, KisTimeSpan *range);
0174 }
0175 
0176 
0177 
0178 Q_DECLARE_METATYPE(KisTimeSpan)
0179 
0180 KRITAIMAGE_EXPORT QDebug operator<<(QDebug dbg, const KisTimeSpan &r);
0181 
0182 
0183 #endif /* __KIS_TIME_RANGE_H */