001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/io/shpapi/MainFile.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 037 package org.deegree.io.shpapi; 038 039 import java.io.File; 040 import java.io.IOException; 041 import java.io.RandomAccessFile; 042 043 import org.deegree.model.spatialschema.ByteUtils; 044 045 /** 046 * Class representing an ESRI Shape File. 047 * <p> 048 * Uses class ByteUtils modified from the original package com.bbn.openmap.layer.shape <br> 049 * Copyright (C) 1998 BBN Corporation 10 Moulton St. Cambridge, MA 02138 <br> 050 * 051 * @version 16.08.2000 052 * @author Andreas Poth 053 * 054 */ 055 public class MainFile { 056 057 /* 058 * A buffer for current record's header. 059 */ 060 protected byte[] recHdr = new byte[ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH]; 061 062 private byte[] envRecBuf = new byte[36]; 063 064 private byte[] dataRecBuf = new byte[36]; 065 066 /* 067 * instance variables 068 */ 069 private FileHeader fh; 070 071 private IndexFile shx; 072 073 /* 074 * file suffixes for shp 075 */ 076 private static final String _shp = ".shp"; 077 078 /* 079 * references to the main file 080 */ 081 private RandomAccessFile raf; 082 083 /** 084 * Construct a MainFile from a file name. 085 * 086 * @param url 087 * @throws IOException 088 */ 089 public MainFile( String url ) throws IOException { 090 091 // creates raf 092 raf = new RandomAccessFile( url + _shp, "r" ); 093 094 fh = new FileHeader( raf ); 095 096 shx = new IndexFile( url ); 097 098 } 099 100 /** 101 * Construct a MainFile from a file name. 102 * 103 * @param url 104 * @param rwflag 105 * @throws IOException 106 */ 107 public MainFile( String url, String rwflag ) throws IOException { 108 109 // delet file if it exists 110 File file = new File( url + _shp ); 111 112 if ( rwflag.indexOf( 'w' ) > -1 && file.exists() ) 113 file.delete(); 114 file = null; 115 116 // creates raf 117 raf = new RandomAccessFile( url + _shp, rwflag ); 118 119 fh = new FileHeader( raf, rwflag.indexOf( 'w' ) > -1 ); 120 121 shx = new IndexFile( url, rwflag ); 122 123 } 124 125 /** 126 * 127 */ 128 public void close() { 129 try { 130 raf.close(); 131 } catch ( Exception ex ) { 132 ex.printStackTrace(); 133 } 134 try { 135 shx.close(); 136 } catch ( Exception ex ) { 137 ex.printStackTrace(); 138 } 139 } 140 141 /** 142 * method: getFileMBR()<BR> 143 * returns the minimum bounding rectangle of geometries<BR> 144 * within the shape-file 145 * 146 * @return the minimum bounding rectangle of geometries<BR> 147 */ 148 public SHPEnvelope getFileMBR() { 149 150 return fh.getFileMBR(); 151 152 } 153 154 /** 155 * method: getRecordNum()<BR> 156 * returns the number of record with in a shape-file<BR> 157 * 158 * @return the number of record with in a shape-file<BR> 159 */ 160 public int getRecordNum() { 161 162 return shx.getRecordNum(); 163 164 } 165 166 /** 167 * method: getRecordMBR(int RecNo)<BR> 168 * returns the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR> 169 * 170 * @param RecNo 171 * @return the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR> 172 * @throws IOException 173 */ 174 public SHPEnvelope getRecordMBR( int RecNo ) 175 throws IOException { 176 177 SHPEnvelope recordMBR = null; 178 179 // index in IndexArray (see IndexFile) 180 int iaIndex = RecNo - 1; 181 182 int off = shx.getRecordOffset( iaIndex ); 183 184 // off holds the offset of the shape-record in 16-bit words (= 2 byte) 185 // multiply with 2 gets number of bytes to seek 186 long rafPos = off * 2; 187 188 // fetch shape record 189 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH ); 190 191 if ( raf.read( envRecBuf, 0, envRecBuf.length ) != -1 ) { 192 193 int shpType = ByteUtils.readLEInt( envRecBuf, 0 ); 194 195 // only for PolyLines, Polygons and MultiPoints minimum bounding rectangles are defined 196 if ( shpType == ShapeConst.SHAPE_TYPE_POLYLINE || shpType == ShapeConst.SHAPE_TYPE_POLYGON 197 || shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT ) { 198 recordMBR = new SHPEnvelope( envRecBuf ); 199 } // end if shpType 200 } // end if result 201 202 return recordMBR; 203 } 204 205 /** 206 * method: getByRecNo (int RecNo)<BR> 207 * retruns a ShapeRecord-Geometry by RecorcNumber<BR> 208 * 209 * @param RecNo 210 * @return a ShapeRecord-Geometry by RecorcNumber<BR> 211 * @throws IOException 212 */ 213 public SHPGeometry getByRecNo( int RecNo ) 214 throws IOException { 215 216 SHPGeometry shpGeom = null; 217 218 // index in IndexArray (see IndexFile) 219 int iaIndex = RecNo - 1; 220 221 int off = shx.getRecordOffset( iaIndex ); 222 223 // calculate length from 16-bit words (= 2 bytes) to lenght in bytes 224 int len = shx.getRecordLength( iaIndex ) * 2; 225 226 // off holds the offset of the shape-record in 16-bit words (= 2 byte) 227 // multiply with 2 gets number of bytes to seek 228 long rafPos = off * 2; 229 230 // fetch record header 231 raf.seek( rafPos ); 232 233 // fetch shape record 234 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH ); 235 236 if ( len > dataRecBuf.length ) { 237 dataRecBuf = new byte[len]; 238 } 239 240 if ( raf.read( dataRecBuf, 0, len ) != -1 ) { 241 242 int shpType = ByteUtils.readLEInt( dataRecBuf, 0 ); 243 244 // create a geometry out of record buffer with shapetype 245 if ( shpType == ShapeConst.SHAPE_TYPE_POINT ) { 246 shpGeom = new SHPPoint( dataRecBuf, 4 ); 247 } else if ( shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT ) { 248 shpGeom = new SHPMultiPoint( dataRecBuf ); 249 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYLINE ) { 250 shpGeom = new SHPPolyLine( dataRecBuf ); 251 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGON ) { 252 shpGeom = new SHPPolygon( dataRecBuf ); 253 } else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGONZ ) { 254 shpGeom = new SHPPolygon3D( dataRecBuf ); 255 } 256 257 } // end if result 258 259 return shpGeom; 260 261 } 262 263 /** 264 * method: getShapeType(int RecNo)<BR> 265 * returns the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR> 266 * 267 * @param RecNo 268 * @return the minimum bound rectangle of RecNo's Geometrie of the shape-file<BR> 269 * @throws IOException 270 */ 271 public int getShapeTypeByRecNo( int RecNo ) 272 throws IOException { 273 274 int shpType = -1; 275 276 // index in IndexArray (see IndexFile) 277 int iaIndex = RecNo - 1; 278 279 int off = shx.getRecordOffset( iaIndex ); 280 281 // calculate length from 16-bit words (= 2 bytes) to length in bytes 282 int len = 4;// shx.getRecordLength( iaIndex ) * 2; 283 284 // off holds the offset of the shape-record in 16-bit words (= 2 byte) 285 // multiply with 2 gets number of bytes to seek 286 long rafPos = off * 2; 287 288 // fetch shape record 289 raf.seek( rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH ); 290 291 byte[] recBuf_ = new byte[len]; 292 293 if ( raf.read( recBuf_, 0, len ) != -1 ) { 294 shpType = ByteUtils.readLEInt( recBuf_, 0 ); 295 } // end if result 296 297 return shpType; 298 } 299 300 /** 301 * method: public void write(byte[] bytearray)<BR> 302 * appends a bytearray to the shape file<BR> 303 * 304 * @param bytearray 305 * @param record 306 * @param mbr 307 * @throws IOException 308 */ 309 public void write( byte[] bytearray, IndexRecord record, SHPEnvelope mbr ) 310 throws IOException { 311 raf.seek( record.offset * 2 ); 312 raf.write( bytearray ); 313 shx.appendRecord( record, mbr ); 314 } 315 316 /** 317 * method: public void writeHeader(int filelength, byte shptype, SHPEnvelope mbr)<BR> 318 * writes a header to the shape and index file<BR> 319 * 320 * @param filelength 321 * @param shptype 322 * @param mbr 323 * @throws IOException 324 */ 325 public void writeHeader( int filelength, byte shptype, SHPEnvelope mbr ) 326 throws IOException { 327 fh.writeHeader( filelength, shptype, mbr ); 328 shx.writeHeader( shptype, mbr ); 329 } 330 331 }