/** * Reads the shape specification as defined in the class javadocs. If the first character is a * letter but it doesn't complete out "Circle" or "CIRCLE" then this method returns null, offering * the caller the opportunity to potentially try additional parsing. If the first character is not * a letter then it's assumed to be a point or rectangle. If that doesn't work out then an {@link * org.locationtech.spatial4j.exception.InvalidShapeException} is thrown. */ public static Shape readShapeOrNull(String str, SpatialContext ctx) throws InvalidShapeException { if (str == null || str.length() == 0) { throw new InvalidShapeException(str); } if (Character.isLetter(str.charAt(0))) { if (str.startsWith("Circle(") || str.startsWith("CIRCLE(")) { int idx = str.lastIndexOf(')'); if (idx > 0) { String body = str.substring("Circle(".length(), idx); StringTokenizer st = new StringTokenizer(body, " "); String token = st.nextToken(); Point pt; if (token.indexOf(',') != -1) { pt = readLatCommaLonPoint(token, ctx); } else { double x = Double.parseDouble(token); double y = Double.parseDouble(st.nextToken()); pt = ctx.makePoint(x, y); } Double d = null; String arg = st.nextToken(); idx = arg.indexOf('='); if (idx > 0) { String k = arg.substring(0, idx); if (k.equals("d") || k.equals("distance")) { d = Double.parseDouble(arg.substring(idx + 1)); } else { throw new InvalidShapeException("unknown arg: " + k + " :: " + str); } } else { d = Double.parseDouble(arg); } if (st.hasMoreTokens()) { throw new InvalidShapeException("Extra arguments: " + st.nextToken() + " :: " + str); } if (d == null) { throw new InvalidShapeException("Missing Distance: " + str); } // NOTE: we are assuming the units of 'd' is the same as that of the spatial context. return ctx.makeCircle(pt, d); } } return null; // caller has opportunity to try other parsing } if (str.indexOf(',') != -1) return readLatCommaLonPoint(str, ctx); StringTokenizer st = new StringTokenizer(str, " "); double p0 = Double.parseDouble(st.nextToken()); double p1 = Double.parseDouble(st.nextToken()); if (st.hasMoreTokens()) { double p2 = Double.parseDouble(st.nextToken()); double p3 = Double.parseDouble(st.nextToken()); if (st.hasMoreTokens()) throw new InvalidShapeException("Only 4 numbers supported (rect) but found more: " + str); return ctx.makeRectangle(p0, p2, p1, p3); } return ctx.makePoint(p0, p1); }
@Test public void testRectangle() throws IOException { Shape s = read("-10 -20 10 20"); assertEquals(ctx.makeRectangle(-10, 10, -20, 20), s); assertEquals(s, writeThenRead(s)); assertTrue(s.hasArea()); }
protected Rectangle randomRectangle(Rectangle bounds) { double[] xNewStartAndWidth = randomSubRange(bounds.getMinX(), bounds.getWidth()); double xMin = xNewStartAndWidth[0]; double xMax = xMin + xNewStartAndWidth[1]; if (bounds.getCrossesDateLine()) { xMin = DistanceUtils.normLonDEG(xMin); xMax = DistanceUtils.normLonDEG(xMax); } double[] yNewStartAndHeight = randomSubRange(bounds.getMinY(), bounds.getHeight()); double yMin = yNewStartAndHeight[0]; double yMax = yMin + yNewStartAndHeight[1]; return ctx.makeRectangle(xMin, xMax, yMin, yMax); }