signalprocesser.voronoi.VoronoiShared Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mia-algorithms Show documentation
Show all versions of mia-algorithms Show documentation
ModularImageAnalysis (MIA) is an ImageJ plugin which provides a modular framework for assembling image and object analysis workflows. Detected objects can be transformed, filtered, measured and related. Analysis workflows are batch-enabled by default, allowing easy processing of high-content datasets.
/*
* "Concave" hulls by Glenn Hudson and Matt Duckham
*
* Source code downloaded from https://archive.md/l3Un5#selection-571.0-587.218 on 3rd November 2021.
*
* - This software is Copyright (C) 2008 Glenn Hudson released under Gnu Public License (GPL). Under
* GPL you are free to use, modify, and redistribute the software. Please acknowledge Glenn Hudson
* and Matt Duckham as the source of this software if you do use or adapt the code in further research
* or other work. For full details of GPL see http://www.gnu.org/licenses/gpl-3.0.txt.
* - This software comes with no warranty of any kind, expressed or implied.
*
* A paper with full details of the characteristic hulls algorithm is published in Pattern Recognition.
* Duckham, M., Kulik, L., Worboys, M.F., Galton, A. (2008) Efficient generation of simple polygons for
* characterizing the shape of a set of points in the plane. Pattern Recognition v41, 3224-3236
*
* The software was developed by Glenn Hudson while working with me as an RA. The characteristic shapes
* algorithm is collaborative work between Matt Duckham, Lars Kulik, Antony Galton, and Mike Worboys.
*
*/
package signalprocesser.voronoi;
import java.awt.Shape;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import signalprocesser.voronoi.eventqueue.VCircleEvent;
import signalprocesser.voronoi.eventqueue.VSiteEvent;
public class VoronoiShared {
// note: the order is very important
// make sure index 0 remains (-b + bsqrdplus4ac), and 1 (-b - bsqrdplus4ac)
public static double[] solveQuadratic(double a, double b, double c) {
if (a == 0.0) {
if (b != 0.0) {
double answers[] = new double[1];
answers[0] = -1 * c / b;
return answers;
} else {
throw new RuntimeException("Only given a non-zero c value");
}
} else {
double answers[] = new double[2];
double bsqrdplus4ac = Math.sqrt(b * b - 4d * a * c);
answers[0] = (-b + bsqrdplus4ac) / ( 2d * a );
answers[1] = (-b - bsqrdplus4ac) / ( 2d * a );
return answers;
}
}
public static VCircleEvent calculateCenter(VSiteEvent u, VSiteEvent v, VSiteEvent w) {
double a = (u.getX() - v.getX())*(v.getY() - w.getY()) - (u.getY() - v.getY())*(v.getX() - w.getX());
if ( a > 0 ) {
double b1 = (u.getX() - v.getX())*(u.getX() + v.getX()) + (u.getY() - v.getY())*(u.getY() + v.getY());
double b2 = (v.getX() - w.getX())*(v.getX() + w.getX()) + (v.getY() - w.getY())*(v.getY() + w.getY());
VCircleEvent centerpoint = new VCircleEvent();
double x = ( b1*(double)(v.getY() - w.getY()) - b2*(double)(u.getY() - v.getY()) ) / ( 2.0 * a );
double center_y = ( b2*(double)(u.getX() - v.getX()) - b1*(double)(v.getX() - w.getX()) ) / ( 2.0 * a );
centerpoint.setX( (int) x );
centerpoint.setY( (int)( center_y + Math.sqrt( (x-u.getX())*(x-u.getX()) + (center_y-u.getY())*(center_y-u.getY()) ) ) );
centerpoint.setCenterY( (int) center_y );
return centerpoint;
} else {
return null;
}
}
// See http://astronomy.swin.edu.au/~pbourke/geometry/polyarea/ for
// explanation as to how area is calculated
public static double calculateAreaOfShape(ArrayList points) {
// If less than or equal to 2 points, return 0
if ( points.size()<=2 ) return 0.0;
// Otherwise, calcualte area
int area = 0;
VPoint first = points.get(0);
VPoint prev, curr = first;
for ( int x=1 ; x=0 ) {
return ( area / 2.0 );
} else {
return ( area / -2.0 );
}
}
public static double calculatePerimeterOfShape(ArrayList points) {
// If less than or equal to 2 points, return 0
if ( points.size()<=1 ) return 0.0;
// Otherwise, calcualte area
double perimeter = 0;
VPoint first = points.get(0);
VPoint prev, curr = first;
for ( int x=1 ; x (" + curr[0] + "," + curr[1] + ") - Area=" + (prev[0] * curr[1] - curr[0] * prev[1]) + ", Subarea=" + subarea);
// Continue
continue;
} else if ( type==PathIterator.SEG_CLOSE ) {
// Add final area to close shape
if ( first[0]!=prev[0] || first[1]!=prev[1] ) {
subarea += prev[0] * first[1] - first[0] * prev[1];
//System.out.println(" - (" + prev[0] + "," + prev[1] + ") --> (" + first[0] + "," + first[1] + ") - Area=" + (prev[0] * first[1] - first[0] * prev[1]) + ", Subarea=" + subarea);
} else {
//System.out.println(" - (" + prev[0] + "," + prev[1] + ") --> (" + first[0] + "," + first[1] + ") - Area=" + (prev[0] * first[1] - first[0] * prev[1]) + ", Subarea=" + subarea + " -- identical?");
}
// Add subarea to the total area
totalarea += ( subarea>=0 ? subarea : -1 * subarea );
//System.out.println(" - Subarea=" + ( subarea>=0 ? subarea : -1 * subarea ) + " --> Total Area=" + totalarea);
// Move to next element
pathiter.next();
// Check if all iterations have been done
if ( pathiter.isDone() ) {
//System.out.println(" - Returning area of " + (totalarea / 2.0) + " (1)");
return totalarea / 2.0;
}
// Break (new shape to consider)
break;
} else {
throw new RuntimeException("Expected either PathIterator.SEG_LINETO or SEG_CLOSE; instead type=" + formatPathIteratorType(type));
}
}
}
}
private static String formatPathIteratorType(int type) {
switch ( type ) {
case PathIterator.SEG_CLOSE:
return "SEG_CLOSE";
case PathIterator.SEG_CUBICTO:
return "SEG_CUBICTO";
case PathIterator.SEG_LINETO:
return "SEG_LINETO";
case PathIterator.SEG_MOVETO:
return "SEG_MOVETO";
case PathIterator.SEG_QUADTO:
return "SEG_QUADTO";
default:
return "UKNOWNTYPE (" + type + ")";
}
}
}