diff 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
line wrap: on
line diff
--- 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