static Geometry densify(Geometry geom, CoordinateReferenceSystem crs, double maxAreaError) throws FactoryException, TransformException { // basic checks if (maxAreaError <= 0) { throw new IllegalArgumentException("maxAreaError must be greater than 0"); } if (!(geom instanceof Polygon) && !(geom instanceof MultiPolygon)) { throw new IllegalArgumentException("Geom must be poligonal"); } if (crs == null) { throw new IllegalArgumentException("CRS cannot be set to null"); } double previousArea = 0.0; CoordinateReferenceSystem targetCRS = CRS.parseWKT(ECKERT_IV_WKT); MathTransform firstTransform = CRS.findMathTransform(crs, targetCRS); GeometryFactory geomFactory = new GeometryFactory(); int ngeom = geom.getNumGeometries(); Geometry densifiedGeometry = geom; double areaError = 1.0d; int maxIterate = 0; do { double max = 0; maxIterate++; // check the maximum side length of the densifiedGeometry for (int j = 0; j < ngeom; j++) { Geometry geometry = densifiedGeometry.getGeometryN(j); Coordinate[] coordinates = geometry.getCoordinates(); int n = coordinates.length; for (int i = 0; i < (n - 1); i++) { Coordinate[] coords = new Coordinate[2]; coords[0] = coordinates[i]; coords[1] = coordinates[i + 1]; LineString lineString = geomFactory.createLineString(coords); if (lineString.getLength() > max) max = lineString.getLength(); } } // calculate the denified geometry densifiedGeometry = Densifier.densify(densifiedGeometry, max / 2); // reproject densifiedGeometry to Eckert IV Geometry targetGeometry = JTS.transform(densifiedGeometry, firstTransform); double nextArea = targetGeometry.getArea(); // evaluate the current error areaError = Math.abs(previousArea - nextArea) / nextArea; // logger3.info("AREA ERROR"+areaError); previousArea = nextArea; // check whether the current error is greater than the maximum allowed } while (areaError > maxAreaError && maxIterate < 10); return densifiedGeometry; }
/** * Creates a circle shape, using the JTS buffer algorithm. The method is used when there is no * street found within the given traveltime, e.g. when the pointer is placed on a field or in the * woods.<br> * TODO: Note it is actually not correct to do buffer calculation in Euclidian 2D, since the * resulting shape will be elliptical when projected. * * @param dropPoint the location given by the user * @param pathToStreet the path from the dropPoint to the street, used to retrieve the buffer * distance * @return a Circle */ private Geometry createCirle(Coordinate dropPoint, LineString pathToStreet) { double length = pathToStreet.getLength(); GeometryFactory gf = new GeometryFactory(); Point dp = gf.createPoint(dropPoint); Geometry buffer = dp.buffer(length); return buffer; }
public void findClosestPoint(String wktA, String wktB) { System.out.println("-------------------------------------"); try { Geometry A = wktRdr.read(wktA); Geometry B = wktRdr.read(wktB); System.out.println("Geometry A: " + A); System.out.println("Geometry B: " + B); DistanceOp distOp = new DistanceOp(A, B); double distance = distOp.distance(); System.out.println("Distance = " + distance); Coordinate[] closestPt = distOp.nearestPoints(); LineString closestPtLine = fact.createLineString(closestPt); System.out.println( "Closest points: " + closestPtLine + " (distance = " + closestPtLine.getLength() + ")"); } catch (Exception ex) { ex.printStackTrace(); } }
/** Splits the input geometry into two LineStrings at a fraction of the distance covered. */ public static P2<LineString> splitGeometryAtFraction(Geometry geometry, double fraction) { LineString empty = new LineString(null, gf); Coordinate[] coordinates = geometry.getCoordinates(); CoordinateSequence sequence = gf.getCoordinateSequenceFactory().create(coordinates); LineString total = new LineString(sequence, gf); if (coordinates.length < 2) return new P2<LineString>(empty, empty); if (fraction <= 0) return new P2<LineString>(empty, total); if (fraction >= 1) return new P2<LineString>(total, empty); double totalDistance = total.getLength(); double requestedDistance = totalDistance * fraction; // An index in JTS can actually refer to any point along the line. It is NOT an array index. LocationIndexedLine line = new LocationIndexedLine(geometry); LinearLocation l = LengthLocationMap.getLocation(geometry, requestedDistance); LineString beginning = (LineString) line.extractLine(line.getStartIndex(), l); LineString ending = (LineString) line.extractLine(l, line.getEndIndex()); return new P2<LineString>(beginning, ending); }
/** * Extraction of a sub-LineString from an existing line, starting from 0; * * @param ls the line from which we extract the sub LineString () * @param fraction [0..1], the length until where we want the substring to go * @return the sub-LineString */ LineString getSubLineString(LineString ls, double fraction) { if (fraction >= 1) return ls; LengthIndexedLine linRefLine = new LengthIndexedLine(ls); LineString subLine = (LineString) linRefLine.extractLine(0, fraction * ls.getLength()); return subLine; }
boolean layout(LineLabel label, LabelIndex labels) { String txt = label.getText(); Rule rule = label.getRule(); Feature f = label.getFeature(); Geometry g = label.getGeometry(); LineString line = null; if (g instanceof MultiLineString) { // TODO: handle multiple lines if (g.getNumGeometries() == 1) { line = (LineString) g.getGeometryN(0); } } else { line = (LineString) g; } if (line == null) { return false; } Paint p = label.get(Paint.class, Paint.class); // compute the bounds of the label with no rotation Rect r = new Rect(); p.getTextBounds(txt, 0, txt.length(), r); // map it to world coordinates RectF bounds = new RectF(r); tx.getCanvasToWorld().mapRect(bounds); // ignore label if its too long for the line if (line.getLength() < bounds.width()) { // ignore this label return false; } // reverse if (line.getPointN(0).getX() > line.getPointN(line.getNumPoints() - 1).getX()) { line = (LineString) line.reverse(); } // compute width of individual letters float[] widths = new float[txt.length()]; p.getTextWidths(txt, widths); // map the widths to world space float sum = 0; for (int i = 0; i < widths.length; i++) { RectF s = new RectF(0, 0, widths[i], 1); tx.getCanvasToWorld().mapRect(s); widths[i] = s.width(); sum += s.width(); } // TODO: properly figure out spacing between letters float space = tx.getCanvasToWorld().mapRadius(1); // allowable angle change in consecutive characters double maxAngleDelta = rule.number(f, TEXT_MAX_CHAR_ANGLE_DELTA, DEFAULT_MAX_ANGLE_CHAR_DELTA); // // sample points along the line for letters // List<LineSegment> path = new ArrayList<LineSegment>(); LineSampler sampler = new LineSampler(line.getCoordinates()); for (int i = 0; i < txt.length(); i++) { // get next point Coordinate c1 = sampler.sample(); // advance by width of letter sampler.advance(widths[i]); // get point for end of letter Coordinate c2 = sampler.sample(); if (c1 == null || c2 == null) { // ran out of room return false; } LineSegment seg = new LineSegment(c1, c2); // check angle made with previous segment if (i > 0) { LineSegment prev = path.get(i - 1); if (Math.abs(angle(seg) - angle(prev)) > maxAngleDelta) { return false; } } path.add(seg); sampler.advance(space); } label.setPath(path); label.setShape(toShape(path, bounds.height())); return labels.insert(label); }