I've come up with a very simple interface for projection algorithms. The
purpose of this is to be model neutral (not tied to JTS), as such it is
not for use by end users but instead for use in higher level libraries
that would work on JTS geometries.
public interface Projection {
void forward();
void reverse();
double getX();
void setX(double x);
double getY();
void setY(double y);
}
To perform a forward projection the code would be as follows.
projection.setX(lonDegrees);
projection.setY(latDegrees);
projection.forward();
x = projection.getX();
y = projection.getY();
Reverse projection would be similar.
projection.setX(xMetres);
projection.setY(yMetres);
projection.reverse();
lonDegrees = projection.getX();
latDegrees = projection.getY();
NOTE: The interface is not thread safe.
The design goals were it must be simple and not require any temporary
objects.
A JTS wrapper for this would have the following two basic methods
public Coordinate forward(double x, double y, double z) {
projection.setX(x);
projection.setY(y);
projection.forward();
Coordinate coordinate = new Coordinate(projection.getX(),
projection.getY(),z);
forwardPrecisionModel.makePrecise(coordinate);
return coordinate;
}
public Coordinate reverse(double x, double y, double z) {
projection.setX(x);
projection.setY(y);
projection.reverse();
Coordinate coordinate = new Coordinate(projection.getX(),
projection.getY(),z);
reversePrecisionModel.makePrecise(coordinate);
return coordinate;
}
plus a number of other methods to deal with all the JTS Geometry types,
see attached for full implementation. Note that there could be a
performance optimization for coordinate sequences to directly deal with
the Projection interface.
Most projections go to/from Geographics to a Cartesian system to go from
one Cartesian to another Cartesian you would need a chained projection
which goes from one to another.
The last piece in the puzzle is to have a ProjectionFactory that can
create projections from EPSG srid codes. There can be many factory
implementations, e.g. one to wrap FME, one to wrap the Java Projection
Library, one for JUMP specific projections and one for GeoTools. You
would then interact with an instance of the factory to create your
projections and then use either the Projection interface or the
JtsProjection wrapper.
What do you guys think?
Paul
package com.revolsys.gis.projection.jts;
import com.revolsys.gis.projection.Projection;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
public class JtsProjection {
private GeometryFactory forwardGeometryFactory;
private GeometryFactory reverseGeometryFactory;
private Projection projection;
private PrecisionModel forwardPrecisionModel;
private PrecisionModel reversePrecisionModel;
public JtsProjection(Projection projection) {
this(new GeometryFactory(), new GeometryFactory(), projection);
}
public JtsProjection(GeometryFactory forwardGeometryFactory, GeometryFactory reverseGeometryFactory, Projection projection) {
this.forwardGeometryFactory = forwardGeometryFactory;
this.reverseGeometryFactory = reverseGeometryFactory;
this.projection = projection;
forwardPrecisionModel = forwardGeometryFactory.getPrecisionModel();
reversePrecisionModel = reverseGeometryFactory.getPrecisionModel();
}
public JtsProjection(GeometryFactory forwardGeometryFactory, Projection projection) {
this(forwardGeometryFactory, new GeometryFactory(), projection);
}
public Coordinate forward(double x, double y, double z) {
projection.setX(x);
projection.setY(y);
projection.forward();
Coordinate coordinate = new Coordinate(projection.getX(), projection.getY(),z);
forwardPrecisionModel.makePrecise(coordinate);
return coordinate;
}
public Coordinate reverse(double x, double y, double z) {
projection.setX(x);
projection.setY(y);
projection.reverse();
Coordinate coordinate = new Coordinate(projection.getX(), projection.getY(),z);
reversePrecisionModel.makePrecise(coordinate);
return coordinate;
}
public Envelope forward(final Envelope envelope) {
Coordinate min = forward(envelope.getMinX(), envelope.getMinY());
Coordinate max = forward(envelope.getMaxX(), envelope.getMaxY());
return new Envelope(min, max);
}
public Geometry forward(Geometry geometry) {
if (geometry instanceof Point) {
Point point = (Point)geometry;
return forward(point);
} else if (geometry instanceof LineString) {
LineString line = (LineString)geometry;
return forward(line);
} else if (geometry instanceof Polygon) {
Polygon polygon = (Polygon)geometry;
return forward(polygon);
} else if (geometry instanceof MultiPoint) {
MultiPoint point = (MultiPoint)geometry;
return forward(point);
} else if (geometry instanceof MultiLineString) {
MultiLineString line = (MultiLineString)geometry;
return forward(line);
} else if (geometry instanceof MultiPolygon) {
MultiPolygon polygon = (MultiPolygon)geometry;
return forward(polygon);
} else {
return geometry;
}
}
public Point forward(final Point point) {
if (point != null) {
Coordinate newCoordinate = forward(point.getCoordinate());
Point newPoint = forwardGeometryFactory.createPoint(newCoordinate);
addUserData(point, newPoint);
return newPoint;
} else {
return null;
}
}
public LineString forward(final LineString line) {
if (line != null) {
Coordinate[] newCoordinates = forward(line.getCoordinates());
LineString newLine = forwardGeometryFactory.createLineString(newCoordinates);
addUserData(line, newLine);
return newLine;
} else {
return null;
}
}
public Polygon forward(final Polygon polygon) {
LinearRing shell = (LinearRing)polygon.getExteriorRing();
LinearRing newShell = forward(shell);
LinearRing[] newHoles = new LinearRing[polygon.getNumInteriorRing()];
for (int i = 0; i < newHoles.length; i++) {
LinearRing hole = (LinearRing)polygon.getInteriorRingN(i);
newHoles[i] = forward(hole);
}
Polygon newPolygon = forwardGeometryFactory.createPolygon(newShell,
newHoles);
addUserData(newPolygon, polygon);
return newPolygon;
}
public MultiPoint forward(final MultiPoint multiPoint) {
if (multiPoint != null) {
Point[] newPoints = new Point[multiPoint.getNumGeometries()];
for (int i = 0; i < multiPoint.getNumGeometries(); i++) {
Point point = (Point)multiPoint.getGeometryN(i);
Point newPoint = forward(point);
addUserData(point, newPoint);
newPoints[i] = newPoint;
}
MultiPoint newMultiPoint = forwardGeometryFactory.createMultiPoint(newPoints);
addUserData(multiPoint, newMultiPoint);
return newMultiPoint;
} else {
return null;
}
}
public MultiLineString forward(final MultiLineString multiLineString) {
if (multiLineString != null) {
LineString[] newLineStrings = new LineString[multiLineString.getNumGeometries()];
for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
LineString line = (LineString)multiLineString.getGeometryN(i);
LineString newLineString = forward(line);
addUserData(line, newLineString);
newLineStrings[i] = newLineString;
}
MultiLineString newMultiLineString = forwardGeometryFactory.createMultiLineString(newLineStrings);
addUserData(multiLineString, newMultiLineString);
return newMultiLineString;
} else {
return null;
}
}
public MultiPolygon forward(final MultiPolygon multiPolygon) {
if (multiPolygon != null) {
Polygon[] newPolygons = new Polygon[multiPolygon.getNumGeometries()];
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
Polygon polygon = (Polygon)multiPolygon.getGeometryN(i);
Polygon newPolygon = forward(polygon);
addUserData(polygon, newPolygon);
newPolygons[i] = newPolygon;
}
MultiPolygon newMultiPolygon = forwardGeometryFactory.createMultiPolygon(newPolygons);
addUserData(multiPolygon, newMultiPolygon);
return newMultiPolygon;
} else {
return null;
}
}
public LinearRing forward(final LinearRing ring) {
if (ring != null) {
CoordinateSequence newCoordinates = forward(ring.getCoordinateSequence());
LinearRing newRing = forwardGeometryFactory.createLinearRing(newCoordinates);
addUserData(ring, newRing);
return newRing;
} else {
return null;
}
}
public Coordinate[] forward(final Coordinate[] coordinates) {
Coordinate[] newCoordinates = new Coordinate[coordinates.length];
for (int i = 0; i < coordinates.length; i++) {
Coordinate coordinate = coordinates[i];
newCoordinates[i] = forward(coordinate);
}
return newCoordinates;
}
public CoordinateSequence forward(final CoordinateSequence coordinates) {
CoordinateSequence newCoordinates = new CoordinateArraySequence(
coordinates.size());
for (int i = 0; i < coordinates.size(); i++) {
Coordinate coordinate = coordinates.getCoordinate(i);
Coordinate projectedCoordinate = forward(coordinate);
newCoordinates.setOrdinate(i, 0, projectedCoordinate.x);
newCoordinates.setOrdinate(i, 1, projectedCoordinate.y);
newCoordinates.setOrdinate(i, 2, projectedCoordinate.z);
}
return newCoordinates;
}
public Coordinate forward(final Coordinate coordinate) {
return forward(coordinate.x, coordinate.y, coordinate.z);
}
public Coordinate forward(double x, double y) {
return forward(x, y, Double.NaN);
}
public Envelope reverse(final Envelope envelope) {
Coordinate min = reverse(envelope.getMinX(), envelope.getMinY());
Coordinate max = reverse(envelope.getMaxX(), envelope.getMaxY());
return new Envelope(min, max);
}
public Geometry reverse(Geometry geometry) {
if (geometry instanceof Point) {
Point point = (Point)geometry;
return projectInverse(point);
} else if (geometry instanceof LineString) {
LineString line = (LineString)geometry;
return reverse(line);
} else if (geometry instanceof Polygon) {
Polygon polygon = (Polygon)geometry;
return reverse(polygon);
} else if (geometry instanceof MultiPoint) {
MultiPoint point = (MultiPoint)geometry;
return projectInverse(point);
} else if (geometry instanceof MultiLineString) {
MultiLineString line = (MultiLineString)geometry;
return projectInverse(line);
} else if (geometry instanceof MultiPolygon) {
MultiPolygon polygon = (MultiPolygon)geometry;
return projectInverse(polygon);
} else {
return geometry;
}
}
public Point projectInverse(final Point point) {
if (point != null) {
Coordinate newCoordinate = reverse(point.getCoordinate());
Point newPoint = reverseGeometryFactory.createPoint(newCoordinate);
addUserData(point, newPoint);
return newPoint;
} else {
return null;
}
}
public LineString reverse(final LineString line) {
if (line != null) {
Coordinate[] newCoordinates = reverse(line.getCoordinates());
LineString newLine = reverseGeometryFactory.createLineString(newCoordinates);
addUserData(line, newLine);
return newLine;
} else {
return null;
}
}
public Polygon reverse(final Polygon polygon) {
LinearRing shell = (LinearRing)polygon.getExteriorRing();
LinearRing newShell = reverse(shell);
LinearRing[] newHoles = new LinearRing[polygon.getNumInteriorRing()];
for (int i = 0; i < newHoles.length; i++) {
LinearRing hole = (LinearRing)polygon.getInteriorRingN(i);
newHoles[i] = reverse(hole);
}
Polygon newPolygon = reverseGeometryFactory.createPolygon(newShell,
newHoles);
addUserData(newPolygon, polygon);
return newPolygon;
}
public MultiPoint projectInverse(final MultiPoint multiPoint) {
if (multiPoint != null) {
Point[] newPoints = new Point[multiPoint.getNumGeometries()];
for (int i = 0; i < multiPoint.getNumGeometries(); i++) {
Point point = (Point)multiPoint.getGeometryN(i);
Point newPoint = projectInverse(point);
addUserData(point, newPoint);
newPoints[i] = newPoint;
}
MultiPoint newMultiPoint = reverseGeometryFactory.createMultiPoint(newPoints);
addUserData(multiPoint, newMultiPoint);
return newMultiPoint;
} else {
return null;
}
}
public MultiLineString projectInverse(final MultiLineString multiLineString) {
if (multiLineString != null) {
LineString[] newLineStrings = new LineString[multiLineString.getNumGeometries()];
for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
LineString line = (LineString)multiLineString.getGeometryN(i);
LineString newLineString = reverse(line);
addUserData(line, newLineString);
newLineStrings[i] = newLineString;
}
MultiLineString newMultiLineString = reverseGeometryFactory.createMultiLineString(newLineStrings);
addUserData(multiLineString, newMultiLineString);
return newMultiLineString;
} else {
return null;
}
}
public MultiPolygon projectInverse(final MultiPolygon multiPolygon) {
if (multiPolygon != null) {
Polygon[] newPolygons = new Polygon[multiPolygon.getNumGeometries()];
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
Polygon polygon = (Polygon)multiPolygon.getGeometryN(i);
Polygon newPolygon = reverse(polygon);
addUserData(polygon, newPolygon);
newPolygons[i] = newPolygon;
}
MultiPolygon newMultiPolygon = reverseGeometryFactory.createMultiPolygon(newPolygons);
addUserData(multiPolygon, newMultiPolygon);
return newMultiPolygon;
} else {
return null;
}
}
public LinearRing reverse(final LinearRing ring) {
if (ring != null) {
CoordinateSequence newCoordinates = reverse(ring.getCoordinateSequence());
LinearRing newRing = reverseGeometryFactory.createLinearRing(newCoordinates);
addUserData(ring, newRing);
return newRing;
} else {
return null;
}
}
public Coordinate[] reverse(final Coordinate[] coordinates) {
Coordinate[] newCoordinates = new Coordinate[coordinates.length];
for (int i = 0; i < coordinates.length; i++) {
Coordinate coordinate = coordinates[i];
newCoordinates[i] = reverse(coordinate);
}
return newCoordinates;
}
public CoordinateSequence reverse(final CoordinateSequence coordinates) {
CoordinateSequence newCoordinates = new CoordinateArraySequence(
coordinates.size());
for (int i = 0; i < coordinates.size(); i++) {
Coordinate coordinate = coordinates.getCoordinate(i);
Coordinate projectedCoordinate = reverse(coordinate);
newCoordinates.setOrdinate(i, 0, projectedCoordinate.x);
newCoordinates.setOrdinate(i, 1, projectedCoordinate.y);
newCoordinates.setOrdinate(i, 2, projectedCoordinate.z);
}
return newCoordinates;
}
public Coordinate reverse(final Coordinate coordinate) {
return reverse(coordinate.x, coordinate.y, coordinate.z);
}
public Coordinate reverse(double x, double y) {
return reverse(x, y, Double.NaN);
}
public GeometryFactory getReverseGeometryFactory() {
return reverseGeometryFactory;
}
public GeometryFactory getForwardGeometryFactory() {
return forwardGeometryFactory;
}
private void addUserData(Geometry oldGeometry, Geometry newGeometry) {
Object userData = oldGeometry.getUserData();
if (userData != null) {
// TODO clone data?
newGeometry.setUserData(userData);
}
}
}
package com.revolsys.gis.projection.rs;
import com.revolsys.gis.projection.Projection;
public class ChainedProjection implements Projection {
private Projection sourceProjection;
private Projection targetProjection;
private double y;
private double x;
public ChainedProjection(Projection sourceProjection,
Projection targetProjection) {
this.sourceProjection = sourceProjection;
this.targetProjection = targetProjection;
}
public void forward() {
sourceProjection.setX(x);
sourceProjection.setY(y);
sourceProjection.forward();
targetProjection.setX(sourceProjection.getX());
targetProjection.setY(sourceProjection.getY());
targetProjection.reverse();
x = targetProjection.getX();
y = targetProjection.getY();
}
public void reverse() {
sourceProjection.setX(x);
sourceProjection.setY(y);
sourceProjection.reverse();
targetProjection.setX(sourceProjection.getX());
targetProjection.setY(sourceProjection.getY());
targetProjection.forward();
x = targetProjection.getX();
y = targetProjection.getY();
}
public double getX() {
return x;
}
public void setX(double x) {
this.x= x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel