package gdsc.foci;
/*-----------------------------------------------------------------------------
* GDSC Plugins for ImageJ
*
* Copyright (C) 2011 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 2 of the License, or
* (at your option) any later version.
*---------------------------------------------------------------------------*/
import java.util.LinkedList;
import java.util.List;
/**
* Stores a set of GridPoints within a grid arrangement at a given resolution. Allows comparison of a coordinate with
* any point within the sampling resolution to locate the highest unassigned grid point.
*
* Currently only supports a 2D grid.
*/
public class GridPointManager
{
private List<GridPoint> allPoints;
@SuppressWarnings("rawtypes")
private List[][] grid;
private int resolution;
private int minX = Integer.MAX_VALUE;
private int minY = Integer.MAX_VALUE;
private int searchMode = 0;
/**
* Define the search modes for the {@link #findUnassignedPoint(int, int)} method
*/
public static final String[] SEARCH_MODES = new String[] { "Highest", "Closest" };
public static final int HIGHEST = 0;
public static final int CLOSEST = 1;
public GridPointManager(List<GridPoint> points, int resolution) throws GridException
{
this.resolution = resolution;
this.allPoints = points;
initialiseGrid();
}
private void initialiseGrid() throws GridException
{
// Find the minimum and maximum x,y
int maxX = 0;
int maxY = maxX;
for (GridPoint p : allPoints)
{
if (p.getX() < minX)
minX = p.getXint();
if (p.getX() > maxX)
maxX = p.getXint();
if (p.getY() < minY)
minY = p.getYint();
if (p.getY() > maxY)
maxY = p.getYint();
}
if (minX < 0 || minY < 0)
throw new GridException("Minimum grid coordinates must not be negative (x" + minX + ",y" + minY + ")");
int xBlocks = getXBlock(maxX) + 1;
int yBlocks = getYBlock(maxY) + 1;
if (xBlocks > 500 || yBlocks > 500)
throw new GridException("Maximum number of grid blocks exceeded, please increase the resolution parameter");
if (xBlocks <= 0 || yBlocks <= 0)
throw new GridException("No coordinates to add to the grid");
grid = new List[xBlocks][yBlocks];
// Assign points
for (GridPoint p : allPoints)
{
addToGrid(p);
}
}
private int getXBlock(int x)
{
return (x - minX) / resolution;
}
private int getYBlock(int y)
{
return (y - minY) / resolution;
}
private void addToGrid(GridPoint p)
{
int xBlock = getXBlock(p.getXint());
int yBlock = getYBlock(p.getYint());
@SuppressWarnings("unchecked")
LinkedList<GridPoint> points = (LinkedList<GridPoint>) grid[xBlock][yBlock];
if (points == null)
{
points = new LinkedList<GridPoint>();
grid[xBlock][yBlock] = points;
}
p.setAssigned(false);
points.add(p);
}
/**
* Resets the assigned flag on all the points
*/
public void resetAssigned()
{
for (GridPoint p : allPoints)
{
p.setAssigned(false);
}
}
/**
* Find the unassigned point using the current search mode
* If a point is found it will have its assigned flag set to true.
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findUnassignedPoint(int xCoord, int yCoord)
{
switch (searchMode)
{
case CLOSEST:
return findClosestUnassignedPoint(xCoord, yCoord);
default:
return findHighestUnassignedPoint(xCoord, yCoord);
}
}
/**
* Find the highest assigned point within the sampling resolution from the given coordinates.
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findHighestAssignedPoint(int xCoord, int yCoord)
{
return findHighest(xCoord, yCoord, true);
}
/**
* Find the highest unassigned point within the sampling resolution from the given coordinates.
* If a point is found it will have its assigned flag set to true.
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findHighestUnassignedPoint(int xCoord, int yCoord)
{
GridPoint point = findHighest(xCoord, yCoord, false);
if (point != null)
point.setAssigned(true);
return point;
}
/**
* Find the highest point within the sampling resolution from the given coordinates with the specified assigned status.
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findHighest(int xCoord, int yCoord, boolean assigned)
{
GridPoint point = null;
int xBlock = getXBlock(xCoord);
int yBlock = getYBlock(yCoord);
double resolution2 = resolution * resolution;
if (!assigned)
{
// Use closest assigned peak to set the resolution for the unassigned search
GridPoint closestPoint = findClosestAssignedPoint(xCoord, yCoord);
if (closestPoint != null)
resolution2 = closestPoint.distance2(xCoord, yCoord);
}
// Check all surrounding blocks for highest unassigned point
float maxValue = Float.NEGATIVE_INFINITY;
for (int x = Math.max(0, xBlock - 1); x <= Math.min(grid.length - 1, xBlock + 1); x++)
{
for (int y = Math.max(0, yBlock - 1); y <= Math.min(grid[0].length - 1, yBlock + 1); y++)
{
if (grid[x][y] != null)
{
@SuppressWarnings("unchecked")
LinkedList<GridPoint> points = (LinkedList<GridPoint>) grid[x][y];
for (GridPoint p : points)
{
if (p.isAssigned() == assigned)
{
if (p.distance2(xCoord, yCoord) < resolution2)
{
//IJ.log(String.format(" x%d,y%d (%d) = %g", p.getX(), p.getY(), p.getValue(), p.distance(xCoord, yCoord)));
if (maxValue < p.getValue())
{
maxValue = p.getValue();
point = p;
}
}
}
}
}
}
}
return point;
}
/**
* Find the assigned point that matches the given coordinates.
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findExactAssignedPoint(int xCoord, int yCoord)
{
return findExact(xCoord, yCoord, true);
}
/**
* Find the unassigned point that matches the given coordinates.
* If a point is found it will have its assigned flag set to true.
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findExactUnassignedPoint(int xCoord, int yCoord)
{
GridPoint point = findExact(xCoord, yCoord, false);
if (point != null)
point.setAssigned(true);
return point;
}
/**
* Find the point that matches the given coordinates with the specified assigned status.
*
* @param xCoord
* @param yCoord
* @param assigned
* @return The GridPoint (or null)
*/
public GridPoint findExact(int xCoord, int yCoord, boolean assigned)
{
int xBlock = getXBlock(xCoord);
int yBlock = getYBlock(yCoord);
int x = Math.min(grid.length - 1, Math.max(0, xBlock));
int y = Math.min(grid[0].length - 1, Math.max(0, yBlock));
if (grid[x][y] != null)
{
@SuppressWarnings("unchecked")
LinkedList<GridPoint> points = (LinkedList<GridPoint>) grid[x][y];
for (GridPoint p : points)
{
if (p.isAssigned() == assigned && p.getX() == xCoord && p.getY() == yCoord)
{
return p;
}
}
}
return null;
}
/**
* Find the closest assigned point within the sampling resolution from the given coordinates
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findClosestAssignedPoint(int xCoord, int yCoord)
{
return findClosest(xCoord, yCoord, true);
}
/**
* Find the closest unassigned point within the sampling resolution from the given coordinates.
* If a point is found it will have its assigned flag set to true.
*
* @param xCoord
* @param yCoord
* @return The GridPoint (or null)
*/
public GridPoint findClosestUnassignedPoint(int xCoord, int yCoord)
{
GridPoint point = findClosest(xCoord, yCoord, false);
if (point != null)
point.setAssigned(true);
return point;
}
/**
* Find the closest point within the sampling resolution from the given coordinates with the specified assigned
* status.
*
* @param xCoord
* @param yCoord
* @param assigned
* @return The GridPoint (or null)
*/
public GridPoint findClosest(int xCoord, int yCoord, boolean assigned)
{
GridPoint point = null;
int xBlock = getXBlock(xCoord);
int yBlock = getYBlock(yCoord);
double resolution2 = resolution * resolution;
for (int x = Math.max(0, xBlock - 1); x <= Math.min(grid.length - 1, xBlock + 1); x++)
{
for (int y = Math.max(0, yBlock - 1); y <= Math.min(grid[0].length - 1, yBlock + 1); y++)
{
if (grid[x][y] != null)
{
@SuppressWarnings("unchecked")
LinkedList<GridPoint> points = (LinkedList<GridPoint>) grid[x][y];
for (GridPoint p : points)
{
if (p.isAssigned() == assigned)
{
final double d2 = p.distance2(xCoord, yCoord);
if (d2 < resolution2)
{
resolution2 = d2;
point = p;
}
}
}
}
}
}
return point;
}
/**
* @return the resolution
*/
public int getResolution()
{
return resolution;
}
/**
* @param searchMode
* the searchMode to set (see {@link #SEARCH_MODES} )
*/
public void setSearchMode(int searchMode)
{
this.searchMode = searchMode;
}
/**
* @return the searchMode
*/
public int getSearchMode()
{
return searchMode;
}
}