comparison layer/TimeValueLayer.cpp @ 553:97e60a895211

* Add "plot derivatives" option to time value layer (scale is not always right)
author Chris Cannam
date Thu, 28 Jan 2010 16:46:04 +0000
parents 2e8194a30f40
children ffeafe09c8d9
comparison
equal deleted inserted replaced
552:2e8194a30f40 553:97e60a895211
53 m_editingCommand(0), 53 m_editingCommand(0),
54 m_colourMap(0), 54 m_colourMap(0),
55 m_plotStyle(PlotConnectedPoints), 55 m_plotStyle(PlotConnectedPoints),
56 m_verticalScale(AutoAlignScale), 56 m_verticalScale(AutoAlignScale),
57 m_drawSegmentDivisions(true), 57 m_drawSegmentDivisions(true),
58 m_derivative(false),
58 m_scaleMinimum(0), 59 m_scaleMinimum(0),
59 m_scaleMaximum(0) 60 m_scaleMaximum(0)
60 { 61 {
61 62
62 } 63 }
92 PropertyList list = SingleColourLayer::getProperties(); 93 PropertyList list = SingleColourLayer::getProperties();
93 list.push_back("Plot Type"); 94 list.push_back("Plot Type");
94 list.push_back("Vertical Scale"); 95 list.push_back("Vertical Scale");
95 list.push_back("Scale Units"); 96 list.push_back("Scale Units");
96 list.push_back("Draw Segment Division Lines"); 97 list.push_back("Draw Segment Division Lines");
98 list.push_back("Show Derivative");
97 return list; 99 return list;
98 } 100 }
99 101
100 QString 102 QString
101 TimeValueLayer::getPropertyLabel(const PropertyName &name) const 103 TimeValueLayer::getPropertyLabel(const PropertyName &name) const
102 { 104 {
103 if (name == "Plot Type") return tr("Plot Type"); 105 if (name == "Plot Type") return tr("Plot Type");
104 if (name == "Vertical Scale") return tr("Vertical Scale"); 106 if (name == "Vertical Scale") return tr("Vertical Scale");
105 if (name == "Scale Units") return tr("Scale Units"); 107 if (name == "Scale Units") return tr("Scale Units");
106 if (name == "Draw Segment Division Lines") return tr("Draw Segment Division Lines"); 108 if (name == "Draw Segment Division Lines") return tr("Draw Segment Division Lines");
109 if (name == "Show Derivative") return tr("Show Derivative");
107 return SingleColourLayer::getPropertyLabel(name); 110 return SingleColourLayer::getPropertyLabel(name);
108 } 111 }
109 112
110 QString 113 QString
111 TimeValueLayer::getPropertyIconName(const PropertyName &name) const 114 TimeValueLayer::getPropertyIconName(const PropertyName &name) const
112 { 115 {
113 if (name == "Draw Segment Division Lines") return "lines"; 116 if (name == "Draw Segment Division Lines") return "lines";
117 if (name == "Show Derivative") return "derivative";
114 return ""; 118 return "";
115 } 119 }
116 120
117 Layer::PropertyType 121 Layer::PropertyType
118 TimeValueLayer::getPropertyType(const PropertyName &name) const 122 TimeValueLayer::getPropertyType(const PropertyName &name) const
120 if (name == "Plot Type") return ValueProperty; 124 if (name == "Plot Type") return ValueProperty;
121 if (name == "Vertical Scale") return ValueProperty; 125 if (name == "Vertical Scale") return ValueProperty;
122 if (name == "Scale Units") return UnitsProperty; 126 if (name == "Scale Units") return UnitsProperty;
123 if (name == "Colour" && m_plotStyle == PlotSegmentation) return ValueProperty; 127 if (name == "Colour" && m_plotStyle == PlotSegmentation) return ValueProperty;
124 if (name == "Draw Segment Division Lines") return ToggleProperty; 128 if (name == "Draw Segment Division Lines") return ToggleProperty;
129 if (name == "Show Derivative") return ToggleProperty;
125 return SingleColourLayer::getPropertyType(name); 130 return SingleColourLayer::getPropertyType(name);
126 } 131 }
127 132
128 QString 133 QString
129 TimeValueLayer::getPropertyGroupName(const PropertyName &name) const 134 TimeValueLayer::getPropertyGroupName(const PropertyName &name) const
130 { 135 {
131 if (name == "Vertical Scale" || name == "Scale Units") { 136 if (name == "Vertical Scale" || name == "Scale Units") {
132 return tr("Scale"); 137 return tr("Scale");
133 } 138 }
134 if (name == "Plot Type" || name == "Draw Segment Division Lines") { 139 if (name == "Plot Type" || name == "Draw Segment Division Lines" ||
140 name == "Show Derivative") {
135 return tr("Plot Type"); 141 return tr("Plot Type");
136 } 142 }
137 return SingleColourLayer::getPropertyGroupName(name); 143 return SingleColourLayer::getPropertyGroupName(name);
138 } 144 }
139 145
179 185
180 if (min) *min = 0; 186 if (min) *min = 0;
181 if (max) *max = 0; 187 if (max) *max = 0;
182 if (deflt) *deflt = 1; 188 if (deflt) *deflt = 1;
183 val = (m_drawSegmentDivisions ? 1.0 : 0.0); 189 val = (m_drawSegmentDivisions ? 1.0 : 0.0);
190
191 } else if (name == "Show Derivative") {
192
193 if (min) *min = 0;
194 if (max) *max = 0;
195 if (deflt) *deflt = 0;
196 val = (m_derivative ? 1.0 : 0.0);
184 197
185 } else { 198 } else {
186 199
187 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt); 200 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
188 } 201 }
233 (UnitDatabase::getInstance()->getUnitById(value)); 246 (UnitDatabase::getInstance()->getUnitById(value));
234 emit modelChanged(); 247 emit modelChanged();
235 } 248 }
236 } else if (name == "Draw Segment Division Lines") { 249 } else if (name == "Draw Segment Division Lines") {
237 setDrawSegmentDivisions(value > 0.5); 250 setDrawSegmentDivisions(value > 0.5);
251 } else if (name == "Show Derivative") {
252 setShowDerivative(value > 0.5);
238 } else { 253 } else {
239 SingleColourLayer::setProperty(name, value); 254 SingleColourLayer::setProperty(name, value);
240 } 255 }
241 } 256 }
242 257
275 if (m_drawSegmentDivisions == draw) return; 290 if (m_drawSegmentDivisions == draw) return;
276 m_drawSegmentDivisions = draw; 291 m_drawSegmentDivisions = draw;
277 emit layerParametersChanged(); 292 emit layerParametersChanged();
278 } 293 }
279 294
295 void
296 TimeValueLayer::setShowDerivative(bool show)
297 {
298 if (m_derivative == show) return;
299 m_derivative = show;
300 emit layerParametersChanged();
301 }
302
280 bool 303 bool
281 TimeValueLayer::isLayerScrollable(const View *v) const 304 TimeValueLayer::isLayerScrollable(const View *v) const
282 { 305 {
283 // We don't illuminate sections in the line or curve modes, so 306 // We don't illuminate sections in the line or curve modes, so
284 // they're always scrollable 307 // they're always scrollable
297 if (!m_model) return false; 320 if (!m_model) return false;
298 min = m_model->getValueMinimum(); 321 min = m_model->getValueMinimum();
299 max = m_model->getValueMaximum(); 322 max = m_model->getValueMaximum();
300 logarithmic = (m_verticalScale == LogScale); 323 logarithmic = (m_verticalScale == LogScale);
301 unit = m_model->getScaleUnits(); 324 unit = m_model->getScaleUnits();
325 if (m_derivative) {
326 max = std::max(fabsf(min), fabsf(max));
327 min = -max;
328 }
302 return true; 329 return true;
303 } 330 }
304 331
305 bool 332 bool
306 TimeValueLayer::getDisplayExtents(float &min, float &max) const 333 TimeValueLayer::getDisplayExtents(float &min, float &max) const
308 if (!m_model || shouldAutoAlign()) return false; 335 if (!m_model || shouldAutoAlign()) return false;
309 336
310 if (m_scaleMinimum == m_scaleMaximum) { 337 if (m_scaleMinimum == m_scaleMaximum) {
311 min = m_model->getValueMinimum(); 338 min = m_model->getValueMinimum();
312 max = m_model->getValueMaximum(); 339 max = m_model->getValueMaximum();
313 return true; 340 } else {
314 } 341 min = m_scaleMinimum;
315 342 max = m_scaleMaximum;
316 min = m_scaleMinimum; 343 }
317 max = m_scaleMaximum; 344
345 if (m_derivative) {
346 max = std::max(fabsf(min), fabsf(max));
347 min = -max;
348 }
318 349
319 #ifdef DEBUG_TIME_VALUE_LAYER 350 #ifdef DEBUG_TIME_VALUE_LAYER
320 std::cerr << "TimeValueLayer::getDisplayExtents: min = " << min << ", max = " << max << std::endl; 351 std::cerr << "TimeValueLayer::getDisplayExtents: min = " << min << ", max = " << max << std::endl;
321 #endif 352 #endif
322 353
370 getDisplayExtents(dmin, dmax); 401 getDisplayExtents(dmin, dmax);
371 402
372 int nr = mapper->getPositionForValue(dmax - dmin); 403 int nr = mapper->getPositionForValue(dmax - dmin);
373 404
374 #ifdef DEBUG_TIME_VALUE_LAYER 405 #ifdef DEBUG_TIME_VALUE_LAYER
375 int n0 = mapper->getPositionForValue(dmax); 406 std::cerr << "TimeValueLayer::getCurrentVerticalZoomStep: dmin = " << dmin << ", dmax = " << dmax << ", nr = " << nr << std::endl;
376 int n1 = mapper->getPositionForValue(dmin);
377 int nr = n1 - n0;
378 if (nr < 0) nr = -nr;
379
380 std::cerr << "TimeValueLayer::getCurrentVerticalZoomStep: dmin = " << dmin << ", dmax = " << dmax << ", n0 = " << n0 << ", n1 = " << n1 << ", nr = " << nr << std::endl;
381 #endif 407 #endif
382 408
383 delete mapper; 409 delete mapper;
384 410
385 return 100 - nr; 411 return 100 - nr;
829 // Profiler profiler("TimeValueLayer::paint", true); 855 // Profiler profiler("TimeValueLayer::paint", true);
830 856
831 int x0 = rect.left(), x1 = rect.right(); 857 int x0 = rect.left(), x1 = rect.right();
832 long frame0 = v->getFrameForX(x0); 858 long frame0 = v->getFrameForX(x0);
833 long frame1 = v->getFrameForX(x1); 859 long frame1 = v->getFrameForX(x1);
860 if (m_derivative) --frame0;
834 861
835 SparseTimeValueModel::PointList points(m_model->getPoints 862 SparseTimeValueModel::PointList points(m_model->getPoints
836 (frame0, frame1)); 863 (frame0, frame1));
837 if (points.empty()) return; 864 if (points.empty()) return;
838 865
881 } 908 }
882 909
883 for (SparseTimeValueModel::PointList::const_iterator i = points.begin(); 910 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
884 i != points.end(); ++i) { 911 i != points.end(); ++i) {
885 912
913 if (m_derivative && i == points.begin()) continue;
914
886 const SparseTimeValueModel::Point &p(*i); 915 const SparseTimeValueModel::Point &p(*i);
887 916
917 float value = p.value;
918 if (m_derivative) {
919 SparseTimeValueModel::PointList::const_iterator j = i;
920 --j;
921 value -= j->value;
922 }
923
888 int x = v->getXForFrame(p.frame); 924 int x = v->getXForFrame(p.frame);
889 int y = getYForValue(v, p.value); 925 int y = getYForValue(v, value);
890 926
891 if (m_plotStyle != PlotSegmentation) { 927 if (m_plotStyle != PlotSegmentation) {
892 textY = y - paint.fontMetrics().height() 928 textY = y - paint.fontMetrics().height()
893 + paint.fontMetrics().ascent(); 929 + paint.fontMetrics().ascent();
894 if (textY < paint.fontMetrics().ascent() + 1) { 930 if (textY < paint.fontMetrics().ascent() + 1) {
903 SparseTimeValueModel::PointList::const_iterator j = i; 939 SparseTimeValueModel::PointList::const_iterator j = i;
904 ++j; 940 ++j;
905 941
906 if (j != points.end()) { 942 if (j != points.end()) {
907 const SparseTimeValueModel::Point &q(*j); 943 const SparseTimeValueModel::Point &q(*j);
944 float nvalue = q.value;
945 if (m_derivative) nvalue -= p.value;
908 nx = v->getXForFrame(q.frame); 946 nx = v->getXForFrame(q.frame);
909 ny = getYForValue(v, q.value); 947 ny = getYForValue(v, nvalue);
910 haveNext = true; 948 haveNext = true;
911 } 949 }
912 950
913 // std::cout << "frame = " << p.frame << ", x = " << x << ", haveNext = " << haveNext 951 // std::cout << "frame = " << p.frame << ", x = " << x << ", haveNext = " << haveNext
914 // << ", nx = " << nx << std::endl; 952 // << ", nx = " << nx << std::endl;
916 if (w < 1) w = 1; 954 if (w < 1) w = 1;
917 paint.setPen(getBaseQColor()); 955 paint.setPen(getBaseQColor());
918 956
919 if (m_plotStyle == PlotSegmentation) { 957 if (m_plotStyle == PlotSegmentation) {
920 paint.setPen(getForegroundQColor(v)); 958 paint.setPen(getForegroundQColor(v));
921 paint.setBrush(getColourForValue(v, p.value)); 959 paint.setBrush(getColourForValue(v, value));
922 } else if (m_plotStyle == PlotLines || 960 } else if (m_plotStyle == PlotLines ||
923 m_plotStyle == PlotCurve) { 961 m_plotStyle == PlotCurve) {
924 paint.setBrush(Qt::NoBrush); 962 paint.setBrush(Qt::NoBrush);
925 } else { 963 } else {
926 paint.setBrush(brushColour); 964 paint.setBrush(brushColour);
1312 1350
1313 void 1351 void
1314 TimeValueLayer::drawEnd(View *, QMouseEvent *) 1352 TimeValueLayer::drawEnd(View *, QMouseEvent *)
1315 { 1353 {
1316 #ifdef DEBUG_TIME_VALUE_LAYER 1354 #ifdef DEBUG_TIME_VALUE_LAYER
1317 std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; 1355 std::cerr << "TimeValueLayer::drawEnd" << std::endl;
1318 #endif 1356 #endif
1319 if (!m_model || !m_editing) return; 1357 if (!m_model || !m_editing) return;
1320 finish(m_editingCommand); 1358 finish(m_editingCommand);
1321 m_editingCommand = 0; 1359 m_editingCommand = 0;
1322 m_editing = false; 1360 m_editing = false;
1418 1456
1419 void 1457 void
1420 TimeValueLayer::editEnd(View *, QMouseEvent *) 1458 TimeValueLayer::editEnd(View *, QMouseEvent *)
1421 { 1459 {
1422 #ifdef DEBUG_TIME_VALUE_LAYER 1460 #ifdef DEBUG_TIME_VALUE_LAYER
1423 std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; 1461 std::cerr << "TimeValueLayer::editEnd" << std::endl;
1424 #endif 1462 #endif
1425 if (!m_model || !m_editing) return; 1463 if (!m_model || !m_editing) return;
1426 1464
1427 if (m_editingCommand) { 1465 if (m_editingCommand) {
1428 1466
1794 TimeValueLayer::toXml(QTextStream &stream, 1832 TimeValueLayer::toXml(QTextStream &stream,
1795 QString indent, QString extraAttributes) const 1833 QString indent, QString extraAttributes) const
1796 { 1834 {
1797 SingleColourLayer::toXml(stream, indent, 1835 SingleColourLayer::toXml(stream, indent,
1798 extraAttributes + 1836 extraAttributes +
1799 QString(" colourMap=\"%1\" plotStyle=\"%2\" verticalScale=\"%3\" scaleMinimum=\"%4\" scaleMaximum=\"%5\" drawDivisions=\"%6\" ") 1837 QString(" colourMap=\"%1\" plotStyle=\"%2\" verticalScale=\"%3\" scaleMinimum=\"%4\" scaleMaximum=\"%5\" drawDivisions=\"%6\" derivative=\"%7\" ")
1800 .arg(m_colourMap) 1838 .arg(m_colourMap)
1801 .arg(m_plotStyle) 1839 .arg(m_plotStyle)
1802 .arg(m_verticalScale) 1840 .arg(m_verticalScale)
1803 .arg(m_scaleMinimum) 1841 .arg(m_scaleMinimum)
1804 .arg(m_scaleMaximum) 1842 .arg(m_scaleMaximum)
1805 .arg(m_drawSegmentDivisions ? "true" : "false")); 1843 .arg(m_drawSegmentDivisions ? "true" : "false")
1844 .arg(m_derivative ? "true" : "false"));
1806 } 1845 }
1807 1846
1808 void 1847 void
1809 TimeValueLayer::setProperties(const QXmlAttributes &attributes) 1848 TimeValueLayer::setProperties(const QXmlAttributes &attributes)
1810 { 1849 {
1824 if (ok) setVerticalScale(scale); 1863 if (ok) setVerticalScale(scale);
1825 1864
1826 bool draw = (attributes.value("drawDivisions").trimmed() == "true"); 1865 bool draw = (attributes.value("drawDivisions").trimmed() == "true");
1827 setDrawSegmentDivisions(draw); 1866 setDrawSegmentDivisions(draw);
1828 1867
1868 bool derivative = (attributes.value("derivative").trimmed() == "true");
1869 setShowDerivative(derivative);
1870
1829 float min = attributes.value("scaleMinimum").toFloat(&ok); 1871 float min = attributes.value("scaleMinimum").toFloat(&ok);
1830 float max = attributes.value("scaleMaximum").toFloat(&alsoOk); 1872 float max = attributes.value("scaleMaximum").toFloat(&alsoOk);
1831 #ifdef DEBUG_TIME_VALUE_LAYER 1873 #ifdef DEBUG_TIME_VALUE_LAYER
1832 std::cerr << "from properties: min = " << min << ", max = " << max << std::endl; 1874 std::cerr << "from properties: min = " << min << ", max = " << max << std::endl;
1833 #endif 1875 #endif