/*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2006 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/deegree/ lat/lon GmbH http://www.lat-lon.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstr. 19 53177 Bonn Germany E-Mail: poth@lat-lon.de Prof. Dr. Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: greve@giub.uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.io.shpapi; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import org.deegree.model.spatialschema.ByteUtils; /** * Class representing an ESRI Shape File. * <p> * Uses class ByteUtils modified * from the original package com.bbn.openmap.layer.shape * <br> * Copyright (C) 1998 BBN Corporation 10 Moulton St. Cambridge, MA 02138 * <br> * * @version 16.08.2000 * @author Andreas Poth * */ public class MainFile { /* * A buffer for current record's header. */ protected byte[] recHdr = new byte[ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH]; /* * instance variables */ private FileHeader fh; private IndexFile shx; /* * file suffixes for shp */ private static final String _shp = ".shp"; /* * references to the main file */ private RandomAccessFile raf; /** * Construct a MainFile from a file name. */ public MainFile(String url) throws IOException { /* * creates raf */ raf= new RandomAccessFile(url + _shp,"r"); fh = new FileHeader(raf); shx = new IndexFile(url); } /** * Construct a MainFile from a file name. */ public MainFile(String url, String rwflag) throws IOException { // delet file if it exists File file = new File(url + _shp); if (rwflag.indexOf('w') > -1 && file.exists()) file.delete(); file = null; /* * creates raf */ raf= new RandomAccessFile(url + _shp,rwflag); fh = new FileHeader(raf, rwflag.indexOf('w') > -1); shx = new IndexFile(url,rwflag); } public void close() { try { raf.close(); } catch (Exception ex) { ex.printStackTrace(); } try { shx.close(); } catch (Exception ex) { ex.printStackTrace(); } } /** * method: getFileMBR()<BR> * returns the minimum bounding rectangle of geometries<BR> * within the shape-file */ public SHPEnvelope getFileMBR() { return fh.getFileMBR(); } /** * method: getRecordNum()<BR> * returns the number of record with in a shape-file<BR> */ public int getRecordNum() { return shx.getRecordNum(); } /** * method: getRecordMBR(int RecNo)<BR> * returns the minimum bound rectangle of RecNo's Geometrie * of the shape-file<BR> */ public SHPEnvelope getRecordMBR(int RecNo) throws IOException{ SHPEnvelope recordMBR = null; byte[] recBuf= null; // index in IndexArray (see IndexFile) int iaIndex = RecNo-1; int off = shx.getRecordOffset(iaIndex); // calculate length from 16-bit words (= 2 bytes) to lenght in bytes int len = shx.getRecordLength(iaIndex) * 2; // off holds the offset of the shape-record in 16-bit words (= 2 byte) // multiply with 2 gets number of bytes to seek long rafPos = off*2; // fetch shape record raf.seek(rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH); recBuf = null; recBuf = new byte[len]; if ( raf.read(recBuf, 0, len) != -1 ) { int shpType = ByteUtils.readLEInt(recBuf, 0); /* * only for PolyLines, Polygons and MultiPoints * minimum bounding rectangles are defined */ if ( (shpType == ShapeConst.SHAPE_TYPE_POLYLINE) || (shpType == ShapeConst.SHAPE_TYPE_POLYGON) || (shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT) ) { recordMBR = new SHPEnvelope(recBuf); } // end if shpType } // end if result return recordMBR; } /** * method: getByRecNo (int RecNo)<BR> * retruns a ShapeRecord-Geometry by RecorcNumber<BR> */ public SHPGeometry getByRecNo (int RecNo) throws IOException { SHPGeometry shpGeom = null; byte[] recBuf= null; // index in IndexArray (see IndexFile) int iaIndex = RecNo-1; int off = shx.getRecordOffset(iaIndex); // calculate length from 16-bit words (= 2 bytes) to lenght in bytes int len = shx.getRecordLength(iaIndex) * 2; // off holds the offset of the shape-record in 16-bit words (= 2 byte) // multiply with 2 gets number of bytes to seek long rafPos= off*2; //fetch record header raf.seek(rafPos); recBuf = null; recBuf = new byte[ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH]; // fetch shape record raf.seek(rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH); recBuf = null; recBuf = new byte[len]; if ( raf.read(recBuf, 0, len) != -1 ) { int shpType = ByteUtils.readLEInt(recBuf, 0); // create a geometry out of record buffer with shapetype if (shpType == ShapeConst.SHAPE_TYPE_POINT) { shpGeom = new SHPPoint(recBuf,4); } else if (shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT) { shpGeom = new SHPMultiPoint(recBuf); } else if (shpType == ShapeConst.SHAPE_TYPE_POLYLINE) { shpGeom = new SHPPolyLine(recBuf); } else if (shpType == ShapeConst.SHAPE_TYPE_POLYGON) { shpGeom = new SHPPolygon(recBuf); } else if( shpType == ShapeConst.SHAPE_TYPE_POLYGONZ ){ shpGeom = new SHPPolygon3D(recBuf); } } // end if result return shpGeom; } /** * method: getShapeType(int RecNo)<BR> * returns the minimum bound rectangle of RecNo's Geometrie * of the shape-file<BR> */ public int getShapeTypeByRecNo(int RecNo) throws IOException { byte[] recBuf = null; int shpType = -1; // index in IndexArray (see IndexFile) int iaIndex = RecNo-1; int off = shx.getRecordOffset(iaIndex); // calculate length from 16-bit words (= 2 bytes) to lenght in bytes int len = shx.getRecordLength(iaIndex) * 2; // off holds the offset of the shape-record in 16-bit words (= 2 byte) // multiply with 2 gets number of bytes to seek long rafPos= off*2; // fetch shape record raf.seek(rafPos + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH); recBuf = null; recBuf = new byte[len]; if ( raf.read(recBuf, 0, len) != -1 ) { shpType = ByteUtils.readLEInt(recBuf, 0); } // end if result return shpType; } /** * method: public void write(byte[] bytearray)<BR> * appends a bytearray to the shape file<BR> */ public void write(byte[] bytearray, IndexRecord record, SHPEnvelope mbr) throws IOException { raf.seek(record.offset*2); raf.write(bytearray); shx.appendRecord(record,mbr); } /** * method: public void writeHeader(int filelength, byte shptype, SHPEnvelope mbr)<BR> * writes a header to the shape and index file<BR> */ public void writeHeader(int filelength, byte shptype, SHPEnvelope mbr) throws IOException { fh.writeHeader(filelength, shptype,mbr); shx.writeHeader(shptype,mbr); } } /* * Last changes: * $Log: MainFile.java,v $ * Revision 1.12 2006/07/12 14:46:14 poth * comment footer added * * Revision 1.11 2006/06/05 15:21:53 poth * support for polygonz type added * * Revision 1.10 2006/05/29 16:16:15 poth * code simplification * * Revision 1.9 2006/04/06 20:25:23 poth * *** empty log message *** * * Revision 1.8 2006/04/04 20:39:41 poth * *** empty log message *** * * Revision 1.7 2006/03/30 21:20:24 poth * *** empty log message *** * * Revision 1.6 2006/01/16 20:36:39 poth * *** empty log message *** * * Revision 1.5 2005/02/14 11:19:43 friebe * fix javadoc errors * * 14.12.1999 ap: import clauses added<BR> * 14.12.1999 ap: private variable declarations<BR> * 14.12.1999 ap: all public static references removed<BR> * 14.12.1999 ap: constructor implemented<BR> * 14.12.1999 ap: method: openFiles (String url) implemented<BR> * 14.12.1999 ap: method: getFileMBR() implemented<BR> * 14.12.1999 ap: method: getRecordNum() implemented<BR> * 14.12.1999 ap: method: getRecordMBR(int RecNo) implemented<BR> * 14.12.1999 ap: method: getByRecNo(int RecNo) implemented<BR> * 14.12.1999 ap: method: getShapeTypeByRecNo(int RecNo) implemented<BR> * 21.12.1999 ap: method: openfiles(String url) removed<BR> * 21.12.1999 ap: all static final declarations replaced<BR> * 07.01.2000 ap: return types of the methods changed from WKBxxxx and Rectangle<BR> * to SHPxxxx<BR> * 07.01.2000 ap: method getRecordMBR modified - SHAPE_TYPE_MULTIPOINT added<BR> * 13.01.2000 ap: method getByRecNo re-implemented<BR> * 21.03.2000 ap: method getByRecNo completed; multipoint is now supported<BR> * 16.08.2000 ap: method write(..) added<BR> * 16.08.2000 ap: method writeHeader(..) added<BR> *//* ******************************************************************** Changes to this class. What the people have been up to: $Log: MainFile.java,v $ Revision 1.12 2006/07/12 14:46:14 poth comment footer added ********************************************************************** */