Index: src/openmap/com/bbn/openmap/omGraphics/OMAreaList.java =================================================================== --- src/openmap/com/bbn/openmap/omGraphics/OMAreaList.java (revision 2264) +++ src/openmap/com/bbn/openmap/omGraphics/OMAreaList.java (working copy) @@ -94,7 +94,7 @@ */ public synchronized boolean generate(Projection p, boolean forceProjectAll) { boolean isGenerated = super.generate(p, forceProjectAll); - if (shape != null) { + if ((shape != null) && (shape.getCurrentPoint() != null)) { shape.closePath(); } return isGenerated; Index: src/openmap/com/bbn/openmap/ext/jts/JTS.java =================================================================== --- src/openmap/com/bbn/openmap/ext/jts/JTS.java (revision 0) +++ src/openmap/com/bbn/openmap/ext/jts/JTS.java (revision 0) @@ -0,0 +1,129 @@ +/* + * + * Copyright 2012 BBN Technologies + * + */ +package com.bbn.openmap.ext.jts; + +import java.util.ArrayList; +import java.util.List; + +import com.bbn.openmap.proj.Projection; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Polygon; + +/** + * A collection of utility methods for using JTS in OpenMap + */ +public class JTS { + + private JTS() { + + } + + /** + * Create a JTS {@link Geometry} for the current view of the given OpenMap + * {@link Projection} expanded with the given pixel buffer. The coordinates + * are all in pixel space. + * + * @param gf + * @param proj + * @param buffer + * @return + */ + public static Polygon createXYViewPolygon(GeometryFactory gf, Projection proj, int buffer) { + Coordinate[] coords = new Coordinate[5]; + coords[0] = new Coordinate(-buffer, proj.getHeight() + buffer); + coords[1] = new Coordinate(proj.getWidth() + buffer, proj.getHeight() + buffer); + coords[2] = new Coordinate(proj.getWidth() + buffer, -buffer); + coords[3] = new Coordinate(-buffer, -buffer); + coords[4] = coords[0]; + LinearRing ring = gf.createLinearRing(coords); + return gf.createPolygon(ring, null); + } + + + public static Geometry createRectangle(GeometryFactory gf, double minx, double miny, double maxx, double maxy) { + Coordinate[] coords = new Coordinate[5]; + coords[0] = new Coordinate(minx, maxy); + coords[1] = new Coordinate(maxx, maxy); + coords[2] = new Coordinate(maxx, miny); + coords[3] = new Coordinate(minx, miny); + coords[4] = coords[0]; + LinearRing ring = gf.createLinearRing(coords); + return gf.createPolygon(ring, null); + } + + /** + * Clip the given List of xypnts to match the given clipGeometry. The result + * is manipulated in to the xypnts List. + * + * @param gf + * @param clipGeometry + * @param xypnts + */ + public static void clip(GeometryFactory gf, Geometry clipGeometry, List xypnts) { + int size = xypnts.size(); + List newxypnts = new ArrayList(size); + + for (int i = 0; i < size; i += 2) { + float[] xpts = xypnts.get(i); + float[] ypts = xypnts.get(i + 1); + + // check if the geometry needs to be clipped + if (contains(clipGeometry.getEnvelopeInternal(), xpts, ypts)) { + newxypnts.add(xpts); + newxypnts.add(ypts); + continue; + } + + CoordinateSequence coords = new XYCoordinateSequence(xpts, ypts); + Geometry original = null; + + // try to figure out if it is a line or a polygon + if (coords.getCoordinate(0).equals2D(coords.getCoordinate(coords.size() - 1))) { + LinearRing ring = gf.createLinearRing(coords); + original = gf.createPolygon(ring, null); + } else { + original = gf.createLineString(coords); + } + + Geometry intersection = original.intersection(clipGeometry); + + // the intersection might result in multiple geometries + int numGeometries = intersection.getNumGeometries(); + for (int j = 0; j < numGeometries; j++) { + Geometry intersectionPart = intersection.getGeometryN(j); + int numPoints = intersectionPart.getNumPoints(); + + float[] newxpts = new float[numPoints]; + float[] newypts = new float[numPoints]; + + XYCoordianteSequenceExtractorFilter filter = new XYCoordianteSequenceExtractorFilter(newxpts, newypts); + intersectionPart.apply(filter); + + newxypnts.add(newxpts); + newxypnts.add(newypts); + } + + } + + xypnts.clear(); + xypnts.addAll(newxypnts); + } + + private static boolean contains(Envelope envelope, float[] xpts, float[] ypts) { + for (int i = 0; i < xpts.length; i++) { + if (!envelope.contains(xpts[i], ypts[i])) { + return false; + } + } + return true; + } + +} Index: src/openmap/com/bbn/openmap/ext/jts/XYCoordinateSequence.java =================================================================== --- src/openmap/com/bbn/openmap/ext/jts/XYCoordinateSequence.java (revision 0) +++ src/openmap/com/bbn/openmap/ext/jts/XYCoordinateSequence.java (revision 0) @@ -0,0 +1,102 @@ +/* + * + * Copyright 2012 BBN Technologies + * + */ +package com.bbn.openmap.ext.jts; + +import com.bbn.openmap.util.DeepCopyUtil; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Envelope; + +class XYCoordinateSequence + implements CoordinateSequence { + + private float[] xpts; + private float[] ypts; + + public XYCoordinateSequence(float[] xpts, float[] ypts) { + this.xpts = xpts; + this.ypts = ypts; + } + + public XYCoordinateSequence(int size) { + this(new float[size], new float[size]); + } + + public int getDimension() { + return 2; + } + + public Coordinate getCoordinate(int i) { + Coordinate c = new Coordinate(); + getCoordinate(i, c); + return c; + } + + public Coordinate getCoordinateCopy(int i) { + return getCoordinate(i); + } + + public void getCoordinate(int index, Coordinate coord) { + coord.x = xpts[index]; + coord.y = ypts[index]; + coord.z = Double.NaN; + } + + public double getX(int index) { + return xpts[index]; + } + + public double getY(int index) { + return ypts[index]; + } + + public double getOrdinate(int index, int ordinateIndex) { + switch (ordinateIndex) { + case 0: + return xpts[index]; + case 1: + return ypts[index]; + default: + return Double.NaN; + } + } + + public int size() { + return xpts.length; + } + + public void setOrdinate(int index, int ordinateIndex, double value) { + switch (ordinateIndex) { + case 0: + xpts[index] = (float) value; + break; + case 1: + ypts[index] = (float) value; + break; + } + } + + public Coordinate[] toCoordinateArray() { + Coordinate[] cs = new Coordinate[size()]; + for (int i = 0; i < cs.length; i++) { + cs[i] = getCoordinate(i); + } + return cs; + } + + public Envelope expandEnvelope(Envelope env) { + for (int i = 0; i < xpts.length; i++) { + env.expandToInclude(xpts[i], ypts[i]); + } + return env; + } + + @Override + public Object clone() { + return new XYCoordinateSequence(DeepCopyUtil.deepCopy(xpts), DeepCopyUtil.deepCopy(ypts)); + } + +} Index: src/openmap/com/bbn/openmap/ext/jts/XYCoordianteSequenceExtractorFilter.java =================================================================== --- src/openmap/com/bbn/openmap/ext/jts/XYCoordianteSequenceExtractorFilter.java (revision 0) +++ src/openmap/com/bbn/openmap/ext/jts/XYCoordianteSequenceExtractorFilter.java (revision 0) @@ -0,0 +1,39 @@ +/* + * + * Copyright 2012 BBN Technologies + * + */ +package com.bbn.openmap.ext.jts; + +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.CoordinateSequenceFilter; + +/** + * A {@link CoordinateSequenceFilter} to extract float[] xpts and ypts from a + * {@link CoordinateSequence} + */ +class XYCoordianteSequenceExtractorFilter + implements CoordinateSequenceFilter { + + private final float[] xpts; + private final float[] ypts; + + public XYCoordianteSequenceExtractorFilter(float[] xpts, float[] ypts) { + this.xpts = xpts; + this.ypts = ypts; + } + + public void filter(CoordinateSequence seq, int i) { + xpts[i] = (float) seq.getX(i); + ypts[i] = (float) seq.getY(i); + } + + public boolean isDone() { + return false; + } + + public boolean isGeometryChanged() { + return false; + } + +} Index: src/openmap/com/bbn/openmap/proj/GeoProj.java =================================================================== --- src/openmap/com/bbn/openmap/proj/GeoProj.java (revision 2264) +++ src/openmap/com/bbn/openmap/proj/GeoProj.java (working copy) @@ -31,10 +31,14 @@ import com.bbn.openmap.Environment; import com.bbn.openmap.MoreMath; +import com.bbn.openmap.ext.jts.JTS; import com.bbn.openmap.proj.coords.GeoCoordTransformation; import com.bbn.openmap.proj.coords.LatLonGCT; import com.bbn.openmap.proj.coords.LatLonPoint; import com.bbn.openmap.util.Debug; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Polygon; /** * GeoProj is the base class of all Projections that deal with coordinates on @@ -1386,29 +1390,11 @@ */ public ArrayList forwardPoly(float[] rawllpts, int ltype, int nsegs, boolean isFilled) { ArrayList stuff = _forwardPoly(rawllpts, ltype, nsegs, isFilled); - // @HACK: workaround XWindows bug. simple clip to a boundary. - // this is ugly. + // @HACK: workaround XWindows bug. clip to a boundary. if (Environment.doingXWindowsWorkaround && (scale <= XSCALE_THRESHOLD)) { - int i, j, size = stuff.size(); - float[] xpts, ypts; - for (i = 0; i < size; i += 2) { - xpts = (float[]) stuff.get(i); - ypts = (float[]) stuff.get(i + 1); - for (j = 0; j < xpts.length; j++) { - if (xpts[j] <= -XTHRESHOLD) { - xpts[j] = -XTHRESHOLD; - } else if (xpts[j] >= XTHRESHOLD) { - xpts[j] = XTHRESHOLD; - } - if (ypts[j] <= -XTHRESHOLD) { - ypts[j] = -XTHRESHOLD; - } else if (ypts[j] >= XTHRESHOLD) { - ypts[j] = XTHRESHOLD; - } - } - stuff.set(i, xpts); - stuff.set(i + 1, ypts); - } + GeometryFactory gf = new GeometryFactory(); + Geometry clip = JTS.createRectangle(gf, -XTHRESHOLD, -XTHRESHOLD, XTHRESHOLD, XTHRESHOLD); + JTS.clip(gf, clip, stuff); } return stuff; } @@ -1432,33 +1418,15 @@ */ public ArrayList forwardPoly(double[] rawllpts, int ltype, int nsegs, boolean isFilled) { ArrayList stuff = _forwardPoly(rawllpts, ltype, nsegs, isFilled); - // @HACK: workaround XWindows bug. simple clip to a boundary. - // this is ugly. + // @HACK: workaround XWindows bug. clip to a boundary. if (Environment.doingXWindowsWorkaround && (scale <= XSCALE_THRESHOLD)) { - int i, j, size = stuff.size(); - float[] xpts, ypts; - for (i = 0; i < size; i += 2) { - xpts = stuff.get(i); - ypts = stuff.get(i + 1); - for (j = 0; j < xpts.length; j++) { - if (xpts[j] <= -XTHRESHOLD) { - xpts[j] = -XTHRESHOLD; - } else if (xpts[j] >= XTHRESHOLD) { - xpts[j] = XTHRESHOLD; - } - if (ypts[j] <= -XTHRESHOLD) { - ypts[j] = -XTHRESHOLD; - } else if (ypts[j] >= XTHRESHOLD) { - ypts[j] = XTHRESHOLD; - } - } - stuff.set(i, xpts); - stuff.set(i + 1, ypts); - } + GeometryFactory gf = new GeometryFactory(); + Geometry clip = JTS.createRectangle(gf, -XTHRESHOLD, -XTHRESHOLD, XTHRESHOLD, XTHRESHOLD); + JTS.clip(gf, clip, stuff); } return stuff; } - + /** * Forward project a lat/lon Poly defined as decimal degree lat/lons. *

Index: src/openmap/com/bbn/openmap/proj/coords/LatLonGCT.java =================================================================== --- src/openmap/com/bbn/openmap/proj/coords/LatLonGCT.java (revision 2264) +++ src/openmap/com/bbn/openmap/proj/coords/LatLonGCT.java (working copy) @@ -44,7 +44,7 @@ } public LatLonPoint inverse(double x, double y, LatLonPoint ret) { - ret.setLatLon((float) y, (float) x); + ret.setLatLon(y, x); return ret; }