/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
* (C) 2010, Geomatys
*
* This library 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 2.1 of the License.
*
* This library 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.
*/
package org.geotoolkit.data.shapefile.shp;
import java.nio.ByteBuffer;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import java.nio.DoubleBuffer;
import org.geotoolkit.geometry.jts.JTS;
import org.apache.sis.storage.DataStoreException;
/**
* The default JTS handler for shapefile. Currently uses the default JTS
* GeometryFactory, since it doesn't seem to matter.
*
* @author Ian Schneider
* @author aaime
* @author Johann Sorel (Geomatys)
* @module
*/
public class MultiLineHandler extends AbstractShapeHandler {
/** Create a MultiLineHandler for ShapeType.ARC */
public MultiLineHandler(final boolean read3D) {
super(ShapeType.ARC,read3D);
}
/**
* Create a MultiLineHandler for one of: <br>
* ShapeType.ARC,ShapeType.ARCM,ShapeType.ARCZ
*
* @param type The ShapeType to use.
* @throws DataStoreException If the ShapeType is not correct (see constructor).
*/
public MultiLineHandler(final ShapeType type,final boolean read3D) throws DataStoreException {
super(type,read3D);
if ((type != ShapeType.ARC) && (type != ShapeType.ARCM) && (type != ShapeType.ARCZ)) {
throw new DataStoreException("MultiLineHandler constructor - expected type to be 3, 13 or 23");
}
}
/**
* Get the type of shape stored
* (ShapeType.ARC,ShapeType.ARCM,ShapeType.ARCZ)
*/
@Override
public ShapeType getShapeType() {
return shapeType;
}
/**
* {@inheritDoc }
*/
@Override
public int getLength(final Object geometry) {
final MultiLineString multi = (MultiLineString) geometry;
final int numlines = multi.getNumGeometries();
final int numpoints = multi.getNumPoints();
if (shapeType == ShapeType.ARC) {
return 44 + (4*numlines) + (16*numpoints);
} else if (shapeType == ShapeType.ARCM) {
return 44 + (4*numlines) + (16*numpoints) + 8 + 8 + (8*numpoints);
} else if (shapeType == ShapeType.ARCZ) {
return 44 + (4*numlines) + (16*numpoints) + 8 + 8 + (8*numpoints) + 8 + 8 + (8*numpoints);
} else {
throw new IllegalStateException("Expected ShapeType of Arc, got " + shapeType);
}
}
protected Object createNull() {
return GEOMETRY_FACTORY.createMultiLineString((LineString[]) null);
}
@Override
public Object estimated(final double minX, final double maxX, final double minY, final double maxY) {
final double[] array = new double[]{minX,minY,maxX,maxY};
return GEOMETRY_FACTORY.createMultiLineString(new LineString[] {
GEOMETRY_FACTORY.createLineString(new ShapeCoordinateSequence2D(array,2))});
}
@Override
public Object read(final ByteBuffer buffer, final ShapeType type) {
if (type == ShapeType.NULL) {
return createNull();
}
final int dimensions = (read3D && shapeType == ShapeType.ARCZ) ? 3 : 2;
// skip bounding box (not needed)
buffer.position(buffer.position() + 4 * 8);
final int numParts = buffer.getInt();
final int numPoints = buffer.getInt(); // total number of points
//store each line string buffer start position
final int[] partOffsets = new int[numParts];
for (int i = 0; i < numParts; i++) {
partOffsets[i] = buffer.getInt();
}
// read the first two coordinates and start building the coordinate sequences
final double[][] lines = new double[numParts][0];
//use a double buffer to increase bulk reading
final DoubleBuffer dbuffer = buffer.asDoubleBuffer();
for (int part = 0; part < numParts; part++) {
final int finish;
if (part == (numParts - 1)) {
finish = numPoints;
} else {
finish = partOffsets[part + 1];
}
final int length = finish - partOffsets[part];
final double[] coords;
if (length == 1) {
//only one point for a line, JTS do not like that, so we make two points at same place.
coords = new double[2*dimensions];
dbuffer.get(coords, 0, 2);
coords[2] = coords[0];
coords[3] = coords[1];
} else {
coords = new double[length*dimensions];
dbuffer.get(coords, 0, length*2);
}
lines[part] = coords;
}
// if we have another coordinate, read and add to the coordinate
// sequences
if (dimensions == 3) {
// z min, max
dbuffer.position(dbuffer.position() + 2);
for (int part = 0; part < numParts; part++) {
final int finish;
if (part == (numParts - 1)) {
finish = numPoints;
} else {
finish = partOffsets[part + 1];
}
final double[] coords = lines[part];
final int length = finish - partOffsets[part];
if (length == 1) {
//only one point for a line, JTS do not like that, so we make two points at same place.
coords[4] = coords[5] = dbuffer.get();
} else {
dbuffer.get(coords, length*2, length);
}
}
}
// Prepare line strings and return the multilinestring
final LineString[] lineCharSequences = new LineString[numParts];
for (int part = 0; part < numParts; part++) {
if(dimensions == 2){
lineCharSequences[part] = GEOMETRY_FACTORY.createLineString(new ShapeCoordinateSequence2D(lines[part]));
}else{
lineCharSequences[part] = GEOMETRY_FACTORY.createLineString(new ShapeCoordinateSequence3D(lines[part]));
}
}
return GEOMETRY_FACTORY.createMultiLineString(lineCharSequences);
}
// @Override
// public Object read(ByteBuffer buffer, ShapeType type) {
//
// if (type == ShapeType.NULL) {
// return createNull();
// }
// final int dimensions = (shapeType == ShapeType.ARCZ) ? 3 : 2;
// // skip bounding box (not needed)
// buffer.position(buffer.position() + 4 * 8);
//
// final int numParts = buffer.getInt();
// final int numPoints = buffer.getInt(); // total number of points
//
// //store each line string buffer start position
// final int[] partOffsets = new int[numParts];
// for (int i = 0; i < numParts; i++) {
// partOffsets[i] = buffer.getInt();
// }
//
// // read the first two coordinates and start building the coordinate sequences
// final Coordinate[][] lines = new Coordinate[numParts][0];
// //use a double buffer to increase bulk reading
// final DoubleBuffer dbuffer = buffer.asDoubleBuffer();
//
// for (int part = 0; part < numParts; part++) {
//
// final int finish;
// if (part == (numParts - 1)) {
// finish = numPoints;
// } else {
// finish = partOffsets[part + 1];
// }
//
// final Coordinate[] coords;
// int length = finish - partOffsets[part];
// if (length == 1) {
// final double x = dbuffer.get();
// final double y = dbuffer.get();
// coords = new Coordinate[]{
// new Coordinate(x,y),
// new Coordinate(x,y)
// };
// } else {
// coords = new Coordinate[length];
// for(int i=0,n=coords.length; i<n; i++){
// coords[i] = new Coordinate(dbuffer.get(), dbuffer.get());
// }
// }
// lines[part] = coords;
// }
//
// // if we have another coordinate, read and add to the coordinate
// // sequences
// if (dimensions == 3) {
// // z min, max
// dbuffer.position(dbuffer.position() + 2);
// for (int part = 0; part < numParts; part++) {
//
// final int finish;
// if (part == (numParts - 1)) {
// finish = numPoints;
// } else {
// finish = partOffsets[part + 1];
// }
//
// final Coordinate[] coords = lines[part];
// int length = finish - partOffsets[part];
// if (length == 1) {
// coords[0].z = dbuffer.get();
// coords[1].z = coords[0].z;
// } else {
// for(Coordinate coord : coords){
// coord.z = dbuffer.get();
// }
// }
// }
// }
//
// // Prepare line strings and return the multilinestring
// final LineString[] lineCharSequences = new LineString[numParts];
// for (int part = 0; part < numParts; part++) {
// lineCharSequences[part] = GEOMETRY_FACTORY.createLineString(new CoordinateArraySequence(lines[part]));
// }
//
// return GEOMETRY_FACTORY.createMultiLineString(lineCharSequences);
// }
@Override
public void write(final ByteBuffer buffer, final Object geometry) {
final MultiLineString multi = (MultiLineString) geometry;
final Envelope box = multi.getEnvelopeInternal();
buffer.putDouble(box.getMinX());
buffer.putDouble(box.getMinY());
buffer.putDouble(box.getMaxX());
buffer.putDouble(box.getMaxY());
final int numParts = multi.getNumGeometries();
final CoordinateSequence[] lines = new CoordinateSequence[numParts];
final double[] zExtreame = {Double.NaN, Double.NaN};
final int npoints = multi.getNumPoints();
buffer.putInt(numParts);
buffer.putInt(npoints);
for (int i=0, idx=0; i<numParts; i++) {
lines[i] = ((LineString) multi.getGeometryN(i)).getCoordinateSequence();
buffer.putInt(idx);
idx += lines[i].size();
}
for(int lineN = 0; lineN < lines.length; lineN++){
final CoordinateSequence coords = lines[lineN];
if (shapeType == ShapeType.ARCZ) {
JTS.zMinMax(coords, zExtreame);
}
final int ncoords = coords.size();
for (int t=0; t<ncoords; t++) {
buffer.putDouble(coords.getX(t));
buffer.putDouble(coords.getY(t));
}
}
if (shapeType == ShapeType.ARCZ) {
if (Double.isNaN(zExtreame[0])) {
buffer.putDouble(0.0);
buffer.putDouble(0.0);
} else {
buffer.putDouble(zExtreame[0]);
buffer.putDouble(zExtreame[1]);
}
for(int lineN = 0; lineN < lines.length; lineN++){
final CoordinateSequence coords = lines[lineN];
final int ncoords = coords.size();
for (int t = 0; t < ncoords; t++) {
final double z = coords.getOrdinate(t, 2);
if (Double.isNaN(z)) {
buffer.putDouble(0.0);
} else {
buffer.putDouble(z);
}
}
}
buffer.putDouble(-10E40);
buffer.putDouble(-10E40);
for (int t = 0; t < npoints; t++) {
buffer.putDouble(-10E40);
}
}
}
}