package ij.gui;
import java.awt.*;
import java.util.Vector;
import java.awt.geom.Rectangle2D;
import java.util.*;
import ij.*;
import ij.process.ImageProcessor;
import ij.plugin.filter.*;
import ij.plugin.*;
import ij.measure.ResultsTable;
public class Overlay implements Iterable<Roi> {
private Vector<Roi> list;
private boolean label;
private boolean drawNames;
private boolean drawBackgrounds;
private Color labelColor;
private Font labelFont;
private boolean scalableLabels;
private boolean isCalibrationBar;
private boolean selectable = true;
private boolean draggable = true;
public Overlay() {
list = new Vector<Roi>();
}
public Overlay(Roi roi) {
list = new Vector<Roi>();
if (roi!=null)
list.add(roi);
}
public void add(Roi roi) {
if (roi!=null)
list.add(roi);
}
public void add(Roi roi, String name) {
roi.setName(name);
add(roi);
}
public void addElement(Roi roi) {
if (roi!=null)
list.add(roi);
}
public void set(Roi roi, int index) {
if (index<0 || index>=list.size())
throw new IllegalArgumentException("set: index out of range");
if (roi!=null)
list.set(index, roi);
}
public void remove(int index) {
if (index>=0)
list.remove(index);
}
public void remove(Roi roi) {
list.remove(roi);
}
public void remove(String name) {
if (name==null) return;
for (int i=size()-1; i>=0; i--) {
if (name.equals(get(i).getName()))
remove(i);
}
}
public void clear() {
list.clear();
}
public Roi get(int index) {
try {
return (Roi)list.get(index);
} catch(Exception e) {
return null;
}
}
public Roi get(String name) {
int index = getIndex(name);
if (index==-1)
return null;
else
return get(index);
}
public int getIndex(String name) {
if (name==null) return -1;
Roi[] rois = toArray();
for (int i=rois.length-1; i>=0; i--) {
if (name.equals(rois[i].getName()))
return i;
}
return -1;
}
public int indexAt(int x, int y) {
Roi[] rois = toArray();
for (int i=rois.length-1; i>=0; i--) {
if (contains(rois[i],x,y))
return i;
}
return -1;
}
private boolean contains(Roi roi, int x, int y) {
if (roi==null) return false;
if (roi instanceof Line)
return (((Line)roi).getFloatPolygon(10)).contains(x,y);
else
return roi.contains(x,y);
}
public boolean contains(Roi roi) {
return list.contains(roi);
}
public int size() {
return list.size();
}
public Roi[] toArray() {
Roi[] array = new Roi[list.size()];
return (Roi[])list.toArray(array);
}
public Roi[] toArray(int[] indexes) {
ArrayList rois = new ArrayList();
for (int i=0; i<size(); i++) {
if (indexes[i]>=0 && indexes[i]<size())
rois.add(get(indexes[i]));
}
return (Roi[])rois.toArray(new Roi[rois.size()]);
}
public void setStrokeColor(Color color) {
for (int i=0; i<size(); i++)
get(i).setStrokeColor(color);
}
public void setStrokeWidth(Double width) {
for (int i=0; i<size(); i++)
get(i).setStrokeWidth(width);
}
public void setFillColor(Color color) {
for (int i=0; i<size(); i++)
get(i).setFillColor(color);
}
public void translate(int dx, int dy) {
for (int i=0; i<size(); i++) {
Roi roi = get(i);
if (roi.subPixelResolution()) {
Rectangle2D r = roi.getFloatBounds();
roi.setLocation(r.getX()+dx, r.getY()+dy);
} else {
Rectangle r = roi.getBounds();
roi.setLocation(r.x+dx, r.y+dy);
}
}
}
public void translate(double dx, double dy) {
boolean intArgs = (int)dx==dx && (int)dy==dy;
for (int i=0; i<size(); i++) {
Roi roi = get(i);
if (roi.subPixelResolution() || !intArgs) {
Rectangle2D r = roi.getFloatBounds();
roi.setLocation(r.getX()+dx, r.getY()+dy);
} else {
Rectangle r = roi.getBounds();
roi.setLocation(r.x+(int)dx, r.y+(int)dy);
}
}
}
public ResultsTable measure(ImagePlus imp) {
ResultsTable rt = new ResultsTable();
rt.showRowNumbers(true);
Analyzer analyzer = new Analyzer(imp, rt);
for (int i=0; i<size(); i++) {
Roi roi = get(i);
imp.setRoi(roi);
analyzer.measure();
}
imp.deleteRoi();
return rt;
}
public Overlay crop(Rectangle bounds) {
if (bounds==null)
return duplicate();
Overlay overlay2 = create();
Roi[] allRois = toArray();
for (Roi roi: allRois) {
Rectangle roiBounds = roi.getBounds();
if (roiBounds.width==0) roiBounds.width=1;
if (roiBounds.height==0) roiBounds.height=1;
if (bounds.intersects(roiBounds))
overlay2.add((Roi)roi.clone());
}
int dx = bounds.x>0?bounds.x:0;
int dy = bounds.y>0?bounds.y:0;
if (dx>0 || dy>0)
overlay2.translate(-dx, -dy);
return overlay2;
}
public void crop(int firstSlice, int lastSlice) {
for (int i=size()-1; i>=0; i--) {
Roi roi = get(i);
int position = roi.getPosition();
if (position>0) {
if (position<firstSlice || position>lastSlice)
remove(i);
else
roi.setPosition(position-firstSlice+1);
}
}
}
public void crop(int firstC, int lastC, int firstZ, int lastZ, int firstT, int lastT) {
int nc = lastC-firstC+1, nz = lastZ-firstZ+1, nt = lastT-firstT+1;
boolean toCStack = nz==1 && nt==1;
boolean toZStack = nt==1 && nc==1;
boolean toTStack = nc==1 && nz==1;
Roi roi;
int c, z, t, c2, z2, t2;
for (int i=size()-1; i>=0; i--) {
roi = get(i);
c = roi.getCPosition();
z = roi.getZPosition();
t = roi.getTPosition();
c2 = c-firstC+1;
z2 = z-firstZ+1;
t2 = t-firstT+1;
if (toCStack)
roi.setPosition(c2);
else if (toZStack)
roi.setPosition(z2);
else if (toTStack)
roi.setPosition(t2);
else
roi.setPosition(c2, z2, t2);
if ((c2<1||c2>nc) && c>0 || (z2<1||z2>nz) && z>0 || (t2<1||t2>nt) && t>0)
remove(i);
}
}
public Roi xor(int[] indexes) {
return Roi.xor(toArray(indexes));
}
public Overlay create() {
Overlay overlay2 = new Overlay();
overlay2.drawLabels(label);
overlay2.drawNames(drawNames);
overlay2.drawBackgrounds(drawBackgrounds);
overlay2.setLabelColor(labelColor);
overlay2.setLabelFont(labelFont, scalableLabels);
overlay2.setIsCalibrationBar(isCalibrationBar);
overlay2.selectable(selectable);
overlay2.setDraggable(draggable);
return overlay2;
}
public Overlay duplicate() {
Roi[] rois = toArray();
Overlay overlay2 = create();
for (int i=0; i<rois.length; i++)
overlay2.add((Roi)rois[i].clone());
return overlay2;
}
public Overlay scale(double xscale, double yscale) {
Overlay overlay2 = create();
for (int i=0; i<size(); i++) {
Roi roi = get(i);
int position = roi.getPosition();
roi = RoiScaler.scale(roi, xscale, yscale, false);
roi.setPosition(position);
overlay2.add(roi);
}
return overlay2;
}
public Overlay rotate(double angle, double xcenter, double ycenter) {
Overlay overlay2 = create();
for (int i=0; i<size(); i++) {
Roi roi = get(i);
int position = roi.getPosition();
if (!Rotator.GRID.equals(roi.getName()))
roi = RoiRotator.rotate(roi, angle, xcenter, ycenter);
roi.setPosition(position);
overlay2.add(roi);
}
return overlay2;
}
public void drawLabels(boolean b) {
label = b;
}
public boolean getDrawLabels() {
return label;
}
public void drawNames(boolean b) {
drawNames = b;
Roi[] rois = toArray();
for (int i=0; i<rois.length; i++)
rois[i].setIgnoreClipRect(drawNames);
}
public boolean getDrawNames() {
return drawNames;
}
public void drawBackgrounds(boolean b) {
drawBackgrounds = b;
}
public boolean getDrawBackgrounds() {
return drawBackgrounds;
}
public void setLabelColor(Color c) {
labelColor = c;
}
public Color getLabelColor() {
return labelColor;
}
public void setLabelFont(Font font) {
setLabelFont(font, false);
}
public void setLabelFont(Font font, boolean scalable) {
labelFont = font;
scalableLabels = scalable;
}
public void setLabelFontSize(int size, String options) {
int style = Font.PLAIN;
if (options!=null) {
scalableLabels = options.contains("scale");
if (options.contains("bold"))
style = Font.BOLD;
drawBackgrounds = options.contains("back");
}
labelFont = new Font("SansSerif", style, size);
drawLabels(true);
}
public Font getLabelFont() {
return labelFont;
}
public void setIsCalibrationBar(boolean b) {
this.isCalibrationBar = b;
}
public boolean isCalibrationBar() {
return isCalibrationBar;
}
public void fill(ImagePlus imp, Color foreground, Color background) {
ImageProcessor ip = imp.getProcessor();
if (background!=null) {
ip.resetRoi();
ip.setColor(background);
ip.fillRect(0,0,ip.getWidth(),ip.getHeight());
}
if (foreground!=null) {
ip.setColor(foreground);
for (int i=0; i<size(); i++)
ip.fill(get(i));
ip.resetRoi();
}
imp.updateAndDraw();
}
void setVector(Vector<Roi> v) {list = v;}
Vector<Roi> getVector() {return list;}
public void selectable(boolean selectable) {
this.selectable = selectable;
}
public boolean isSelectable() {
return selectable;
}
public void setDraggable(boolean draggable) {
this.draggable = draggable;
}
public boolean isDraggable() {
return draggable;
}
public boolean scalableLabels() {
return scalableLabels;
}
public String toString() {
return "Overlay[size="+size()+" "+(scalableLabels?"scale":"")+" "+Colors.colorToString(getLabelColor())+"]";
}
public static void updateTableOverlay(ImagePlus imp, int first, int last, int tableSize) {
if (imp==null)
return;
Overlay overlay = imp.getOverlay();
if (overlay==null)
return;
if (overlay.size()!=tableSize)
return;
if (first<0)
first = 0;
if (last>tableSize-1)
last = tableSize-1;
if (first>last)
return;
String name1 = overlay.get(0).getName();
String name2 = overlay.get(overlay.size()-1).getName();
if (!"1".equals(name1) || !(""+tableSize).equals(name2))
return;
int count = last-first+1;
if (overlay.size()==count && !IJ.isMacro()) {
if (count==1 || IJ.showMessageWithCancel("ImageJ", "Delete "+overlay.size()+" element overlay? "))
imp.setOverlay(null);
return;
}
for (int i=0; i<count; i++)
overlay.remove(first);
for (int i=first; i<overlay.size(); i++)
overlay.get(i).setName(""+(i+1));
imp.draw();
}
public static Overlay createStackOverlay(Roi[] rois) {
Overlay overlay = new Overlay();
for (int i=0; i<rois.length; i++) {
Roi roi = (Roi)rois[i].clone();
roi.setLocation(0,0);
roi.setPosition(i+1);
overlay.add(roi);
}
return overlay;
}
@Override
public Iterator<Roi> iterator() {
final Overlay overlay = this;
Iterator<Roi> it = new Iterator<Roi>() {
private int index = -1;
@Override
public boolean hasNext() {
if (index+1<overlay.size())
return true;
else
return false;
}
@Override
public Roi next() {
if (index+1<overlay.size())
return overlay.get(++index);
else
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}