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