private static void transformGeometry(Geometry geometry) { if (geometry == null) { return; } if (geometry instanceof GeometryCollection) { GeometryCollection collection = (GeometryCollection) geometry; for (int i = 0; i < collection.getNumGeometries(); i++) { transformGeometry(collection.getGeometryN(i)); } } else if (geometry instanceof Polygon) { Polygon polygon = (Polygon) geometry; transformGeometry(polygon.getExteriorRing()); for (int i = 0; i < polygon.getNumInteriorRing(); i++) { transformGeometry(polygon.getInteriorRingN(i)); } } else if (geometry instanceof LineString) { LiteCoordinateSequence seq = (LiteCoordinateSequence) ((LineString) geometry).getCoordinateSequence(); double[] coords = seq.getArray(); for (int i = 0; i < coords.length; i++) { coords[i] = (int) (coords[i] + 0.5d); } seq.setArray(coords); } }
private CoordinateSequence decimate(LiteCoordinateSequence seq) { double[] coords = seq.getArray(); int numDoubles = coords.length; int dim = seq.getDimension(); int readDoubles = 0; double prevx, currx, prevy, curry, diffx, diffy; for (int currentDoubles = 0; currentDoubles < numDoubles; currentDoubles += dim) { if (currentDoubles >= dim && currentDoubles < numDoubles - 1) { prevx = coords[readDoubles - dim]; currx = coords[currentDoubles]; diffx = Math.abs(prevx - currx); prevy = coords[readDoubles - dim + 1]; curry = coords[currentDoubles + 1]; diffy = Math.abs(prevy - curry); if (diffx > spanx || diffy > spany) { readDoubles = copyCoordinate(coords, dim, readDoubles, currentDoubles); } } else { readDoubles = copyCoordinate(coords, dim, readDoubles, currentDoubles); } } double[] newCoords = new double[readDoubles]; System.arraycopy(coords, 0, newCoords, 0, readDoubles); seq.setArray(newCoords); return seq; }
/** decimates JTS geometries. */ public final Geometry decimate(Geometry geom) { GeometryFactory gFac = new GeometryFactory(geom.getPrecisionModel(), geom.getSRID()); if (spanx == -1) return geom; if (geom instanceof MultiPoint) { // TODO check geometry and if its bbox is too small turn it into a 1 // point geom return geom; } if (geom instanceof GeometryCollection) { // TODO check geometry and if its bbox is too small turn it into a // 1-2 point geom // takes a bit of work because the geometry will need to be // recreated. GeometryCollection collection = (GeometryCollection) geom; Geometry[] result = new Geometry[collection.getDimension()]; final int numGeometries = collection.getNumGeometries(); for (int i = 0; i < numGeometries; i++) { result[i] = decimate(collection.getGeometryN(i)); } return gFac.createGeometryCollection(result); } else if (geom instanceof LineString) { LineString line = (LineString) geom; CoordinateSequence seq = (CoordinateSequence) line.getCoordinateSequence(); LiteCoordinateSequence lseq = new LiteCoordinateSequence(seq.toCoordinateArray()); if (decimateOnEnvelope(line, lseq)) { if (lseq.size() >= 2) return gFac.createLineString(lseq); } if (lseq.size() >= 2) return gFac.createLineString(decimate(lseq)); return null; } else if (geom instanceof Polygon) { Polygon line = (Polygon) geom; Coordinate[] exterior = decimate(line.getExteriorRing()).getCoordinates(); forceClosed(exterior); if (exterior.length > 3) { LinearRing ring = gFac.createLinearRing(exterior); final int numRings = line.getNumInteriorRing(); List<LinearRing> rings = new ArrayList<LinearRing>(); for (int i = 0; i < numRings; i++) { Coordinate[] interior = decimate(line.getInteriorRingN(i)).getCoordinates(); forceClosed(interior); if (interior.length > 3) rings.add(gFac.createLinearRing(interior)); } return gFac.createPolygon(ring, rings.toArray(new LinearRing[] {})); } return null; } return geom; }
/** * @param geom * @param seq */ private boolean decimateOnEnvelope(Geometry geom, LiteCoordinateSequence seq) { Envelope env = geom.getEnvelopeInternal(); if (env.getWidth() <= spanx && env.getHeight() <= spany) { double[] coords = seq.getArray(); int dim = seq.getDimension(); double[] newcoords = new double[dim * 2]; for (int i = 0; i < dim; i++) { newcoords[i] = coords[i]; newcoords[dim + i] = coords[coords.length - dim + i]; } seq.setArray(coords); return true; } return false; }
/** * 1. remove any points that are within the spanx,spany. We ALWAYS keep 1st and last point 2. * transform to screen coordinates 3. remove any points that are close (span <1) * * @param seq * @param tranform */ private final void decimateTransformGeneralize( LiteCoordinateSequence seq, MathTransform transform) throws TransformException { // decimates before XFORM int ncoords = seq.size(); double originalOrds[] = seq.getXYArray(); // 2*#of points if (ncoords < 2) { if (ncoords == 1) // 1 coordinate -- just xform it { double[] newCoordsXformed2 = new double[2]; transform.transform(originalOrds, 0, newCoordsXformed2, 0, 1); seq.setArray(newCoordsXformed2); return; } else return; // ncoords =0 } // unfortunately, we have to keep things in double precion until after // the transform or we could move things. double[] allCoords = new double[ncoords * 2]; // preallocate -- might // not be full (throw // away Z) allCoords[0] = originalOrds[0]; // allways have 1st one allCoords[1] = originalOrds[1]; int actualCoords = 1; double lastX = allCoords[0]; double lastY = allCoords[1]; for (int t = 1; t < (ncoords - 1); t++) { // see if this one should be added double x = originalOrds[t * 2]; double y = originalOrds[t * 2 + 1]; if ((Math.abs(x - lastX) > spanx) || (Math.abs(y - lastY)) > spany) { allCoords[actualCoords * 2] = x; allCoords[actualCoords * 2 + 1] = y; lastX = x; lastY = y; actualCoords++; } } allCoords[actualCoords * 2] = originalOrds[(ncoords - 1) * 2]; // always have last one allCoords[actualCoords * 2 + 1] = originalOrds[(ncoords - 1) * 2 + 1]; actualCoords++; double[] newCoordsXformed; // DO THE XFORM if ((transform == null) || (transform.isIdentity())) // no actual // xform { newCoordsXformed = allCoords; } else { newCoordsXformed = new double[actualCoords * 2]; transform.transform(allCoords, 0, newCoordsXformed, 0, actualCoords); } // GENERALIZE -- we should be in screen space so spanx=spany=1.0 // unfortunately, we have to keep things in double precion until after // the transform or we could move things. double[] finalCoords = new double[ncoords * 2]; // preallocate -- might // not be full (throw // away Z) finalCoords[0] = newCoordsXformed[0]; // allways have 1st one finalCoords[1] = newCoordsXformed[1]; int actualCoordsGen = 1; lastX = newCoordsXformed[0]; lastY = newCoordsXformed[1]; for (int t = 1; t < (actualCoords - 1); t++) { // see if this one should be added double x = newCoordsXformed[t * 2]; double y = newCoordsXformed[t * 2 + 1]; if ((Math.abs(x - lastX) > 0.75) || (Math.abs(y - lastY)) > 0.75) // 0.75 // instead of 1 just because it tends to look nicer for slightly // more work. magic number. { finalCoords[actualCoordsGen * 2] = x; finalCoords[actualCoordsGen * 2 + 1] = y; lastX = x; lastY = y; actualCoordsGen++; } } finalCoords[actualCoordsGen * 2] = newCoordsXformed[(actualCoords - 1) * 2]; // always have last one finalCoords[actualCoordsGen * 2 + 1] = newCoordsXformed[(actualCoords - 1) * 2 + 1]; actualCoordsGen++; // stick back in double[] seqDouble = new double[2 * actualCoordsGen]; System.arraycopy(finalCoords, 0, seqDouble, 0, actualCoordsGen * 2); seq.setArray(seqDouble); }