changeset 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 38fe0ea9e46e
children 9f55af9676b4
files layer/Colour3DPlotLayer.cpp layer/Colour3DPlotLayer.h layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/TimeInstantLayer.cpp layer/TimeInstantLayer.h layer/TimeValueLayer.cpp layer/TimeValueLayer.h layer/WaveformLayer.cpp widgets/Pane.cpp
diffstat 10 files changed, 298 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.cpp	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/Colour3DPlotLayer.cpp	Mon Feb 06 17:24:52 2006 +0000
@@ -374,21 +374,30 @@
 */
 }
 
-int
-Colour3DPlotLayer::getNearestFeatureFrame(int frame,
-					  size_t &resolution,
-					  bool snapRight) const
+bool
+Colour3DPlotLayer::snapToFeatureFrame(int &frame,
+				      size_t &resolution,
+				      SnapType snap) const
 {
     if (!m_model) {
-	return Layer::getNearestFeatureFrame(frame, resolution, snapRight);
+	return Layer::snapToFeatureFrame(frame, resolution, snap);
     }
 
     resolution = m_model->getWindowSize();
+    int left = (frame / resolution) * resolution;
+    int right = left + resolution;
+
+    switch (snap) {
+    case SnapLeft:  frame = left;  break;
+    case SnapRight: frame = right; break;
+    case SnapNearest:
+    case SnapNeighbouring:
+	if (frame - left > right - frame) frame = right;
+	else frame = left;
+	break;
+    }
     
-    int returnFrame = (frame / resolution) * resolution;
-    if (snapRight) returnFrame += resolution;
-    
-    return returnFrame;
+    return true;
 }
 
 #ifdef INCLUDE_MOCFILES
--- a/layer/Colour3DPlotLayer.h	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/Colour3DPlotLayer.h	Mon Feb 06 17:24:52 2006 +0000
@@ -48,9 +48,9 @@
 
     virtual QString getFeatureDescription(QPoint &) const;
 
-    virtual int getNearestFeatureFrame(int frame, 
-				       size_t &resolution,
-				       bool snapRight = true) const;
+    virtual bool snapToFeatureFrame(int &frame, 
+				    size_t &resolution,
+				    SnapType snap) const;
 
     virtual bool isLayerScrollable() const;
 
--- a/layer/SpectrogramLayer.cpp	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/SpectrogramLayer.cpp	Mon Feb 06 17:24:52 2006 +0000
@@ -1483,16 +1483,27 @@
     return completion;
 }
 
-int
-SpectrogramLayer::getNearestFeatureFrame(int frame, 
-					 size_t &resolution,
-					 bool snapRight) const
+bool
+SpectrogramLayer::snapToFeatureFrame(int &frame,
+				     size_t &resolution,
+				     SnapType snap) const
 {
     resolution = getWindowIncrement();
-    int snapFrame = (frame / resolution) * resolution;
-    if (snapRight) snapFrame += resolution;
-    return snapFrame;
-}
+    int left = (frame / resolution) * resolution;
+    int right = left + resolution;
+
+    switch (snap) {
+    case SnapLeft:  frame = left;  break;
+    case SnapRight: frame = right; break;
+    case SnapNearest:
+    case SnapNeighbouring:
+	if (frame - left > right - frame) frame = right;
+	else frame = left;
+	break;
+    }
+    
+    return true;
+} 
 
 QString
 SpectrogramLayer::getFeatureDescription(QPoint &pos) const
--- a/layer/SpectrogramLayer.h	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/SpectrogramLayer.h	Mon Feb 06 17:24:52 2006 +0000
@@ -53,9 +53,9 @@
 
     virtual QString getFeatureDescription(QPoint &) const;
 
-    virtual int getNearestFeatureFrame(int frame, 
-				       size_t &resolution,
-				       bool snapRight = true) const;
+    virtual bool snapToFeatureFrame(int &frame,
+				    size_t &resolution,
+				    SnapType snap) const;
 
     void setModel(const DenseTimeValueModel *model);
 
--- a/layer/TimeInstantLayer.cpp	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/TimeInstantLayer.cpp	Mon Feb 06 17:24:52 2006 +0000
@@ -27,7 +27,8 @@
     m_editing(false),
     m_editingPoint(0, tr("New Point")),
     m_editingCommand(0),
-    m_colour(QColor(200, 50, 255))
+    m_colour(QColor(200, 50, 255)),
+    m_plotStyle(PlotInstants)
 {
     m_view->addLayer(this);
 }
@@ -55,6 +56,7 @@
 {
     PropertyList list;
     list.push_back(tr("Colour"));
+    list.push_back(tr("Plot Type"));
     return list;
 }
 
@@ -82,6 +84,13 @@
 	else if (m_colour == QColor(200, 50, 255)) deft = 4;
 	else if (m_colour == QColor(255, 150, 50)) deft = 5;
 
+    } else if (name == tr("Plot Type")) {
+	
+	if (min) *min = 0;
+	if (max) *max = 1;
+	
+	deft = int(m_plotStyle);
+
     } else {
 	
 	deft = Layer::getPropertyRangeAndValue(name, min, max);
@@ -104,6 +113,12 @@
 	case 4: return tr("Purple");
 	case 5: return tr("Orange");
 	}
+    } else if (name == tr("Plot Type")) {
+	switch (value) {
+	default:
+	case 0: return tr("Instants");
+	case 1: return tr("Segmentation");
+	}
     }
     return tr("<unknown>");
 }
@@ -121,6 +136,8 @@
 	case 4: setBaseColour(QColor(200, 50, 255)); break;
 	case 5: setBaseColour(QColor(255, 150, 50)); break;
 	}
+    } else if (name == tr("Plot Type")) {
+	setPlotStyle(PlotStyle(value));
     }
 }
 
@@ -132,6 +149,14 @@
     emit layerParametersChanged();
 }
 
+void
+TimeInstantLayer::setPlotStyle(PlotStyle style)
+{
+    if (m_plotStyle == style) return;
+    m_plotStyle = style;
+    emit layerParametersChanged();
+}
+
 bool
 TimeInstantLayer::isLayerScrollable() const
 {
@@ -142,6 +167,10 @@
 SparseOneDimensionalModel::PointList
 TimeInstantLayer::getLocalPoints(int x) const
 {
+    // Return a set of points that all have the same frame number, the
+    // nearest to the given x coordinate, and that are within a
+    // certain fuzz distance of that x coordinate.
+
     if (!m_model) return SparseOneDimensionalModel::PointList();
 
     long frame = getFrameForX(x);
@@ -170,6 +199,15 @@
 	usePoints = nextPoints;
     }
 
+    if (!usePoints.empty()) {
+	int fuzz = 2;
+	int px = getXForFrame(usePoints.begin()->frame);
+	if ((px > x && px - x > fuzz) ||
+	    (px < x && x - px > fuzz + 1)) {
+	    usePoints.clear();
+	}
+    }
+
     return usePoints;
 }
 
@@ -209,36 +247,76 @@
     return text;
 }
 
-int
-TimeInstantLayer::getNearestFeatureFrame(int frame,
-					 size_t &resolution,
-					 bool snapRight) const
+bool
+TimeInstantLayer::snapToFeatureFrame(int &frame,
+				     size_t &resolution,
+				     SnapType snap) const
 {
     if (!m_model) {
-	return Layer::getNearestFeatureFrame(frame, resolution, snapRight);
+	return Layer::snapToFeatureFrame(frame, resolution, snap);
     }
 
     resolution = m_model->getResolution();
-    SparseOneDimensionalModel::PointList points(m_model->getPoints(frame, frame));
+    SparseOneDimensionalModel::PointList points;
 
-    int returnFrame = frame;
+    if (snap == SnapNeighbouring) {
+	
+	points = getLocalPoints(getXForFrame(frame));
+	if (points.empty()) return false;
+	frame = points.begin()->frame;
+	return true;
+    }    
+
+    points = m_model->getPoints(frame, frame);
+    int snapped = frame;
+    bool found = false;
 
     for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin();
 	 i != points.end(); ++i) {
 
-	if (snapRight) {
-	    if (i->frame > frame) {
-		returnFrame = i->frame;
+	if (snap == SnapRight) {
+
+	    if (i->frame >= frame) {
+		snapped = i->frame;
+		found = true;
 		break;
 	    }
-	} else {
+
+	} else if (snap == SnapLeft) {
+
 	    if (i->frame <= frame) {
-		returnFrame = i->frame;
+		snapped = i->frame;
+		found = true; // don't break, as the next may be better
+	    } else {
+		break;
+	    }
+
+	} else { // nearest
+
+	    SparseOneDimensionalModel::PointList::const_iterator j = i;
+	    ++j;
+
+	    if (j == points.end()) {
+
+		snapped = i->frame;
+		found = true;
+		break;
+
+	    } else if (j->frame >= frame) {
+
+		if (j->frame - frame < frame - i->frame) {
+		    snapped = j->frame;
+		} else {
+		    snapped = i->frame;
+		}
+		found = true;
+		break;
 	    }
 	}
     }
 
-    return returnFrame;
+    frame = snapped;
+    return found;
 }
 
 void
@@ -256,12 +334,34 @@
     SparseOneDimensionalModel::PointList points(m_model->getPoints
 						(frame0, frame1));
 
+    bool odd = false;
+    if (m_plotStyle == PlotSegmentation && !points.empty()) {
+	int index = m_model->getIndexOf(*points.begin());
+	odd = ((index % 2) == 1);
+    }
+
     paint.setPen(m_colour);
 
     QColor brushColour(m_colour);
     brushColour.setAlpha(100);
     paint.setBrush(brushColour);
 
+    QColor oddBrushColour(brushColour);
+    if (m_plotStyle == PlotSegmentation) {
+	if (m_colour == Qt::black) {
+	    oddBrushColour = Qt::gray;
+	} else if (m_colour == Qt::darkRed) {
+	    oddBrushColour = Qt::red;
+	} else if (m_colour == Qt::darkBlue) {
+	    oddBrushColour = Qt::blue;
+	} else if (m_colour == Qt::darkGreen) {
+	    oddBrushColour = Qt::green;
+	} else {
+	    oddBrushColour = oddBrushColour.light(150);
+	}
+	oddBrushColour.setAlpha(100);
+    }
+
 //    std::cerr << "TimeInstantLayer::paint: resolution is "
 //	      << m_model->getResolution() << " frames" << std::endl;
 
@@ -305,11 +405,39 @@
 	    paint.setPen(brushColour);
 	}
 
-	if (iw > 1) {
-	    paint.drawRect(x, 0, iw - 1, m_view->height() - 1);
+	if (m_plotStyle == PlotInstants) {
+	    if (iw > 1) {
+		paint.drawRect(x, 0, iw - 1, m_view->height() - 1);
+	    } else {
+		paint.drawLine(x, 0, x, m_view->height() - 1);
+	    }
 	} else {
-	    paint.drawLine(x, 0, x, m_view->height() - 1);
+
+	    if (odd) paint.setBrush(oddBrushColour);
+	    else paint.setBrush(brushColour);
+	    
+	    int nx;
+	    
+	    if (j != points.end()) {
+		const SparseOneDimensionalModel::Point &q(*j);
+		nx = getXForFrame(q.frame);
+	    } else {
+		nx = getXForFrame(m_model->getEndFrame());
+	    }
+
+	    if (nx >= x) {
+		
+		if (illuminateFrame != p.frame &&
+		    (nx < x + 5 || x >= m_view->width() - 1)) {
+		    paint.setPen(Qt::NoPen);
+		}
+
+		paint.drawRect(x, -1, nx - x, m_view->height() + 1);
+	    }
+
+	    odd = !odd;
 	}
+
 	paint.setPen(m_colour);
 	
 	if (p.label != "") {
@@ -448,7 +576,8 @@
 TimeInstantLayer::toXmlString(QString indent, QString extraAttributes) const
 {
     return Layer::toXmlString(indent, extraAttributes +
-			      QString(" colour=\"%1\"").arg(encodeColour(m_colour)));
+			      QString(" colour=\"%1\" plotStyle=\"%2\"")
+			      .arg(encodeColour(m_colour)).arg(m_plotStyle));
 }
 
 void
@@ -461,6 +590,11 @@
 	    setBaseColour(QColor(colourSpec));
 	}
     }
+
+    bool ok;
+    PlotStyle style = (PlotStyle)
+	attributes.value("plotStyle").toInt(&ok);
+    if (ok) setPlotStyle(style);
 }
 
 #ifdef INCLUDE_MOCFILES
--- a/layer/TimeInstantLayer.h	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/TimeInstantLayer.h	Mon Feb 06 17:24:52 2006 +0000
@@ -30,9 +30,9 @@
 
     virtual QString getFeatureDescription(QPoint &) const;
 
-    virtual int getNearestFeatureFrame(int frame, 
-				       size_t &resolution,
-				       bool snapRight = true) const;
+    virtual bool snapToFeatureFrame(int &frame,
+				    size_t &resolution,
+				    SnapType snap) const;
 
     virtual void drawStart(QMouseEvent *);
     virtual void drawDrag(QMouseEvent *);
@@ -56,6 +56,14 @@
     void setBaseColour(QColor);
     QColor getBaseColour() const { return m_colour; }
 
+    enum PlotStyle {
+	PlotInstants,
+	PlotSegmentation
+    };
+
+    void setPlotStyle(PlotStyle style);
+    PlotStyle getPlotStyle() const { return m_plotStyle; }
+
     virtual bool isLayerScrollable() const;
 
     virtual bool isLayerEditable() const { return true; }
@@ -75,6 +83,7 @@
     SparseOneDimensionalModel::Point m_editingPoint;
     SparseOneDimensionalModel::EditCommand *m_editingCommand;
     QColor m_colour;
+    PlotStyle m_plotStyle;
 };
 
 #endif
--- a/layer/TimeValueLayer.cpp	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/TimeValueLayer.cpp	Mon Feb 06 17:24:52 2006 +0000
@@ -210,6 +210,15 @@
 	usePoints = nextPoints;
     }
 
+    if (!usePoints.empty()) {
+	int fuzz = 2;
+	int px = getXForFrame(usePoints.begin()->frame);
+	if ((px > x && px - x > fuzz) ||
+	    (px < x && x - px > fuzz + 1)) {
+	    usePoints.clear();
+	}
+    }
+
     return usePoints;
 }
 
@@ -251,36 +260,76 @@
     return text;
 }
 
-int
-TimeValueLayer::getNearestFeatureFrame(int frame,
-				       size_t &resolution,
-				       bool snapRight) const
+bool
+TimeValueLayer::snapToFeatureFrame(int &frame,
+				   size_t &resolution,
+				   SnapType snap) const
 {
     if (!m_model) {
-	return Layer::getNearestFeatureFrame(frame, resolution, snapRight);
+	return Layer::snapToFeatureFrame(frame, resolution, snap);
     }
 
     resolution = m_model->getResolution();
-    SparseTimeValueModel::PointList points(m_model->getPoints(frame, frame));
+    SparseTimeValueModel::PointList points;
 
-    int returnFrame = frame;
+    if (snap == SnapNeighbouring) {
+	
+	points = getLocalPoints(getXForFrame(frame));
+	if (points.empty()) return false;
+	frame = points.begin()->frame;
+	return true;
+    }    
+
+    points = m_model->getPoints(frame, frame);
+    int snapped = frame;
+    bool found = false;
 
     for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
 	 i != points.end(); ++i) {
 
-	if (snapRight) {
+	if (snap == SnapRight) {
+
 	    if (i->frame > frame) {
-		returnFrame = i->frame;
+		snapped = i->frame;
+		found = true;
 		break;
 	    }
-	} else {
+
+	} else if (snap == SnapLeft) {
+
 	    if (i->frame <= frame) {
-		returnFrame = i->frame;
+		snapped = i->frame;
+		found = true; // don't break, as the next may be better
+	    } else {
+		break;
+	    }
+
+	} else { // nearest
+
+	    SparseTimeValueModel::PointList::const_iterator j = i;
+	    ++j;
+
+	    if (j == points.end()) {
+
+		snapped = i->frame;
+		found = true;
+		break;
+
+	    } else if (j->frame >= frame) {
+
+		if (j->frame - frame < frame - i->frame) {
+		    snapped = j->frame;
+		} else {
+		    snapped = i->frame;
+		}
+		found = true;
+		break;
 	    }
 	}
     }
 
-    return returnFrame;
+    frame = snapped;
+    return found;
 }
 
 int
@@ -473,7 +522,8 @@
 
 	    if (nx <= x) continue;
 
-	    if (nx < x + 5 && illuminateFrame != p.frame) {
+	    if (illuminateFrame != p.frame &&
+		(nx < x + 5 || x >= m_view->width() - 1)) {
 		paint.setPen(Qt::NoPen);
 	    }
 
--- a/layer/TimeValueLayer.h	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/TimeValueLayer.h	Mon Feb 06 17:24:52 2006 +0000
@@ -30,9 +30,9 @@
 
     virtual QString getFeatureDescription(QPoint &) const;
 
-    virtual int getNearestFeatureFrame(int frame, 
-				       size_t &resolution,
-				       bool snapRight = true) const;
+    virtual bool snapToFeatureFrame(int &frame,
+				    size_t &resolution,
+				    SnapType snap) const;
 
     virtual void drawStart(QMouseEvent *);
     virtual void drawDrag(QMouseEvent *);
--- a/layer/WaveformLayer.cpp	Fri Feb 03 17:30:47 2006 +0000
+++ b/layer/WaveformLayer.cpp	Mon Feb 06 17:24:52 2006 +0000
@@ -385,12 +385,12 @@
 	paint->setPen(Qt::black);
 	paint->setBrush(Qt::NoBrush);
 
-	paint->setRenderHint(QPainter::Antialiasing, false);
-
     } else {
 	paint = &viewPainter;
     }
 
+    paint->setRenderHint(QPainter::Antialiasing, false);
+
     int x0 = 0, x1 = w - 1;
     int y0 = 0, y1 = h - 1;
 
@@ -399,6 +399,9 @@
     y0 = rect.top();
     y1 = rect.bottom();
 
+    if (x0 > 0) --x0;
+    if (x1 < m_view->width()) ++x1;
+
     long frame0 = getFrameForX(x0);
     long frame1 = getFrameForX(x1 + 1);
      
@@ -440,6 +443,7 @@
     for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
 
 	int prevRangeBottom = -1, prevRangeTop = -1;
+	QColor prevRangeBottomColour = m_colour, prevRangeTopColour = m_colour;
 
 	int m = (h / channels) / 2;
 	int my = m + (((ch - minChannel) * h) / channels);
@@ -593,15 +597,17 @@
 	    if (x != x0 && prevRangeBottom != -1) {
 		if (prevRangeBottom > rangeBottom &&
 		    prevRangeTop    > rangeBottom) {
-		    paint->setPen(midColour);
+//		    paint->setPen(midColour);
+		    paint->setPen(m_colour);
 		    paint->drawLine(x-1, prevRangeTop, x, rangeBottom);
-		    paint->setPen(m_colour);
+		    paint->setPen(prevRangeTopColour);
 		    paint->drawPoint(x-1, prevRangeTop);
 		} else if (prevRangeBottom < rangeTop &&
 			   prevRangeTop    < rangeTop) {
-		    paint->setPen(midColour);
+//		    paint->setPen(midColour);
+		    paint->setPen(m_colour);
 		    paint->drawLine(x-1, prevRangeBottom, x, rangeTop);
-		    paint->setPen(m_colour);
+		    paint->setPen(prevRangeBottomColour);
 		    paint->drawPoint(x-1, prevRangeBottom);
 		}
 	    }
@@ -620,6 +626,9 @@
 
 	    paint->drawLine(x, rangeBottom, x, rangeTop);
 
+	    prevRangeTopColour = m_colour;
+	    prevRangeBottomColour = m_colour;
+
 	    if (m_greyscale && (m_scale == LinearScale) && ready) {
 		if (!clipped) {
 		    if (rangeTop < rangeBottom) {
@@ -627,11 +636,13 @@
 			    (!drawMean || (rangeTop < meanTop - 1))) {
 			    paint->setPen(greys[topFill - 1]);
 			    paint->drawPoint(x, rangeTop);
+			    prevRangeTopColour = greys[topFill - 1];
 			}
 			if (bottomFill > 0 && 
 			    (!drawMean || (rangeBottom > meanBottom + 1))) {
 			    paint->setPen(greys[bottomFill - 1]);
 			    paint->drawPoint(x, rangeBottom);
+			    prevRangeBottomColour = greys[bottomFill - 1];
 			}
 		    }
 		}
--- a/widgets/Pane.cpp	Fri Feb 03 17:30:47 2006 +0000
+++ b/widgets/Pane.cpp	Mon Feb 06 17:24:52 2006 +0000
@@ -40,14 +40,6 @@
 bool
 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos)
 {
-/*!!!
-    for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
-	--vi;
-	if (layer != *vi) return false;
-	pos = m_identifyPoint;
-	return m_identifyFeatures;
-    }
-*/
     if (layer == getSelectedLayer()) {
 	pos = m_identifyPoint;
 	return m_identifyFeatures;
@@ -352,8 +344,7 @@
 	
 	    Layer *layer = getSelectedLayer();
 	    if (layer) {
-		snapFrame = layer->getNearestFeatureFrame(mouseFrame, resolution,
-							  false);
+		layer->snapToFeatureFrame(snapFrame, resolution, Layer::SnapLeft);
 	    }
 	    
 	    if (snapFrame < 0) snapFrame = 0;
@@ -486,6 +477,9 @@
     ViewManager::ToolMode mode = ViewManager::NavigateMode;
     if (m_manager) mode = m_manager->getToolMode();
 
+    QPoint prevPoint = m_identifyPoint;
+    m_identifyPoint = e->pos();
+
     if (!m_clickedInRange) {
 	
 	if (mode == ViewManager::SelectMode) {
@@ -501,10 +495,7 @@
 	if (mode != ViewManager::DrawMode) {
 
 	    bool previouslyIdentifying = m_identifyFeatures;
-	    QPoint prevPoint = m_identifyPoint;
-
 	    m_identifyFeatures = true;
-	    m_identifyPoint = e->pos();
 	    
 	    if (m_identifyFeatures != previouslyIdentifying ||
 		m_identifyPoint != prevPoint) {
@@ -555,12 +546,12 @@
 	
 	Layer *layer = getSelectedLayer();
 	if (layer) {
-	    snapFrameLeft = layer->getNearestFeatureFrame(mouseFrame, resolution,
-							  false);
-	    snapFrameRight = layer->getNearestFeatureFrame(mouseFrame, resolution,
-							   true);
+	    layer->snapToFeatureFrame(snapFrameLeft, resolution, Layer::SnapLeft);
+	    layer->snapToFeatureFrame(snapFrameRight, resolution, Layer::SnapRight);
 	}
 	
+	std::cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << std::endl;
+
 	if (snapFrameLeft < 0) snapFrameLeft = 0;
 	if (snapFrameRight < 0) snapFrameRight = 0;