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 |
