001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 }