/**
* Copyright (c) 2009-2011, chunquedong(YangJiandong)
*
* This file is part of ChunMap project
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
*
* History:
* 2010-05-05 Jed Young Creation
*/
package chunmap.data.provider.shp;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import chunmap.model.elem.Envelope;
import chunmap.model.geom.GeoPoint;
import chunmap.model.geom.Geometry;
import chunmap.model.geom.GeometryType;
/**
* @author chunquedong
*
*/
public class ShapefileReader {
private String path;
private String name;
private RandomAccessFile shaperf;
private RandomAccessFile indexrf;
private GeometryType geometryType;
private int shapefileType;
private long shapeCount;
private int version;
private Envelope envelop;
private final ShapefileReaderHelper helper = new ShapefileReaderHelper();
public ShapefileReader(String path) {
setPath(path);
open();
readHeader();
}
private void setPath(String apath) {
File file = new File(apath);
this.name = file.getName();
this.path = apath.substring(0, apath.lastIndexOf("."));
}
private void open() {
try {
shaperf = new RandomAccessFile(path + ".shp", "r");
indexrf = new RandomAccessFile(path + ".shx", "r");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public void close() {
try {
indexrf.close();
shaperf.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void readHeader() {
try {
// 文件编号
indexrf.seek(0);
int ii = indexrf.readInt();
if (ii != 9994)
throw new IOException("bad file");
// 文件长度
indexrf.seek(24);
int fileLength = 2 * indexrf.readInt();// 16位算一个
// 图形个数
shapeCount = (fileLength - 100) / 8;// 100bytes头文件。偏移4bytes,长度4bytes,没条记录共占8bytes。
// 格式版本
version = Integer.reverseBytes(indexrf.readInt());
// 图类型
shapefileType = Integer.reverseBytes(indexrf.readInt());
// 边框盒子
geometryType = ShapefileType.getShapeType(shapefileType);
envelop = helper.readEnvelop(indexrf);
} catch (IOException e) {
throw new RuntimeException(e);
}
// _envelop.MinPoint.Z = _binaryReader_Index.ReadDouble();
// _envelop.MaxPoint.Z = _binaryReader_Index.ReadDouble();
// _envelop.MinPoint.Coordinate.M = _binaryReader_Index.ReadDouble();
// _envelop.MaxPoint.Coordinate.M = _binaryReader_Index.ReadDouble();
}
public Geometry getGeometry(long id) throws IOException {
int index = getIndex(id) + 8;// 加8表示跳过记录头信息,包括记录号和记录长度。
shaperf.seek(index);
int type = Integer.reverseBytes(shaperf.readInt());
Geometry geometry;
switch (type) {
case ShapefileType.Null:
return null;
case ShapefileType.Point:
geometry = new GeoPoint(helper.readPoint(shaperf));
break;
case ShapefileType.Multipoint:
geometry = helper.readMultiPoint(shaperf);
break;
case ShapefileType.PolyLine:
geometry = helper.readMultiLine(shaperf);
break;
case ShapefileType.Polygon:
geometry = helper.readMultiPolygon(shaperf);
break;
// case ShapefileType.PointM:
// geometry = helper.readPointM(shaperf);
// break;
// case ShapefileType.MultiPointM:
// geometry = helper.readMultiPointM(shaperf);
// break;
// case ShapefileType.PolyLineM:
// geometry = helper.readMultiLineM(shaperf);
// break;
// case ShapefileType.PolygonM:
// geometry = helper.readMultiPolygonM(shaperf);
// break;
// case ShapefileType.PointZ:
// geometry = helper.readPointZ(shaperf);
// break;
// case ShapefileType.MultiPointZ:
// geometry = helper.readMultiPointZ(shaperf);
// break;
// case ShapefileType.PolyLineZ:
// geometry = helper.readMultiPolygonZ(shaperf);
// break;
//
// case ShapefileType.PolygonZ:
// geometry = helper.readMultiLineZ(shaperf);
// break;
default:
throw new UnsupportedOperationException(
"this ShapefileType is unsupported");
}
//geometry.setId(id + "");
return geometry;
}
// 从索引文件查到偏移量
public int getIndex(long id) throws IOException {
indexrf.seek(id * 8 + 100);
return 2 * indexrf.readInt();// 16位算一个
}
public Envelope getShapeEnvelop(long id) throws IOException {
int index = getIndex(id) + 8;// 加8表示跳过记录头信息,包括记录号和记录长度。
shaperf.seek(index);
int type = Integer.reverseBytes(shaperf.readInt());
Envelope elp;
if (type == ShapefileType.Null)
return new Envelope();
else if (type == ShapefileType.Point || type == ShapefileType.PointM
|| type == ShapefileType.PointZ) {
elp = new GeoPoint(helper.readPoint(shaperf)).getEnvelop();
} else {
elp = helper.readEnvelop(shaperf);
}
return elp;
}
public String getPath() {
return path;
}
public String getName() {
return name;
}
public GeometryType getGeometryType() {
return geometryType;
}
public int getShapefileType() {
return shapefileType;
}
public long getShapeCount() {
return shapeCount;
}
public int getVersion() {
return version;
}
public Envelope getEnvelop() {
return envelop;
}
}