File indexing completed on 2024-05-12 03:47:45

0001 /*
0002     File                 : IntervalAttribute.h
0003     Project              : LabPlot
0004     Description          : A class representing an interval-based attribute
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2007 Knut Franke <knut.franke@gmx.de>
0007     SPDX-FileCopyrightText: 2007 Tilman Benkert <thzs@gmx.net>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #ifndef INTERVALATTRIBUTE_H
0013 #define INTERVALATTRIBUTE_H
0014 
0015 #include "Interval.h"
0016 #include <QVector>
0017 
0018 //! A class representing an interval-based attribute
0019 template<class T>
0020 class IntervalAttribute {
0021 public:
0022     void setValue(const Interval<int>& i, T value) {
0023         // first: subtract the new interval from all others
0024         QVector<Interval<int>> temp_list;
0025         for (int c = 0; c < m_intervals.size(); c++) {
0026             temp_list = Interval<int>::subtract(m_intervals.at(c), i);
0027             if (temp_list.isEmpty()) {
0028                 m_intervals.removeAt(c);
0029                 m_values.removeAt(c--);
0030             } else {
0031                 m_intervals.replace(c, temp_list.at(0));
0032                 if (temp_list.size() > 1) {
0033                     m_intervals.insert(c, temp_list.at(1));
0034                     m_values.insert(c, m_values.at(c));
0035                 }
0036             }
0037         }
0038 
0039         // second: try to merge the new interval with an old one
0040         for (int c = 0; c < m_intervals.size(); c++) {
0041             if (m_intervals.at(c).touches(i) && m_values.at(c) == value) {
0042                 m_intervals.replace(c, Interval<int>::merge(m_intervals.at(c), i));
0043                 return;
0044             }
0045         }
0046         // if it could not be merged, just append it
0047         m_intervals.append(i);
0048         m_values.append(value);
0049     }
0050 
0051     // overloaded for convenience
0052     void setValue(int row, T value) {
0053         setValue(Interval<int>(row, row), value);
0054     }
0055 
0056     T value(int row) const {
0057         for (int c = m_intervals.size() - 1; c >= 0; c--) {
0058             if (m_intervals.at(c).contains(row))
0059                 return m_values.at(c);
0060         }
0061         return T();
0062     }
0063 
0064     void insertRows(int before, int count) {
0065         QVector<Interval<int>> temp_list;
0066         // first: split all intervals that contain 'before'
0067         for (int c = 0; c < m_intervals.size(); c++) {
0068             if (m_intervals.at(c).contains(before)) {
0069                 temp_list = Interval<int>::split(m_intervals.at(c), before);
0070                 m_intervals.replace(c, temp_list.at(0));
0071                 if (temp_list.size() > 1) {
0072                     m_intervals.insert(c, temp_list.at(1));
0073                     m_values.insert(c, m_values.at(c));
0074                     c++;
0075                 }
0076             }
0077         }
0078         // second: translate all intervals that start at 'before' or later
0079         for (int c = 0; c < m_intervals.size(); c++) {
0080             if (m_intervals.at(c).start() >= before)
0081                 m_intervals[c].translate(count);
0082         }
0083     }
0084 
0085     void removeRows(int first, int count) {
0086         QVector<Interval<int>> temp_list;
0087         Interval<int> i(first, first + count - 1);
0088         // first: remove the relevant rows from all intervals
0089         for (int c = 0; c < m_intervals.size(); c++) {
0090             temp_list = Interval<int>::subtract(m_intervals.at(c), i);
0091             if (temp_list.isEmpty()) {
0092                 m_intervals.removeAt(c);
0093                 m_values.removeAt(c--);
0094             } else {
0095                 m_intervals.replace(c, temp_list.at(0));
0096                 if (temp_list.size() > 1) {
0097                     m_intervals.insert(c, temp_list.at(1));
0098                     m_values.insert(c, m_values.at(c));
0099                     c++;
0100                 }
0101             }
0102         }
0103         // second: translate all intervals that start at 'first+count' or later
0104         for (int c = 0; c < m_intervals.size(); c++) {
0105             if (m_intervals.at(c).start() >= first + count)
0106                 m_intervals[c].translate(-count);
0107         }
0108         // third: merge as many intervals as possible
0109         QVector<T> values_copy = m_values;
0110         QVector<Interval<int>> intervals_copy = m_intervals;
0111         m_values.clear();
0112         m_intervals.clear();
0113         for (int c = 0; c < intervals_copy.size(); c++) {
0114             i = intervals_copy.at(c);
0115             T value = values_copy.at(c);
0116             for (int cc = 0; cc < m_intervals.size(); cc++) {
0117                 if (m_intervals.at(cc).touches(i) && m_values.at(cc) == value) {
0118                     m_intervals.replace(cc, Interval<int>::merge(m_intervals.at(cc), i));
0119                     return;
0120                 }
0121             }
0122             // if it could not be merged, just append it
0123             m_intervals.append(i);
0124             m_values.append(value);
0125         }
0126     }
0127 
0128     void clear() {
0129         m_values.clear();
0130         m_intervals.clear();
0131     }
0132 
0133     QVector<Interval<int>> intervals() const {
0134         return m_intervals;
0135     }
0136     QVector<T> values() const {
0137         return m_values;
0138     }
0139 
0140 private:
0141     QVector<T> m_values;
0142     QVector<Interval<int>> m_intervals;
0143 };
0144 
0145 //! A class representing an interval-based attribute (bool version)
0146 template<>
0147 class IntervalAttribute<bool> {
0148 public:
0149     IntervalAttribute<bool>() {
0150     }
0151     IntervalAttribute<bool>(const QVector<Interval<int>>& intervals)
0152         : m_intervals(intervals) {
0153     }
0154 
0155     void setValue(const Interval<int>& i, bool value = true) {
0156         if (value) {
0157             for (const auto& iv : m_intervals)
0158                 if (iv.contains(i))
0159                     return;
0160 
0161             Interval<int>::mergeIntervalIntoList(&m_intervals, i);
0162         } else { // unset
0163             Interval<int>::subtractIntervalFromList(&m_intervals, i);
0164         }
0165     }
0166 
0167     void setValue(int row, bool value) {
0168         setValue(Interval<int>(row, row), value);
0169     }
0170 
0171     bool isSet(int row) const {
0172         for (const auto& iv : m_intervals)
0173             if (iv.contains(row))
0174                 return true;
0175         return false;
0176     }
0177 
0178     bool isSet(const Interval<int>& i) const {
0179         for (const auto& iv : m_intervals)
0180             if (iv.contains(i))
0181                 return true;
0182         return false;
0183     }
0184 
0185     void insertRows(int before, int count) {
0186         QVector<Interval<int>> temp_list;
0187         int c;
0188         // first: split all intervals that contain 'before'
0189         for (c = 0; c < m_intervals.size(); c++) {
0190             if (m_intervals.at(c).contains(before)) {
0191                 temp_list = Interval<int>::split(m_intervals.at(c), before);
0192                 m_intervals.replace(c, temp_list.at(0));
0193                 if (temp_list.size() > 1)
0194                     m_intervals.insert(c++, temp_list.at(1));
0195             }
0196         }
0197         // second: translate all intervals that start at 'before' or later
0198         for (c = 0; c < m_intervals.size(); c++) {
0199             if (m_intervals.at(c).start() >= before)
0200                 m_intervals[c].translate(count);
0201         }
0202     }
0203 
0204     void removeRows(int first, int count) {
0205         int c;
0206         // first: remove the relevant rows from all intervals
0207         Interval<int>::subtractIntervalFromList(&m_intervals, Interval<int>(first, first + count - 1));
0208         // second: translate all intervals that start at 'first+count' or later
0209         for (c = 0; c < m_intervals.size(); c++) {
0210             if (m_intervals.at(c).start() >= first + count)
0211                 m_intervals[c].translate(-count);
0212         }
0213         // third: merge as many intervals as possible
0214         for (c = m_intervals.size() - 1; c >= 0; c--) {
0215             Interval<int> iv = m_intervals.takeAt(c);
0216             int size_before = m_intervals.size();
0217             Interval<int>::mergeIntervalIntoList(&m_intervals, iv);
0218             if (size_before == m_intervals.size()) // merge successful
0219                 c--;
0220         }
0221     }
0222 
0223     QVector<Interval<int>> intervals() const {
0224         return m_intervals;
0225     }
0226 
0227     void clear() {
0228         m_intervals.clear();
0229     }
0230 
0231 private:
0232     QVector<Interval<int>> m_intervals;
0233 };
0234 
0235 #endif