/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* 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;
* version 2.1 of the License.
*
* 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.
*/
package org.geotools.geometry.iso.primitive;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.geotools.factory.Factory;
import org.geotools.factory.GeoTools;
import org.geotools.factory.Hints;
import org.geotools.geometry.GeometryFactoryFinder;
import org.geotools.geometry.iso.coordinate.DirectPositionImpl;
import org.geotools.geometry.iso.coordinate.LineSegmentImpl;
import org.geotools.geometry.iso.coordinate.LineStringImpl;
import org.geotools.geometry.iso.coordinate.PointArrayImpl;
import org.geotools.geometry.iso.coordinate.PositionImpl;
import org.geotools.geometry.iso.coordinate.SurfacePatchImpl;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.geometry.MismatchedReferenceSystemException;
import org.opengis.geometry.PositionFactory;
import org.opengis.geometry.coordinate.LineSegment;
import org.opengis.geometry.coordinate.Position;
import org.opengis.geometry.primitive.Curve;
import org.opengis.geometry.primitive.CurveSegment;
import org.opengis.geometry.primitive.OrientableCurve;
import org.opengis.geometry.primitive.Point;
import org.opengis.geometry.primitive.PrimitiveFactory;
import org.opengis.geometry.primitive.Ring;
import org.opengis.geometry.primitive.SolidBoundary;
import org.opengis.geometry.primitive.SurfaceBoundary;
import org.opengis.geometry.primitive.SurfacePatch;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystemAxis;
/**
* @author Jackson Roehrig & Sanjay Jena
*
*
*
* @source $URL$
*/
public class PrimitiveFactoryImpl implements Serializable, Factory, PrimitiveFactory {
/**
*
*/
private static final long serialVersionUID = 1L;
private CoordinateReferenceSystem crs;
private PositionFactory positionFactory;
private Boolean geomValidate;
/** Map of hints we care about during construction, used by FactoryFinder/Registry madness */
private Map hintsWeCareAbout = new HashMap();
/** FactorySPI entry point */
public PrimitiveFactoryImpl() {
this(null );
}
/** Just the defaults, use GeometryFactoryFinder for the rest */
public PrimitiveFactoryImpl( Hints hints ) {
if (hints == null) {
this.crs = DefaultGeographicCRS.WGS84;
hints = GeoTools.getDefaultHints();
hints.put(Hints.CRS, crs );
geomValidate = true;
hints.put(Hints.GEOMETRY_VALIDATE, geomValidate);
}
else {
this.crs = (CoordinateReferenceSystem) hints.get( Hints.CRS );
if( crs == null ){
throw new NullPointerException("A CRS Hint is required in order to use PrimitiveFactoryImpl");
}
geomValidate = (Boolean) hints.get( Hints.GEOMETRY_VALIDATE );
if (geomValidate == null) {
geomValidate = true;
}
}
this.positionFactory = GeometryFactoryFinder.getPositionFactory(hints);
hintsWeCareAbout.put(Hints.CRS, crs );
hintsWeCareAbout.put(Hints.POSITION_FACTORY, positionFactory );
hintsWeCareAbout.put(Hints.GEOMETRY_VALIDATE, geomValidate );
}
/**
* @param crs
*/
public PrimitiveFactoryImpl(CoordinateReferenceSystem crs, PositionFactory positionFactory) {
this.crs = crs;
if( crs == null ){
throw new NullPointerException("A non null crs is required in order to use PrimitiveFactoryImpl");
}
if (positionFactory == null) {
Hints hints = GeoTools.getDefaultHints();
hints.put(Hints.CRS, crs );
this.positionFactory = GeometryFactoryFinder.getPositionFactory(hints);
}
else {
this.positionFactory = positionFactory;
}
geomValidate = true;
hintsWeCareAbout.put(Hints.CRS, crs );
hintsWeCareAbout.put(Hints.POSITION_FACTORY, positionFactory );
hintsWeCareAbout.put(Hints.GEOMETRY_VALIDATE, geomValidate );
}
/** These are the hints we used */
public Map getImplementationHints() {
return Collections.unmodifiableMap( hintsWeCareAbout );
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#getCoordinateReferenceSystem()
*/
public CoordinateReferenceSystem getCoordinateReferenceSystem() {
// TODO test
// TODO documentation
return this.crs;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#getCoordinateReferenceSystem()
*/
public PositionFactory getPositionFactory() {
// TODO test
// TODO documentation
return this.positionFactory;
}
/**
* Returns the Coordinate Dimension of the used Coordinate System (Sanjay)
*
* @return dimension Coordinate Dimension used in this Factory
*/
public int getDimension() {
// Test OK
return this.crs.getCoordinateSystem().getDimension();
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createPoint(double[])
*/
public PointImpl createPoint(double[] coord) {
// Test ok
if (coord == null)
throw new NullPointerException();
if (coord.length != this.getDimension())
throw new MismatchedDimensionException();
return new PointImpl(positionFactory.createDirectPosition(coord));
}
/**
* Creates a Point by copying the coordinates of a given DirectPosition
*
* @param dp
* DirectPosition, will be copied
* @return PointImpl
*/
public PointImpl createPoint(DirectPositionImpl dp) {
if (dp == null)
throw new NullPointerException();
// Test ok
// Compare Dimension (which is the Coordinate Dimension) of the
// DirectPosition with the CoordinateDimension of the current Coordinate
// System in Euclidian Space
if (dp.getDimension() != this.getDimension())
throw new MismatchedDimensionException();
return new PointImpl(dp.clone());
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createPoint(org.opengis.geometry.coordinate.Position)
*/
public PointImpl createPoint(Position position)
throws MismatchedReferenceSystemException,
MismatchedDimensionException {
// Test ok
if (position == null) {
throw new IllegalArgumentException("Parameter position is null.");
}
if (position.getPosition().getDimension() != this.getDimension()) {
throw new MismatchedDimensionException();
}
DirectPosition copy = positionFactory.createDirectPosition(position.getPosition().getCoordinates());
return new PointImpl(copy);
}
/**
* Creates a CurveBoundary
*
* @param dp0
* @param dp1
* @return CurveBoundaryImpl
*/
public CurveBoundaryImpl createCurveBoundary(DirectPosition dp0,
DirectPosition dp1) {
// Test OK (Sanjay)
if (dp0 == null || dp1 == null)
throw new NullPointerException(
"One or both of the parameters is NULL");
return new CurveBoundaryImpl(getCoordinateReferenceSystem(),
createPoint(dp0),
createPoint(dp1));
}
/**
* Creates a CurveBoundary
*
* @param p0
* @param p1
* @return CurveBoundaryImpl
*/
public CurveBoundaryImpl createCurveBoundary(Point p0, Point p1) {
if (p0 == null || p1 == null)
throw new NullPointerException(
"One or both of the parameters is NULL");
return new CurveBoundaryImpl(getCoordinateReferenceSystem(), p0, p1);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createCurve(java.util.List)
*/
public CurveImpl createCurve(List<CurveSegment> segments) {
// test OK
if (segments == null)
throw new NullPointerException();
// A curve will be created
// - The curve will be set as parent curves for the Curve segments
// - Start and end params for the CurveSegments will be set
return new CurveImpl(getCoordinateReferenceSystem(), segments);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createRing(java.util.List)
*/
public Ring createRing(List<OrientableCurve> orientableCurves)
throws MismatchedReferenceSystemException,
MismatchedDimensionException {
/**
* Creates a Ring from triple Array of DirectPositions (Array of arrays,
* which each represent a future Curve. Each array contain an array of
* positions, which each represent a future lineString)
*/
// TODO semantic JR
// test OK
for (OrientableCurve orientableCurve : orientableCurves) {
// Comment by Sanjay
// TODO JR: Zur Kenntnisnahme und Berücksichtigung in Sourcen: Für
// alle
// Primitives gilt, dass getDimension die Dimension des Objektes,
// und getCoordinateDimension die Dimension des Koordinatensystems,
// in welchem das Objekt instanziert wurde, wiedergibt
// if (this.getDimension() != orientableCurve.getDimension(null)) {
if (this.getDimension() != orientableCurve.getCoordinateDimension()) {
throw new MismatchedDimensionException();
}
if (!CRS.equalsIgnoreMetadata(this.getCoordinateReferenceSystem(), orientableCurve
.getCoordinateReferenceSystem()) ) {
throw new MismatchedReferenceSystemException();
}
}
// if we don't want to validate the ring upon creation (for faster creation) use
// RingImplUnsafe instead of RingImpl
if ( geomValidate ) {
return new RingImpl(orientableCurves);
}
else {
return new RingImplUnsafe(orientableCurves);
}
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createSurfaceBoundary(org.opengis.geometry.primitive.Ring,
* java.util.List)
*/
public SurfaceBoundaryImpl createSurfaceBoundary(Ring exterior,
List<Ring> interiors) throws MismatchedReferenceSystemException,
MismatchedDimensionException {
// Test ok
if (interiors == null && exterior == null)
throw new NullPointerException();
CoordinateReferenceSystem thisCRS = this.getCoordinateReferenceSystem();
if (exterior != null) {
if (this.getDimension() != exterior.getCoordinateDimension()) {
throw new MismatchedDimensionException();
}
CoordinateReferenceSystem exteriorCRS = exterior
.getCoordinateReferenceSystem();
if (!CRS.equalsIgnoreMetadata(thisCRS,exteriorCRS)) {
throw new MismatchedReferenceSystemException();
}
}
if (interiors != null) {
for (Ring ring : interiors) {
if (ring != null) {
if (this.getDimension() != ring.getCoordinateDimension()) {
throw new MismatchedDimensionException();
}
if (!CRS.equalsIgnoreMetadata(thisCRS, ring
.getCoordinateReferenceSystem()) ) {
throw new MismatchedReferenceSystemException();
}
}
}
}
return new SurfaceBoundaryImpl(getCoordinateReferenceSystem(),
exterior, interiors);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createSurface(java.util.List)
*/
public SurfaceImpl createSurface(List<SurfacePatch> surfacePatches)
throws MismatchedReferenceSystemException,
MismatchedDimensionException {
// tested in /test/TestSurface.java
// TODO SurfaceBoundary NOT calculated !!!
// Create Surface
SurfaceImpl rSurface = new SurfaceImpl(getCoordinateReferenceSystem(),
surfacePatches);
// Set reference to the generated Surface for each SurfacePatch
for (int i = 0; i < surfacePatches.size(); i++) {
SurfacePatchImpl actPatch = (SurfacePatchImpl) surfacePatches
.get(i);
actPatch.setSurface(rSurface);
}
return rSurface;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createSurface(org.opengis.geometry.primitive.SurfaceBoundary)
*/
public SurfaceImpl createSurface(SurfaceBoundary boundary)
throws MismatchedReferenceSystemException,
MismatchedDimensionException {
// Test ok
// Creates a Surface without SurfacePatches
return new SurfaceImpl(boundary);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createSolid(org.opengis.geometry.primitive.SolidBoundary)
*/
public SolidImpl createSolid(SolidBoundary boundary)
throws MismatchedReferenceSystemException,
MismatchedDimensionException {
// TODO semantic SJ, JR
// TODO implementation
// TODO test
// TODO documentation
return new SolidImpl(boundary);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createPrimitive(org.opengis.geometry.coordinate.Envelope)
*/
// public PrimitiveImpl createPrimitive_try2(Envelope envelope)
// throws MismatchedReferenceSystemException,
// MismatchedDimensionException {
//
// List<DirectPosition> positions = new ArrayList<DirectPosition>();
//
// for (int d = 0; d < crs.getCoordinateSystem().getDimension(); d++) {
// CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis(d);
// AxisDirection direction = axis.getDirection();
// double min, max;
// if (direction == AxisDirection.OTHER) {
// // we are going to "skip" min/max calculation on OTHER
// // used for 2.5 D stuff
// min = Double.NaN;
// max = Double.NaN;
// } else {
// // figure out min & max from envelope
// min = envelope.getMinimum(d);
// max = envelope.getMaximum(d);
// }
// if (positions.isEmpty()) {
// DirectPositionImpl min1 = (DirectPositionImpl) positionFactory.createDirectPosition(null);//new DirectPositionImpl(crs);
// min1.setOrdinate(d, min);
// DirectPositionImpl max1 = (DirectPositionImpl) positionFactory.createDirectPosition(null);//new DirectPositionImpl(crs);
// max1.setOrdinate(d, max);
//
// positions.add(min1);
// positions.add(max1);
// } else {
// // update min in place
// for (DirectPosition minN : positions) {
// minN.setOrdinate(d, min);
// }
// // copy and update max
// List<DirectPosition> copy = new ArrayList<DirectPosition>();
// for (DirectPosition position : positions) {
// DirectPositionImpl maxN = (DirectPositionImpl) positionFactory.createDirectPosition(position.getCoordinates()); //new DirectPositionImpl(position);
// maxN.setOrdinate(d, max);
// }
// positions.addAll(copy);
// }
// }
//
// return this.createSurfaceByDirectPositions(positions);
// }
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.PrimitiveFactory#createPrimitive(org.opengis.geometry.coordinate.Envelope)
*/
public PrimitiveImpl createPrimitive(Envelope bounds)
throws MismatchedReferenceSystemException,
MismatchedDimensionException {
//final int D = crs.getCoordinateSystem().getDimension();
LineSegment segment = processBoundsToSegment(bounds);
return processSegmentToPrimitive( bounds, segment, 1 );
}
private PrimitiveImpl processSegmentToPrimitive(Envelope bounds, LineSegment segment, int dimension) {
//int D = crs.getCoordinateSystem().getDimension();
CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis( dimension );
if( axis.getDirection() == AxisDirection.OTHER ){
return processSegmentToPrimitive( bounds, segment, dimension+1 );
}
Ring ring = processBoundsToRing( bounds, segment, dimension );
return processRingToPrimitive( bounds, ring, dimension+1 );
}
private PrimitiveImpl processRingToPrimitive(Envelope bounds, Ring ring, int dimension) {
int D = crs.getCoordinateSystem().getDimension();
if( dimension == D ){ // create Surface from ring and return
SurfaceBoundary boundary = new SurfaceBoundaryImpl( crs, ring, Collections.EMPTY_LIST );
return new SurfaceImpl( boundary );
}
CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis( dimension );
if( axis.getDirection() == AxisDirection.OTHER ){
return processRingToPrimitive( bounds, ring, dimension+1 );
}
return processRingToVolumne( bounds, ring, dimension+1 );
}
private PrimitiveImpl processRingToVolumne(Envelope bounds, Ring ring, int i) {
// go into a volume
throw new UnsupportedOperationException("Not yet 3D");
}
/**
* This is the first and easy step ...
* @param bounds
* @param dimension
*/
public LineSegment processBoundsToSegment( Envelope bounds ){
final int D=0;
CoordinateReferenceSystem crs = bounds.getCoordinateReferenceSystem();
CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis( D );
DirectPosition positionA = positionFactory.createDirectPosition(null); //new DirectPositionImpl(crs);
DirectPosition positionB = positionFactory.createDirectPosition(null); //new DirectPositionImpl(crs);
if( axis.getDirection() != AxisDirection.OTHER ){
positionA.setOrdinate(D, bounds.getMinimum(D) );
positionB.setOrdinate(D, bounds.getMaximum(D) );
}
PointArrayImpl array = new PointArrayImpl(crs );
array.add( positionA );
array.add( positionB );
return new LineSegmentImpl( array, 0.0 );
}
/**
* This is pass #2 ...
* @return
*/
public Ring processBoundsToRing( Envelope bounds, LineSegment segment, final int D ){
DirectPosition one = positionFactory.createDirectPosition(segment.getStartPoint().getCoordinates()); //new DirectPositionImpl( segment.getStartPoint() );
one.setOrdinate( D, bounds.getMinimum(D) );
DirectPosition two = positionFactory.createDirectPosition(segment.getEndPoint().getCoordinates()); //new DirectPositionImpl( segment.getEndPoint() );
two.setOrdinate( D, bounds.getMinimum(D) );
DirectPosition three = positionFactory.createDirectPosition(two.getCoordinates()); //new DirectPositionImpl( two );
three.setOrdinate( D, bounds.getMaximum(D) );
DirectPosition four = positionFactory.createDirectPosition(one.getCoordinates()); //new DirectPositionImpl( one );
four.setOrdinate( D, bounds.getMaximum(D) );
LineSegment edge1 = new LineSegmentImpl( one, two, 0.0 );
LineSegment edge2 = new LineSegmentImpl( two, three, 0.0 );
LineSegment edge3 = new LineSegmentImpl( three, four, 0.0 );
LineSegment edge4 = new LineSegmentImpl( four, one, 0.0 );
List<OrientableCurve> edges = new ArrayList<OrientableCurve>();
edges.add( new CurveImpl( edge1 ));
edges.add( new CurveImpl( edge2 ));
edges.add( new CurveImpl( edge3 ));
edges.add( new CurveImpl( edge4 ));
return this.createRing(edges);
}
/**
* Creates a Ring conforming to the given DirectPositions. Helps to build
* Rings for SurfaceBoundaries.
*
* @param directPositions
* @return a Ring
*/
public Ring createRingByDirectPositions(List<DirectPosition> directPositions) {
// Test ok
// Create List of OrientableCurve´s (Curve´s)
OrientableCurve curve = this
.createCurveByDirectPositions(directPositions);
List<OrientableCurve> orientableCurves = new ArrayList<OrientableCurve>();
orientableCurves.add(curve);
return this.createRing(orientableCurves);
}
/**
* Creates a Ring conforming to the given Positions
*
* @param aPositions
* @return
*/
public Ring createRingByPositions(List<Position> aPositions) {
// Create List of OrientableCurve´s (Curve´s)
OrientableCurve curve = this.createCurveByPositions(aPositions);
List<OrientableCurve> orientableCurves = new ArrayList<OrientableCurve>();
orientableCurves.add(curve);
return this.createRing(orientableCurves);
}
/**
* Creates a Curve conforming to the given DirectPositions Tested by Sanjay -
*
* @param directPositions
* @return a Ring
*/
public Curve createCurveByDirectPositions(
List<DirectPosition> aDirectPositions) {
// Test ok
// GeometryFactoryImpl coordFactory =
// this.geometryFactory.getGeometryFactoryImpl();
// Create List of Position´s
List<Position> positionList = createPositions(aDirectPositions);
// List<Position> positionList =
// coordFactory.createPositions(aDirectPositions);
// Create List of CurveSegment´s (LineString´s)
LineStringImpl lineString = new LineStringImpl(new PointArrayImpl(
positionList), 0.0);
// LineStringImpl lineString =
// coordFactory.createLineString(aPositions);
List<CurveSegment> segments = new ArrayList<CurveSegment>();
segments.add(lineString);
// Create List of OrientableCurve´s (Curve´s)
return this.createCurve(segments);
}
/**
* Converts a List of DirectPosition objects to a List of Position objects
*
* @param aDirectPositions
* List of DirectPosition objects
* @return List of Position objects
*/
public List<Position> createPositions(List<DirectPosition> aDirectPositions) {
List<Position> rPositions = new LinkedList<Position>();
for (int i = 0; i < aDirectPositions.size(); i++) {
rPositions.add(new PositionImpl(aDirectPositions.get(i)));
}
return rPositions;
}
/**
* Creates a curve bu Positions
*
* @param aPositions
* @return Curve
*/
public CurveImpl createCurveByPositions(List<Position> aPositions) {
// GeometryFactoryImpl coordFactory =
// this.geometryFactory.getGeometryFactoryImpl();
// Create List of CurveSegment´s (LineString´s)
LineStringImpl lineString = new LineStringImpl(new PointArrayImpl(
aPositions), 0.0);
// LineStringImpl lineString =
// coordFactory.createLineString(aPositions);
List<CurveSegment> segments = new ArrayList<CurveSegment>();
segments.add(lineString);
// Create List of OrientableCurve´s (Curve´s)
return this.createCurve(segments);
}
/**
* Creates a simple surface without holes by a list of DirectPositions
*
* @param positions
* List of positions, the last positions must be equal to the
* first position
* @return a Surface defined by the given positions
*/
public SurfaceImpl createSurfaceByDirectPositions(
List<DirectPosition> positions) {
// Test ok
Ring extRing = this.createRingByDirectPositions(positions);
List<Ring> intRings = new ArrayList<Ring>();
SurfaceBoundary sfb = this.createSurfaceBoundary(extRing, intRings);
return this.createSurface(sfb);
}
}