Mercurial > dive4elements > gnv-client
diff gnv-artifacts/src/main/java/de/intevation/gnv/raster/Vectorizer.java @ 801:d766fe2d917a
More javadoc.
gnv-artifacts/trunk@883 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 06 Apr 2010 16:53:43 +0000 |
parents | 6cff63d0c434 |
children | f953c9a559d8 |
line wrap: on
line diff
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/raster/Vectorizer.java Tue Apr 06 13:07:11 2010 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/raster/Vectorizer.java Tue Apr 06 16:53:43 2010 +0000 @@ -10,14 +10,30 @@ import org.apache.log4j.Logger; /** + * Instances of this class are able to vectorize 2D integer arrays + * with a kind of flood filling regions detection mechanism to + * a set of line strings and polygons. + * * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a> */ public class Vectorizer { private static Logger log = Logger.getLogger(Vectorizer.class); + /** + * Callback to process the found line strings and polygons. + */ public interface RingsHandler { + /** + * Called from {@link #process(de.intevation.gnv.raster.Vectorizer.RingsHandler) } + * to give the found features to the postprocessing backend. + * @param rings The found line strings and polygons. + * @param value The integer value of the raster surrounded by + * the features. + * @param width The width of the index space of the vectorized data. + * @param height The height of the index space of the vectorized data. + */ void handleRings( List<Edge> rings, int value, @@ -26,27 +42,65 @@ } // interface RingsHandler + /** + * Doubly link list representing a line string or a polygon. + */ public static final class Edge { + /** + * The predecessor. + */ public Edge prev; + /** + * The successor. + */ public Edge next; + /** + * Index of first vertex. To separate x and y values + * you have to divide the value by the width of the + * index space. + */ public int a; + /** + * Index of second vertex. To separate x and y values + * you have to divide the value by the width of the + * index space. + */ public int b; + /** + * Default constructor. + */ public Edge() { } + /** + * Constructor to create Edge with two vertices. + * @param a The first vertex. + * @param b The second vertex. + */ public Edge(int a, int b) { this.a = a; this.b = b; } + /** + * Copy constructor + * @param other The edge to clone. + */ public Edge(Edge other) { a = other.a; b = other.b; } + /** + * Chain a given edge segment to this segment. The + * side of the chaining is determined by a given + * parameter. + * @param other The segment to chain. + * @param found The side to chain. + */ public void chain(Edge other, int found) { if (found == a) { @@ -64,6 +118,11 @@ throw new IllegalStateException("cannot chain"); } + /** + * Tells if the list is complete which means that this + * edge list is a closed polygon. + * @return true if edge list is closed else false. + */ public boolean isComplete() { Edge current = this; do { @@ -76,6 +135,11 @@ return true; } + /** + * Returns the length of this edge list in next direction. + * Segments in prev direction are ignored. + * @return The length of this edge list. + */ public int length() { int length = 0; Edge current = this; @@ -84,24 +148,47 @@ return length; } - public Edge head() { - Edge current = this; - while (current.prev != null) { - current = current.prev; - } - return current; - } + /** + * Returns the head node of this edge list. + * @return The head node. + */ + public Edge head() { + Edge current = this; + while (current.prev != null) { + current = current.prev; + } + return current; + } + /** + * Hashes the two vertex indices to a common value. + * @return The hash value. + */ + @Override public int hashCode() { return (a << 16) | b; } + /** + * Two edges are considered equal if they have the same + * a and b vertices. + * @param other The other edge. + * @return true if the edges are equal else false. + */ + @Override public boolean equals(Object other) { Edge e = (Edge)other; return a == e.a && b == e.b; } } // class Edge + /** + * Simplifies a given edge list by removing collinear vertices. + * Attention: The original list is modified. + * @param edge The edge list to simplify. + * @param width The width of the vertex index space. + * @return The simplified list. + */ protected static Edge simplify(Edge edge, int width) { Edge e1 = edge, start = edge; @@ -150,55 +237,127 @@ return start; } + /** + * The raster to be traced. + */ protected int [] raster; + /** + * The width of the raster. + */ protected int width; + /** + * Map of the currently open edges. + */ protected TIntObjectHashMap openEdges; + /** + * List of rings already found. + */ protected List<Edge> rings; + /** + * Flag to signal if a simplification should be performed + * after a ring is completed. + */ protected boolean simplify; + /** + * Default constructor. Simplification is turned on. + */ public Vectorizer() { this(true); } + /** + * Constructor to create a vectorized with an explicit + * simplification policy. + * @param simplify Indicates if simplification should be + * used on ring completion. + */ public Vectorizer(boolean simplify) { openEdges = new TIntObjectHashMap(); rings = new ArrayList<Edge>(); this.simplify = simplify; } + /** + * Constructor to create a vectorizer with a given raster and width. + * Simplification is turn on. + * @param raster The raster to be vectorized. + * @param width The width of the raster. + */ public Vectorizer(int [] raster, int width) { this(true, raster, width); } + /** + * Constructor to create a vectorizer with a given raster, width + * and an explicit simplification policy. + * @param simplify Indicates if simplification should be + * used on ring completion. + * @param raster The raster to be vectorized. + * @param width The width of the raster. + */ public Vectorizer(boolean simplify, int [] raster, int width) { this(simplify); this.raster = raster; this.width = width; } + /** + * Returns (x, y+1) for given vertex in index space. + * @param i vertex in index space. + * @param w width of raster. + * @return (x, y+1) in index space. + */ public static final int tl(int i, int w) { int x = i % w; int y = i / w; return x + (w + 1)*y; } + /** + * Returns tl(i, w) + 1. + * @param i vertex in index space. + * @param w width of raster. + * @return tl(i, w) + 1. + */ public static final int tr(int i, int w) { return tl(i, w) + 1; } + /** + * Returns tl(i, w) + w + 1. + * @param i vertex in index space. + * @param w width of raster. + * @return tl(i, w) + w + 1. + */ public static final int bl(int i, int w) { return tl(i, w) + w + 1; } + /** + * Returns bl(i, w) + 1. + * @param i vertex in index space. + * @param w width of raster. + * @return bl(i, w) + 1. + */ public static final int br(int i, int w) { return bl(i, w) + 1; } + /** + * Resets open resources after a set of features were found. + */ protected void resetRegion() { openEdges.clear(); rings.clear(); } + /** + * Adds an edge to the map of open edges, joins it + * with its direct neighbors of if complete add the + * list to the complete features. + * @param edge + */ protected void emit(Edge edge) { Edge otherA = (Edge)openEdges.remove(edge.a); @@ -224,6 +383,12 @@ } } + /** + * Vectorize the raster. The found features are fed into + * the given ring handler. + * @param handler The RingHandler to postprocess the found features. + * @return The number of regions found. + */ public int process(RingsHandler handler) { BitSet visited = new BitSet(raster.length);