Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* "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.representation.triangulation;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import signalprocesser.voronoi.VPoint;
import signalprocesser.voronoi.representation.AbstractRepresentation;
import signalprocesser.voronoi.statusstructure.VLinkedNode;
public class TriangulationRepresentation extends AbstractRepresentation {
/* ***************************************************** */
// Constants
public static final int OUTER_VERTEXNUMBER = -1;
/* ***************************************************** */
// Static Variables
public static boolean SHOW_INTERNAL_TRIANGLES = false;
public static boolean SHOW_EDGE_LENGTHS = false;
public static boolean SHOW_DEBUG_INFO = false;
public static int MAX_EDGES_TO_REMOVE = -1;
public static int MODE_REDUCE_OUTER_BOUNDARIES = 1;
public static int MODE_GETSTATS_EXCLUDINGMSTSTATS = 2;
public static int MODE_DETERMINE_MINSPANNINGTREE = 3;
public static int MODE_DETERMINE_CLUSTERS = 4;
/* ***************************************************** */
// Variables
private int mode;
private int vertexnumber;
private Collection vertexpoints;
private CalcCutOff calccutoff = null;
private int length_cutoff = -1;
private double gradient_diff_before_cluster_cutoff = 1.2;
private final ArrayList clusters = new ArrayList();
private boolean update_statistics;
private int max_length = -1;
private int min_length = -1;
private int max_length_of_smallesttriangleedge = -1;
private int max_length_from_minimumspanningtree = -1;
/* ***************************************************** */
// Constructor
public TriangulationRepresentation() {
setReduceOuterBoundariesMode();
}
public TriangulationRepresentation(int length_cutoff) {
this(); setIntegerLengthCutoff( length_cutoff );
}
public TriangulationRepresentation(CalcCutOff calccutoff) {
this(); setCalcCutOff( calccutoff );
}
/* ***************************************************** */
// Modes
public int getMode() { return mode; }
public void setReduceOuterBoundariesMode() {
update_statistics = true;
mode = MODE_REDUCE_OUTER_BOUNDARIES;
}
public void setGetStatsMode() {
update_statistics = true;
mode = MODE_DETERMINE_MINSPANNINGTREE;
}
public void setGetStatsExcludingMSTStatsMode() {
update_statistics = true;
mode = MODE_GETSTATS_EXCLUDINGMSTSTATS;
}
public void setDetermineMinSpanningTreeMode() {
update_statistics = false;
mode = MODE_DETERMINE_MINSPANNINGTREE;
}
public void setDetermineClustersMode() {
update_statistics = false;
mode = MODE_DETERMINE_CLUSTERS;
}
/* ***************************************************** */
// Getters and Setters
public int calculateLengthCutoff() {
if ( calccutoff!=null ) {
return calccutoff.calculateCutOff(this);
} else {
return length_cutoff;
}
}
public int getIntegerLengthCutoff() {
if ( calccutoff!=null ) {
throw new RuntimeException("CalcCutOff object registered - length_cutoff variable is ignored");
}
return length_cutoff;
}
public void setIntegerLengthCutoff(int _length_cutoff) {
if ( calccutoff!=null ) {
throw new RuntimeException("CalcCutOff object registered - length_cutoff variable is ignored");
}
this.length_cutoff = _length_cutoff;
}
public CalcCutOff getCalcCutOff() { return calccutoff; }
public void setCalcCutOff( CalcCutOff _calccutoff ) {
this.calccutoff = _calccutoff;
this.length_cutoff = -1;
}
public int getMaxLength() {
if ( update_statistics ) {
return max_length;
} else {
throw new RuntimeException("Calculation of statistics are currently disabled");
}
}
public int getMinLength() {
if ( update_statistics ) {
return min_length;
} else {
throw new RuntimeException("Calculation of statistics are currently disabled");
}
}
public int getMaxLengthOfSmallestTriangleEdge() {
if ( update_statistics ) {
return max_length_of_smallesttriangleedge;
} else {
throw new RuntimeException("Calculation of statistics are currently disabled");
}
}
public int getMaxLengthOfMinimumSpanningTree() {
if ( update_statistics ) {
return max_length_from_minimumspanningtree;
} else {
throw new RuntimeException("Calculation of statistics are currently disabled");
}
}
/* ***************************************************** */
// Create Point
public VPoint createPoint(int x, int y) {
return new VVertex(x, y);
}
/* ***************************************************** */
// Data/Representation Interface Method
// Executed before the algorithm begins to process (can be used to
// initialise any data structures required)
public void beginAlgorithm(Collection points) {
// Store list of points
vertexpoints = points;
// Reset each VVertex
for ( VPoint point : points ) {
VVertex vertex = (VVertex) point;
vertex.clearEdges();
}
// Reset length values
if ( update_statistics ) {
max_length = -1;
min_length = -1;
max_length_of_smallesttriangleedge = -1;
max_length_from_minimumspanningtree = -1;
}
// Clear clusters list
clusters.clear();
// Reset the vertex number back to 1
vertexnumber = 1;
}
// Called to record that a vertex has been found
public void siteEvent( VLinkedNode n1 , VLinkedNode n2 , VLinkedNode n3 ) { }
public void circleEvent( VLinkedNode n1 , VLinkedNode n2 , VLinkedNode n3 , int circle_x , int circle_y ) {
// Do calculations for this representation
VVertex v1 = (VVertex) n1.siteevent.getPoint();
VVertex v2 = (VVertex) n2.siteevent.getPoint();
VVertex v3 = (VVertex) n3.siteevent.getPoint();
// Create Vertex between triangular vertex between points (clockwise direction)
VHalfEdge e1, e2, e3;
v1.addEdge( e1 = new VHalfEdge( vertexnumber , v1 ) );
v2.addEdge( e2 = new VHalfEdge( vertexnumber , v2 ) );
v3.addEdge( e3 = new VHalfEdge( vertexnumber , v3 ) );
// Connect half edges
e1.next = e2;
e2.next = e3;
e3.next = e1;
// Consider side lengths and update side length values
if ( update_statistics ) {
int[] lengths = new int[]{ e1.getLength() , e2.getLength() , e3.getLength() };
Arrays.sort(lengths);
if ( lengths[2] > max_length )
max_length = lengths[2];
if ( min_length < 0 || lengths[0] < min_length )
min_length = lengths[0];
if ( lengths[0] > max_length_of_smallesttriangleedge )
max_length_of_smallesttriangleedge = lengths[0];
}
// Increment the vertex number
vertexnumber++;
}
// Called when the algorithm has finished processing
public void endAlgorithm(Collection points, int lastsweeplineposition, VLinkedNode headnode) {
VHalfEdge outeredge = createOuterEdge();
if ( outeredge!=null ) {
// Calculate MST before removing edges, as this would affect the result returned
if ( mode==MODE_GETSTATS_EXCLUDINGMSTSTATS ) {
// Don't calculate minimum spanning tree
} else if ( mode==MODE_DETERMINE_CLUSTERS ) {
max_length_from_minimumspanningtree =
SharedMinimumSpanningTree.determineMSTUsingPrimsAlgorithm(outeredge.vertex, gradient_diff_before_cluster_cutoff, clusters);
} else {
max_length_from_minimumspanningtree =
SharedMinimumSpanningTree.determineMSTUsingPrimsAlgorithm(outeredge.vertex);
}
// Remove edges, but only if we're not showing the MST
if ( mode==MODE_REDUCE_OUTER_BOUNDARIES ) {
int length_cutoff = calculateLengthCutoff();
SharedEdgeRemoval.removeEdgesInOrderFromOuterBoundary(outeredge, length_cutoff);
}
}
}
private VHalfEdge createOuterEdge() {
VVertex currvertex = null;
VVertex firstvertex = null;
VHalfEdge firstedge = null;
// Find an outer edge
//System.out.println("Finding outer edge");
outerloop: {
for ( VPoint point : vertexpoints ) {
VVertex vertex = (VVertex) point;
//System.out.println(" - Vertex " + vertex.id);
// Check the vertex has edges
if ( vertex.hasEdges()==false ) continue;
// Check if the edge is an outer edge
for ( VHalfEdge edge : vertex.getEdges() ) {
// Continue until we find a non-double edge (i.e. an outer edge)
if ( edge.getConnectedVertex().isConnectedTo(vertex) ) {
//System.out.println(" + Vertex " + edge.getConnectedVertex().id + " connected");
continue;
}
// Otherwise, we're found an outer edge
firstvertex = vertex;
currvertex = edge.getConnectedVertex();
currvertex.addEdge( firstedge = new VHalfEdge(OUTER_VERTEXNUMBER,currvertex) );
//System.out.println(" - Vertex " + edge.getConnectedVertex().id + " NOT connected, adding edge to Vertex " + currvertex.id);
break outerloop;
}
}
}
// Return as there are probably less than 3 points, or this
// method has already been called!
if ( currvertex==null ) {
//throw new RuntimeException("Outer edge not found");
return null;
}
// Form an outer edge around the shape
//System.out.println("Forming outer edge");
VVertex nextvertex;
VHalfEdge prevedge = firstedge;
do {
// Find next vertex
nextvertex = null;
for ( VHalfEdge edge : currvertex.getEdges() ) {
// Continue until we find a non-double edge (i.e. an outer edge)
if ( edge.getConnectedVertex().isConnectedTo(currvertex) ) continue;
// Otherwise, we're found an outer edge
nextvertex = edge.getConnectedVertex();
break;
}
//System.out.println(" - Found next Vertex " + nextvertex.id);
// Check next vertex was found
if ( nextvertex==null ) {
throw new RuntimeException("Edge's in invalid state - didn't find next vertex");
}
// Connect to next vertex
//System.out.println(" - Added edge to " + nextvertex.id + ", connected Edge from " + prevedge.vertex.id + " to Edge from " + nextvertex.id);
nextvertex.addEdge( prevedge = new VHalfEdge(OUTER_VERTEXNUMBER,nextvertex, prevedge) );
} while ( (currvertex=nextvertex)!=firstvertex );
// Connect to edge to final edge
firstedge.next = prevedge;
// Return first edge create of the outer edge
// (doesn't really matter which edge is returned)
return firstedge;
}
/* ***************************************************** */
// Get outer boundary
public ArrayList getPointsFormingOutterBoundary() {
// Find an outer edge
VHalfEdge outeredge = findOuterEdge();
// Check is not null and next is not null
if ( outeredge==null || outeredge.next==null ) {
return null;
}
// Initialise variables
VHalfEdge curredge = outeredge;
ArrayList pointlist = new ArrayList();
do {
pointlist.add( curredge.vertex );
} while ( (curredge=curredge.next).next!=null && curredge!=outeredge );
// Add the first/final point as well to close the shape
if ( curredge==outeredge ) {
pointlist.add( curredge.vertex );
}
// Return the point list
return pointlist;
}
/* ***************************************************** */
// Paint Method
public void paint(Graphics2D g) {
if ( mode==MODE_REDUCE_OUTER_BOUNDARIES && SHOW_INTERNAL_TRIANGLES==false ) {
// Find an outer edge
VHalfEdge outeredge = findOuterEdge();
// Check is not null and next is not null
if ( outeredge==null || outeredge.next==null ) {
return;
}
// Initialise variables
VHalfEdge curredge = outeredge;
do {
g.drawLine( curredge.getX() , curredge.getY() , curredge.next.getX() , curredge.next.getY() );
// Draw edge lengths
if ( SHOW_EDGE_LENGTHS ) {
VVertex vertex = curredge.vertex;
VVertex vertex2 = curredge.getConnectedVertex();
g.drawString( Integer.toString(curredge.getLength()) , (int)(vertex.x + (vertex2.x-vertex.x)*0.5 + 3.0) , (int)(vertex.y + (vertex2.y-vertex.y)*0.5 - 3.0));
}
// Draw caption string for node
if ( SHOW_DEBUG_INFO ) {
VVertex vertex = curredge.vertex;
g.drawString(Integer.toString(vertex.id), vertex.x+6, vertex.y);
}
} while ( (curredge=curredge.next).next!=null && curredge!=outeredge );
} else {
// Paint for this method
for ( VPoint point : vertexpoints ) {
VVertex vertex = (VVertex) point;
// Check the vertex has edges
if ( vertex.hasEdges()==false ) {
continue;
}
// Paint each of those edges
for ( VHalfEdge edge : vertex.getEdges() ) {
// Simple addition to show MST
if ( mode!=MODE_REDUCE_OUTER_BOUNDARIES && edge.shownonminimumspanningtree==false ) continue;
// Draw the line
//if ( edge.next==null) continue;
VVertex vertex2 = edge.next.vertex;
//if ( vertex2==null ) return;
g.drawLine( vertex.x , vertex.y , vertex2.x , vertex2.y );
if ( SHOW_EDGE_LENGTHS ) {
g.drawString( Integer.toString(edge.getLength()) , (int)(vertex.x + (vertex2.x-vertex.x)*0.5 + 3.0) , (int)(vertex.y + (vertex2.y-vertex.y)*0.5 - 3.0));
}
//g.fillOval( (int)(vertex.x + (vertex2.x-vertex.x)*0.85 - 3.0) , (int)(vertex.y + (vertex2.y-vertex.y)*0.85 - 3.0) , 6 , 6 );
}
// Draw caption string for node
if ( SHOW_DEBUG_INFO ) {
g.drawString(Integer.toString(vertex.id), vertex.x+6, vertex.y);
}
}
}
}
private VHalfEdge findOuterEdge() {
for ( VPoint point : vertexpoints ) {
VVertex vertex = (VVertex) point;
// Check the vertex has edges
if ( vertex.hasEdges()==false ) {
continue;
}
// Paint each of those edges
for ( VHalfEdge edge : vertex.getEdges() ) {
if ( edge.isOuterEdge() ) {
return edge;
}
}
}
return null;
}
/* ***************************************************** */
abstract static public class CalcCutOff {
abstract public int calculateCutOff(TriangulationRepresentation representation);
}
/* ***************************************************** */
}