0001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/io/shpapi/ShapeFile.java $
0002: /*---------------- FILE HEADER ------------------------------------------
0003:
0004: This file is part of deegree.
0005: Copyright (C) 2001-2008 by:
0006: EXSE, Department of Geography, University of Bonn
0007: http://www.giub.uni-bonn.de/deegree/
0008: lat/lon GmbH
0009: http://www.lat-lon.de
0010:
0011: This library is free software; you can redistribute it and/or
0012: modify it under the terms of the GNU Lesser General Public
0013: License as published by the Free Software Foundation; either
0014: version 2.1 of the License, or (at your option) any later version.
0015:
0016: This library is distributed in the hope that it will be useful,
0017: but WITHOUT ANY WARRANTY; without even the implied warranty of
0018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0019: Lesser General Public License for more details.
0020:
0021: You should have received a copy of the GNU Lesser General Public
0022: License along with this library; if not, write to the Free Software
0023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0024:
0025: Contact:
0026:
0027: Andreas Poth
0028: lat/lon GmbH
0029: Aennchenstr. 19
0030: 53177 Bonn
0031: Germany
0032: E-Mail: poth@lat-lon.de
0033:
0034: Prof. Dr. Klaus Greve
0035: Department of Geography
0036: University of Bonn
0037: Meckenheimer Allee 166
0038: 53115 Bonn
0039: Germany
0040: E-Mail: greve@giub.uni-bonn.de
0041:
0042:
0043: ---------------------------------------------------------------------------*/
0044: package org.deegree.io.shpapi;
0045:
0046: import java.io.ByteArrayInputStream;
0047: import java.io.IOException;
0048: import java.util.ArrayList;
0049: import java.util.Enumeration;
0050: import java.util.Hashtable;
0051: import java.util.List;
0052: import java.util.Map;
0053:
0054: import org.deegree.datatypes.Types;
0055: import org.deegree.io.dbaseapi.DBaseException;
0056: import org.deegree.io.dbaseapi.DBaseFile;
0057: import org.deegree.io.dbaseapi.DBaseIndex;
0058: import org.deegree.io.dbaseapi.DBaseIndexException;
0059: import org.deegree.io.dbaseapi.FieldDescriptor;
0060: import org.deegree.io.rtree.HyperBoundingBox;
0061: import org.deegree.io.rtree.HyperPoint;
0062: import org.deegree.io.rtree.RTree;
0063: import org.deegree.io.rtree.RTreeException;
0064: import org.deegree.model.feature.Feature;
0065: import org.deegree.model.feature.FeatureCollection;
0066: import org.deegree.model.feature.FeatureFactory;
0067: import org.deegree.model.feature.FeatureProperty;
0068: import org.deegree.model.feature.schema.FeatureType;
0069: import org.deegree.model.feature.schema.GeometryPropertyType;
0070: import org.deegree.model.feature.schema.PropertyType;
0071: import org.deegree.model.spatialschema.ByteUtils;
0072: import org.deegree.model.spatialschema.Curve;
0073: import org.deegree.model.spatialschema.Envelope;
0074: import org.deegree.model.spatialschema.Geometry;
0075: import org.deegree.model.spatialschema.GeometryException;
0076: import org.deegree.model.spatialschema.GeometryFactory;
0077: import org.deegree.model.spatialschema.JTSAdapter;
0078: import org.deegree.model.spatialschema.MultiCurve;
0079: import org.deegree.model.spatialschema.MultiPoint;
0080: import org.deegree.model.spatialschema.MultiSurface;
0081: import org.deegree.model.spatialschema.Point;
0082: import org.deegree.model.spatialschema.Position;
0083: import org.deegree.model.spatialschema.Ring;
0084: import org.deegree.model.spatialschema.Surface;
0085: import org.deegree.model.spatialschema.SurfaceInterpolationImpl;
0086:
0087: import com.vividsolutions.jts.algorithm.CGAlgorithms;
0088:
0089: /**
0090: * Class representing an ESRI Shape File.
0091: *
0092: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
0093: * @author last edited by: $Author: apoth $
0094: *
0095: * @version $Revision: 9342 $, $Date: 2007-12-27 04:32:57 -0800 (Thu, 27 Dec 2007) $
0096: */
0097: public class ShapeFile {
0098:
0099: private DBaseFile dbf = null;
0100:
0101: private SHP2WKS shpwks = new SHP2WKS();
0102:
0103: /*
0104: * contains the dBase indexes
0105: */
0106: private Hashtable<String, DBaseIndex> dBaseIndexes = new Hashtable<String, DBaseIndex>(
0107: 50);
0108:
0109: /*
0110: * aggregated Instance-variables
0111: */
0112: private MainFile shp = null;
0113:
0114: private RTree rti = null;
0115:
0116: private String fileName = null;
0117:
0118: /*
0119: * indicates if a dBase-file is associated to the shape-file
0120: */
0121: private boolean hasDBaseFile = true;
0122:
0123: /*
0124: * indicates if an R-tree index is associated to the shape-file
0125: */
0126: private boolean hasRTreeIndex = true;
0127:
0128: /**
0129: * constructor: <BR>
0130: * Construct a ShapeFile from a file name.<BR>
0131: */
0132: public ShapeFile(String fileName) throws IOException {
0133: this .fileName = fileName;
0134: /*
0135: * initialize the MainFile
0136: */
0137: shp = new MainFile(fileName);
0138:
0139: /*
0140: * initialize the DBaseFile
0141: */
0142: try {
0143: dbf = new DBaseFile(fileName);
0144: } catch (IOException e) {
0145: hasDBaseFile = false;
0146: }
0147:
0148: /*
0149: * initialize the RTreeIndex
0150: */
0151: try {
0152: rti = new RTree(fileName + ".rti");
0153: } catch (RTreeException e) {
0154: hasRTreeIndex = false;
0155: }
0156:
0157: if (hasDBaseFile) {
0158: String[] s = null;
0159: try {
0160: s = getProperties();
0161: } catch (Exception e) {
0162: e.printStackTrace();
0163: }
0164: for (int i = 0; i < s.length; i++) {
0165: try {
0166: dBaseIndexes.put(s[i], new DBaseIndex(fileName
0167: + "$" + s[i]));
0168: } catch (IOException e) {
0169: }
0170: }
0171: }
0172: }
0173:
0174: /**
0175: * constructor: <BR>
0176: * Construct a ShapeFile from a file name.<BR>
0177: */
0178: public ShapeFile(String url, String rwflag) throws IOException {
0179: this .fileName = url;
0180: shp = new MainFile(url, rwflag);
0181: // TODO: initialize dbf, rti
0182: hasDBaseFile = false;
0183: hasRTreeIndex = false;
0184: }
0185:
0186: /**
0187: *
0188: */
0189: public void close() {
0190:
0191: shp.close();
0192: dbf.close();
0193:
0194: if (rti != null) {
0195: try {
0196: rti.close();
0197: } catch (Exception e) {
0198: // should never happen
0199: e.printStackTrace();
0200: }
0201: }
0202:
0203: for (Enumeration e = dBaseIndexes.elements(); e
0204: .hasMoreElements();) {
0205: DBaseIndex index = (DBaseIndex) e.nextElement();
0206:
0207: try {
0208: index.close();
0209: } catch (Exception ex) {
0210: }
0211: }
0212: }
0213:
0214: /**
0215: * Overrides the default feature type (which is generated from all columns in the dbase file) to
0216: * allow customized naming and ordering of properties.
0217: *
0218: * @param ft
0219: * @param ftMapping
0220: */
0221: public void setFeatureType(FeatureType ft,
0222: Map<PropertyType, String> ftMapping) {
0223: dbf.setFeatureType(ft, ftMapping);
0224: }
0225:
0226: /**
0227: * returns true if a column is indexed
0228: */
0229: public boolean hasDBaseIndex(String column) {
0230: DBaseIndex index = dBaseIndexes.get(column);
0231: return index != null;
0232: }
0233:
0234: /**
0235: * returns true if a dBase-file is associated to the shape-file<BR>
0236: */
0237: public boolean hasDBaseFile() {
0238: return this .hasDBaseFile;
0239: }
0240:
0241: /**
0242: * returns true if an R-tree index is associated to the shape-file<BR>
0243: */
0244: public boolean hasRTreeIndex() {
0245: return this .hasRTreeIndex;
0246: }
0247:
0248: /**
0249: * returns the number of records within a shape-file<BR>
0250: */
0251: public int getRecordNum() {
0252: return shp.getRecordNum();
0253: }
0254:
0255: /**
0256: * returns the minimum bounding rectangle of all geometries<BR>
0257: * within the shape-file
0258: */
0259: public Envelope getFileMBR() {
0260: double xmin = shp.getFileMBR().west;
0261: double xmax = shp.getFileMBR().east;
0262: double ymin = shp.getFileMBR().south;
0263: double ymax = shp.getFileMBR().north;
0264:
0265: return GeometryFactory.createEnvelope(xmin, ymin, xmax, ymax,
0266: null);
0267: }
0268:
0269: /**
0270: * returns the minimum bound rectangle of RecNo'th Geometrie<BR>
0271: */
0272: public Envelope getMBRByRecNo(int recNo) throws IOException {
0273: SHPEnvelope shpenv = shp.getRecordMBR(recNo);
0274: double xmin = shpenv.west;
0275: double xmax = shpenv.east;
0276: double ymin = shpenv.south;
0277: double ymax = shpenv.north;
0278:
0279: return GeometryFactory.createEnvelope(xmin, ymin, xmax, ymax,
0280: null);
0281: }
0282:
0283: /**
0284: * Returns the given entry of the shape file as a {@link Feature} instance.
0285: * <p>
0286: * This contains the geometry as well as the attributes stored into the dbase file. The geometry
0287: * property will use a default name (app:GEOM).
0288: *
0289: * @param RecNo
0290: * @return the given entry of the shape file as a Feature instance
0291: * @throws IOException
0292: * @throws HasNoDBaseFileException
0293: * @throws DBaseException
0294: */
0295: public Feature getFeatureByRecNo(int RecNo) throws IOException,
0296: HasNoDBaseFileException, DBaseException {
0297:
0298: if (!hasDBaseFile) {
0299: throw new HasNoDBaseFileException(
0300: "Exception: there is no dBase-file "
0301: + "associated to this shape-file");
0302: }
0303:
0304: // get feature (without geometry property) from DBaseFile
0305: Feature feature = dbf.getFRow(RecNo);
0306:
0307: // exchange null geometries with real geometry
0308: Geometry geo = getGeometryByRecNo(RecNo);
0309: GeometryPropertyType[] geoPTs = feature.getFeatureType()
0310: .getGeometryProperties();
0311: for (int i = 0; i < geoPTs.length; i++) {
0312: FeatureProperty[] geoProp = feature.getProperties(geoPTs[i]
0313: .getName());
0314: for (int j = 0; j < geoProp.length; j++) {
0315: geoProp[j].setValue(geo);
0316: }
0317: }
0318:
0319: return feature;
0320: }
0321:
0322: /**
0323: * returns RecNo'th Geometrie<BR>
0324: */
0325: public Geometry getGeometryByRecNo(int recNo) throws IOException {
0326: Geometry geom = null;
0327:
0328: int shpType = getShapeTypeByRecNo(recNo);
0329:
0330: if (shpType == ShapeConst.SHAPE_TYPE_POINT) {
0331: SHPPoint shppoint = (SHPPoint) shp.getByRecNo(recNo);
0332: geom = shpwks.transformPoint(null, shppoint);
0333: } else if (shpType == ShapeConst.SHAPE_TYPE_MULTIPOINT) {
0334: SHPMultiPoint shpmultipoint = (SHPMultiPoint) shp
0335: .getByRecNo(recNo);
0336: Point[] points = shpwks.transformMultiPoint(null,
0337: shpmultipoint);
0338: if (points != null) {
0339: MultiPoint mp = GeometryFactory
0340: .createMultiPoint(points);
0341: geom = mp;
0342: } else {
0343: geom = null;
0344: }
0345: } else if (shpType == ShapeConst.SHAPE_TYPE_POLYLINE) {
0346: SHPPolyLine shppolyline = (SHPPolyLine) shp
0347: .getByRecNo(recNo);
0348: Curve[] curves = shpwks
0349: .transformPolyLine(null, shppolyline);
0350: if ((curves != null) && (curves.length > 1)) {
0351: // create multi curve
0352: MultiCurve mc = GeometryFactory
0353: .createMultiCurve(curves);
0354: geom = mc;
0355: } else if ((curves != null) && (curves.length == 1)) {
0356: // single curve
0357: geom = curves[0];
0358: } else {
0359: geom = null;
0360: }
0361: } else if (shpType == ShapeConst.SHAPE_TYPE_POLYGON) {
0362: SHPPolygon shppoly = (SHPPolygon) shp.getByRecNo(recNo);
0363: Surface[] polygons = shpwks.transformPolygon(null, shppoly);
0364: if ((polygons != null) && (polygons.length > 1)) {
0365: // create multi surface
0366: MultiSurface ms = GeometryFactory
0367: .createMultiSurface(polygons);
0368: geom = ms;
0369: } else if ((polygons != null) && (polygons.length == 1)) {
0370: geom = polygons[0];
0371: } else {
0372: geom = null;
0373: }
0374: } else if (shpType == ShapeConst.SHAPE_TYPE_POLYGONZ) {
0375:
0376: SHPPolygon3D shppoly = (SHPPolygon3D) shp.getByRecNo(recNo);
0377:
0378: Surface[] polygons = shpwks.transformPolygon(null, shppoly);
0379:
0380: if ((polygons != null) && (polygons.length > 1)) {
0381: // create multi surface
0382: MultiSurface ms = GeometryFactory
0383: .createMultiSurface(polygons);
0384: geom = ms;
0385: } else if ((polygons != null) && (polygons.length == 1)) {
0386: geom = polygons[0];
0387: } else {
0388: geom = null;
0389: }
0390: }
0391:
0392: return geom;
0393: }
0394:
0395: /**
0396: * returns the type of the RecNo'th Geometrie<BR>
0397: * per definition a shape file contains onlay one shape type<BR>
0398: * but null shapes are possible too!<BR>
0399: */
0400: public int getShapeTypeByRecNo(int RecNo) throws IOException {
0401: return shp.getShapeTypeByRecNo(RecNo);
0402: }
0403:
0404: /**
0405: * returns a int array that containts all the record numbers that matches the search operation
0406: */
0407: public int[] getGeoNumbersByAttribute(String column,
0408: Comparable value) throws IOException, DBaseIndexException {
0409: DBaseIndex index = dBaseIndexes.get(column);
0410:
0411: if (index == null) {
0412: return null;
0413: }
0414:
0415: return index.search(value);
0416: }
0417:
0418: /**
0419: * returns a ArrayList that contains all geomeries of the shape file<BR>
0420: * which mbr's are completly or partly within the rectangle r<BR>
0421: * only Points, MultiPoints, PolyLines and Polygons are handled<BR>
0422: */
0423: public int[] getGeoNumbersByRect(Envelope r) throws IOException {
0424: SHPPoint geom = null;
0425: int[] num = null;
0426: int numRecs = getRecordNum();
0427:
0428: Envelope mbr = getFileMBR();
0429:
0430: if (!mbr.intersects(r)) {
0431: return null;
0432: }
0433:
0434: if (hasRTreeIndex) {
0435: try {
0436: // translate envelope (deegree) to bounding box (rtree)
0437: HyperBoundingBox box = new HyperBoundingBox(
0438: new HyperPoint(r.getMin().getAsArray()),
0439: new HyperPoint(r.getMax().getAsArray()));
0440: Object[] iNumbers = rti.intersects(box);
0441: num = new int[iNumbers.length];
0442:
0443: for (int i = 0; i < iNumbers.length; i++)
0444: num[i] = ((Integer) iNumbers[i]).intValue();
0445:
0446: return num;
0447: } catch (Exception e) {
0448: e.printStackTrace();
0449: }
0450: }
0451:
0452: // for every geometry (record) within the shape file
0453: // check if it's inside the search-rectangle r
0454: List<Integer> numbers = new ArrayList<Integer>(500);
0455: for (int i = 0; i < numRecs; i++) {
0456: if (getShapeTypeByRecNo(i + 1) == ShapeConst.SHAPE_TYPE_NULL) {
0457: } else if (getShapeTypeByRecNo(i + 1) == ShapeConst.SHAPE_TYPE_POINT) {
0458: geom = (SHPPoint) shp.getByRecNo(i + 1);
0459:
0460: // is the Point within the seach rectangle?
0461: Position pos = GeometryFactory.createPosition(geom.x,
0462: geom.y);
0463:
0464: if (r.contains(pos) == true) {
0465: numbers.add(new Integer(i + 1));
0466: }
0467: } else {
0468: // get minimum bounding rectangle of the i'th record
0469: mbr = getMBRByRecNo(i + 1);
0470:
0471: // is the i'th record a geometrie having a mbr
0472: // (only for PolyLines, Polygons and MultiPoints mbrs are defined)
0473: if (mbr != null) {
0474: // if the tested rectangles are not disjunct the number of the
0475: // actual record is added to the ArrayList
0476: if (mbr.intersects(r)) {
0477: numbers.add(new Integer(i + 1));
0478: }
0479: }
0480: }
0481: }
0482:
0483: if (numbers.size() > 0) {
0484: num = new int[numbers.size()];
0485:
0486: // put all numbers within numbers to an array
0487: for (int i = 0; i < numbers.size(); i++) {
0488: num[i] = numbers.get(i);
0489: }
0490: }
0491:
0492: return num;
0493: } // end of getGeoNumbersByRect
0494:
0495: /**
0496: * is a property unique?
0497: */
0498: public boolean isUnique(String property) {
0499: DBaseIndex index = dBaseIndexes.get(property);
0500:
0501: if (index == null) {
0502: return false;
0503: }
0504:
0505: return index.isUnique();
0506: }
0507:
0508: /**
0509: * returns the properties (column headers) of the dBase-file<BR>
0510: * associated to the shape-file<BR>
0511: */
0512: public String[] getProperties() throws HasNoDBaseFileException,
0513: DBaseException {
0514: if (!hasDBaseFile) {
0515: throw new HasNoDBaseFileException(
0516: "Exception: there is no dBase-file "
0517: + "associated to this shape-file");
0518: }
0519:
0520: return dbf.getProperties();
0521: }
0522:
0523: /**
0524: * returns the datatype of each column of the database file<BR>
0525: * associated to the shape-file<BR>
0526: */
0527: public String[] getDataTypes() throws HasNoDBaseFileException,
0528: DBaseException {
0529: if (!hasDBaseFile) {
0530: throw new HasNoDBaseFileException(
0531: "Exception: there is no dBase-file "
0532: + "associated to this shape-file");
0533: }
0534:
0535: return dbf.getDataTypes();
0536: }
0537:
0538: /**
0539: *
0540: *
0541: * @return
0542: *
0543: * @throws HasNoDBaseFileException
0544: * @throws DBaseException
0545: */
0546: public int[] getDataLengths() throws HasNoDBaseFileException,
0547: DBaseException {
0548: String[] properties = getProperties();
0549: int[] retval = new int[properties.length];
0550:
0551: for (int i = 0; i < properties.length; i++) {
0552: retval[i] = dbf.getDataLength(properties[i]);
0553: }
0554:
0555: return retval;
0556: }
0557:
0558: /**
0559: * returns the datatype of each column of the dBase associated<BR>
0560: * to the shape-file specified by fields<BR>
0561: */
0562: public String[] getDataTypes(String[] fields)
0563: throws HasNoDBaseFileException, DBaseException {
0564: if (!hasDBaseFile) {
0565: throw new HasNoDBaseFileException(
0566: "Exception: there is no dBase-file "
0567: + "associated to this shape-file");
0568: }
0569:
0570: return dbf.getDataTypes(fields);
0571: }
0572:
0573: /**
0574: * returns the number of geometries within a feature collection<BR>
0575: *
0576: * @param fc :
0577: * featurecollection which is checked for the number geomtries<BR>
0578: */
0579: private int getGeometryCount(FeatureCollection fc) {
0580: return fc.size();
0581: }
0582:
0583: /**
0584: * returns the type of the n'th feature in a featurecollection
0585: *
0586: * @param fc
0587: * FeatureCollection. must not be empty.
0588: * @param n
0589: * number of the feature which should be examined starts with 0
0590: */
0591: private int getGeometryType(FeatureCollection fc, int n) {
0592: Feature feature = null;
0593:
0594: feature = fc.getFeature(n);
0595:
0596: Geometry[] g = feature.getGeometryPropertyValues();
0597:
0598: if ((g == null) || (g.length == 0)) {
0599: return -1;
0600: }
0601:
0602: if (g[0] instanceof Point) {
0603: return 0;
0604: }
0605:
0606: if (g[0] instanceof Curve) {
0607: return 1;
0608: }
0609:
0610: if (g[0] instanceof Surface) {
0611: return 2;
0612: }
0613:
0614: if (g[0] instanceof MultiPoint) {
0615: return 3;
0616: }
0617:
0618: if (g[0] instanceof MultiCurve) {
0619: return 4;
0620: }
0621:
0622: if (g[0] instanceof MultiSurface) {
0623: return 5;
0624: }
0625:
0626: return -1;
0627: }
0628:
0629: /**
0630: * returns the n'th feature of a featurecollection as a Geometry<BR>
0631: *
0632: * @param fc :
0633: * FeatureCollection<BR>
0634: * @param n :
0635: * number of the feature which should be returned<BR>
0636: */
0637: private Geometry getFeatureAsGeometry(FeatureCollection fc, int n) {
0638: Feature feature = null;
0639:
0640: feature = fc.getFeature(n);
0641:
0642: return feature.getGeometryPropertyValues()[0];
0643: }
0644:
0645: /**
0646: */
0647: public FeatureProperty[] getFeatureProperties(FeatureCollection fc,
0648: int n) {
0649: Feature feature = null;
0650:
0651: feature = fc.getFeature(n);
0652:
0653: PropertyType[] ftp = feature.getFeatureType().getProperties();
0654: FeatureProperty[] fp = new FeatureProperty[ftp.length];
0655: FeatureProperty[] fp_ = feature.getProperties();
0656:
0657: for (int i = 0; i < ftp.length; i++) {
0658: fp[i] = FeatureFactory.createFeatureProperty(ftp[i]
0659: .getName(), fp_[i].getValue());
0660: }
0661:
0662: return fp;
0663: }
0664:
0665: /**
0666: */
0667: private void initDBaseFile(FeatureCollection fc)
0668: throws DBaseException {
0669: FieldDescriptor[] fieldDesc = null;
0670:
0671: // get feature properties
0672: FeatureProperty[] pairs = getFeatureProperties(fc, 0);
0673:
0674: // count regular fields
0675: int cnt = 0;
0676: FeatureType featT = fc.getFeature(0).getFeatureType();
0677: PropertyType[] ftp = featT.getProperties();
0678: for (int i = 0; i < pairs.length; i++) {
0679: Object obj = pairs[i].getValue();
0680:
0681: if (obj instanceof Object[]) {
0682: obj = ((Object[]) obj)[0];
0683: }
0684: if (!(obj instanceof ByteArrayInputStream)
0685: && !(obj instanceof Geometry)) {
0686: cnt++;
0687: }
0688: }
0689:
0690: // allocate memory for fielddescriptors
0691: fieldDesc = new FieldDescriptor[cnt];
0692:
0693: // get properties names and types and create a FieldDescriptor
0694: // for each properties except the geometry-property
0695: cnt = 0;
0696: for (int i = 0; i < ftp.length; i++) {
0697: int pos = ftp[i].getName().getLocalName().lastIndexOf('.');
0698: if (pos < 0) {
0699: pos = -1;
0700: }
0701: String s = ftp[i].getName().getLocalName().substring(
0702: pos + 1);
0703: if (ftp[i].getType() == Types.INTEGER) {
0704: fieldDesc[cnt++] = new FieldDescriptor(s, "N",
0705: (byte) 20, (byte) 0);
0706: } else if (ftp[i].getType() == Types.BIGINT) {
0707: fieldDesc[cnt++] = new FieldDescriptor(s, "N",
0708: (byte) 30, (byte) 0);
0709: } else if (ftp[i].getType() == Types.SMALLINT) {
0710: fieldDesc[cnt++] = new FieldDescriptor(s, "N",
0711: (byte) 4, (byte) 0);
0712: } else if (ftp[i].getType() == Types.CHAR) {
0713: fieldDesc[cnt++] = new FieldDescriptor(s, "C",
0714: (byte) 1, (byte) 0);
0715: } else if (ftp[i].getType() == Types.FLOAT) {
0716: fieldDesc[cnt++] = new FieldDescriptor(s, "N",
0717: (byte) 30, (byte) 10);
0718: } else if (ftp[i].getType() == Types.DOUBLE
0719: || ftp[i].getType() == Types.NUMERIC) {
0720: fieldDesc[cnt++] = new FieldDescriptor(s, "N",
0721: (byte) 30, (byte) 10);
0722: } else if (ftp[i].getType() == Types.VARCHAR) {
0723: fieldDesc[cnt++] = new FieldDescriptor(s, "C",
0724: (byte) 127, (byte) 0);
0725: } else if (ftp[i].getType() == Types.DATE) {
0726: fieldDesc[cnt++] = new FieldDescriptor(s, "D",
0727: (byte) 12, (byte) 0);
0728: }
0729: }
0730:
0731: // initialize/create DBaseFile
0732: try {
0733: dbf = new DBaseFile(fileName, fieldDesc);
0734: } catch (DBaseException e) {
0735: hasDBaseFile = false;
0736: }
0737: }
0738:
0739: /**
0740: * writes a OGC FeatureCollection to a ESRI shape file.<BR>
0741: * all features in the collection must have the same properties.<BR>
0742: *
0743: * @param fc
0744: * FeatureCollection. must not be null or empty.
0745: * @throws Exception
0746: */
0747: public void writeShape(FeatureCollection fc) throws Exception {
0748:
0749: int nbyte = 0;
0750: int geotype = -1;
0751: byte shptype = -1;
0752: int typ_ = getGeometryType(fc, 0);
0753: byte[] bytearray = null;
0754: IndexRecord record = null;
0755: SHPEnvelope mbr = null;
0756: // mbr of the whole shape file
0757: SHPEnvelope shpmbr = new SHPEnvelope();
0758:
0759: // Set the Offset to the end of the fileHeader
0760: int offset = ShapeConst.SHAPE_FILE_HEADER_LENGTH;
0761:
0762: // initialize the dbasefile associated with the shapefile
0763: initDBaseFile(fc);
0764:
0765: // loop throug the Geometries of the feature collection anf write them
0766: // to a bytearray
0767: for (int i = 0; i < getGeometryCount(fc); i++) {
0768: if (i % 1000 == 0) {
0769: System.gc();
0770: }
0771: // write i'th features properties to a ArrayList
0772: PropertyType[] ftp = fc.getFeature(0).getFeatureType()
0773: .getProperties();
0774: ArrayList<Object> vec = new ArrayList<Object>(ftp.length);
0775: for (int j = 0; j < ftp.length; j++) {
0776: if (ftp[j].getType() == Types.GEOMETRY)
0777: continue;
0778: FeatureProperty fp = fc.getFeature(i)
0779: .getDefaultProperty(ftp[j].getName());
0780: Object obj = null;
0781: if (fp != null) {
0782: obj = fp.getValue();
0783: }
0784:
0785: if (obj instanceof Object[]) {
0786: obj = ((Object[]) obj)[0];
0787: }
0788:
0789: if ((ftp[j].getType() == Types.INTEGER)
0790: || (ftp[j].getType() == Types.BIGINT)
0791: || (ftp[j].getType() == Types.SMALLINT)
0792: || (ftp[j].getType() == Types.CHAR)
0793: || (ftp[j].getType() == Types.FLOAT)
0794: || (ftp[j].getType() == Types.DOUBLE)
0795: || (ftp[j].getType() == Types.NUMERIC)
0796: || (ftp[j].getType() == Types.VARCHAR)
0797: || (ftp[j].getType() == Types.DATE)) {
0798: vec.add(obj);
0799: }
0800:
0801: }
0802:
0803: // write the ArrayList (properties) to the dbase file
0804: try {
0805: dbf.setRecord(vec);
0806: } catch (DBaseException db) {
0807: db.printStackTrace();
0808: throw new Exception(db.toString());
0809: }
0810:
0811: // Get Geometry Type of i'th feature
0812: geotype = getGeometryType(fc, i);
0813:
0814: if (geotype < 0) {
0815: continue;
0816: }
0817:
0818: if ((typ_ == 0) || (typ_ == 3)) {
0819: if ((geotype != 0) && (geotype != 3)) {
0820: throw new Exception(
0821: "Not a homogen FeatureCollection");
0822: }
0823: }
0824:
0825: if ((typ_ == 1) || (typ_ == 4)) {
0826: if ((geotype != 1) && (geotype != 4)) {
0827: throw new Exception(
0828: "Not a homogen FeatureCollection");
0829: }
0830: }
0831:
0832: if ((typ_ == 2) || (typ_ == 5)) {
0833: if ((geotype != 2) && (geotype != 5)) {
0834: throw new Exception(
0835: "Not a homogen FeatureCollection");
0836: }
0837: }
0838:
0839: // get wks geometrie for feature (i) and write it to a file
0840: if (geotype == 0) {
0841: // Geometrie Type = Point
0842: Point wks = (Point) getFeatureAsGeometry(fc, i);
0843: SHPPoint shppoint = new SHPPoint(wks.getPosition());
0844: nbyte = shppoint.size();
0845: bytearray = new byte[nbyte
0846: + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
0847: shppoint.writeSHPPoint(bytearray,
0848: ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
0849: mbr = new SHPEnvelope(shppoint, shppoint);
0850:
0851: if (i == 0) {
0852: shpmbr = mbr;
0853: }
0854:
0855: shptype = 1;
0856: } else if (geotype == 1) {
0857: // Geometrie Type = LineString
0858: Curve[] wks = new Curve[1];
0859: wks[0] = (Curve) getFeatureAsGeometry(fc, i);
0860:
0861: SHPPolyLine shppolyline = new SHPPolyLine(wks);
0862: nbyte = shppolyline.size();
0863: bytearray = new byte[nbyte
0864: + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
0865: shppolyline.writeSHPPolyLine(bytearray,
0866: ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
0867: mbr = shppolyline.getEnvelope();
0868:
0869: if (i == 0) {
0870: shpmbr = mbr;
0871: }
0872:
0873: shptype = 3;
0874: } else if (geotype == 2) {
0875: // Geometrie Type = Polygon
0876: Surface[] wks = new Surface[1];
0877: wks[0] = (Surface) getFeatureAsGeometry(fc, i);
0878: validateOrientation(wks);
0879:
0880: SHPPolygon shppolygon = new SHPPolygon(wks);
0881: nbyte = shppolygon.size();
0882: bytearray = new byte[nbyte
0883: + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
0884: shppolygon.writeSHPPolygon(bytearray,
0885: ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
0886: mbr = shppolygon.getEnvelope();
0887:
0888: if (i == 0) {
0889: shpmbr = mbr;
0890: }
0891:
0892: shptype = 5;
0893: } else if (geotype == 3) {
0894: // Geometrie Type = MultiPoint
0895: MultiPoint wks = (MultiPoint) getFeatureAsGeometry(fc,
0896: i);
0897: SHPMultiPoint shpmultipoint = new SHPMultiPoint(wks);
0898: nbyte = shpmultipoint.size();
0899: bytearray = new byte[nbyte
0900: + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
0901: shpmultipoint.writeSHPMultiPoint(bytearray,
0902: ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
0903: mbr = shpmultipoint.getEnvelope();
0904: shptype = 8;
0905: } else if (geotype == 4) {
0906: // Geometrie Type = MultiLineString
0907: MultiCurve wks = (MultiCurve) getFeatureAsGeometry(fc,
0908: i);
0909: SHPPolyLine shppolyline = new SHPPolyLine(wks
0910: .getAllCurves());
0911: nbyte = shppolyline.size();
0912: bytearray = new byte[nbyte
0913: + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
0914: shppolyline.writeSHPPolyLine(bytearray,
0915: ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
0916: mbr = shppolyline.getEnvelope();
0917:
0918: if (i == 0) {
0919: shpmbr = mbr;
0920: }
0921:
0922: shptype = 3;
0923: } else if (geotype == 5) {
0924: // Geometrie Type = MultiPolygon
0925: MultiSurface wks = (MultiSurface) getFeatureAsGeometry(
0926: fc, i);
0927: SHPPolygon shppolygon = new SHPPolygon(wks
0928: .getAllSurfaces());
0929: nbyte = shppolygon.size();
0930: bytearray = new byte[nbyte
0931: + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH];
0932: shppolygon.writeSHPPolygon(bytearray,
0933: ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
0934: mbr = shppolygon.getEnvelope();
0935:
0936: if (i == 0) {
0937: shpmbr = mbr;
0938: }
0939:
0940: shptype = 5;
0941: }
0942:
0943: // write bytearray to the shape file
0944: record = new IndexRecord(offset / 2, nbyte / 2);
0945:
0946: // write recordheader to the bytearray
0947: ByteUtils.writeBEInt(bytearray, 0, i);
0948: ByteUtils.writeBEInt(bytearray, 4, nbyte / 2);
0949:
0950: // write record (bytearray) including recordheader to the shape file
0951: shp.write(bytearray, record, mbr);
0952:
0953: // actualise shape file minimum boundary rectangle
0954: if (mbr.west < shpmbr.west) {
0955: shpmbr.west = mbr.west;
0956: }
0957:
0958: if (mbr.east > shpmbr.east) {
0959: shpmbr.east = mbr.east;
0960: }
0961:
0962: if (mbr.south < shpmbr.south) {
0963: shpmbr.south = mbr.south;
0964: }
0965:
0966: if (mbr.north > shpmbr.north) {
0967: shpmbr.north = mbr.north;
0968: }
0969:
0970: // icrement offset for pointing at the end of the file
0971: offset += (nbyte + ShapeConst.SHAPE_FILE_RECORD_HEADER_LENGTH);
0972:
0973: bytearray = null;
0974: }
0975:
0976: dbf.writeAllToFile();
0977:
0978: // write shape header
0979: shp.writeHeader(offset, shptype, shpmbr);
0980:
0981: }
0982:
0983: private void validateOrientation(Surface[] wks)
0984: throws GeometryException {
0985: com.vividsolutions.jts.geom.Geometry jts = JTSAdapter
0986: .export(wks[0]);
0987: CGAlgorithms.isCCW(jts.getCoordinates());
0988: if (CGAlgorithms.isCCW(jts.getCoordinates())) {
0989: Position[] pos = wks[0].getSurfaceBoundary()
0990: .getExteriorRing().getPositions();
0991: Position[] pos2 = new Position[pos.length];
0992: for (int j = 0; j < pos2.length; j++) {
0993: pos2[j] = pos[pos.length - j - 1];
0994: }
0995: Position[][] iPos = null;
0996: if (wks[0].getSurfaceBoundary().getInteriorRings() != null) {
0997: Ring[] rings = wks[0].getSurfaceBoundary()
0998: .getInteriorRings();
0999: iPos = new Position[rings.length][];
1000: for (int j = 0; j < rings.length; j++) {
1001: pos = rings[j].getPositions();
1002: iPos[j] = new Position[pos.length];
1003: for (int k = 0; k < pos.length; k++) {
1004: iPos[j][k] = pos[pos.length - k - 1];
1005: }
1006: }
1007: }
1008: wks[0] = GeometryFactory.createSurface(pos2, iPos,
1009: new SurfaceInterpolationImpl(), wks[0]
1010: .getCoordinateSystem());
1011: }
1012: }
1013: }
|