package jeql.io.shapefile;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import jeql.api.row.ArrayRowList;
import jeql.api.row.Row;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.PrecisionModel;
class TableShpWriter {
public TableShpWriter() {
}
public void write(ArrayRowList rowList, String shpfilePathNoExt)
throws Exception {
int geomIndex = ShapefileWriter.findFirstGeometryIndex(rowList.getSchema());
// this gc will be a collection of either multi-points, multi-polygons, or
// multi-linestrings
// polygons will have the rings in the correct order
GeometryCollection gc = creatShpGeometryCollection(rowList.getRows(),
geomIndex);
int coordDim = Shapefile.XY; // default is XY
if (gc.getNumGeometries() > 0) {
coordDim = ShapefileWriter.determineCoordinateDimension(gc
.getGeometryN(0));
}
URL url = new URL("file", "localhost", shpfilePathNoExt + ".shp");
ShpWriter shpWriter = new ShpWriter(url);
shpWriter.write(gc, coordDim);
// write index
// *
// don't bother writing index
// String shxPath = shpfilePathNoExt + ".shx";
// writer.writeIndex(gc, coordDim, shxPath);
// */
}
public void OLDwrite(ArrayRowList rowList, String shpfilePathNoExt)
throws Exception {
int geomIndex = ShapefileWriter.findFirstGeometryIndex(rowList.getSchema());
// this gc will be a collection of either multi-points, multi-polygons, or
// multi-linestrings
// polygons will have the rings in the correct order
GeometryCollection gc = creatShpGeometryCollection(rowList.getRows(),
geomIndex);
int coordDim = Shapefile.XY; // default is XY
if (gc.getNumGeometries() > 0) {
coordDim = ShapefileWriter.determineCoordinateDimension(gc
.getGeometryN(0));
}
URL url = new URL("file", "localhost", shpfilePathNoExt + ".shp");
ShpWriter shpWriter = new ShpWriter(url);
shpWriter.write(gc, coordDim);
// write index
// *
// don't bother writing index
// String shxPath = shpfilePathNoExt + ".shx";
// writer.writeIndex(gc, coordDim, shxPath);
// */
}
private static final int DEFAULT_GEOM_TYPE = Shapefile.POINT;
/**
* Find the generic geometry type for the collection of geometries. The
* collection is expected to be homogeneous. For Polygons and lines,
* shapefiles handle single and multi geometries uniformly, so no special
* logic is required. For points, shapefiles treat single points and
* multipoints as distinct types. Because of this, the type is only returned
* as POINT if all geometries are single points. Otherwise, MULTIPOINT is
* returned.
*
* @param rows
* rows containing geometries
* @param geomIndex
* index of column containing geometry
* @return a code indicating the type of geometry to create
**/
private static int findBestGeometryType(List rows, int geomIndex) {
boolean isPoint = false;
boolean isMultiPoint = false;
int rowCount = 0;
for (Iterator i = rows.iterator(); i.hasNext();) {
Row row = (Row) i.next();
rowCount++;
// sanity check on geomIndex, and provide nicer error msg
if (geomIndex < 0 || geomIndex >= row.size()) {
throw new IllegalArgumentException(
"Unable to determine geometry column");
}
Geometry geom = (Geometry) row.getValue(geomIndex);
if (geom instanceof Point) {
isPoint = true;
}
if (geom instanceof MultiPoint) {
isMultiPoint = true;
}
if (geom instanceof LineString) {
return Shapefile.ARC;
}
if (geom instanceof MultiLineString) {
return Shapefile.ARC;
}
if (geom instanceof Polygon) {
return Shapefile.POLYGON;
}
if (geom instanceof MultiPolygon) {
return Shapefile.POLYGON;
}
}
// occurrence of any multipoint forces entire file to be multipoint
if (isMultiPoint)
return Shapefile.MULTIPOINT;
if (isPoint)
return Shapefile.POINT;
if (rowCount == 0)
return DEFAULT_GEOM_TYPE;
// unknown type
return 0;
}
/**
* return a single geometry collection <Br>
* result.GeometryN(i) = the i-th feature in the FeatureCollection<br>
* All the geometry types will be the same type (ie. all polygons) - or they
* will be set to<br>
* NULL geometries<br>
* <br>
* GeometryN(i) = {Multipoint,Multilinestring, or Multipolygon)<br>
*
* @param rows
* input rows
* @param geomIndex
* index of geometry in row
*/
public GeometryCollection creatShpGeometryCollection(List rows, int geomIndex)
throws Exception {
Geometry[] allGeoms = new Geometry[rows.size()];
int geomtype = findBestGeometryType(rows, geomIndex);
if (geomtype == 0) {
throw new IllegalArgumentException(
"Could not determine shapefile geometry type (data is either empty or all GeometryCollections)");
}
for (int t = 0; t < rows.size(); t++) {
Row row = (Row) rows.get(t);
Geometry geom = (Geometry) row.getValue(geomIndex);
allGeoms[t] = ShapeGeometryBuilder.buildGeometry(geom, geomtype);
}
GeometryCollection result = new GeometryCollection(allGeoms,
new PrecisionModel(), 0);
return result;
}
}