Mercurial > hg > svgui
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 |