//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/io/shpapi/ShapeFile.java,v 1.41 2006/11/28 09:31:35 poth Exp $
/*---------------- 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.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.deegree.datatypes.Types;
import org.deegree.io.dbaseapi.DBaseException;
import org.deegree.io.dbaseapi.DBaseFile;
import org.deegree.io.dbaseapi.DBaseIndex;
import org.deegree.io.dbaseapi.DBaseIndexException;
import org.deegree.io.dbaseapi.FieldDescriptor;
import org.deegree.io.rtree.HyperBoundingBox;
import org.deegree.io.rtree.HyperPoint;
import org.deegree.io.rtree.RTree;
import org.deegree.io.rtree.RTreeException;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.FeatureFactory;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.feature.schema.FeatureType;
import org.deegree.model.feature.schema.GeometryPropertyType;
import org.deegree.model.feature.schema.PropertyType;
import org.deegree.model.spatialschema.ByteUtils;
import org.deegree.model.spatialschema.Curve;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.JTSAdapter;
import org.deegree.model.spatialschema.MultiCurve;
import org.deegree.model.spatialschema.MultiPoint;
import org.deegree.model.spatialschema.MultiSurface;
import org.deegree.model.spatialschema.Point;
import org.deegree.model.spatialschema.Position;
import org.deegree.model.spatialschema.Ring;
import org.deegree.model.spatialschema.Surface;
import org.deegree.model.spatialschema.SurfaceInterpolationImpl;
import com.vividsolutions.jts.algorithm.CGAlgorithms;
/**
* Class representing an ESRI Shape File.
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author: poth $
*
* @version $Revision: 1.41 $, $Date: 2006/11/28 09:31:35 $
*/
public class ShapeFile {
private DBaseFile dbf = null;
private SHP2WKS shpwks = new SHP2WKS();
/*
* contains the dBase indexes
*/
private Hashtable dBaseIndexes = new Hashtable();
/*
* aggregated Instance-variables
*/
private MainFile shp = null;
private RTree rti = null;
private String fileName = null;
/*
* indicates if a dBase-file is associated to the shape-file
*/
private boolean hasDBaseFile = true;
/*
* indicates if an R-tree index is associated to the shape-file
*/
private boolean hasRTreeIndex = true;
/**
* constructor: <BR>
* Construct a ShapeFile from a file name.<BR>
*/
public ShapeFile( String fileName ) throws IOException {
this.fileName = fileName;
/*
* initialize the MainFile
*/
shp = new MainFile( fileName );
/*
* initialize the DBaseFile
*/
try {
dbf = new DBaseFile( fileName );
} catch ( IOException e ) {
hasDBaseFile = false;
}
/*
* initialize the RTreeIndex
*/
try {
rti = new RTree( fileName + ".rti" );
} catch ( RTreeException e ) {
hasRTreeIndex = false;
}
if ( hasDBaseFile ) {
String[] s = null;
try {
s = getProperties();
} catch ( Exception e ) {
e.printStackTrace();
}
for ( int i = 0; i < s.length; i++ ) {
try {
dBaseIndexes.put( s[i], new DBaseIndex( fileName + "$" + s[i] ) );
} catch ( IOException e ) {
}
}
}
}
/**
* constructor: <BR>
* Construct a ShapeFile from a file name.<BR>
*/
public ShapeFile( String url, String rwflag ) throws IOException {
this.fileName = url;
shp = new MainFile( url, rwflag );
// TODO: initialize dbf, rti
hasDBaseFile = false;
hasRTreeIndex = false;
}
/**
*
*/
public void close() {
shp.close();
dbf.close();
if ( rti != null ) {
try {
rti.close();
} catch ( Exception e ) {
// should never happen
e.printStackTrace();
}
}
for ( Enumeration e = dBaseIndexes.elements(); e.hasMoreElements(); ) {
DBaseIndex index = (DBaseIndex) e.nextElement();
try {
index.close();
} catch ( Exception ex ) {
}
}
}
/**
* Overrides the default feature type (which is generated from all columns in the dbase file)
* to allow customized naming and ordering of properties.
*
* @param ft
* @param ftMapping
*/
public void setFeatureType( FeatureType ft, Map ftMapping ) {
dbf.setFeatureType( ft, ftMapping );
}
/**
* returns true if a column is indexed
*/
public boolean hasDBaseIndex( String column ) {
DBaseIndex index = (DBaseIndex) dBaseIndexes.get( column );
return index != null;
}
/**
* returns true if a dBase-file is associated to the shape-file<BR>
*/
public boolean hasDBaseFile() {
return this.hasDBaseFile;
}
/**
* returns true if an R-tree index is associated to the shape-file<BR>
*/
public boolean hasRTreeIndex() {
return this.hasRTreeIndex;
}
/**
* returns the number of records within a shape-file<BR>
*/
public int getRecordNum() {
return shp.getRecordNum();
}
/**
* returns the minimum bounding rectangle of all geometries<BR>
* within the shape-file
*/
public Envelope getFileMBR() {
double xmin = shp.getFileMBR().west;
double xmax = shp.getFileMBR().east;
double ymin = shp.getFileMBR().south;
double ymax = shp.getFileMBR().north;
return GeometryFactory.createEnvelope( xmin, ymin, xmax, ymax, null );
}
/**
* returns the minimum bound rectangle of RecNo'th Geometrie<BR>
*/
public Envelope getMBRByRecNo( int recNo )
throws IOException {
SHPEnvelope shpenv = shp.getRecordMBR( recNo );
double xmin = shpenv.west;
double xmax = shpenv.east;
double ymin = shpenv.south;
double ymax = shpenv.north;
return GeometryFactory.createEnvelope( xmin, ymin, xmax, ymax, null );
}
/**
* Returns the given entry of the shape file as a {@link Feature} instance.
* <p>
* This contains the geometry as well as the attributes stored into the dbase file. The
* geometry property will use a default name (app:GEOM).
*
* @param RecNo
* @return the given entry of the shape file as a Feature instance
* @throws IOException
* @throws HasNoDBaseFileException
* @throws DBaseException
*/
public Feature getFeatureByRecNo( int RecNo )
throws IOException, HasNoDBaseFileException, DBaseException {
if ( !hasDBaseFile ) {
throw new HasNoDBaseFileException( "Exception: there is no dBase-file "
+ "associated to this shape-file" );
}
// get feature (without geometry property) from DBaseFile
Feature feature = dbf.getFRow( RecNo );
// exchange null geometries with real geometry
Geometry geo = getGeometryByRecNo( RecNo );
GeometryPropertyType [] geoPTs= feature.getFeatureType().getGeometryProperties();
for ( int i = 0; i < geoPTs.length; i++ ) {
FeatureProperty [] geoProp = feature.getProperties( geoPTs [i].getName() );
for ( int j = 0; j < geoProp.length; j++ ) {
geoProp [j].setValue( geo );
}
}
return feature;
}
/**
* returns RecNo'th Geometrie<BR>
*/
public Geometry getGeometryByRecNo( int recNo )
throws IOException {
Geometry geom = null;
int shpType = getShapeTypeByRecNo( recNo );
if ( shpType == ShapeConst.SHAPE_TYPE_POINT ) {
SHPPoint shppoint = (SHPPoint) shp.getByRecNo( recNo );
geom = shpwks.transformPoint( null, shppoint );
} else if ( shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT ) {
SHPMultiPoint shpmultipoint = (SHPMultiPoint) shp.getByRecNo( recNo );
Point[] points = shpwks.transformMultiPoint( null, shpmultipoint );
if ( points != null ) {
MultiPoint mp = GeometryFactory.createMultiPoint( points );
geom = mp;
} else {
geom = null;
}
} else if ( shpType == ShapeConst.SHAPE_TYPE_POLYLINE ) {
SHPPolyLine shppolyline = (SHPPolyLine) shp.getByRecNo( recNo );
Curve[] curves = shpwks.transformPolyLine( null, shppolyline );
if ( ( curves != null ) && ( curves.length > 1 ) ) {
// create multi curve
MultiCurve mc = GeometryFactory.createMultiCurve( curves );
geom = mc;
} else if ( ( curves != null ) && ( curves.length == 1 ) ) {
// single curve
geom = curves[0];
} else {
geom = null;
}
} else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGON ) {
SHPPolygon shppoly = (SHPPolygon) shp.getByRecNo( recNo );
Surface[] polygons = shpwks.transformPolygon( null, shppoly );
if ( ( polygons != null ) && ( polygons.length > 1 ) ) {
// create multi surface
MultiSurface ms = GeometryFactory.createMultiSurface( polygons );
geom = ms;
} else if ( ( polygons != null ) && ( polygons.length == 1 ) ) {
geom = polygons[0];
} else {
geom = null;
}
} else if ( shpType == ShapeConst.SHAPE_TYPE_POLYGONZ ) {
SHPPolygon3D shppoly = (SHPPolygon3D) shp.getByRecNo( recNo );
Surface[] polygons = shpwks.transformPolygon( null, shppoly );
if ( ( polygons != null ) && ( polygons.length > 1 ) ) {
// create multi surface
MultiSurface ms = GeometryFactory.createMultiSurface( polygons );
geom = ms;
} else if ( ( polygons != null ) && ( polygons.length == 1 ) ) {
geom = polygons[0];
} else {
geom = null;
}
}
return geom;
}
/**
* returns the type of the RecNo'th Geometrie<BR>
* per definition a shape file contains onlay one shape type<BR>
* but null shapes are possible too!<BR>
*/
public int getShapeTypeByRecNo( int RecNo )
throws IOException {
return shp.getShapeTypeByRecNo( RecNo );
}
/**
* returns a int array that containts all the record numbers that matches the search operation
*/
public int[] getGeoNumbersByAttribute( String column, Comparable value )
throws IOException, DBaseIndexException {
DBaseIndex index = (DBaseIndex) dBaseIndexes.get( column );
if ( index == null ) {
return null;
}
return index.search( value );
}
/**
* returns a ArrayList that contains all geomeries of the shape file<BR>
* which mbr's are completly or partly within the rectangle r<BR>
* only Points, MultiPoints, PolyLines and Polygons are handled<BR>
*/
public int[] getGeoNumbersByRect( Envelope r )
throws IOException {
SHPPoint geom = null;
int[] num = null;
int numRecs = getRecordNum();
Envelope mbr = getFileMBR();
if ( !mbr.intersects( r ) ) {
return null;
}
if ( hasRTreeIndex ) {
try {
// translate envelope (deegree) to bounding box (rtree)
HyperBoundingBox box = new HyperBoundingBox(
new HyperPoint(
r.getMin().getAsArray() ),
new HyperPoint(
r.getMax().getAsArray() ) );
Object[] iNumbers = rti.intersects( box );
num = new int[iNumbers.length];
for ( int i = 0; i < iNumbers.length; i++ )
num[i] = ( (Integer) iNumbers[i] ).intValue();
return num;
} catch ( Exception e ) {
e.printStackTrace();
}
}
// for every geometry (record) within the shape file
// check if it's inside the search-rectangle r
List numbers = new ArrayList( 500 );
for ( int i = 0; i < numRecs; i++ ) {
if ( getShapeTypeByRecNo( i + 1 ) == ShapeConst.SHAPE_TYPE_NULL ) {
} else if ( getShapeTypeByRecNo( i + 1 ) == ShapeConst.SHAPE_TYPE_POINT ) {
geom = (SHPPoint) shp.getByRecNo( i + 1 );
// is the Point within the seach rectangle?
Position pos = GeometryFactory.createPosition( geom.x, geom.y );
if ( r.contains( pos ) == true ) {
numbers.add( new Integer( i + 1 ) );
}
} else {
// get minimum bounding rectangle of the i'th record
mbr = getMBRByRecNo( i + 1 );
// is the i'th record a geometrie having a mbr
// (only for PolyLines, Polygons and MultiPoints mbrs are defined)
if ( mbr != null ) {
// if the tested rectangles are not disjunct the number of the
// actual record is added to the ArrayList
if ( mbr.intersects( r ) ) {
numbers.add( new Integer( i + 1 ) );
}
}
}
}
if ( numbers.size() > 0 ) {
num = new int[numbers.size()];
// put all numbers within numbers to an array
for ( int i = 0; i < numbers.size(); i++ ) {
num[i] = ( (Integer) numbers.get( i ) ).intValue();
}
}
return num;
} // end of getGeoNumbersByRect
/**
* is a property unique?
*/
public boolean isUnique( String property ) {
DBaseIndex index = (DBaseIndex) dBaseIndexes.get( property );
if ( index == null ) {
return false;
}
return index.isUnique();
}
/**
* returns the properties (column headers) of the dBase-file<BR>
* associated to the shape-file<BR>
*/
public String[] getProperties()
throws HasNoDBaseFileException, DBaseException {
if ( !hasDBaseFile ) {
throw new HasNoDBaseFileException( "Exception: there is no dBase-file "
+ "associated to this shape-file" );
}
return dbf.getProperties();
}
/**
* returns the datatype of each column of the database file<BR>
* associated to the shape-file<BR>
*/
public String[] getDataTypes()
throws HasNoDBaseFileException, DBaseException {
if ( !hasDBaseFile ) {
throw new HasNoDBaseFileException( "Exception: there is no dBase-file "
+ "associated to this shape-file" );
}
return dbf.getDataTypes();
}
/**
*
*
* @return
*
* @throws HasNoDBaseFileException
* @throws DBaseException
*/
public int[] getDataLengths()
throws HasNoDBaseFileException, DBaseException {
String[] properties = getProperties();
int[] retval = new int[properties.length];
for ( int i = 0; i < properties.length; i++ ) {
retval[i] = dbf.getDataLength( properties[i] );
}
return retval;
}
/**
* returns the datatype of each column of the dBase associated<BR>
* to the shape-file specified by fields<BR>
*/
public String[] getDataTypes( String[] fields )
throws HasNoDBaseFileException, DBaseException {
if ( !hasDBaseFile ) {
throw new HasNoDBaseFileException( "Exception: there is no dBase-file "
+ "associated to this shape-file" );
}
return dbf.getDataTypes( fields );
}
/**
* returns the number of geometries within a feature collection<BR>
*
* @param fc :
* featurecollection which is checked for the number geomtries<BR>
*/
private int getGeometryCount( FeatureCollection fc ) {
return fc.size();
}
/**
* returns the type of the n'th feature in a featurecollection
*
* @param fc :
* FeatureCollection
* @param n :
* number of the feature which should be examined starts with 0
*/
private int getGeometryType( FeatureCollection fc, int n ) {
Feature feature = null;
feature = fc.getFeature( n );
Geometry[] g = feature.getGeometryPropertyValues();
if ( ( g == null ) || ( g.length == 0 ) ) {
return -1;
}
if ( g[0] instanceof Point ) {
return 0;
}
if ( g[0] instanceof Curve ) {
return 1;
}
if ( g[0] instanceof Surface ) {
return 2;
}
if ( g[0] instanceof MultiPoint ) {
return 3;
}
if ( g[0] instanceof MultiCurve ) {
return 4;
}
if ( g[0] instanceof MultiSurface ) {
return 5;
}
return -1;
}
/**
* returns the n'th feature of a featurecollection as a Geometry<BR>
*
* @param fc :
* FeatureCollection<BR>
* @param n :
* number of the feature which should be returned<BR>
*/
private Geometry getFeatureAsGeometry( FeatureCollection fc, int n ) {
Feature feature = null;
feature = fc.getFeature( n );
return feature.getGeometryPropertyValues()[0];
}
/**
*/
public FeatureProperty[] getFeatureProperties( FeatureCollection fc, int n ) {
Feature feature = null;
feature = fc.getFeature( n );
PropertyType[] ftp = feature.getFeatureType().getProperties();
FeatureProperty[] fp = new FeatureProperty[ftp.length];
FeatureProperty[] fp_ = feature.getProperties();
for ( int i = 0; i < ftp.length; i++ ) {
fp[i] = FeatureFactory.createFeatureProperty( ftp[i].getName(), fp_[i].getValue() );
}
return fp;
}
/**
*/
private void initDBaseFile( FeatureCollection fc )
throws DBaseException {
FieldDescriptor[] fieldDesc = null;
// get feature properties
FeatureProperty[] pairs = getFeatureProperties( fc, 0 );
// count regular fields
int cnt = 0;
FeatureType featT = fc.getFeature( 0 ).getFeatureType();
PropertyType[] ftp = featT.getProperties();
for ( int i = 0; i < pairs.length; i++ ) {
Object obj = pairs[i].getValue();
if ( obj instanceof Object[] ) {
obj = ( (Object[]) obj )[0];
}
if ( !( obj instanceof ByteArrayInputStream ) && !( obj instanceof Geometry ) ) {
cnt++;
}
}
// allocate memory for fielddescriptors
fieldDesc = new FieldDescriptor[cnt];
// get properties names and types and create a FieldDescriptor
// for each properties except the geometry-property
cnt = 0;
for ( int i = 0; i < ftp.length; i++ ) {
int pos = ftp[i].getName().getLocalName().lastIndexOf( '.' );
if ( pos < 0 ) {
pos = -1;
}
String s = ftp[i].getName().getLocalName().substring( pos + 1 );
if ( ftp[i].getType() == Types.INTEGER ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "N", (byte) 20, (byte) 0 );
} else if ( ftp[i].getType() == Types.BIGINT ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "N", (byte) 30, (byte) 0 );
} else if ( ftp[i].getType() == Types.SMALLINT ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "N", (byte) 4, (byte) 0 );
} else if ( ftp[i].getType() == Types.CHAR ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "C", (byte) 1, (byte) 0 );
} else if ( ftp[i].getType() == Types.FLOAT ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "N", (byte) 30, (byte) 10 );
} else if ( ftp[i].getType() == Types.DOUBLE || ftp[i].getType() == Types.NUMERIC ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "N", (byte) 30, (byte) 10 );
} else if ( ftp[i].getType() == Types.VARCHAR ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "C", (byte) 127, (byte) 0 );
} else if ( ftp[i].getType() == Types.DATE ) {
fieldDesc[cnt++] = new FieldDescriptor( s, "D", (byte) 12, (byte) 0 );
}
}
// initialize/create DBaseFile
try {
dbf = new DBaseFile( fileName, fieldDesc );
} catch ( DBaseException e ) {
hasDBaseFile = false;
}
}
/**
* writes a OGC FeatureCollection to a ESRI shape file.<BR>
* all features in the collection must have the same properties.<BR>
*/
public void writeShape( FeatureCollection fc )
throws Exception {
int nbyte = 0;
int geotype = -1;
byte shptype = -1;
int typ_ = getGeometryType( fc, 0 );
byte[] bytearray = null;
IndexRecord record = null;
SHPEnvelope mbr = null;
// mbr of the whole shape file
SHPEnvelope shpmbr = new SHPEnvelope();
// Set the Offset to the end of the fileHeader
int offset = ShapeConst.SHAPE_FILE_HEADER_LENGTH;
// initialize the dbasefile associated with the shapefile
initDBaseFile( fc );
// loop throug the Geometries of the feature collection anf write them
// to a bytearray
for ( int i = 0; i < getGeometryCount( fc ); i++ ) {
if ( i % 1000 == 0 ) {
System.gc();
}
// write i'th features properties to a ArrayList
PropertyType[] ftp = fc.getFeature( 0 ).getFeatureType().getProperties();
ArrayList vec = new ArrayList( ftp.length );
for ( int j = 0; j < ftp.length; j++ ) {
if ( ftp[j].getType() == Types.GEOMETRY )
continue;
FeatureProperty fp = fc.getFeature( i ).getDefaultProperty( ftp[j].getName() );
Object obj = null;
if ( fp != null ) {
obj = fp.getValue();
}
if ( obj instanceof Object[] ) {
obj = ( (Object[]) obj )[0];
}
if ( ( ftp[j].getType() == Types.INTEGER ) || ( ftp[j].getType() == Types.BIGINT )
|| ( ftp[j].getType() == Types.SMALLINT ) || ( ftp[j].getType() == Types.CHAR )
|| ( ftp[j].getType() == Types.FLOAT ) || ( ftp[j].getType() == Types.DOUBLE )
|| ( ftp[j].getType() == Types.NUMERIC )
|| ( ftp[j].getType() == Types.VARCHAR ) || ( ftp[j].getType() == Types.DATE ) ) {
vec.add( obj );
}
}
// write the ArrayList (properties) to the dbase file
try {
dbf.setRecord( vec );
} catch ( DBaseException db ) {
db.printStackTrace();
throw new Exception( db.toString() );
}
// Get Geometry Type of i'th feature
geotype = getGeometryType( fc, i );
if ( geotype < 0 ) {
continue;
}
if ( ( typ_ == 0 ) || ( typ_ == 3 ) ) {
if ( ( geotype != 0 ) && ( geotype != 3 ) ) {
throw new Exception( "not a homogen featurecollectiom" );
}
}
if ( ( typ_ == 1 ) || ( typ_ == 4 ) ) {
if ( ( geotype != 1 ) && ( geotype != 4 ) ) {
throw new Exception( "not a homogen featurecollectiom" );
}
}
if ( ( typ_ == 2 ) || ( typ_ == 5 ) ) {
if ( ( geotype != 2 ) && ( geotype != 5 ) ) {
throw new Exception( "not a homogen featurecollectiom" );
}
}
// get wks geometrie for feature (i) and write it to a file
if ( geotype == 0 ) {
// Geometrie Type = Point
Point wks = (Point) getFeatureAsGeometry( fc, i );
SHPPoint shppoint = new SHPPoint( wks.getPosition() );
nbyte = shppoint.size();
bytearray = new byte[nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
shppoint.writeSHPPoint( bytearray, ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
mbr = new SHPEnvelope( shppoint, shppoint );
if ( i == 0 ) {
shpmbr = mbr;
}
shptype = 1;
} else if ( geotype == 1 ) {
// Geometrie Type = LineString
Curve[] wks = new Curve[1];
wks[0] = (Curve) getFeatureAsGeometry( fc, i );
SHPPolyLine shppolyline = new SHPPolyLine( wks );
nbyte = shppolyline.size();
bytearray = new byte[nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
shppolyline.writeSHPPolyLine( bytearray, ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
mbr = shppolyline.getEnvelope();
if ( i == 0 ) {
shpmbr = mbr;
}
shptype = 3;
} else if ( geotype == 2 ) {
// Geometrie Type = Polygon
Surface[] wks = new Surface[1];
wks[0] = (Surface) getFeatureAsGeometry( fc, i );
validateOrientation( wks );
SHPPolygon shppolygon = new SHPPolygon( wks );
nbyte = shppolygon.size();
bytearray = new byte[nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
shppolygon.writeSHPPolygon( bytearray, ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
mbr = shppolygon.getEnvelope();
if ( i == 0 ) {
shpmbr = mbr;
}
shptype = 5;
} else if ( geotype == 3 ) {
// Geometrie Type = MultiPoint
MultiPoint wks = (MultiPoint) getFeatureAsGeometry( fc, i );
SHPMultiPoint shpmultipoint = new SHPMultiPoint( wks );
nbyte = shpmultipoint.size();
bytearray = new byte[nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
shpmultipoint.writeSHPMultiPoint( bytearray,
ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
mbr = shpmultipoint.getEnvelope();
shptype = 8;
} else if ( geotype == 4 ) {
// Geometrie Type = MultiLineString
MultiCurve wks = (MultiCurve) getFeatureAsGeometry( fc, i );
SHPPolyLine shppolyline = new SHPPolyLine( wks.getAllCurves() );
nbyte = shppolyline.size();
bytearray = new byte[nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
shppolyline.writeSHPPolyLine( bytearray, ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
mbr = shppolyline.getEnvelope();
if ( i == 0 ) {
shpmbr = mbr;
}
shptype = 3;
} else if ( geotype == 5 ) {
// Geometrie Type = MultiPolygon
MultiSurface wks = (MultiSurface) getFeatureAsGeometry( fc, i );
SHPPolygon shppolygon = new SHPPolygon( wks.getAllSurfaces() );
nbyte = shppolygon.size();
bytearray = new byte[nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
shppolygon.writeSHPPolygon( bytearray, ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
mbr = shppolygon.getEnvelope();
if ( i == 0 ) {
shpmbr = mbr;
}
shptype = 5;
}
// write bytearray to the shape file
record = new IndexRecord( offset / 2, nbyte / 2 );
// write recordheader to the bytearray
ByteUtils.writeBEInt( bytearray, 0, i );
ByteUtils.writeBEInt( bytearray, 4, nbyte / 2 );
// write record (bytearray) including recordheader to the shape file
shp.write( bytearray, record, mbr );
// actualise shape file minimum boundary rectangle
if ( mbr.west < shpmbr.west ) {
shpmbr.west = mbr.west;
}
if ( mbr.east > shpmbr.east ) {
shpmbr.east = mbr.east;
}
if ( mbr.south < shpmbr.south ) {
shpmbr.south = mbr.south;
}
if ( mbr.north > shpmbr.north ) {
shpmbr.north = mbr.north;
}
// icrement offset for pointing at the end of the file
offset += ( nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH );
bytearray = null;
}
dbf.writeAllToFile();
// write shape header
shp.writeHeader( offset, shptype, shpmbr );
}
private void validateOrientation( Surface[] wks )
throws GeometryException {
com.vividsolutions.jts.geom.Geometry jts = JTSAdapter.export( wks[0] );
CGAlgorithms.isCCW( jts.getCoordinates() );
if ( CGAlgorithms.isCCW( jts.getCoordinates() ) ) {
Position[] pos = wks[0].getSurfaceBoundary().getExteriorRing().getPositions();
Position[] pos2 = new Position[pos.length];
for ( int j = 0; j < pos2.length; j++ ) {
pos2[j] = pos[pos.length - j - 1];
}
Position[][] iPos = null;
if ( wks[0].getSurfaceBoundary().getInteriorRings() != null ) {
Ring[] rings = wks[0].getSurfaceBoundary().getInteriorRings();
iPos = new Position[rings.length][];
for ( int j = 0; j < rings.length; j++ ) {
pos = rings[j].getPositions();
iPos[j] = new Position[pos.length];
for ( int k = 0; k < pos.length; k++ ) {
iPos[j][k] = pos[pos.length - k - 1];
}
}
}
wks[0] = GeometryFactory.createSurface( pos2, iPos, new SurfaceInterpolationImpl(),
wks[0].getCoordinateSystem() );
}
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: ShapeFile.java,v $
Revision 1.41 2006/11/28 09:31:35 poth
set initDBaseFile( FeatureCollection fc ) to private
Revision 1.40 2006/11/27 09:07:52 poth
JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code.
Revision 1.39 2006/10/17 15:02:24 poth
bug fix - building column names
Revision 1.38 2006/08/30 17:03:05 mschneider
Rewrote handling of mapping to custom feature types (necessary for ShapeDatastore).
Revision 1.37 2006/07/13 21:02:10 poth
*** empty log message ***
Revision 1.36 2006/06/25 20:33:59 poth
*** empty log message ***
Revision 1.35 2006/06/06 10:33:48 poth
bug fix
Revision 1.34 2006/06/05 15:21:53 poth
support for polygonz type added
Revision 1.33 2006/05/29 16:16:05 poth
code simplification
********************************************************************** */