001: /*
002: * $Id: MultiLineHandler.java 3 2005-06-16 15:03:35Z javamap $
003: *
004: */
005:
006: package org.geotools.shapefile;
007:
008: import java.io.IOException;
009:
010: import com.vividsolutions.jts.geom.*;
011: import com.vividsolutions.jump.io.EndianDataInputStream;
012: import com.vividsolutions.jump.io.EndianDataOutputStream;
013:
014: /**
015: * Wrapper for a Shapefile arc.
016: */
017: public class MultiLineHandler implements ShapeHandler {
018:
019: int myShapeType = -1;
020:
021: public MultiLineHandler() {
022: myShapeType = 3;
023: }
024:
025: public MultiLineHandler(int type) throws InvalidShapefileException {
026: if ((type != 3) && (type != 13) && (type != 23))
027: throw new InvalidShapefileException(
028: "MultiLineHandler constructor - expected type to be 3,13 or 23");
029:
030: myShapeType = type;
031: }
032:
033: public Geometry read(EndianDataInputStream file,
034: GeometryFactory geometryFactory, int contentLength)
035: throws IOException, InvalidShapefileException {
036:
037: double junk;
038: int actualReadWords = 0; //actual number of words read (word = 16bits)
039:
040: //file.setLittleEndianMode(true);
041:
042: int shapeType = file.readIntLE();
043: actualReadWords += 2;
044:
045: if (shapeType == 0) {
046: return new MultiLineString(null, new PrecisionModel(), 0); //null shape
047: }
048:
049: if (shapeType != myShapeType) {
050: throw new InvalidShapefileException(
051: "MultilineHandler.read() - file says its type "
052: + shapeType + " but i'm expecting type "
053: + myShapeType);
054: }
055:
056: //read bounding box (not needed)
057: junk = file.readDoubleLE();
058: junk = file.readDoubleLE();
059: junk = file.readDoubleLE();
060: junk = file.readDoubleLE();
061: actualReadWords += 4 * 4;
062:
063: int numParts = file.readIntLE();
064: int numPoints = file.readIntLE();//total number of points
065: actualReadWords += 4;
066:
067: int[] partOffsets = new int[numParts];
068:
069: //points = new Coordinate[numPoints];
070:
071: for (int i = 0; i < numParts; i++) {
072: partOffsets[i] = file.readIntLE();
073: actualReadWords += 2;
074: }
075:
076: LineString lines[] = new LineString[numParts];
077: Coordinate[] coords = new Coordinate[numPoints];
078:
079: for (int t = 0; t < numPoints; t++) {
080: coords[t] = new Coordinate(file.readDoubleLE(), file
081: .readDoubleLE());
082: actualReadWords += 8;
083: }
084:
085: if (myShapeType == 13) {
086: junk = file.readDoubleLE(); //z min, max
087: junk = file.readDoubleLE();
088: actualReadWords += 8;
089:
090: for (int t = 0; t < numPoints; t++) {
091: coords[t].z = file.readDoubleLE(); //z value
092: actualReadWords += 4;
093: }
094: }
095:
096: if (myShapeType >= 13) {
097: // int fullLength = 22 + 2*numParts + (numPoints * 8) + 4+4+4*numPoints+ 4+4+4*numPoints;
098: int fullLength;
099: if (myShapeType == 13) {
100: //polylineZ (with M)
101: fullLength = 22 + 2 * numParts + (numPoints * 8) + 4
102: + 4 + 4 * numPoints + 4 + 4 + 4 * numPoints;
103: } else {
104: // polylineM (with M)
105: fullLength = 22 + 2 * numParts + (numPoints * 8) + 4
106: + 4 + 4 * numPoints;
107: }
108: if (contentLength >= fullLength) //are ms actually there?
109: {
110: junk = file.readDoubleLE(); //m min, max
111: junk = file.readDoubleLE();
112: actualReadWords += 8;
113:
114: for (int t = 0; t < numPoints; t++) {
115: junk = file.readDoubleLE(); //m value
116: actualReadWords += 4;
117: }
118: }
119: }
120:
121: //verify that we have read everything we need
122: while (actualReadWords < contentLength) {
123: int junk2 = file.readShortBE();
124: actualReadWords += 1;
125: }
126:
127: int offset = 0;
128: int start, finish, length;
129: for (int part = 0; part < numParts; part++) {
130: start = partOffsets[part];
131: if (part == numParts - 1) {
132: finish = numPoints;
133: } else {
134: finish = partOffsets[part + 1];
135: }
136: length = finish - start;
137: Coordinate points[] = new Coordinate[length];
138: for (int i = 0; i < length; i++) {
139: points[i] = coords[offset];
140: offset++;
141: }
142: lines[part] = geometryFactory.createLineString(points);
143:
144: }
145: if (numParts == 1)
146: return lines[0];
147: else
148: return geometryFactory.createMultiLineString(lines);
149: }
150:
151: public void write(Geometry geometry, EndianDataOutputStream file)
152: throws IOException {
153: MultiLineString multi = (MultiLineString) geometry;
154: int npoints;
155:
156: Coordinate[] coords;
157: //file.setLittleEndianMode(true);
158: file.writeIntLE(getShapeType());
159:
160: Envelope box = multi.getEnvelopeInternal();
161: file.writeDoubleLE(box.getMinX());
162: file.writeDoubleLE(box.getMinY());
163: file.writeDoubleLE(box.getMaxX());
164: file.writeDoubleLE(box.getMaxY());
165:
166: int numParts = multi.getNumGeometries();
167:
168: file.writeIntLE(numParts);
169: npoints = multi.getNumPoints();
170: file.writeIntLE(npoints);
171:
172: LineString[] lines = new LineString[numParts];
173: int idx = 0;
174:
175: for (int i = 0; i < numParts; i++) {
176: lines[i] = (LineString) multi.getGeometryN(i);
177: file.writeIntLE(idx);
178: idx = idx + lines[i].getNumPoints();
179: }
180:
181: coords = multi.getCoordinates();
182: for (int t = 0; t < npoints; t++) {
183: file.writeDoubleLE(coords[t].x);
184: file.writeDoubleLE(coords[t].y);
185: }
186:
187: if (myShapeType == 13) {
188: //z
189: double[] zExtreame = zMinMax(multi);
190: if (Double.isNaN(zExtreame[0])) {
191: file.writeDoubleLE(0.0);
192: file.writeDoubleLE(0.0);
193: } else {
194: file.writeDoubleLE(zExtreame[0]);
195: file.writeDoubleLE(zExtreame[1]);
196: }
197: for (int t = 0; t < npoints; t++) {
198: double z = coords[t].z;
199: if (Double.isNaN(z))
200: file.writeDoubleLE(0.0);
201: else
202: file.writeDoubleLE(z);
203: }
204: }
205:
206: if (myShapeType >= 13) {
207: //m
208: file.writeDoubleLE(-10E40);
209: file.writeDoubleLE(-10E40);
210: for (int t = 0; t < npoints; t++) {
211: file.writeDoubleLE(-10E40);
212: }
213: }
214:
215: }
216:
217: /**
218: * Get the type of shape stored (Shapefile.ARC)
219: */
220: public int getShapeType() {
221: return myShapeType;
222: }
223:
224: public int getLength(Geometry geometry) {
225: MultiLineString multi = (MultiLineString) geometry;
226:
227: int numlines, numpoints;
228:
229: numlines = multi.getNumGeometries();
230: numpoints = multi.getNumPoints();
231:
232: if (myShapeType == 3) {
233: return 22 + 2 * numlines + (numpoints * 8);
234: }
235: if (myShapeType == 23) {
236: return 22 + 2 * numlines + (numpoints * 8) + 4 + 4 + 4
237: * numpoints;
238: }
239:
240: return 22 + 2 * numlines + (numpoints * 8) + 4 + 4 + 4
241: * numpoints + 4 + 4 + 4 * numpoints;
242:
243: // return 22 + 2*numlines + (numpoints * 8);
244:
245: //return (44+(4*((GeometryCollection)geometry).getNumGeometries()));
246: }
247:
248: double[] zMinMax(Geometry g) {
249: double zmin, zmax;
250: boolean validZFound = false;
251: Coordinate[] cs = g.getCoordinates();
252: double[] result = new double[2];
253:
254: zmin = Double.NaN;
255: zmax = Double.NaN;
256: double z;
257:
258: for (int t = 0; t < cs.length; t++) {
259: z = cs[t].z;
260: if (!(Double.isNaN(z))) {
261: if (validZFound) {
262: if (z < zmin)
263: zmin = z;
264: if (z > zmax)
265: zmax = z;
266: } else {
267: validZFound = true;
268: zmin = z;
269: zmax = z;
270: }
271: }
272:
273: }
274:
275: result[0] = (zmin);
276: result[1] = (zmax);
277: return result;
278:
279: }
280:
281: }
282:
283: /*
284: * $Log$
285: * Revision 1.1 2005/06/16 14:54:43 javamap
286: * *** empty log message ***
287: *
288: * Revision 1.1 2005/04/29 13:30:59 javamap
289: * *** empty log message ***
290: *
291: * Revision 1.4 2003/07/25 18:49:15 dblasby
292: * Allow "extra" data after the content. Fixes the ICI shapefile bug.
293: *
294: * Revision 1.3 2003/02/04 02:10:37 jaquino
295: * Feature: EditWMSQuery dialog
296: *
297: * Revision 1.2 2003/01/22 18:31:05 jaquino
298: * Enh: Make About Box configurable
299: *
300: * Revision 1.3 2002/10/30 22:36:11 dblasby
301: * Line reader now returns LINESTRING(..) if there is only one part to the arc
302: * polyline.
303: *
304: * Revision 1.2 2002/09/09 20:46:22 dblasby
305: * Removed LEDatastream refs and replaced with EndianData[in/out]putstream
306: *
307: * Revision 1.1 2002/08/27 21:04:58 dblasby
308: * orginal
309: *
310: * Revision 1.2 2002/03/05 10:23:59 jmacgill
311: * made sure geometries were created using the factory methods
312: *
313: * Revision 1.1 2002/02/28 00:38:50 jmacgill
314: * Renamed files to more intuitve names
315: *
316: * Revision 1.3 2002/02/13 00:23:53 jmacgill
317: * First semi working JTS version of Shapefile code
318: *
319: * Revision 1.2 2002/02/11 18:42:45 jmacgill
320: * changed read and write statements so that they produce and take Geometry objects instead of specific MultiLine objects
321: * changed parts[] array name to partOffsets[] for clarity and consistency with ShapePolygon
322: *
323: * Revision 1.1 2002/02/11 16:54:43 jmacgill
324: * added shapefile code and directories
325: *
326: */
|