package jeql.io.shapefile; import jeql.api.error.ExecutionException; import jeql.api.row.ArrayRowList; import jeql.api.row.Row; import jeql.api.row.RowIterator; import jeql.api.row.RowSchema; import jeql.api.table.Table; import jeql.util.IOUtil; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; /** * A writer which writes a {@link Table} to a shapefile (which consists of a * .shp and a .dbf file). Currently the .shx file is not written */ public class ShapefileWriter { /** * Returns: <br> * 2 for 2d (default) <br> * 4 for 3d - one of the oordinates has a non-NaN z value <br> * (3 is for x,y,m but thats not supported yet) <br> * * @param g * geometry to test - looks at 1st coordinate **/ public static int determineCoordinateDimension(Geometry g) { Coordinate[] cs = g.getCoordinates(); for (int t = 0; t < cs.length; t++) { if (!(Double.isNaN(cs[t].z))) { return Shapefile.XYZM; } } return Shapefile.XY; } public static int findFirstGeometryIndex(RowSchema schema) { for (int i = 0; i < schema.size(); i++) { if (schema.getType(i) == Geometry.class) return i; } return -1; } /** * Creates a new writer */ public ShapefileWriter() { } /** * Writes a table to a shapefile (2d, 3d or 4d). * * @param tbl * table to write * @param shpfilePath * file path to write to (*.shp) * @param prj * projection string to write, or <tt>null</tt> */ public void write(Table tbl, String shpfilePath, String prj) throws Exception { int dotLoc = shpfilePath.lastIndexOf("."); if (dotLoc == -1) { throw new IllegalArgumentException("Filename must end in '.shp'"); } String pathNoExt = shpfilePath.substring(0, dotLoc); String dbfname = pathNoExt + ".dbf"; String shpname = pathNoExt + ".shp"; String prjName = pathNoExt + ".prj"; writeShpDbfStream(tbl, shpname, dbfname); if (prj != null) { writePrj(prjName, prj); } } private void writeShpDbf(Table tbl, String shpname, String dbfname) throws Exception { // memorize the rowlist to allow determining size ArrayRowList memRowList = new ArrayRowList(tbl.getRows()); TableDbfWriter dbfWriter = new TableDbfWriter(); dbfWriter.write(memRowList, dbfname); RowListShpWriter shpWriter = new RowListShpWriter(); // TableShpWriter shpWriter = new TableShpWriter(); shpWriter.write(memRowList, shpname); } private void writePrj(String filename, String prj) { IOUtil.writeToFileNoThrow(filename, prj); } private void writeShpDbfStream(Table tbl, String shpname, String dbfname) throws Exception { // memorize the rowlist to allow determining size ArrayRowList rowList = new ArrayRowList(tbl.getRows()); int geomIndex = ShapefileWriter.findFirstGeometryIndex(rowList.getSchema()); if (geomIndex < 0) { throw new ExecutionException("No geometry column in table"); } ShpStreamWriter shpWriter = new ShpStreamWriter(shpname); RowIterator it = rowList.iterator(); while (true) { Row row = it.next(); if (row == null) break; Geometry geom = (Geometry) row.getValue(geomIndex); shpWriter.write(geom); // Write dbf row here } shpWriter.close(); // for now only TableDbfWriter dbfWriter = new TableDbfWriter(); dbfWriter.write(rowList, dbfname); } }