/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* <http://www.h2database.com>. H2GIS is developed by CNRS
* <http://www.cnrs.fr/>.
*
* This code is part of the H2GIS project. H2GIS 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;
* version 3.0 of the License.
*
* H2GIS 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 <http://www.gnu.org/licenses/>.
*
*
* For more information, please consult: <http://www.h2gis.org/>
* or contact directly: info_at_h2gis.org
*/
package org.h2gis.functions.io.shp.internal;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import org.h2gis.functions.io.utility.WriteBufferManager;
import java.io.IOException;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
/**
* ShapefileWriter allows for the storage of geometries in esris shp format.
* During writing, an index will also be created. To create a ShapefileWriter,
* do something like<br>
* <code>
* GeometryCollection geoms;
* File shp = new File("myshape.shp");
* File shx = new File("myshape.shx");
* ShapefileWriter writer = new ShapefileWriter(
* shp.getChannel(),shx.getChannel()
* );
* writer.write(geoms,ShapeType.ARC);
* </code>
* This example assumes that each shape in the collection is a LineString.
*
* @author jamesm
* @author aaime
* @author Ian Schneider
*
* @source $URL:
* http://svn.geotools.org/geotools/tags/2.3.1/plugin/shapefile/src/org/geotools/data/shapefile/shp/ShapefileWriter.java $
*/
public class ShapefileWriter {
private FileChannel shpChannel;
private FileChannel shxChannel;
private WriteBufferManager shapeBuffer;
private WriteBufferManager indexBuffer;
private ShapeHandler handler;
private ShapeType type;
private int offset;
private int cnt = 0; //number of geometries
private Envelope bounds;
/**
* Creates a new instance of ShapeFileWriter
*
* @param shpChannel
* @param shxChannel
* @throws java.io.IOException
*/
public ShapefileWriter(FileChannel shpChannel, FileChannel shxChannel)
throws IOException {
this.shpChannel = shpChannel;
this.shxChannel = shxChannel;
}
/**
* @return The Shape File Channel
*/
public FileChannel getShpChannel() {
return shpChannel;
}
/**
* Write the headers for this shapefile.Use this function before inserting the first geometry, then when all geometries are inserted.
* @param type Shape type
* @throws java.io.IOException
*/
public void writeHeaders(ShapeType type) throws IOException {
try {
handler = type.getShapeHandler();
} catch (ShapefileException se) {
throw new IOException("Error with type " + type, se);
}
if(indexBuffer != null) {
indexBuffer.flush();
}
if(shapeBuffer != null) {
shapeBuffer.flush();
}
long fileLength = shpChannel.position();
shpChannel.position(0);
shxChannel.position(0);
ShapefileHeader header = new ShapefileHeader();
Envelope writeBounds = bounds;
if(writeBounds == null) {
writeBounds = new Envelope();
}
indexBuffer = new WriteBufferManager(shxChannel);
shapeBuffer = new WriteBufferManager(shpChannel);
header.write(shapeBuffer, type, cnt, (int)(fileLength / 2),
writeBounds.getMinX(), writeBounds.getMinY(), writeBounds.getMaxX(), writeBounds
.getMaxY());
header.write(indexBuffer, type, cnt,
50 + 4 * cnt, writeBounds.getMinX(),
writeBounds.getMinY(), writeBounds.getMaxX(), writeBounds.getMaxY());
offset = 50;
this.type = type;
}
/**
* Write a single Geometry to this shapefile. The Geometry must be
* compatable with the ShapeType assigned during the writing of the headers.
*
* @param g
* @throws java.io.IOException
*/
public void writeGeometry(Geometry g) throws IOException {
if(type == null) {
throw new IllegalStateException("Header must be written before writeGeometry");
}
if(bounds != null) {
if(g != null) {
bounds.expandToInclude(g.getEnvelopeInternal());
}
} else {
bounds = g.getEnvelopeInternal();
}
int length;
if (g == null) {
length = 4;
} else {
length = handler.getLength(g);
}
length /= 2;
shapeBuffer.order(ByteOrder.BIG_ENDIAN);
shapeBuffer.putInt(++cnt);
shapeBuffer.putInt(length);
shapeBuffer.order(ByteOrder.LITTLE_ENDIAN);
if (g == null) {
shapeBuffer.putInt(0);
} else {
shapeBuffer.putInt(type.id);
handler.write(shapeBuffer, g);
}
// write to the shx
indexBuffer.putInt(offset);
indexBuffer.putInt(length);
offset += length + 4;
}
/**
* Close the underlying Channels.
*
* @throws java.io.IOException
*/
public void close() throws IOException {
indexBuffer.flush();
shapeBuffer.flush();
if (shpChannel != null && shpChannel.isOpen()) {
shpChannel.close();
}
if (shxChannel != null && shxChannel.isOpen()) {
shxChannel.close();
}
shpChannel = null;
shxChannel = null;
handler = null;
indexBuffer = null;
shapeBuffer = null;
}
}