package ie.dcu.segment.annotate; import ie.dcu.swt.*; import java.util.*; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.*; /** * Class encapsulating a single image annotation. * * @author Kevin McGuinness */ public class Annotation { private final AnnotationType type; private final LinkedList points; private Rectangle bounds; private int lineWidth; /** * Create an annotation of the given type. * * @param type * The annotation type. */ public Annotation(AnnotationType type) { this(type, 1); } /** * Create an annotation of the given type and brush size. * * @param type * The annotation type. * @param width * The brush size. */ public Annotation(AnnotationType type, int width) { this (type, width, null); } /** * Create an annotation of the given type, brush size, and with * the given initial point. * * @param type * The annotation type. * @param width * The brush size. * @param pt * The initial point. */ public Annotation(AnnotationType type, int width, Point pt) { assert (type != null); this.type = type; points = new LinkedList(); setLineWidth(width); if (pt != null) { add(pt); } } /** * Set the annotation brush size. * * @param width * The brush size (must be > 0). */ public void setLineWidth(int width) { assert (width > 0); lineWidth = width; } /** * Get the annotation brush size. */ public int getLineWidth() { return lineWidth; } /** * Get the type of annotation. */ public AnnotationType getType() { return type; } /** * Add a point to the annotation. * * @param pt * A point */ public void add(Point pt) { // Add point points.add(pt); // Expand bounds Rectangle m = new Rectangle( pt.x-1, pt.y-1, 3, 3 ); if (bounds == null) { bounds = SwtUtils.clone(m); } else { bounds.add(m); } } /** * Returns the last point in the annotation, or null if the * annotation has no points. */ public Point last() { return points.getLast(); } /** * Returns the first point in the annotation, or null if the * annotation has no points. */ public Point first() { return points.getFirst(); } /** * Render the points onto an {@link ObservableImage} instance. * * @param image * An {@link ObservableImage}. */ public void paint(ObservableImage image) { GC gc = image.beginPaint(); paint(gc, true); image.endPaint(getBounds()); } /** * Render the annotations onto an SWT image instance. * * @param image * An image. * @param antialias * Flag indicating whether antialiasing should be done. */ public void paint(Image image, boolean antialias) { GC gc = new GC(image); paint(gc, antialias); gc.dispose(); } /** * Render the annotation onto the graphics context. * * @param gc * A graphics context. * @param antialias * Flag indicating whether antialiasing should be done. */ public void paint(GC gc, boolean antialias) { int npoints = points.size(); if (npoints == 0) return; if (antialias) { gc.setAntialias(SWT.ON); } gc.setLineCap(SWT.CAP_ROUND); gc.setLineJoin(SWT.JOIN_ROUND); gc.setLineWidth(lineWidth); gc.setForeground(type.getColor()); Point last = null; // Ensure single point or zero length lines are drawn switch (npoints) { case 1: case 2: Point pt = points.get(0); last = new Point(pt.x+1, pt.y); } // Draw points for (Point p : points) { if (last != null) { gc.drawLine(last.x, last.y, p.x, p.y); } last = p; } } /** * Returns a rectangle that encloses all pixels that this annotation * represents. If the annotation is empty, returns null. */ public Rectangle getBounds() { if (bounds != null) { return new Rectangle( bounds.x - lineWidth / 2, bounds.y - lineWidth / 2, bounds.width + lineWidth, bounds.height + lineWidth ); } return null; } /** * Returns an unmodifiable list of points for this annotation */ public List points() { return Collections.unmodifiableList(points); } /** * Returns the number of points in this annotation. */ public int count() { return points.size(); } }