Mercurial > hg > svcore
comparison data/model/EditableDenseThreeDimensionalModel.cpp @ 534:6038cb6fcd30
* Some simple compression for dense 3d models that actually represent
multirate data such as wavelet transform outputs. If a column has
many elements at top or bottom that are the same as those of an
earlier column, store a reference to that one and truncate the
duplicate values.
author | Chris Cannam |
---|---|
date | Fri, 23 Jan 2009 13:31:51 +0000 |
parents | 55ad231c9db7 |
children | 3ccf48fb81d6 |
comparison
equal
deleted
inserted
replaced
533:55ad231c9db7 | 534:6038cb6fcd30 |
---|---|
21 #include <QStringList> | 21 #include <QStringList> |
22 | 22 |
23 #include <iostream> | 23 #include <iostream> |
24 | 24 |
25 #include <cmath> | 25 #include <cmath> |
26 #include <cassert> | |
26 | 27 |
27 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(size_t sampleRate, | 28 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(size_t sampleRate, |
28 size_t resolution, | 29 size_t resolution, |
29 size_t yBinCount, | 30 size_t yBinCount, |
30 bool notifyOnAdd) : | 31 bool notifyOnAdd) : |
66 } | 67 } |
67 | 68 |
68 Model * | 69 Model * |
69 EditableDenseThreeDimensionalModel::clone() const | 70 EditableDenseThreeDimensionalModel::clone() const |
70 { | 71 { |
72 QMutexLocker locker(&m_mutex); | |
73 | |
71 EditableDenseThreeDimensionalModel *model = | 74 EditableDenseThreeDimensionalModel *model = |
72 new EditableDenseThreeDimensionalModel | 75 new EditableDenseThreeDimensionalModel |
73 (m_sampleRate, m_resolution, m_yBinCount); | 76 (m_sampleRate, m_resolution, m_yBinCount); |
74 | 77 |
75 model->m_minimum = m_minimum; | 78 model->m_minimum = m_minimum; |
139 | 142 |
140 EditableDenseThreeDimensionalModel::Column | 143 EditableDenseThreeDimensionalModel::Column |
141 EditableDenseThreeDimensionalModel::getColumn(size_t index) const | 144 EditableDenseThreeDimensionalModel::getColumn(size_t index) const |
142 { | 145 { |
143 QMutexLocker locker(&m_mutex); | 146 QMutexLocker locker(&m_mutex); |
144 | 147 if (index >= m_data.size()) return Column(); |
145 Column result; | 148 return expandAndRetrieve(index); |
146 | |
147 if (index < m_data.size()) { | |
148 result = m_data.at(index); | |
149 } else { | |
150 result.clear(); | |
151 } | |
152 | |
153 while (result.size() < m_yBinCount) result.push_back(m_minimum); | |
154 return result; | |
155 } | 149 } |
156 | 150 |
157 float | 151 float |
158 EditableDenseThreeDimensionalModel::getValueAt(size_t index, size_t n) const | 152 EditableDenseThreeDimensionalModel::getValueAt(size_t index, size_t n) const |
159 { | 153 { |
160 QMutexLocker locker(&m_mutex); | 154 Column c = getColumn(index); |
161 | 155 if (n < c.size()) return s.at(n); |
162 if (index < m_data.size()) { | |
163 const Column &s = m_data.at(index); | |
164 // std::cerr << "index " << index << ", n " << n << ", res " << m_resolution << ", size " << s.size() | |
165 // << std::endl; | |
166 if (n < s.size()) return s.at(n); | |
167 } | |
168 | |
169 return m_minimum; | 156 return m_minimum; |
157 } | |
158 | |
159 static int given = 0, stored = 0; | |
160 | |
161 void | |
162 EditableDenseThreeDimensionalModel::truncateAndStore(size_t index, | |
163 const Column &values) | |
164 { | |
165 assert(index < m_data.size()); | |
166 | |
167 //std::cout << "truncateAndStore(" << index << ", " << values.size() << ")" << std::endl; | |
168 | |
169 m_trunc[index] = 0; | |
170 if (index == 0 || values.size() != m_yBinCount) { | |
171 given += values.size(); | |
172 stored += values.size(); | |
173 m_data[index] = values; | |
174 return; | |
175 } | |
176 | |
177 static int maxdist = 120; | |
178 | |
179 bool known = false; | |
180 bool top = false; | |
181 | |
182 int tdist = 1; | |
183 int ptrunc = m_trunc[index-1]; | |
184 if (ptrunc < 0) { | |
185 top = false; | |
186 known = true; | |
187 tdist = -ptrunc + 1; | |
188 } else if (ptrunc > 0) { | |
189 top = true; | |
190 known = true; | |
191 tdist = ptrunc + 1; | |
192 } | |
193 | |
194 Column p = expandAndRetrieve(index - tdist); | |
195 int h = m_yBinCount; | |
196 | |
197 if (p.size() == h && tdist <= maxdist) { | |
198 | |
199 int bcount = 0, tcount = 0; | |
200 if (!known || !top) { | |
201 for (int i = 0; i < h; ++i) { | |
202 if (values.at(i) == p.at(i)) ++bcount; | |
203 else break; | |
204 } | |
205 } | |
206 if (!known || top) { | |
207 for (int i = h; i > 0; --i) { | |
208 if (values.at(i-1) == p.at(i-1)) ++tcount; | |
209 else break; | |
210 } | |
211 } | |
212 if (!known) top = (tcount > bcount); | |
213 | |
214 int limit = h / 4; | |
215 if ((top ? tcount : bcount) > limit) { | |
216 | |
217 if (!top) { | |
218 Column tcol(h - bcount); | |
219 given += values.size(); | |
220 stored += h - bcount; | |
221 for (int i = bcount; i < h; ++i) { | |
222 tcol[i - bcount] = values.at(i); | |
223 } | |
224 m_data[index] = tcol; | |
225 m_trunc[index] = -tdist; | |
226 //std::cout << "bottom " << bcount << " as col at " << -tdist << std::endl; | |
227 return; | |
228 } else { | |
229 Column tcol(h - tcount); | |
230 given += values.size(); | |
231 stored += h - tcount; | |
232 for (int i = 0; i < h - tcount; ++i) { | |
233 tcol[i] = values.at(i); | |
234 } | |
235 m_data[index] = tcol; | |
236 m_trunc[index] = tdist; | |
237 //std::cout << "top " << tcount << " as col at " << -tdist << std::endl; | |
238 return; | |
239 } | |
240 } | |
241 } | |
242 | |
243 given += values.size(); | |
244 stored += values.size(); | |
245 | |
246 // std::cout << "given: " << given << ", stored: " << stored << " (" | |
247 // << ((float(stored) / float(given)) * 100.f) << "%)" << std::endl; | |
248 | |
249 m_data[index] = values; | |
250 return; | |
251 } | |
252 | |
253 EditableDenseThreeDimensionalModel::Column | |
254 EditableDenseThreeDimensionalModel::expandAndRetrieve(size_t index) const | |
255 { | |
256 assert(index < m_data.size()); | |
257 Column c = m_data.at(index); | |
258 if (index == 0) { | |
259 return c; | |
260 } | |
261 int trunc = (int)m_trunc[index]; | |
262 if (trunc == 0) { | |
263 return c; | |
264 } | |
265 bool top = true; | |
266 int tdist = trunc; | |
267 if (trunc < 0) { top = false; tdist = -trunc; } | |
268 Column p = expandAndRetrieve(index - tdist); | |
269 if (p.size() != m_yBinCount) { | |
270 std::cerr << "WARNING: EditableDenseThreeDimensionalModel::expandAndRetrieve: Trying to expand from incorrectly sized column" << std::endl; | |
271 } | |
272 if (top) { | |
273 for (int i = c.size(); i < p.size(); ++i) { | |
274 c.push_back(p.at(i)); | |
275 } | |
276 } else { | |
277 for (int i = int(p.size()) - int(c.size()); i >= 0; --i) { | |
278 c.push_front(p.at(i)); | |
279 } | |
280 } | |
281 return c; | |
170 } | 282 } |
171 | 283 |
172 void | 284 void |
173 EditableDenseThreeDimensionalModel::setColumn(size_t index, | 285 EditableDenseThreeDimensionalModel::setColumn(size_t index, |
174 const Column &values) | 286 const Column &values) |
175 { | 287 { |
176 QMutexLocker locker(&m_mutex); | 288 QMutexLocker locker(&m_mutex); |
177 | 289 |
178 while (index >= m_data.size()) { | 290 while (index >= m_data.size()) { |
179 m_data.push_back(Column()); | 291 m_data.push_back(Column()); |
292 m_trunc.push_back(0); | |
180 } | 293 } |
181 | 294 |
182 bool allChange = false; | 295 bool allChange = false; |
183 | 296 |
184 if (values.size() > m_yBinCount) m_yBinCount = values.size(); | 297 // if (values.size() > m_yBinCount) m_yBinCount = values.size(); |
185 | 298 |
186 for (size_t i = 0; i < values.size(); ++i) { | 299 for (size_t i = 0; i < values.size(); ++i) { |
187 float value = values[i]; | 300 float value = values[i]; |
188 if (std::isnan(value) || std::isinf(value)) { | 301 if (std::isnan(value) || std::isinf(value)) { |
189 continue; | 302 continue; |
197 allChange = true; | 310 allChange = true; |
198 } | 311 } |
199 m_haveExtents = true; | 312 m_haveExtents = true; |
200 } | 313 } |
201 | 314 |
202 m_data[index] = values; | 315 truncateAndStore(index, values); |
316 | |
317 assert(values == expandAndRetrieve(index)); | |
203 | 318 |
204 long windowStart = index; | 319 long windowStart = index; |
205 windowStart *= m_resolution; | 320 windowStart *= m_resolution; |
206 | 321 |
207 if (m_notifyOnAdd) { | 322 if (m_notifyOnAdd) { |
251 } | 366 } |
252 | 367 |
253 bool | 368 bool |
254 EditableDenseThreeDimensionalModel::shouldUseLogValueScale() const | 369 EditableDenseThreeDimensionalModel::shouldUseLogValueScale() const |
255 { | 370 { |
371 QMutexLocker locker(&m_mutex); | |
372 | |
256 QVector<float> sample; | 373 QVector<float> sample; |
257 QVector<int> n; | 374 QVector<int> n; |
258 | 375 |
259 for (int i = 0; i < 10; ++i) { | 376 for (int i = 0; i < 10; ++i) { |
260 size_t index = i * 10; | 377 size_t index = i * 10; |
308 } | 425 } |
309 | 426 |
310 QString | 427 QString |
311 EditableDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter) const | 428 EditableDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter) const |
312 { | 429 { |
430 QMutexLocker locker(&m_mutex); | |
313 QString s; | 431 QString s; |
314 for (size_t i = 0; i < m_data.size(); ++i) { | 432 for (size_t i = 0; i < m_data.size(); ++i) { |
315 QStringList list; | 433 QStringList list; |
316 for (size_t j = 0; j < m_data.at(i).size(); ++j) { | 434 for (size_t j = 0; j < m_data.at(i).size(); ++j) { |
317 list << QString("%1").arg(m_data.at(i).at(j)); | 435 list << QString("%1").arg(m_data.at(i).at(j)); |
324 void | 442 void |
325 EditableDenseThreeDimensionalModel::toXml(QTextStream &out, | 443 EditableDenseThreeDimensionalModel::toXml(QTextStream &out, |
326 QString indent, | 444 QString indent, |
327 QString extraAttributes) const | 445 QString extraAttributes) const |
328 { | 446 { |
447 QMutexLocker locker(&m_mutex); | |
448 | |
329 // For historical reasons we read and write "resolution" as "windowSize" | 449 // For historical reasons we read and write "resolution" as "windowSize" |
330 | 450 |
331 std::cerr << "EditableDenseThreeDimensionalModel::toXml" << std::endl; | 451 std::cerr << "EditableDenseThreeDimensionalModel::toXml" << std::endl; |
332 | 452 |
333 Model::toXml | 453 Model::toXml |