sascha@437: package de.intevation.gnv.raster; sascha@437: sascha@437: import java.util.List; sascha@437: import java.util.HashSet; sascha@437: import java.util.HashMap; sascha@437: import java.util.ArrayList; sascha@437: import java.util.Collection; sascha@437: sascha@447: import org.apache.log4j.Logger; sascha@447: sascha@447: import gnu.trove.TIntHashSet; sascha@437: import gnu.trove.TIntObjectHashMap; sascha@437: import gnu.trove.TDoubleArrayList; sascha@447: import gnu.trove.TObjectProcedure; sascha@437: sascha@437: import de.intevation.gnv.raster.Vectorizer.RingsHandler; sascha@437: import de.intevation.gnv.raster.Vectorizer.Edge; sascha@437: sascha@437: import de.intevation.gnv.math.IJKey; sascha@437: sascha@437: import de.intevation.gnv.jfreechart.PolygonSeries; sascha@437: import de.intevation.gnv.jfreechart.CompactXYItems; sascha@437: sascha@437: /** sascha@437: * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) sascha@437: */ sascha@437: public class IsoPolygonSeriesProducer sascha@437: implements RingsHandler sascha@437: { sascha@448: private static Logger log = Logger.getLogger( sascha@448: IsoPolygonSeriesProducer.class); sascha@447: sascha@447: public static final Float LINE_WIDTH = Float.valueOf(0.1f); sascha@447: sascha@448: public interface AttributeGenerator { sascha@437: sascha@448: Object generateAttribute(int neighbor1, int neighbor2); sascha@437: sascha@448: } // interface AttributeGenerator sascha@437: sascha@437: protected HashMap open; sascha@437: protected HashMap commonOpen; sascha@437: protected HashMap> complete; sascha@437: sascha@437: protected int width; sascha@437: protected int height; sascha@437: sascha@437: protected double minX; sascha@437: protected double minY; sascha@437: protected double maxX; sascha@437: protected double maxY; sascha@437: sascha@437: public IsoPolygonSeriesProducer( sascha@437: double minX, double minY, sascha@437: double maxX, double maxY sascha@437: ) { sascha@437: this.minX = minX; sascha@437: this.minY = minY; sascha@437: this.maxX = maxX; sascha@437: this.maxY = maxY; sascha@437: sascha@437: open = new HashMap(); sascha@437: commonOpen = new HashMap(); sascha@437: complete = new HashMap>(); sascha@437: } sascha@437: sascha@437: public void handleRings( sascha@437: List rings, sascha@437: int value, sascha@437: int width, sascha@437: int height sascha@437: ) { sascha@437: if (value == -1) { sascha@437: return; sascha@437: } sascha@437: this.width = width; sascha@437: this.height = height; sascha@437: sascha@437: Integer v = Integer.valueOf(value); sascha@437: sascha@437: for (Edge head: rings) { sascha@437: Edge current = head; sascha@437: do { sascha@437: Integer neighbor = open.remove(current); sascha@437: sascha@437: if (neighbor != null) { sascha@437: IJKey pair = new IJKey(value, neighbor.intValue()); sascha@437: pair.sort(); sascha@437: sascha@437: TIntObjectHashMap co = commonOpen.get(pair); sascha@437: sascha@437: if (co == null) { sascha@437: commonOpen.put(pair, co = new TIntObjectHashMap()); sascha@437: } sascha@437: sascha@437: Edge edge = new Edge(current); sascha@437: sascha@437: Edge otherA = (Edge)co.remove(edge.a); sascha@437: if (otherA != null) { sascha@437: otherA.chain(edge, edge.a); sascha@437: } sascha@437: sascha@437: Edge otherB = (Edge)co.remove(edge.b); sascha@437: if (otherB != null) { sascha@437: otherB.chain(edge, edge.b); sascha@437: } sascha@437: sascha@437: if (edge.isComplete()) { sascha@437: ArrayList list = complete.get(pair); sascha@437: if (list == null) { sascha@437: complete.put(pair, list = new ArrayList()); sascha@437: } sascha@437: list.add(Vectorizer.simplify(edge, width)); sascha@437: } sascha@437: else { sascha@437: if (otherA == null) { sascha@437: co.put(edge.a, edge); sascha@437: } sascha@437: if (otherB == null) { sascha@437: co.put(edge.b, edge); sascha@437: } sascha@437: } sascha@437: } sascha@437: else { sascha@437: Edge edge = new Edge(current.b, current.a); sascha@437: open.put(edge, v); sascha@437: } sascha@437: sascha@437: current = current.next; sascha@437: } sascha@437: while (current != head); sascha@437: } // for all rings sascha@437: sascha@437: } // handleRings sascha@437: sascha@437: public Collection getSeries() { sascha@437: return getSeries(null); sascha@437: } sascha@437: sascha@448: public Collection getSeries( sascha@448: AttributeGenerator attributeGenerator sascha@448: ) { sascha@437: ArrayList series = new ArrayList(); sascha@447: sascha@437: double b1 = minX; sascha@437: double m1 = width != 1 sascha@437: ? (maxX - minX)/(width-1) sascha@437: : 0d; sascha@437: sascha@437: double b2 = minY; sascha@437: double m2 = height != 1 sascha@437: ? (maxY - minY)/(height-1) sascha@437: : 0d; sascha@437: sascha@437: // join keys of complete and open polygons sascha@437: HashSet pairs = new HashSet(); sascha@437: for (IJKey key: complete.keySet()) { sascha@437: pairs.add(key); sascha@437: } sascha@437: for (IJKey key: commonOpen.keySet()) { sascha@437: pairs.add(key); sascha@437: } sascha@437: sascha@437: TDoubleArrayList vertices = new TDoubleArrayList(); sascha@437: sascha@437: for (IJKey key: pairs) { sascha@437: PolygonSeries ps = new PolygonSeries(); sascha@437: sascha@437: // process complete sascha@437: ArrayList completeList = complete.get(key); sascha@437: if (completeList != null) { sascha@437: for (Edge head: completeList) { sascha@437: Edge current = head; sascha@437: do { sascha@437: vertices.add(m1*(current.a % width) + b1); sascha@437: vertices.add(m2*(current.a / width) + b2); sascha@437: } sascha@437: while ((current = current.next) != head); sascha@447: // add head again to close shape sascha@447: vertices.add(m1*(head.a % width) + b1); sascha@447: vertices.add(m2*(head.a / width) + b2); sascha@437: ps.addRing(new CompactXYItems(vertices.toNativeArray())); sascha@437: vertices.clear(); sascha@437: } sascha@437: } sascha@437: sascha@437: // process open sascha@437: TIntObjectHashMap map = commonOpen.get(key); sascha@447: sascha@437: if (map != null) { sascha@448: final ArrayList headList = new ArrayList(); sascha@448: map.forEachValue(new TObjectProcedure() { sascha@448: TIntHashSet headSet = new TIntHashSet(); sascha@448: public boolean execute(Object value) { sascha@448: Edge head = ((Edge)value).head(); sascha@448: if (headSet.add(head.a)) { sascha@448: headList.add(head); sascha@448: } sascha@448: return true; sascha@448: } sascha@448: }); sascha@447: sascha@447: for (Edge head: headList) { sascha@447: sascha@437: head = Vectorizer.simplify(head, width); sascha@437: Edge current = head, last = head; sascha@437: do { sascha@437: vertices.add(m1*(current.a % width) + b1); sascha@437: vertices.add(m2*(current.a / width) + b2); sascha@437: last = current; sascha@437: } sascha@437: while ((current = current.next) != null); sascha@437: // add b from tail sascha@437: vertices.add(m1*(last.b % width) + b1); sascha@437: vertices.add(m2*(last.b / width) + b2); sascha@437: ps.addRing(new CompactXYItems(vertices.toNativeArray())); sascha@437: vertices.clear(); sascha@437: } // for all in common open sascha@437: } // if map defined for key sascha@447: sascha@448: if (ps.getItemCount() > 0) { sascha@447: series.add(ps); sascha@448: if (attributeGenerator != null) { sascha@448: Object attribute = attributeGenerator sascha@448: .generateAttribute(key.i, key.j); sascha@448: sascha@448: if (attribute != null) { sascha@448: ps.setAttribute("label", attribute); sascha@448: } sascha@447: } sascha@447: ps.setAttribute("line.width", LINE_WIDTH); sascha@447: } sascha@437: } // for all pairs sascha@437: sascha@437: return series; sascha@437: } sascha@448: sascha@448: public void clear() { sascha@448: open.clear(); sascha@448: complete.clear(); sascha@448: commonOpen.clear(); sascha@448: } sascha@437: } sascha@437: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: