Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/raster/Vectorizer.java @ 522:c896282c2601
Issue 156 solved. Added width, height and points as parameter to svg and pdf output mode. Width and height have an effact on the width and height of the export, points is a boolean property which enables/disables the drawing of data points.
gnv-artifacts/trunk@616 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Mon, 25 Jan 2010 09:18:31 +0000 |
parents | 92b7ccbf6163 |
children | 9a828e5a2390 |
line wrap: on
line source
package de.intevation.gnv.raster; import java.util.BitSet; import java.util.List; import java.util.ArrayList; import gnu.trove.TIntStack; import gnu.trove.TIntObjectHashMap; import org.apache.log4j.Logger; /** * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) */ public class Vectorizer { private static Logger log = Logger.getLogger(Vectorizer.class); public interface RingsHandler { void handleRings( List<Edge> rings, int value, int width, int height); } // interface RingsHandler public static final class Edge { public Edge prev; public Edge next; public int a; public int b; public Edge() { } public Edge(int a, int b) { this.a = a; this.b = b; } public Edge(Edge other) { a = other.a; b = other.b; } public void chain(Edge other, int found) { if (found == a) { other.next = this; prev = other; return; } if (found == b) { next = other; other.prev = this; return; } throw new IllegalStateException("cannot chain"); } public boolean isComplete() { Edge current = this; do { if (current.prev == null || current.next == null) { return false; } current = current.next; } while (current != this); return true; } public int length() { int length = 0; Edge current = this; do { ++length; } while ((current = current.next) != null && current != this); return length; } public Edge head() { Edge current = this; while (current.prev != null) { current = current.prev; } return current; } public int hashCode() { return (a << 16) | b; } public boolean equals(Object other) { Edge e = (Edge)other; return a == e.a && b == e.b; } } // class Edge protected static Edge simplify(Edge edge, int width) { Edge e1 = edge, start = edge; int length = edge.length(); if (length < 2) { return e1; } Edge e2 = edge.next; int count = 0; do { int e1x = e1.a % width; int e1y = e1.a / width; int e2x = e1.b % width; int e2y = e1.b / width; int e3x = e2.b % width; int e3y = e2.b / width; if ((e1x == e2x && e2x == e3x && e1x == e3x) || (e1y == e2y && e2y == e3y && e1y == e3y)) { e1.b = e2.b; Edge removed = e1.next; e1.next = e2.next; if (e1.next != null) { e1.next.prev = e1; } e2 = e1.next; count = 0; --length; if (removed == start) { start = e1; } } else { e1 = e1.next; e2 = e2.next; ++count; } } while (length > 1 && e2 != null && count < length + 2); return start; } protected int [] raster; protected int width; protected TIntObjectHashMap openEdges; protected List<Edge> rings; protected boolean simplify; public Vectorizer() { this(true); } public Vectorizer(boolean simplify) { openEdges = new TIntObjectHashMap(); rings = new ArrayList<Edge>(); this.simplify = simplify; } public Vectorizer(int [] raster, int width) { this(true, raster, width); } public Vectorizer(boolean simplify, int [] raster, int width) { this(simplify); this.raster = raster; this.width = width; } public static final int tl(int i, int w) { int x = i % w; int y = i / w; return x + (w + 1)*y; } public static final int tr(int i, int w) { return tl(i, w) + 1; } public static final int bl(int i, int w) { return tl(i, w) + w + 1; } public static final int br(int i, int w) { return bl(i, w) + 1; } protected void resetRegion() { openEdges.clear(); rings.clear(); } protected void emit(Edge edge) { Edge otherA = (Edge)openEdges.remove(edge.a); if (otherA != null) { otherA.chain(edge, edge.a); } Edge otherB = (Edge)openEdges.remove(edge.b); if (otherB != null) { otherB.chain(edge, edge.b); } if (edge.isComplete()) { rings.add(simplify ? simplify(edge, width + 1) : edge); } else { if (otherA == null) { openEdges.put(edge.a, edge); } if (otherB == null) { openEdges.put(edge.b, edge); } } } public int process(RingsHandler handler) { BitSet visited = new BitSet(raster.length); TIntStack stack = new TIntStack(); int regions = 0; int height = raster.length / width; for (int i = 0; i < raster.length; ++i) { if (visited.get(i)) { continue; } ++regions; int currentValue = raster[i]; visited.set(i); int current = i; visited.set(current); for (;;) { int tl = tl(current, width); int tr = tr(current, width); int bl = bl(current, width); int br = br(current, width); int t = current - width; if (t < 0) { emit(new Edge(tr, tl)); } else { if (raster[t] != currentValue) { emit(new Edge(tr, tl)); } else { if (!visited.get(t)) { visited.set(t); stack.push(t); } } } int b = current + width; if (b >= raster.length) { emit(new Edge(bl, br)); } else { if (raster[b] != currentValue) { emit(new Edge(bl, br)); } else { if (!visited.get(b)) { visited.set(b); stack.push(b); } } } int x = current % width; if (x == 0) { emit(new Edge(tl, bl)); } else { int l = current - 1; if (raster[l] != currentValue) { emit(new Edge(tl, bl)); } else { if (!visited.get(l)) { visited.set(l); stack.push(l); } } } if (x == width - 1) { emit(new Edge(br, tr)); } else { int r = current + 1; if (raster[r] != currentValue) { emit(new Edge(br, tr)); } else { if (!visited.get(r)) { visited.set(r); stack.push(r); } } } if (stack.size() == 0) { break; } current = stack.pop(); } handler.handleRings( rings, currentValue, width + 1, height + 1); resetRegion(); } return regions; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: