001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.geometry.jts;
017:
018: // JTS dependencies
019: import com.vividsolutions.jts.geom.Coordinate;
020: import com.vividsolutions.jts.geom.CoordinateSequence;
021: import com.vividsolutions.jts.geom.CoordinateSequenceFactory;
022: import com.vividsolutions.jts.geom.DefaultCoordinateSequenceFactory;
023: import org.opengis.geometry.MismatchedDimensionException;
024:
025: // OpenGIS dependencies
026: import org.opengis.referencing.operation.MathTransform;
027: import org.opengis.referencing.operation.TransformException;
028:
029: /**
030: * A default implementation of {@linkplain CoordinateSequenceTransformer coordinate sequence
031: * transformer}. This transformer applies the coordinate transformations immediately (which
032: * means that caller are immediately notified if a transformation fails).
033: * <p>
034: * This transformer support {@linkplain MathTransform math transform} with up to 3 source
035: * or target dimensions. This transformer is not thread-safe.
036: *
037: * @since 2.1
038: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/api/src/main/java/org/geotools/geometry/jts/DefaultCoordinateSequenceTransformer.java $
039: * @version $Id: DefaultCoordinateSequenceTransformer.java 26186 2007-07-10 02:18:59Z jdeolive $
040: * @author Andrea Aime
041: * @author Martin Desruisseaux
042: */
043: public class DefaultCoordinateSequenceTransformer implements
044: CoordinateSequenceTransformer {
045: /**
046: * A buffer for coordinate transformations. We choose a length which is divisible by
047: * both 2 and 3, since JTS coordinates may be up to three-dimensional. If the number
048: * of coordinates point to transform is greater than the buffer capacity, then the
049: * buffer will be flushed to the destination array before to continue. We avoid to
050: * create a buffer as large than the number of point to transforms, because it would
051: * consume a large amount of memory for big geometries.
052: */
053: private final transient double[] buffer = new double[96];
054:
055: /**
056: * The coordinate sequence factory to use.
057: */
058: private final CoordinateSequenceFactory csFactory;
059:
060: /**
061: * Constructs a default coordinate sequence transformer.
062: */
063: public DefaultCoordinateSequenceTransformer() {
064: csFactory = DefaultCoordinateSequenceFactory.instance();
065: }
066:
067: /**
068: * {@inheritDoc}
069: */
070: public CoordinateSequence transform(
071: final CoordinateSequence sequence,
072: final MathTransform transform) throws TransformException {
073: final int sourceDim = transform.getSourceDimensions();
074: final int targetDim = transform.getTargetDimensions();
075: final int size = sequence.size();
076: final Coordinate[] tcs = new Coordinate[size];
077: final int bufferCapacity = buffer.length
078: / Math.max(sourceDim, targetDim);
079: int remainingBeforeFlush = Math.min(bufferCapacity, size);
080: int ib = 0; // Index in the buffer array.
081: int it = 0; // Index in the target array.
082:
083: for (int i = 0; i < size; i++) {
084: final Coordinate c = sequence.getCoordinate(i);
085:
086: switch (sourceDim) {
087: default:
088: throw new MismatchedDimensionException();
089:
090: case 3:
091: buffer[ib + 2] = c.z; // Fall through
092:
093: case 2:
094: buffer[ib + 1] = c.y; // Fall through
095:
096: case 1:
097: buffer[ib] = c.x; // Fall through
098:
099: case 0:
100: break;
101: }
102:
103: ib += sourceDim;
104:
105: if (--remainingBeforeFlush == 0) {
106: /*
107: * The buffer is full, or we just copied the last coordinates.
108: * Transform the coordinates and flush to the destination array.
109: */
110: assert (ib % sourceDim) == 0;
111:
112: final int n = ib / sourceDim;
113: transform.transform(buffer, 0, buffer, 0, n);
114: ib = 0;
115:
116: for (int j = 0; j < n; j++) {
117: final Coordinate t;
118:
119: switch (targetDim) {
120: default:
121: throw new MismatchedDimensionException();
122:
123: case 3:
124: t = new Coordinate(buffer[ib++], buffer[ib++],
125: buffer[ib++]);
126:
127: break;
128:
129: case 2:
130: t = new Coordinate(buffer[ib++], buffer[ib++]);
131:
132: break;
133:
134: case 1:
135: t = new Coordinate(buffer[ib++], Double.NaN);
136:
137: break;
138:
139: case 0:
140: t = new Coordinate(Double.NaN, Double.NaN);
141:
142: break;
143: }
144:
145: tcs[it++] = t;
146: }
147: assert ib == (n * targetDim);
148: ib = 0;
149: remainingBeforeFlush = Math.min(bufferCapacity, size
150: - (i + 1));
151: }
152: }
153: assert it == tcs.length : tcs.length - it;
154:
155: return csFactory.create(tcs);
156: }
157: }
|