Skip to content

Commit

Permalink
GIS #462: added GeometryCollections and tests for them
Browse files Browse the repository at this point in the history
  • Loading branch information
danylokravchenko committed Nov 3, 2023
1 parent 47f040c commit 2d817d3
Show file tree
Hide file tree
Showing 10 changed files with 506 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.activej.serializer.CorruptedDataException;
import io.activej.serializer.SimpleSerializerDef;
import io.activej.serializer.annotations.Deserialize;
import java.util.List;
import java.util.Objects;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -78,33 +79,33 @@ public class PolyGeometry extends PolyValue {
*/
public PolyGeometry( @JsonProperty("wkt") @Deserialize("wkt") String wkt ) throws InvalidGeometryException {
this( PolyType.GEOMETRY );
int SRID = NO_SRID;
int srid = NO_SRID;
try {
wkt = wkt.trim();
// WKT is actually an extended EWKT with SRID before the WKT
if ( wkt.startsWith( "SRID" ) ) {
// in WKT semicolon is invalid character, so we could safely split by it
String[] ewktParts = wkt.split( ";" );
SRID = Integer.parseInt( ewktParts[0].replace( "SRID=", "" ) );
srid = Integer.parseInt( ewktParts[0].replace( "SRID=", "" ) );
wkt = ewktParts[1];
}
} catch ( NumberFormatException e ) {
throw new InvalidGeometryException( e.getMessage() );
}
init( wkt, SRID );
init( wkt, srid );
}


/**
* Constructor creates the {@link PolyGeometry} from the WKT text using the provided SRID.
*
* @param wkt Well Know Text representation of the geometry
* @param SRID Spatial reference system of the geometry
* @param srid Spatial reference system of the geometry
* @throws InvalidGeometryException if {@link PolyGeometry} is invalid or provided WKT is invalid.
*/
public PolyGeometry( @JsonProperty("wkt") @Deserialize("wkt") String wkt, int SRID ) throws InvalidGeometryException {
public PolyGeometry( @JsonProperty("wkt") @Deserialize("wkt") String wkt, int srid ) throws InvalidGeometryException {
this( PolyType.GEOMETRY );
init( wkt, SRID );
init( wkt, srid );
}


Expand All @@ -126,8 +127,8 @@ public static PolyGeometry of( String wkt ) throws InvalidGeometryException {
}


public static PolyGeometry of( String wkt, int SRID ) throws InvalidGeometryException {
return new PolyGeometry( wkt, SRID );
public static PolyGeometry of( String wkt, int srid ) throws InvalidGeometryException {
return new PolyGeometry( wkt, srid );
}


Expand All @@ -136,8 +137,8 @@ public static PolyGeometry of( Geometry geometry ) {
}


private void init( String wkt, int SRID ) throws InvalidGeometryException {
this.SRID = SRID;
private void init( String wkt, int srid ) throws InvalidGeometryException {
this.SRID = srid;
WKTReader reader = new WKTReader();
try {
this.jtsGeometry = reader.read( wkt );
Expand All @@ -160,9 +161,17 @@ protected PolyGeometryType getPolyGeometryType() {
case "LineString":
return PolyGeometryType.LINESTRING;
case "LinearRing":
return PolyGeometryType.LINEAR_RING;
return PolyGeometryType.LINEARRING;
case "Polygon":
return PolyGeometryType.POLYGON;
case "GeometryCollection":
return PolyGeometryType.GEOMETRYCOLLECTION;
case "MultiPoint":
return PolyGeometryType.MULTIPOINT;
case "MultiLineString":
return PolyGeometryType.MULTILINESTRING;
case "MultiPolygon":
return PolyGeometryType.MULTIPOLYGON;
default:
throw new NotImplementedException( "value" );
}
Expand Down Expand Up @@ -198,7 +207,7 @@ public PolyLineString asLineString() {


public boolean isLinearRing() {
return geometryType.equals( PolyGeometryType.LINEAR_RING );
return geometryType.equals( PolyGeometryType.LINEARRING );
}


Expand All @@ -225,51 +234,64 @@ public PolyPolygon asPolygon() {
}


public boolean isGeometryCollection() {
return List.of( PolyGeometryType.GEOMETRYCOLLECTION, PolyGeometryType.MULTIPOINT, PolyGeometryType.MULTILINESTRING, PolyGeometryType.MULTIPOLYGON ).contains( geometryType );
}


@NotNull
public PolyGeometryCollection asGeometryCollection() {
if ( isGeometryCollection() ) {
return PolyGeometryCollection.of( jtsGeometry );
}
throw cannotParse( this, PolyGeometryCollection.class );
}


/**
* Tests whether this {@link Geometry} is simple.
* Tests whether this {@link PolyGeometry} is a simple geometry: does not intersect itself.
* May touch its own boundary at any point.
*
* @return <code>true</code> if {@link Geometry} is simple.
* @return <code>true</code> if {@link PolyGeometry} is simple.
*/
public boolean isSimple() {
return jtsGeometry.isSimple();
}


/**
* @return <code>true</code> if the set of points covered by this {@link Geometry} is empty.
* @return <code>true</code> if the set of points covered by this {@link PolyGeometry} is empty.
*/
public boolean isEmpty() {
return jtsGeometry.isEmpty();
}


/**
* @return the count of this {@link Geometry} vertices.
* @return the count of this {@link PolyGeometry} vertices.
*/
public int getNumPoints() {
return jtsGeometry.getNumPoints();
}


/**
* @return the dimension of this {@link Geometry}.
* @return the dimension of this {@link PolyGeometry}.
*/
public int getDimension() {
return jtsGeometry.getDimension();
}

// TODO: add geometry collections (@link) to documentation


/**
* Linear geometries return their length.
* Areal geometries return their perimeter.
* The length of a {@link PolyPoint} or {link PolyMultiPoint} is 0.
* The length of a {@link PolyLineString} is the sum of the lengths of each line segment: distance from the start point to the end point
* The length of a {@link PolyPolygon} is the sum of the lengths of the exterior boundary and any interior boundaries.
* The length of any {link GeometryCollection} is the sum of the lengths of all {@link PolyGeometry} it contains.
* The length of a {@link PolyPoint} or {@link PolyMultiPoint} is 0.
* The length of a {@link PolyLineString} or {@link PolyMultiLineString} is the sum of the lengths of each line segment: distance from the start point to the end point
* The length of a {@link PolyPolygon} or {@link PolyMultiPolygon} is the sum of the lengths of the exterior boundary and any interior boundaries.
* The length of any {@link PolyGeometryCollection} is the sum of the lengths of all {@link PolyGeometry} it contains.
*
* @return the length of this {@link Geometry}
* @return the length of this {@link PolyGeometry}
*/
public double getLength() {
return jtsGeometry.getLength();
Expand All @@ -279,15 +301,15 @@ public double getLength() {
/**
* Areal Geometries have a non-zero area.
*
* @return the area of this {@link Geometry}
* @return the area of this {@link PolyGeometry}
*/
public double getArea() {
return jtsGeometry.getArea();
}


/**
* Bound the {@link PolyGeometry} my the minimum box that could fit this geometry.
* Bound the {@link PolyGeometry} by the minimum box that could fit this geometry.
*
* @return {@link PolyGeometry} with minimum bounding box
*/
Expand All @@ -298,17 +320,28 @@ public PolyGeometry getEnvelope() {

/**
* The boundary of a {@link PolyGeometry} is a set of {@link PolyGeometry}s of the next lower dimension
* that define the limit of this {@link PolyGeometry}.
* that define the limit of this {@link PolyGeometry}:
* For {@link PolyLineString} the boundary is start and end {@link PolyPoint}: {@link PolyMultiPoint}.
* For {@link PolyPolygon} the boundary is an exterior shell {@link PolyLinearRing}.
*
* @return the closure of the combinatorial boundary of this {@link PolyGeometry}
* @return the set of the combinatorial boundary {@link PolyGeometry} that define the limit of this {@link PolyGeometry}
*/
public PolyGeometry getBoundary() {
return PolyGeometry.of( jtsGeometry.getBoundary() );
}


/**
* @return the dimension of the boundary of this {@link PolyGeometry}.
*/
public int getBoundaryDimension() {
return jtsGeometry.getBoundaryDimension();
}


/**
* Calculate the smallest convex {@link PolyGeometry} that contains this {@link PolyGeometry}.
*
* @return the minimum area {@link PolyGeometry} containing all points in this {@link PolyGeometry}
*/
public PolyGeometry convexHull() {
Expand Down Expand Up @@ -342,7 +375,7 @@ public PolyPoint getCentroid() {
* @return a {@link PolyPolygon} that represent buffer region around this {@link PolyGeometry}
*/
public PolyGeometry buffer( double distance ) {
return PolyPoint.of( jtsGeometry.buffer( distance ) );
return PolyPoint.of( jtsGeometry.buffer( distance ) );
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright 2019-2023 The Polypheny Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.polypheny.db.type.entity.spatial;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.activej.serializer.annotations.Deserialize;
import org.jetbrains.annotations.NotNull;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.polypheny.db.type.PolyType;

/**
* {@link PolyGeometryCollection} is collection that holds {@link PolyGeometry}
* and it is a base class for all <strong>Multi</strong> spatial data types.
* <p>
* Collection of {@link PolyGeometry} of any {@link PolyGeometryType} and dimension.
*/
public class PolyGeometryCollection extends PolyGeometry {

private GeometryCollection jtsGeometryCollection;


public PolyGeometryCollection( @JsonProperty("wkt") @Deserialize("wkt") String wkt ) throws InvalidGeometryException {
super( wkt );
this.geometryType = getPolyGeometryType();
this.jtsGeometryCollection = (GeometryCollection) jtsGeometry;
}


public PolyGeometryCollection( @JsonProperty("wkt") @Deserialize("wkt") String wkt, int srid ) throws InvalidGeometryException {
super( wkt, srid );
this.geometryType = getPolyGeometryType();
this.jtsGeometryCollection = (GeometryCollection) jtsGeometry;
}


public PolyGeometryCollection( Geometry geometry ) {
super( geometry );
this.geometryType = getPolyGeometryType();
this.jtsGeometry = geometry;
this.jtsGeometryCollection = (GeometryCollection) jtsGeometry;
this.SRID = geometry.getSRID();
}


protected PolyGeometryCollection( PolyType type ) {
super( type );
this.geometryType = getPolyGeometryType();
}


public static PolyGeometryCollection of( Geometry geometry ) {
return new PolyGeometryCollection( geometry );
}


/**
* @return the number of {@link PolyGeometry} geometries in the {@link PolyGeometryCollection}.
*/
public int getNumGeometries() {
return jtsGeometryCollection.getNumGeometries();
}


/**
* Get the nth {@link PolyGeometry} in the collection.
*
* @param n number of the {@link PolyGeometry} in the collection
* @return the nth {@link PolyGeometry} in the collection.
*/
public PolyGeometry getGeometryN( int n ) {
return PolyGeometry.of( jtsGeometryCollection.getGeometryN( n ) );
}


public boolean isMultiPoint() {
return geometryType.equals( PolyGeometryType.MULTIPOINT );
}


@NotNull
public PolyMultiPoint asMultiPoint() {
if ( isMultiPoint() ) {
return PolyMultiPoint.of( jtsGeometry );
}
throw cannotParse( this, PolyMultiPoint.class );
}


public boolean isMultiLineString() {
return geometryType.equals( PolyGeometryType.MULTILINESTRING );
}


@NotNull
public PolyMultiLineString asMultiLineString() {
if ( isMultiLineString() ) {
return PolyMultiLineString.of( jtsGeometry );
}
throw cannotParse( this, PolyMultiLineString.class );
}


public boolean isMultiPolygon() {
return geometryType.equals( PolyGeometryType.MULTIPOLYGON );
}


@NotNull
public PolyMultiPolygon asMultiPolygon() {
if ( isMultiPolygon() ) {
return PolyMultiPolygon.of( jtsGeometry );
}
throw cannotParse( this, PolyMultiPolygon.class );
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public enum PolyGeometryType {
POINT( 1 ),
LINESTRING( 2 ),
// not actually a full type
LINEAR_RING( 2 ),
LINEARRING( 2 ),
POLYGON(3),
MULTIPOINT( 4 ),
MULTILINESTRING( 5 ),
MULTIPOLYGON( 6 ),
GEOMCOLLECTION( 7 ),
GEOMETRYCOLLECTION( 7 ),
CURVE( 13 ),
SURFACE( 14 ),
POLYHEDRALSURFACE( 15 );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static PolyLineString of( Geometry geometry ) {
/**
* Test whether {@link PolyLineString} is closed: line starts and ends at the same point.
*
* @return <code>true</code> if {@link LineString} is closed.
* @return <code>true</code> if {@link PolyLineString} is closed.
*/
public boolean isClosed() {
return jtsLineString.isClosed();
Expand All @@ -85,7 +85,7 @@ public boolean isClosed() {
/**
* Test whether {@link PolyLineString} is a ring: simple and closed at the same time.
*
* @return <code>true</code> if {@link LineString} is ring.
* @return <code>true</code> if {@link PolyLineString} is ring.
*/
public boolean isRing() {
return jtsLineString.isRing();
Expand Down
Loading

0 comments on commit 2d817d3

Please sign in to comment.