Mercurial > hg > svgui
comparison layer/TimeInstantLayer.cpp @ 28:202d1dca67d2
* Rationalise the local feature identification API in Layer subclasses
* Add segmentation mode to TimeInstantLayer
author | Chris Cannam |
---|---|
date | Mon, 06 Feb 2006 17:24:52 +0000 |
parents | dcdb21b62dbb |
children | 78515b1e29eb |
comparison
equal
deleted
inserted
replaced
27:38fe0ea9e46e | 28:202d1dca67d2 |
---|---|
25 Layer(w), | 25 Layer(w), |
26 m_model(0), | 26 m_model(0), |
27 m_editing(false), | 27 m_editing(false), |
28 m_editingPoint(0, tr("New Point")), | 28 m_editingPoint(0, tr("New Point")), |
29 m_editingCommand(0), | 29 m_editingCommand(0), |
30 m_colour(QColor(200, 50, 255)) | 30 m_colour(QColor(200, 50, 255)), |
31 m_plotStyle(PlotInstants) | |
31 { | 32 { |
32 m_view->addLayer(this); | 33 m_view->addLayer(this); |
33 } | 34 } |
34 | 35 |
35 void | 36 void |
53 Layer::PropertyList | 54 Layer::PropertyList |
54 TimeInstantLayer::getProperties() const | 55 TimeInstantLayer::getProperties() const |
55 { | 56 { |
56 PropertyList list; | 57 PropertyList list; |
57 list.push_back(tr("Colour")); | 58 list.push_back(tr("Colour")); |
59 list.push_back(tr("Plot Type")); | |
58 return list; | 60 return list; |
59 } | 61 } |
60 | 62 |
61 Layer::PropertyType | 63 Layer::PropertyType |
62 TimeInstantLayer::getPropertyType(const PropertyName &) const | 64 TimeInstantLayer::getPropertyType(const PropertyName &) const |
79 else if (m_colour == Qt::darkRed) deft = 1; | 81 else if (m_colour == Qt::darkRed) deft = 1; |
80 else if (m_colour == Qt::darkBlue) deft = 2; | 82 else if (m_colour == Qt::darkBlue) deft = 2; |
81 else if (m_colour == Qt::darkGreen) deft = 3; | 83 else if (m_colour == Qt::darkGreen) deft = 3; |
82 else if (m_colour == QColor(200, 50, 255)) deft = 4; | 84 else if (m_colour == QColor(200, 50, 255)) deft = 4; |
83 else if (m_colour == QColor(255, 150, 50)) deft = 5; | 85 else if (m_colour == QColor(255, 150, 50)) deft = 5; |
86 | |
87 } else if (name == tr("Plot Type")) { | |
88 | |
89 if (min) *min = 0; | |
90 if (max) *max = 1; | |
91 | |
92 deft = int(m_plotStyle); | |
84 | 93 |
85 } else { | 94 } else { |
86 | 95 |
87 deft = Layer::getPropertyRangeAndValue(name, min, max); | 96 deft = Layer::getPropertyRangeAndValue(name, min, max); |
88 } | 97 } |
102 case 2: return tr("Blue"); | 111 case 2: return tr("Blue"); |
103 case 3: return tr("Green"); | 112 case 3: return tr("Green"); |
104 case 4: return tr("Purple"); | 113 case 4: return tr("Purple"); |
105 case 5: return tr("Orange"); | 114 case 5: return tr("Orange"); |
106 } | 115 } |
116 } else if (name == tr("Plot Type")) { | |
117 switch (value) { | |
118 default: | |
119 case 0: return tr("Instants"); | |
120 case 1: return tr("Segmentation"); | |
121 } | |
107 } | 122 } |
108 return tr("<unknown>"); | 123 return tr("<unknown>"); |
109 } | 124 } |
110 | 125 |
111 void | 126 void |
119 case 2: setBaseColour(Qt::darkBlue); break; | 134 case 2: setBaseColour(Qt::darkBlue); break; |
120 case 3: setBaseColour(Qt::darkGreen); break; | 135 case 3: setBaseColour(Qt::darkGreen); break; |
121 case 4: setBaseColour(QColor(200, 50, 255)); break; | 136 case 4: setBaseColour(QColor(200, 50, 255)); break; |
122 case 5: setBaseColour(QColor(255, 150, 50)); break; | 137 case 5: setBaseColour(QColor(255, 150, 50)); break; |
123 } | 138 } |
139 } else if (name == tr("Plot Type")) { | |
140 setPlotStyle(PlotStyle(value)); | |
124 } | 141 } |
125 } | 142 } |
126 | 143 |
127 void | 144 void |
128 TimeInstantLayer::setBaseColour(QColor colour) | 145 TimeInstantLayer::setBaseColour(QColor colour) |
130 if (m_colour == colour) return; | 147 if (m_colour == colour) return; |
131 m_colour = colour; | 148 m_colour = colour; |
132 emit layerParametersChanged(); | 149 emit layerParametersChanged(); |
133 } | 150 } |
134 | 151 |
152 void | |
153 TimeInstantLayer::setPlotStyle(PlotStyle style) | |
154 { | |
155 if (m_plotStyle == style) return; | |
156 m_plotStyle = style; | |
157 emit layerParametersChanged(); | |
158 } | |
159 | |
135 bool | 160 bool |
136 TimeInstantLayer::isLayerScrollable() const | 161 TimeInstantLayer::isLayerScrollable() const |
137 { | 162 { |
138 QPoint discard; | 163 QPoint discard; |
139 return !m_view->shouldIlluminateLocalFeatures(this, discard); | 164 return !m_view->shouldIlluminateLocalFeatures(this, discard); |
140 } | 165 } |
141 | 166 |
142 SparseOneDimensionalModel::PointList | 167 SparseOneDimensionalModel::PointList |
143 TimeInstantLayer::getLocalPoints(int x) const | 168 TimeInstantLayer::getLocalPoints(int x) const |
144 { | 169 { |
170 // Return a set of points that all have the same frame number, the | |
171 // nearest to the given x coordinate, and that are within a | |
172 // certain fuzz distance of that x coordinate. | |
173 | |
145 if (!m_model) return SparseOneDimensionalModel::PointList(); | 174 if (!m_model) return SparseOneDimensionalModel::PointList(); |
146 | 175 |
147 long frame = getFrameForX(x); | 176 long frame = getFrameForX(x); |
148 | 177 |
149 SparseOneDimensionalModel::PointList onPoints = | 178 SparseOneDimensionalModel::PointList onPoints = |
168 } else if (nextPoints.begin()->frame - frame < | 197 } else if (nextPoints.begin()->frame - frame < |
169 frame - prevPoints.begin()->frame) { | 198 frame - prevPoints.begin()->frame) { |
170 usePoints = nextPoints; | 199 usePoints = nextPoints; |
171 } | 200 } |
172 | 201 |
202 if (!usePoints.empty()) { | |
203 int fuzz = 2; | |
204 int px = getXForFrame(usePoints.begin()->frame); | |
205 if ((px > x && px - x > fuzz) || | |
206 (px < x && x - px > fuzz + 1)) { | |
207 usePoints.clear(); | |
208 } | |
209 } | |
210 | |
173 return usePoints; | 211 return usePoints; |
174 } | 212 } |
175 | 213 |
176 QString | 214 QString |
177 TimeInstantLayer::getFeatureDescription(QPoint &pos) const | 215 TimeInstantLayer::getFeatureDescription(QPoint &pos) const |
207 | 245 |
208 pos = QPoint(getXForFrame(useFrame), pos.y()); | 246 pos = QPoint(getXForFrame(useFrame), pos.y()); |
209 return text; | 247 return text; |
210 } | 248 } |
211 | 249 |
212 int | 250 bool |
213 TimeInstantLayer::getNearestFeatureFrame(int frame, | 251 TimeInstantLayer::snapToFeatureFrame(int &frame, |
214 size_t &resolution, | 252 size_t &resolution, |
215 bool snapRight) const | 253 SnapType snap) const |
216 { | 254 { |
217 if (!m_model) { | 255 if (!m_model) { |
218 return Layer::getNearestFeatureFrame(frame, resolution, snapRight); | 256 return Layer::snapToFeatureFrame(frame, resolution, snap); |
219 } | 257 } |
220 | 258 |
221 resolution = m_model->getResolution(); | 259 resolution = m_model->getResolution(); |
222 SparseOneDimensionalModel::PointList points(m_model->getPoints(frame, frame)); | 260 SparseOneDimensionalModel::PointList points; |
223 | 261 |
224 int returnFrame = frame; | 262 if (snap == SnapNeighbouring) { |
263 | |
264 points = getLocalPoints(getXForFrame(frame)); | |
265 if (points.empty()) return false; | |
266 frame = points.begin()->frame; | |
267 return true; | |
268 } | |
269 | |
270 points = m_model->getPoints(frame, frame); | |
271 int snapped = frame; | |
272 bool found = false; | |
225 | 273 |
226 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); | 274 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); |
227 i != points.end(); ++i) { | 275 i != points.end(); ++i) { |
228 | 276 |
229 if (snapRight) { | 277 if (snap == SnapRight) { |
230 if (i->frame > frame) { | 278 |
231 returnFrame = i->frame; | 279 if (i->frame >= frame) { |
280 snapped = i->frame; | |
281 found = true; | |
232 break; | 282 break; |
233 } | 283 } |
234 } else { | 284 |
285 } else if (snap == SnapLeft) { | |
286 | |
235 if (i->frame <= frame) { | 287 if (i->frame <= frame) { |
236 returnFrame = i->frame; | 288 snapped = i->frame; |
237 } | 289 found = true; // don't break, as the next may be better |
238 } | 290 } else { |
239 } | 291 break; |
240 | 292 } |
241 return returnFrame; | 293 |
294 } else { // nearest | |
295 | |
296 SparseOneDimensionalModel::PointList::const_iterator j = i; | |
297 ++j; | |
298 | |
299 if (j == points.end()) { | |
300 | |
301 snapped = i->frame; | |
302 found = true; | |
303 break; | |
304 | |
305 } else if (j->frame >= frame) { | |
306 | |
307 if (j->frame - frame < frame - i->frame) { | |
308 snapped = j->frame; | |
309 } else { | |
310 snapped = i->frame; | |
311 } | |
312 found = true; | |
313 break; | |
314 } | |
315 } | |
316 } | |
317 | |
318 frame = snapped; | |
319 return found; | |
242 } | 320 } |
243 | 321 |
244 void | 322 void |
245 TimeInstantLayer::paint(QPainter &paint, QRect rect) const | 323 TimeInstantLayer::paint(QPainter &paint, QRect rect) const |
246 { | 324 { |
253 long frame0 = getFrameForX(x0); | 331 long frame0 = getFrameForX(x0); |
254 long frame1 = getFrameForX(x1); | 332 long frame1 = getFrameForX(x1); |
255 | 333 |
256 SparseOneDimensionalModel::PointList points(m_model->getPoints | 334 SparseOneDimensionalModel::PointList points(m_model->getPoints |
257 (frame0, frame1)); | 335 (frame0, frame1)); |
336 | |
337 bool odd = false; | |
338 if (m_plotStyle == PlotSegmentation && !points.empty()) { | |
339 int index = m_model->getIndexOf(*points.begin()); | |
340 odd = ((index % 2) == 1); | |
341 } | |
258 | 342 |
259 paint.setPen(m_colour); | 343 paint.setPen(m_colour); |
260 | 344 |
261 QColor brushColour(m_colour); | 345 QColor brushColour(m_colour); |
262 brushColour.setAlpha(100); | 346 brushColour.setAlpha(100); |
263 paint.setBrush(brushColour); | 347 paint.setBrush(brushColour); |
348 | |
349 QColor oddBrushColour(brushColour); | |
350 if (m_plotStyle == PlotSegmentation) { | |
351 if (m_colour == Qt::black) { | |
352 oddBrushColour = Qt::gray; | |
353 } else if (m_colour == Qt::darkRed) { | |
354 oddBrushColour = Qt::red; | |
355 } else if (m_colour == Qt::darkBlue) { | |
356 oddBrushColour = Qt::blue; | |
357 } else if (m_colour == Qt::darkGreen) { | |
358 oddBrushColour = Qt::green; | |
359 } else { | |
360 oddBrushColour = oddBrushColour.light(150); | |
361 } | |
362 oddBrushColour.setAlpha(100); | |
363 } | |
264 | 364 |
265 // std::cerr << "TimeInstantLayer::paint: resolution is " | 365 // std::cerr << "TimeInstantLayer::paint: resolution is " |
266 // << m_model->getResolution() << " frames" << std::endl; | 366 // << m_model->getResolution() << " frames" << std::endl; |
267 | 367 |
268 QPoint localPos; | 368 QPoint localPos; |
303 paint.setPen(Qt::black); //!!! | 403 paint.setPen(Qt::black); //!!! |
304 } else { | 404 } else { |
305 paint.setPen(brushColour); | 405 paint.setPen(brushColour); |
306 } | 406 } |
307 | 407 |
308 if (iw > 1) { | 408 if (m_plotStyle == PlotInstants) { |
309 paint.drawRect(x, 0, iw - 1, m_view->height() - 1); | 409 if (iw > 1) { |
410 paint.drawRect(x, 0, iw - 1, m_view->height() - 1); | |
411 } else { | |
412 paint.drawLine(x, 0, x, m_view->height() - 1); | |
413 } | |
310 } else { | 414 } else { |
311 paint.drawLine(x, 0, x, m_view->height() - 1); | 415 |
312 } | 416 if (odd) paint.setBrush(oddBrushColour); |
417 else paint.setBrush(brushColour); | |
418 | |
419 int nx; | |
420 | |
421 if (j != points.end()) { | |
422 const SparseOneDimensionalModel::Point &q(*j); | |
423 nx = getXForFrame(q.frame); | |
424 } else { | |
425 nx = getXForFrame(m_model->getEndFrame()); | |
426 } | |
427 | |
428 if (nx >= x) { | |
429 | |
430 if (illuminateFrame != p.frame && | |
431 (nx < x + 5 || x >= m_view->width() - 1)) { | |
432 paint.setPen(Qt::NoPen); | |
433 } | |
434 | |
435 paint.drawRect(x, -1, nx - x, m_view->height() + 1); | |
436 } | |
437 | |
438 odd = !odd; | |
439 } | |
440 | |
313 paint.setPen(m_colour); | 441 paint.setPen(m_colour); |
314 | 442 |
315 if (p.label != "") { | 443 if (p.label != "") { |
316 | 444 |
317 // only draw if there's enough room from here to the next point | 445 // only draw if there's enough room from here to the next point |
446 | 574 |
447 QString | 575 QString |
448 TimeInstantLayer::toXmlString(QString indent, QString extraAttributes) const | 576 TimeInstantLayer::toXmlString(QString indent, QString extraAttributes) const |
449 { | 577 { |
450 return Layer::toXmlString(indent, extraAttributes + | 578 return Layer::toXmlString(indent, extraAttributes + |
451 QString(" colour=\"%1\"").arg(encodeColour(m_colour))); | 579 QString(" colour=\"%1\" plotStyle=\"%2\"") |
580 .arg(encodeColour(m_colour)).arg(m_plotStyle)); | |
452 } | 581 } |
453 | 582 |
454 void | 583 void |
455 TimeInstantLayer::setProperties(const QXmlAttributes &attributes) | 584 TimeInstantLayer::setProperties(const QXmlAttributes &attributes) |
456 { | 585 { |
459 QColor colour(colourSpec); | 588 QColor colour(colourSpec); |
460 if (colour.isValid()) { | 589 if (colour.isValid()) { |
461 setBaseColour(QColor(colourSpec)); | 590 setBaseColour(QColor(colourSpec)); |
462 } | 591 } |
463 } | 592 } |
593 | |
594 bool ok; | |
595 PlotStyle style = (PlotStyle) | |
596 attributes.value("plotStyle").toInt(&ok); | |
597 if (ok) setPlotStyle(style); | |
464 } | 598 } |
465 | 599 |
466 #ifdef INCLUDE_MOCFILES | 600 #ifdef INCLUDE_MOCFILES |
467 #include "TimeInstantLayer.moc.cpp" | 601 #include "TimeInstantLayer.moc.cpp" |
468 #endif | 602 #endif |