comparison layer/SliceLayer.cpp @ 1238:4d0ca1ab4cd0

Some work to make spectrum layers (and slice layers generally) zoomable in the frequency axis. Also fixes a number of view id mixups in SliceLayer which broke offset calculations for the x axis scale.
author Chris Cannam
date Tue, 07 Feb 2017 14:55:19 +0000
parents 1a7c2ca31579
children 9e1559b08f0d
comparison
equal deleted inserted replaced
1237:2cc9e0e5df51 1238:4d0ca1ab4cd0
38 m_binScale(LinearBins), 38 m_binScale(LinearBins),
39 m_normalize(false), 39 m_normalize(false),
40 m_threshold(0.0), 40 m_threshold(0.0),
41 m_initialThreshold(0.0), 41 m_initialThreshold(0.0),
42 m_gain(1.0), 42 m_gain(1.0),
43 m_minbin(0),
44 m_maxbin(0),
43 m_currentf0(0), 45 m_currentf0(0),
44 m_currentf1(0) 46 m_currentf1(0)
45 { 47 {
46 } 48 }
47 49
65 67
66 m_sliceableModel = sliceable; 68 m_sliceableModel = sliceable;
67 69
68 connectSignals(m_sliceableModel); 70 connectSignals(m_sliceableModel);
69 71
72 m_minbin = 0;
73 m_maxbin = m_sliceableModel->getHeight();
74
70 emit modelReplaced(); 75 emit modelReplaced();
76 emit layerParametersChanged();
71 } 77 }
72 78
73 void 79 void
74 SliceLayer::sliceableModelReplaced(const Model *orig, const Model *replacement) 80 SliceLayer::sliceableModelReplaced(const Model *orig, const Model *replacement)
75 { 81 {
105 { 111 {
106 minbin = 0; 112 minbin = 0;
107 maxbin = 0; 113 maxbin = 0;
108 if (!m_sliceableModel) return ""; 114 if (!m_sliceableModel) return "";
109 115
110 int xorigin = m_xorigins[v]; 116 minbin = int(round(getBinForX(v, p.x())));
111 int w = v->getPaintWidth() - xorigin - 1; 117 maxbin = int(round(getBinForX(v, p.x() + 1)));
112 118
113 int mh = m_sliceableModel->getHeight(); 119 int mh = m_sliceableModel->getHeight();
114 minbin = getBinForX(p.x() - xorigin, mh, w);
115 maxbin = getBinForX(p.x() - xorigin + 1, mh, w);
116
117 if (minbin >= mh) minbin = mh - 1; 120 if (minbin >= mh) minbin = mh - 1;
118 if (maxbin >= mh) maxbin = mh - 1; 121 if (maxbin >= mh) maxbin = mh - 1;
119 if (minbin < 0) minbin = 0; 122 if (minbin < 0) minbin = 0;
120 if (maxbin < 0) maxbin = 0; 123 if (maxbin < 0) maxbin = 0;
121 124
131 134
132 QString rtrangestr = QString("%1 s").arg((rt1 - rt0).toText().c_str()); 135 QString rtrangestr = QString("%1 s").arg((rt1 - rt0).toText().c_str());
133 136
134 if (includeBinDescription) { 137 if (includeBinDescription) {
135 138
139 int i0 = minbin - m_minbin;
140 int i1 = maxbin - m_minbin;
141
136 float minvalue = 0.0; 142 float minvalue = 0.0;
137 if (minbin < int(m_values.size())) minvalue = m_values[minbin]; 143 if (in_range_for(m_values, i0)) minvalue = m_values[i0];
138 144
139 float maxvalue = minvalue; 145 float maxvalue = minvalue;
140 if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; 146 if (in_range_for(m_values, i1)) maxvalue = m_values[i1];
141 147
142 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); 148 if (minvalue > maxvalue) std::swap(minvalue, maxvalue);
143 149
144 QString binstr; 150 QString binstr;
145 if (maxbin != minbin) { 151 if (maxbin != minbin) {
146 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); 152 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1);
178 return description; 184 return description;
179 } 185 }
180 } 186 }
181 187
182 double 188 double
183 SliceLayer::getXForBin(int bin, int count, double w) const 189 SliceLayer::getXForBin(const LayerGeometryProvider *v, double bin) const
184 { 190 {
185 double x = 0; 191 double x = 0;
192
193 bin -= m_minbin;
194 if (bin < 0) bin = 0;
195
196 double count = m_maxbin - m_minbin;
197 if (count < 0) count = 0;
198
199 int pw = v->getPaintWidth();
200 int origin = m_xorigins[v->getId()];
201 int w = pw - origin;
202 if (w < 1) w = 1;
186 203
187 switch (m_binScale) { 204 switch (m_binScale) {
188 205
189 case LinearBins: 206 case LinearBins:
190 x = (w * bin) / count; 207 x = (w * bin) / count;
196 213
197 case InvertedLogBins: 214 case InvertedLogBins:
198 x = w - (w * log10(count - bin - 1)) / log10(count); 215 x = w - (w * log10(count - bin - 1)) / log10(count);
199 break; 216 break;
200 } 217 }
201 218
202 return x; 219 return x + origin;
203 } 220 }
204 221
205 int 222 double
206 SliceLayer::getBinForX(double x, int count, double w) const 223 SliceLayer::getBinForX(const LayerGeometryProvider *v, double x) const
207 { 224 {
208 int bin = 0; 225 double bin = 0;
209 226
227 double count = m_maxbin - m_minbin;
228 if (count < 0) count = 0;
229
230 int pw = v->getPaintWidth();
231 int origin = m_xorigins[v->getId()];
232
233 int w = pw - origin;
234 if (w < 1) w = 1;
235
236 x = x - origin;
237 if (x < 0) x = 0;
238
210 switch (m_binScale) { 239 switch (m_binScale) {
211 240
212 case LinearBins: 241 case LinearBins:
213 bin = int((x * count) / w + 0.0001); 242 bin = int((x * count) / w + 0.0001);
214 break; 243 break;
220 case InvertedLogBins: 249 case InvertedLogBins:
221 bin = count + 1 - int(pow(10.0, (log10(count) * (w - x)) / double(w)) + 0.0001); 250 bin = count + 1 - int(pow(10.0, (log10(count) * (w - x)) / double(w)) + 0.0001);
222 break; 251 break;
223 } 252 }
224 253
225 return bin; 254 return bin + m_minbin;
226 } 255 }
227 256
228 double 257 double
229 SliceLayer::getYForValue(double value, const LayerGeometryProvider *v, double &norm) const 258 SliceLayer::getYForValue(const LayerGeometryProvider *v, double value, double &norm) const
230 { 259 {
231 norm = 0.0; 260 norm = 0.0;
232 261
233 if (m_yorigins.find(v) == m_yorigins.end()) return 0; 262 if (m_yorigins.find(v->getId()) == m_yorigins.end()) return 0;
234 263
235 value *= m_gain; 264 value *= m_gain;
236 265
237 int yorigin = m_yorigins[v]; 266 int yorigin = m_yorigins[v->getId()];
238 int h = m_heights[v]; 267 int h = m_heights[v->getId()];
239 double thresh = getThresholdDb(); 268 double thresh = getThresholdDb();
240 269
241 double y = 0.0; 270 double y = 0.0;
242 271
243 if (h <= 0) return y; 272 if (h <= 0) return y;
274 303
275 return y; 304 return y;
276 } 305 }
277 306
278 double 307 double
279 SliceLayer::getValueForY(double y, const LayerGeometryProvider *v) const 308 SliceLayer::getValueForY(const LayerGeometryProvider *v, double y) const
280 { 309 {
281 double value = 0.0; 310 double value = 0.0;
282 311
283 if (m_yorigins.find(v) == m_yorigins.end()) return value; 312 if (m_yorigins.find(v->getId()) == m_yorigins.end()) return value;
284 313
285 int yorigin = m_yorigins[v]; 314 int yorigin = m_yorigins[v->getId()];
286 int h = m_heights[v]; 315 int h = m_heights[v->getId()];
287 double thresh = getThresholdDb(); 316 double thresh = getThresholdDb();
288 317
289 if (h <= 0) return value; 318 if (h <= 0) return value;
290 319
291 y = yorigin - y; 320 y = yorigin - y;
339 } 368 }
340 369
341 int xorigin = getVerticalScaleWidth(v, true, paint) + 1; 370 int xorigin = getVerticalScaleWidth(v, true, paint) + 1;
342 int w = v->getPaintWidth() - xorigin - 1; 371 int w = v->getPaintWidth() - xorigin - 1;
343 372
344 m_xorigins[v] = xorigin; // for use in getFeatureDescription 373 m_xorigins[v->getId()] = xorigin; // for use in getFeatureDescription
345 374
346 int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 7; 375 int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 7;
347 int h = yorigin - paint.fontMetrics().height() - 8; 376 int h = yorigin - paint.fontMetrics().height() - 8;
348 377
349 m_yorigins[v] = yorigin; // for getYForValue etc 378 m_yorigins[v->getId()] = yorigin; // for getYForValue etc
350 m_heights[v] = h; 379 m_heights[v->getId()] = h;
351 380
352 if (h <= 0) return; 381 if (h <= 0) return;
353 382
354 QPainterPath path; 383 QPainterPath path;
355 384
356 int mh = m_sliceableModel->getHeight(); 385 int mh = m_sliceableModel->getHeight();
357 386 int bin0 = 0;
387
388 if (m_maxbin > m_minbin) {
389 mh = m_maxbin - m_minbin;
390 bin0 = m_minbin;
391 }
392
358 int divisor = 0; 393 int divisor = 0;
359 394
360 m_values.clear(); 395 m_values.clear();
361 for (int bin = 0; bin < mh; ++bin) { 396 for (int bin = 0; bin < mh; ++bin) {
362 m_values.push_back(0.0); 397 m_values.push_back(0.0);
386 getBiasCurve(curve); 421 getBiasCurve(curve);
387 int cs = int(curve.size()); 422 int cs = int(curve.size());
388 423
389 for (int col = col0; col <= col1; ++col) { 424 for (int col = col0; col <= col1; ++col) {
390 for (int bin = 0; bin < mh; ++bin) { 425 for (int bin = 0; bin < mh; ++bin) {
391 float value = m_sliceableModel->getValueAt(col, bin); 426 float value = m_sliceableModel->getValueAt(col, bin0 + bin);
392 if (bin < cs) value *= curve[bin]; 427 if (bin < cs) value *= curve[bin];
393 if (m_samplingMode == SamplePeak) { 428 if (m_samplingMode == SamplePeak) {
394 if (value > m_values[bin]) m_values[bin] = value; 429 if (value > m_values[bin]) m_values[bin] = value;
395 } else { 430 } else {
396 m_values[bin] += value; 431 m_values[bin] += value;
410 for (int bin = 0; bin < mh; ++bin) { 445 for (int bin = 0; bin < mh; ++bin) {
411 m_values[bin] /= max; 446 m_values[bin] /= max;
412 } 447 }
413 } 448 }
414 449
415 double nx = xorigin; 450 double nx = getXForBin(v, bin0);
416 451
417 ColourMapper mapper(m_colourMap, 0, 1); 452 ColourMapper mapper(m_colourMap, 0, 1);
418 453
419 for (int bin = 0; bin < mh; ++bin) { 454 for (int bin = 0; bin < mh; ++bin) {
420 455
421 double x = nx; 456 double x = nx;
422 nx = xorigin + getXForBin(bin + 1, mh, w); 457 nx = getXForBin(v, bin + bin0 + 1);
423 458
424 double value = m_values[bin]; 459 double value = m_values[bin];
425 double norm = 0.0; 460 double norm = 0.0;
426 double y = getYForValue(value, v, norm); 461 double y = getYForValue(v, value, norm);
427 462
428 if (m_plotStyle == PlotLines) { 463 if (m_plotStyle == PlotLines) {
429 464
430 if (bin == 0) { 465 if (bin == 0) {
431 path.moveTo((x + nx) / 2, y); 466 path.moveTo((x + nx) / 2, y);
459 494
460 if (m_plotStyle != PlotFilledBlocks) { 495 if (m_plotStyle != PlotFilledBlocks) {
461 paint.drawPath(path); 496 paint.drawPath(path);
462 } 497 }
463 paint.restore(); 498 paint.restore();
464 /*
465 QPoint discard;
466
467 if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount() &&
468 v->shouldIlluminateLocalFeatures(this, discard)) {
469
470 int sampleRate = m_sliceableModel->getSampleRate();
471
472 QString startText = QString("%1 / %2")
473 .arg(QString::fromStdString
474 (RealTime::frame2RealTime
475 (f0, sampleRate).toText(true)))
476 .arg(f0);
477
478 QString endText = QString(" %1 / %2")
479 .arg(QString::fromStdString
480 (RealTime::frame2RealTime
481 (f1, sampleRate).toText(true)))
482 .arg(f1);
483
484 QString durationText = QString("(%1 / %2) ")
485 .arg(QString::fromStdString
486 (RealTime::frame2RealTime
487 (f1 - f0 + 1, sampleRate).toText(true)))
488 .arg(f1 - f0 + 1);
489
490 v->drawVisibleText
491 (paint, xorigin + 5,
492 paint.fontMetrics().ascent() + 5,
493 startText, PaintAssistant::OutlinedText);
494
495 v->drawVisibleText
496 (paint, xorigin + 5,
497 paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10,
498 endText, PaintAssistant::OutlinedText);
499
500 v->drawVisibleText
501 (paint, xorigin + 5,
502 paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15,
503 durationText, PaintAssistant::OutlinedText);
504 }
505 */
506 } 499 }
507 500
508 int 501 int
509 SliceLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const 502 SliceLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const
510 { 503 {
504 int width;
511 if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) { 505 if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) {
512 return std::max(paint.fontMetrics().width("0.0") + 13, 506 width = std::max(paint.fontMetrics().width("0.0") + 13,
513 paint.fontMetrics().width("x10-10")); 507 paint.fontMetrics().width("x10-10"));
514 } else { 508 } else {
515 return std::max(paint.fontMetrics().width(tr("0dB")), 509 width = std::max(paint.fontMetrics().width(tr("0dB")),
516 paint.fontMetrics().width(tr("-Inf"))) + 13; 510 paint.fontMetrics().width(tr("-Inf"))) + 13;
517 } 511 }
512 return width;
518 } 513 }
519 514
520 void 515 void
521 SliceLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const 516 SliceLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const
522 { 517 {
628 623
629 *min = -50; 624 *min = -50;
630 *max = 50; 625 *max = 50;
631 *deflt = 0; 626 *deflt = 0;
632 627
633 cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl; 628 // cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl;
634 629
635 val = int(lrint(log10(m_gain) * 20.0)); 630 val = int(lrint(log10(m_gain) * 20.0));
636 if (val < *min) val = *min; 631 if (val < *min) val = *min;
637 if (val > *max) val = *max; 632 if (val > *max) val = *max;
638 633
895 "samplingMode=\"%3\" " 890 "samplingMode=\"%3\" "
896 "plotStyle=\"%4\" " 891 "plotStyle=\"%4\" "
897 "binScale=\"%5\" " 892 "binScale=\"%5\" "
898 "gain=\"%6\" " 893 "gain=\"%6\" "
899 "threshold=\"%7\" " 894 "threshold=\"%7\" "
900 "normalize=\"%8\"") 895 "normalize=\"%8\" %9")
901 .arg(m_colourMap) 896 .arg(m_colourMap)
902 .arg(m_energyScale) 897 .arg(m_energyScale)
903 .arg(m_samplingMode) 898 .arg(m_samplingMode)
904 .arg(m_plotStyle) 899 .arg(m_plotStyle)
905 .arg(m_binScale) 900 .arg(m_binScale)
906 .arg(m_gain) 901 .arg(m_gain)
907 .arg(m_threshold) 902 .arg(m_threshold)
908 .arg(m_normalize ? "true" : "false"); 903 .arg(m_normalize ? "true" : "false")
904 .arg(QString("minbin=\"%1\" "
905 "maxbin=\"%2\"")
906 .arg(m_minbin)
907 .arg(m_maxbin));
909 908
910 SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s); 909 SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s);
911 } 910 }
912 911
913 void 912 void
942 float threshold = attributes.value("threshold").toFloat(&ok); 941 float threshold = attributes.value("threshold").toFloat(&ok);
943 if (ok) setThreshold(threshold); 942 if (ok) setThreshold(threshold);
944 943
945 bool normalize = (attributes.value("normalize").trimmed() == "true"); 944 bool normalize = (attributes.value("normalize").trimmed() == "true");
946 setNormalize(normalize); 945 setNormalize(normalize);
946
947 bool alsoOk = false;
948
949 float min = attributes.value("minbin").toFloat(&ok);
950 float max = attributes.value("maxbin").toFloat(&alsoOk);
951 if (ok && alsoOk) setDisplayExtents(min, max);
947 } 952 }
948 953
949 bool 954 bool
950 SliceLayer::getValueExtents(double &, double &, bool &, QString &) const 955 SliceLayer::getValueExtents(double &min, double &max, bool &logarithmic,
951 { 956 QString &unit) const
952 return false; 957 {
953 } 958 if (!m_sliceableModel) return false;
954 959
960 min = 0;
961 max = double(m_sliceableModel->getHeight());
962
963 logarithmic = (m_binScale == BinScale::LogBins);
964 unit = "";
965
966 return true;
967 }
968
969 bool
970 SliceLayer::getDisplayExtents(double &min, double &max) const
971 {
972 if (!m_sliceableModel) return false;
973
974 double hmax = double(m_sliceableModel->getHeight());
975
976 min = m_minbin;
977 max = m_maxbin;
978 if (max <= min) {
979 min = 0;
980 max = hmax;
981 }
982 if (min < 0) min = 0;
983 if (max > hmax) max = hmax;
984
985 return true;
986 }
987
988 bool
989 SliceLayer::setDisplayExtents(double min, double max)
990 {
991 if (!m_sliceableModel) return false;
992
993 m_minbin = int(lrint(min));
994 m_maxbin = int(lrint(max));
995
996 emit layerParametersChanged();
997 return true;
998 }
999
1000 int
1001 SliceLayer::getVerticalZoomSteps(int &defaultStep) const
1002 {
1003 if (!m_sliceableModel) return 0;
1004
1005 defaultStep = 0;
1006 int h = m_sliceableModel->getHeight();
1007 return h;
1008 }
1009
1010 int
1011 SliceLayer::getCurrentVerticalZoomStep() const
1012 {
1013 if (!m_sliceableModel) return 0;
1014
1015 double min, max;
1016 getDisplayExtents(min, max);
1017 return m_sliceableModel->getHeight() - int(lrint(max - min));
1018 }
1019
1020 void
1021 SliceLayer::setVerticalZoomStep(int step)
1022 {
1023 if (!m_sliceableModel) return;
1024
1025 // SVDEBUG << "SliceLayer::setVerticalZoomStep(" <<step <<"): before: minbin = " << m_minbin << ", maxbin = " << m_maxbin << endl;
1026
1027 int dist = m_sliceableModel->getHeight() - step;
1028 if (dist < 1) dist = 1;
1029 double centre = m_minbin + (m_maxbin - m_minbin) / 2.0;
1030 m_minbin = int(lrint(centre - dist/2.0));
1031 if (m_minbin < 0) m_minbin = 0;
1032 m_maxbin = m_minbin + dist;
1033 if (m_maxbin > m_sliceableModel->getHeight()) m_maxbin = m_sliceableModel->getHeight();
1034
1035 // SVDEBUG << "SliceLayer::setVerticalZoomStep(" <<step <<"): after: minbin = " << m_minbin << ", maxbin = " << m_maxbin << endl;
1036
1037 emit layerParametersChanged();
1038 }
1039
1040 RangeMapper *
1041 SliceLayer::getNewVerticalZoomRangeMapper() const
1042 {
1043 if (!m_sliceableModel) return 0;
1044
1045 return new LinearRangeMapper(0, m_sliceableModel->getHeight(),
1046 0, m_sliceableModel->getHeight(), "");
1047 }