/******************************************************************************* * Copyright (c) 2016 David Smiley * All rights reserved. This program and the accompanying materials * are made available under the terms of the Apache License, Version 2.0 which * accompanies this distribution and is available at * http://www.apache.org/licenses/LICENSE-2.0.txt ******************************************************************************/ package org.locationtech.spatial4j.shape; import org.locationtech.spatial4j.context.SpatialContext; import java.util.List; /** * A factory for {@link Shape}s. * Stateless and thread-safe, except for any returned builders. */ public interface ShapeFactory { SpatialContext getSpatialContext(); /** If true then {@link #normX(double)} will wrap longitudes outside of the standard * geodetic boundary into it. Example: 181 will become -179. */ boolean isNormWrapLongitude(); // TODO annoying that a ShapeReader must remember to call norm* methods. Perhaps // there should be another shapeFactory impl for shape reading? :-/ Or not. /** Normalize the 'x' dimension. Might reduce precision or wrap it to be within the bounds. This * is called by {@link org.locationtech.spatial4j.io.ShapeReader}s before creating a shape. */ double normX(double x); /** @see #normX(double) */ double normY(double y); /** (disclaimer: the Z dimension isn't fully supported) * @see #normX(double) */ double normZ(double z); /** * Called to normalize a value that isn't X or Y or Z. X & Y & Z are normalized via * {@link org.locationtech.spatial4j.context.SpatialContext#normX(double)} & normY & normZ. This * is called by a {@link org.locationtech.spatial4j.io.ShapeReader} before creating a shape. */ double normDist(double d); /** Ensure fits in the world bounds. It's called by any shape factory method that * gets an 'x' dimension. */ void verifyX(double x); /** @see #verifyX(double) */ void verifyY(double y); /** (disclaimer: the Z dimension isn't fully supported) * @see #verifyX(double) */ void verifyZ(double z); /** Construct a point. */ Point pointXY(double x, double y); /** Construct a point of 3 dimensions. The implementation might ignore unsupported * dimensions like 'z' or throw an error. */ Point pointXYZ(double x, double y, double z); /** Construct a rectangle. */ Rectangle rect(Point lowerLeft, Point upperRight); /** * Construct a rectangle. If just one longitude is on the dateline (+/- 180) and if * {@link SpatialContext#isGeo()} * then potentially adjust its sign to ensure the rectangle does not cross the * dateline. */ Rectangle rect(double minX, double maxX, double minY, double maxY); /** Construct a circle. The units of "distance" should be the same as x & y. */ Circle circle(double x, double y, double distance); /** Construct a circle. The units of "distance" should be the same as x & y. */ Circle circle(Point point, double distance); /** Constructs a line string with a possible buffer. It's an ordered sequence of connected vertexes, * with a buffer distance along the line in all directions. There * is no official shape/interface for it so we just return Shape. */ @Deprecated // use a builder Shape lineString(List<Point> points, double buf); /** Construct a ShapeCollection, analogous to an OGC GeometryCollection. */ @Deprecated // use a builder <S extends Shape> ShapeCollection<S> multiShape(List<S> coll); // BUILDERS: /** (Builder) Constructs a line string, with a possible buffer. * It's an ordered sequence of connected vertexes. * There is no official shape/interface for it yet so we just return Shape. */ LineStringBuilder lineString(); /** (Builder) Constructs a polygon. * There is no official shape/interface for it yet so we just return Shape. */ PolygonBuilder polygon(); /** (Builder) Constructs a Shape aggregate in which each component/member * is an instance of the specified class. */ <T extends Shape> MultiShapeBuilder<T> multiShape(Class<T> shapeClass); /** (Builder) Constructs a MultiPoint. */ MultiPointBuilder multiPoint(); /** (Builder) Constructs a MultiLineString, or possibly the result of that buffered. */ MultiLineStringBuilder multiLineString(); /** (Builder) Constructs a MultiPolygon. */ MultiPolygonBuilder multiPolygon(); // misc: //Shape buffer(Shape shape); ? // TODO need Polygon shape // TODO need LineString shape // TODO need BufferedLineString shape // TODO need ShapeCollection to be typed /** Builds a point and returns the generic specified type (usually whatever "this" is). */ interface PointsBuilder<T> { /** @see ShapeFactory#pointXY(double, double) */ T pointXY(double x, double y); /** @see ShapeFactory#pointXYZ(double, double, double) */ T pointXYZ(double x, double y, double z); } /** @see #lineString() */ interface LineStringBuilder extends PointsBuilder<LineStringBuilder> { // TODO add dimensionality hint method? LineStringBuilder buffer(double distance); Shape build(); } /** @see #polygon() */ interface PolygonBuilder extends PointsBuilder<PolygonBuilder> { // TODO add dimensionality hint method? /** Starts a new hole. You must add at least 4 points; furthermore the first and last must be the same. * And don't forget to call {@link HoleBuilder#endHole()}! */ HoleBuilder hole(); /** Builds the polygon and renders this builder instance invalid. */ Shape build();// never a Rect Shape buildOrRect(); interface HoleBuilder extends PointsBuilder<HoleBuilder> { /** Finishes the hole and returns the {@link PolygonBuilder}.*/ PolygonBuilder endHole(); } } // TODO add dimensionality hint method to the multi* builders? /** @see #multiShape(Class) */ interface MultiShapeBuilder<T extends Shape> { // TODO add dimensionality hint method? MultiShapeBuilder<T> add(T shape); //ShapeCollection<T> build(); TODO wait till it's a typed interface Shape build(); } /** @see #multiPoint() */ interface MultiPointBuilder extends PointsBuilder<MultiPointBuilder> { Shape build(); // TODO MultiShape<Point> } /** @see #multiLineString() */ interface MultiLineStringBuilder { LineStringBuilder lineString(); MultiLineStringBuilder add(LineStringBuilder lineStringBuilder); Shape build(); // TODO MultiShape<LineString> } /** @see #multiPolygon() */ interface MultiPolygonBuilder { PolygonBuilder polygon(); MultiPolygonBuilder add(PolygonBuilder polygonBuilder); Shape build(); // TODO MultiShape<Polygon> } }