001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/io/shpapi/shape_new/ShapePolyline.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036 package org.deegree.io.shpapi.shape_new;
037
038 import java.util.Arrays;
039 import java.util.List;
040
041 import org.deegree.framework.log.ILogger;
042 import org.deegree.framework.log.LoggerFactory;
043 import org.deegree.model.crs.CoordinateSystem;
044 import org.deegree.model.spatialschema.ByteUtils;
045 import org.deegree.model.spatialschema.Curve;
046 import org.deegree.model.spatialschema.Geometry;
047 import org.deegree.model.spatialschema.GeometryException;
048 import org.deegree.model.spatialschema.GeometryFactory;
049 import org.deegree.model.spatialschema.LineString;
050 import org.deegree.model.spatialschema.Position;
051 import org.deegree.model.spatialschema.WKTAdapter;
052
053 /**
054 * <code>ShapePolyline</code> corresponds to the Polyline, PolylineM and PolylineZ shapes of the shapefile spec.
055 *
056 * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
057 * @author last edited by: $Author: mschneider $
058 *
059 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
060 */
061 public class ShapePolyline implements Shape {
062
063 private static final ILogger LOG = LoggerFactory.getLogger( ShapePolyline.class );
064
065 protected CoordinateSystem crs; // optional crs for geometry
066
067 protected boolean isM, isZ;
068
069 private ShapeEnvelope envelope;
070
071 protected ShapePoint[][] points;
072
073 /**
074 * Empty constructor. Should be used in concert with read().
075 */
076 public ShapePolyline() {
077 // all default
078 }
079
080 /**
081 * Creates a new Polyline/M/Z.
082 *
083 * @param z
084 * @param m
085 */
086 public ShapePolyline( boolean z, boolean m ) {
087 isM = m;
088 isZ = z;
089 }
090
091 /**
092 * Creates a new Polyline/M/Z.
093 *
094 * @param z
095 * @param m
096 * @param crs
097 * CoordinateSystem for shape
098 */
099 public ShapePolyline( boolean z, boolean m, CoordinateSystem crs ) {
100 isM = m;
101 isZ = z;
102 this.crs = crs;
103 }
104
105 /**
106 * Creates a new PolylineZ from deegree Curves.
107 *
108 * @param cs
109 */
110 public ShapePolyline( List<Curve> cs ) {
111 try {
112 points = new ShapePoint[cs.size()][];
113 int partNum = 0;
114 for ( Curve c : cs ) {
115
116 if ( envelope == null ) {
117 envelope = new ShapeEnvelope( c.getEnvelope() );
118 }
119 LineString ls = c.getAsLineString();
120
121 points[partNum] = new ShapePoint[ls.getNumberOfPoints()];
122
123 ShapePoint p;
124 for ( int i = 0; i < ls.getNumberOfPoints(); i++ ) {
125 p = new ShapePoint( ls.getPositionAt( i ) );
126 points[partNum][i] = p;
127 envelope.fit( p.x, p.y, p.z );
128 }
129 ++partNum;
130
131 // uses only the last one, but whatever will happen if they're not consistent anyway...
132 if ( c.getDimension() == 3 ) {
133 isZ = true;
134 }
135 }
136 } catch ( GeometryException e ) {
137 LOG.logError( "Something was wrong with a Curve object. " + "This will probably lead to followup errors, "
138 + "better check your input data. Stack Trace:", e );
139 }
140 }
141
142 /**
143 * Creates a new PolylineZ from deegree Curve.
144 *
145 * @param c
146 */
147 public ShapePolyline( Curve c ) {
148 this( Arrays.asList( new Curve[] { c } ) );
149 }
150
151 private int numPoints() {
152 int num = 0;
153
154 for ( ShapePoint[] ps : points ) {
155 num += ps.length;
156 }
157
158 return num;
159 }
160
161 /*
162 * (non-Javadoc)
163 *
164 * @see org.deegree.io.shpapi.Shape#getByteLength()
165 */
166 public int getByteLength() {
167 int numPoints = numPoints();
168
169 int len = 44 + 4 * points.length + 16 * numPoints;
170
171 if ( isM ) {
172 len += 8 * numPoints + 16;
173 }
174
175 if ( isZ ) {
176 len += 16 * numPoints + 32;
177 }
178
179 return len;
180 }
181
182 protected int readPolyline( byte[] bytes, int offset ) {
183 int off = offset;
184 envelope = new ShapeEnvelope( false, false );
185 off = envelope.read( bytes, off );
186
187 int numParts = ByteUtils.readLEInt( bytes, off );
188 off += 4;
189
190 int numPoints = ByteUtils.readLEInt( bytes, off );
191 off += 4;
192
193 points = new ShapePoint[numParts][];
194 int[] partStart = new int[numParts];
195
196 for ( int i = 0; i < numParts; ++i ) {
197 partStart[i] = ByteUtils.readLEInt( bytes, off );
198 off += 4;
199 }
200
201 for ( int i = 0; i < numParts; ++i ) {
202
203 // calculate number of points for current part
204 int len;
205 if ( i == numParts - 1 ) {
206 len = numPoints - partStart[i];
207 } else {
208 len = partStart[i + 1] - partStart[i];
209 }
210
211 points[i] = new ShapePoint[len];
212 for ( int j = 0; j < len; ++j ) {
213 points[i][j] = new ShapePoint( bytes, off );
214 off += 16;
215 }
216 }
217
218 return off;
219 }
220
221 protected int readPolylineZ( byte[] bytes, int offset ) {
222 isZ = true;
223
224 int off = readPolyline( bytes, offset );
225
226 int numPoints = numPoints();
227
228 double zmin, zmax, mmin, mmax;
229 zmin = ByteUtils.readLEDouble( bytes, off );
230 off += 8;
231 zmax = ByteUtils.readLEDouble( bytes, off );
232 off += 8;
233
234 double[] zVals = new double[numPoints];
235 for ( int i = 0; i < numPoints; ++i ) {
236 zVals[i] = ByteUtils.readLEDouble( bytes, off );
237 off += 8;
238 }
239
240 mmin = ByteUtils.readLEDouble( bytes, off );
241 off += 8;
242 mmax = ByteUtils.readLEDouble( bytes, off );
243 off += 8;
244
245 double[] mVals = new double[numPoints];
246 for ( int i = 0; i < numPoints; ++i ) {
247 mVals[i] = ByteUtils.readLEDouble( bytes, off );
248 off += 8;
249 }
250
251 int i = 0;
252 for ( ShapePoint[] ps : points ) {
253 for ( ShapePoint p : ps ) {
254 p.extend( zVals[i], mVals[i] );
255 ++i;
256 }
257 }
258
259 envelope.extend( zmin, zmax, mmin, mmax );
260
261 return off;
262 }
263
264 protected int readPolylineM( byte[] bytes, int offset ) {
265 isM = true;
266
267 int off = readPolyline( bytes, offset );
268
269 int numPoints = numPoints();
270
271 double mmin, mmax;
272 mmin = ByteUtils.readLEDouble( bytes, off );
273 off += 8;
274 mmax = ByteUtils.readLEDouble( bytes, off );
275 off += 8;
276
277 envelope.extend( mmin, mmax );
278
279 double[] mVals = new double[numPoints];
280 for ( int i = 0; i < numPoints; ++i ) {
281 mVals[i] = ByteUtils.readLEDouble( bytes, off );
282 off += 8;
283 }
284
285 int i = 0;
286 for ( ShapePoint[] ps : points ) {
287 for ( ShapePoint p : ps ) {
288 p.extend( mVals[i] );
289 ++i;
290 }
291 }
292
293 return off;
294 }
295
296 /*
297 * (non-Javadoc)
298 *
299 * @see org.deegree.io.shpapi.Shape#read(byte[], int)
300 */
301 public int read( byte[] bytes, int offset ) {
302 int off = offset;
303
304 int type = ByteUtils.readLEInt( bytes, off );
305 off += 4;
306
307 if ( type == ShapeFile.NULL ) {
308 return off;
309 }
310
311 if ( type == ShapeFile.POLYLINE ) {
312 isZ = false;
313 isM = false;
314 return readPolyline( bytes, off );
315 }
316
317 if ( type == ShapeFile.POLYLINEZ ) {
318 isZ = true;
319 isM = false;
320 return readPolylineZ( bytes, off );
321 }
322
323 if ( type == ShapeFile.POLYLINEM ) {
324 isZ = false;
325 isM = true;
326 return readPolylineM( bytes, off );
327 }
328
329 return -1;
330 }
331
332 protected int writePolyline( byte[] bytes, int offset ) {
333 int off = envelope.write( bytes, offset );
334
335 ByteUtils.writeLEInt( bytes, off, points.length );
336 off += 4;
337
338 int numPoints = numPoints();
339 ByteUtils.writeLEInt( bytes, off, numPoints );
340 off += 4;
341
342 int pos = 0;
343 for ( ShapePoint[] ps : points ) {
344 ByteUtils.writeLEInt( bytes, off, pos );
345 off += 4;
346 pos += ps.length;
347 }
348
349 for ( ShapePoint[] ps : points ) {
350 for ( ShapePoint p : ps ) {
351 ByteUtils.writeLEDouble( bytes, off, p.x );
352 off += 8;
353 ByteUtils.writeLEDouble( bytes, off, p.y );
354 off += 8;
355 }
356 }
357
358 return off;
359 }
360
361 protected int writePolylineZ( byte[] bytes, int offset ) {
362 int off = writePolyline( bytes, offset );
363
364 ByteUtils.writeLEDouble( bytes, off, envelope.zmin );
365 off += 8;
366 ByteUtils.writeLEDouble( bytes, off, envelope.zmax );
367 off += 8;
368
369 for ( ShapePoint[] ps : points ) {
370 for ( ShapePoint p : ps ) {
371 ByteUtils.writeLEDouble( bytes, off, p.z );
372 off += 8;
373 }
374 }
375
376 ByteUtils.writeLEDouble( bytes, off, envelope.mmin );
377 off += 8;
378 ByteUtils.writeLEDouble( bytes, off, envelope.mmax );
379 off += 8;
380
381 for ( ShapePoint[] ps : points ) {
382 for ( ShapePoint p : ps ) {
383 ByteUtils.writeLEDouble( bytes, off, p.m );
384 off += 8;
385 }
386 }
387
388 return off;
389 }
390
391 protected int writePolylineM( byte[] bytes, int offset ) {
392 int off = writePolyline( bytes, offset );
393
394 ByteUtils.writeLEDouble( bytes, off, envelope.mmin );
395 off += 8;
396 ByteUtils.writeLEDouble( bytes, off, envelope.mmax );
397 off += 8;
398
399 for ( ShapePoint[] ps : points ) {
400 for ( ShapePoint p : ps ) {
401 ByteUtils.writeLEDouble( bytes, off, p.m );
402 off += 8;
403 }
404 }
405
406 return off;
407 }
408
409 /*
410 * (non-Javadoc)
411 *
412 * @see org.deegree.io.shpapi.Shape#write(byte[], int)
413 */
414 public int write( byte[] bytes, int offset ) {
415 if ( isZ ) {
416 ByteUtils.writeLEInt( bytes, offset, ShapeFile.POLYLINEZ );
417 return writePolylineZ( bytes, offset + 4 );
418 }
419 if ( isM ) {
420 ByteUtils.writeLEInt( bytes, offset, ShapeFile.POLYLINEM );
421 return writePolylineM( bytes, offset + 4 );
422 }
423 ByteUtils.writeLEInt( bytes, offset, ShapeFile.POLYLINE );
424 return writePolyline( bytes, offset + 4 );
425 }
426
427 /*
428 * (non-Javadoc)
429 *
430 * @see org.deegree.io.shpapi.shape_new.Shape#getType()
431 */
432 public int getType() {
433 if ( isZ ) {
434 return ShapeFile.POLYLINEZ;
435 }
436 if ( isM ) {
437 return ShapeFile.POLYLINEM;
438 }
439 return ShapeFile.POLYLINE;
440 }
441
442 /*
443 * (non-Javadoc)
444 *
445 * @see org.deegree.io.shpapi.shape_new.Shape#getEnvelope()
446 */
447 public ShapeEnvelope getEnvelope() {
448 return envelope;
449 }
450
451 /**
452 * This creates a MultiCurve object.
453 *
454 * @see org.deegree.io.shpapi.shape_new.Shape#getGeometry()
455 */
456 public Geometry getGeometry()
457 throws ShapeGeometryException {
458 if ( points == null ) {
459 return null;
460 }
461 try {
462 Curve[] cs = new Curve[points.length];
463
464 for ( int i = 0; i < points.length; ++i ) {
465 Position[] ps = new Position[points[i].length];
466 for ( int k = 0; k < points[i].length; ++k ) {
467 if ( isZ ) {
468 ps[k] = GeometryFactory.createPosition( points[i][k].x, points[i][k].y, points[i][k].z );
469 } else {
470 ps[k] = GeometryFactory.createPosition( points[i][k].x, points[i][k].y );
471 }
472 }
473 cs[i] = GeometryFactory.createCurve( ps, crs );
474 }
475
476 return GeometryFactory.createMultiCurve( cs, crs );
477 } catch ( GeometryException e ) {
478 throw new ShapeGeometryException( "MultiCurve could not be constructed" + " from ShapePolyline.", e );
479 }
480 }
481
482 @Override
483 public String toString() {
484 try {
485 return WKTAdapter.export( getGeometry() ).toString();
486 } catch ( GeometryException e ) {
487 return "(unknown)";
488 }
489 }
490
491 }