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