001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002, 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: */
017: package org.geotools.renderer.shape.shapehandler.simple;
018:
019: import java.awt.geom.Point2D;
020: import java.nio.ByteBuffer;
021:
022: import org.geotools.data.shapefile.shp.ShapeHandler;
023: import org.geotools.data.shapefile.shp.ShapeType;
024: import org.geotools.renderer.shape.GeometryHandlerUtilities;
025: import org.geotools.renderer.shape.ShapefileRenderer;
026: import org.geotools.renderer.shape.SimpleGeometry;
027: import org.opengis.referencing.operation.MathTransform;
028: import org.opengis.referencing.operation.TransformException;
029:
030: import com.vividsolutions.jts.geom.Envelope;
031:
032: /**
033: * A ShapeHandler that reads PointHandler objects from a file. It returns a SimpleGeometry and decimates all points that
034: * map to the same screen location.
035: *
036: * @author jeichar
037: * @since 2.1.x
038: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/shapefile-renderer/src/main/java/org/geotools/renderer/shape/shapehandler/simple/PolygonHandler.java $
039: */
040: public class PolygonHandler implements ShapeHandler {
041:
042: private ShapeType type;
043:
044: private Envelope bbox;
045:
046: double spanx, spany;
047:
048: private MathTransform mt;
049:
050: /**
051: * Create new instance
052: *
053: * @param type
054: * the type of shape.
055: * @param env
056: * the area that is visible. If shape is not in area then skip.
057: * @param mt
058: * the transform to go from data to the envelope (and that should
059: * be used to transform the shape coords)
060: * @param hasOpacity
061: */
062: public PolygonHandler(ShapeType type, Envelope env,
063: MathTransform mt, boolean hasOpacity)
064: throws TransformException {
065: if (mt == null) {
066: throw new NullPointerException();
067: }
068: this .type = type;
069: this .bbox = env;
070: this .mt = mt;
071: Point2D span = GeometryHandlerUtilities.calculateSpan(mt, 0, 0);
072: this .spanx = span.getX();
073: this .spany = span.getY();
074: }
075:
076: /**
077: * @see org.geotools.data.shapefile.shp.ShapeHandler#getShapeType()
078: */
079: public ShapeType getShapeType() {
080: return type;
081: }
082:
083: public Object read(ByteBuffer buffer, ShapeType type) {
084: if (type == ShapeType.NULL) {
085: return null;
086: }
087:
088: Envelope geomBBox = GeometryHandlerUtilities.readBounds(buffer);
089:
090: if (!bbox.intersects(geomBBox)) {
091: return null;
092: }
093:
094: boolean bboxdecimate = geomBBox.getWidth() <= spanx
095: && geomBBox.getHeight() <= spany;
096: int numParts = buffer.getInt();
097: int numPoints = buffer.getInt(); // total number of points
098:
099: int[] partOffsets = new int[numParts];
100:
101: // points = new Coordinate[numPoints];
102: for (int i = 0; i < numParts; i++) {
103: partOffsets[i] = buffer.getInt();
104: }
105: double[][] coords = new double[numParts][];
106: double[][] transformed = new double[numParts][];
107: // if needed in future otherwise all references to a z are commented
108: // out.
109: // if( dimensions==3 )
110: // z=new double[numParts][];
111:
112: int finish, start = 0;
113: int length = 0;
114: if (bboxdecimate) {
115: coords = new double[1][];
116: coords[0] = new double[4];
117: transformed = new double[1][];
118: transformed[0] = new double[8];
119: coords[0][0] = buffer.getDouble();
120: coords[0][1] = buffer.getDouble();
121: try {
122: mt.transform(coords[0], 0, transformed[0], 0, 1);
123: } catch (Exception e) {
124: ShapefileRenderer.LOGGER
125: .severe("could not transform coordinates "
126: + e.getLocalizedMessage());
127: transformed[0] = coords[0];
128: }
129: transformed[0][2] = transformed[0][0];
130: transformed[0][3] = transformed[0][1] + 0.1;
131: transformed[0][4] = transformed[0][0] + 0.1;
132: transformed[0][5] = transformed[0][1] + 0.1;
133: transformed[0][6] = transformed[0][0];
134: transformed[0][7] = transformed[0][1];
135: } else {
136: Envelope partEnvelope = new Envelope();
137: int partsInBBox = 0;
138:
139: for (int part = 0; part < numParts; part++) {
140: start = partOffsets[part];
141: partEnvelope.init();
142:
143: if (part == (numParts - 1)) {
144: finish = numPoints;
145: } else {
146: finish = partOffsets[part + 1];
147: }
148:
149: length = finish - start;
150: int totalDoubles = length * 2;
151: coords[part] = new double[totalDoubles];
152: int readDoubles = 0;
153: int currentDoubles = 0;
154: for (; currentDoubles < totalDoubles;) {
155: try {
156: coords[part][readDoubles] = buffer.getDouble();
157: readDoubles++;
158: currentDoubles++;
159: coords[part][readDoubles] = buffer.getDouble();
160: readDoubles++;
161: currentDoubles++;
162: } catch (Exception e) {
163: e.printStackTrace();
164: }
165: if (collapsePoints(coords, part, totalDoubles,
166: readDoubles, currentDoubles)) {
167: readDoubles -= 2;
168: } else {
169: partEnvelope.expandToInclude(
170: coords[part][readDoubles - 2],
171: coords[part][readDoubles - 1]);
172: }
173: }
174: if (!partEnvelope.intersects(bbox)) {
175: continue;
176: }
177:
178: if (readDoubles < 8)
179: transformed[partsInBBox] = new double[8];
180: else
181: transformed[partsInBBox] = new double[readDoubles];
182:
183: if (!mt.isIdentity()) {
184: try {
185: GeometryHandlerUtilities.transform(type, mt,
186: coords[part], transformed[partsInBBox]);
187: // mt.transform(coords[part], 0, transformed[partsInBBox],
188: // 0, readDoubles / 2);
189: } catch (Exception e) {
190: ShapefileRenderer.LOGGER
191: .severe("could not transform coordinates "
192: + e.getLocalizedMessage());
193: transformed[partsInBBox] = coords[part];
194: }
195: } else {
196: System.arraycopy(coords[part], 0,
197: transformed[partsInBBox], 0,
198: readDoubles / 2);
199: }
200: if (readDoubles < 8) {
201: for (int i = readDoubles; i < transformed[partsInBBox].length; i++) {
202: transformed[partsInBBox][i] = transformed[partsInBBox][i - 2];
203: }
204: }
205: partsInBBox++;
206: }
207: if (partsInBBox == 0)
208: return null;
209: if (partsInBBox != numParts) {
210: double[][] tmp = new double[partsInBBox][];
211: System.arraycopy(transformed, 0, tmp, 0, partsInBBox);
212: transformed = tmp;
213: }
214: }
215: return createGeometry(type, geomBBox, transformed);
216: }
217:
218: protected Object createGeometry(ShapeType type, Envelope geomBBox,
219: double[][] transformed) {
220: return new SimpleGeometry(type, transformed, geomBBox);
221: }
222:
223: /**
224: * Return true if the current point and the last point should be collapsed
225: * into a single point. The first and last point must be the same so if the
226: * current doubles is the 1-2 second double or if one of the last two the it
227: * will return false. Otherwise it will return true if the distance in the y
228: * axis is less than the distance of one pixel... similar comparison is done
229: * along the x-axis.
230: *
231: * @return true if the current point and the last point should be collapsed
232: * into a single point.
233: */
234: private boolean collapsePoints(double[][] coords, int part,
235: int totalDoubles, int readDoubles, int currentDoubles) {
236: return currentDoubles > 3
237: && currentDoubles < totalDoubles - 1
238: && Math.abs(coords[part][readDoubles - 4]
239: - coords[part][readDoubles - 2]) <= spanx
240: && Math.abs(coords[part][readDoubles - 3]
241: - coords[part][readDoubles - 1]) <= spany;
242: }
243:
244: /**
245: * @see org.geotools.data.shapefile.shp.ShapeHandler#write(java.nio.ByteBuffer,
246: * java.lang.Object)
247: */
248: public void write(ByteBuffer buffer, Object geometry) {
249: // This handler doesnt write
250: throw new UnsupportedOperationException(
251: "This handler is only for reading");
252: }
253:
254: /**
255: * @see org.geotools.data.shapefile.shp.ShapeHandler#getLength(java.lang.Object)
256: */
257: public int getLength(Object geometry) {
258: // TODO Auto-generated method stub
259: return 0;
260: }
261:
262: }
|