HHH-6510 : Initial commit.

Source code copied from Hibernate Spatial 1.1.1-SNAPSHOT.
Root package is now org.hibernate.spatial (instead of org.hibernatespatial)
GeometryType replaces GeometryUserType.
SpatialDialects remap SpatialSqlTypeDescriptors.
Hibernate Spatial registers GeometryType in Integrator (temporary fix: see HHH-6507).
This commit is contained in:
Karel Maesen 2011-07-23 15:39:27 +02:00 committed by Steve Ebersole
parent ae43670290
commit 812da6e7cd
82 changed files with 12013 additions and 2 deletions

View File

@ -26,12 +26,16 @@ package org.hibernate.type;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.HibernateException;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.UserType;
import org.jboss.logging.Logger;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A registry of {@link BasicType} instances
@ -123,7 +127,8 @@ public class BasicTypeRegistry implements Serializable {
@SuppressWarnings({ "UnusedDeclaration" })
private BasicTypeRegistry(Map<String, BasicType> registeredTypes) {
registry.putAll( registeredTypes );
locked = true;
//TODO - this is just a temporary work-around!
// locked = true;
}
public void register(BasicType type) {

View File

@ -0,0 +1,32 @@
apply plugin: 'java'
dependencies {
compile( project( ':hibernate-core' ) )
compile( [group: 'com.vividsolutions', name: 'jts', version: '1.11'] ) {
transitive = false
}
compile( [group: 'org.postgis', name: 'postgis-jdbc', version: '1.1.6'] )
compile( [group: 'postgresql', name: 'postgresql', version: '8.1-407.jdbc3'] )
compile( libraries.dom4j ) {
transitive = false
}
compile( libraries.slf4j_log4j12) {
transitive = true
}
testCompile( libraries.junit )
testCompile( project(':hibernate-testing') )
testCompile( [group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4'])
}
sourceSets {
test {
// resources inherently exclude sources
resources {
setSrcDirs( ['src/test/java','src/test/resources'] )
}
}
}

View File

@ -0,0 +1,578 @@
/*
* $Id: Circle.java 253 2010-10-02 15:14:52Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.PrecisionModel;
import java.util.ArrayList;
import java.util.List;
/**
* This class provides operations for handling the usage of Circles and arcs in
* Geometries.
* <p/>
* Date: Oct 15, 2007
*
* @author Tom Acree
*/
public class Circle {
private Coordinate center = new Coordinate(0.0, 0.0);
private double radius = 0;
private PrecisionModel precisionModel = new PrecisionModel();
// Constructors **********************************************************
/**
* Creates a circle whose center is at the origin and whose radius is 0.
*/
protected Circle() {
}
/**
* Create a circle with a defined center and radius
*
* @param center The coordinate representing the center of the circle
* @param radius The radius of the circle
*/
public Circle(Coordinate center, double radius) {
this.center = center;
this.radius = radius;
}
/**
* Create a circle using the x/y coordinates for the center.
*
* @param xCenter The x coordinate of the circle's center
* @param yCenter The y coordinate of the circle's center
* @param radius the radius of the circle
*/
public Circle(double xCenter, double yCenter, double radius) {
this(new Coordinate(xCenter, yCenter), radius);
}
/**
* Creates a circle based on bounding box. It is possible for the user of
* this class to pass bounds to this method that do not represent a square.
* If this is the case, we must force the bounding rectangle to be a square.
* To this end, we check the box and set the side of the box to the larger
* dimension of the rectangle
*
* @param xLeft
* @param yUpper
* @param xRight
* @param yLower
*/
public Circle(double xLeft, double yUpper, double xRight, double yLower) {
double side = Math.min(Math.abs(xRight - xLeft), Math.abs(yLower
- yUpper));
this.center.x = Math.min(xRight, xLeft) + side / 2;
this.center.y = Math.min(yUpper, yLower) + side / 2;
this.radius = side / 2;
}
/**
* Three point method of circle construction. All three points must be on
* the circumference of the circle.
*
* @param point1
* @param point2
* @param point3
*/
public Circle(Coordinate point1, Coordinate point2, Coordinate point3) {
initThreePointCircle(point1, point2, point3);
}
/**
* Three point method of circle construction. All three points must be on
* the circumference of the circle.
*
* @param x1
* @param y1
* @param x2
* @param y2
* @param x3
* @param y3
*/
public Circle(double x1, double y1, double x2, double y2, double x3,
double y3) {
this(new Coordinate(x1, y1), new Coordinate(x2, y2), new Coordinate(x3,
y3));
}
/**
* shift the center of the circle by delta X and delta Y
*/
public void shift(double deltaX, double deltaY) {
this.center.x = this.center.x + deltaX;
this.center.y = this.center.y + deltaY;
}
/**
* Move the circle to a new center
*/
public void move(double x, double y) {
this.center.x = x;
this.center.y = y;
}
/**
* Defines the circle based on three points. All three points must be on on
* the circumference of the circle, and hence, the 3 points cannot be have
* any pair equal, and cannot form a line. Therefore, each point given is
* one radius measure from the circle's center.
*
* @param p1 A point on the desired circle
* @param p2 A point on the desired circle
* @param p3 A point on the desired circle
*/
private void initThreePointCircle(Coordinate p1, Coordinate p2,
Coordinate p3) {
double a13, b13, c13;
double a23, b23, c23;
double x = 0., y = 0., rad = 0.;
// begin pre-calculations for linear system reduction
a13 = 2 * (p1.x - p3.x);
b13 = 2 * (p1.y - p3.y);
c13 = (p1.y * p1.y - p3.y * p3.y) + (p1.x * p1.x - p3.x * p3.x);
a23 = 2 * (p2.x - p3.x);
b23 = 2 * (p2.y - p3.y);
c23 = (p2.y * p2.y - p3.y * p3.y) + (p2.x * p2.x - p3.x * p3.x);
// testsuite-suite to be certain we have three distinct points passed
double smallNumber = 0.01;
if ((Math.abs(a13) < smallNumber && Math.abs(b13) < smallNumber)
|| (Math.abs(a13) < smallNumber && Math.abs(b13) < smallNumber)) {
// // points too close so set to default circle
x = 0;
y = 0;
rad = 0;
} else {
// everything is acceptable do the y calculation
y = (a13 * c23 - a23 * c13) / (a13 * b23 - a23 * b13);
// x calculation
// choose best formula for calculation
if (Math.abs(a13) > Math.abs(a23)) {
x = (c13 - b13 * y) / a13;
} else {
x = (c23 - b23 * y) / a23;
}
// radius calculation
rad = Math.sqrt((x - p1.x) * (x - p1.x) + (y - p1.y) * (y - p1.y));
}
this.center.x = x;
this.center.y = y;
this.radius = rad;
}
public Coordinate getCenter() {
return this.center;
}
public double getRadius() {
return this.radius;
}
/**
* Given 2 points defining an arc on the circle, interpolates the circle
* into a collection of points that provide connected chords that
* approximate the arc based on the tolerance value. The tolerance value
* specifies the maximum distance between a chord and the circle.
*
* @param x1 x coordinate of point 1
* @param y1 y coordinate of point 1
* @param x2 x coordinate of point 2
* @param y2 y coordinate of point 2
* @param x3 x coordinate of point 3
* @param y3 y coordinate of point 3
* @param tolerence maximum distance between the center of the chord and the outer
* edge of the circle
* @return an ordered list of Coordinates representing a series of chords
* approximating the arc.
*/
public static Coordinate[] linearizeArc(double x1, double y1, double x2,
double y2, double x3, double y3, double tolerence) {
Coordinate p1 = new Coordinate(x1, y1);
Coordinate p2 = new Coordinate(x2, y2);
Coordinate p3 = new Coordinate(x3, y3);
return new Circle(p1, p2, p3).linearizeArc(p1, p2, p3, tolerence);
}
/**
* Given 2 points defining an arc on the circle, interpolates the circle
* into a collection of points that provide connected chords that
* approximate the arc based on the tolerance value. This method uses a
* tolerence value of 1/100 of the length of the radius.
*
* @param x1 x coordinate of point 1
* @param y1 y coordinate of point 1
* @param x2 x coordinate of point 2
* @param y2 y coordinate of point 2
* @param x3 x coordinate of point 3
* @param y3 y coordinate of point 3
* @return an ordered list of Coordinates representing a series of chords
* approximating the arc.
*/
public static Coordinate[] linearizeArc(double x1, double y1, double x2,
double y2, double x3, double y3) {
Coordinate p1 = new Coordinate(x1, y1);
Coordinate p2 = new Coordinate(x2, y2);
Coordinate p3 = new Coordinate(x3, y3);
Circle c = new Circle(p1, p2, p3);
double tolerence = 0.01 * c.getRadius();
return c.linearizeArc(p1, p2, p3, tolerence);
}
/**
* Given a circle defined by the 3 points, creates a linearized
* interpolation of the circle starting and ending on the first coordinate.
* This method uses a tolerence value of 1/100 of the length of the radius.
*
* @param x1 x coordinate of point 1
* @param y1 y coordinate of point 1
* @param x2 x coordinate of point 2
* @param y2 y coordinate of point 2
* @param x3 x coordinate of point 3
* @param y3 y coordinate of point 3
* @return an ordered list of Coordinates representing a series of chords
* approximating the arc.
*/
public static Coordinate[] linearizeCircle(double x1, double y1, double x2,
double y2, double x3, double y3) {
Coordinate p1 = new Coordinate(x1, y1);
Coordinate p2 = new Coordinate(x2, y2);
Coordinate p3 = new Coordinate(x3, y3);
Circle c = new Circle(p1, p2, p3);
double tolerence = 0.01 * c.getRadius();
return c.linearizeArc(p1, p2, p1, tolerence);
}
/**
* Given 2 points defining an arc on the circle, interpolates the circle
* into a collection of points that provide connected chords that
* approximate the arc based on the tolerance value. The tolerance value
* specifies the maximum distance between a chord and the circle.
*
* @param p1 begin coordinate of the arc
* @param p2 any other point on the arc
* @param p3 end coordinate of the arc
* @param tolerence maximum distance between the center of the chord and the outer
* edge of the circle
* @return an ordered list of Coordinates representing a series of chords
* approximating the arc.
*/
public Coordinate[] linearizeArc(Coordinate p1, Coordinate p2,
Coordinate p3, double tolerence) {
Arc arc = createArc(p1, p2, p3);
List<Coordinate> result = linearizeInternal(null, arc, tolerence);
return result.toArray(new Coordinate[result.size()]);
}
private List<Coordinate> linearizeInternal(List<Coordinate> coordinates,
Arc arc, double tolerence) {
if (coordinates == null) {
coordinates = new ArrayList<Coordinate>();
}
double arcHt = arc.getArcHeight();
if (Double.compare(arcHt, tolerence) <= 0) {
int lastIndex = coordinates.size() - 1;
Coordinate lastCoord = lastIndex >= 0 ? coordinates.get(lastIndex)
: null;
if (lastCoord == null || !arc.getP1().equals2D(lastCoord)) {
coordinates.add(arc.getP1());
coordinates.add(arc.getP2());
} else {
coordinates.add(arc.getP2());
}
} else {
// otherwise, split
Arc[] splits = arc.split();
linearizeInternal(coordinates, splits[0], tolerence);
linearizeInternal(coordinates, splits[1], tolerence);
}
return coordinates;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Circle circle = (Circle) o;
if (Double.compare(circle.radius, this.radius) != 0) {
return false;
}
if (this.center != null ? !this.center.equals2D(circle.center)
: circle.center != null) {
return false;
}
return true;
}
public String toString() {
return "Circle with Radius = " + this.radius
+ " and a center at the coordinates (" + this.center.x + ", "
+ this.center.y + ")";
}
/**
* Returns the angle of the point from the center and the horizontal line
* from the center.
*
* @param p a point in space
* @return The angle of the point from the center of the circle
*/
public double getAngle(Coordinate p) {
double dx = p.x - this.center.x;
double dy = p.y - this.center.y;
double angle;
if (dx == 0.0) {
if (dy == 0.0) {
angle = 0.0;
} else if (dy > 0.0) {
angle = Math.PI / 2.0;
} else {
angle = (Math.PI * 3.0) / 2.0;
}
} else if (dy == 0.0) {
if (dx > 0.0) {
angle = 0.0;
} else {
angle = Math.PI;
}
} else {
if (dx < 0.0) {
angle = Math.atan(dy / dx) + Math.PI;
} else if (dy < 0.0) {
angle = Math.atan(dy / dx) + (2 * Math.PI);
} else {
angle = Math.atan(dy / dx);
}
}
return angle;
}
public Coordinate getPoint(final double angle) {
double x = Math.cos(angle) * this.radius;
x = x + this.center.x;
x = this.precisionModel.makePrecise(x);
double y = Math.sin(angle) * this.radius;
y = y + this.center.y;
y = this.precisionModel.makePrecise(y);
return new Coordinate(x, y);
}
/**
* @param p A point in space
* @return The distance the point is from the center of the circle
*/
public double distanceFromCenter(Coordinate p) {
return Math.abs(this.center.distance(p));
}
public Arc createArc(Coordinate p1, Coordinate p2, Coordinate p3) {
return new Arc(p1, p2, p3);
}
/**
* Returns an angle between 0 and 2*PI. For example, 4*PI would get returned
* as 2*PI since they are equivalent.
*
* @param angle an angle in radians to normalize
* @return an angle between 0 and 2*PI
*/
public static double normalizeAngle(double angle) {
double maxRadians = 2 * Math.PI;
if (angle >= 0 && angle <= maxRadians) {
return angle;
}
if (angle < 0) {
return maxRadians - Math.abs(angle);
} else {
return angle % maxRadians;
}
}
/**
* Returns the angle between the angles a1 and a2 in radians. Angle is
* calculated in the counterclockwise direction.
*
* @param a1 first angle
* @param a2 second angle
* @return the angle between a1 and a2 in the clockwise direction
*/
public static double subtractAngles(double a1, double a2) {
if (a1 < a2) {
return a2 - a1;
} else {
return TWO_PI - Math.abs(a2 - a1);
}
}
private static final double TWO_PI = Math.PI * 2;
public class Arc {
private Coordinate p1, p2;
private double arcAngle; // angle in radians
private double p1Angle;
private double p2Angle;
private boolean clockwise;
private Arc(Coordinate p1, Coordinate midPt, Coordinate p2) {
this.p1 = p1;
this.p2 = p2;
this.p1Angle = getAngle(p1);
// See if this arc covers the whole circle
if (p1.equals2D(p2)) {
this.p2Angle = TWO_PI + this.p1Angle;
this.arcAngle = TWO_PI;
} else {
this.p2Angle = getAngle(p2);
double midPtAngle = getAngle(midPt);
// determine the direction
double ccDegrees = Circle.subtractAngles(this.p1Angle,
midPtAngle)
+ Circle.subtractAngles(midPtAngle, this.p2Angle);
if (ccDegrees < TWO_PI) {
this.clockwise = false;
this.arcAngle = ccDegrees;
} else {
this.clockwise = true;
this.arcAngle = TWO_PI - ccDegrees;
}
}
}
private Arc(Coordinate p1, Coordinate p2, boolean isClockwise) {
this.p1 = p1;
this.p2 = p2;
this.clockwise = isClockwise;
this.p1Angle = getAngle(p1);
if (p1.equals2D(p2)) {
this.p2Angle = TWO_PI + this.p1Angle;
} else {
this.p2Angle = getAngle(p2);
}
determineArcAngle();
}
private void determineArcAngle() {
double diff;
if (this.p1.equals2D(this.p2)) {
diff = TWO_PI;
} else if (this.clockwise) {
diff = this.p1Angle - this.p2Angle;
} else {
diff = this.p2Angle - this.p1Angle;
}
this.arcAngle = Circle.normalizeAngle(diff);
}
/**
* given a an arc defined from p1 to p2 existing on this circle, returns
* the height of the arc. This height is defined as the distance from
* the center of a chord defined by (p1, p2) and the outer edge of the
* circle.
*
* @return the arc height
*/
public double getArcHeight() {
Coordinate chordCenterPt = this.getChordCenterPoint();
double dist = distanceFromCenter(chordCenterPt);
if (this.arcAngle > Math.PI) {
return Circle.this.radius + dist;
} else {
return Circle.this.radius - dist;
}
}
public Coordinate getChordCenterPoint() {
double centerX = this.p1.x + (this.p2.x - this.p1.x) / 2;
double centerY = this.p1.y + (this.p2.y - this.p1.y) / 2;
return new Coordinate(centerX, centerY);
}
public Arc[] split() {
int directionFactor = isClockwise() ? -1 : 1;
double angleOffset = directionFactor * (this.arcAngle / 2);
double midAngle = this.p1Angle + angleOffset;
Coordinate newMidPoint = getPoint(midAngle);
Arc arc1 = new Arc(this.p1, newMidPoint, isClockwise());
Arc arc2 = new Arc(newMidPoint, this.p2, isClockwise());
return new Arc[]{arc1, arc2};
}
public Coordinate getP1() {
return this.p1;
}
public Coordinate getP2() {
return this.p2;
}
public double getArcAngle() {
return this.arcAngle;
}
public double getArcAngleDegrees() {
return Math.toDegrees(this.arcAngle);
}
public double getP1Angle() {
return this.p1Angle;
}
public double getP2Angle() {
return this.p2Angle;
}
public boolean isClockwise() {
return this.clockwise;
}
public String toString() {
return "P1: " + this.p1 + " P2: " + this.p2 + " clockwise: " + this.clockwise;
}
}
}

View File

@ -0,0 +1,66 @@
/**
* $Id: GeometryType.java 310 2011-05-18 18:05:39Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
/**
* TODO javadoc
*
* @author Karel Maesen
*/
public class GeometryType extends AbstractSingleColumnStandardBasicType<Geometry> {
public static final GeometryType INSTANCE = new GeometryType();
@Override
public String[] getRegistrationKeys() {
return new String[]{
com.vividsolutions.jts.geom.Geometry.class.getCanonicalName(),
com.vividsolutions.jts.geom.Point.class.getCanonicalName(),
com.vividsolutions.jts.geom.Polygon.class.getCanonicalName(),
com.vividsolutions.jts.geom.MultiPolygon.class.getCanonicalName(),
com.vividsolutions.jts.geom.LineString.class.getCanonicalName(),
com.vividsolutions.jts.geom.MultiLineString.class.getCanonicalName(),
com.vividsolutions.jts.geom.MultiPoint.class.getCanonicalName(),
com.vividsolutions.jts.geom.GeometryCollection.class.getCanonicalName()
};
}
public GeometryType() {
super(SpatialGeometrySqlTypeDescriptor.INSTANCE, SpatialGeometryJavaTypeDescriptor.INSTANCE);
}
@Override
public String getName() {
return "Geometry";
}
}

View File

@ -0,0 +1,237 @@
/**
* $Id: HBSpatialExtension.java 253 2010-10-02 15:14:52Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
import org.hibernate.spatial.helper.GeometryFactoryHelper;
import org.hibernate.spatial.cfg.HSConfiguration;
import org.hibernate.spatial.helper.PropertyFileReader;
import org.hibernate.spatial.mgeom.MGeometryFactory;
import org.hibernate.spatial.spi.SpatialDialectProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
/**
* This is the bootstrap class that is used to get an
* <code>SpatialDialect</code>.
* <p/>
* It also provides a default <code>SpatialDialect</code>.
* <code>GeometryType</code>s that do not have a <code>dialect</code>
* parameter use this default.
* <p/>
* The default <code>SpatialDialect</code> will be the first one that is
* returned by the <code>getDefaultDialect</code> method of the provider at
* least if it is non null.
*
* @author Karel Maesen
*/
//TODO -- this should be moved to the
public class HBSpatialExtension {
protected static List<SpatialDialectProvider> providers = new ArrayList<SpatialDialectProvider>();
private static final Logger log = LoggerFactory.getLogger(HBSpatialExtension.class);
private static SpatialDialect defaultSpatialDialect = null;
private static final String DIALECT_PROP_NAME = "hibernate.spatial.dialect";
private static HSConfiguration configuration = null;
private static MGeometryFactory defaultGeomFactory = new MGeometryFactory();
private static boolean configured = false;
static {
log.info("Initializing HBSpatialExtension");
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resources = null;
try {
resources = loader.getResources("META-INF/services/"
+ SpatialDialectProvider.class.getName());
Set<String> names = new HashSet<String>();
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
InputStream is = url.openStream();
try {
names.addAll(providerNamesFromReader(is));
} finally {
is.close();
}
}
for (String s : names) {
try {
log.info("Attempting to load Hibernate Spatial Provider "
+ s);
SpatialDialectProvider provider = (SpatialDialectProvider) loader
.loadClass(s).newInstance();
providers.add(provider);
} catch (Exception e) {
throw new HibernateSpatialException(
"Problem loading provider class", e);
}
}
} catch (IOException e) {
throw new HibernateSpatialException("No "
+ SpatialDialectProvider.class.getName()
+ " found in META-INF/services", e);
}
// configuration - check if there is a system property
String dialectProp = System.getProperty(DIALECT_PROP_NAME);
if (dialectProp != null) {
HSConfiguration hsConfig = new HSConfiguration();
hsConfig.setDefaultDialect(dialectProp);
setConfiguration(hsConfig);
}
// configuration - load the config file
log.info("Checking for default configuration file.");
HSConfiguration hsConfig = new HSConfiguration();
if (hsConfig.configure()) {
configuration = hsConfig;
}
}
/**
* Make sure nobody can instantiate this class
*/
private HBSpatialExtension() {
}
public static void setConfiguration(HSConfiguration c) {
log.info("Setting configuration object:" + c);
configuration = c;
//if the HSExtension has already been initialized,
//then it should be reconfigured.
if (configured == true) {
forceConfigure();
}
}
private static synchronized void configure() {
// // do nothing if already configured
if (configured) {
return;
}
configured = true;
forceConfigure();
}
private static void forceConfigure() {
// if no configuration object, take the first dialect that is available.
if (configuration == null) {
return;
} else {
log.info("Configuring HBSpatialExtension from "
+ configuration.getSource());
String dialectName = configuration.getDefaultDialect();
if (dialectName != null) {
SpatialDialect dialect = createSpatialDialect(dialectName);
if (dialect != null) {
log.info("Setting Spatial Dialect to : " + dialectName);
setDefaultSpatialDialect(dialect);
}
}
// trying to create a defaultGeometryFactory
log.info("Creating default Geometry Factory");
defaultGeomFactory = GeometryFactoryHelper
.createGeometryFactory(configuration);
}
if (defaultSpatialDialect == null) {
log.warn("Hibernate Spatial Configured but no spatial dialect");
} else {
log.info("Hibernate Spatial configured. Using dialect: "
+ defaultSpatialDialect.getClass().getCanonicalName());
}
}
public static HSConfiguration getConfiguration() {
return configuration;
}
/**
* @param dialect
*/
private static void setDefaultSpatialDialect(SpatialDialect dialect) {
defaultSpatialDialect = dialect;
}
public static SpatialDialect getDefaultSpatialDialect() {
configure();
return defaultSpatialDialect;
}
public static SpatialDialect createSpatialDialect(String dialectName) {
SpatialDialect dialect = null;
for (SpatialDialectProvider provider : providers) {
dialect = provider.createSpatialDialect(dialectName);
if (dialect != null) {
break;
}
}
if (dialect == null) {
throw new HibernateSpatialException(
"No SpatialDialect provider for persistenceUnit "
+ dialectName);
}
return dialect;
}
//TODO -- this is not thread-safe!
//find another way to initialize
public static MGeometryFactory getDefaultGeomFactory() {
configure();
return defaultGeomFactory;
}
// Helper methods
private static Set<String> providerNamesFromReader(InputStream is)
throws IOException {
PropertyFileReader reader = new PropertyFileReader(is);
return reader.getNonCommentLines();
}
}

View File

@ -0,0 +1,55 @@
/**
* $Id: HibernateSpatialException.java 54 2007-11-12 21:16:42Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
/**
* Exception for Hibernate Spatial
*
* @author Karel Maesen
*/
public class HibernateSpatialException extends RuntimeException {
/**
* generated serialVersionUID
*/
private static final long serialVersionUID = -2153256823661407568L;
public HibernateSpatialException(String msg) {
super(msg);
}
public HibernateSpatialException(Throwable cause) {
super(cause);
}
public HibernateSpatialException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,36 @@
/*
* $Id: SpatialAggregate.java 200 2010-03-31 19:52:12Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
/**
* Enumeration of types of Spatial Aggregation
*
* @author Karel Maesen
*/
public interface SpatialAggregate {
public static final int EXTENT = 1;
}

View File

@ -0,0 +1,48 @@
/*
* $Id: SpatialAnalysis.java 200 2010-03-31 19:52:12Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
/**
* The spatial analysis functions defined in the OGC SFS specification.
*
* @author Karel Maesen
*/
public interface SpatialAnalysis {
public static int DISTANCE = 1;
public static int BUFFER = 2;
public static int CONVEXHULL = 3;
public static int INTERSECTION = 4;
public static int UNION = 5;
public static int DIFFERENCE = 6;
public static int SYMDIFFERENCE = 7;
}

View File

@ -0,0 +1,110 @@
/*
* $Id: SpatialDialect.java 301 2011-05-07 18:00:18Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
import java.io.Serializable;
/**
* Describes the features of a spatially enabled dialect.
*
* @author Karel Maesen
*/
public interface SpatialDialect extends Serializable {
/**
* Returns the SQL fragment for the SQL WHERE-clause when parsing
* <code>org.hibernatespatial.criterion.SpatialRelateExpression</code>s
* into prepared statements.
* <p/>
*
* @param columnName The name of the geometry-typed column to which the relation is
* applied
* @param spatialRelation The type of spatial relation (as defined in
* <code>SpatialRelation</code>).
* @return SQL fragment for use in the SQL WHERE-clause.
*/
public String getSpatialRelateSQL(String columnName, int spatialRelation);
/**
* Returns the SQL fragment for the SQL WHERE-expression when parsing
* <code>org.hibernate.spatial.criterion.SpatialFilterExpression</code>s
* into prepared statements.
*
* @param columnName- the name of the geometry-typed column to which the filter is
* be applied.
* @return
*/
public String getSpatialFilterExpression(String columnName);
/**
* @param columnName the name of the Geometry property
* @param aggregation the type of <code>SpatialAggregate</code>
* @return the SQL fragment for the projection
*/
public String getSpatialAggregateSQL(String columnName, int aggregation);
/**
* Returns the SQL fragment when parsing a <code>DWithinExpression</code>.
*
* @param columnName the geometry column to test against
* @return
*/
public String getDWithinSQL(String columnName);
/**
* Returns the SQL fragment when parsing an <code>HavingSridExpression</code>.
*
* @param columnName the geometry column to test against
* @return
*/
public String getHavingSridSQL(String columnName);
/**
* Returns the SQL fragment when parsing a <code>IsEmptyExpression</code> or
* <code>IsNotEmpty</code> expression.
*
* @param columnName the geometry column
* @param isEmpty whether the geometry is tested for empty or non-empty
* @return
*/
public String getIsEmptySQL(String columnName, boolean isEmpty);
/**
* Returns true if this <code>SpatialDialect</code> supports a specific filtering function.
* <p/>
* This is intended to signal DB-support for fast window queries, or MBR-overlap queries
*/
public boolean supportsFiltering();
/**
* Does this dialect supports the specified <code>SpatialFunction</code>.
*
* @param function <code>SpatialFunction</code>
* @return true if this <code>SpatialDialect</code> supports the spatial function specified by the function parameter.
*/
public boolean supports(SpatialFunction function);
}

View File

@ -0,0 +1,74 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2011 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
/**
* Spatial functions that users generally expect in a database.
*
* @author Karel Maesen, Geovise BVBA
* creation-date: Oct 7, 2010
*/
public enum SpatialFunction {
dimension("SFS 1.1"),
geometrytype("SFS 1.1"),
srid("SFS 1.1"),
envelope("SFS 1.1"),
astext("SFS 1.1"),
asbinary("SFS 1.1"),
isempty("SFS 1.1"),
issimple("SFS 1.1"),
boundary("SFS 1.1"),
equals("SFS 1.1"),
disjoint("SFS 1.1"),
intersects("SFS 1.1"),
touches("SFS 1.1"),
crosses("SFS 1.1"),
within("SFS 1.1"),
contains("SFS 1.1"),
overlaps("SFS 1.1"),
relate("SFS 1.1"),
distance("SFS 1.1"),
buffer("SFS 1.1"),
convexhull("SFS 1.1"),
intersection("SFS 1.1"),
geomunion("SFS 1.1"), //is actually UNION but this conflicts with SQL UNION construct
difference("SFS 1.1"),
symdifference("SFS 1.1"),
//the distance within function - dwithin(geom, geom, distance) : boolean)
dwithin("common"),
//the transform function - transform(geom, epsg-code): geometry
transform("common");
private final String description;
SpatialFunction(String specification) {
this.description = specification;
}
}

View File

@ -0,0 +1,48 @@
package org.hibernate.spatial;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 7/27/11
*/
public class SpatialGeometryJavaTypeDescriptor extends AbstractTypeDescriptor<Geometry> {
public static final JavaTypeDescriptor<Geometry> INSTANCE = new SpatialGeometryJavaTypeDescriptor(Geometry.class);
protected SpatialGeometryJavaTypeDescriptor(Class<Geometry> type) {
super(type);
}
@Override
public String toString(Geometry value) {
return value.toText();
}
@Override
public Geometry fromString(String string) {
WKTReader reader = new WKTReader();
try {
return reader.read(string);
} catch (ParseException e) {
throw new RuntimeException(String.format("Can't parse string %s as WKT",string));
}
}
@Override
public <X> X unwrap(Geometry value, Class<X> type, WrapperOptions options) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public <X> Geometry wrap(X value, WrapperOptions options) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
}

View File

@ -0,0 +1,43 @@
package org.hibernate.spatial;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import java.sql.Types;
/**
* A generic <code>SqlTypeDescriptor</code>, intended to be remapped
* by the spatial dialect.
*
* @author Karel Maesen, Geovise BVBA
* creation-date: 7/27/11
*/
public class SpatialGeometrySqlTypeDescriptor implements SqlTypeDescriptor {
public static final SpatialGeometrySqlTypeDescriptor INSTANCE = new SpatialGeometrySqlTypeDescriptor();
@Override
public int getSqlType() {
return Types.STRUCT; //this works only for postgis!
//sqltype remapping issue: HHH-6074 needs to be resolved first.
// return Types.OTHER;
}
@Override
public boolean canBeRemapped() {
return true;
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
throw new UnsupportedOperationException();
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,58 @@
/**
* $Id: SpatialRelation.java 287 2011-02-15 21:30:01Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
/**
* These spatial relations are all defined in "OpenGIS Simple Feature
* Specification for SQL, Rev. 1.1" of the Open Geospatial Consortium (OGC).
*
* @author Karel Maesen
*/
public interface SpatialRelation {
public static int EQUALS = 0;
public static int DISJOINT = 1;
public static int TOUCHES = 2;
public static int CROSSES = 3;
public static int WITHIN = 4;
public static int OVERLAPS = 5;
public static int CONTAINS = 6;
public static int INTERSECTS = 7;
@Deprecated
public static int FILTER = 8;
}

View File

@ -0,0 +1,206 @@
/**
* $Id: HSConfiguration.java 134 2009-06-22 20:41:53Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.cfg;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.hibernate.cfg.Configuration;
/**
* Configuration information for the Hibernate Spatial Extension.
*
* @author Karel Maesen
*
*
*/
public class HSConfiguration extends Properties {
/**
*
*/
private static final long serialVersionUID = 1L;
private static Logger logger = LoggerFactory.getLogger(HSConfiguration.class);
private String source = "runtime configuration object";
private HSProperty[] HSProperties;
public HSConfiguration() {
HSProperties = HSProperty.values();
}
public String getDefaultDialect() {
return getProperty(HSProperty.DEFAULT_DIALECT.toString());
}
public void setDefaultDialect(String dialect) {
setProperty(HSProperty.DEFAULT_DIALECT, dialect);
}
public String getPrecisionModel() {
return getProperty(HSProperty.PRECISION_MODEL.toString());
}
public void setPrecisionModel(String precisionModel) {
setProperty(HSProperty.PRECISION_MODEL, precisionModel);
}
public String getPrecisionModelScale() {
return getProperty(HSProperty.PRECISION_MODEL_SCALE.toString());
}
public void setPrecisionModelScale(String scale) {
setProperty(HSProperty.PRECISION_MODEL_SCALE, scale);
}
protected String getProperty(HSProperty property) {
return getProperty(property.toString());
}
protected void setProperty(HSProperty property, String value) {
setProperty(property.toString(), value);
}
/**
* Derives the configuration from the Hibernate Configuration object.
*
* @param hibernateConfig
* Hibernate Configuration object
* @return true, if the configuration is successfull.
*/
public boolean configure(Configuration hibernateConfig) {
String dialect = hibernateConfig.getProperty("hibernate.dialect");
setProperty(HSProperty.DEFAULT_DIALECT, dialect);
return true;
}
/**
* Gets the configuriation from the hibernate-spatail.cfg.xml file on the
* classpath.
*
* @return true if the configuration is successfull;
*/
public boolean configure() {
return configure("hibernate-spatial.cfg.xml");
}
/**
* Gets the configuriation from the specified file.
*
* @param resource
* the configuration file
* @return true if the configuration is successfull;
*/
public boolean configure(File resource) {
logger.info("Attempting to configuring from file: "
+ resource.getName());
try {
this.source = resource.getAbsolutePath();
return doConfigure(new FileInputStream(resource));
} catch (FileNotFoundException e) {
logger.warn("could not find file: " + resource + ".");
} catch (DocumentException e) {
logger.warn("Failed to load configuration file: " + resource
+ ".\nCause:" + e.getMessage());
}
return false;
}
/**
* The source file or URL for this configuration.
*
* @return The source name (file or URL).
*/
public String getSource() {
return this.source;
}
/**
* Gets the configuriation from the specified file on the class path.
*
* @param resource
* the configuration file
* @return true if the configuration is successfull;
*/
public boolean configure(String resource) {
logger.debug("Attempting to load configuration from file: " + resource);
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
try {
URL url = classLoader.getResource(resource);
if (url == null) {
logger.info("No configuration file " + resource
+ " on the classpath.");
return false;
}
this.source = url.getFile();
return doConfigure(url.openStream());
} catch (Exception e) {
logger.warn("Failed to load configuration file: " + resource
+ ".\nCause:" + e.getMessage());
}
return false;
}
private boolean doConfigure(InputStream stream) throws DocumentException {
try {
SAXReader reader = new SAXReader();
Document configDoc = reader.read(stream);
Element root = configDoc.getRootElement();
for (HSProperty hsprop : HSProperties) {
Element propEl = root.element(hsprop.toString().toLowerCase());
if (propEl != null) {
setProperty(hsprop, propEl.getText());
}
}
return true;
} finally {
try {
stream.close();
} catch (Exception e) {
} // Can't do anything about this.
}
}
public String toString(){
return this.source;
}
}

View File

@ -0,0 +1,41 @@
/**
* $Id: HSProperty.java 71 2008-01-25 19:18:02Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.cfg;
/**
* This enum contains the configurable properties of the Hibernate Spatial
* Extension.
*
* @author Karel Maesen
*
*/
public enum HSProperty {
DEFAULT_DIALECT, PRECISION_MODEL, PRECISION_MODEL_SCALE
}

View File

@ -0,0 +1,72 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2011 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.SpatialFunction;
import org.hibernate.type.StandardBasicTypes;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 2/1/11
*/
public class DWithinExpression implements Criterion {
private final String propertyName;
private final Geometry geometry;
private final double distance;
public DWithinExpression(String propertyName, Geometry geometry, double distance) {
this.propertyName = propertyName;
this.geometry = geometry;
this.distance = distance;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
String column = ExpressionUtil.findColumn(propertyName, criteria, criteriaQuery);
SpatialDialect spatialDialect = ExpressionUtil.getSpatialDialect(criteriaQuery, SpatialFunction.dwithin);
return spatialDialect.getDWithinSQL(column);
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[]{
criteriaQuery.getTypedValue(criteria, propertyName, geometry),
new TypedValue(StandardBasicTypes.DOUBLE, Double.valueOf(distance), EntityMode.POJO)
};
}
}

View File

@ -0,0 +1,63 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2011 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.dialect.Dialect;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.SpatialFunction;
/**
* This class assists in the formation of a SQL-fragment in the various spatial query expressions.
*
* @author Karel Maesen, Geovise BVBA
* creation-date: 2/15/11
*/
public class ExpressionUtil {
public static SpatialDialect getSpatialDialect(CriteriaQuery criteriaQuery, SpatialFunction function) {
Dialect dialect = criteriaQuery.getFactory().getDialect();
if (!(dialect instanceof SpatialDialect)) {
throw new HibernateException("A spatial expression requires a spatial dialect.");
}
SpatialDialect spatialDialect = (SpatialDialect) dialect;
if (!spatialDialect.supports(function)) {
throw new HibernateException(function + " function not supported by this dialect");
}
return spatialDialect;
}
public static String findColumn(String propertyName, Criteria criteria, CriteriaQuery criteriaQuery) {
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
if (columns.length != 1)
throw new HibernateException("Spatial Expression may only be used with single-column properties");
return columns[0];
}
}

View File

@ -0,0 +1,66 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2011 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.SpatialFunction;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 2/9/11
*/
public class HavingSridExpression implements Criterion {
private final String propertyName;
private final int srid;
public HavingSridExpression(String propertyName, int srid) {
this.propertyName = propertyName;
this.srid = srid;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
String column = ExpressionUtil.findColumn(propertyName, criteria, criteriaQuery);
SpatialDialect spatialDialect = ExpressionUtil.getSpatialDialect(criteriaQuery, SpatialFunction.srid);
return spatialDialect.getHavingSridSQL(column);
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[]{
new TypedValue(StandardBasicTypes.INTEGER, Integer.valueOf(srid), EntityMode.POJO)
};
}
}

View File

@ -0,0 +1,65 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2011 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.SpatialFunction;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 2/15/11
*/
public class IsEmptyExpression implements Criterion {
private final static TypedValue[] NO_VALUES = new TypedValue[0];
private final String propertyName;
private final boolean isEmpty;
public IsEmptyExpression(String propertyName, boolean isEmpty) {
this.propertyName = propertyName;
this.isEmpty = isEmpty;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
String column = ExpressionUtil.findColumn(propertyName, criteria, criteriaQuery);
SpatialDialect spatialDialect = ExpressionUtil.getSpatialDialect(criteriaQuery, SpatialFunction.isempty);
return spatialDialect.getIsEmptySQL(column, isEmpty);
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return NO_VALUES;
}
}

View File

@ -0,0 +1,90 @@
/**
* $Id: SpatialFilter.java 54 2007-11-12 21:16:42Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.helper.EnvelopeAdapter;
/**
* An implementation for a simple spatial filter. This <code>Criterion</code>
* restricts the resultset to those features whose bounding box overlaps the
* filter geometry. It is intended for quick, but inexact spatial queries.
*
* @author Karel Maesen
*/
public class SpatialFilter implements Criterion {
private static final long serialVersionUID = 1L;
private String propertyName = null;
private Geometry filter = null;
public SpatialFilter(String propertyName, Geometry filter) {
this.propertyName = propertyName;
this.filter = filter;
}
public SpatialFilter(String propertyName, Envelope envelope, int SRID) {
this.propertyName = propertyName;
this.filter = EnvelopeAdapter.toPolygon(envelope, SRID);
}
public TypedValue[] getTypedValues(Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[] { criteriaQuery.getTypedValue(criteria,
propertyName, filter) };
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
SessionFactoryImplementor factory = criteriaQuery.getFactory();
String[] columns = criteriaQuery.getColumnsUsingProjection(criteria,
this.propertyName);
Dialect dialect = factory.getDialect();
if (dialect instanceof SpatialDialect) {
SpatialDialect seDialect = (SpatialDialect) dialect;
return seDialect.getSpatialFilterExpression(columns[0]);
} else
throw new IllegalStateException(
"Dialect must be spatially enabled dialect");
}
}

View File

@ -0,0 +1,79 @@
/**
* $Id: SpatialProjections.java 64 2007-12-16 16:02:31Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.SimpleProjection;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.spatial.SpatialAggregate;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.type.Type;
/**
* @author Karel Maesen
*
*/
public class SpatialProjections {
public static Projection extent(final String propertyName) {
return new SimpleProjection() {
public Type[] getTypes(Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
return new Type[] { criteriaQuery.getType(criteria,
propertyName) };
}
public String toSqlString(Criteria criteria, int position,
CriteriaQuery criteriaQuery) throws HibernateException {
StringBuilder stbuf = new StringBuilder();
SessionFactoryImplementor factory = criteriaQuery.getFactory();
String[] columns = criteriaQuery.getColumnsUsingProjection(
criteria, propertyName);
Dialect dialect = factory.getDialect();
if (dialect instanceof SpatialDialect) {
SpatialDialect seDialect = (SpatialDialect) dialect;
stbuf.append(seDialect.getSpatialAggregateSQL(columns[0],
SpatialAggregate.EXTENT));
stbuf.append(" as y").append(position).append('_');
return stbuf.toString();
}
return null;
}
};
}
}

View File

@ -0,0 +1,111 @@
/**
* $Id: SpatialRelateExpression.java 287 2011-02-15 21:30:01Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.spatial.SpatialDialect;
/**
* An implementation of the <code>Criterion</code> interface that implements
* spatial queries: queries to the effect that a geometry property has a
* specific spatial relation to a test geometry
*
* @author Karel Maesen
*/
public class SpatialRelateExpression implements Criterion {
/**
* The geometry property
*/
private String propertyName = null;
/**
* The test geometry
*/
private Geometry value = null;
/**
* The spatial relation that is queried for.
*/
private int spatialRelation = -1;
private static final long serialVersionUID = 1L;
public SpatialRelateExpression(String propertyName,
Geometry value, int spatialRelation) {
this.propertyName = propertyName;
this.spatialRelation = spatialRelation;
this.value = value;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.criterion.Criterion#getTypedValues(org.hibernate.Criteria,
* org.hibernate.criterion.CriteriaQuery)
*/
public TypedValue[] getTypedValues(Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[]{criteriaQuery.getTypedValue(criteria,
propertyName, value)};
}
/*
* (non-Javadoc)
*
* @see org.hibernate.criterion.Criterion#toSqlString(org.hibernate.Criteria,
* org.hibernate.criterion.CriteriaQuery)
*/
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
SessionFactoryImplementor factory = criteriaQuery.getFactory();
String[] columns = criteriaQuery.getColumnsUsingProjection(criteria,
this.propertyName);
Dialect dialect = factory.getDialect();
if (dialect instanceof SpatialDialect) {
SpatialDialect seDialect = (SpatialDialect) dialect;
return seDialect.getSpatialRelateSQL(columns[0],
spatialRelation);
} else {
throw new IllegalStateException(
"Dialect must be spatially enabled dialect");
}
}
}

View File

@ -0,0 +1,149 @@
/**
* $Id: SpatialRestrictions.java 287 2011-02-15 21:30:01Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.criterion;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.criterion.Criterion;
import org.hibernate.spatial.SpatialRelation;
/**
* Static Factory Class for creating spatial criterion types.
* <p/>
* <p>
* The criterion types created by this class implement the spatial query
* expressions of the OpenGIS Simple Features Specification for SQL, Revision
* 1.1.
* <p/>
* In addition, it provides for a simple spatial <code>filter</code> that
* works mostly using the spatial index. This corresponds to the Oracle
* Spatial's "SDO_FILTER" function, or the "&&" operator of PostGIS.
* </p>
*
* @author Karel Maesen
*/
public class SpatialRestrictions {
SpatialRestrictions() {
}
public static SpatialRelateExpression eq(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.EQUALS);
}
public static SpatialRelateExpression within(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.WITHIN);
}
public static SpatialRelateExpression contains(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.CONTAINS);
}
public static SpatialRelateExpression crosses(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.CROSSES);
}
public static SpatialRelateExpression disjoint(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.DISJOINT);
}
public static SpatialRelateExpression intersects(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.INTERSECTS);
}
public static SpatialRelateExpression overlaps(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.OVERLAPS);
}
public static SpatialRelateExpression touches(String propertyName, Geometry value) {
return new SpatialRelateExpression(propertyName, value,
SpatialRelation.TOUCHES);
}
public static SpatialFilter filter(String propertyName, Geometry filter) {
return new SpatialFilter(propertyName, filter);
}
public static SpatialFilter filter(String propertyName, Envelope envelope,
int SRID) {
return new SpatialFilter(propertyName, envelope, SRID);
}
public static Criterion distanceWithin(String propertyName, Geometry geometry, double distance) {
return new DWithinExpression(propertyName, geometry, distance);
}
public static Criterion havingSRID(String propertyName, int srid) {
return new HavingSridExpression(propertyName, srid);
}
public static Criterion isEmpty(String propertyName) {
return new IsEmptyExpression(propertyName, true);
}
public static Criterion isNotEmpty(String propertyName) {
return new IsEmptyExpression(propertyName, false);
}
public static Criterion spatialRestriction(int relation,
String propertyName, Geometry value) {
switch (relation) {
case SpatialRelation.CONTAINS:
return contains(propertyName, value);
case SpatialRelation.CROSSES:
return crosses(propertyName, value);
case SpatialRelation.DISJOINT:
return disjoint(propertyName, value);
case SpatialRelation.INTERSECTS:
return intersects(propertyName, value);
case SpatialRelation.EQUALS:
return eq(propertyName, value);
case SpatialRelation.FILTER:
return filter(propertyName, value);
case SpatialRelation.OVERLAPS:
return overlaps(propertyName, value);
case SpatialRelation.TOUCHES:
return touches(propertyName, value);
case SpatialRelation.WITHIN:
return within(propertyName, value);
default:
throw new IllegalArgumentException(
"Non-existant spatial relation passed.");
}
}
}

View File

@ -0,0 +1,38 @@
package org.hibernate.spatial.dialect.postgis;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import java.sql.Types;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 7/27/11
*/
public class PGGeometryTypeDescriptor implements SqlTypeDescriptor {
public static final SqlTypeDescriptor INSTANCE = new PGGeometryTypeDescriptor();
@Override
public int getSqlType() {
return Types.STRUCT;
}
@Override
public boolean canBeRemapped() {
return false;
}
@Override
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new PGGeometryValueBinder();
}
@Override
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new PGGeometryValueExtractor();
}
}

View File

@ -0,0 +1,239 @@
package org.hibernate.spatial.dialect.postgis;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import org.hibernate.spatial.HBSpatialExtension;
import org.hibernate.spatial.mgeom.MCoordinate;
import org.hibernate.spatial.mgeom.MGeometry;
import org.hibernate.spatial.mgeom.MGeometryFactory;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.WrapperOptions;
import org.postgis.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 7/27/11
*/
public class PGGeometryValueBinder implements ValueBinder {
@Override
public void bind(PreparedStatement st, Object value, int index, WrapperOptions options) throws SQLException {
if (value == null) {
st.setNull(index, Types.STRUCT);
} else {
Geometry jtsGeom = (Geometry) value;
Object dbGeom = toJTS(jtsGeom, st.getConnection());
st.setObject(index, dbGeom);
}
}
public MGeometryFactory getGeometryFactory(){
return HBSpatialExtension.getDefaultGeomFactory();
}
/**
* Converts a JTS <code>Geometry</code> to a native geometry object.
*
* @param jtsGeom JTS Geometry to convert
* @param connection the current database connection
* @return native database geometry object corresponding to jtsGeom.
*/
public Object toJTS(Geometry jtsGeom, Connection connection) {
org.postgis.Geometry geom = null;
jtsGeom = forceEmptyToGeometryCollection(jtsGeom);
if (jtsGeom instanceof com.vividsolutions.jts.geom.Point) {
geom = convertJTSPoint((com.vividsolutions.jts.geom.Point) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.LineString) {
geom = convertJTSLineString((com.vividsolutions.jts.geom.LineString) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiLineString) {
geom = convertJTSMultiLineString((com.vividsolutions.jts.geom.MultiLineString) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.Polygon) {
geom = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPoint) {
geom = convertJTSMultiPoint((com.vividsolutions.jts.geom.MultiPoint) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPolygon) {
geom = convertJTSMultiPolygon((com.vividsolutions.jts.geom.MultiPolygon) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.GeometryCollection) {
geom = convertJTSGeometryCollection((com.vividsolutions.jts.geom.GeometryCollection) jtsGeom);
}
if (geom != null)
return new PGgeometry(geom);
else
throw new UnsupportedOperationException("Conversion of "
+ jtsGeom.getClass().getSimpleName()
+ " to PGgeometry not supported");
}
//Postgis treats every empty geometry as an empty geometrycollection
private Geometry forceEmptyToGeometryCollection(Geometry jtsGeom) {
Geometry forced = jtsGeom;
if (forced.isEmpty()) {
GeometryFactory factory = jtsGeom.getFactory();
if (factory == null) {
factory = HBSpatialExtension.getDefaultGeomFactory();
}
forced = factory.createGeometryCollection(null);
forced.setSRID(jtsGeom.getSRID());
}
return forced;
}
private MultiPolygon convertJTSMultiPolygon(
com.vividsolutions.jts.geom.MultiPolygon multiPolygon) {
Polygon[] pgPolygons = new Polygon[multiPolygon.getNumGeometries()];
for (int i = 0; i < pgPolygons.length; i++) {
pgPolygons[i] = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) multiPolygon
.getGeometryN(i));
}
MultiPolygon mpg = new MultiPolygon(pgPolygons);
mpg.setSrid(multiPolygon.getSRID());
return mpg;
}
private MultiPoint convertJTSMultiPoint(
com.vividsolutions.jts.geom.MultiPoint multiPoint) {
Point[] pgPoints = new Point[multiPoint.getNumGeometries()];
for (int i = 0; i < pgPoints.length; i++) {
pgPoints[i] = convertJTSPoint((com.vividsolutions.jts.geom.Point) multiPoint
.getGeometryN(i));
}
MultiPoint mp = new MultiPoint(pgPoints);
mp.setSrid(multiPoint.getSRID());
return mp;
}
private Polygon convertJTSPolygon(
com.vividsolutions.jts.geom.Polygon jtsPolygon) {
int numRings = jtsPolygon.getNumInteriorRing();
org.postgis.LinearRing[] rings = new org.postgis.LinearRing[numRings + 1];
rings[0] = convertJTSLineStringToLinearRing(jtsPolygon
.getExteriorRing());
for (int i = 0; i < numRings; i++) {
rings[i + 1] = convertJTSLineStringToLinearRing(jtsPolygon
.getInteriorRingN(i));
}
Polygon polygon = new org.postgis.Polygon(rings);
polygon.setSrid(jtsPolygon.getSRID());
return polygon;
}
private LinearRing convertJTSLineStringToLinearRing(
com.vividsolutions.jts.geom.LineString lineString) {
LinearRing lr = new org.postgis.LinearRing(toPoints(lineString
.getCoordinates()));
lr.setSrid(lineString.getSRID());
return lr;
}
private LineString convertJTSLineString(
com.vividsolutions.jts.geom.LineString string) {
LineString ls = new org.postgis.LineString(toPoints(string
.getCoordinates()));
if (string instanceof MGeometry) {
ls.haveMeasure = true;
}
ls.setSrid(string.getSRID());
return ls;
}
private MultiLineString convertJTSMultiLineString(
com.vividsolutions.jts.geom.MultiLineString string) {
org.postgis.LineString[] lines = new org.postgis.LineString[string
.getNumGeometries()];
for (int i = 0; i < string.getNumGeometries(); i++) {
lines[i] = new org.postgis.LineString(toPoints(string.getGeometryN(
i).getCoordinates()));
}
MultiLineString mls = new MultiLineString(lines);
if (string instanceof MGeometry) {
mls.haveMeasure = true;
}
mls.setSrid(string.getSRID());
return mls;
}
private Point convertJTSPoint(com.vividsolutions.jts.geom.Point point) {
org.postgis.Point pgPoint = new org.postgis.Point();
pgPoint.srid = point.getSRID();
pgPoint.x = point.getX();
pgPoint.y = point.getY();
Coordinate coordinate = point.getCoordinate();
if (Double.isNaN(coordinate.z)) {
pgPoint.dimension = 2;
} else {
pgPoint.z = coordinate.z;
pgPoint.dimension = 3;
}
pgPoint.haveMeasure = false;
if (coordinate instanceof MCoordinate && !Double.isNaN(((MCoordinate) coordinate).m)) {
pgPoint.m = ((MCoordinate) coordinate).m;
pgPoint.haveMeasure = true;
}
return pgPoint;
}
private GeometryCollection convertJTSGeometryCollection(
com.vividsolutions.jts.geom.GeometryCollection collection) {
com.vividsolutions.jts.geom.Geometry currentGeom;
org.postgis.Geometry[] pgCollections = new org.postgis.Geometry[collection
.getNumGeometries()];
for (int i = 0; i < pgCollections.length; i++) {
currentGeom = collection.getGeometryN(i);
currentGeom = forceEmptyToGeometryCollection(currentGeom);
if (currentGeom.getClass() == com.vividsolutions.jts.geom.LineString.class) {
pgCollections[i] = convertJTSLineString((com.vividsolutions.jts.geom.LineString) currentGeom);
} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.LinearRing.class) {
pgCollections[i] = convertJTSLineStringToLinearRing((com.vividsolutions.jts.geom.LinearRing) currentGeom);
} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.MultiLineString.class) {
pgCollections[i] = convertJTSMultiLineString((com.vividsolutions.jts.geom.MultiLineString) currentGeom);
} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.MultiPoint.class) {
pgCollections[i] = convertJTSMultiPoint((com.vividsolutions.jts.geom.MultiPoint) currentGeom);
} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.MultiPolygon.class) {
pgCollections[i] = convertJTSMultiPolygon((com.vividsolutions.jts.geom.MultiPolygon) currentGeom);
} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.Point.class) {
pgCollections[i] = convertJTSPoint((com.vividsolutions.jts.geom.Point) currentGeom);
} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.Polygon.class) {
pgCollections[i] = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) currentGeom);
} else if (currentGeom.getClass() == com.vividsolutions.jts.geom.GeometryCollection.class) {
pgCollections[i] = convertJTSGeometryCollection((com.vividsolutions.jts.geom.GeometryCollection) currentGeom);
}
}
GeometryCollection gc = new GeometryCollection(pgCollections);
gc.setSrid(collection.getSRID());
return gc;
}
private Point[] toPoints(Coordinate[] coordinates) {
Point[] points = new Point[coordinates.length];
for (int i = 0; i < coordinates.length; i++) {
Coordinate c = coordinates[i];
Point pt;
if (Double.isNaN(c.z)) {
pt = new Point(c.x, c.y);
} else {
pt = new Point(c.x, c.y, c.z);
}
if (c instanceof MCoordinate) {
MCoordinate mc = (MCoordinate) c;
if (!Double.isNaN(mc.m)) {
pt.setM(mc.m);
}
}
points[i] = pt;
}
return points;
}
}

View File

@ -0,0 +1,231 @@
package org.hibernate.spatial.dialect.postgis;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.spatial.HBSpatialExtension;
import org.hibernate.spatial.mgeom.MCoordinate;
import org.hibernate.spatial.mgeom.MGeometryFactory;
import org.hibernate.spatial.mgeom.MLineString;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.postgis.*;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 7/27/11
*/
public class PGGeometryValueExtractor implements ValueExtractor {
@Override
public Object extract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
Object geomObj = rs.getObject(name);
return toJTS(geomObj);
}
public MGeometryFactory getGeometryFactory() {
return HBSpatialExtension.getDefaultGeomFactory();
}
public Geometry toJTS(Object object) {
if (object == null)
return null;
// in some cases, Postgis returns not PGgeometry objects
// but org.postgis.Geometry instances.
// This has been observed when retrieving GeometryCollections
// as the result of an SQL-operation such as Union.
if (object instanceof org.postgis.Geometry) {
object = new PGgeometry((org.postgis.Geometry) object);
}
if (object instanceof PGgeometry) {
PGgeometry geom = (PGgeometry) object;
com.vividsolutions.jts.geom.Geometry out = null;
switch (geom.getGeoType()) {
case org.postgis.Geometry.POINT:
out = convertPoint((org.postgis.Point) geom.getGeometry());
break;
case org.postgis.Geometry.LINESTRING:
out = convertLineString((org.postgis.LineString) geom
.getGeometry());
break;
case org.postgis.Geometry.POLYGON:
out = convertPolygon((org.postgis.Polygon) geom.getGeometry());
break;
case org.postgis.Geometry.MULTILINESTRING:
out = convertMultiLineString((org.postgis.MultiLineString) geom
.getGeometry());
break;
case org.postgis.Geometry.MULTIPOINT:
out = convertMultiPoint((org.postgis.MultiPoint) geom
.getGeometry());
break;
case org.postgis.Geometry.MULTIPOLYGON:
out = convertMultiPolygon((org.postgis.MultiPolygon) geom
.getGeometry());
break;
case org.postgis.Geometry.GEOMETRYCOLLECTION:
out = convertGeometryCollection((org.postgis.GeometryCollection) geom
.getGeometry());
break;
default:
throw new RuntimeException("Unknown type of PGgeometry");
}
out.setSRID(geom.getGeometry().srid);
return out;
} else if (object instanceof org.postgis.PGboxbase) {
return convertBox((org.postgis.PGboxbase) object);
} else {
throw new IllegalArgumentException("Can't convert object of type "
+ object.getClass().getCanonicalName());
}
}
private Geometry convertBox(PGboxbase box) {
Point ll = box.getLLB();
Point ur = box.getURT();
Coordinate[] ringCoords = new Coordinate[5];
if (box instanceof org.postgis.PGbox2d) {
ringCoords[0] = new Coordinate(ll.x, ll.y);
ringCoords[1] = new Coordinate(ur.x, ll.y);
ringCoords[2] = new Coordinate(ur.x, ur.y);
ringCoords[3] = new Coordinate(ll.x, ur.y);
ringCoords[4] = new Coordinate(ll.x, ll.y);
} else {
ringCoords[0] = new Coordinate(ll.x, ll.y, ll.z);
ringCoords[1] = new Coordinate(ur.x, ll.y, ll.z);
ringCoords[2] = new Coordinate(ur.x, ur.y, ur.z);
ringCoords[3] = new Coordinate(ll.x, ur.y, ur.z);
ringCoords[4] = new Coordinate(ll.x, ll.y, ll.z);
}
com.vividsolutions.jts.geom.LinearRing shell = getGeometryFactory()
.createLinearRing(ringCoords);
return getGeometryFactory().createPolygon(shell, null);
}
private Geometry convertGeometryCollection(GeometryCollection collection) {
org.postgis.Geometry[] geometries = collection.getGeometries();
com.vividsolutions.jts.geom.Geometry[] jtsGeometries = new com.vividsolutions.jts.geom.Geometry[geometries.length];
for (int i = 0; i < geometries.length; i++) {
jtsGeometries[i] = toJTS(geometries[i]);
//TODO - refactor this so the following line is not necessary
jtsGeometries[i].setSRID(0); // convert2JTS sets SRIDs, but constituent geometries in a collection must have srid == 0
}
com.vividsolutions.jts.geom.GeometryCollection jtsGCollection = getGeometryFactory()
.createGeometryCollection(jtsGeometries);
return jtsGCollection;
}
private Geometry convertMultiPolygon(MultiPolygon pgMultiPolygon) {
com.vividsolutions.jts.geom.Polygon[] polygons = new com.vividsolutions.jts.geom.Polygon[pgMultiPolygon
.numPolygons()];
for (int i = 0; i < polygons.length; i++) {
Polygon pgPolygon = pgMultiPolygon.getPolygon(i);
polygons[i] = (com.vividsolutions.jts.geom.Polygon) convertPolygon(pgPolygon);
}
com.vividsolutions.jts.geom.MultiPolygon out = getGeometryFactory()
.createMultiPolygon(polygons);
return out;
}
private Geometry convertMultiPoint(MultiPoint pgMultiPoint) {
com.vividsolutions.jts.geom.Point[] points = new com.vividsolutions.jts.geom.Point[pgMultiPoint
.numPoints()];
for (int i = 0; i < points.length; i++) {
points[i] = convertPoint(pgMultiPoint.getPoint(i));
}
com.vividsolutions.jts.geom.MultiPoint out = getGeometryFactory()
.createMultiPoint(points);
out.setSRID(pgMultiPoint.srid);
return out;
}
private com.vividsolutions.jts.geom.Geometry convertMultiLineString(
MultiLineString mlstr) {
com.vividsolutions.jts.geom.MultiLineString out;
if (mlstr.haveMeasure) {
MLineString[] lstrs = new MLineString[mlstr.numLines()];
for (int i = 0; i < mlstr.numLines(); i++) {
MCoordinate[] coordinates = toJTSCoordinates(mlstr.getLine(i)
.getPoints());
lstrs[i] = getGeometryFactory().createMLineString(coordinates);
}
out = getGeometryFactory().createMultiMLineString(lstrs);
} else {
com.vividsolutions.jts.geom.LineString[] lstrs = new com.vividsolutions.jts.geom.LineString[mlstr
.numLines()];
for (int i = 0; i < mlstr.numLines(); i++) {
lstrs[i] = getGeometryFactory().createLineString(
toJTSCoordinates(mlstr.getLine(i).getPoints()));
}
out = getGeometryFactory().createMultiLineString(lstrs);
}
return out;
}
protected com.vividsolutions.jts.geom.Geometry convertPolygon(
Polygon polygon) {
com.vividsolutions.jts.geom.LinearRing shell = getGeometryFactory()
.createLinearRing(
toJTSCoordinates(polygon.getRing(0).getPoints()));
com.vividsolutions.jts.geom.Polygon out = null;
if (polygon.numRings() > 1) {
com.vividsolutions.jts.geom.LinearRing[] rings = new com.vividsolutions.jts.geom.LinearRing[polygon
.numRings() - 1];
for (int r = 1; r < polygon.numRings(); r++) {
rings[r - 1] = getGeometryFactory().createLinearRing(
toJTSCoordinates(polygon.getRing(r).getPoints()));
}
out = getGeometryFactory().createPolygon(shell, rings);
} else {
out = getGeometryFactory().createPolygon(shell, null);
}
return out;
}
protected com.vividsolutions.jts.geom.Point convertPoint(Point pnt) {
com.vividsolutions.jts.geom.Point g = getGeometryFactory().createPoint(
this.toJTSCoordinate(pnt));
return g;
}
protected com.vividsolutions.jts.geom.LineString convertLineString(
org.postgis.LineString lstr) {
com.vividsolutions.jts.geom.LineString out = lstr.haveMeasure ? getGeometryFactory()
.createMLineString(toJTSCoordinates(lstr.getPoints()))
: getGeometryFactory().createLineString(
toJTSCoordinates(lstr.getPoints()));
return out;
}
private MCoordinate[] toJTSCoordinates(Point[] points) {
MCoordinate[] coordinates = new MCoordinate[points.length];
for (int i = 0; i < points.length; i++) {
coordinates[i] = this.toJTSCoordinate(points[i]);
}
return coordinates;
}
private MCoordinate toJTSCoordinate(Point pt) {
MCoordinate mc;
if (pt.dimension == 2) {
mc = pt.haveMeasure ? MCoordinate.create2dWithMeasure(pt.getX(), pt
.getY(), pt.getM()) : MCoordinate.create2d(pt.getX(), pt
.getY());
} else {
mc = pt.haveMeasure ? MCoordinate.create3dWithMeasure(pt.getX(), pt
.getY(), pt.getZ(), pt.getM()) : MCoordinate.create3d(pt
.getX(), pt.getY(), pt.getZ());
}
return mc;
}
}

View File

@ -0,0 +1,198 @@
/**
* $Id: PostgisDialect.java 289 2011-02-15 21:34:56Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.dialect.postgis;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.spatial.*;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/**
* Extends the PostgreSQLDialect by also including information on spatial
* operators, constructors and processing functions.
*
* @author Karel Maesen
*/
public class PostgisDialect extends PostgreSQLDialect implements SpatialDialect {
public PostgisDialect() {
super();
registerTypesAndFunctions();
}
protected void registerTypesAndFunctions() {
registerColumnType(java.sql.Types.STRUCT, "geometry");
// registering OGC functions
// (spec_simplefeatures_sql_99-04.pdf)
// section 2.1.1.1
// Registerfunction calls for registering geometry functions:
// first argument is the OGC standard functionname, second the name as
// it occurs in the spatial dialect
registerFunction("dimension", new StandardSQLFunction("st_dimension",
StandardBasicTypes.INTEGER));
registerFunction("geometrytype", new StandardSQLFunction(
"st_geometrytype", StandardBasicTypes.STRING));
registerFunction("srid", new StandardSQLFunction("st_srid",
StandardBasicTypes.INTEGER));
registerFunction("envelope", new StandardSQLFunction("st_envelope",
GeometryType.INSTANCE));
registerFunction("astext", new StandardSQLFunction("st_astext",
StandardBasicTypes.STRING));
registerFunction("asbinary", new StandardSQLFunction("st_asbinary",
StandardBasicTypes.BINARY));
registerFunction("isempty", new StandardSQLFunction("st_isempty",
StandardBasicTypes.BOOLEAN));
registerFunction("issimple", new StandardSQLFunction("st_issimple",
StandardBasicTypes.BOOLEAN));
registerFunction("boundary", new StandardSQLFunction("st_boundary",
GeometryType.INSTANCE));
// Register functions for spatial relation constructs
registerFunction("overlaps", new StandardSQLFunction("st_overlaps",
StandardBasicTypes.BOOLEAN));
registerFunction("intersects", new StandardSQLFunction("st_intersects",
StandardBasicTypes.BOOLEAN));
registerFunction("equals", new StandardSQLFunction("st_equals",
StandardBasicTypes.BOOLEAN));
registerFunction("contains", new StandardSQLFunction("st_contains",
StandardBasicTypes.BOOLEAN));
registerFunction("crosses", new StandardSQLFunction("st_crosses",
StandardBasicTypes.BOOLEAN));
registerFunction("disjoint", new StandardSQLFunction("st_disjoint",
StandardBasicTypes.BOOLEAN));
registerFunction("touches", new StandardSQLFunction("st_touches",
StandardBasicTypes.BOOLEAN));
registerFunction("within", new StandardSQLFunction("st_within",
StandardBasicTypes.BOOLEAN));
registerFunction("relate", new StandardSQLFunction("st_relate",
StandardBasicTypes.BOOLEAN));
// register the spatial analysis functions
registerFunction("distance", new StandardSQLFunction("st_distance",
StandardBasicTypes.DOUBLE));
registerFunction("buffer", new StandardSQLFunction("st_buffer",
GeometryType.INSTANCE));
registerFunction("convexhull", new StandardSQLFunction("st_convexhull",
GeometryType.INSTANCE));
registerFunction("difference", new StandardSQLFunction("st_difference",
GeometryType.INSTANCE));
registerFunction("intersection", new StandardSQLFunction(
"st_intersection", new GeometryType()));
registerFunction("symdifference",
new StandardSQLFunction("st_symdifference", GeometryType.INSTANCE));
registerFunction("geomunion", new StandardSQLFunction("st_union",
GeometryType.INSTANCE));
//register Spatial Aggregate function
registerFunction("extent", new StandardSQLFunction("extent",
GeometryType.INSTANCE));
//other common functions
registerFunction("dwithin", new StandardSQLFunction("st_dwithin",
StandardBasicTypes.BOOLEAN));
registerFunction("transform", new StandardSQLFunction("st_transform",
GeometryType.INSTANCE));
}
@Override
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
if (sqlTypeDescriptor instanceof SpatialGeometrySqlTypeDescriptor) {
return PGGeometryTypeDescriptor.INSTANCE;
}
return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
}
public String getSpatialRelateSQL(String columnName, int spatialRelation) {
switch (spatialRelation) {
case SpatialRelation.WITHIN:
return " ST_within(" + columnName + ",?)";
case SpatialRelation.CONTAINS:
return " ST_contains(" + columnName + ", ?)";
case SpatialRelation.CROSSES:
return " ST_crosses(" + columnName + ", ?)";
case SpatialRelation.OVERLAPS:
return " ST_overlaps(" + columnName + ", ?)";
case SpatialRelation.DISJOINT:
return " ST_disjoint(" + columnName + ", ?)";
case SpatialRelation.INTERSECTS:
return " ST_intersects(" + columnName
+ ", ?)";
case SpatialRelation.TOUCHES:
return " ST_touches(" + columnName + ", ?)";
case SpatialRelation.EQUALS:
return " ST_equals(" + columnName + ", ?)";
default:
throw new IllegalArgumentException(
"Spatial relation is not known by this dialect");
}
}
public String getDWithinSQL(String columnName) {
return "ST_DWithin(" + columnName + ",?,?)";
}
public String getHavingSridSQL(String columnName) {
return "( ST_srid(" + columnName + ") = ?)";
}
public String getIsEmptySQL(String columnName, boolean isEmpty) {
String emptyExpr = " ST_IsEmpty(" + columnName + ") ";
return isEmpty ? emptyExpr : "( NOT " + emptyExpr + ")";
}
public String getSpatialFilterExpression(String columnName) {
return "(" + columnName + " && ? ) ";
}
public String getSpatialAggregateSQL(String columnName, int aggregation) {
switch (aggregation) {
case SpatialAggregate.EXTENT:
StringBuilder stbuf = new StringBuilder();
stbuf.append("extent(").append(columnName).append(")");
return stbuf.toString();
default:
throw new IllegalArgumentException("Aggregation of type "
+ aggregation + " are not supported by this dialect");
}
}
public boolean supportsFiltering() {
return true;
}
public boolean supports(SpatialFunction function) {
return (getFunctions().get(function.toString()) != null);
}
}

View File

@ -0,0 +1,144 @@
package org.hibernate.spatial.dialect.postgis;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.spatial.GeometryType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.spatial.SpatialFunction;
import org.hibernate.spatial.SpatialRelation;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Dec 18, 2010
*/
public class PostgisNoSQLMM extends PostgisDialect {
@Override
protected void registerTypesAndFunctions() {
registerColumnType(java.sql.Types.STRUCT, "geometry");
// registering OGC functions
// (spec_simplefeatures_sql_99-04.pdf)
// section 2.1.1.1
// Registerfunction calls for registering geometry functions:
// first argument is the OGC standard functionname, second the name as
// it occurs in the spatial dialect
registerFunction("dimension", new StandardSQLFunction("dimension",
StandardBasicTypes.INTEGER));
registerFunction("geometrytype", new StandardSQLFunction(
"geometrytype", StandardBasicTypes.STRING));
registerFunction("srid", new StandardSQLFunction("srid",
StandardBasicTypes.INTEGER));
registerFunction("envelope", new StandardSQLFunction("envelope",
new GeometryType()));
registerFunction("astext", new StandardSQLFunction("astext",
StandardBasicTypes.STRING));
registerFunction("asbinary", new StandardSQLFunction("asbinary",
StandardBasicTypes.BINARY));
registerFunction("isempty", new StandardSQLFunction("isempty",
StandardBasicTypes.BOOLEAN));
registerFunction("issimple", new StandardSQLFunction("issimple",
StandardBasicTypes.BOOLEAN));
registerFunction("boundary", new StandardSQLFunction("boundary",
new GeometryType()));
// Register functions for spatial relation constructs
registerFunction("overlaps", new StandardSQLFunction("overlaps",
StandardBasicTypes.BOOLEAN));
registerFunction("intersects", new StandardSQLFunction("intersects",
StandardBasicTypes.BOOLEAN));
registerFunction("equals", new StandardSQLFunction("equals",
StandardBasicTypes.BOOLEAN));
registerFunction("contains", new StandardSQLFunction("contains",
StandardBasicTypes.BOOLEAN));
registerFunction("crosses", new StandardSQLFunction("crosses",
StandardBasicTypes.BOOLEAN));
registerFunction("disjoint", new StandardSQLFunction("disjoint",
StandardBasicTypes.BOOLEAN));
registerFunction("touches", new StandardSQLFunction("touches",
StandardBasicTypes.BOOLEAN));
registerFunction("within", new StandardSQLFunction("within",
StandardBasicTypes.BOOLEAN));
registerFunction("relate", new StandardSQLFunction("relate",
StandardBasicTypes.BOOLEAN));
// register the spatial analysis functions
registerFunction("distance", new StandardSQLFunction("distance",
StandardBasicTypes.DOUBLE));
registerFunction("buffer", new StandardSQLFunction("buffer",
GeometryType.INSTANCE));
registerFunction("convexhull", new StandardSQLFunction("convexhull",
GeometryType.INSTANCE));
registerFunction("difference", new StandardSQLFunction("difference",
GeometryType.INSTANCE));
registerFunction("intersection", new StandardSQLFunction(
"intersection", new GeometryType()));
registerFunction("symdifference",
new StandardSQLFunction("symdifference", GeometryType.INSTANCE));
registerFunction("geomunion", new StandardSQLFunction("geomunion",
GeometryType.INSTANCE));
//register Spatial Aggregate function
registerFunction("extent", new StandardSQLFunction("extent",
GeometryType.INSTANCE));
//other common spatial functions
registerFunction("transform", new StandardSQLFunction("transform",
GeometryType.INSTANCE));
}
@Override
public String getDWithinSQL(String columnName) {
return "( dwithin(" + columnName + ",?,?) )";
}
@Override
public String getHavingSridSQL(String columnName) {
return "( srid(" + columnName + ") = ?)";
}
@Override
public String getIsEmptySQL(String columnName, boolean isEmpty) {
String emptyExpr = "( isempty(" + columnName + ")) ";
return isEmpty ? emptyExpr : "not " + emptyExpr;
}
public String getSpatialRelateSQL(String columnName, int spatialRelation,
boolean hasFilter) {
switch (spatialRelation) {
case SpatialRelation.WITHIN:
return hasFilter ? "(" + columnName + " && ? AND within("
+ columnName + ", ?))" : " within(" + columnName + ",?)";
case SpatialRelation.CONTAINS:
return hasFilter ? "(" + columnName + " && ? AND contains("
+ columnName + ", ?))" : " contains(" + columnName + ", ?)";
case SpatialRelation.CROSSES:
return hasFilter ? "(" + columnName + " && ? AND crosses("
+ columnName + ", ?))" : " crosses(" + columnName + ", ?)";
case SpatialRelation.OVERLAPS:
return hasFilter ? "(" + columnName + " && ? AND overlaps("
+ columnName + ", ?))" : " overlaps(" + columnName + ", ?)";
case SpatialRelation.DISJOINT:
return hasFilter ? "(" + columnName + " && ? AND disjoint("
+ columnName + ", ?))" : " disjoint(" + columnName + ", ?)";
case SpatialRelation.INTERSECTS:
return hasFilter ? "(" + columnName + " && ? AND intersects("
+ columnName + ", ?))" : " intersects(" + columnName
+ ", ?)";
case SpatialRelation.TOUCHES:
return hasFilter ? "(" + columnName + " && ? AND touches("
+ columnName + ", ?))" : " touches(" + columnName + ", ?)";
case SpatialRelation.EQUALS:
return hasFilter ? "(" + columnName + " && ? AND equals("
+ columnName + ", ?))" : " equals(" + columnName + ", ?)";
default:
throw new IllegalArgumentException(
"Spatial relation is not known by this dialect");
}
}
@Override
public boolean supports(SpatialFunction function) {
return super.supports(function);
}
}

View File

@ -0,0 +1,60 @@
/**
* $Id: EnvelopeAdapter.java 97 2008-06-21 12:00:01Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.helper;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;
public class EnvelopeAdapter {
static private GeometryFactory geomFactory = new GeometryFactory();
static public Polygon toPolygon(Envelope env, int SRID) {
Coordinate[] coords = new Coordinate[5];
coords[0] = new Coordinate(env.getMinX(), env.getMinY());
coords[1] = new Coordinate(env.getMinX(), env.getMaxY());
coords[2] = new Coordinate(env.getMaxX(), env.getMaxY());
coords[3] = new Coordinate(env.getMaxX(), env.getMinY());
coords[4] = new Coordinate(env.getMinX(), env.getMinY());
LinearRing shell = geomFactory.createLinearRing(coords);
Polygon pg = geomFactory.createPolygon(shell, null);
pg.setSRID(SRID);
return pg;
}
public static void setGeometryFactory(GeometryFactory gf) {
geomFactory = gf;
}
}

View File

@ -0,0 +1,42 @@
/**
* $Id: FinderException.java 97 2008-06-21 12:00:01Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2008 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.helper;
/**
* This exception is thrown when Hibernate Spatial fails to find a required
* resource.
*
* @author maesenka
*
*/
public class FinderException extends Exception {
private static final long serialVersionUID = 1L;
public FinderException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,52 @@
/**
* $Id: FinderStrategy.java 248 2010-10-02 12:30:33Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2008 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.helper;
/**
* A <code>FinderStrategy</code> is used to find a specific feature. It is
* useful in cases where reflection is used to determine some property of a
* class.
*
* @author Karel Maesen
*
* @param <T>
* the return type of the <code>find</code> method
* @param <S>
* the type of subject
*/
public interface FinderStrategy<T, S> {
/**
* Find a feature or property of a subject
*
* @param subject
* the object that is being searched
* @return the object sought
* @throws FinderException
* thrown when the feature can be found;
*/
public T find(S subject) throws FinderException;
}

View File

@ -0,0 +1,85 @@
/*
* $Id: GeometryFactoryHelper.java 200 2010-03-31 19:52:12Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.helper;
import com.vividsolutions.jts.geom.PrecisionModel;
import org.hibernate.spatial.cfg.HSProperty;
import org.hibernate.spatial.mgeom.MGeometryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* Factory for creating a <code>GeometryFactory</code> given a map of
* configuration parameters.
*
* @author Karel Maesen, Geovise BVBA
*/
public class GeometryFactoryHelper {
private static Logger logger = LoggerFactory.getLogger(GeometryFactoryHelper.class);
public static MGeometryFactory createGeometryFactory(Map map) {
if (map == null) {
return new MGeometryFactory();
}
String precisionModelName = null;
Double scale = null;
if (map.containsKey(HSProperty.PRECISION_MODEL.toString())) {
precisionModelName = (String) map.get(HSProperty.PRECISION_MODEL
.toString());
}
if (map.containsKey(HSProperty.PRECISION_MODEL_SCALE.toString())) {
scale = Double.parseDouble(((String) map
.get(HSProperty.PRECISION_MODEL_SCALE.toString())));
}
if (scale != null && !scale.isNaN() && precisionModelName != null
&& precisionModelName.equalsIgnoreCase("FIXED")) {
return new MGeometryFactory(new PrecisionModel(scale));
}
if (precisionModelName == null) {
return new MGeometryFactory();
}
if (precisionModelName.equalsIgnoreCase("FIXED")) {
return new MGeometryFactory(
new PrecisionModel(PrecisionModel.FIXED));
}
if (precisionModelName.equalsIgnoreCase("FLOATING")) {
return new MGeometryFactory(new PrecisionModel(
PrecisionModel.FLOATING));
}
if (precisionModelName.equalsIgnoreCase("FLOATING_SINGLE")) {
return new MGeometryFactory(new PrecisionModel(
PrecisionModel.FLOATING_SINGLE));
}
logger.warn("Configured for PrecisionModel: " + precisionModelName
+ " but don't know how to instantiate.");
logger.warn("Reverting to default GeometryModel");
return new MGeometryFactory();
}
}

View File

@ -0,0 +1,27 @@
package org.hibernate.spatial.helper;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.Type;
import com.vividsolutions.jts.geom.Geometry;
/**
* This <code>FinderStrategy</code> implementation returns the first
* geometry-valued property.
*
*/
public class GeometryPropertyFinder implements FinderStrategy<String, ClassMetadata> {
public String find(ClassMetadata metadata) throws FinderException {
for (String prop : metadata.getPropertyNames()) {
Type type = metadata.getPropertyType(prop);
if (Geometry.class.isAssignableFrom(type.getReturnedClass())) {
return prop;
}
}
throw new FinderException(
"Could not find a Geometry-valued property in "
+ metadata.getEntityName());
}
}

View File

@ -0,0 +1,102 @@
/**
* $Id: PropertyFileReader.java 130 2009-04-01 22:13:06Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.helper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper class to read settings and properties files.
*
* @author Karel Maesen
*
*/
public class PropertyFileReader {
private static final Logger log = LoggerFactory.getLogger(PropertyFileReader.class);
/**
* pattern for comment lines. If it matches, it is a comment.
*/
private static final Pattern nonCommentPattern = Pattern
.compile("^([^#]+)");
private InputStream is = null;
public PropertyFileReader(InputStream is) {
this.is = is;
}
public Properties getProperties() throws IOException {
if (is == null)
return null;
Properties props = new Properties();
props.load(is);
return props;
}
/**
* Returns the non-comment lines in a file.
*
* @return set of non-comment strings.
* @throws IOException
*/
public Set<String> getNonCommentLines() throws IOException {
Set<String> lines = new HashSet<String>();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
line = line.trim();
Matcher m = nonCommentPattern.matcher(line);
if (m.find()) {
lines.add(m.group().trim());
}
}
return lines;
}
public void close() {
try {
this.is.close();
} catch (IOException e) {
log.warn("Exception when closing PropertyFileReader: " + e);
}
}
}

View File

@ -0,0 +1,24 @@
package org.hibernate.spatial.integration;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.hibernate.spatial.GeometryType;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 7/27/11
*/
public class SpatialIntegrator implements Integrator {
@Override
public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
sessionFactory.getTypeResolver().registerTypeOverride(GeometryType.INSTANCE);
}
@Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
//do nothing.
}
}

View File

@ -0,0 +1,101 @@
/*
* $Id:$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
/**
* This utility class is used to testsuite-suite doubles for equality
*
* @author Didier H. Besset <p/> Adapted from "Object-oriented implementation of
* numerical methods"
*/
//TODO: This class should be removed.
public final class DoubleComparator {
private final static int radix = computeRadix();
private final static double machinePrecision = computeMachinePrecision();
private final static double defaultNumericalPrecision = Math
.sqrt(machinePrecision);
private static int computeRadix() {
int radix = 0;
double a = 1.0d;
double tmp1, tmp2;
do {
a += a;
tmp1 = a + 1.0d;
tmp2 = tmp1 - a;
} while (tmp2 - 1.0d != 0.0d);
double b = 1.0d;
while (radix == 0) {
b += b;
tmp1 = a + b;
radix = (int) (tmp1 - a);
}
return radix;
}
public static int getRadix() {
return radix;
}
private static double computeMachinePrecision() {
double floatingRadix = getRadix();
double inverseRadix = 1.0d / floatingRadix;
double machinePrecision = 1.0d;
double tmp = 1.0d + machinePrecision;
while (tmp - 1.0d != 0.0) {
machinePrecision *= inverseRadix;
tmp = 1.0d + machinePrecision;
}
return machinePrecision;
}
public static double getMachinePrecision() {
return machinePrecision;
}
public static double defaultNumericalPrecision() {
return defaultNumericalPrecision;
}
public static boolean equals(double a, double b) {
return equals(a, b, defaultNumericalPrecision());
}
public static boolean equals(double a, double b, double precision) {
double norm = Math.max(Math.abs(a), Math.abs(b));
boolean result = norm < precision || Math.abs(a - b) < precision * norm;
return result || (Double.isNaN(a) && Double.isNaN(b));
}
public static void main(String[] args) {
System.out.println("Machine precision = " + getMachinePrecision());
System.out.println("Radix = " + getRadix());
System.out.println("default numerical precision = "
+ defaultNumericalPrecision());
}
}

View File

@ -0,0 +1,79 @@
/*
* $Id:$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import java.util.ArrayList;
import java.util.List;
public class EventLocator {
/**
* Returns the point on the specified MGeometry where its measure equals the specified position.
*
* @return a Point Geometry
* @throws MGeometryException
*/
public static Point getPointGeometry(MGeometry lrs, double position)
throws MGeometryException {
if (lrs == null) {
throw new MGeometryException("Non-null MGeometry parameter is required.");
}
Coordinate c = lrs.getCoordinateAtM(position);
Point pnt = lrs.getFactory().createPoint(c);
copySRID(lrs.asGeometry(), pnt);
return pnt;
}
public static MultiMLineString getLinearGeometry(MGeometry lrs,
double begin, double end) throws MGeometryException {
if (lrs == null) {
throw new MGeometryException("Non-null MGeometry parameter is required.");
}
MGeometryFactory factory = (MGeometryFactory) lrs.getFactory();
CoordinateSequence[] cs = lrs.getCoordinatesBetween(begin, end);
List<MLineString> linestrings = new ArrayList<MLineString>(cs.length);
for (int i = 0; i < cs.length; i++) {
MLineString ml;
if (cs[i].size() >= 2) {
ml = factory.createMLineString(cs[i]);
linestrings.add(ml);
}
}
MultiMLineString result = factory.createMultiMLineString(linestrings.toArray(new MLineString[linestrings.size()]));
copySRID(lrs.asGeometry(), result.asGeometry());
return result;
}
public static void copySRID(Geometry source, Geometry target) {
target.setSRID(source.getSRID());
}
}

View File

@ -0,0 +1,273 @@
/**
* $Id$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
/**
* This coordinate class supports 4D coordinates, where the first 3 measures
* (x,y,z) are coordinates in a 3 dimensional space (cartesian for example), and
* the fourth is a measure value used for linear referencing. Note that the
* measure value is independent of whether the (x,y,z) values are used. For
* example, the z value can not be used while the measure value is used. <p/>
* While this class extends the Coordinate class, it can be used seamlessly as a
* substitute in the event that the Measure value is not used. In these cases
* the Measure value shall simply be Double.NaN
*
* @see com.vividsolutions.jts.geom.Coordinate
*/
public class MCoordinate extends Coordinate {
/**
*
*/
private static final long serialVersionUID = 1L;
public double m;
/**
* Default constructor
*/
public MCoordinate() {
super();
this.m = Double.NaN;
}
public MCoordinate(double x, double y, double z, double m) {
super(x, y, z);
this.m = m;
}
public MCoordinate(double x, double y) {
super(x, y);
m = Double.NaN;
}
public MCoordinate(Coordinate coord) {
super(coord);
if (coord instanceof MCoordinate)
m = ((MCoordinate) coord).m;
else
m = Double.NaN;
}
public MCoordinate(MCoordinate coord) {
super(coord);
m = coord.m;
}
/**
* TODO: I'd like to see this method added to the base Coordinate class
* Returns the ordinate value specified in this Coordinate instance. The
* index of the desired ordinates are specified in the CoordinateSequence
* class; hence CoodinateSequence.X returns the x ordinate,
* CoodinateSequence.Y the y ordinate, CoodinateSequence.Z the z ordinate,
* and CoodinateSequence.M the m ordinate. Note that the dimension may not
* imply the desired ordinate in the case where one is using a 2 dimensional
* geometry with a measure value. Therefore, these constants are highly
* recommended.
*
* @param ordinateIndex
* the desired ordinate index.
* @return the value of stored in the ordinate index. Incorrect or unused
* indexes shall return Double.NaN
*/
public double getOrdinate(int ordinateIndex) {
switch (ordinateIndex) {
case CoordinateSequence.X:
return this.x;
case CoordinateSequence.Y:
return this.y;
case CoordinateSequence.Z:
return this.z;
case CoordinateSequence.M:
return this.m;
}
return Double.NaN;
}
/**
* TODO: I'd like to see this method added to the base Coordinate class Sets
* the value for a given ordinate. This should be specified using the
* CoordinateSequence ordinate index constants.
*
* @param ordinateIndex
* the desired ordinate index.
* @param value
* the new ordinate value
* @throws IllegalArgumentException
* if the ordinateIndex value is incorrect
* @see #getOrdinate(int)
*/
public void setOrdinate(int ordinateIndex, double value) {
switch (ordinateIndex) {
case CoordinateSequence.X:
this.x = value;
break;
case CoordinateSequence.Y:
this.y = value;
break;
case CoordinateSequence.Z:
this.z = value;
break;
case CoordinateSequence.M:
this.m = value;
break;
default:
throw new IllegalArgumentException("invalid ordinateIndex");
}
}
public boolean equals2DWithMeasure(Coordinate other) {
boolean result = this.equals2D(other);
if (result) {
MCoordinate mc = convertCoordinate(other);
result = (Double.compare(this.m, mc.m) == 0);
}
return result;
}
public boolean equals3DWithMeasure(Coordinate other) {
boolean result = this.equals3D(other);
if (result) {
MCoordinate mc = convertCoordinate(other);
result = (Double.compare(this.m, mc.m) == 0);
}
return result;
}
/*
* Default equality is now equality in 2D-plane. This is required to remain
* consistent with JTS.
*
* TODO:check whether this method is still needed.
*
* (non-Javadoc)
*
* @see com.vividsolutions.jts.geom.Coordinate#equals(java.lang.Object)
*/
public boolean equals(Object other) {
if (other instanceof Coordinate) {
return equals2D((Coordinate) other);
} else {
return false;
}
}
public String toString() {
return "(" + x + "," + y + "," + z + "," + " m=" + m + ")";
}
/**
* Converts a standard Coordinate instance to an MCoordinate instance. If
* coordinate is already an instance of an MCoordinate, then it is simply
* returned. In cases where it is converted, the measure value of the
* coordinate is initialized to Double.NaN.
*
* @param coordinate
* The coordinate to be converted
* @return an instance of MCoordinate corresponding to the
* <code>coordinate</code> parameter
*/
public static MCoordinate convertCoordinate(Coordinate coordinate) {
if (coordinate == null)
return null;
if (coordinate instanceof MCoordinate)
return (MCoordinate) coordinate;
return new MCoordinate(coordinate);
}
/**
* A convenience method for creating a MCoordinate instance where there are
* only 2 coordinates and an lrs measure value. The z value of the
* coordinate shall be set to Double.NaN
*
* @param x
* the x coordinate value
* @param y
* the y coordinate value
* @param m
* the lrs measure value
* @return The constructed MCoordinate value
*/
public static MCoordinate create2dWithMeasure(double x, double y, double m) {
return new MCoordinate(x, y, Double.NaN, m);
}
/**
* A convenience method for creating a MCoordinate instance where there are
* only 2 coordinates and an lrs measure value. The z and m value of the
* coordinate shall be set to Double.NaN
*
* @param x
* the x coordinate value
* @param y
* the y coordinate value
* @return The constructed MCoordinate value
*/
public static MCoordinate create2d(double x, double y) {
return new MCoordinate(x, y, Double.NaN, Double.NaN);
}
/**
* A convenience method for creating a MCoordinate instance where there are
* 3 coordinates and an lrs measure value.
*
* @param x
* the x coordinate value
* @param y
* the y coordinate value
* @param z
* the z coordinate value
* @param m
* the lrs measure value
* @return The constructed MCoordinate value
*/
public static MCoordinate create3dWithMeasure(double x, double y, double z,
double m) {
return new MCoordinate(x, y, z, m);
}
/**
* A convenience method for creating a MCoordinate instance where there are
* 3 coordinates but no lrs measure value. The m value of the coordinate
* shall be set to Double.NaN
*
* @param x
* the x coordinate value
* @param y
* the y coordinate value
* @param z
* the z coordinate value
* @return The constructed MCoordinate value
*/
public static MCoordinate create3d(double x, double y, double z) {
return new MCoordinate(x, y, z, Double.NaN);
}
}

View File

@ -0,0 +1,232 @@
/**
* $Id$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import java.io.Serializable;
/**
* Implements the CoordinateSequence interface. In this implementation,
* Coordinates returned by #toArray and #get are live -- parties that change
* them are actually changing the MCoordinateSequence's underlying data.
*/
public class MCoordinateSequence implements CoordinateSequence, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private MCoordinate[] coordinates;
public static MCoordinate[] copy(Coordinate[] coordinates) {
MCoordinate[] copy = new MCoordinate[coordinates.length];
for (int i = 0; i < coordinates.length; i++) {
copy[i] = new MCoordinate(coordinates[i]);
}
return copy;
}
public static MCoordinate[] copy(CoordinateSequence coordSeq) {
MCoordinate[] copy = new MCoordinate[coordSeq.size()];
for (int i = 0; i < coordSeq.size(); i++) {
copy[i] = new MCoordinate(coordSeq.getCoordinate(i));
}
return copy;
}
/**
* Copy constructor -- simply aliases the input array, for better
* performance.
*
* @param coordinates
*/
public MCoordinateSequence(MCoordinate[] coordinates) {
this.coordinates = coordinates;
}
/**
* Constructor that makes a copy of an array of Coordinates. Always makes a
* copy of the input array, since the actual class of the Coordinates in the
* input array may be different from MCoordinate.
*
* @param copyCoords
*/
public MCoordinateSequence(Coordinate[] copyCoords) {
coordinates = copy(copyCoords);
}
/**
* Constructor that makes a copy of a CoordinateSequence.
*
* @param coordSeq
*/
public MCoordinateSequence(CoordinateSequence coordSeq) {
coordinates = copy(coordSeq);
}
/**
* Constructs a sequence of a given size, populated with new
* {@link MCoordinate}s.
*
* @param size
* the size of the sequence to create
*/
public MCoordinateSequence(int size) {
coordinates = new MCoordinate[size];
for (int i = 0; i < size; i++) {
coordinates[i] = new MCoordinate();
}
}
/**
* @see com.vividsolutions.jts.geom.CoordinateSequence#getDimension()
*/
public int getDimension() {
return 4;
}
public Coordinate getCoordinate(int i) {
return coordinates[i];
}
/**
* @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinateCopy(int)
*/
public Coordinate getCoordinateCopy(int index) {
return new Coordinate(coordinates[index]);
}
/**
* @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int,
* com.vividsolutions.jts.geom.Coordinate)
*/
public void getCoordinate(int index, Coordinate coord) {
coord.x = coordinates[index].x;
coord.y = coordinates[index].y;
}
/**
* @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
*/
public double getX(int index) {
return coordinates[index].x;
}
/**
* @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int)
*/
public double getY(int index) {
return coordinates[index].y;
}
/**
* @return the measure value of the coordinate in the index
*/
public double getM(int index) {
return coordinates[index].m;
}
/**
* @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int,int)
*/
public double getOrdinate(int index, int ordinateIndex) {
switch (ordinateIndex) {
case CoordinateSequence.X:
return coordinates[index].x;
case CoordinateSequence.Y:
return coordinates[index].y;
case CoordinateSequence.Z:
return coordinates[index].z;
case CoordinateSequence.M:
return coordinates[index].m;
}
return Double.NaN;
}
/**
* @see com.vividsolutions.jts.geom.CoordinateSequence#setOrdinate(int,int,double)
*/
public void setOrdinate(int index, int ordinateIndex, double value) {
switch (ordinateIndex) {
case CoordinateSequence.X:
coordinates[index].x = value;
break;
case CoordinateSequence.Y:
coordinates[index].y = value;
break;
case CoordinateSequence.Z:
coordinates[index].z = value;
break;
case CoordinateSequence.M:
coordinates[index].m = value;
break;
default:
throw new IllegalArgumentException("invalid ordinateIndex");
}
}
public Object clone() {
MCoordinate[] cloneCoordinates = new MCoordinate[size()];
for (int i = 0; i < coordinates.length; i++) {
cloneCoordinates[i] = (MCoordinate) coordinates[i].clone();
}
return new MCoordinateSequence(cloneCoordinates);
}
public int size() {
return coordinates.length;
}
public Coordinate[] toCoordinateArray() {
return coordinates;
}
public Envelope expandEnvelope(Envelope env) {
for (int i = 0; i < coordinates.length; i++) {
env.expandToInclude(coordinates[i]);
}
return env;
}
public String toString() {
StringBuffer strBuf = new StringBuffer();
strBuf.append("MCoordinateSequence [");
for (int i = 0; i < coordinates.length; i++) {
if (i > 0)
strBuf.append(", ");
strBuf.append(coordinates[i]);
}
strBuf.append("]");
return strBuf.toString();
}
}

View File

@ -0,0 +1,86 @@
/**
* $Id$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import java.io.Serializable;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.CoordinateSequenceFactory;
/**
* Creates MCoordinateSequenceFactory internally represented as an array of
* {@link MCoordinate}s.
*/
public class MCoordinateSequenceFactory implements CoordinateSequenceFactory,
Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static MCoordinateSequenceFactory instance = new MCoordinateSequenceFactory();
private MCoordinateSequenceFactory() {
}
/**
* Returns the singleton instance of MCoordinateSequenceFactory
*/
public static MCoordinateSequenceFactory instance() {
return instance;
}
/**
* Returns an MCoordinateSequence based on the given array -- the array is
* used directly if it is an instance of MCoordinate[]; otherwise it is
* copied.
*/
public CoordinateSequence create(Coordinate[] coordinates) {
return coordinates instanceof MCoordinate[] ? new MCoordinateSequence(
(MCoordinate[]) coordinates) : new MCoordinateSequence(
coordinates);
}
public CoordinateSequence create(CoordinateSequence coordSeq) {
return new MCoordinateSequence(coordSeq);
}
/**
* Creates a MCoordinateSequence instance initialized to the size parameter.
* Note that the dimension argument is ignored.
*
* @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int,int)
*/
public CoordinateSequence create(int size, int dimension) {
return new MCoordinateSequence(size);
}
}

View File

@ -0,0 +1,187 @@
/**
* $Id$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import java.io.Serializable;
/**
* Defines geometries that carry measures in their CoordinateSequence.
*
* @author Karel Maesen
*/
public interface MGeometry extends Cloneable, Serializable {
/**
* Measures are increasing in the direction of the MGeometry
*/
public final static int INCREASING = 1;
/**
* Measures are constant across the Geometry
*/
public final static int CONSTANT = 0;
/**
* Measures are decreasing in the direction of the MGeometry
*/
public final static int DECREASING = -1;
/**
* Measures are not monotone along the Geometry
*/
public final static int NON_MONOTONE = -3;
/**
* Returns the measure value at the Coordinate
*
* @param c
* the Coordinate for which the measure value is sought
* @param tolerance
* distance to the MGeometry within which Coordinate c has to lie
* @return the measure value if Coordinate c is within tolerance of the
* Geometry, else Double.NaN
* <p>
* When the geometry is a ring or is self-intersecting more
* coordinates may be determined by one coordinate. In that case,
* the lowest measure is returned.
* @throws MGeometryException
* when this MGeometry is not monotone
*/
public double getMatCoordinate(Coordinate c, double tolerance)
throws MGeometryException;
/**
* Builds measures along the Geometry based on the length from the beginning
* (first coordinate) of the Geometry.
*
* @param keepBeginMeasure -
* if true, the measure of the first coordinate is maintained and
* used as start value, unless this measure is Double.NaN
*/
public void measureOnLength(boolean keepBeginMeasure);
/**
* Returns the Coordinate along the Geometry at the measure value
*
* @param m
* measure value
* @return the Coordinate if m is on the MGeometry otherwise null
* @throws MGeometryException
* when MGeometry is not monotone
*/
public Coordinate getCoordinateAtM(double m) throws MGeometryException;
/**
* Returns the coordinatesequence(s) containing all coordinates between the
* begin and end measures.
*
* @param begin
* begin measure
* @param end
* end measure
* @return an array containing all coordinatesequences in order between
* begin and end. Each CoordinateSequence covers a contiguous
* stretch of the MGeometry.
* @throws MGeometryException
* when this MGeometry is not monotone
*/
public CoordinateSequence[] getCoordinatesBetween(double begin, double end)
throws MGeometryException;
/**
* Returns the GeometryFactory of the MGeometry
*
* @return the GeometryFactory of this MGeometry
*/
public GeometryFactory getFactory();
/**
* Returns the minimum M-value of the MGeometry
*
* @return the minimum M-value
*/
public double getMinM();
/**
* Returns the maximum M-value of the MGeometry
*
* @return the maximum M-value
*/
public double getMaxM();
/**
* Determine whether the LRS measures (not the x,y,z coordinates) in the
* Coordinate sequence of the geometry is Monotone. Monotone implies that
* all measures in a sequence of coordinates are consecutively increasing,
* decreasing or equal according to the definition of the implementing
* geometry. Monotonicity is a pre-condition for most operations on
* MGeometries. The following are examples on Monotone measure sequences on
* a line string:
* <ul>
* <li> [0,1,2,3,4] - Monotone Increasing
* <li> [4,3,2,1] - Monotone Decreasing
* <li> [0,1,1,2,3] - Non-strict Monotone Increasing
* <li> [5,3,3,0] - Non-strict Monotone Decreasing
* </ul>
*
* @return true if the coordinates in the CoordinateSequence of the geometry
* are monotone.
*/
public boolean isMonotone(boolean strict);
// /**
// * Strict Monotone is similar to Monotone, with the added constraint that
// all measure coordinates
// * in the CoordinateSequence are ONLY consecutively increasing or
// decreasing. No consecutive
// * duplicate measures are allowed.
// *
// * @return true if the coordinates in the CoordinateSequence of the
// geometry are strictly monotone; that is, consitently
// * increasing or decreasing with no duplicate measures.
// * @see #isMonotone()
// */
// public boolean isStrictMonotone();
/**
* Returns this <code>MGeometry</code> as a <code>Geometry</code>.
*
* Modifying the returned <code>Geometry</code> will result in internal state changes.
*
* @return this object as a Geometry.
*/
public Geometry asGeometry();
}

View File

@ -0,0 +1,71 @@
/**
* $Id$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
/**
* @author Karel Maesen
*
*
*/
public class MGeometryException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public final static int OPERATION_REQUIRES_MONOTONE = 1;
public final static int UNIONM_ON_DISJOINT_MLINESTRINGS = 2;
public final static int GENERAL_MGEOMETRY_EXCEPTION = 0;
// type of exception
private final int type;
public MGeometryException(String s) {
super(s);
type = 0;
}
public MGeometryException(int type) {
super();
this.type = type;
}
public MGeometryException(int type, String msg) {
super(msg);
this.type = type;
}
public int getType() {
return type;
}
}

View File

@ -0,0 +1,104 @@
/**
* $Id$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import com.vividsolutions.jts.geom.*;
/**
* Extension of the GeometryFactory for constructing Geometries with Measure
* support.
*
* @see com.vividsolutions.jts.geom.GeometryFactory
*/
public class MGeometryFactory extends GeometryFactory {
/**
*
*/
private static final long serialVersionUID = 1L;
public MGeometryFactory(PrecisionModel precisionModel, int SRID,
MCoordinateSequenceFactory coordinateSequenceFactory) {
super(precisionModel, SRID, coordinateSequenceFactory);
}
public MGeometryFactory(MCoordinateSequenceFactory coordinateSequenceFactory) {
super(coordinateSequenceFactory);
}
public MGeometryFactory(PrecisionModel precisionModel) {
this(precisionModel, 0, MCoordinateSequenceFactory.instance());
}
public MGeometryFactory(PrecisionModel precisionModel, int SRID) {
this(precisionModel, SRID, MCoordinateSequenceFactory.instance());
}
public MGeometryFactory() {
this(new PrecisionModel(), 0);
}
/**
* Constructs a MLineString using the given Coordinates; a null or empty
* array will create an empty MLineString.
*
* @param coordinates
* array of MCoordinate defining this geometry's vertices
* @see #createLineString(com.vividsolutions.jts.geom.Coordinate[])
* @return An instance of MLineString containing the coordinates
*/
public MLineString createMLineString(MCoordinate[] coordinates) {
return createMLineString(coordinates != null ? getCoordinateSequenceFactory()
.create(coordinates)
: null);
}
public MultiMLineString createMultiMLineString(MLineString[] mlines,
double mGap) {
return new MultiMLineString(mlines, mGap, this);
}
public MultiMLineString createMultiMLineString(MLineString[] mlines) {
return new MultiMLineString(mlines, 0.0d, this);
}
/**
* Creates a MLineString using the given CoordinateSequence; a null or empty
* CoordinateSequence will create an empty MLineString.
*
* @param coordinates
* a CoordinateSequence possibly empty, or null
* @return An MLineString instance based on the <code>coordinates</code>
* @see #createLineString(com.vividsolutions.jts.geom.CoordinateSequence)
*/
public MLineString createMLineString(CoordinateSequence coordinates) {
return new MLineString(coordinates, this);
}
}

View File

@ -0,0 +1,689 @@
/**
* $Id$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import com.vividsolutions.jts.geom.*;
import java.util.ArrayList;
import java.util.List;
/**
* An implementation of the LineString class with the addition that the
* containing CoordinateSequence can carry measure. Note that this is not a
* strict requirement of the class, and can interact with non-measure geometries
* for JTS topological comparisons regardless.
*
* @author Karel Maesen
*/
public class MLineString extends LineString implements MGeometry {
/**
*
*/
private static final long serialVersionUID = 1L;
private boolean monotone = false;
private boolean strictMonotone = false;
public MLineString(CoordinateSequence points, GeometryFactory factory) {
super(points, factory);
determineMonotone();
}
public Object clone() {
LineString ls = (LineString) super.clone();
return new MLineString(ls.getCoordinateSequence(), this.getFactory());
}
/**
* Calculates whether the measures in the CoordinateSequence are monotone
* and strict monotone. The strict parameter indicates whether the
* determination should apply the definition of "strict monotonicity" or
* non-strict.
*/
private void determineMonotone() {
this.monotone = true;
this.strictMonotone = true;
if (!this.isEmpty()) {
double m[] = this.getMeasures();
// short circuit if the first value is NaN
if (Double.isNaN(m[0])) {
this.monotone = false;
this.strictMonotone = false;
} else {
int result = 0;
int prevResult = 0;
for (int i = 1; i < m.length && this.monotone; i++) {
result = Double.compare(m[i - 1], m[i]);
this.monotone = !(result * prevResult < 0 || Double
.isNaN(m[i]));
this.strictMonotone &= this.monotone && result != 0;
prevResult = result;
}
}
}
// if not monotone, then certainly not strictly monotone
assert (!(this.strictMonotone && !this.monotone));
}
protected void geometryChangedAction() {
determineMonotone();
}
/**
* @param co input coordinate in the neighbourhood of the MLineString
* @param tolerance max. distance that co may be from this MLineString
* @return an MCoordinate on this MLineString with appropriate M-value
*/
public MCoordinate getClosestPoint(Coordinate co, double tolerance)
throws MGeometryException {
if (!this.isMonotone(false)) {
throw new MGeometryException(
MGeometryException.OPERATION_REQUIRES_MONOTONE);
}
if (!this.isEmpty()) {
LineSegment seg = new LineSegment();
Coordinate[] coAr = this.getCoordinates();
seg.p0 = coAr[0];
double d = 0.0;
double projfact = 0.0;
double minDist = Double.POSITIVE_INFINITY;
MCoordinate mincp = null;
for (int i = 1; i < coAr.length; i++) {
seg.p1 = coAr[i];
Coordinate cp = seg.closestPoint(co);
d = cp.distance(co);
if (d <= tolerance && d <= minDist) {
MCoordinate testcp = new MCoordinate(cp);
projfact = seg.projectionFactor(cp);
testcp.m = ((MCoordinate) coAr[i - 1]).m
+ projfact
* (((MCoordinate) coAr[i]).m - ((MCoordinate) coAr[i - 1]).m);
if (d < minDist || testcp.m < mincp.m) {
mincp = testcp;
minDist = d;
}
}
seg.p0 = seg.p1;
}
if (minDist > tolerance) {
return null;
} else {
return mincp;
}
} else {
return null;
}
}
/*
* (non-Javadoc)
*
* @see org.hibernatespatial.mgeom.MGeometry#getCoordinateAtM(double)
*/
public Coordinate getCoordinateAtM(double m) throws MGeometryException {
if (!this.isMonotone(false)) {
throw new MGeometryException(
MGeometryException.OPERATION_REQUIRES_MONOTONE);
}
if (this.isEmpty()) {
return null;
} else {
double mval[] = this.getMeasures();
double lb = getMinM();
double up = getMaxM();
if (m < lb || m > up) {
return null;
} else {
// determine linesegment that contains m;
for (int i = 1; i < mval.length; i++) {
if ((mval[i - 1] <= m && m <= mval[i])
|| (mval[i] <= m && m <= mval[i - 1])) {
MCoordinate p0 = (MCoordinate) this
.getCoordinateN(i - 1);
MCoordinate p1 = (MCoordinate) this.getCoordinateN(i);
// r indicates how far in this segment the M-values lies
double r = (m - mval[i - 1]) / (mval[i] - mval[i - 1]);
double dx = r * (p1.x - p0.x);
double dy = r * (p1.y - p0.y);
double dz = r * (p1.z - p0.z);
MCoordinate nc = new MCoordinate(p0.x + dx, p0.y + dy,
p0.z + dz, m);
return nc;
}
}
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see com.vividsolutions.jts.geom.Geometry#getGeometryType()
*/
public String getGeometryType() {
return "MLineString";
}
/*
* (non-Javadoc)
*
* @see com.vividsolutions.jts.geom.Geometry#getMatCoordinate(com.vividsolutions.jts.geom.Coordinate,
* double)
*/
public double getMatCoordinate(Coordinate c, double tolerance)
throws MGeometryException {
MCoordinate mco = this.getClosestPoint(c, tolerance);
if (mco == null) {
return Double.NaN;
} else {
return (mco.m);
}
}
/**
* get the measure of the specified coordinate
*
* @param n index of the coordinate
* @return The measure of the coordinate. If the coordinate does not exists
* it returns Double.NaN
*/
public double getMatN(int n) {
return ((MCoordinate) (this.getCoordinates()[n])).m;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.spatial.mgeom.MGeometry##MGeometry#getMaxM()
*/
public double getMaxM() {
if (this.isEmpty()) {
return Double.NaN;
} else {
double[] measures = this.getMeasures();
if (this.getMeasureDirection() == MGeometry.INCREASING) {
return measures[measures.length - 1];
} else if (this.getMeasureDirection() == MGeometry.DECREASING
|| this.getMeasureDirection() == MGeometry.CONSTANT) {
return measures[0];
} else {
double ma = Double.NEGATIVE_INFINITY;
for (int i = 0; i < measures.length; i++) {
if (ma < measures[i]) {
ma = measures[i];
}
}
return ma;
}
}
}
/**
* Copies the coordinates of the specified array that fall between fromM and toM to a CoordinateSubSequence.
* <p/>
* The CoordinateSubSequence also contains the array indices of the first and last coordinate in firstIndex, resp.
* lastIndex. If there are no coordinates between fromM and toM, then firstIndex will contain -1, and lastIndex
* will point to the coordinate that is close to fromM or toM.
* <p/>
* This function expects that fromM is less than or equal to toM, and that the coordinates in the array are
* sorted monotonic w.r.t. to their m-values.
*
* @param mcoordinates
* @param fromM
* @param toM
* @param direction INCREASING or DECREASING
* @return a CoordinateSubSequence containing the coordinates between fromM and toM
*/
private CoordinateSubSequence copyCoordinatesBetween(MCoordinate[] mcoordinates, double fromM, double toM, int direction) {
CoordinateSubSequence sseq = new CoordinateSubSequence();
sseq.firstIndex = -1;
sseq.lastIndex = -1;
for (int i = 0; i < mcoordinates.length; i++) {
double m = mcoordinates[i].m;
if (m >= fromM && m <= toM) {
sseq.vertices.add(mcoordinates[i]);
if (sseq.firstIndex == -1) {
sseq.firstIndex = i;
}
}
if (direction == MGeometry.INCREASING) {
if (m > toM) break;
sseq.lastIndex = i;
} else {
if (m < fromM) break;
sseq.lastIndex = i;
}
}
return sseq;
}
/**
* Interpolates a coordinate between mco1, mco2, based on the measured value m
*/
private MCoordinate interpolate(MCoordinate mco1, MCoordinate mco2, double m) {
if (mco1.m > mco2.m) {
MCoordinate h = mco1;
mco1 = mco2;
mco2 = h;
}
if (m < mco1.m || m > mco2.m)
throw new IllegalArgumentException("Internal Error: m-value not in interval mco1.m/mco2.m");
double r = (m - mco1.m) / (mco2.m - mco1.m);
MCoordinate interpolated = new MCoordinate(
mco1.x + r * (mco2.x - mco1.x),
mco1.y + r * (mco2.y - mco1.y),
mco1.z + r * (mco2.z - mco1.z),
m);
this.getPrecisionModel().makePrecise(interpolated);
return interpolated;
}
public CoordinateSequence[] getCoordinatesBetween(double fromM, double toM) throws MGeometryException {
if (!this.isMonotone(false)) {
throw new MGeometryException(
MGeometryException.OPERATION_REQUIRES_MONOTONE,
"Operation requires geometry with monotonic measures");
}
if (fromM > toM) {
return getCoordinatesBetween(toM, fromM);
}
MCoordinateSequence mc;
if (!isOverlapping(fromM, toM)) {
mc = new MCoordinateSequence(new MCoordinate[]{});
} else {
MCoordinate[] mcoordinates = (MCoordinate[]) this.getCoordinates();
CoordinateSubSequence subsequence = copyCoordinatesBetween(mcoordinates, fromM, toM, this.getMeasureDirection());
addInterpolatedEndPoints(fromM, toM, mcoordinates, subsequence);
MCoordinate[] ra = subsequence.vertices.toArray(new MCoordinate[subsequence.vertices.size()]);
mc = new MCoordinateSequence(ra);
}
return new MCoordinateSequence[]{mc};
}
private boolean isOverlapping(double fromM, double toM) {
if (this.isEmpty()) return false;
//WARNING: this assumes a monotonic increasing or decreasing measures
MCoordinate beginCo = (MCoordinate) this.getCoordinateN(0);
MCoordinate endCo = (MCoordinate) this.getCoordinateN(this.getNumPoints() - 1);
return !(Math.min(fromM, toM) > Math.max(beginCo.m, endCo.m) ||
Math.max(fromM, toM) < Math.min(beginCo.m, endCo.m));
}
private void addInterpolatedEndPoints(double fromM, double toM, MCoordinate[] mcoordinates, CoordinateSubSequence subsequence) {
boolean increasing = this.getMeasureDirection() == MGeometry.INCREASING;
double fM, lM;
if (increasing) {
fM = fromM;
lM = toM;
} else {
fM = toM;
lM = fromM;
}
if (subsequence.firstIndex == -1) {
MCoordinate fi = interpolate(mcoordinates[subsequence.lastIndex], mcoordinates[subsequence.lastIndex + 1], fM);
subsequence.vertices.add(fi);
MCoordinate li = interpolate(mcoordinates[subsequence.lastIndex], mcoordinates[subsequence.lastIndex + 1], lM);
subsequence.vertices.add(li);
} else {
//interpolate a first vertex if necessary
if (subsequence.firstIndex > 0 && (
increasing && mcoordinates[subsequence.firstIndex].m > fromM ||
!increasing && mcoordinates[subsequence.firstIndex].m < toM
)) {
MCoordinate fi = interpolate(mcoordinates[subsequence.firstIndex - 1], mcoordinates[subsequence.firstIndex], fM);
subsequence.vertices.add(0, fi);
}
//interpolate a last vertex if necessary
if (subsequence.lastIndex < (mcoordinates.length - 1) && (
increasing && mcoordinates[subsequence.lastIndex].m < toM ||
!increasing && mcoordinates[subsequence.lastIndex].m > fromM)) {
MCoordinate li = interpolate(mcoordinates[subsequence.lastIndex], mcoordinates[subsequence.lastIndex + 1], lM);
subsequence.vertices.add(li);
}
}
}
private MCoordinate[] inverse(MCoordinate[] mcoordinates) {
for (int i = 0; i < mcoordinates.length / 2; i++) {
MCoordinate h = mcoordinates[i];
mcoordinates[i] = mcoordinates[mcoordinates.length - 1 - i];
mcoordinates[mcoordinates.length - 1 - i] = h;
}
return mcoordinates;
}
/**
* determine the direction of the measures w.r.t. the direction of the line
*
* @return MGeometry.NON_MONOTONE<BR>
* MGeometry.INCREASING<BR>
* MGeometry.DECREASING<BR>
* MGeometry.CONSTANT
*/
public int getMeasureDirection() {
if (!this.monotone) {
return MGeometry.NON_MONOTONE;
}
MCoordinate c1 = (MCoordinate) this.getCoordinateN(0);
MCoordinate c2 = (MCoordinate) this
.getCoordinateN(this.getNumPoints() - 1);
if (c1.m < c2.m) {
return MGeometry.INCREASING;
} else if (c1.m > c2.m) {
return MGeometry.DECREASING;
} else {
return MGeometry.CONSTANT;
}
}
/**
* @return the array with measure-values of the vertices
*/
public double[] getMeasures() {
// return the measures of all vertices
if (!this.isEmpty()) {
Coordinate[] co = this.getCoordinates();
double[] a = new double[co.length];
for (int i = 0; i < co.length; i++) {
a[i] = ((MCoordinate) co[i]).m;
}
return a;
} else {
return null;
}
}
public double getMinM() {
if (this.isEmpty()) {
return Double.NaN;
} else {
double[] a = this.getMeasures();
if (this.getMeasureDirection() == MGeometry.INCREASING) {
return a[0];
} else if (this.getMeasureDirection() == MGeometry.DECREASING
|| this.getMeasureDirection() == MGeometry.CONSTANT) {
return a[a.length - 1];
} else {
double ma = Double.POSITIVE_INFINITY;
for (int i = 0; i < a.length; i++) {
if (ma > a[i]) {
ma = a[i];
}
}
return ma;
}
}
}
/**
* Assigns the first coordinate in the CoordinateSequence to the
* <code>beginMeasure</code> and the last coordinate in the
* CoordinateSequence to the <code>endMeasure</code>. Measure values for
* intermediate coordinates are then interpolated proportionally based on
* their 2d offset of the overall 2d length of the LineString.
* <p/>
* If the beginMeasure and endMeasure values are equal it is assumed that
* all intermediate coordinates shall be the same value.
*
* @param beginMeasure Measure value for first coordinate
* @param endMeasure Measure value for last coordinate
*/
public void interpolate(double beginMeasure, double endMeasure) {
if (this.isEmpty()) {
return;
}
// interpolate with first vertex = beginMeasure; last vertex =
// endMeasure
Coordinate[] coordinates = this.getCoordinates();
double length = this.getLength();
double mLength = endMeasure - beginMeasure;
double d = 0;
boolean continuous = DoubleComparator.equals(beginMeasure, endMeasure);
double m = beginMeasure;
MCoordinate prevCoord = MCoordinate.convertCoordinate(coordinates[0]);
prevCoord.m = m;
MCoordinate curCoord;
for (int i = 1; i < coordinates.length; i++) {
curCoord = MCoordinate.convertCoordinate(coordinates[i]);
if (continuous) {
curCoord.m = beginMeasure;
} else {
d += curCoord.distance(prevCoord);
m = beginMeasure + (d / length) * mLength;
curCoord.m = m;
prevCoord = curCoord;
}
}
this.geometryChanged();
assert (this.isMonotone(false)) : "interpolate function should always leave MGeometry monotone";
}
/**
* Returns the measure length of the segment. This method assumes that the
* length of the LineString is defined by the absolute value of (last
* coordinate - first coordinate) in the CoordinateSequence. If either
* measure is not defined or the CoordinateSequence contains no coordinates,
* then Double.NaN is returned. If there is only 1 element in the
* CoordinateSequence, then 0 is returned.
*
* @return The measure length of the LineString
*/
public double getMLength() {
if (getCoordinateSequence().size() == 0)
return Double.NaN;
if (getCoordinateSequence().size() == 1)
return 0.0D;
else {
int lastIndex = getCoordinateSequence().size() - 1;
double begin = getCoordinateSequence().getOrdinate(0,
CoordinateSequence.M);
double end = getCoordinateSequence().getOrdinate(lastIndex,
CoordinateSequence.M);
return (Double.isNaN(begin) || Double.isNaN(end)) ? Double.NaN
: Math.abs(end - begin);
}
}
/**
* Indicates whether the MLineString has monotone increasing or decreasing
* M-values
*
* @return <code>true if MLineString is empty or M-values are increasing (NaN) values, false otherwise</code>
*/
public boolean isMonotone(boolean strict) {
return strict ? this.strictMonotone : this.monotone;
}
public Geometry asGeometry() {
return this;
}
// TODO get clear on function and implications of normalize
// public void normalize(){
//
// }
public void measureOnLength(boolean keepBeginMeasure) {
Coordinate[] co = this.getCoordinates();
if (!this.isEmpty()) {
double d = 0.0;
MCoordinate pco = (MCoordinate) co[0];
if (!keepBeginMeasure || Double.isNaN(pco.m)) {
pco.m = 0.0d;
}
MCoordinate mco;
for (int i = 1; i < co.length; i++) {
mco = (MCoordinate) co[i];
d += mco.distance(pco);
mco.m = d;
pco = mco;
}
this.geometryChanged();
}
}
/**
* This method reverses the measures assigned to the Coordinates in the
* CoordinateSequence without modifying the positional (x,y,z) values.
*/
public void reverseMeasures() {
if (!this.isEmpty()) {
double m[] = this.getMeasures();
MCoordinate[] coar = (MCoordinate[]) this.getCoordinates();
double nv;
for (int i = 0; i < m.length; i++) {
nv = m[m.length - 1 - i];
coar[i].m = nv;
}
this.geometryChanged();
}
}
public void setMeasureAtIndex(int index, double m) {
getCoordinateSequence().setOrdinate(index, CoordinateSequence.M, m);
this.geometryChanged();
}
/**
* Shift all measures by the amount parameter. A negative amount shall
* subtract the amount from the measure. Note that this can make for
* negative measures.
*
* @param amount the positive or negative amount by which to shift the measures
* in the CoordinateSequence.
*/
public void shiftMeasure(double amount) {
Coordinate[] coordinates = this.getCoordinates();
MCoordinate mco;
if (!this.isEmpty()) {
for (int i = 0; i < coordinates.length; i++) {
mco = (MCoordinate) coordinates[i];
mco.m = mco.m + amount;
}
}
this.geometryChanged();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString() {
Coordinate[] ar = this.getCoordinates();
StringBuffer buf = new StringBuffer(ar.length * 17 * 3);
for (int i = 0; i < ar.length; i++) {
buf.append(ar[i].x);
buf.append(" ");
buf.append(ar[i].y);
buf.append(" ");
buf.append(((MCoordinate) ar[i]).m);
buf.append("\n");
}
return buf.toString();
}
public MLineString unionM(MLineString l) throws MGeometryException {
if (!this.monotone || !l.monotone) {
throw new MGeometryException(
MGeometryException.OPERATION_REQUIRES_MONOTONE);
}
Coordinate[] linecoar = l.getCoordinates();
if (l.getMeasureDirection() == MGeometry.DECREASING) {
CoordinateArrays.reverse(linecoar);
}
Coordinate[] thiscoar = this.getCoordinates();
if (this.getMeasureDirection() == MGeometry.DECREASING) {
CoordinateArrays.reverse(thiscoar);
}
// either the last coordinate in thiscoar equals the first in linecoar;
// or the last in linecoar equals the first in thiscoar;
MCoordinate lasttco = (MCoordinate) thiscoar[thiscoar.length - 1];
MCoordinate firsttco = (MCoordinate) thiscoar[0];
MCoordinate lastlco = (MCoordinate) linecoar[linecoar.length - 1];
MCoordinate firstlco = (MCoordinate) linecoar[0];
MCoordinate[] newcoar = new MCoordinate[thiscoar.length
+ linecoar.length - 1];
if (lasttco.equals2D(firstlco)
&& DoubleComparator.equals(lasttco.m, firstlco.m)) {
System.arraycopy(thiscoar, 0, newcoar, 0, thiscoar.length);
System.arraycopy(linecoar, 1, newcoar, thiscoar.length,
linecoar.length - 1);
} else if (lastlco.equals2D(firsttco)
&& DoubleComparator.equals(lastlco.m, firsttco.m)) {
System.arraycopy(linecoar, 0, newcoar, 0, linecoar.length);
System.arraycopy(thiscoar, 1, newcoar, linecoar.length,
thiscoar.length - 1);
} else {
throw new MGeometryException(
MGeometryException.UNIONM_ON_DISJOINT_MLINESTRINGS);
}
CoordinateSequence mcs = this.getFactory()
.getCoordinateSequenceFactory().create(newcoar);
MLineString returnmlinestring = new MLineString(mcs, this.getFactory());
assert (returnmlinestring.isMonotone(false)) : "new unionM-ed MLineString is not monotone";
return returnmlinestring;
}
static class CoordinateSubSequence {
private int firstIndex;
private int lastIndex;
private List<MCoordinate> vertices = new ArrayList<MCoordinate>();
}
}

View File

@ -0,0 +1,279 @@
/*
* $Id:$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.mgeom;
import com.vividsolutions.jts.geom.*;
public class MultiMLineString extends MultiLineString implements MGeometry {
/**
*
*/
private static final long serialVersionUID = 1L;
private final double mGap; // difference in m between end of one part and
private boolean monotone = false;
private boolean strictMonotone = false;
/**
* @param MlineStrings the <code>MLineString</code>s for this
* <code>MultiMLineString</code>, or <code>null</code> or an
* empty array to create the empty geometry. Elements may be
* empty <code>LineString</code>s, but not <code>null</code>s.
*/
public MultiMLineString(MLineString[] MlineStrings, double mGap,
GeometryFactory factory) {
super(MlineStrings, factory);
this.mGap = mGap;
determineMonotone();
}
/**
* TODO Improve this, and add more unit tests
*/
private void determineMonotone() {
this.monotone = true;
this.strictMonotone = true;
if (this.isEmpty()) {
return;
}
int mdir = MGeometry.CONSTANT;
for (int i = 0; i < this.geometries.length; i++) {
MLineString ml = (MLineString) this.geometries[0];
if (!ml.isEmpty()) {
mdir = ml.getMeasureDirection();
break;
}
}
for (int i = 0; i < this.geometries.length; i++) {
MLineString ml = (MLineString) this.geometries[i];
if (ml.isEmpty()) continue;
// check whether mlinestrings are all pointing in same direction,
// and
// are monotone
if (!ml.isMonotone(false)
|| (ml.getMeasureDirection() != mdir && !(ml
.getMeasureDirection() == MGeometry.CONSTANT))) {
this.monotone = false;
break;
}
if (!ml.isMonotone(true) || (ml.getMeasureDirection() != mdir)) {
this.strictMonotone = false;
break;
}
// check whether the geometry measures do not overlap or
// are inconsistent with previous parts
if (i > 0) {
MLineString mlp = (MLineString) this.geometries[i - 1];
if (mdir == MGeometry.INCREASING) {
if (mlp.getMaxM() > ml.getMinM()) {
monotone = false;
} else if (mlp.getMaxM() >= ml.getMinM()) {
strictMonotone = false;
}
} else {
if (mlp.getMinM() < ml.getMaxM()) {
monotone = false;
} else if (mlp.getMinM() <= ml.getMaxM()) {
strictMonotone = false;
}
}
}
}
if (!monotone) {
this.strictMonotone = false;
}
}
protected void geometryChangedAction() {
determineMonotone();
}
public String getGeometryType() {
return "MultiMLineString";
}
public double getMGap() {
return this.mGap;
}
public double getMatCoordinate(Coordinate co, double tolerance)
throws MGeometryException {
if (!this.isMonotone(false)) {
throw new MGeometryException(
MGeometryException.OPERATION_REQUIRES_MONOTONE);
}
double mval = Double.NaN;
double dist = Double.POSITIVE_INFINITY;
com.vividsolutions.jts.geom.Point p = this.getFactory().createPoint(co);
// find points within tolerance for getMatCoordinate
for (int i = 0; i < this.getNumGeometries(); i++) {
MLineString ml = (MLineString) this.getGeometryN(i);
// go to next MLineString if the input point is beyond tolerance
if (ml.distance(p) > tolerance)
continue;
MCoordinate mc = ml.getClosestPoint(co, tolerance);
if (mc != null) {
double d = mc.distance(co);
if (d <= tolerance && d < dist) {
dist = d;
mval = mc.m;
}
}
}
return mval;
}
public Object clone() {
MultiLineString ml = (MultiLineString) super.clone();
return ml;
}
public void measureOnLength(boolean keepBeginMeasure) {
double startM = 0.0;
for (int i = 0; i < this.getNumGeometries(); i++) {
MLineString ml = (MLineString) this.getGeometryN(i);
if (i == 0) {
ml.measureOnLength(keepBeginMeasure);
} else {
ml.measureOnLength(false);
}
if (startM != 0.0) {
ml.shiftMeasure(startM);
}
startM += ml.getLength() + mGap;
}
this.geometryChanged();
}
/*
* (non-Javadoc)
*
* @see org.hibernate.spatial.mgeom.MGeometry#getCoordinateAtM(double)
*/
public Coordinate getCoordinateAtM(double m) throws MGeometryException {
if (!this.isMonotone(false)) {
throw new MGeometryException(
MGeometryException.OPERATION_REQUIRES_MONOTONE);
}
Coordinate c = null;
for (int i = 0; i < this.getNumGeometries(); i++) {
MGeometry mg = (MGeometry) this.getGeometryN(i);
c = mg.getCoordinateAtM(m);
if (c != null) {
return c;
}
}
return null;
}
public CoordinateSequence[] getCoordinatesBetween(double begin, double end)
throws MGeometryException {
if (!this.isMonotone(false)) {
throw new MGeometryException(
MGeometryException.OPERATION_REQUIRES_MONOTONE,
"Operation requires geometry with monotonic measures");
}
if (this.isEmpty())
return null;
java.util.ArrayList<CoordinateSequence> ar = new java.util.ArrayList<CoordinateSequence>();
for (int i = 0; i < this.getNumGeometries(); i++) {
MLineString ml = (MLineString) this.getGeometryN(i);
for (CoordinateSequence cs : ml.getCoordinatesBetween(begin, end)) {
if (cs.size() > 0) {
ar.add(cs);
}
}
}
return ar.toArray(new CoordinateSequence[ar.size()]);
}
/*
* (non-Javadoc)
*
* @see org.hibernate.spatial.mgeom.MGeometry#getMinM()
*/
public double getMinM() {
double minM = Double.POSITIVE_INFINITY;
for (int i = 0; i < this.getNumGeometries(); i++) {
MLineString ml = (MLineString) this.getGeometryN(i);
double d = ml.getMinM();
if (d < minM)
minM = d;
}
return minM;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.spatial.mgeom.MGeometry#getMaxM()
*/
public double getMaxM() {
double maxM = Double.NEGATIVE_INFINITY;
for (int i = 0; i < this.getNumGeometries(); i++) {
MLineString ml = (MLineString) this.getGeometryN(i);
double d = ml.getMaxM();
if (d > maxM)
maxM = d;
}
return maxM;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.spatial.mgeom.MGeometry#isMonotone()
*/
public boolean isMonotone(boolean strictMonotone) {
return strictMonotone ? this.strictMonotone : monotone;
}
public Geometry asGeometry() {
return this;
}
}

View File

@ -0,0 +1,70 @@
/*
* $Id: SpatialDialectProvider.java 200 2010-03-31 19:52:12Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.spi;
import org.hibernate.spatial.SpatialDialect;
/**
* Interface that is implemented by a SpatialDialect Provider.
* <p/>
* A <class>SpatialDialectProvider</class> creates a SpatialDialect for one or
* more database systems. These databases are identified by a dialect string.
* Usually this is the fully qualified class name of a
* <code>org.hibernate.dialect.Dialect</code> or <code>SpatialDialect</code>
* implementation
*
* @author Karel Maesen, Geovise BVBA
*/
public interface SpatialDialectProvider {
/**
* create Spatial Dialect with the provided name.
*
* @param dialect Name of the dialect to create.
* @return a SpatialDialect
*/
public SpatialDialect createSpatialDialect(String dialect);
/**
* Returns the default dialect for this provider.
*
* @return The Default Dialect provided by the implementation.
* <p/>
* Implementations should never return null for this method.
*/
public SpatialDialect getDefaultDialect();
/**
* Returns the Dialect names
* <p/>
* This method must return the canonical class names of the Spatialdialect
* implementations that this provider provides.
*
* @return array of dialect names.
*/
public String[] getSupportedDialects();
}

View File

@ -0,0 +1,119 @@
package org.hibernate.spatial.util;
import java.sql.*;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Oct 28, 2010
*/
public class MetadataInspector {
static String driver;
static String dbURI;
static String userName;
static String passWord;
static String table;
public static void main(String[] args) throws Exception {
readArgs(args);
// Connection reference
Connection conn = null;
try {
// Load database driver
try {
Class.forName(driver);
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
// Make connection
conn = DriverManager.getConnection(dbURI, userName, passWord);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * from " + table);
// Get the ResultSet meta data
ResultSetMetaData rmd = rs.getMetaData();
rs.next();
if (rmd == null) {
System.out.println("ResultSet meta data not available");
} else {
int columnCount = rmd.getColumnCount();
// Display number of Columns in the ResultSet
System.out.println("Number of Columns in the table : " + columnCount);
for (int i = 1; i <= columnCount; i++) {
// Display number of Column name
System.out.println("Column Name : " + rmd.getColumnName(i));
// Display number of Column Type
System.out.println("Column TypeName : " + rmd.getColumnTypeName(i));
System.out.println("Column type : " + rmd.getColumnType(i));
Object o = rs.getObject(i);
System.out.println("Column object class: " + o.getClass().getName());
// Display if Column can be NOT NULL
switch (rmd.isNullable(i)) {
case ResultSetMetaData.columnNoNulls:
System.out.println(" NOT NULL");
break;
case ResultSetMetaData.columnNullable:
System.out.println(" NULLABLE");
break;
case ResultSetMetaData.columnNullableUnknown:
System.out.println(" NULLABLE Unkown");
}
System.out.println();
}
}
} finally {
// Close connection
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
System.out.println("Error in closing Conection");
}
}
}
}
// private static String getJavaJDBCTypeName(int type){
//
// }
private static void readArgs(String[] args) {
try {
driver = args[0];
dbURI = args[1];
userName = args[2];
passWord = args[3];
table = args[4];
} catch (Exception e) {
System.out.printf("Usage: metadataInspector <driver> <dbUri> <userName> <passWord> <table>");
System.exit(1);
}
}
}

View File

@ -0,0 +1 @@
org.hibernate.spatial.integration.SpatialIntegrator

View File

@ -0,0 +1,162 @@
package org.hibernate.spatial;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.spatial.test.*;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.slf4j.Logger;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Sep 30, 2010
*/
public abstract class SpatialFunctionalTestCase extends BaseCoreFunctionalTestCase {
protected TestData testData;
protected DataSourceUtils dataSourceUtils;
protected GeometryEquality geometryEquality;
protected AbstractExpectationsFactory expectationsFactory;
public void insertTestData() {
try {
dataSourceUtils.insertTestData(testData);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void deleteAllTestEntities() {
Session session = null;
Transaction tx = null;
try {
session = openSession();
tx = session.beginTransaction();
String hql = "delete from GeomEntity";
Query q = session.createQuery(hql);
q.executeUpdate();
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
} finally {
if (session != null) session.close();
}
}
public void prepareTest() {
try {
TestSupport tsFactory = TestSupportFactories.instance().getTestSupportFactory(getDialect());
Configuration cfg = configuration();
dataSourceUtils = tsFactory.createDataSourceUtil(cfg);
expectationsFactory = tsFactory.createExpectationsFactory(dataSourceUtils);
testData = tsFactory.createTestData(this);
geometryEquality = tsFactory.createGeometryEquality();
dataSourceUtils.afterCreateSchema();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void cleanupTest() throws SQLException {
dataSourceUtils.close();
}
public Connection getConnection() throws SQLException {
return dataSourceUtils.getConnection();
}
public String getBaseForMappings() {
// return "org/hibernatespatial/test/";
return "";
}
public String[] getMappings() {
return new String[]{"GeomEntity.hbm.xml"};
}
/**
* Returns true if the spatial dialect supports the specified function
*
* @param spatialFunction
* @return
*/
public boolean isSupportedByDialect(SpatialFunction spatialFunction) {
SpatialDialect dialect = (SpatialDialect) getDialect();
return dialect.supports(spatialFunction);
}
/**
* Supports true if the spatial dialect supports filtering (e.g. ST_overlap, MBROverlap, SDO_FILTER)
*
* @return
*/
public boolean dialectSupportsFiltering() {
SpatialDialect dialect = (SpatialDialect) getDialect();
return dialect.supportsFiltering();
}
abstract protected Logger getLogger();
/**
* Adds the query results to a Map.
* <p/>
* Each row is added as a Map entry with the first column the key,
* and the second the value. It is assumed that the first column is an
* identifier of a type assignable to Integer.
*
* @param result map of
* @param query the source Query
* @param <T> type of the second column in the query results
*/
protected <T> void addQueryResults(Map<Integer, T> result, Query query) {
List<Object[]> rows = (List<Object[]>) query.list();
if (rows.size() == 0) {
getLogger().warn("No results returned for query!!");
}
for (Object[] row : rows) {
Integer id = (Integer) row[0];
T val = (T) row[1];
result.put(id, val);
}
}
protected <T> void compare(Map<Integer, T> expected, Map<Integer, T> received) {
for (Integer id : expected.keySet()) {
getLogger().debug("Case :" + id);
getLogger().debug("expected: " + expected.get(id));
getLogger().debug("received: " + received.get(id));
compare(id, expected.get(id), received.get(id));
}
}
protected void compare(Integer id, Object expected, Object received) {
assertTrue(expected != null || (expected == null && received == null));
if (expected instanceof byte[]) {
assertArrayEquals("Failure on testsuite-suite for case " + id, (byte[]) expected, (byte[]) received);
} else if (expected instanceof Geometry) {
if (!(received instanceof Geometry))
fail("Expected a Geometry, but received an object of type " + received.getClass().getCanonicalName());
assertTrue("Failure on testsuite-suite for case " + id, geometryEquality.test((Geometry) expected, (Geometry) received));
} else {
if (expected instanceof Long) {
assertEquals("Failure on testsuite-suite for case " + id, ((Long) expected).intValue(), received);
} else {
assertEquals("Failure on testsuite-suite for case " + id, expected, received);
}
}
}
}

View File

@ -0,0 +1,359 @@
/*
* $Id: TestSpatialFunctions.java 193 2010-03-26 15:56:02Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
import com.vividsolutions.jts.geom.Geometry;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* @author Karel Maesen, Geovise BVBA
*/
public class TestSpatialFunctions extends SpatialFunctionalTestCase {
private static Logger LOGGER = LoggerFactory.getLogger(TestSpatialFunctions.class);
public void prepareTest() {
super.prepareTest();
insertTestData();
}
protected Logger getLogger() {
return LOGGER;
}
@Test
public void testSpatialFunctions() throws Exception {
dimension();
astext();
asbinary();
geometrytype();
srid();
issimple();
isempty();
boundary();
envelope();
within();
equals();
crosses();
contains();
disjoint();
intersects();
overlaps();
touches();
relate();
distance();
buffer();
convexhull();
intersection();
difference();
symdifference();
geomunion();
dwithin();
transform();
}
public void dimension() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.dimension)) return;
Map<Integer, Integer> dbexpected = expectationsFactory.getDimension();
String hql = "SELECT id, dimension(geom) FROM GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void astext() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.astext)) return;
Map<Integer, String> dbexpected = expectationsFactory.getAsText();
String hql = "SELECT id, astext(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void asbinary() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.asbinary)) return;
Map<Integer, byte[]> dbexpected = expectationsFactory.getAsBinary();
String hql = "SELECT id, asbinary(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void geometrytype() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.geometrytype)) return;
Map<Integer, String> dbexpected = expectationsFactory.getGeometryType();
String hql = "SELECT id, geometrytype(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void srid() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.srid)) return;
Map<Integer, Integer> dbexpected = expectationsFactory.getSrid();
String hql = "SELECT id, srid(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void issimple() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.issimple)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getIsSimple();
String hql = "SELECT id, issimple(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void isempty() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.isempty)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getIsEmpty();
String hql = "SELECT id, isEmpty(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void boundary() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.boundary)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getBoundary();
String hql = "SELECT id, boundary(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void envelope() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.envelope)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getEnvelope();
String hql = "SELECT id, envelope(geom) from GeomEntity";
retrieveHQLResultsAndCompare(dbexpected, hql);
}
public void within() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.within)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getWithin(expectationsFactory.getTestPolygon());
String hql = "SELECT id, within(geom, :filter) from GeomEntity where within(geom, :filter) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void equals() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.equals)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getEquals(expectationsFactory.getTestPolygon());
String hql = "SELECT id, equals(geom, :filter) from GeomEntity where equals(geom, :filter) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void crosses() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.crosses)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getCrosses(expectationsFactory.getTestPolygon());
String hql = "SELECT id, crosses(geom, :filter) from GeomEntity where crosses(geom, :filter) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void contains() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.contains)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getContains(expectationsFactory.getTestPolygon());
String hql = "SELECT id, contains(geom, :filter) from GeomEntity where contains(geom, :filter) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void disjoint() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.disjoint)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getDisjoint(expectationsFactory.getTestPolygon());
String hql = "SELECT id, disjoint(geom, :filter) from GeomEntity where disjoint(geom, :filter) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void intersects() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.intersects)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getIntersects(expectationsFactory.getTestPolygon());
String hql = "SELECT id, intersects(geom, :filter) from GeomEntity where intersects(geom, :filter) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void overlaps() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.overlaps)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getOverlaps(expectationsFactory.getTestPolygon());
String hql = "SELECT id, overlaps(geom, :filter) from GeomEntity where overlaps(geom, :filter) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void touches() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.touches)) return;
String hql = "SELECT id, touches(geom, :filter) from GeomEntity where touches(geom, :filter) = true and srid(geom) = 4326";
Map<Integer, Boolean> dbexpected = expectationsFactory.getTouches(expectationsFactory.getTestPolygon());
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void relate() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.relate)) return;
String matrix = "T*T***T**";
Map<Integer, Boolean> dbexpected = expectationsFactory.getRelate(expectationsFactory.getTestPolygon(), matrix);
String hql = "SELECT id, relate(geom, :filter, :matrix) from GeomEntity where relate(geom, :filter, :matrix) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
params.put("matrix", matrix);
retrieveHQLResultsAndCompare(dbexpected, hql, params);
matrix = "FF*FF****";
dbexpected = expectationsFactory.getRelate(expectationsFactory.getTestPolygon(), matrix);
params.put("matrix", matrix);
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void distance() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.distance)) return;
Map<Integer, Double> dbexpected = expectationsFactory.getDistance(expectationsFactory.getTestPolygon());
String hql = "SELECT id, distance(geom, :filter) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void buffer() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.buffer)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getBuffer(Double.valueOf(1.0));
String hql = "SELECT id, buffer(geom, :distance) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("distance", Double.valueOf(1.0));
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void convexhull() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.convexhull)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getConvexHull(expectationsFactory.getTestPolygon());
String hql = "SELECT id, convexhull(geomunion(geom, :polygon)) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("polygon", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void intersection() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.intersection)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getIntersection(expectationsFactory.getTestPolygon());
String hql = "SELECT id, intersection(geom, :polygon) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("polygon", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void difference() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.difference)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getDifference(expectationsFactory.getTestPolygon());
String hql = "SELECT id, difference(geom, :polygon) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("polygon", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void symdifference() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.symdifference)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getSymDifference(expectationsFactory.getTestPolygon());
String hql = "SELECT id, symdifference(geom, :polygon) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("polygon", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void geomunion() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.geomunion)) return;
Map<Integer, Geometry> dbexpected = expectationsFactory.getGeomUnion(expectationsFactory.getTestPolygon());
String hql = "SELECT id, geomunion(geom, :polygon) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("polygon", expectationsFactory.getTestPolygon());
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void dwithin() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.dwithin)) return;
double distance = 30.0;
Map<Integer, Boolean> dbexpected = expectationsFactory.getDwithin(expectationsFactory.getTestPoint(), distance);
String hql = "SELECT id, dwithin(geom, :filter, :distance) from GeomEntity where dwithin(geom, :filter, :distance) = true and srid(geom) = 4326";
Map<String, Object> params = createQueryParams("filter", expectationsFactory.getTestPoint());
params.put("distance", 30.0);
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public void transform() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.transform)) return;
int epsg = 4324;
Map<Integer, Geometry> dbexpected = expectationsFactory.getTransform(epsg);
String hql = "SELECT id, transform(geom, :epsg) from GeomEntity where srid(geom) = 4326";
Map<String, Object> params = createQueryParams("epsg", Integer.valueOf(epsg));
retrieveHQLResultsAndCompare(dbexpected, hql, params);
}
public <T> void retrieveHQLResultsAndCompare(Map<Integer, T> dbexpected, String hql) {
retrieveHQLResultsAndCompare(dbexpected, hql, null);
}
protected <T> void retrieveHQLResultsAndCompare(Map<Integer, T> dbexpected, String hql, Map<String, Object> params) {
Map<Integer, T> hsreceived = new HashMap<Integer, T>();
doInSession(hql, hsreceived, params);
compare(dbexpected, hsreceived);
}
private Map<String, Object> createQueryParams(String filterParamName, Object value) {
Map<String, Object> params = new HashMap<String, Object>();
params.put(filterParamName, value);
return params;
}
private <T> void doInSession(String hql, Map<Integer, T> result, Map<String, Object> params) {
Session session = null;
Transaction tx = null;
try {
session = openSession();
tx = session.beginTransaction();
Query query = session.createQuery(hql);
setParameters(params, query);
addQueryResults(result, query);
} finally {
if (tx != null) tx.rollback();
if (session != null) session.close();
}
}
private void setParameters(Map<String, Object> params, Query query) {
if (params == null) return;
for (String param : params.keySet()) {
Object value = params.get(param);
// if (value instanceof Geometry) {
// query.setParameter(param, value, GeometryType.TYPE);
// } else {
query.setParameter(param, value);
// }
}
}
}

View File

@ -0,0 +1,210 @@
/*
* $Id: TestSpatialRestrictions.java 242 2010-09-22 20:40:07Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.spatial.criterion.SpatialRestrictions;
import org.hibernate.spatial.test.GeomEntity;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.fail;
public class TestSpatialRestrictions extends SpatialFunctionalTestCase {
private static Logger LOGGER = LoggerFactory.getLogger(TestSpatialRestrictions.class);
public void prepareTest() {
super.prepareTest();
try {
dataSourceUtils.insertTestData(testData);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
protected Logger getLogger() {
return LOGGER;
}
@Test
public void testRestrictions() throws Exception {
within();
filter();
contains();
crosses();
touches();
disjoint();
eq();
intersects();
overlaps();
dwithin();
havingSRID();
isEmpty();
isNotEmpty();
}
public void within() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.within)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getWithin(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.within("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void filter() throws SQLException {
if (!dialectSupportsFiltering()) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getFilter(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.filter("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void contains() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.contains)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getContains(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.contains("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void crosses() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.crosses)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getCrosses(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.crosses("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void touches() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.touches)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getTouches(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.touches("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void disjoint() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.disjoint)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getDisjoint(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.disjoint("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void eq() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.equals)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getEquals(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.eq("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void intersects() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.intersects)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getIntersects(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.intersects("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void overlaps() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.overlaps)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getOverlaps(expectationsFactory.getTestPolygon());
Criterion spatialCriterion = SpatialRestrictions.overlaps("geom", expectationsFactory.getTestPolygon());
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void dwithin() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.dwithin)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getDwithin(expectationsFactory.getTestPoint(), 30.0);
Criterion spatialCriterion = SpatialRestrictions.distanceWithin("geom", expectationsFactory.getTestPoint(), 30.0);
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void isEmpty() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.isempty)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getIsEmpty();
Criterion spatialCriterion = SpatialRestrictions.isEmpty("geom");
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void isNotEmpty() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.isempty)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.getIsNotEmpty();
Criterion spatialCriterion = SpatialRestrictions.isNotEmpty("geom");
retrieveAndCompare(dbexpected, spatialCriterion);
}
public void havingSRID() throws SQLException {
if (!isSupportedByDialect(SpatialFunction.srid)) return;
Map<Integer, Boolean> dbexpected = expectationsFactory.havingSRID(4326);
Criterion spatialCriterion = SpatialRestrictions.havingSRID("geom", 4326);
retrieveAndCompare(dbexpected, spatialCriterion);
dbexpected = expectationsFactory.havingSRID(31370);
spatialCriterion = SpatialRestrictions.havingSRID("geom", 31370);
retrieveAndCompare(dbexpected, spatialCriterion);
}
private void retrieveAndCompare(Map<Integer, Boolean> dbexpected, Criterion spatialCriterion) {
Session session = null;
Transaction tx = null;
try {
session = openSession();
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(GeomEntity.class);
criteria.add(spatialCriterion);
compare(dbexpected, criteria.list());
} finally {
if (tx != null) tx.rollback();
if (session != null) session.close();
}
}
private void compare(Map<Integer, Boolean> dbexpected, List list) {
int cnt = 0;
for (Integer id : dbexpected.keySet()) {
if (dbexpected.get(id)) {
cnt++;
if (!findInList(id, (List<GeomEntity>) list))
fail(String.format("Expected object with id= %d, but not found in result", id));
}
}
assertEquals(cnt, list.size());
LOGGER.info(String.format("Found %d objects within testsuite-suite polygon.", cnt));
}
private boolean findInList(Integer id, List<GeomEntity> list) {
for (GeomEntity entity : list) {
if (entity.getId() == id) return true;
}
return false;
}
}

View File

@ -0,0 +1,173 @@
/*
* $Id: TestStoreRetrieve.java 242 2010-09-22 20:40:07Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.spatial.test.GeomEntity;
import org.hibernate.spatial.test.TestDataElement;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* This testsuite-suite class verifies whether the <code>Geometry</code>s retrieved
* are equal to the <code>Geometry</code>s stored.
*/
public class TestStoreRetrieve extends SpatialFunctionalTestCase {
private static Logger LOGGER = LoggerFactory.getLogger(TestStoreRetrieve.class);
protected Logger getLogger() {
return LOGGER;
}
@Test
public void testStoreRetrieve() throws ParseException {
Map<Integer, GeomEntity> stored = new HashMap<Integer, GeomEntity>();
//check whether we retrieve exactly what we store
storeTestObjects(stored);
retrieveAndCompare(stored);
deleteAllTestEntities();
//check if we can store null-geometries
storeNullGeometry();
//check if we can retrieve null-geometries
retrieveNullGeometry();
}
private void retrieveAndCompare(Map<Integer, GeomEntity> stored) {
int id = -1;
Transaction tx = null;
Session session = null;
try {
session = openSession();
tx = session.beginTransaction();
for (GeomEntity storedEntity : stored.values()) {
id = storedEntity.getId();
GeomEntity retrievedEntity = (GeomEntity) session.get(GeomEntity.class, id);
Geometry retrievedGeometry = retrievedEntity.getGeom();
Geometry storedGeometry = storedEntity.getGeom();
String msg = createFailureMessage(storedEntity.getId(), storedGeometry, retrievedGeometry);
assertTrue(msg, geometryEquality.test(storedGeometry, retrievedGeometry));
}
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
throw new RuntimeException(String.format("Failure on case: %d", id), e);
}
finally {
if (session != null) session.close();
}
}
private String createFailureMessage(int id, Geometry storedGeometry, Geometry retrievedGeometry) {
String expectedText = (storedGeometry != null ? storedGeometry.toText() : "NULL");
String retrievedText = (retrievedGeometry != null ? retrievedGeometry.toText() : "NULL");
return String.format("Equality testsuite-suite failed for %d.\nExpected: %s\nReceived:%s", id, expectedText, retrievedText);
}
private void storeTestObjects(Map<Integer, GeomEntity> stored) {
Session session = null;
Transaction tx = null;
int id = -1;
try {
session = openSession();
// Every testsuite-suite instance is committed seperately
// to improve feedback in case of failure
for (TestDataElement element : testData) {
id = element.id;
tx = session.beginTransaction();
GeomEntity entity = GeomEntity.createFrom(element);
stored.put(entity.getId(), entity);
session.save(entity);
tx.commit();
}
} catch (Exception e) {
if (tx != null) tx.rollback();
throw new RuntimeException("Failed storing testsuite-suite object with id:" + id, e);
} finally {
if (session != null) session.close();
}
}
private void storeNullGeometry() {
GeomEntity entity = null;
Session session = null;
Transaction tx = null;
try {
session = openSession();
tx = session.beginTransaction();
entity = new GeomEntity();
entity.setId(1);
entity.setType("NULL OBJECT");
session.save(entity);
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
throw new RuntimeException("Failed storing testsuite-suite object with id:" + entity.getId(), e);
} finally {
if (session != null) session.close();
}
}
private void retrieveNullGeometry() {
Transaction tx = null;
Session session = null;
try {
session = openSession();
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(GeomEntity.class);
List<GeomEntity> retrieved = criteria.list();
assertEquals("Expected exactly one result", 1, retrieved.size());
GeomEntity entity = retrieved.get(0);
assertNull(entity.getGeom());
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
throw new RuntimeException(e);
} finally {
if (session != null) session.close();
}
}
}

View File

@ -0,0 +1,62 @@
package org.hibernate.spatial;
import org.hibernate.dialect.Dialect;
import org.hibernate.spatial.test.TestSupport;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Sep 30, 2010
*/
public class TestSupportFactories {
private static TestSupportFactories instance = new TestSupportFactories();
public static TestSupportFactories instance() {
return instance;
}
private TestSupportFactories() {
}
public TestSupport getTestSupportFactory(Dialect dialect) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if (dialect == null) throw new IllegalArgumentException("Dialect argument is required.");
String testSupportFactoryClassName = getSupportFactoryClassName(dialect);
return instantiate(testSupportFactoryClassName);
}
private TestSupport instantiate(String testSupportFactoryClassName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ClassLoader cloader = getClassLoader();
Class<TestSupport> cl = (Class<TestSupport>) (cloader.loadClass(testSupportFactoryClassName));
return cl.newInstance();
}
private ClassLoader getClassLoader() {
return this.getClass().getClassLoader();
}
private static String getSupportFactoryClassName(Dialect dialect) {
String canonicalName = dialect.getClass().getCanonicalName();
if ("org.hibernate.spatial.dialect.postgis.PostgisDialect".equals(canonicalName)) {
return "org.hibernate.spatial.dialect.postgis.PostgisTestSupport";
}
// if ("org.hibernate.spatial.geodb.GeoDBDialect".equals(canonicalName)) {
// return "org.hibernate.spatial.geodb.GeoDBSupport";
// }
// if ("org.hibernatespatial.sqlserver.SQLServerSpatialDialect".equals(canonicalName)) {
// return "org.hibernatespatial.sqlserver.SQLServerTestSupport";
// }
// if ("org.hibernatespatial.mysql.MySQLSpatialDialect".equals(canonicalName) ||
// "org.hibernatespatial.mysql.MySQLSpatialInnoDBDialect".equals(canonicalName)) {
// return "org.hibernatespatial.mysql.MySQLTestSupport";
// }
// if ("org.hibernatespatial.oracle.OracleSpatial10gDialect".equals(canonicalName)) {
// return "org.hibernatespatial.oracle.OracleSDOTestSupport";
// }
throw new IllegalArgumentException("Dialect not known in test suite");
}
}

View File

@ -0,0 +1,30 @@
package org.hibernate.spatial.cfg;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class HSConfigurationTest {
@Test
public void testConfigureFailure() {
HSConfiguration config = new HSConfiguration();
config.configure("non-existing-file");
}
@Test
public void testConfigureFile() {
HSConfiguration config = new HSConfiguration();
config.configure("test.cfg.xml");
testResults(config);
}
private void testResults(HSConfiguration config) {
assertEquals("org.hibernate.spatial.postgis.PostgisDialect", config
.getDefaultDialect());
assertEquals("FIXED", config.getPrecisionModel());
assertEquals("5", config.getPrecisionModelScale());
}
}

View File

@ -0,0 +1,236 @@
/*
* $Id:$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.dialect.postgis;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import org.hibernate.spatial.test.AbstractExpectationsFactory;
import org.hibernate.spatial.test.DataSourceUtils;
import org.hibernate.spatial.test.NativeSQLStatement;
/**
* This class provides the expected return values to the testsuite-suite classes in this package.
*
* @author Karel Maesen, Geovise BVBA
*/
public class PostgisExpectationsFactory extends AbstractExpectationsFactory {
private final PGGeometryValueExtractor decoder = new PGGeometryValueExtractor();
public PostgisExpectationsFactory(DataSourceUtils utils) {
super(utils);
}
@Override
protected NativeSQLStatement createNativeTouchesStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_touches(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_touches(t.geom, ST_geomFromText(?, 4326)) = 'true' and st_srid(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeOverlapsStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_overlaps(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_overlaps(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeRelateStatement(Geometry geom, String matrix) {
String sql = "select t.id, st_relate(t.geom, ST_GeomFromText(?, 4326), '" + matrix + "' ) from GeomTest t where st_relate(t.geom, ST_GeomFromText(?, 4326), '" + matrix + "') = 'true' and ST_SRID(t.geom) = 4326";
return createNativeSQLStatementAllWKTParams(sql, geom.toText());
}
@Override
protected NativeSQLStatement createNativeDwithinStatement(Point geom, double distance) {
String sql = "select t.id, st_dwithin(t.geom, ST_GeomFromText(?, 4326), " + distance + " ) from GeomTest t where st_dwithin(t.geom, ST_GeomFromText(?, 4326), " + distance + ") = 'true' and ST_SRID(t.geom) = 4326";
return createNativeSQLStatementAllWKTParams(sql, geom.toText());
}
@Override
protected NativeSQLStatement createNativeIntersectsStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_intersects(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_intersects(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeFilterStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, t.geom && ST_GeomFromText(?, 4326) from GeomTest t where st_intersects(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeDistanceStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_distance(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeDimensionSQL() {
return createNativeSQLStatement("select id, st_dimension(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeBufferStatement(Double distance) {
return createNativeSQLStatement("select t.id, st_buffer(t.geom,?) from GeomTest t where ST_SRID(t.geom) = 4326", new Object[]{distance});
}
@Override
protected NativeSQLStatement createNativeConvexHullStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_convexhull(st_union(t.geom, ST_GeomFromText(?, 4326))) from GeomTest t where ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeIntersectionStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_intersection(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeDifferenceStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_difference(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeSymDifferenceStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_symdifference(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeGeomUnionStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_union(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeTransformStatement(int epsg) {
return createNativeSQLStatement(
"select t.id, st_transform(t.geom," + epsg + ") from GeomTest t where ST_SRID(t.geom) = 4326"
);
}
@Override
protected NativeSQLStatement createNativeHavingSRIDStatement(int srid) {
return createNativeSQLStatement("select t.id, (st_srid(t.geom) = " + srid + ") from GeomTest t where ST_SRID(t.geom) = " + srid);
}
@Override
protected NativeSQLStatement createNativeAsTextStatement() {
return createNativeSQLStatement("select id, st_astext(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeSridStatement() {
return createNativeSQLStatement("select id, ST_SRID(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeIsSimpleStatement() {
return createNativeSQLStatement("select id, st_issimple(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeIsEmptyStatement() {
return createNativeSQLStatement("select id, st_isempty(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeIsNotEmptyStatement() {
return createNativeSQLStatement("select id, not st_isempty(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeBoundaryStatement() {
return createNativeSQLStatement("select id, st_boundary(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeEnvelopeStatement() {
return createNativeSQLStatement("select id, st_envelope(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeAsBinaryStatement() {
return createNativeSQLStatement("select id, st_asbinary(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeGeometryTypeStatement() {
return createNativeSQLStatement("select id, st_GeometryType(geom) from geomtest");
}
@Override
protected NativeSQLStatement createNativeWithinStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_within(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_within(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeEqualsStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_equals(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_equals(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeCrossesStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_crosses(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_crosses(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeContainsStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_contains(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_contains(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) {
return createNativeSQLStatementAllWKTParams(
"select t.id, st_disjoint(t.geom, ST_GeomFromText(?, 4326)) from GeomTest t where st_disjoint(t.geom, ST_GeomFromText(?, 4326)) = 'true' and ST_SRID(t.geom) = 4326",
geom.toText());
}
@Override
protected Geometry decode(Object o) {
return decoder.toJTS(o);
}
}

View File

@ -0,0 +1,43 @@
/*
* $Id:$
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.dialect.postgis;
import org.hibernate.spatial.test.SQLExpressionTemplate;
import org.hibernate.spatial.test.TestDataElement;
/**
* The template for postgis insert SQL
*
* @Author Karel Maesen, Geovise BVBA
*/
public class PostgisExpressionTemplate implements SQLExpressionTemplate {
final String SQL_TEMPLATE = "insert into geomtest values (%d, '%s', GeomFromText('%s', %d))";
public String toInsertSql(TestDataElement testDataElement) {
return String.format(SQL_TEMPLATE, testDataElement.id, testDataElement.type, testDataElement.wkt, testDataElement.srid);
}
}

View File

@ -0,0 +1,32 @@
package org.hibernate.spatial.dialect.postgis;
import org.hibernate.spatial.test.*;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Sep 30, 2010
*/
public class PostgisTestSupport extends TestSupport {
public TestData createTestData(BaseCoreFunctionalTestCase testcase) {
if (testcase.getClass().getCanonicalName().contains("TestSpatialFunctions") ||
testcase.getClass().getCanonicalName().contains("TestSpatialRestrictions")) {
return TestData.fromFile("postgis-functions-test.xml");
}
return TestData.fromFile("test-data-set.xml");
}
public AbstractExpectationsFactory createExpectationsFactory(DataSourceUtils dataSourceUtils) {
return new PostgisExpectationsFactory(dataSourceUtils);
}
@Override
public SQLExpressionTemplate getSQLExpressionTemplate() {
return new org.hibernate.spatial.dialect.postgis.PostgisExpressionTemplate();
}
}

View File

@ -0,0 +1,25 @@
package org.hibernate.spatial.dialect.postgis.unittests;
import junit.framework.TestCase;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.SpatialFunction;
import org.hibernate.spatial.dialect.postgis.PostgisDialect;
import org.junit.Test;
/**
* Tests support for
*
* @author Karel Maesen, Geovise BVBA
* creation-date: 1/19/11
*/
public class PostgisDialectTest extends TestCase {
SpatialDialect dialect = new PostgisDialect();
@Test
public void testSupports() throws Exception {
for (SpatialFunction sf : SpatialFunction.values()) {
assertTrue("Dialect doesn't support " + sf, dialect.supports(sf));
}
}
}

View File

@ -0,0 +1,803 @@
/*
* $Id: AbstractExpectationsFactory.java 287 2011-02-15 21:30:01Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
/**
* An <code>AbstractExpectationsFactory</code> provides the expected
* values to be used in the unit tests of the spatial functions
* provided by specific providers.
* <p/>
* The expected values are returned as a map of (identifier, expected value) pairs.
*
* @author Karel Maesen, Geovise BVBA
*/
public abstract class AbstractExpectationsFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractExpectationsFactory.class);
public final static String TEST_POLYGON_WKT = "POLYGON((0 0, 50 0, 100 100, 0 100, 0 0))";
public final static String TEST_POINT_WKT = "POINT(0 0)";
public final static int INTEGER = 1;
public final static int DOUBLE = 2;
public final static int GEOMETRY = 3;
public final static int STRING = 4;
public final static int BOOLEAN = 5;
public final static int OBJECT = -1;
private final static int TEST_SRID = 4326;
private final DataSourceUtils dataSourceUtils;
private static final int MAX_BYTE_LEN = 1024;
public AbstractExpectationsFactory(DataSourceUtils dataSourceUtils) {
this.dataSourceUtils = dataSourceUtils;
}
protected DataSourceUtils getDataSourceUtils() {
return this.dataSourceUtils;
}
/**
* Returns the SRID in which all tests are conducted. This is for now 4326;
*
* @return
*/
public int getTestSrid() {
return TEST_SRID;
}
/**
* Returns the expected dimensions of all testsuite-suite geometries.
*
* @return map of identifier, dimension
* @throws SQLException
*/
public Map<Integer, Integer> getDimension() throws SQLException {
return retrieveExpected(createNativeDimensionSQL(), INTEGER);
}
/**
* Returns the expected WKT of all testsuite-suite geometries.
*
* @return map of identifier, WKT-string
* @throws SQLException
*/
public Map<Integer, String> getAsText() throws SQLException {
return retrieveExpected(createNativeAsTextStatement(), STRING);
}
/**
* Returns the expected WKB representations of all testsuite-suite geometries
*
* @return map of identifier, WKB representation
* @throws SQLException
*/
public Map<Integer, byte[]> getAsBinary() throws SQLException {
return retrieveExpected(createNativeAsBinaryStatement(), OBJECT);
}
/**
* Returns the expected type names of all testsuite-suite geometries
*
* @return map of identifier, type name
* @throws SQLException
*/
public Map<Integer, String> getGeometryType() throws SQLException {
return retrieveExpected(createNativeGeometryTypeStatement(), STRING);
}
/**
* Returns the expected SRID codes of all testsuite-suite geometries
*
* @return map of identifier, SRID
* @throws SQLException
*/
public Map<Integer, Integer> getSrid() throws SQLException {
return retrieveExpected(createNativeSridStatement(), INTEGER);
}
/**
* Returns whether the testsuite-suite geometries are simple
*
* @return map of identifier and whether testsuite-suite geometry is simple
* @throws SQLException
*/
public Map<Integer, Boolean> getIsSimple() throws SQLException {
return retrieveExpected(createNativeIsSimpleStatement(), BOOLEAN);
}
/**
* Returns whether the testsuite-suite geometries are empty
*
* @return map of identifier and whether testsuite-suite geometry is empty
* @throws SQLException
*/
public Map<Integer, Boolean> getIsEmpty() throws SQLException {
return retrieveExpected(createNativeIsEmptyStatement(), BOOLEAN);
}
/**
* Returns whether the testsuite-suite geometries are empty
*
* @return map of identifier and whether testsuite-suite geometry is empty
* @throws SQLException
*/
public Map<Integer, Boolean> getIsNotEmpty() throws SQLException {
return retrieveExpected(createNativeIsNotEmptyStatement(), BOOLEAN);
}
/**
* Returns the expected boundaries of all testsuite-suite geometries
*
* @return map of identifier and boundary geometry
* @throws SQLException
*/
public Map<Integer, Geometry> getBoundary() throws SQLException {
return retrieveExpected(createNativeBoundaryStatement(), GEOMETRY);
}
/**
* Returns the expected envelopes of all testsuite-suite geometries
*
* @return map of identifier and envelope
* @throws SQLException
*/
public Map<Integer, Geometry> getEnvelope() throws SQLException {
return retrieveExpected(createNativeEnvelopeStatement(), GEOMETRY);
}
/**
* Returns the expected results of the within operator
*
* @param geom testsuite-suite geometry
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getWithin(Geometry geom) throws SQLException {
return retrieveExpected(createNativeWithinStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the equals operator
*
* @param geom
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getEquals(Geometry geom) throws SQLException {
return retrieveExpected(createNativeEqualsStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the crosses operator
*
* @param geom
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getCrosses(Geometry geom) throws SQLException {
return retrieveExpected(createNativeCrossesStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the contains operator
*/
public Map<Integer, Boolean> getContains(Geometry geom) throws SQLException {
return retrieveExpected(createNativeContainsStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the disjoint operator
*
* @param geom
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getDisjoint(Geometry geom) throws SQLException {
return retrieveExpected(createNativeDisjointStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the intersects operator
*
* @param geom
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getIntersects(Geometry geom) throws SQLException {
return retrieveExpected(createNativeIntersectsStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the touches operator
*
* @param geom
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getTouches(Geometry geom) throws SQLException {
return retrieveExpected(createNativeTouchesStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the overlaps operator
*
* @param geom
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getOverlaps(Geometry geom) throws SQLException {
return retrieveExpected(createNativeOverlapsStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the DWithin operator
*
* @param geom
* @param distance
* @return
*/
public Map<Integer, Boolean> getDwithin(Point geom, double distance) throws SQLException {
return retrieveExpected(createNativeDwithinStatement(geom, distance), BOOLEAN);
}
/**
* Returns the expected result of the havingSRID operator
*
* @param srid the SRID (EPSG code)
* @return
*/
public Map<Integer, Boolean> havingSRID(int srid) throws SQLException {
return retrieveExpected(createNativeHavingSRIDStatement(srid), BOOLEAN);
}
/**
* Returns the expected results of the relate operator
*
* @param geom
* @param matrix
* @return
* @throws SQLException
*/
public Map<Integer, Boolean> getRelate(Geometry geom, String matrix) throws SQLException {
return retrieveExpected(createNativeRelateStatement(geom, matrix), BOOLEAN);
}
/**
* Returns the expected results for the geometry filter
*
* @param geom filter Geometry
* @return
*/
public Map<Integer, Boolean> getFilter(Geometry geom) throws SQLException {
return retrieveExpected(createNativeFilterStatement(geom), BOOLEAN);
}
/**
* Returns the expected results of the distance function
*
* @param geom geometry parameter to distance function
* @return
* @throws SQLException
*/
public Map<Integer, Double> getDistance(Geometry geom) throws SQLException {
return retrieveExpected(createNativeDistanceStatement(geom), DOUBLE);
}
/**
* Returns the expected results of the buffering function
*
* @param distance distance parameter to the buffer function
* @return
* @throws SQLException
*/
public Map<Integer, Geometry> getBuffer(Double distance) throws SQLException {
return retrieveExpected(createNativeBufferStatement(distance), GEOMETRY);
}
/**
* Returns the expected results of the convexhull function
*
* @param geom geometry with which each testsuite-suite geometry is unioned before convexhull calculation
* @return
* @throws SQLException
*/
public Map<Integer, Geometry> getConvexHull(Geometry geom) throws SQLException {
return retrieveExpected(createNativeConvexHullStatement(geom), GEOMETRY);
}
/**
* Returns the expected results of the intersection function
*
* @param geom parameter to the intersection function
* @return
* @throws SQLException
*/
public Map<Integer, Geometry> getIntersection(Geometry geom) throws SQLException {
return retrieveExpected(createNativeIntersectionStatement(geom), GEOMETRY);
}
/**
* Returns the expected results of the difference function
*
* @param geom parameter to the difference function
* @return
* @throws SQLException
*/
public Map<Integer, Geometry> getDifference(Geometry geom) throws SQLException {
return retrieveExpected(createNativeDifferenceStatement(geom), GEOMETRY);
}
/**
* Returns the expected results of the symdifference function
*
* @param geom parameter to the symdifference function
* @return
* @throws SQLException
*/
public Map<Integer, Geometry> getSymDifference(Geometry geom) throws SQLException {
return retrieveExpected(createNativeSymDifferenceStatement(geom), GEOMETRY);
}
/**
* Returns the expected results of the geomunion function
*
* @param geom parameter to the geomunion function
* @return
* @throws SQLException
*/
public Map<Integer, Geometry> getGeomUnion(Geometry geom) throws SQLException {
return retrieveExpected(createNativeGeomUnionStatement(geom), GEOMETRY);
}
/**
* Returns the expected result of the transform function
*
* @param epsg
* @return
* @throws SQLException
*/
public Map<Integer, Geometry> getTransform(int epsg) throws SQLException {
return retrieveExpected(createNativeTransformStatement(epsg), GEOMETRY);
}
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, touches(geom, :filter) from GeomEntity where touches(geom, :filter) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeTouchesStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, overlaps(geom, :filter) from GeomEntity where overlaps(geom, :filter) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeOverlapsStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, relate(geom, :filter, :matrix) from GeomEntity where relate(geom, :filter, :matrix) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @param matrix the string corresponding to the ':matrix' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeRelateStatement(Geometry geom, String matrix);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, dwithin(geom, :filter, :distance) from GeomEntity where dwithin(geom, :filter, :distance) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @param distance the string corresponding to the ':distance' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeDwithinStatement(Point geom, double distance);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, intersects(geom, :filter) from GeomEntity where intersects(geom, :filter) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeIntersectsStatement(Geometry geom);
/**
* Returns the statement corresponding to the SpatialRestrictions.filter() method.
*
* @param geom filter geometry
* @return
*/
protected abstract NativeSQLStatement createNativeFilterStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, distance(geom, :filter) from GeomEntity where srid(geom) = 4326"
*
* @param geom
* @return
*/
protected abstract NativeSQLStatement createNativeDistanceStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "select id, dimension(geom) from GeomEntity".
*
* @return the SQL String
*/
protected abstract NativeSQLStatement createNativeDimensionSQL();
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, buffer(geom, :distance) from GeomEntity where srid(geom) = 4326"
*
* @param distance parameter corresponding to the ':distance' query parameter
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeBufferStatement(Double distance);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, convexhull(geomunion(geom, :polygon)) from GeomEntity where srid(geom) = 4326"
*
* @param geom parameter corresponding to the ':polygon' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeConvexHullStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, intersection(geom, :polygon) from GeomEntity where srid(geom) = 4326"
*
* @param geom parameter corresponding to the ':polygon' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeIntersectionStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, difference(geom, :polygon) from GeomEntity where srid(geom) = 4326"26"
*
* @param geom parameter corresponding to the ':polygon' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeDifferenceStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, symdifference(geom, :polygon) from GeomEntity where srid(geom) = 4326"26"
*
* @param geom parameter corresponding to the ':polygon' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeSymDifferenceStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, geomunion(geom, :polygon) from GeomEntity where srid(geom) = 4326"26"
*
* @param geom parameter corresponding to the ':polygon' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeGeomUnionStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "select id, astext(geom) from GeomEntity".
*
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeAsTextStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id, srid(geom) from GeomEntity".
*
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeSridStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id, issimple(geom) from GeomEntity".
*
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeIsSimpleStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id, isempty(geom) from GeomEntity".
*
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeIsEmptyStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id,not isempty(geom) from GeomEntity".
*
* @return
*/
protected abstract NativeSQLStatement createNativeIsNotEmptyStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id, boundary(geom) from GeomEntity".
*
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeBoundaryStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id, envelope(geom) from GeomEntity".
*
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeEnvelopeStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id, asbinary(geom) from GeomEntity".
*
* @return the native SQL Statement
*/
protected abstract NativeSQLStatement createNativeAsBinaryStatement();
/**
* Returns a statement corresponding to the HQL statement:
* "select id, geometrytype(geom) from GeomEntity".
*
* @return the SQL String
*/
protected abstract NativeSQLStatement createNativeGeometryTypeStatement();
/**
* Returns a statement corresponding to the HQL statement
* "SELECT id, within(geom, :filter) from GeomEntity where within(geom, :filter) = true and srid(geom) = 4326"
*
* @param testPolygon the geometry corresponding to the ':filter' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeWithinStatement(Geometry testPolygon);
/**
* Returns a statement corresponding to the HQL statement
* "SELECT id, equals(geom, :filter) from GeomEntity where equals(geom, :filter) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeEqualsStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement
* "SELECT id, crosses(geom, :filter) from GeomEntity where crosses(geom, :filter) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeCrossesStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement:
* "SELECT id, contains(geom, :filter) from GeomEntity where contains(geom, :geom) = true and srid(geom) = 4326";
*
* @param geom
* @return
*/
protected abstract NativeSQLStatement createNativeContainsStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement
* "SELECT id, disjoint(geom, :filter) from GeomEntity where disjoint(geom, :filter) = true and srid(geom) = 4326"
*
* @param geom the geometry corresponding to the ':filter' query parameter
* @return
*/
protected abstract NativeSQLStatement createNativeDisjointStatement(Geometry geom);
/**
* Returns a statement corresponding to the HQL statement
* "SELECT id, transform(geom, :epsg) from GeomEntity where srid(geom) = 4326"
*
* @param epsg - the EPSG code of the target projection system.
* @return
*/
protected abstract NativeSQLStatement createNativeTransformStatement(int epsg);
/**
* Returns the statement corresponding to the HQL statement
* "select id, (srid(geom) = :epsg) from GeomEntity where srid(geom) = :epsg ";
*
* @param srid
* @return
*/
protected abstract NativeSQLStatement createNativeHavingSRIDStatement(int srid);
/**
* Creates a connection to the database
*
* @return a Connection
* @throws SQLException
*/
protected Connection createConnection() throws SQLException {
return this.dataSourceUtils.getConnection();
}
/**
* Decodes a native database object to a JTS <code>Geometry</code> instance
*
* @param o native database object
* @return decoded geometry
*/
protected abstract Geometry decode(Object o);
/**
* Return a testsuite-suite polygon (filter, ...)
*
* @return a testsuite-suite polygon
*/
public Polygon getTestPolygon() {
WKTReader reader = new WKTReader();
try {
Polygon polygon = (Polygon) reader.read(TEST_POLYGON_WKT);
polygon.setSRID(getTestSrid());
return polygon;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* Return a testsuite-suite point (filter, ...)
*
* @return a testsuite-suite point
*/
public Point getTestPoint() {
WKTReader reader = new WKTReader();
try {
Point point = (Point) reader.read(TEST_POINT_WKT);
point.setSRID(getTestSrid());
return point;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
protected <T> Map<Integer, T> retrieveExpected(NativeSQLStatement nativeSQLStatement, int type) throws SQLException {
PreparedStatement preparedStatement = null;
Connection cn = null;
Map<Integer, T> expected = new HashMap<Integer, T>();
try {
cn = createConnection();
preparedStatement = nativeSQLStatement.prepare(cn);
LOGGER.info("Native SQL is: " + preparedStatement.toString());
ResultSet results = preparedStatement.executeQuery();
while (results.next()) {
int id = results.getInt(1);
switch (type) {
case GEOMETRY:
expected.put(id, (T) decode(results.getObject(2)));
break;
case STRING:
expected.put(id, (T) results.getString(2));
break;
case INTEGER:
expected.put(id, (T) Long.valueOf(results.getLong(2)));
break;
case DOUBLE:
Double value = Double.valueOf(results.getDouble(2));
if (results.wasNull())
value = null; //this is required because SQL Server converts automatically null to 0.0
expected.put(id, (T) value);
break;
case BOOLEAN:
expected.put(id, (T) Boolean.valueOf(results.getBoolean(2)));
break;
default:
T val = (T) results.getObject(2);
//this code is a hack to deal with Oracle Spatial that returns Blob's for asWKB() function
//TODO -- clean up
if (val instanceof Blob) {
val = (T) ((Blob) val).getBytes(1, MAX_BYTE_LEN);
}
expected.put(id, val);
}
}
return expected;
} finally {
if (preparedStatement != null) preparedStatement.close();
if (cn != null) cn.close();
}
}
protected NativeSQLStatement createNativeSQLStatement(final String sql) {
return new NativeSQLStatement() {
public PreparedStatement prepare(Connection connection) throws SQLException {
return connection.prepareStatement(sql);
}
};
}
protected NativeSQLStatement createNativeSQLStatementAllWKTParams(final String sql, final String wkt) {
return new NativeSQLStatement() {
public PreparedStatement prepare(Connection connection) throws SQLException {
PreparedStatement pstmt = connection.prepareStatement(sql);
for (int i = 1; i <= numPlaceHoldersInSQL(sql); i++) {
pstmt.setString(i, wkt);
}
return pstmt;
}
};
}
protected NativeSQLStatement createNativeSQLStatement(final String sql, final Object[] params) {
return new NativeSQLStatement() {
public PreparedStatement prepare(Connection connection) throws SQLException {
PreparedStatement pstmt = connection.prepareStatement(sql);
int i = 1;
for (Object param : params) {
pstmt.setObject(i++, param);
}
return pstmt;
}
};
}
protected int numPlaceHoldersInSQL(String sql) {
return sql.replaceAll("[^?]", "").length();
}
}

View File

@ -0,0 +1,343 @@
/*
* $Id: DataSourceUtils.java 287 2011-02-15 21:30:01Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernate.spatial.org/
*/
package org.hibernate.spatial.test;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import org.apache.commons.dbcp.BasicDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.io.*;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* <p>Unit testsuite-suite support class.</p>
*
* @author Karel Maesen, Geovise BVBA.
*/
public class DataSourceUtils {
private static Logger LOGGER = LoggerFactory.getLogger(DataSourceUtils.class);
private final SQLExpressionTemplate sqlExpressionTemplate;
private final String jdbcDriver;
private final String jdbcUrl;
private final String jdbcUser;
private final String jdbcPass;
private DataSource dataSource;
/**
* Constructor for the DataSourceUtils object.
* <p/>
* <p>The following entities are required in the property file:
* <il>
* <li> jdbcUrl: jdbc connection URL</li>
* <li> dbUsername: username for the database</li>
* <li> dbPassword: password for the database</li>
* <li> driver: fully-qualified class name for the JDBC Driver</li>
* </il>
*
* @param jdbcDriver
* @param jdbcUrl
* @param jdbcUser
* @param jdbcPass
* @param sqlExpressionTemplate SQLExpressionTemplate object that generates SQL statements for this database
*/
public DataSourceUtils(String jdbcDriver, String jdbcUrl, String jdbcUser, String jdbcPass, SQLExpressionTemplate sqlExpressionTemplate) {
this.jdbcDriver = jdbcDriver;
this.jdbcUrl = jdbcUrl;
this.jdbcUser = jdbcUser;
this.jdbcPass = jdbcPass;
this.sqlExpressionTemplate = sqlExpressionTemplate;
createBasicDataSource();
}
/**
* Constructor using a properties file
*
* @param propertyFile
* @param template
*/
public DataSourceUtils(String propertyFile, SQLExpressionTemplate template) {
Properties properties = readProperties(propertyFile);
this.jdbcUrl = properties.getProperty("jdbcUrl");
this.jdbcDriver = properties.getProperty("jdbcDriver");
this.jdbcUser = properties.getProperty("jdbcUser");
this.jdbcPass = properties.getProperty("jdbcPass");
this.sqlExpressionTemplate = template;
createBasicDataSource();
}
private Properties readProperties(String propertyFile) {
InputStream is = null;
try {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(propertyFile);
if (is == null) throw new RuntimeException(String.format("File %s not found on classpath.", propertyFile));
Properties properties = new Properties();
properties.load(is);
return properties;
} catch (IOException e) {
throw (new RuntimeException(e));
} finally {
if (is != null) try {
is.close();
} catch (IOException e) {
//nothing to do
}
}
}
private void createBasicDataSource() {
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName(jdbcDriver);
bds.setUrl(jdbcUrl);
bds.setUsername(jdbcUser);
bds.setPassword(jdbcPass);
dataSource = bds;
}
/**
* Closes the connections to the database.
*
* @throws SQLException
*/
public void close() throws SQLException {
((BasicDataSource) dataSource).close();
}
/**
* Returns a DataSource for the configured database.
*
* @return a DataSource
*/
public DataSource getDataSource() {
return dataSource;
}
/**
* Returns a JDBC connection to the database
*
* @return a JDBC Connection object
* @throws SQLException
*/
public Connection getConnection() throws SQLException {
Connection cn = getDataSource().getConnection();
cn.setAutoCommit(false);
return cn;
}
/**
* Delete all testsuite-suite data from the database
*
* @throws SQLException
*/
public void deleteTestData() throws SQLException {
Connection cn = null;
try {
cn = getDataSource().getConnection();
cn.setAutoCommit(false);
PreparedStatement pmt = cn.prepareStatement("delete from GEOMTEST");
if (!pmt.execute()) {
int updateCount = pmt.getUpdateCount();
LOGGER.info("Removing " + updateCount + " rows.");
}
cn.commit();
pmt.close();
} finally {
try {
if (cn != null) cn.close();
} catch (SQLException e) {
// nothing to do
}
}
}
public void insertTestData(TestData testData) throws SQLException {
Connection cn = null;
try {
cn = getDataSource().getConnection();
cn.setAutoCommit(false);
Statement stmt = cn.createStatement();
for (TestDataElement testDataElement : testData) {
String sql = sqlExpressionTemplate.toInsertSql(testDataElement);
LOGGER.debug("adding stmt: " + sql);
stmt.addBatch(sql);
}
int[] insCounts = stmt.executeBatch();
cn.commit();
stmt.close();
LOGGER.info("Loaded " + sum(insCounts) + " rows.");
} finally {
try {
if (cn != null) cn.close();
} catch (SQLException e) {
// nothing to do
}
}
}
/**
* Parses the content of a file into an executable SQL statement.
*
* @param fileName name of a file containing SQL-statements
* @return
* @throws IOException
*/
public String parseSqlIn(String fileName) throws IOException {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
if (is == null) {
throw new RuntimeException("File " + fileName + " not found on Classpath.");
}
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(is));
StringWriter sw = new StringWriter();
BufferedWriter writer = new BufferedWriter(sw);
for (int c = reader.read(); c != -1; c = reader.read()) {
writer.write(c);
}
writer.flush();
return sw.toString();
} finally {
if (is != null) {
is.close();
}
}
}
/**
* Executes a SQL statement.
* <p/>
* This is used e.g. to drop/create a spatial index, or update the
* geometry metadata statements.
*
* @param sql the (native) SQL Statement to execute
* @throws SQLException
*/
public void executeStatement(String sql) throws SQLException {
Connection cn = null;
try {
cn = getDataSource().getConnection();
cn.setAutoCommit(false);
PreparedStatement statement = cn.prepareStatement(sql);
LOGGER.info("Executing statement: " + sql);
statement.execute();
cn.commit();
statement.close();
} finally {
try {
if (cn != null) cn.close();
} catch (SQLException e) {
} //do nothing.
}
}
/**
* Operations to fully initialize the
*/
public void afterCreateSchema() {
}
/**
* Return the geometries of the testsuite-suite objects as raw (i.e. undecoded) objects from the database.
*
* @param type type of geometry
* @return map of identifier, undecoded geometry object
*/
public Map<Integer, Object> rawDbObjects(String type) {
Map<Integer, Object> map = new HashMap<Integer, Object>();
Connection cn = null;
try {
cn = getDataSource().getConnection();
PreparedStatement pstmt = cn.prepareStatement("select id, geom from geomtest where type = ? order by id");
pstmt.setString(1, type);
ResultSet results = pstmt.executeQuery();
while (results.next()) {
Integer id = results.getInt(1);
Object obj = results.getObject(2);
map.put(id, obj);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (cn != null) cn.close();
} catch (SQLException e) {
// nothing we can do.
}
}
return map;
}
/**
* Returns the JTS geometries that are expected of a decoding of the testsuite-suite object's geometry.
* <p/>
* <p>This method reads the WKT of the testsuite-suite objects and returns the result.</p>
*
* @param type type of geometry
* @return map of identifier and JTS geometry
*/
public Map<Integer, Geometry> expectedGeoms(String type, TestData testData) {
Map<Integer, Geometry> result = new HashMap<Integer, Geometry>();
EWKTReader parser = new EWKTReader();
for (TestDataElement testDataElement : testData) {
if (testDataElement.type.equalsIgnoreCase(type)) {
try {
result.put(testDataElement.id, parser.read(testDataElement.wkt));
} catch (ParseException e) {
System.out.println(String.format("Parsing WKT fails for case %d : %s", testDataElement.id, testDataElement.wkt));
throw new RuntimeException(e);
}
}
}
return result;
}
private static int sum(int[] insCounts) {
int result = 0;
for (int idx = 0; idx < insCounts.length; idx++) {
result += insCounts[idx];
}
return result;
}
}

View File

@ -0,0 +1,834 @@
/*
* $Id: EWKTReader.java 166 2010-03-11 22:17:49Z maesenka $
*
* This file is an adapted version of the JTS WKTReader. It has
* been extended by Martin Steinwender to deal with Measured coordinates.
*
* Original copyright notice:
*
* The JTS Topology Suite is a collection of Java classes that
* implement the fundamental operations required to validate a given
* geo-spatial data set to a known topological specification.
*
* Copyright (C) 2001 Vivid Solutions
*
* 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
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package org.hibernate.spatial.test;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.util.Assert;
import org.hibernate.spatial.mgeom.MCoordinate;
import org.hibernate.spatial.mgeom.MGeometryFactory;
import org.hibernate.spatial.mgeom.MLineString;
import java.io.IOException;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.util.ArrayList;
/**
* 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 &lt;Geometry Tagged Text&gt;.
* @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 &lt;Point Text&gt;.
* @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 &lt;LineString Text&gt;.
* @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 &lt;LineString Text&gt;.
* @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 &lt;MultiPoint Text&gt;.
* @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 &lt;Polygon Text&gt;.
* @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 &lt;MultiLineString Text&gt;.
* @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 &lt;MultiPolygon Text&gt;.
* @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 &lt;GeometryCollection Text&gt;.
* @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));
}
}

View File

@ -0,0 +1,93 @@
/*
* $Id: GeomEntity.java 253 2010-10-02 15:14:52Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
/**
* Test class used in unit testing.
*/
public class GeomEntity implements TestFeature {
private Integer id;
private String type;
private Geometry geom;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Geometry getGeom() {
return geom;
}
public void setGeom(Geometry geom) {
this.geom = geom;
}
public static GeomEntity createFrom(TestDataElement element) throws ParseException {
EWKTReader reader = new EWKTReader();
GeomEntity result = new GeomEntity();
result.setId(element.id);
Geometry geom = reader.read(element.wkt);
geom.setSRID(element.srid);
result.setGeom(geom);
result.setType(element.type);
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GeomEntity geomEntity = (GeomEntity) o;
if (id != geomEntity.id) return false;
return true;
}
@Override
public int hashCode() {
return id;
}
}

View File

@ -0,0 +1,96 @@
/*
* $Id: GeometryEquality.java 271 2010-12-16 22:00:24Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import org.hibernate.spatial.mgeom.MCoordinate;
/**
* This class tests for the equality between geometries.
* <p/>
* The notion of geometric equality can differ slightly between
* spatial databases.
*/
public class GeometryEquality {
public boolean test(Geometry geom1, Geometry geom2) {
if (geom1 == null) return geom2 == null;
if (geom1.isEmpty()) return geom2.isEmpty() && geom1.getSRID() == geom2.getSRID();
if (geom1 instanceof GeometryCollection) {
if (!(geom2 instanceof GeometryCollection)) return false;
GeometryCollection expectedCollection = (GeometryCollection) geom1;
GeometryCollection receivedCollection = (GeometryCollection) geom2;
for (int partIndex = 0; partIndex < expectedCollection.getNumGeometries(); partIndex++) {
Geometry partExpected = expectedCollection.getGeometryN(partIndex);
Geometry partReceived = receivedCollection.getGeometryN(partIndex);
if (!test(partExpected, partReceived)) return false;
}
return true;
} else {
return testSimpleGeometryEquality(geom1, geom2);
}
}
/**
* Test whether two geometries, not of type GeometryCollection are equal.
*
* @param geom1
* @param geom2
* @return
*/
protected boolean testSimpleGeometryEquality(Geometry geom1, Geometry geom2) {
//return geom1.equals(geom2);
return testTypeAndVertexEquality(geom1, geom2) && geom1.getSRID() == geom2.getSRID();
}
protected boolean testTypeAndVertexEquality(Geometry geom1, Geometry geom2) {
if (!geom1.getGeometryType().equals(geom2.getGeometryType())) return false;
if (geom1.getNumGeometries() != geom2.getNumGeometries()) return false;
if (geom1.getNumPoints() != geom2.getNumPoints()) return false;
Coordinate[] coordinates1 = geom1.getCoordinates();
Coordinate[] coordinates2 = geom2.getCoordinates();
for (int i = 0; i < coordinates1.length; i++) {
Coordinate c1 = coordinates1[i];
Coordinate c2 = coordinates2[i];
if (!testCoordinateEquality(c1, c2)) return false;
}
return true;
}
private boolean testCoordinateEquality(Coordinate c1, Coordinate c2) {
if (c1 instanceof MCoordinate) {
if (!(c2 instanceof MCoordinate)) return false;
MCoordinate mc1 = (MCoordinate) c1;
MCoordinate mc2 = (MCoordinate) c2;
if (!Double.isNaN(mc1.m) && mc1.m != mc2.m) return false;
}
if (!Double.isNaN(c1.z) && c1.z != c2.z) return false;
return c1.x == c2.x && c1.y == c2.y;
}
}

View File

@ -0,0 +1,49 @@
/*
* $Id: NativeSQLStatement.java 166 2010-03-11 22:17:49Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* <code>NativeSQLStatement</code>s can instantiate a
* database-specific <code>PreparedStatement</code> for
* some database query or operation.
*
* @author Karel Maesen, Geovise BVBA
*/
public interface NativeSQLStatement {
/**
* create a PreparedStatement from the specified connection
*
* @param connection Connection to the database.
* @return
* @throws SQLException
*/
public PreparedStatement prepare(Connection connection) throws SQLException;
}

View File

@ -0,0 +1,44 @@
/*
* $Id: SQLExpressionTemplate.java 225 2010-06-25 21:59:05Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
/**
* <code>SQLExpressoinTemplate</code>s generate database-specific
* SQL statements for a given <code>TestDataElement</code> instance.
*
* @author Karel Maesen, Geovise BVBA
*/
public interface SQLExpressionTemplate {
/**
* Returns an insert SQL statement for the specified <code>TestDataElement</code>
*
* @param testDataElement
* @return an insert SQL for testDataElement
*/
public String toInsertSql(TestDataElement testDataElement);
}

View File

@ -0,0 +1,196 @@
/**
* $Id: TestCircle.java 274 2010-12-18 14:02:06Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
import com.vividsolutions.jts.geom.Coordinate;
import org.hibernate.spatial.Circle;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test functionality of Circle class Date: Oct 15, 2007
*
* @author Tom Acree
*/
public class TestCircle {
@Test
public void testCreateCircle() {
Coordinate center = (new Coordinate(0, 0));
double radius = 5;
Coordinate p1 = new Coordinate(3, 4);
Coordinate p2 = new Coordinate(0, 5);
Coordinate p3 = new Coordinate(-3, 4);
Circle c0 = new Circle(center, radius);
Circle c1 = new Circle(p1, p2, p3);
assertEquals(c0, c1);
assertTrue(Double.compare(c1.getRadius(), radius) == 0);
assertTrue(c1.getCenter().equals2D(center));
double distance = c1.distanceFromCenter(p3);
assertTrue(Double.compare(c1.getRadius(), distance) == 0);
}
@Test
public void testNormalize() {
double actual, expected = 0;
double angleIncr = Math.PI / 4; // increment by 45 degrees
double twoPi = Math.PI * 2;
int factor = 8;
for (int i = 0; i <= factor; i++) {
expected = i * angleIncr;
actual = (Circle.normalizeAngle(expected));
assertEquals(actual, expected, Math.ulp(expected));
double degrees = Math.toDegrees(actual);
assertTrue(actual <= twoPi);
assertTrue(degrees <= 360);
}
factor = -8;
double testAngle;
for (int i = -1; i >= factor; i--) {
testAngle = i * angleIncr;
expected = twoPi + (i * angleIncr);
actual = (Circle.normalizeAngle(testAngle));
assertEquals(actual, expected, Math.ulp(expected));
double degrees = Math.toDegrees(actual);
assertTrue(actual <= Math.PI * 2);
assertTrue(degrees <= 360);
}
// couple extra boundary cases
expected = 0;
actual = Circle.normalizeAngle(twoPi * 8);
assertEquals(expected, actual, Math.ulp(expected));
testAngle = angleIncr + twoPi;
expected = angleIncr;
actual = Circle.normalizeAngle(testAngle);
assertEquals(expected, actual, Math.ulp(expected));
testAngle = angleIncr - twoPi;
expected = angleIncr;
actual = Circle.normalizeAngle(testAngle);
assertEquals(expected, actual, Math.ulp(expected));
}
@Test
public void testAngleDifference() {
double a1 = Math.PI / 8;
double a2 = Math.PI / 4;
double diff = Circle.subtractAngles(a1, a2);
assertTrue(diff < Math.PI);
diff = Circle.subtractAngles(a2, a1);
assertTrue(diff > Math.PI);
}
@Test
public void testMajorArc() {
Coordinate expectedCenter = new Coordinate(3, 0);
double expectedRadius = 5;
Coordinate p1 = new Coordinate(0, 4);
Coordinate p2 = new Coordinate(8, 0);
Coordinate p3 = new Coordinate(0, -4);
Circle c = new Circle(p1, p2, p3);
assertTrue(c.getCenter().equals2D(expectedCenter));
assertTrue(Double.compare(c.getRadius(), expectedRadius) == 0);
}
@Test
public void testArcDirection() {
Coordinate[] coords = new Coordinate[]{new Coordinate(0, 5),
new Coordinate(3, 4), new Coordinate(5, 0),
new Coordinate(3, -4), new Coordinate(0, -5),
new Coordinate(-3, -4), new Coordinate(-5, 0),
new Coordinate(-3, 4)};
for (int i = 0; i < coords.length; i++) {
Coordinate p1 = coords[i];
Coordinate p2 = coords[(i + 1) % coords.length];
Coordinate p3 = coords[(i + 2) % coords.length];
Circle c = new Circle(p1, p2, p3);
Circle.Arc a = c.createArc(p1, p2, p3);
assertTrue("Failed Points:" + p1 + ", " + p2 + ", " + p3, a
.isClockwise());
}
for (int i = 0; i < coords.length; i++) {
Coordinate p3 = coords[i];
Coordinate p2 = coords[(i + 1) % coords.length];
Coordinate p1 = coords[(i + 2) % coords.length];
Circle c = new Circle(p1, p2, p3);
Circle.Arc a = c.createArc(p1, p2, p3);
assertFalse("Failed Points:" + p1 + ", " + p2 + ", " + p3, a
.isClockwise());
}
}
@Test
public void testLinearize() {
Coordinate p1 = new Coordinate(5, 0);
Coordinate p2 = new Coordinate(4, 3);
Coordinate p3 = new Coordinate(4, -3);
Circle c = new Circle(p1, p2, p3);
Coordinate[] results = c.linearizeArc(p3, p2, p1, c.getRadius() * 0.01);
assertNotNull(results);
assertTrue(results.length > 0);
for (Coordinate coord : results) {
double error = c.getRadius() - c.distanceFromCenter(coord);
assertTrue(Double.compare(error, 0.0001) < 0);
}
}
@Test
public void testLinearizeCircle() {
Coordinate p1 = new Coordinate(5, 0);
Coordinate p2 = new Coordinate(4, 3);
Coordinate p3 = new Coordinate(4, -3);
Circle c = new Circle(p1, p2, p3);
Coordinate[] results = c.linearizeArc(p1, p2, p1,
(c.getRadius() * 0.01));
for (Coordinate coord : results) {
double error = c.getRadius() - c.distanceFromCenter(coord);
assertTrue(Double.compare(error, 0.0001) < 0);
}
}
}

View File

@ -0,0 +1,163 @@
/*
* $Id: TestData.java 253 2010-10-02 15:14:52Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
import java.io.InputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* A <code>TestData</code> instance is a list object
* that contains all the <code>TestDataElement</code>s that
* are used in a unit testsuite-suite suite.
*
* @author Karel Maesen, Geovise BVBA
*/
public class TestData implements List<TestDataElement> {
private List<TestDataElement> testDataElements;
private InputStream in;
protected TestData() {
}
;
public int size() {
return testDataElements.size();
}
public boolean isEmpty() {
return testDataElements.isEmpty();
}
public boolean contains(Object o) {
return testDataElements.contains(o);
}
public Iterator<TestDataElement> iterator() {
return testDataElements.iterator();
}
public Object[] toArray() {
return testDataElements.toArray();
}
public <T> T[] toArray(T[] a) {
return testDataElements.toArray(a);
}
public boolean add(TestDataElement testDataElement) {
return testDataElements.add(testDataElement);
}
public boolean remove(Object o) {
return testDataElements.remove(o);
}
public boolean containsAll(Collection<?> c) {
return testDataElements.containsAll(c);
}
public boolean addAll(Collection<? extends TestDataElement> c) {
return testDataElements.addAll(c);
}
public boolean addAll(int index, Collection<? extends TestDataElement> c) {
return testDataElements.addAll(index, c);
}
public boolean removeAll(Collection<?> c) {
return testDataElements.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
return testDataElements.retainAll(c);
}
public void clear() {
testDataElements.clear();
}
public boolean equals(Object o) {
return testDataElements.equals(o);
}
public int hashCode() {
return testDataElements.hashCode();
}
public TestDataElement get(int index) {
return testDataElements.get(index);
}
public TestDataElement set(int index, TestDataElement element) {
return testDataElements.set(index, element);
}
public void add(int index, TestDataElement element) {
testDataElements.add(index, element);
}
public TestDataElement remove(int index) {
return testDataElements.remove(index);
}
public int indexOf(Object o) {
return testDataElements.indexOf(o);
}
public int lastIndexOf(Object o) {
return testDataElements.lastIndexOf(o);
}
public ListIterator<TestDataElement> listIterator() {
return testDataElements.listIterator();
}
public ListIterator<TestDataElement> listIterator(int index) {
return testDataElements.listIterator(index);
}
public List<TestDataElement> subList(int fromIndex, int toIndex) {
return testDataElements.subList(fromIndex, toIndex);
}
public static TestData fromFile(String fileName) {
TestDataReader reader = new TestDataReader();
return fromFile(fileName, reader);
}
public static TestData fromFile(String fileName, TestDataReader reader) {
List<TestDataElement> elements = reader.read(fileName);
TestData testData = new TestData();
testData.testDataElements = elements;
return testData;
}
}

View File

@ -0,0 +1,49 @@
/*
* $Id: TestDataElement.java 253 2010-10-02 15:14:52Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
/**
* A <code>TestDataElement</code> captures the information necessary to build a testsuite-suite geometry.
*
* @author Karel Maesen, Geovise BVBA
*/
public class TestDataElement {
final public String wkt;
final public int id;
final public int srid;
final public String type;
protected TestDataElement(int id, String type, String wkt, int srid) {
this.wkt = wkt;
this.id = id;
this.type = type;
this.srid = srid;
}
}

View File

@ -0,0 +1,75 @@
/*
* $Id: TestDataReader.java 253 2010-10-02 15:14:52Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestDataReader {
public List<TestDataElement> read(String fileName) {
if (fileName == null) throw new RuntimeException("Null testsuite-suite data file specified.");
List<TestDataElement> testDataElements = new ArrayList<TestDataElement>();
SAXReader reader = new SAXReader();
try {
Document document = reader.read(getInputStream(fileName));
addDataElements(document, testDataElements);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
return testDataElements;
}
protected void addDataElements(Document document, List<TestDataElement> testDataElements) {
Element root = document.getRootElement();
for (Iterator it = root.elementIterator(); it.hasNext();) {
Element element = (Element) it.next();
addDataElement(element, testDataElements);
}
}
protected void addDataElement(Element element, List<TestDataElement> testDataElements) {
int id = Integer.valueOf(element.selectSingleNode("id").getText());
String type = element.selectSingleNode("type").getText();
String wkt = element.selectSingleNode("wkt").getText();
int srid = Integer.valueOf(element.selectSingleNode("srid").getText());
TestDataElement testDataElement = new TestDataElement(id, type, wkt, srid);
testDataElements.add(testDataElement);
}
protected InputStream getInputStream(String fileName) {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
if (is == null) throw new RuntimeException(String.format("File %s not found on classpath.", fileName));
return is;
}
}

View File

@ -0,0 +1,22 @@
package org.hibernate.spatial.test;
import com.vividsolutions.jts.geom.Geometry;
/**
* Interface for persistent entities in
* integration tests.
*
* @author Karel Maesen, Geovise BVBA
* creation-date: Oct 2, 2010
*/
public interface TestFeature {
public Integer getId();
public void setId(Integer id);
public Geometry getGeom();
public void setGeom(Geometry geom);
}

View File

@ -0,0 +1,45 @@
package org.hibernate.spatial.test;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Sep 30, 2010
*/
public abstract class TestSupport {
protected Configuration configuration;
public DataSourceUtils createDataSourceUtil(Configuration configuration) {
this.configuration = configuration;
return new DataSourceUtils(driver(), url(), user(), passwd(), getSQLExpressionTemplate());
}
public GeometryEquality createGeometryEquality() {
return new GeometryEquality();
}
public abstract TestData createTestData(BaseCoreFunctionalTestCase testcase);
public abstract AbstractExpectationsFactory createExpectationsFactory(DataSourceUtils dataSourceUtils);
public abstract SQLExpressionTemplate getSQLExpressionTemplate();
protected String driver() {
return configuration.getProperty("hibernate.connection.driver_class");
}
protected String url() {
return configuration.getProperty("hibernate.connection.url");
}
protected String user() {
return configuration.getProperty("hibernate.connection.username");
}
protected String passwd() {
return configuration.getProperty("hibernate.connection.password");
}
}

View File

@ -0,0 +1,714 @@
/**
* $Id: MLineStringTest.java 296 2011-03-05 11:50:41Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test.mgeom;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.CoordinateSequenceComparator;
import com.vividsolutions.jts.geom.PrecisionModel;
import junit.framework.TestCase;
import org.hibernate.spatial.mgeom.*;
/**
* @author Karel Maesen
*/
public class MLineStringTest extends TestCase {
private PrecisionModel prec = new PrecisionModel(PrecisionModel.FIXED);
private MGeometryFactory mgeomFactory = new MGeometryFactory(
MCoordinateSequenceFactory.instance());
private MLineString controlledLine;
private MLineString arbitraryLine;
private MLineString nullLine;
private MLineString ringLine;
public static void main(String[] args) {
junit.textui.TestRunner.run(MLineStringTest.class);
}
/*
* @see TestCase#setUp()
*/
protected void setUp() throws Exception {
super.setUp();
MCoordinate mc0 = MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0);
MCoordinate mc1 = MCoordinate.create2dWithMeasure(1.0, 0.0, 0.0);
MCoordinate mc2 = MCoordinate.create2dWithMeasure(1.0, 1.0, 0.0);
MCoordinate mc3 = MCoordinate.create2dWithMeasure(2.0, 1.0, 0.0);
MCoordinate[] mcoar = new MCoordinate[]{mc0, mc1, mc2, mc3};
controlledLine = mgeomFactory.createMLineString(mcoar);
mc0 = MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0);
mc1 = MCoordinate.create2dWithMeasure(1.0, 0.0, 0.0);
mc2 = MCoordinate.create2dWithMeasure(1.0, 1.0, 0.0);
mc3 = MCoordinate.create2dWithMeasure(0.0, 1.0, 0.0);
MCoordinate mc4 = MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0);
mcoar = new MCoordinate[]{mc0, mc1, mc2, mc3, mc4};
ringLine = mgeomFactory.createMLineString(mcoar);
int l = (int) Math.round(Math.random() * 250.0);
l = Math.max(2, l);
System.out.println("Size of arbitraryline ==" + l);
mcoar = new MCoordinate[l];
for (int i = 0; i < mcoar.length; i++) {
double x = Math.random() * 100000.0;
double y = Math.random() * 100000.0;
double z = Double.NaN; // JTS doesn't support operations on the
// z-coordinate value
double m = Math.random() * 100000.0;
mcoar[i] = new MCoordinate(x, y, z, m);
}
arbitraryLine = mgeomFactory.createMLineString(mcoar);
mcoar = new MCoordinate[0];
nullLine = mgeomFactory.createMLineString(mcoar);
}
/*
* @see TestCase#tearDown()
*/
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Constructor for MLineStringTest.
*
* @param name
*/
public MLineStringTest(String name) {
super(name);
}
//
// public void testMLineString() {
// }
/*
* Class under testsuite-suite for Object clone()
*/
public void testClone() {
MLineString mltest = (MLineString) arbitraryLine.clone();
Coordinate[] testco = mltest.getCoordinates();
Coordinate[] arco = arbitraryLine.getCoordinates();
assertEquals(testco.length, arco.length);
for (int i = 0; i < arco.length; i++) {
// clones must have equal, but not identical coordinates
assertEquals(arco[i], testco[i]);
assertNotSame(arco[i], testco[i]);
}
mltest = (MLineString) nullLine.clone();
assertEquals(mltest.isEmpty(), nullLine.isEmpty());
assertTrue(mltest.isEmpty());
}
public void testGetClosestPoint() {
try {
if (!arbitraryLine.isMonotone(false)) {
Coordinate mc = arbitraryLine.getClosestPoint(new Coordinate(
1.0, 2.0), 0.1);
assertTrue(false); // should never evaluate this
}
} catch (Exception e) {
assertTrue(((MGeometryException) e).getType() == MGeometryException.OPERATION_REQUIRES_MONOTONE);
}
try {
// check reaction on null string
MCoordinate mc = nullLine.getClosestPoint(new Coordinate(0.0, 1.0),
1.0);
assertNull(mc);
// must return the very same coordinate if the coordinate is a
// coordinate of the line
arbitraryLine.measureOnLength(false);
int selp = (int) (arbitraryLine.getNumPoints() / 2);
MCoordinate mcexp = (MCoordinate) arbitraryLine
.getCoordinateN(selp);
MCoordinate mctest = arbitraryLine.getClosestPoint(mcexp, 1);
assertEquals(mcexp, mctest);
// must not return a point that is beyond the tolerance
mctest = controlledLine.getClosestPoint(
new Coordinate(20.0, 20, 0), 1.0);
assertNull(mctest);
// check for cases of circular MGeometry: lowest measure should be
// return.
ringLine.measureOnLength(false);
assertTrue(ringLine.isRing());
assertTrue(ringLine.isMonotone(false));
assertTrue(ringLine.getMeasureDirection() == MGeometry.INCREASING);
MCoordinate expCo = MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0);
MCoordinate testCo = ringLine.getClosestPoint(expCo, 0.1);
assertTrue(DoubleComparator.equals(testCo.m, expCo.m));
ringLine.reverseMeasures();
testCo = ringLine.getClosestPoint(expCo, 0.1);
assertTrue(DoubleComparator.equals(testCo.m, expCo.m));
ringLine.measureOnLength(false);
int n = ringLine.getNumPoints() - 1;
ringLine.setMeasureAtIndex(n, 100.0);
ringLine.setMeasureAtIndex(0, 0.0);
testCo = ringLine.getClosestPoint(expCo, 0.001);
assertTrue(DoubleComparator.equals(testCo.m, 0.0));
// get two neighbouring points along the arbitraryline
arbitraryLine.measureOnLength(false);
int elem1Indx = (int) (Math.random() * (arbitraryLine
.getNumPoints() - 1));
int elem2Indx = 0;
if (elem1Indx == arbitraryLine.getNumPoints() - 1) {
elem2Indx = elem1Indx - 1;
} else {
elem2Indx = elem1Indx + 1;
}
// testsuite-suite whether a coordinate between these two returns exactly
MCoordinate mco1 = (MCoordinate) arbitraryLine
.getCoordinateN(elem1Indx);
MCoordinate mco2 = (MCoordinate) arbitraryLine
.getCoordinateN(elem2Indx);
double d = mco1.distance(mco2);
double offset = Math.random();
mcexp = MCoordinate.create2dWithMeasure(mco1.x + offset
* (mco2.x - mco1.x), mco1.y + offset * (mco2.y - mco1.y),
0.0);
mctest = arbitraryLine.getClosestPoint(mcexp, d);
mcexp.m = mco1.m + offset * (mco2.m - mco1.m);
assertEquals(mcexp.x, mctest.x, 0.001);
assertEquals(mcexp.y, mctest.y, 0.001);
assertEquals(mcexp.z, mctest.z, 0.001);
double delta = Math.random();
MCoordinate mcin = MCoordinate.create2dWithMeasure(mco1.x + offset
* (mco2.x - mco1.x) + delta, mco1.y + offset
* (mco2.y - mco1.y) + delta, 0.0);
// returned point is on the line
mctest = arbitraryLine.getClosestPoint(mcin, d);
assertEquals(mcin.x, mctest.x, delta * Math.sqrt(2));
assertEquals(mcin.y, mctest.y, delta * Math.sqrt(2));
} catch (Exception e) {
e.printStackTrace();
assertTrue(false); // should never reach this point
}
}
public void testGetCoordinateAtM() {
// what if null string
try {
Coordinate mc = nullLine.getCoordinateAtM(2);
assertNull(mc);
// get two neighbouring points along the arbitraryline
arbitraryLine.measureOnLength(false);
int elem1Indx = (int) (Math.random() * (arbitraryLine
.getNumPoints() - 1));
int elem2Indx = 0;
if (elem1Indx == arbitraryLine.getNumPoints() - 1) {
elem2Indx = elem1Indx - 1;
} else {
elem2Indx = elem1Indx + 1;
}
// if m is value of a coordinate, the returned coordinate should
// equal that coordinate
MCoordinate mco1 = (MCoordinate) arbitraryLine
.getCoordinateN(elem1Indx);
MCoordinate mcotest = (MCoordinate) arbitraryLine
.getCoordinateAtM(mco1.m);
assertNotSame(mco1, mcotest);
assertEquals(mco1.x, mcotest.x, Math.ulp(100 * mco1.x));
assertEquals(mco1.y, mcotest.y, Math.ulp(100 * mco1.y));
assertEquals(mco1.m, mcotest.m, Math.ulp(100 * mco1.m));
MCoordinate mco2 = (MCoordinate) arbitraryLine
.getCoordinateN(elem2Indx);
double offset = Math.random();
double newM = mco1.m + offset * (mco2.m - mco1.m);
MCoordinate mcexp = new MCoordinate(mco1.x + offset
* (mco2.x - mco1.x), mco1.y + offset * (mco2.y - mco1.y),
Double.NaN, mco1.m + offset * (mco2.m - mco1.m));
MCoordinate mctest = (MCoordinate) arbitraryLine
.getCoordinateAtM(newM);
assertEquals(mcexp.x, mctest.x, 0.0001);
assertEquals(mcexp.y, mctest.y, 0.0001);
assertEquals(mcexp.m, mctest.m, 0.0001);
} catch (Exception e) {
System.err.println(e);
}
}
/*
* Class under testsuite-suite for String getGeometryType()
*/
public void testGetGeometryType() {
assertEquals("MLineString", arbitraryLine.getGeometryType());
}
public void testGetMatCoordinate() {
try {
// what in case of the null string
assertTrue(Double.isNaN(nullLine.getMatCoordinate(new Coordinate(
1.0, 1.0), 1.0)));
// get two neighbouring points along the arbitraryline
arbitraryLine.measureOnLength(false);
int elem1Indx = (int) (Math.random() * (arbitraryLine
.getNumPoints() - 1));
int elem2Indx = 0;
if (elem1Indx == arbitraryLine.getNumPoints() - 1) {
elem2Indx = elem1Indx - 1;
} else {
elem2Indx = elem1Indx + 1;
}
// if a coordinate of the geometry is passed, it should return
// exactly that m-value
MCoordinate mco1 = (MCoordinate) arbitraryLine
.getCoordinateN(elem1Indx);
double m = arbitraryLine.getMatCoordinate(mco1, 0.00001);
assertEquals(mco1.m, m, DoubleComparator
.defaultNumericalPrecision());
// check for a coordinate between mco1 and mco2 (neighbouring
// coordinates)
MCoordinate mco2 = (MCoordinate) arbitraryLine
.getCoordinateN(elem2Indx);
double offset = Math.random();
double expectedM = mco1.m + offset * (mco2.m - mco1.m);
Coordinate mctest = new Coordinate(mco1.x + offset
* (mco2.x - mco1.x), mco1.y + offset * (mco2.y - mco1.y));
double testM = arbitraryLine.getMatCoordinate(mctest, offset);
assertEquals(expectedM, testM, DoubleComparator
.defaultNumericalPrecision());
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);// should never reach here
}
}
public void testGetMatN() {
// Implement getMatN().
}
public void testGetMaxM() {
// Implement getMaxM().
}
public void testGetCoordinatesBetween() {
try {
// what if the null value is passed
CoordinateSequence[] cs = nullLine.getCoordinatesBetween(0.0, 5.0);
assertTrue("cs.length = " + cs.length + ". Should be 1", cs.length == 1);
assertEquals(cs[0].size(), 0);
arbitraryLine.measureOnLength(false);
// what if from/to is outside of the range of values
double maxM = arbitraryLine.getMaxM();
cs = arbitraryLine.getCoordinatesBetween(maxM + 1.0, maxM + 10.0);
// check for several ascending M-values
int minIdx = (int) (Math.random() * (arbitraryLine.getNumPoints() - 1));
int maxIdx = Math.min((arbitraryLine.getNumPoints() - 1),
minIdx + 10);
double minM = ((MCoordinate) arbitraryLine.getCoordinateN(minIdx)).m;
maxM = ((MCoordinate) arbitraryLine.getCoordinateN(maxIdx)).m;
cs = arbitraryLine.getCoordinatesBetween(minM, maxM);
assertNotNull(cs);
assertTrue(cs.length > 0);
Coordinate[] coar = cs[0].toCoordinateArray();
int j = 0;
for (int i = minIdx; i <= maxIdx; i++) {
assertEquals((MCoordinate) arbitraryLine.getCoordinateN(i),
coar[j]);
j++;
}
minM = Math.max(0.0, minM - Math.random() * 10);
cs = arbitraryLine.getCoordinatesBetween(minM, maxM);
coar = cs[0].toCoordinateArray();
MCoordinate mctest = (MCoordinate) coar[0];
MCoordinate mcexp = (MCoordinate) arbitraryLine
.getCoordinateAtM(minM);
assertEquals(mcexp, mctest);
assertEquals(mctest.m, minM, DoubleComparator
.defaultNumericalPrecision());
maxM = Math.min(arbitraryLine.getLength(), maxM + Math.random()
* 10);
cs = arbitraryLine.getCoordinatesBetween(minM, maxM);
coar = cs[0].toCoordinateArray();
mctest = (MCoordinate) coar[coar.length - 1];
mcexp = (MCoordinate) arbitraryLine.getCoordinateAtM(maxM);
assertEquals(mcexp.x, mctest.x, Math.ulp(mcexp.x) * 100);
assertEquals(mcexp.y, mctest.y, Math.ulp(mcexp.y) * 100);
assertEquals(mctest.m, maxM, DoubleComparator
.defaultNumericalPrecision());
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);// should never reach here
}
}
public void testGetMeasureDirection() {
assertTrue(nullLine.isMonotone(false));
assertTrue(arbitraryLine.isMonotone(false)
|| (!arbitraryLine.isMonotone(false) && arbitraryLine
.getMeasureDirection() == MGeometry.NON_MONOTONE));
arbitraryLine.measureOnLength(false);
assertEquals(MGeometry.INCREASING, arbitraryLine.getMeasureDirection());
arbitraryLine.reverseMeasures();
assertEquals(MGeometry.DECREASING, arbitraryLine.getMeasureDirection());
for (int i = 0; i < arbitraryLine.getNumPoints(); i++) {
arbitraryLine.setMeasureAtIndex(i, 0.0);
}
assertEquals(MGeometry.CONSTANT, arbitraryLine.getMeasureDirection());
}
public void testGetMeasures() {
}
public void testGetMinM() {
}
public void testInterpolate() {
MCoordinate mc0NaN = MCoordinate.create2d(0.0, 0.0);
MCoordinate mc0 = MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0);
MCoordinate mc2NaN = MCoordinate.create2d(2.0, 0.0);
MCoordinate mc5NaN = MCoordinate.create2d(5.0, 0.0);
MCoordinate mc10NaN = MCoordinate.create2d(10.0, 0.0);
MCoordinate mc10 = MCoordinate.create2dWithMeasure(10.0, 0.0, 10.0);
// Internal coordinate measures are not defined, outer measures are
// 0-10, total 2d length is 10
MLineString line = mgeomFactory.createMLineString(new MCoordinate[]{
mc0, mc2NaN, mc5NaN, mc10});
MLineString lineBeginNaN = mgeomFactory
.createMLineString(new MCoordinate[]{mc0NaN, mc2NaN, mc5NaN,
mc10});
MLineString lineEndNaN = mgeomFactory
.createMLineString(new MCoordinate[]{mc0, mc2NaN, mc5NaN,
mc10NaN});
assertTrue(DoubleComparator.equals(line.getLength(), 10));
assertTrue(DoubleComparator.equals(lineBeginNaN.getLength(), 10));
assertTrue(DoubleComparator.equals(lineEndNaN.getLength(), 10));
line.interpolate(mc0.m, mc10.m);
lineBeginNaN.interpolate(mc0.m, mc10.m);
lineEndNaN.interpolate(mc0.m, mc10.m);
assertTrue(line.isMonotone(false));
assertTrue(line.isMonotone(true));
assertTrue(lineBeginNaN.isMonotone(false));
assertTrue(lineBeginNaN.isMonotone(true));
assertTrue(lineEndNaN.isMonotone(false));
assertTrue(lineEndNaN.isMonotone(true));
double[] expectedM = new double[]{mc0.m, 2.0, 5.0, mc10.m};
for (int i = 0; i < expectedM.length; i++) {
double actualMLine = line.getCoordinateSequence().getOrdinate(i,
CoordinateSequence.M);
double actualBeginNaN = lineBeginNaN.getCoordinateSequence()
.getOrdinate(i, CoordinateSequence.M);
double actualEndNaN = lineEndNaN.getCoordinateSequence()
.getOrdinate(i, CoordinateSequence.M);
assertTrue(DoubleComparator.equals(expectedM[i], actualMLine));
assertTrue(DoubleComparator.equals(expectedM[i], actualBeginNaN));
assertTrue(DoubleComparator.equals(expectedM[i], actualEndNaN));
}
// Test Continuous case by interpolating with begin and end measures
// equal
double continuousMeasure = 0.0D;
line.interpolate(continuousMeasure, continuousMeasure);
double[] measures = line.getMeasures();
for (int i = 0; i < measures.length; i++)
assertTrue(DoubleComparator.equals(measures[i], continuousMeasure));
}
public void testIsMonotone() {
MCoordinate mc0NaN = MCoordinate.create2d(1.0, 0.0);
MCoordinate mc0 = MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0);
MCoordinate mc1NaN = MCoordinate.create2d(1.0, 0.0);
MCoordinate mc1 = MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0);
MCoordinate mc2NaN = MCoordinate.create2d(2.0, 0.0);
MCoordinate mc2 = MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0);
MCoordinate mc3NaN = MCoordinate.create2d(3.0, 0.0);
MCoordinate mc3 = MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0);
MLineString emptyLine = mgeomFactory
.createMLineString(new MCoordinate[]{});
MLineString orderedLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0, mc1, mc2, mc3});
MLineString unorderedLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0, mc2, mc1, mc3});
MLineString constantLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc2, mc2, mc2, mc2});
MLineString reverseOrderedLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc3, mc2, mc1, mc0});
MLineString reverseUnOrderedLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc3, mc1, mc2, mc0});
MLineString dupCoordLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0, mc1, mc1, mc2});
MLineString reverseDupCoordLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc2, mc1, mc1, mc0});
assertTrue(emptyLine.isMonotone(false));
assertTrue(emptyLine.isMonotone(true));
assertTrue(orderedLine.isMonotone(false));
assertTrue(orderedLine.isMonotone(true));
// testsuite-suite reversing the ordered line
orderedLine.reverseMeasures();
assertTrue(orderedLine.isMonotone(false));
assertTrue(orderedLine.isMonotone(true));
// testsuite-suite shifting
orderedLine.shiftMeasure(1.0);
assertTrue(orderedLine.isMonotone(false));
assertTrue(orderedLine.isMonotone(true));
orderedLine.shiftMeasure(-1.0);
assertTrue(orderedLine.isMonotone(false));
assertTrue(orderedLine.isMonotone(true));
assertFalse(unorderedLine.isMonotone(false));
assertFalse(unorderedLine.isMonotone(true));
assertTrue(constantLine.isMonotone(false));
assertFalse(constantLine.isMonotone(true));
// testsuite-suite shifting
constantLine.shiftMeasure(1.0);
assertTrue(constantLine.isMonotone(false));
assertFalse(constantLine.isMonotone(true));
constantLine.shiftMeasure(-1.0);
assertTrue(constantLine.isMonotone(false));
assertFalse(constantLine.isMonotone(true));
assertTrue(reverseOrderedLine.isMonotone(false));
assertTrue(reverseOrderedLine.isMonotone(true));
// testsuite-suite reversing the line
reverseOrderedLine.reverseMeasures();
assertTrue(reverseOrderedLine.isMonotone(false));
assertTrue(reverseOrderedLine.isMonotone(true));
// testsuite-suite shifting
reverseOrderedLine.shiftMeasure(1.0);
assertTrue(reverseOrderedLine.isMonotone(false));
assertTrue(reverseOrderedLine.isMonotone(true));
reverseOrderedLine.shiftMeasure(-1.0);
assertTrue(reverseOrderedLine.isMonotone(false));
assertTrue(reverseOrderedLine.isMonotone(true));
assertFalse(reverseUnOrderedLine.isMonotone(false));
assertFalse(reverseUnOrderedLine.isMonotone(true));
assertTrue(dupCoordLine.isMonotone(false));
assertFalse(dupCoordLine.isMonotone(true));
// testsuite-suite shifting
dupCoordLine.shiftMeasure(1.0);
assertTrue(dupCoordLine.isMonotone(false));
assertFalse(dupCoordLine.isMonotone(true));
dupCoordLine.shiftMeasure(-1.0);
assertTrue(dupCoordLine.isMonotone(false));
assertFalse(dupCoordLine.isMonotone(true));
assertTrue(reverseDupCoordLine.isMonotone(false));
assertFalse(reverseDupCoordLine.isMonotone(true));
// testsuite-suite shifting
reverseDupCoordLine.shiftMeasure(1.0);
assertTrue(reverseDupCoordLine.isMonotone(false));
assertFalse(reverseDupCoordLine.isMonotone(true));
reverseDupCoordLine.shiftMeasure(-1.0);
assertTrue(reverseDupCoordLine.isMonotone(false));
assertFalse(reverseDupCoordLine.isMonotone(true));
assertEquals(orderedLine.getMeasureDirection(), MGeometry.INCREASING);
assertEquals(unorderedLine.getMeasureDirection(),
MGeometry.NON_MONOTONE);
assertEquals(reverseOrderedLine.getMeasureDirection(),
MGeometry.DECREASING);
assertEquals(dupCoordLine.getMeasureDirection(), MGeometry.INCREASING);
assertEquals(reverseDupCoordLine.getMeasureDirection(),
MGeometry.DECREASING);
// Test scenario where there are NaN middle measures
MLineString internalNaNLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0, mc1NaN, mc2NaN, mc3});
MLineString beginNaNLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0NaN, mc2, mc3});
MLineString endNaNLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0, mc2, mc3NaN});
MLineString beginEndNaNLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0NaN, mc2, mc3NaN});
assertFalse(internalNaNLine.isMonotone(false));
assertFalse(internalNaNLine.isMonotone(true));
internalNaNLine.measureOnLength(false);
assertTrue(internalNaNLine.isMonotone(false));
assertTrue(internalNaNLine.isMonotone(true));
assertFalse(beginNaNLine.isMonotone(false));
assertFalse(beginNaNLine.isMonotone(true));
beginNaNLine.measureOnLength(false);
assertTrue(beginNaNLine.isMonotone(false));
assertTrue(beginNaNLine.isMonotone(true));
assertFalse(endNaNLine.isMonotone(false));
assertFalse(endNaNLine.isMonotone(true));
endNaNLine.measureOnLength(false);
assertTrue(endNaNLine.isMonotone(false));
assertTrue(endNaNLine.isMonotone(true));
assertFalse(beginEndNaNLine.isMonotone(false));
assertFalse(beginEndNaNLine.isMonotone(true));
beginEndNaNLine.measureOnLength(false);
assertTrue(beginEndNaNLine.isMonotone(false));
assertTrue(beginEndNaNLine.isMonotone(true));
}
public void testGetCoordinatesBetweenNonStrict() {
try {
CoordinateSequenceComparator coordCompare = new CoordinateSequenceComparator();
MCoordinate mc0 = MCoordinate.create2dWithMeasure(0.0, 0.0, 0);
MCoordinate mc1 = MCoordinate.create2dWithMeasure(0.0, 1.0, 1);
MCoordinate mc2_1 = MCoordinate.create2dWithMeasure(0.0, 2.0, 1);
MCoordinate mc2 = MCoordinate.create2dWithMeasure(0.0, 2.0, 2);
MCoordinate mc3 = MCoordinate.create2dWithMeasure(0.0, 3.0, 3);
MCoordinate mc4 = MCoordinate.create2dWithMeasure(0.0, 4.0, 4);
// Test non-strict sequence where all coordinate x,y positions are
// unique, but contains a
// duplicate measure. The measure sequence in this testsuite-suite s
// [0,1,1,3,4]
MLineString nonStrictPointLine = mgeomFactory
.createMLineString(new MCoordinate[]{mc0, mc1, mc2_1,
mc3, mc4});
CoordinateSequence[] nonStrictSeq = nonStrictPointLine
.getCoordinatesBetween(mc0.m, mc2_1.m);
assertNotNull(nonStrictSeq);
nonStrictSeq = nonStrictPointLine.getCoordinatesBetween(mc0.m,
mc4.m);
assertNotNull(nonStrictSeq);
nonStrictSeq = nonStrictPointLine.getCoordinatesBetween(mc1.m,
mc4.m);
assertNotNull(nonStrictSeq);
nonStrictSeq = nonStrictPointLine
.getCoordinatesBetween(1.1D, mc4.m);
assertNotNull(nonStrictSeq);
} catch (MGeometryException e) {
e.printStackTrace();
}
}
public void testmeasureOnLength() {
arbitraryLine.measureOnLength(false);
double maxM = arbitraryLine.getMaxM();
double minM = arbitraryLine.getMinM();
assertEquals(maxM, arbitraryLine.getLength(), DoubleComparator
.defaultNumericalPrecision());
assertEquals(minM, 0.0d, DoubleComparator.defaultNumericalPrecision());
MCoordinate mco = (MCoordinate) arbitraryLine
.getCoordinateN(arbitraryLine.getNumPoints() - 1);
assertEquals(mco.m, maxM, DoubleComparator.defaultNumericalPrecision());
mco = (MCoordinate) arbitraryLine.getCoordinateN(0);
assertEquals(mco.m, minM, DoubleComparator.defaultNumericalPrecision());
}
public void testReverseMeasures() {
nullLine.reverseMeasures();
arbitraryLine.measureOnLength(false);
arbitraryLine.reverseMeasures();
assertTrue(arbitraryLine.getMeasureDirection() == MGeometry.DECREASING);
double mlast = arbitraryLine.getMatN(arbitraryLine.getNumPoints() - 1);
arbitraryLine.reverseMeasures();
assertTrue(arbitraryLine.getMeasureDirection() == MGeometry.INCREASING);
double mfirst = arbitraryLine.getMatN(0);
assertEquals(mlast, mfirst, DoubleComparator
.defaultNumericalPrecision());
}
public void testSetMatN() {
// TODO Implement setMeasureAtIndex().
}
public void testShiftMBy() {
// TODO Implement shiftMeasure().
}
/*
* Class under testsuite-suite for String toString()
*/
public void testToString() {
// TODO Implement toString().
}
public void testUnionM() {
// TODO Implement unionM().
}
public void testVerifyMonotone() {
// TODO Implement verifyMonotone().
}
}

View File

@ -0,0 +1,185 @@
/**
* $Id: MultiMLineStringTest.java 253 2010-10-02 15:14:52Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007 Geovise BVBA
* Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium
*
* This work was partially supported by the European Commission,
* under the 6th Framework Programme, contract IST-2-004688-STP.
*
* 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test.mgeom;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.GeometryFactory;
import junit.framework.TestCase;
import org.hibernate.spatial.mgeom.MCoordinate;
import org.hibernate.spatial.mgeom.MCoordinateSequenceFactory;
import org.hibernate.spatial.mgeom.MLineString;
import org.hibernate.spatial.mgeom.MultiMLineString;
/**
* @author Karel Maesen
*/
public class MultiMLineStringTest extends TestCase {
private final MCoordinateSequenceFactory mcfactory = MCoordinateSequenceFactory
.instance();
private final GeometryFactory geomfactory = new GeometryFactory(mcfactory);
protected MLineString ml1;
protected MLineString ml2;
protected MultiMLineString mm1;
protected MultiMLineString mmsimple;
protected MCoordinate lastco;
public static void main(String[] args) {
junit.textui.TestRunner.run(MultiMLineStringTest.class);
}
/*
* @see TestCase#setUp()
*/
protected void setUp() throws Exception {
super.setUp();
MCoordinate mc0 = new MCoordinate(0.0, 0.0, 0.0, 0.0);
MCoordinate mc1 = new MCoordinate(1.0, 0.0, 0.0, 0.1);
MCoordinate mc2 = new MCoordinate(1.0, 1.0, 0.0, 0.2);
MCoordinate mc3 = new MCoordinate(5.0, 1.0, 0.0, 0.3);
MCoordinate mc4 = new MCoordinate(5.0, 3.0, 0.0, 0.4);
lastco = mc4;
MCoordinate[] m1 = {mc0, mc1, mc2};
MCoordinate[] m2 = {mc3, mc4};
CoordinateSequence mseq1 = mcfactory.create(m1);
ml1 = new MLineString(mseq1, geomfactory);
CoordinateSequence mseq2 = mcfactory.create(m2);
ml2 = new MLineString(mseq2, geomfactory);
mmsimple = new MultiMLineString(new MLineString[]{ml1}, 0.1,
geomfactory);
mm1 = new MultiMLineString(new MLineString[]{ml1, ml2}, 0.1,
geomfactory);
}
/*
* @see TestCase#tearDown()
*/
protected void tearDown() throws Exception {
super.tearDown();
}
public void testMaxM() {
assertEquals(0.4, mm1.getMaxM(), 0.000001);
}
/*
* Class under testsuite-suite for java.lang.String getGeometryType()
*/
public void testGetGeometryType() {
assertTrue("wrong type reported", mm1.getGeometryType()
.equalsIgnoreCase("multimlinestring"));
}
public void testGetDimension() {
// TODO Implement getDimension().
}
public void testGetBoundary() {
// TODO Implement getBoundary().
}
public void testGetBoundaryDimension() {
// TODO Implement getBoundaryDimension().
}
/*
* Class under testsuite-suite for boolean
* equalsExact(com.vividsolutions.jts.geom.Geometry, double)
*/
public void testEqualsExactGeometrydouble() {
// TODO Implement equalsExact().
}
/*
* Class under testsuite-suite for void
* MultiLineString(com.vividsolutions.jts.geom.LineString[],
* com.vividsolutions.jts.geom.PrecisionModel, int)
*/
public void testMultiLineStringLineStringArrayPrecisionModelint() {
// TODO Implement MultiLineString().
}
/*
* Class under testsuite-suite for void
* MultiLineString(com.vividsolutions.jts.geom.LineString[],
* com.vividsolutions.jts.geom.GeometryFactory)
*/
public void testMultiLineStringLineStringArrayGeometryFactory() {
// TODO Implement MultiLineString().
}
public void testIsClosed() {
// TODO Implement isClosed().
}
public void testClone() {
// TODO implement
}
public void testInterpolate() {
mm1.measureOnLength(false);
Coordinate[] ca = mm1.getCoordinates();
assertTrue("co 0 not OK", ((MCoordinate) ca[0]).m == 0.0);
assertTrue("co 1 not OK",
Math.abs(((MCoordinate) ca[1]).m - 1.0) < 0.00001);
assertTrue("co 2 not OK",
Math.abs(((MCoordinate) ca[2]).m - 2.0) < 0.00001);
assertTrue("co 3 not OK", Math.abs(((MCoordinate) ca[3]).m
- (2.0 + mm1.getMGap())) < 0.00001);
assertTrue("co 4 not OK", Math.abs(((MCoordinate) ca[4]).m
- (4.0 + mm1.getMGap())) < 0.00001);
double dist = mm1.getLength();
dist += (mm1.getNumGeometries() - 1) * mm1.getMGap();
assertTrue("interpolation not consistent with distance", Math
.abs(((MCoordinate) ca[4]).m - dist) < 0.00001);
}
}

View File

@ -0,0 +1,120 @@
/*
* $Id: TestEventLocator.java 226 2010-06-28 20:58:45Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test.mgeom;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.PrecisionModel;
import org.hibernate.spatial.mgeom.*;
import org.junit.Before;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class TestEventLocator {
private PrecisionModel prec = new PrecisionModel(PrecisionModel.FIXED);
private MGeometryFactory mgeomFactory = new MGeometryFactory(
MCoordinateSequenceFactory.instance());
private MultiMLineString incrML;
@Before
public void setUp() {
MCoordinate[] coordinates = new MCoordinate[]{
MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0),
MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0),
MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0),
MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0)
};
MLineString line1 = mgeomFactory.createMLineString(coordinates);
MCoordinate[] coordinates2 = new MCoordinate[]{
MCoordinate.create2dWithMeasure(5.0, 0.0, 5.0),
MCoordinate.create2dWithMeasure(6.0, 0.0, 6.0),
MCoordinate.create2dWithMeasure(7.0, 0.0, 7.0),
};
MLineString line2 = mgeomFactory.createMLineString(coordinates2);
MCoordinate[] coordinates3 = new MCoordinate[]{
MCoordinate.create2dWithMeasure(9.0, 0.0, 9.0),
MCoordinate.create2dWithMeasure(10.0, 0.0, 10.0),
MCoordinate.create2dWithMeasure(11.0, 0.0, 11.0),
};
MLineString line3 = mgeomFactory.createMLineString(coordinates2);
incrML = mgeomFactory.createMultiMLineString(new MLineString[]{line1, line2});
}
@Test
public void test_event_starts_at_end_of_component() throws MGeometryException {
MultiMLineString result = EventLocator.getLinearGeometry(incrML, 4.0, 5.5);
assertNotNull(result);
assertEquals(1, result.getNumGeometries());
assertEquals(2, result.getCoordinates().length);
Coordinate[] coordinates = result.getCoordinates();
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 5.0), (MCoordinate) coordinates[0]);
assertEquals(MCoordinate.create2dWithMeasure(5.5, 0.0, 5.5), (MCoordinate) coordinates[1]);
}
@Test
public void test_event_ends_at_begin_of_component() throws MGeometryException {
MultiMLineString result = EventLocator.getLinearGeometry(incrML, 3.0, 5.0);
assertNotNull(result);
assertEquals(1, result.getNumGeometries());
assertEquals(2, result.getCoordinates().length);
Coordinate[] coordinates = result.getCoordinates();
assertEquals(MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0), (MCoordinate) coordinates[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), (MCoordinate) coordinates[1]);
}
@Test
public void test_event_ends_at_end_of_component() throws MGeometryException {
MultiMLineString result = EventLocator.getLinearGeometry(incrML, 4.5, 7.0);
assertNotNull(result);
assertEquals(1, result.getNumGeometries());
assertEquals(3, result.getCoordinates().length);
Coordinate[] coordinates = result.getCoordinates();
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 5.0), (MCoordinate) coordinates[0]);
assertEquals(MCoordinate.create2dWithMeasure(6.0, 0.0, 6.0), (MCoordinate) coordinates[1]);
assertEquals(MCoordinate.create2dWithMeasure(7.0, 0.0, 7.0), (MCoordinate) coordinates[2]);
}
@Test
public void test_locator_result_has_same_srid_as_input_mgeometry() throws MGeometryException {
incrML.setSRID(123);
MultiMLineString result = EventLocator.getLinearGeometry(incrML, 4.5, 7.0);
assertEquals(123, result.getSRID());
}
}

View File

@ -0,0 +1,512 @@
/*
* $Id: TestMLineStringGetCoordinatesBetween.java 225 2010-06-25 21:59:05Z maesenka $
*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for geographic data.
*
* Copyright © 2007-2010 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
*
* For more information, visit: http://www.hibernatespatial.org/
*/
package org.hibernate.spatial.test.mgeom;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.PrecisionModel;
import org.hibernate.spatial.mgeom.*;
import org.junit.Before;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
public class TestMLineStringGetCoordinatesBetween {
MLineString incrLine;
MLineString decLine;
MLineString emptyLine;
MLineString nonMonotoneLine;
MLineString partiallyConstantIncreasing;
MLineString partiallyConstantDecreasing;
private PrecisionModel prec = new PrecisionModel(PrecisionModel.FIXED);
private MGeometryFactory mgeomFactory = new MGeometryFactory(
MCoordinateSequenceFactory.instance());
@Before
public void setUp() {
MCoordinate[] coordinates = new MCoordinate[]{
MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0),
MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0),
MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0),
MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0)
};
incrLine = mgeomFactory.createMLineString(coordinates);
coordinates = new MCoordinate[]{
MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0),
MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0),
MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0),
MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0)
};
decLine = mgeomFactory.createMLineString(coordinates);
coordinates = new MCoordinate[]{
MCoordinate.create2dWithMeasure(0.0, 0.0, 1.0),
MCoordinate.create2dWithMeasure(1.0, 0.0, 3.0),
MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(3.0, 0.0, 5.0),
MCoordinate.create2dWithMeasure(4.0, 0.0, 1.5)
};
nonMonotoneLine = mgeomFactory.createMLineString(coordinates);
coordinates = new MCoordinate[]{
MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0),
MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0),
MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(3.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(4.0, 0.0, 3.0),
MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0)
};
partiallyConstantIncreasing = mgeomFactory.createMLineString(coordinates);
coordinates = new MCoordinate[]{
MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0),
MCoordinate.create2dWithMeasure(4.0, 0.0, 3.0),
MCoordinate.create2dWithMeasure(3.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0),
MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0),
MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0)
};
partiallyConstantDecreasing = mgeomFactory.createMLineString(coordinates);
}
@Test
public void test_measure_inside_monotone_increasing() throws MGeometryException {
CoordinateSequence[] result;
result = incrLine.getCoordinatesBetween(0.5, 3.5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[crds.length - 1]);
result = incrLine.getCoordinatesBetween(1.0, 3.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(3, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0), crds[2]);
result = incrLine.getCoordinatesBetween(0.0, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[4]);
result = incrLine.getCoordinatesBetween(0.5, 1.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(3, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(1.5, 0.0, 1.5), crds[crds.length - 1]);
result = incrLine.getCoordinatesBetween(3.5, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.5), crds[crds.length - 1]);
result = incrLine.getCoordinatesBetween(3.5, 3.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.7, 0.0, 3.7), crds[1]);
result = incrLine.getCoordinatesBetween(0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[1]);
result = incrLine.getCoordinatesBetween(-0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[1]);
result = incrLine.getCoordinatesBetween(3.5, 4.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[1]);
}
@Test
public void test_measure_inside_partially_constant_increasing() throws MGeometryException {
CoordinateSequence[] result;
result = partiallyConstantIncreasing.getCoordinatesBetween(0.5, 2.5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 2.5), crds[crds.length - 1]);
result = partiallyConstantIncreasing.getCoordinatesBetween(1.0, 3.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(4, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 3.0), crds[3]);
result = partiallyConstantIncreasing.getCoordinatesBetween(0.0, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(6, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0), crds[5]);
result = partiallyConstantIncreasing.getCoordinatesBetween(0.5, 1.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(3, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(1.5, 0.0, 1.5), crds[crds.length - 1]);
result = partiallyConstantIncreasing.getCoordinatesBetween(1.5, 2.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(4, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(1.5, 0.0, 1.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 2.5), crds[crds.length - 1]);
result = partiallyConstantIncreasing.getCoordinatesBetween(3.5, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0), crds[crds.length - 1]);
result = partiallyConstantIncreasing.getCoordinatesBetween(3.5, 3.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.7, 0.0, 3.7), crds[1]);
result = partiallyConstantIncreasing.getCoordinatesBetween(0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[1]);
result = partiallyConstantIncreasing.getCoordinatesBetween(-0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[1]);
result = partiallyConstantIncreasing.getCoordinatesBetween(3.5, 4.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0), crds[1]);
}
@Test
public void test_measures_monotone_decreasing() throws MGeometryException {
CoordinateSequence[] result;
result = decLine.getCoordinatesBetween(0.5, 3.5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[crds.length - 1]);
result = decLine.getCoordinatesBetween(1.0, 3.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(3, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0), crds[2]);
result = decLine.getCoordinatesBetween(0.0, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.0, 0.0, 3.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[4]);
result = decLine.getCoordinatesBetween(0.5, 1.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(3, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(1.5, 0.0, 1.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[crds.length - 1]);
result = decLine.getCoordinatesBetween(3.5, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[crds.length - 1]);
result = decLine.getCoordinatesBetween(3.5, 3.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.7, 0.0, 3.7), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[1]);
result = decLine.getCoordinatesBetween(0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[1]);
result = decLine.getCoordinatesBetween(-0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[1]);
result = decLine.getCoordinatesBetween(3.5, 4.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[0]);
}
@Test
public void test_measures_partially_constant_decreasing() throws MGeometryException {
CoordinateSequence[] result;
result = partiallyConstantDecreasing.getCoordinatesBetween(0.5, 3.5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(6, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[crds.length - 1]);
result = partiallyConstantDecreasing.getCoordinatesBetween(1.0, 3.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(4, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 3.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.0, 0.0, 2.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0), crds[2]);
assertEquals(MCoordinate.create2dWithMeasure(1.0, 0.0, 1.0), crds[3]);
result = partiallyConstantDecreasing.getCoordinatesBetween(0.0, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(6, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 3.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[5]);
result = partiallyConstantDecreasing.getCoordinatesBetween(0.5, 1.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(3, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(1.5, 0.0, 1.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[crds.length - 1]);
result = partiallyConstantDecreasing.getCoordinatesBetween(1.5, 2.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(4, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 2.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.0, 0.0, 2.0), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(2.0, 0.0, 2.0), crds[2]);
assertEquals(MCoordinate.create2dWithMeasure(1.5, 0.0, 1.5), crds[3]);
result = partiallyConstantDecreasing.getCoordinatesBetween(3.5, 4.0);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.5, 0.0, 3.5), crds[crds.length - 1]);
result = partiallyConstantDecreasing.getCoordinatesBetween(3.5, 3.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.7, 0.0, 3.7), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.5, 0.0, 3.5), crds[1]);
result = partiallyConstantDecreasing.getCoordinatesBetween(0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[1]);
result = partiallyConstantDecreasing.getCoordinatesBetween(-0.5, 0.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.7, 0.0, 0.7), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[1]);
result = partiallyConstantDecreasing.getCoordinatesBetween(3.5, 4.7);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(2, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.5, 0.0, 3.5), crds[1]);
assertEquals(MCoordinate.create2dWithMeasure(5.0, 0.0, 4.0), crds[0]);
}
@Test
public void test_measure_outside_monotone_increasing() throws MGeometryException {
CoordinateSequence[] result;
result = incrLine.getCoordinatesBetween(-1.5, -0.5);
assertEquals(1, result.length);
assertEquals(0, result[0].size());
result = incrLine.getCoordinatesBetween(10.0, 20.0);
assertEquals(1, result.length);
assertEquals(0, result[0].size());
}
@Test
public void test_measure_outside_monotone_decreasing() throws MGeometryException {
CoordinateSequence[] result;
result = decLine.getCoordinatesBetween(-1.5, -0.5);
assertEquals(1, result.length);
assertEquals(0, result[0].size());
result = decLine.getCoordinatesBetween(10.0, 20.0);
assertEquals(1, result.length);
assertEquals(0, result[0].size());
}
@Test
public void test_measure_overlap_monotone_increasing() throws MGeometryException {
CoordinateSequence[] result;
result = incrLine.getCoordinatesBetween(-0.5, 5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[crds.length - 1]);
result = incrLine.getCoordinatesBetween(0.5, 5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[crds.length - 1]);
result = incrLine.getCoordinatesBetween(-1.0, 2.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(4, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(2.5, 0.0, 2.5), crds[crds.length - 1]);
result = incrLine.getCoordinatesBetween(4.0, 5.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(1, crds.length);
}
@Test
public void test_measure_overlap_monotone_decreasing() throws MGeometryException {
CoordinateSequence[] result;
result = decLine.getCoordinatesBetween(-0.5, 5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[crds.length - 1]);
result = decLine.getCoordinatesBetween(0.5, 5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(4.0, 0.0, 4.0), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[crds.length - 1]);
result = decLine.getCoordinatesBetween(-1.0, 2.5);
assertEquals(1, result.length);
crds = result[0].toCoordinateArray();
assertEquals(4, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(2.5, 0.0, 2.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.0, 0.0, 0.0), crds[crds.length - 1]);
}
@Test
public void test_measure_inverse_monotone_increasing() throws MGeometryException {
CoordinateSequence[] result;
result = incrLine.getCoordinatesBetween(3.5, 0.5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[crds.length - 1]);
}
@Test
public void test_measure_inverse_monotone_decreasing() throws MGeometryException {
CoordinateSequence[] result;
result = decLine.getCoordinatesBetween(3.5, 0.5);
assertEquals(1, result.length);
Coordinate[] crds = result[0].toCoordinateArray();
assertEquals(5, crds.length);
assertEquals(MCoordinate.create2dWithMeasure(3.5, 0.0, 3.5), crds[0]);
assertEquals(MCoordinate.create2dWithMeasure(0.5, 0.0, 0.5), crds[crds.length - 1]);
}
@Test
public void test_fail_on_non_monotone() throws MGeometryException {
try {
nonMonotoneLine.getCoordinatesBetween(0.5, 10.0);
fail("Needs to throw an IllegalArgumentException on non-monotone linestrings.");
} catch (MGeometryException e) {
assertEquals(e.getType(), MGeometryException.OPERATION_REQUIRES_MONOTONE);
}
}
}

View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<!--
~ $Id: GeomEntity.hbm.xml 242 2010-09-22 20:40:07Z maesenka $
~
~ This file is part of Hibernate Spatial, an extension to the
~ hibernate ORM solution for geographic data.
~
~ Copyright © 2007-2010 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
~
~ For more information, visit: http://www.hibernatespatial.org/
-->
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
" http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.hibernate.spatial.test.GeomEntity" table="GEOMTEST">
<id name="id" type="integer">
<generator class="assigned"/>
</id>
<property name="type" type="string">
<column name="type" length="50"/>
</property>
<property name="geom" type="org.hibernate.spatial.GeometryType">
<column name="geom"/>
</property>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,37 @@
#
# Hibernate, Relational Persistence for Idiomatic Java
#
# Copyright (c) 2010, Red Hat Inc. or third-party contributors as
# indicated by the @author tags or express copyright attribution
# statements applied by the authors. All third-party contributions are
# distributed under license by Red Hat Inc.
#
# This copyrighted material is made available to anyone wishing to use, modify,
# copy, or redistribute it subject to the terms and conditions of the GNU
# Lesser General Public License, as published by the Free Software Foundation.
#
# This program 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 distribution; if not, write to:
# Free Software Foundation, Inc.
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301 USA
#
hibernate.dialect org.hibernate.spatial.dialect.postgis.PostgisDialect
hibernate.connection.driver_class org.postgresql.Driver
hibernate.connection.url jdbc:postgresql://localhost:5432:hibbrtru
hibernate.connection.username hibbrtru
hibernate.connection.password hibbrtru
hibernate.connection.pool_size 5
hibernate.show_sql true
hibernate.max_fetch_depth 5
hibernate.cache.region_prefix hibernate.test
hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFactory

View File

@ -0,0 +1,9 @@
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=info, stdout
log4j.logger.org.hibernate.spatial=debug

View File

@ -0,0 +1,78 @@
<TestData>
<!-- points -->
<Element>
<id>1</id>
<type>POINT</type>
<wkt>POINT(10 5)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>2</id>
<type>POINT</type>
<wkt>POINT(79 79)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>3</id>
<type>POINT</type>
<wkt>POINT(50 50)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>4</id>
<type>POINT</type>
<wkt>POINT(10 20)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>5</id>
<type>POINT</type>
<wkt>POINT(-4 -5)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>6</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0, 20.0 15.0)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>7</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>8</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>9</id>
<type>MULTILINESTRING</type>
<wkt>MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0))
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>10</id>
<type>POLYGON</type>
<wkt>POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) )</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>11</id>
<type>MULTIPOLYGON</type>
<wkt>MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((15 10, 12 14, 13 13, 15 10)) )</wkt>
<srid>4326</srid>
</Element>
</TestData>

View File

@ -0,0 +1,298 @@
<TestData>
<Element>
<id>1</id>
<type>POINT</type>
<wkt>POINT(10 5)</wkt>
<srid>0</srid>
</Element>
<Element>
<id>2</id>
<type>POINT</type>
<wkt>POINT(52.25 2.53)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>3</id>
<type>POINT</type>
<wkt>POINT(150000 200000)</wkt>
<srid>31370</srid>
</Element>
<Element>
<id>4</id>
<type>POINT</type>
<wkt>POINT(10.0 2.0 1.0 3.0)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>5</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0, 20.0 15.0)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>6</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>7</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0 0.0, 20.0 15.0 3.0)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>8</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0 0.0 0.0, 20.0 15.0 3.0 1.0)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>9</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>10</id>
<type>LINESTRING</type>
<wkt>LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>11</id>
<type>MULTILINESTRING</type>
<wkt>MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>12</id>
<type>MULTILINESTRING</type>
<wkt>MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0))
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>13</id>
<type>MULTILINESTRING</type>
<wkt>MULTILINESTRING((10.0 5.0 1.0, 20.0 15.0 2.0, 30.3 22.4 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 1.0,
43.0 16.0 2.0, 40 14.0 3.0))
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>14</id>
<type>MULTILINESTRING</type>
<wkt>MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0
3.0, 42.0 18.0 1.0 4.0, 43.0 16.0 2.0 5.0, 40 14.0 3.0 6.0))
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>15</id>
<type>MULTILINESTRING</type>
<wkt>MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>16</id>
<type>POLYGON</type>
<wkt>POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) )</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>17</id>
<type>POLYGON</type>
<wkt>POLYGON( (0 0 0, 0 10 1, 10 10 1, 10 0 1, 0 0 0) )</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>18</id>
<type>POLYGON</type>
<wkt>POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>19</id>
<type>POLYGON</type>
<wkt>POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) )</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>20</id>
<type>MULTIPOLYGON</type>
<wkt>MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) )</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>21</id>
<type>MULTIPOLYGON</type>
<wkt>MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) )
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>22</id>
<type>MULTIPOLYGON</type>
<wkt>MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130
134, 105 100)) )
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>25</id>
<type>MULTIPOINT</type>
<wkt>MULTIPOINT(21 2, 25 5, 30 3)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>26</id>
<type>MULTIPOINT</type>
<wkt>MULTIPOINT(21 2)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>27</id>
<type>MULTIPOINT</type>
<wkt>MULTIPOINT(21 2 1, 25 5 2, 30 3 5)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>28</id>
<type>MULTIPOINT</type>
<wkt>MULTIPOINT(21 2 1 0, 25 5 2 4, 30 3 5 2)</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>30</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>31</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0)))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>32</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2,
1 1)))
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>33</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100,
120 140, 130 134, 105 100)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)))
</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>34</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), POINT EMPTY, LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>35</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), LINESTRING EMPTY, LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>36</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), GEOMETRYCOLLECTION EMPTY, LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>37</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), POLYGON EMPTY, LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>38</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), MULTILINESTRING EMPTY, LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>39</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), MULTIPOINT EMPTY, LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>40</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION(POINT(4 0), MULTIPOLYGON EMPTY, LINESTRING(4 2, 5 3))</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>50</id>
<type>POINT</type>
<wkt>POINT EMPTY</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>51</id>
<type>LINESTRING</type>
<wkt>LINESTRING EMPTY</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>52</id>
<type>POLYGON</type>
<wkt>POLYGON EMPTY</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>53</id>
<type>MULTIPOINT</type>
<wkt>MULTIPOINT EMPTY</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>54</id>
<type>MULTILINESTRING</type>
<wkt>MULTILINESTRING EMPTY</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>55</id>
<type>MULTIPOLYGON</type>
<wkt>MULTIPOLYGON EMPTY</wkt>
<srid>4326</srid>
</Element>
<Element>
<id>56</id>
<type>GEOMETRYCOLLECTION</type>
<wkt>GEOMETRYCOLLECTION EMPTY</wkt>
<srid>4326</srid>
</Element>
</TestData>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-spatial>
<default_dialect>org.hibernate.spatial.postgis.PostgisDialect</default_dialect>
<precision_model>FIXED</precision_model>
<precision_model_scale>5</precision_model_scale>
</hibernate-spatial>

View File

@ -6,6 +6,7 @@ include 'hibernate-core'
include 'hibernate-testing'
include 'hibernate-entitymanager'
include 'hibernate-envers'
include 'hibernate-spatial'
include 'hibernate-java8'