HHH-6511 - Geolatte WKT decoder replaces custom EWKT parser.
This commit is contained in:
parent
4b7c319cc0
commit
b4b626c398
|
@ -27,8 +27,10 @@ import javax.persistence.Table;
|
||||||
|
|
||||||
import com.vividsolutions.jts.geom.Geometry;
|
import com.vividsolutions.jts.geom.Geometry;
|
||||||
import com.vividsolutions.jts.io.ParseException;
|
import com.vividsolutions.jts.io.ParseException;
|
||||||
|
import org.geolatte.geom.codec.Wkt;
|
||||||
|
import org.geolatte.geom.codec.WktDecoder;
|
||||||
|
import org.geolatte.geom.jts.JTS;
|
||||||
|
|
||||||
import org.hibernate.spatial.testing.EWKTReader;
|
|
||||||
import org.hibernate.spatial.testing.TestDataElement;
|
import org.hibernate.spatial.testing.TestDataElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,10 +73,10 @@ public class GeomEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeomEntity createFrom(TestDataElement element) throws ParseException {
|
public static GeomEntity createFrom(TestDataElement element) throws ParseException {
|
||||||
EWKTReader reader = new EWKTReader();
|
WktDecoder<org.geolatte.geom.Geometry> decoder = Wkt.newWktDecoder( Wkt.Dialect.POSTGIS_EWKT_1 );
|
||||||
|
Geometry geom = JTS.to( decoder.decode( element.wkt ) );
|
||||||
GeomEntity result = new GeomEntity();
|
GeomEntity result = new GeomEntity();
|
||||||
result.setId( element.id );
|
result.setId( element.id );
|
||||||
Geometry geom = reader.read( element.wkt );
|
|
||||||
geom.setSRID( element.srid );
|
geom.setSRID( element.srid );
|
||||||
result.setGeom( geom );
|
result.setGeom( geom );
|
||||||
result.setType( element.type );
|
result.setType( element.type );
|
||||||
|
|
|
@ -38,8 +38,11 @@ import java.util.Properties;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import com.vividsolutions.jts.geom.Geometry;
|
import com.vividsolutions.jts.geom.Geometry;
|
||||||
import com.vividsolutions.jts.io.ParseException;
|
|
||||||
import org.apache.commons.dbcp.BasicDataSource;
|
import org.apache.commons.dbcp.BasicDataSource;
|
||||||
|
import org.geolatte.geom.codec.Wkt;
|
||||||
|
import org.geolatte.geom.codec.WktDecodeException;
|
||||||
|
import org.geolatte.geom.codec.WktDecoder;
|
||||||
|
import org.geolatte.geom.jts.JTS;
|
||||||
|
|
||||||
import org.hibernate.spatial.Log;
|
import org.hibernate.spatial.Log;
|
||||||
import org.hibernate.spatial.LogFactory;
|
import org.hibernate.spatial.LogFactory;
|
||||||
|
@ -356,13 +359,13 @@ public class DataSourceUtils {
|
||||||
*/
|
*/
|
||||||
public Map<Integer, Geometry> expectedGeoms(String type, TestData testData) {
|
public Map<Integer, Geometry> expectedGeoms(String type, TestData testData) {
|
||||||
Map<Integer, Geometry> result = new HashMap<Integer, Geometry>();
|
Map<Integer, Geometry> result = new HashMap<Integer, Geometry>();
|
||||||
EWKTReader parser = new EWKTReader();
|
WktDecoder<org.geolatte.geom.Geometry> decoder = Wkt.newWktDecoder();
|
||||||
for ( TestDataElement testDataElement : testData ) {
|
for ( TestDataElement testDataElement : testData ) {
|
||||||
if ( testDataElement.type.equalsIgnoreCase( type ) ) {
|
if ( testDataElement.type.equalsIgnoreCase( type ) ) {
|
||||||
try {
|
try {
|
||||||
result.put( testDataElement.id, parser.read( testDataElement.wkt ) );
|
result.put( testDataElement.id, JTS.to( decoder.decode( testDataElement.wkt ) ) );
|
||||||
}
|
}
|
||||||
catch ( ParseException e ) {
|
catch ( WktDecodeException e ) {
|
||||||
System.out
|
System.out
|
||||||
.println(
|
.println(
|
||||||
String.format(
|
String.format(
|
||||||
|
|
|
@ -1,907 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of Hibernate Spatial, an extension to the
|
|
||||||
* hibernate ORM solution for spatial (geographic) data.
|
|
||||||
*
|
|
||||||
* Copyright © 2007-2012 Geovise BVBA
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package org.hibernate.spatial.testing;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StreamTokenizer;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import com.vividsolutions.jts.geom.Coordinate;
|
|
||||||
import com.vividsolutions.jts.geom.Geometry;
|
|
||||||
import com.vividsolutions.jts.geom.GeometryCollection;
|
|
||||||
import com.vividsolutions.jts.geom.GeometryFactory;
|
|
||||||
import com.vividsolutions.jts.geom.LineString;
|
|
||||||
import com.vividsolutions.jts.geom.LinearRing;
|
|
||||||
import com.vividsolutions.jts.geom.MultiPoint;
|
|
||||||
import com.vividsolutions.jts.geom.MultiPolygon;
|
|
||||||
import com.vividsolutions.jts.geom.Point;
|
|
||||||
import com.vividsolutions.jts.geom.Polygon;
|
|
||||||
import com.vividsolutions.jts.geom.PrecisionModel;
|
|
||||||
import com.vividsolutions.jts.io.ParseException;
|
|
||||||
import com.vividsolutions.jts.util.Assert;
|
|
||||||
|
|
||||||
import org.hibernate.spatial.jts.mgeom.MCoordinate;
|
|
||||||
import org.hibernate.spatial.jts.mgeom.MGeometryFactory;
|
|
||||||
import org.hibernate.spatial.jts.mgeom.MLineString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a geometry in EWKT to a JTS-Geometry.
|
|
||||||
* <p/>
|
|
||||||
* <code>EWKTReader</code> supports
|
|
||||||
* extracting <code>Geometry</code> objects from either {@link java.io.Reader}s or
|
|
||||||
* {@link String}s. This allows it to function as a parser to read <code>Geometry</code>
|
|
||||||
* objects from text blocks embedded in other data formats (e.g. XML). <P>
|
|
||||||
* <p/>
|
|
||||||
* A <code>WKTReader</code> is parameterized by a <code>GeometryFactory</code>,
|
|
||||||
* to allow it to create <code>Geometry</code> objects of the appropriate
|
|
||||||
* implementation. In particular, the <code>GeometryFactory</code>
|
|
||||||
* determines the <code>PrecisionModel</code> and <code>SRID</code> that is
|
|
||||||
* used. <P>
|
|
||||||
* <p/>
|
|
||||||
* The <code>WKTReader</code> converts all input numbers to the precise
|
|
||||||
* internal representation.
|
|
||||||
* <p/>
|
|
||||||
* <h3>Notes:</h3>
|
|
||||||
* <ul>
|
|
||||||
* <li>The reader supports non-standard "LINEARRING" tags.
|
|
||||||
* <li>The reader uses Double.parseDouble to perform the conversion of ASCII
|
|
||||||
* numbers to floating point. This means it supports the Java
|
|
||||||
* syntax for floating point literals (including scientific notation).
|
|
||||||
* </ul>
|
|
||||||
* <p/>
|
|
||||||
* <h3>Syntax</h3>
|
|
||||||
* The following syntax specification describes the version of Well-Known Text
|
|
||||||
* supported by JTS.
|
|
||||||
* (The specification uses a syntax language similar to that used in
|
|
||||||
* the C and Java language specifications.)
|
|
||||||
* <p/>
|
|
||||||
* <p/>
|
|
||||||
* <blockquote><pre>
|
|
||||||
* <i>WKTGeometry:</i> one of<i>
|
|
||||||
* <p/>
|
|
||||||
* WKTPoint WKTLineString WKTLinearRing WKTPolygon
|
|
||||||
* WKTMultiPoint WKTMultiLineString WKTMultiPolygon
|
|
||||||
* WKTGeometryCollection</i>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTPoint:</i> <b>POINT ( </b><i>Coordinate</i> <b>)</b>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTLineString:</i> <b>LINESTRING</b> <i>CoordinateSequence</i>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTLinearRing:</i> <b>LINEARRING</b> <i>CoordinateSequence</i>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTPolygon:</i> <b>POLYGON</b> <i>CoordinateSequenceList</i>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTMultiPoint:</i> <b>MULTIPOINT</b> <i>CoordinateSequence</i>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTMultiLineString:</i> <b>MULTILINESTRING</b> <i>CoordinateSequenceList</i>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTMultiPolygon:</i>
|
|
||||||
* <b>MULTIPOLYGON (</b> <i>CoordinateSequenceList {</i> , <i>CoordinateSequenceList }</i> <b>)</b>
|
|
||||||
* <p/>
|
|
||||||
* <i>WKTGeometryCollection: </i>
|
|
||||||
* <b>GEOMETRYCOLLECTION (</b> <i>WKTGeometry {</i> , <i>WKTGeometry }</i> <b>)</b>
|
|
||||||
* <p/>
|
|
||||||
* <i>CoordinateSequenceList:</i>
|
|
||||||
* <b>(</b> <i>CoordinateSequence {</i> <b>,</b> <i>CoordinateSequence }</i> <b>)</b>
|
|
||||||
* <p/>
|
|
||||||
* <i>CoordinateSequence:</i>
|
|
||||||
* <b>(</b> <i>Coordinate {</i> , <i>Coordinate }</i> <b>)</b>
|
|
||||||
* <p/>
|
|
||||||
* <i>Coordinate:
|
|
||||||
* Number Number Number<sub>opt</sub></i>
|
|
||||||
* <p/>
|
|
||||||
* <i>Number:</i> A Java-style floating-point number
|
|
||||||
* <p/>
|
|
||||||
* </pre></blockquote>
|
|
||||||
*
|
|
||||||
* @see WKTWriter
|
|
||||||
*/
|
|
||||||
public class EWKTReader {
|
|
||||||
private static final String EMPTY = "EMPTY";
|
|
||||||
private static final String COMMA = ",";
|
|
||||||
private static final String L_PAREN = "(";
|
|
||||||
private static final String R_PAREN = ")";
|
|
||||||
private static final String EQUALS = "=";
|
|
||||||
private static final String SEMICOLON = ";";
|
|
||||||
|
|
||||||
private GeometryFactory geometryFactory;
|
|
||||||
private PrecisionModel precisionModel;
|
|
||||||
private StreamTokenizer tokenizer;
|
|
||||||
|
|
||||||
private int dimension = -1;
|
|
||||||
private Boolean hasM = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a reader that creates objects using the default {@link GeometryFactory}.
|
|
||||||
*/
|
|
||||||
public EWKTReader() {
|
|
||||||
this( new MGeometryFactory() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a reader that creates objects using the given
|
|
||||||
* {@link GeometryFactory}.
|
|
||||||
*
|
|
||||||
* @param geometryFactory the factory used to create <code>Geometry</code>s.
|
|
||||||
*/
|
|
||||||
public EWKTReader(GeometryFactory geometryFactory) {
|
|
||||||
this.geometryFactory = geometryFactory;
|
|
||||||
precisionModel = geometryFactory.getPrecisionModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a Well-Known Text representation of a {@link com.vividsolutions.jts.geom.Geometry}
|
|
||||||
* from a {@link String}.
|
|
||||||
*
|
|
||||||
* @param wellKnownText one or more <Geometry Tagged Text>strings (see the OpenGIS
|
|
||||||
* Simple Features Specification) separated by whitespace
|
|
||||||
*
|
|
||||||
* @return a <code>Geometry</code> specified by <code>wellKnownText</code>
|
|
||||||
*
|
|
||||||
* @throws com.vividsolutions.jts.io.ParseException if a parsing problem occurs
|
|
||||||
*/
|
|
||||||
public Geometry read(String wellKnownText) throws ParseException {
|
|
||||||
StringReader reader = new StringReader( wellKnownText );
|
|
||||||
try {
|
|
||||||
return read( reader );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a Well-Known Text representation of a {@link Geometry}
|
|
||||||
* from a {@link java.io.Reader}.
|
|
||||||
*
|
|
||||||
* @param reader a Reader which will return a <Geometry Tagged Text>
|
|
||||||
* string (see the OpenGIS Simple Features Specification)
|
|
||||||
*
|
|
||||||
* @return a <code>Geometry</code> read from <code>reader</code>
|
|
||||||
*
|
|
||||||
* @throws ParseException if a parsing problem occurs
|
|
||||||
*/
|
|
||||||
public Geometry read(Reader reader) throws ParseException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
synchronized ( this ) {
|
|
||||||
if ( this.tokenizer != null ) {
|
|
||||||
throw new RuntimeException( "EWKT-Reader is already in use." );
|
|
||||||
}
|
|
||||||
tokenizer = new StreamTokenizer( reader );
|
|
||||||
}
|
|
||||||
|
|
||||||
// set tokenizer to NOT parse numbers
|
|
||||||
tokenizer.resetSyntax();
|
|
||||||
tokenizer.wordChars( 'a', 'z' );
|
|
||||||
tokenizer.wordChars( 'A', 'Z' );
|
|
||||||
tokenizer.wordChars( 128 + 32, 255 );
|
|
||||||
tokenizer.wordChars( '0', '9' );
|
|
||||||
tokenizer.wordChars( '-', '-' );
|
|
||||||
tokenizer.wordChars( '+', '+' );
|
|
||||||
tokenizer.wordChars( '.', '.' );
|
|
||||||
tokenizer.whitespaceChars( 0, ' ' );
|
|
||||||
tokenizer.commentChar( '#' );
|
|
||||||
|
|
||||||
this.hasM = null;
|
|
||||||
this.dimension = -1;
|
|
||||||
|
|
||||||
return readGeometryTaggedText();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
throw new ParseException( e.toString() );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
this.tokenizer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next array of <code>Coordinate</code>s in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next element returned by the stream should be L_PAREN (the
|
|
||||||
* beginning of "(x1 y1, x2 y2, ..., xn yn)") or EMPTY.
|
|
||||||
*
|
|
||||||
* @return the next array of <code>Coordinate</code>s in the
|
|
||||||
* stream, or an empty array if EMPTY is the next element returned by
|
|
||||||
* the stream.
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws ParseException if an unexpected token was encountered
|
|
||||||
*/
|
|
||||||
private MCoordinate[] getCoordinates()
|
|
||||||
throws IOException, ParseException {
|
|
||||||
String nextToken = getNextEmptyOrOpener();
|
|
||||||
if ( nextToken.equals( EMPTY ) ) {
|
|
||||||
return new MCoordinate[] { };
|
|
||||||
}
|
|
||||||
ArrayList coordinates = new ArrayList();
|
|
||||||
coordinates.add( getPreciseCoordinate() );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
while ( nextToken.equals( COMMA ) ) {
|
|
||||||
coordinates.add( getPreciseCoordinate() );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
}
|
|
||||||
return (MCoordinate[]) coordinates.toArray( new MCoordinate[coordinates.size()] );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the next Coordinate and checks dimension
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws ParseException
|
|
||||||
*/
|
|
||||||
private Coordinate getPreciseCoordinate()
|
|
||||||
throws IOException, ParseException {
|
|
||||||
MCoordinate coord = new MCoordinate();
|
|
||||||
coord.x = getNextNumber();
|
|
||||||
coord.y = getNextNumber();
|
|
||||||
|
|
||||||
Double thirdOrdinateValue = null;
|
|
||||||
Double fourthOrdinateValue = null;
|
|
||||||
|
|
||||||
if ( this.dimension == 3 ) {
|
|
||||||
thirdOrdinateValue = getNextNumber();
|
|
||||||
}
|
|
||||||
else if ( this.dimension == 4 ) {
|
|
||||||
thirdOrdinateValue = getNextNumber();
|
|
||||||
fourthOrdinateValue = getNextNumber();
|
|
||||||
}
|
|
||||||
else if ( this.dimension < 0 ) {
|
|
||||||
if ( isNumberNext() ) {
|
|
||||||
thirdOrdinateValue = getNextNumber();
|
|
||||||
}
|
|
||||||
if ( isNumberNext() ) {
|
|
||||||
fourthOrdinateValue = getNextNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( fourthOrdinateValue != null ) {
|
|
||||||
this.dimension = 4;
|
|
||||||
setHasM( true );
|
|
||||||
}
|
|
||||||
else if ( thirdOrdinateValue != null ) {
|
|
||||||
this.dimension = 3;
|
|
||||||
setHasM( Boolean.TRUE.equals( this.hasM ) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.dimension = 2;
|
|
||||||
setHasM( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ( this.dimension ) {
|
|
||||||
case 2:
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if ( this.hasM ) {
|
|
||||||
coord.m = thirdOrdinateValue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
coord.z = thirdOrdinateValue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if ( this.hasM ) {
|
|
||||||
coord.z = thirdOrdinateValue;
|
|
||||||
coord.m = fourthOrdinateValue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new ParseException( "Unsupported geometry dimension." );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ParseException( "Unsupported geometry dimension." );
|
|
||||||
}
|
|
||||||
|
|
||||||
precisionModel.makePrecise( coord );
|
|
||||||
return coord;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private boolean isNumberNext() throws IOException {
|
|
||||||
int type = tokenizer.nextToken();
|
|
||||||
tokenizer.pushBack();
|
|
||||||
return type == StreamTokenizer.TT_WORD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the next number in the stream.
|
|
||||||
* Numbers with exponents are handled.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next token must be a number.
|
|
||||||
*
|
|
||||||
* @return the next number in the stream
|
|
||||||
*
|
|
||||||
* @throws ParseException if the next token is not a valid number
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private double getNextNumber() throws IOException,
|
|
||||||
ParseException {
|
|
||||||
int type = tokenizer.nextToken();
|
|
||||||
switch ( type ) {
|
|
||||||
case StreamTokenizer.TT_WORD: {
|
|
||||||
try {
|
|
||||||
return Double.parseDouble( tokenizer.sval );
|
|
||||||
}
|
|
||||||
catch ( NumberFormatException ex ) {
|
|
||||||
throw new ParseException( "Invalid number: " + tokenizer.sval );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parseError( "number" );
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next EMPTY or L_PAREN in the stream as uppercase text.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next token must be EMPTY or L_PAREN.
|
|
||||||
*
|
|
||||||
* @return the next EMPTY or L_PAREN in the stream as uppercase
|
|
||||||
* text.
|
|
||||||
*
|
|
||||||
* @throws ParseException if the next token is not EMPTY or L_PAREN
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private String getNextEmptyOrOpener() throws IOException, ParseException {
|
|
||||||
String nextWord = getNextWord();
|
|
||||||
if ( nextWord.equals( EMPTY ) || nextWord.equals( L_PAREN ) ) {
|
|
||||||
return nextWord;
|
|
||||||
}
|
|
||||||
parseError( EMPTY + " or " + L_PAREN );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next R_PAREN or COMMA in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next token must be R_PAREN or COMMA.
|
|
||||||
*
|
|
||||||
* @return the next R_PAREN or COMMA in the stream
|
|
||||||
*
|
|
||||||
* @throws ParseException if the next token is not R_PAREN or COMMA
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private String getNextCloserOrComma() throws IOException, ParseException {
|
|
||||||
String nextWord = getNextWord();
|
|
||||||
if ( nextWord.equals( COMMA ) || nextWord.equals( R_PAREN ) ) {
|
|
||||||
return nextWord;
|
|
||||||
}
|
|
||||||
parseError( COMMA + " or " + R_PAREN );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next R_PAREN in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next token must be R_PAREN.
|
|
||||||
*
|
|
||||||
* @return the next R_PAREN in the stream
|
|
||||||
*
|
|
||||||
* @throws ParseException if the next token is not R_PAREN
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private String getNextCloser() throws IOException, ParseException {
|
|
||||||
String nextWord = getNextWord();
|
|
||||||
if ( nextWord.equals( R_PAREN ) ) {
|
|
||||||
return nextWord;
|
|
||||||
}
|
|
||||||
parseError( R_PAREN );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next R_PAREN in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next token must be R_PAREN.
|
|
||||||
*
|
|
||||||
* @return the next R_PAREN in the stream
|
|
||||||
*
|
|
||||||
* @throws ParseException if the next token is not R_PAREN
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private int getSRID() throws IOException, ParseException {
|
|
||||||
if ( !getNextWord().equals( EQUALS ) ) {
|
|
||||||
parseError( EQUALS );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int srid = Integer.parseInt( getNextWord() );
|
|
||||||
if ( !getNextWord().equals( SEMICOLON ) ) {
|
|
||||||
parseError( SEMICOLON );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return srid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next word in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next token must be a word.
|
|
||||||
*
|
|
||||||
* @return the next word in the stream as uppercase text
|
|
||||||
*
|
|
||||||
* @throws ParseException if the next token is not a word
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private String getNextWord() throws IOException, ParseException {
|
|
||||||
int type = tokenizer.nextToken();
|
|
||||||
switch ( type ) {
|
|
||||||
case StreamTokenizer.TT_WORD:
|
|
||||||
|
|
||||||
String word = tokenizer.sval;
|
|
||||||
if ( word.equalsIgnoreCase( EMPTY ) ) {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
return word;
|
|
||||||
|
|
||||||
case '(':
|
|
||||||
return L_PAREN;
|
|
||||||
case ')':
|
|
||||||
return R_PAREN;
|
|
||||||
case ',':
|
|
||||||
return COMMA;
|
|
||||||
case '=':
|
|
||||||
return EQUALS;
|
|
||||||
case ';':
|
|
||||||
return SEMICOLON;
|
|
||||||
}
|
|
||||||
parseError( "word" );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Throws a formatted ParseException for the current token.
|
|
||||||
*
|
|
||||||
* @param expected a description of what was expected
|
|
||||||
*
|
|
||||||
* @throws ParseException
|
|
||||||
* @throws com.vividsolutions.jts.util.AssertionFailedException if an invalid token is encountered
|
|
||||||
*/
|
|
||||||
private void parseError(String expected)
|
|
||||||
throws ParseException {
|
|
||||||
// throws Asserts for tokens that should never be seen
|
|
||||||
if ( tokenizer.ttype == StreamTokenizer.TT_NUMBER ) {
|
|
||||||
Assert.shouldNeverReachHere( "Unexpected NUMBER token" );
|
|
||||||
}
|
|
||||||
if ( tokenizer.ttype == StreamTokenizer.TT_EOL ) {
|
|
||||||
Assert.shouldNeverReachHere( "Unexpected EOL token" );
|
|
||||||
}
|
|
||||||
|
|
||||||
String tokenStr = tokenString();
|
|
||||||
throw new ParseException( "Expected " + expected + " but found " + tokenStr );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a description of the current token
|
|
||||||
*
|
|
||||||
* @return a description of the current token
|
|
||||||
*/
|
|
||||||
private String tokenString() {
|
|
||||||
switch ( tokenizer.ttype ) {
|
|
||||||
case StreamTokenizer.TT_NUMBER:
|
|
||||||
return "<NUMBER>";
|
|
||||||
case StreamTokenizer.TT_EOL:
|
|
||||||
return "End-of-Line";
|
|
||||||
case StreamTokenizer.TT_EOF:
|
|
||||||
return "End-of-Stream";
|
|
||||||
case StreamTokenizer.TT_WORD:
|
|
||||||
return "'" + tokenizer.sval + "'";
|
|
||||||
}
|
|
||||||
return "'" + (char) tokenizer.ttype + "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>Geometry</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <Geometry Tagged Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>Geometry</code> specified by the next token
|
|
||||||
* in the stream
|
|
||||||
*
|
|
||||||
* @throws ParseException if the coordinates used to create a <code>Polygon</code>
|
|
||||||
* shell and holes do not form closed linestrings, or if an unexpected
|
|
||||||
* token was encountered
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private Geometry readGeometryTaggedText() throws IOException, ParseException {
|
|
||||||
|
|
||||||
String type = null;
|
|
||||||
Geometry geom;
|
|
||||||
|
|
||||||
int srid = geometryFactory.getSRID();
|
|
||||||
|
|
||||||
try {
|
|
||||||
String firstWord = getNextWord();
|
|
||||||
if ( "SRID".equals( firstWord ) ) {
|
|
||||||
srid = getSRID();
|
|
||||||
type = getNextWord();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
type = firstWord;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch ( ParseException e ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( type.equals( "POINT" ) ) {
|
|
||||||
geom = readPointText();
|
|
||||||
}
|
|
||||||
else if ( type.equals( "POINTM" ) ) {
|
|
||||||
setHasM( true );
|
|
||||||
geom = readPointText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "LINESTRING" ) ) {
|
|
||||||
geom = readLineStringText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "LINESTRINGM" ) ) {
|
|
||||||
setHasM( true );
|
|
||||||
geom = readLineStringText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "LINEARRING" ) ) {
|
|
||||||
geom = readLinearRingText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "LINEARRINGM" ) ) {
|
|
||||||
setHasM( true );
|
|
||||||
geom = readLinearRingText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "POLYGON" ) ) {
|
|
||||||
geom = readPolygonText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "POLYGONM" ) ) {
|
|
||||||
//setHasM(true);
|
|
||||||
//geom = readPolygonText();
|
|
||||||
throw new RuntimeException( "PolygonM is not supported." );
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "MULTIPOINT" ) ) {
|
|
||||||
geom = readMultiPointText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "MULTIPOINTM" ) ) {
|
|
||||||
setHasM( true );
|
|
||||||
geom = readMultiPointText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "MULTILINESTRING" ) ) {
|
|
||||||
geom = readMultiLineStringText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "MULTILINESTRINGM" ) ) {
|
|
||||||
setHasM( true );
|
|
||||||
geom = readMultiLineStringText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "MULTIPOLYGON" ) ) {
|
|
||||||
geom = readMultiPolygonText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "MULTIPOLYGONM" ) ) {
|
|
||||||
//setHasM(true);
|
|
||||||
//geom = readMultiPolygonText();
|
|
||||||
throw new RuntimeException( "MultiPolygonM is not supported." );
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "GEOMETRYCOLLECTION" ) ) {
|
|
||||||
geom = readGeometryCollectionText();
|
|
||||||
}
|
|
||||||
else if ( type.equalsIgnoreCase( "GEOMETRYCOLLECTIONM" ) ) {
|
|
||||||
setHasM( true );
|
|
||||||
geom = readGeometryCollectionText();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new ParseException( "Unknown geometry type: " + type );
|
|
||||||
}
|
|
||||||
geom.setSRID( srid );
|
|
||||||
|
|
||||||
return geom;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* m-values sicherstellen
|
|
||||||
*
|
|
||||||
* @throws ParseException
|
|
||||||
*/
|
|
||||||
private void setHasM(boolean hasM) throws ParseException {
|
|
||||||
if ( this.hasM == null ) {
|
|
||||||
this.hasM = hasM;
|
|
||||||
}
|
|
||||||
else if ( this.hasM != hasM ) {
|
|
||||||
throw new ParseException( "Inkonsistent use of m-values." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>Point</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <Point Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>Point</code> specified by the next token in
|
|
||||||
* the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws ParseException if an unexpected token was encountered
|
|
||||||
*/
|
|
||||||
private Point readPointText() throws IOException, ParseException {
|
|
||||||
|
|
||||||
String nextToken = getNextEmptyOrOpener();
|
|
||||||
if ( nextToken.equals( EMPTY ) ) {
|
|
||||||
return geometryFactory.createPoint( (Coordinate) null );
|
|
||||||
}
|
|
||||||
Point point = geometryFactory.createPoint( getPreciseCoordinate() );
|
|
||||||
getNextCloser();
|
|
||||||
return point;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>LineString</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <LineString Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>LineString</code> specified by the next
|
|
||||||
* token in the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws ParseException if an unexpected token was encountered
|
|
||||||
*/
|
|
||||||
private LineString readLineStringText() throws IOException, ParseException {
|
|
||||||
|
|
||||||
MCoordinate[] coords = getCoordinates();
|
|
||||||
if ( this.hasM != null && this.hasM ) {
|
|
||||||
return ( (MGeometryFactory) geometryFactory ).createMLineString( coords );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return geometryFactory.createLineString( coords );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>LinearRing</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <LineString Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>LinearRing</code> specified by the next
|
|
||||||
* token in the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws ParseException if the coordinates used to create the <code>LinearRing</code>
|
|
||||||
* do not form a closed linestring, or if an unexpected token was
|
|
||||||
* encountered
|
|
||||||
*/
|
|
||||||
private LinearRing readLinearRingText()
|
|
||||||
throws IOException, ParseException {
|
|
||||||
MCoordinate[] coords = getCoordinates();
|
|
||||||
if ( this.hasM ) {
|
|
||||||
throw new RuntimeException( "LinearRingM not supported." );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return geometryFactory.createLinearRing( coords );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>MultiPoint</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <MultiPoint Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>MultiPoint</code> specified by the next
|
|
||||||
* token in the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws ParseException if an unexpected token was encountered
|
|
||||||
*/
|
|
||||||
private MultiPoint readMultiPointText() throws IOException, ParseException {
|
|
||||||
MCoordinate[] coords = getCoordinates();
|
|
||||||
Point[] pts = toPoints( coords );
|
|
||||||
return geometryFactory.createMultiPoint( pts );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an array of <code>Point</code>s having the given <code>Coordinate</code>
|
|
||||||
* s.
|
|
||||||
*
|
|
||||||
* @param coordinates the <code>Coordinate</code>s with which to create the
|
|
||||||
* <code>Point</code>s
|
|
||||||
*
|
|
||||||
* @return <code>Point</code>s created using this <code>WKTReader</code>
|
|
||||||
* s <code>GeometryFactory</code>
|
|
||||||
*/
|
|
||||||
private Point[] toPoints(Coordinate[] coordinates) {
|
|
||||||
ArrayList points = new ArrayList();
|
|
||||||
for ( int i = 0; i < coordinates.length; i++ ) {
|
|
||||||
points.add( geometryFactory.createPoint( coordinates[i] ) );
|
|
||||||
}
|
|
||||||
return (Point[]) points.toArray( new Point[] { } );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>Polygon</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param hasM
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <Polygon Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>Polygon</code> specified by the next token
|
|
||||||
* in the stream
|
|
||||||
*
|
|
||||||
* @throws ParseException if the coordinates used to create the <code>Polygon</code>
|
|
||||||
* shell and holes do not form closed linestrings, or if an unexpected
|
|
||||||
* token was encountered.
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private Polygon readPolygonText() throws IOException, ParseException {
|
|
||||||
|
|
||||||
// PolygonM is not supported
|
|
||||||
setHasM( false );
|
|
||||||
|
|
||||||
String nextToken = getNextEmptyOrOpener();
|
|
||||||
if ( nextToken.equals( EMPTY ) ) {
|
|
||||||
return geometryFactory.createPolygon(
|
|
||||||
geometryFactory.createLinearRing(
|
|
||||||
new Coordinate[] { }
|
|
||||||
), new LinearRing[] { }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ArrayList holes = new ArrayList();
|
|
||||||
LinearRing shell = readLinearRingText();
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
while ( nextToken.equals( COMMA ) ) {
|
|
||||||
LinearRing hole = readLinearRingText();
|
|
||||||
holes.add( hole );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
}
|
|
||||||
LinearRing[] array = new LinearRing[holes.size()];
|
|
||||||
return geometryFactory.createPolygon( shell, (LinearRing[]) holes.toArray( array ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>MultiLineString</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param hasM
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <MultiLineString Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>MultiLineString</code> specified by the
|
|
||||||
* next token in the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws ParseException if an unexpected token was encountered
|
|
||||||
*/
|
|
||||||
private com.vividsolutions.jts.geom.MultiLineString readMultiLineStringText() throws IOException, ParseException {
|
|
||||||
|
|
||||||
ArrayList lineStrings = new ArrayList();
|
|
||||||
|
|
||||||
String nextToken = getNextEmptyOrOpener();
|
|
||||||
if ( nextToken.equals( EMPTY ) ) {
|
|
||||||
// No Coordinates for LineString
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LineString lineString = readLineStringText();
|
|
||||||
lineStrings.add( lineString );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
while ( nextToken.equals( COMMA ) ) {
|
|
||||||
lineString = readLineStringText();
|
|
||||||
lineStrings.add( lineString );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this.hasM != null && this.hasM == true ) {
|
|
||||||
MLineString[] mlines = (MLineString[]) lineStrings.toArray( new MLineString[lineStrings.size()] );
|
|
||||||
return ( (MGeometryFactory) geometryFactory ).createMultiMLineString( mlines );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setHasM( false );
|
|
||||||
LineString[] lines = (LineString[]) lineStrings.toArray( new LineString[lineStrings.size()] );
|
|
||||||
return geometryFactory.createMultiLineString( lines );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>MultiPolygon</code> using the next token in the stream.
|
|
||||||
*
|
|
||||||
* @param hasM
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <MultiPolygon Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>MultiPolygon</code> specified by the next
|
|
||||||
* token in the stream, or if if the coordinates used to create the
|
|
||||||
* <code>Polygon</code> shells and holes do not form closed linestrings.
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws ParseException if an unexpected token was encountered
|
|
||||||
*/
|
|
||||||
private MultiPolygon readMultiPolygonText()
|
|
||||||
throws IOException, ParseException {
|
|
||||||
|
|
||||||
// MultiPolygonM is not supported
|
|
||||||
setHasM( false );
|
|
||||||
|
|
||||||
String nextToken = getNextEmptyOrOpener();
|
|
||||||
if ( nextToken.equals( EMPTY ) ) {
|
|
||||||
return geometryFactory.createMultiPolygon( new Polygon[] { } );
|
|
||||||
}
|
|
||||||
ArrayList polygons = new ArrayList();
|
|
||||||
Polygon polygon = readPolygonText();
|
|
||||||
polygons.add( polygon );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
while ( nextToken.equals( COMMA ) ) {
|
|
||||||
polygon = readPolygonText();
|
|
||||||
polygons.add( polygon );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
}
|
|
||||||
Polygon[] array = new Polygon[polygons.size()];
|
|
||||||
return geometryFactory.createMultiPolygon( (Polygon[]) polygons.toArray( array ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a <code>GeometryCollection</code> using the next token in the
|
|
||||||
* stream.
|
|
||||||
*
|
|
||||||
* @param tokenizer tokenizer over a stream of text in Well-known Text
|
|
||||||
* format. The next tokens must form a <GeometryCollection Text>.
|
|
||||||
*
|
|
||||||
* @return a <code>GeometryCollection</code> specified by the
|
|
||||||
* next token in the stream
|
|
||||||
*
|
|
||||||
* @throws ParseException if the coordinates used to create a <code>Polygon</code>
|
|
||||||
* shell and holes do not form closed linestrings, or if an unexpected
|
|
||||||
* token was encountered
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
*/
|
|
||||||
private GeometryCollection readGeometryCollectionText()
|
|
||||||
throws IOException, ParseException {
|
|
||||||
|
|
||||||
String nextToken = getNextEmptyOrOpener();
|
|
||||||
if ( nextToken.equals( EMPTY ) ) {
|
|
||||||
return geometryFactory.createGeometryCollection( new Geometry[] { } );
|
|
||||||
}
|
|
||||||
ArrayList geometries = new ArrayList();
|
|
||||||
Geometry geometry = readGeometryTaggedText();
|
|
||||||
geometries.add( geometry );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
while ( nextToken.equals( COMMA ) ) {
|
|
||||||
geometry = readGeometryTaggedText();
|
|
||||||
geometries.add( geometry );
|
|
||||||
nextToken = getNextCloserOrComma();
|
|
||||||
}
|
|
||||||
Geometry[] array = new Geometry[geometries.size()];
|
|
||||||
return geometryFactory.createGeometryCollection( (Geometry[]) geometries.toArray( array ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -40,7 +40,7 @@ public class GeometryEquality {
|
||||||
return geom2 == null;
|
return geom2 == null;
|
||||||
}
|
}
|
||||||
if ( geom1.isEmpty() ) {
|
if ( geom1.isEmpty() ) {
|
||||||
return geom2.isEmpty() && geom1.getSRID() == geom2.getSRID();
|
return geom2.isEmpty() && equalSRID( geom1, geom2 );
|
||||||
}
|
}
|
||||||
if ( geom1 instanceof GeometryCollection ) {
|
if ( geom1 instanceof GeometryCollection ) {
|
||||||
if ( !( geom2 instanceof GeometryCollection ) ) {
|
if ( !( geom2 instanceof GeometryCollection ) ) {
|
||||||
|
@ -62,6 +62,18 @@ public class GeometryEquality {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two geometries are equal iff both have the same SRID, or both are unknown (i.e. a SRID of 0 or -1).
|
||||||
|
*
|
||||||
|
* @param geom1
|
||||||
|
* @param geom2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean equalSRID(Geometry geom1, Geometry geom2) {
|
||||||
|
return geom1.getSRID() == geom2.getSRID() ||
|
||||||
|
( geom1.getSRID() <1 && geom2.getSRID() < 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether two geometries, not of type GeometryCollection are equal.
|
* Test whether two geometries, not of type GeometryCollection are equal.
|
||||||
*
|
*
|
||||||
|
@ -72,7 +84,7 @@ public class GeometryEquality {
|
||||||
*/
|
*/
|
||||||
protected boolean testSimpleGeometryEquality(Geometry geom1, Geometry geom2) {
|
protected boolean testSimpleGeometryEquality(Geometry geom1, Geometry geom2) {
|
||||||
//return geom1.equals(geom2);
|
//return geom1.equals(geom2);
|
||||||
return testTypeAndVertexEquality( geom1, geom2 ) && geom1.getSRID() == geom2.getSRID();
|
return testTypeAndVertexEquality( geom1, geom2 ) && equalSRID( geom1, geom2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean testTypeAndVertexEquality(Geometry geom1, Geometry geom2) {
|
protected boolean testTypeAndVertexEquality(Geometry geom1, Geometry geom2) {
|
||||||
|
|
Loading…
Reference in New Issue