/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.plugin.editing.client.service;
import java.util.ArrayList;
import java.util.List;
import org.geomajas.annotation.Api;
import org.geomajas.geometry.Coordinate;
import org.geomajas.geometry.Geometry;
import org.geomajas.geometry.service.GeometryService;
import org.geomajas.geometry.service.GeometryValidationState;
/**
* Service for managing sub-parts of geometries through special geometry indices.
*
* @author Pieter De Graef
* @author Jan De Moerloose
* @since 2.0.0
*/
@Api(allMethods = true)
public class GeometryIndexService {
private org.geomajas.geometry.service.GeometryIndexService delegate =
new org.geomajas.geometry.service.GeometryIndexService();
// ------------------------------------------------------------------------
// Methods concerning index construction:
// ------------------------------------------------------------------------
/**
* Create a new index given a type and a list of values. This index will be built recursively and will have a depth
* equal to the number of values given.
*
* @param type The type of index applied on the deepest child index. Note that all parent index nodes will be of the
* type <code>GeometryIndexType.TYPE_GEOMETRY</code>. Only the deepest child will use this given type.
* @param values A list of integer values that determine the indices on each level in the index.
* @return The recursive geometry index resulting from the given parameters.
*/
public GeometryIndex create(GeometryIndexType type, int... values) {
return fromDelegate(delegate.create(toDelegate(type), values));
}
/**
* Given a certain geometry index, add more levels to it (This method will not change the underlying geometry !).
*
* @param index The index to start out from.
* @param type Add more levels to it, where the deepest level should be of this type.
* @param values A list of integer values that determine the indices on each level in the index.
* @return The recursive geometry index resulting from adding the given parameters to the given parent index.
*/
public GeometryIndex addChildren(GeometryIndex index, GeometryIndexType type, int... values) {
return fromDelegate(delegate.addChildren(toDelegate(index), toDelegate(type), values));
}
// ------------------------------------------------------------------------
// Methods concerning index parsing/formatting:
// ------------------------------------------------------------------------
/**
* Format a given geometry index, creating something like "geometry2.vertex1".
*
* @param index The geometry index to format.
* @return Returns the string value resulting from the index.
*/
public String format(GeometryIndex index) {
return delegate.format(toDelegate(index));
}
/**
* Given a certain string identifier, parse it as a geometry index.
*
* @param id The identifier to try and parse.
* @return Returns the associating geometry index (if no exception was thrown).
* @throws GeometryIndexNotFoundException In case the identifier could not be parsed.
*/
public GeometryIndex parse(String id) throws GeometryIndexNotFoundException {
try {
return fromDelegate(delegate.parse(id));
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
// ------------------------------------------------------------------------
// Methods for geometry retrieval:
// ------------------------------------------------------------------------
/**
* Given a certain geometry, get the sub-geometry the index points to. This only works if the index actually points
* to a sub-geometry.
*
* @param geometry The geometry to search in.
* @param index The index that points to a sub-geometry within the given geometry.
* @return Returns the sub-geometry if it exists.
* @throws GeometryIndexNotFoundException Thrown in case the index is of the wrong type, or if the sub-geometry
* could not be found within the given geometry.
*/
public Geometry getGeometry(Geometry geometry, GeometryIndex index) throws GeometryIndexNotFoundException {
try {
return delegate.getGeometry(geometry, toDelegate(index));
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
/**
* Given a certain geometry, get the vertex the index points to. This only works if the index actually points to a
* vertex.
*
* @param geometry The geometry to search in.
* @param index The index that points to a vertex within the given geometry.
* @return Returns the vertex if it exists.
* @throws GeometryIndexNotFoundException Thrown in case the index is of the wrong type, or if the vertex could not
* be found within the given geometry.
*/
public Coordinate getVertex(Geometry geometry, GeometryIndex index) throws GeometryIndexNotFoundException {
try {
return delegate.getVertex(geometry, toDelegate(index));
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
/**
* Given a certain geometry, get the edge the index points to. This only works if the index actually points to an
* edge.
*
* @param geometry The geometry to search in.
* @param index The index that points to an edge within the given geometry.
* @return Returns the edge if it exists.
* @throws GeometryIndexNotFoundException Thrown in case the index is of the wrong type, or if the edge could not be
* found within the given geometry.
*/
public Coordinate[] getEdge(Geometry geometry, GeometryIndex index) throws GeometryIndexNotFoundException {
try {
return delegate.getEdge(geometry, toDelegate(index));
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
// ------------------------------------------------------------------------
// Helper methods:
// ------------------------------------------------------------------------
/**
* Does the given index point to a vertex or not? We look at the deepest level to check this.
*
* @param index The index to check.
* @return true or false.
*/
public boolean isVertex(GeometryIndex index) {
return delegate.isVertex(toDelegate(index));
}
/**
* Does the given index point to an edge or not? We look at the deepest level to check this.
*
* @param index The index to check.
* @return true or false.
*/
public boolean isEdge(GeometryIndex index) {
return delegate.isEdge(toDelegate(index));
}
/**
* Does the given index point to a sub-geometry or not? We look at the deepest level to check this.
*
* @param index The index to check.
* @return true or false.
*/
public boolean isGeometry(GeometryIndex index) {
return delegate.isGeometry(toDelegate(index));
}
/**
* Get the type of sub-part the given index points to. We look at the deepest level to check this.
*
* @param index The index to check.
* @return true or false.
*/
public GeometryIndexType getType(GeometryIndex index) {
return fromDelegate(delegate.getType(toDelegate(index)));
}
/**
* What is the geometry type of the sub-geometry pointed to by the given index? If the index points to a vertex or
* edge, the geometry type at the parent level is returned.
*
* @param geometry The geometry wherein to search.
* @param index The index pointing to a vertex/edge/sub-geometry. In the case of a vertex/edge, the parent geometry
* type is returned. If index is null, the type of the given geometry is returned.
* @return The geometry type as defined in the {@link Geometry} class.
* @throws GeometryIndexNotFoundException Thrown in case the index points to a non-existing sub-geometry.
*/
public String getGeometryType(Geometry geometry, GeometryIndex index) throws GeometryIndexNotFoundException {
try {
return delegate.getGeometryType(geometry, toDelegate(index));
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
/**
* Checks to see if a given index is the child of another index.
*
* @param parentIndex The so-called parent index.
* @param childIndex The so-called child index.
* @return Is the second index really a child of the first index?
*/
public boolean isChildOf(GeometryIndex parentIndex, GeometryIndex childIndex) {
return delegate.isChildOf(toDelegate(parentIndex), toDelegate(childIndex));
}
/**
* Returns the value of the innermost child index.
*
* @param index The index to recursively search.
* @return The value of the deepest child.
*/
public int getValue(GeometryIndex index) {
return delegate.getValue(toDelegate(index));
}
/**
* Returns a new index that is one level higher than this index. Useful to get the index of a ring for a vertex.
*
* @param index
* @return the parent index
* @since 2.1.0
*/
public GeometryIndex getParent(GeometryIndex index) {
return fromDelegate(delegate.getParent(toDelegate(index)));
}
// ------------------------------------------------------------------------
// Methods concerning adjacency (finding ones neighbors):
// ------------------------------------------------------------------------
/**
* Given a certain geometry and index, find the neighboring vertices. It is important to understand that searching
* vertices within a closed ring will always return 2 vertices (unless the ring contains only 1 or 2 coordinates),
* while searching within a LineString can yield different results (the beginning or end only has 1 neighbor).
*
* @param geometry The geometry wherein to search for neighboring vertices.
* @param index The index to start out from. Must point to either a vertex or and edge.
* @return The list of neighboring vertices.
* @throws GeometryIndexNotFoundException Thrown in case the given index does not match the given geometry.
*/
public List<GeometryIndex> getAdjacentVertices(Geometry geometry, GeometryIndex index)
throws GeometryIndexNotFoundException {
try {
List<org.geomajas.geometry.service.GeometryIndex> delegateVertices = delegate.getAdjacentVertices(geometry,
toDelegate(index));
List<GeometryIndex> vertices = new ArrayList<GeometryIndex>();
for (org.geomajas.geometry.service.GeometryIndex i : delegateVertices) {
vertices.add(fromDelegate(i));
}
return vertices;
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
/**
* Given a certain geometry and index, find the neighboring edges. It is important to understand that searching
* edges within a closed ring will always return 2 results (unless the ring contains only 1 or 2 coordinates), while
* searching within a LineString can yield different results (the beginning or end only has 1 neighbor).
*
* @param geometry The geometry wherein to search for neighboring edges.
* @param index The index to start out from. Must point to either a vertex or and edge.
* @return The list of neighboring edges.
* @throws GeometryIndexNotFoundException Thrown in case the given index does not match the given geometry.
*/
public List<GeometryIndex> getAdjacentEdges(Geometry geometry, GeometryIndex index)
throws GeometryIndexNotFoundException {
try {
List<org.geomajas.geometry.service.GeometryIndex> delegateEdges = delegate.getAdjacentEdges(geometry,
toDelegate(index));
List<GeometryIndex> edges = new ArrayList<GeometryIndex>();
for (org.geomajas.geometry.service.GeometryIndex i : delegateEdges) {
edges.add(fromDelegate(i));
}
return edges;
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
/**
* Given a certain geometry and index (one), check if the the other index (two) is a neighbor.
*
* @param geometry The geometry wherein to search if indices one and two are neighbors.
* @param one One of the indices. Must point to either a vertex or and edge.
* @param two Another one of the indices. Must point to either a vertex or and edge.
* @return true or false.
*/
public boolean isAdjacent(Geometry geometry, GeometryIndex one, GeometryIndex two) {
return delegate.isAdjacent(geometry, toDelegate(one), toDelegate(two));
}
/**
* Given a certain index, find the next vertex in line.
*
* @param index The index to start out from. Must point to either a vertex or and edge.
* @return Returns the next vertex index. Note that no geometry is given, and so no actual checking is done. It just
* returns the theoretical answer.
*/
public GeometryIndex getNextVertex(GeometryIndex index) {
return fromDelegate(delegate.getNextVertex(toDelegate(index)));
}
/**
* Given a certain index, find the previous vertex in line.
*
* @param index The index to start out from. Must point to either a vertex or and edge.
* @return Returns the previous vertex index. Note that no geometry is given, and so no actual checking is done. It
* just returns the theoretical answer.
*/
public GeometryIndex getPreviousVertex(GeometryIndex index) {
return fromDelegate(delegate.getPreviousVertex(toDelegate(index)));
}
/**
* Given a certain index, how many indices of the same type can be found within the given geometry. This count
* includes the given index.<br>
* For example, if the index points to a vertex on a LinearRing within a polygon, then this will return the amount
* of vertices on that LinearRing.
*
* @param geometry The geometry to look into.
* @param index The index to take as example (can be of any type).
* @return Returns the total amount of siblings.
*/
public int getSiblingCount(Geometry geometry, GeometryIndex index) {
return delegate.getSiblingCount(geometry, toDelegate(index));
}
/**
* Get the full list of sibling vertices in the form of a coordinate array.
*
* @param geometry The geometry wherein to search for a certain coordinate array.
* @param index An index pointing to a vertex or edge within the geometry. This index will then naturally be a part
* of a coordinate array. It is this array we're looking for.
* @return Returns the array of coordinate from within the geometry where the given index is a part of.
* @throws GeometryIndexNotFoundException geometry index not found
*/
public Coordinate[] getSiblingVertices(Geometry geometry, GeometryIndex index)
throws GeometryIndexNotFoundException {
try {
return delegate.getSiblingVertices(geometry, toDelegate(index));
} catch (org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
throw fromDelegate(e);
}
}
/**
* Get the index of the (smallest) linear ring of the geometry that contains this coordinate.
*
* @param geometry
* @param c
* @return the index (empty array indicates no containment)
* @since 2.1.0
*/
public GeometryIndex getLinearRingIndex(Geometry geometry, Coordinate location) {
return fromDelegate(GeometryService.getLinearRingIndex(geometry, location));
}
/**
* Validates a geometry, focusing on changes at a specific sub-level of the geometry. The sublevel is indicated by
* passing an index. The only checks are on intersection (for coordinates) and containment (for subgeometries), we
* don't check on too few coordinates as we want to support incremental creation of polygons.
*
* @param geometry The geometry to check.
* @param index index that points to a sub-geometry, edge, vertex, etc...
* @return validation state.
* @since 2.1.0
*/
public GeometryValidationState validate(Geometry geometry, GeometryIndex index) {
return GeometryService.validate(geometry, toDelegate(index));
}
// Conversion methods from/to the indexService of the geometry project
private org.geomajas.geometry.service.GeometryIndex toDelegate(GeometryIndex index) {
if (index == null) {
return null;
}
org.geomajas.geometry.service.GeometryIndex result = delegate.create(toDelegate(index.getType()),
index.getValue());
GeometryIndex child = index.getChild();
while (child != null) {
result = delegate.addChildren(result, toDelegate(child.getType()), child.getValue());
child = child.getChild();
}
return result;
}
private GeometryIndex fromDelegate(org.geomajas.geometry.service.GeometryIndex index) {
if (index == null) {
return null;
}
GeometryIndex result = new GeometryIndex(fromDelegate(index.getType()), index.getValue(),
fromDelegate(index.getChild()));
return result;
}
private org.geomajas.geometry.service.GeometryIndexType toDelegate(GeometryIndexType type) {
return org.geomajas.geometry.service.GeometryIndexType.valueOf(type.name());
}
private GeometryIndexType fromDelegate(org.geomajas.geometry.service.GeometryIndexType type) {
return GeometryIndexType.valueOf(type.name());
}
private GeometryIndexNotFoundException fromDelegate(
org.geomajas.geometry.service.GeometryIndexNotFoundException e) {
return new GeometryIndexNotFoundException(e.getMessage(), e.getCause());
}
}