package gdsc.smlm.ij.utils;
/*-----------------------------------------------------------------------------
* GDSC SMLM Software
*
* Copyright (C) 2013 Alex Herbert
* Genome Damage and Stability Centre
* University of Sussex, UK
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*---------------------------------------------------------------------------*/
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import gdsc.core.ij.Utils;
import gdsc.core.utils.Sort;
import ij.ImagePlus;
import ij.WindowManager;
import ij.gui.Overlay;
import ij.gui.PointRoi;
import ij.text.TextPanel;
/**
* Attaches to a text panel and listens for mouse events. Upon double click it obtains the coordinates from a provider
* and draws a point ROI on the named image. Supports drawing multi-point ROI when multiple lines in the table are
* selected.
* <p>
* The provider should provide [slice,x,y] coordinates for the image ROI.
*/
public class ImageROIPainter implements MouseListener
{
private TextPanel textPanel;
private String title;
private CoordinateProvider coordProvider;
/**
* @param textPanel
* The text panel to listen to for mouse events
* @param title
* The title of the image to add the ROI to
* @param coordProvider
* Provides coordinates from the lines selected in the text panel
*/
public ImageROIPainter(TextPanel textPanel, String title, CoordinateProvider coordProvider)
{
// Check if the image is displayed
this.title = title;
this.textPanel = textPanel;
this.coordProvider = coordProvider;
textPanel.addMouseListener(this);
}
public void mouseClicked(MouseEvent e)
{
// Show the result that was double clicked in the result table
if (e.getClickCount() > 1)
{
ImagePlus imp = WindowManager.getImage(title);
if (imp == null)
return;
int index = textPanel.getSelectionStart();
if (index == -1)
return;
double[] position = coordProvider.getCoordinates(textPanel.getLine(index));
if (position == null || position.length < 3)
return;
int slice = (int) position[0];
double x = position[1];
double y = position[2];
addRoi(imp, slice, new PointRoi(x, y));
Utils.adjustSourceRect(imp, 0, (int) x, (int) y);
}
}
public void mousePressed(MouseEvent e)
{
// If a multiple-line selection is made then show all the points
int index = textPanel.getSelectionStart();
if (index == -1)
return;
int index2 = textPanel.getSelectionEnd();
if (index == index2)
return;
ImagePlus imp = WindowManager.getImage(title);
if (imp == null)
return;
// Show all
int points = 0;
float[] x = new float[index2 - index + 1];
float[] y = new float[x.length];
int[] slice = new int[x.length];
while (index <= index2)
{
double[] position = coordProvider.getCoordinates(textPanel.getLine(index));
if (position == null || position.length < 3)
continue;
slice[points] = (int) position[0];
x[points] = (float) position[1];
y[points] = (float) position[2];
points++;
index++;
}
if (points == 0)
return;
// Simple code to add the ROI onto a single slice: addRoi(imp, slice[0], new PointRoi(x, y, points));
// Add the ROI to each relevant slice
// Sort the slices
int[] indices = new int[points];
for (int i = 0; i < points; i++)
indices[i] = i;
Sort.sort(indices, slice);
Overlay o = new Overlay();
// Create an ROI for each slice
int start = 0;
for (int i = 0; i < points; i++)
{
if (slice[indices[i]] != slice[indices[start]])
{
appendRoi(x, y, slice, indices, o, start, i);
start = i;
}
}
appendRoi(x, y, slice, indices, o, start, points);
// Choose the first slice and add the final overlay
imp.setSlice(slice[indices[start]]);
if (imp.getWindow() != null)
imp.getWindow().toFront();
o.setStrokeColor(Color.green);
imp.setOverlay(o);
}
/**
* Adds a new ROI to the overlay using the coordinates from start to end (non-inclusive)
*
* @param x
* @param y
* @param slice
* @param indices
* @param o
* @param start
* @param end
*/
private void appendRoi(float[] x, float[] y, int[] slice, int[] indices, Overlay o, int start, int end)
{
int p = end - start;
float[] x2 = new float[p];
float[] y2 = new float[p];
for (int j = start, ii = 0; j < end; j++, ii++)
{
x2[ii] = x[indices[j]];
y2[ii] = y[indices[j]];
}
PointRoi roi = new PointRoi(x2, y2, p);
roi.setPosition(slice[indices[start]]);
o.add(roi);
}
public static void addRoi(ImagePlus imp, int slice, PointRoi roi)
{
if (imp != null && slice > 0 && slice <= imp.getStackSize())
{
imp.setSlice(slice);
if (imp.getWindow() != null)
imp.getWindow().toFront();
if (roi != null)
{
//imp.setRoi(roi);
if (imp.getStackSize() > 1)
roi.setPosition(slice);
Overlay o = new Overlay(roi);
o.setStrokeColor(Color.green);
imp.setOverlay(o);
}
else
{
imp.setOverlay(null);
}
}
}
public void mouseReleased(MouseEvent e)
{
// Ignore
}
public void mouseEntered(MouseEvent e)
{
// Ignore
}
public void mouseExited(MouseEvent e)
{
// Ignore
}
/**
* @return the title of the image
*/
public String getTitle()
{
return title;
}
/**
* @param title
* the title of the image
*/
public void setTitle(String title)
{
this.title = title;
}
/**
* @return the coordProvider
*/
public CoordinateProvider getCoordProvider()
{
return coordProvider;
}
/**
* @param coordProvider
* the coordProvider to set
*/
public void setCoordProvider(CoordinateProvider coordProvider)
{
this.coordProvider = coordProvider;
}
}