/*
* MultiPointHandler.java
*
* Created on July 17, 2002, 4:13 PM
*/
package org.geotools.shapefile;
import java.io.IOException;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jump.io.EndianDataInputStream;
import com.vividsolutions.jump.io.EndianDataOutputStream;
/**
* Wrapper for a Shapefile MultiPoint.
*
* @author dblasby
*/
public class MultiPointHandler implements ShapeHandler {
int myShapeType= -1;
/** Creates new MultiPointHandler */
public MultiPointHandler() {
myShapeType = 8;
}
public MultiPointHandler(int type) throws InvalidShapefileException {
if ((type != 8) && (type != 18) && (type != 28)) {
throw new InvalidShapefileException("Multipointhandler constructor - expected type to be 8, 18, or 28");
}
myShapeType = type;
}
public Geometry read(EndianDataInputStream file,
GeometryFactory geometryFactory,
int contentLength) throws IOException, InvalidShapefileException {
int actualReadWords = 0; //actual number of 16 bits words read
Geometry geom = null;
int shapeType = file.readIntLE();
actualReadWords += 2;
if (shapeType == 0) {
geom = geometryFactory.createMultiPoint(new Point[0]);
}
else if (shapeType != myShapeType) {
throw new InvalidShapefileException("Multipointhandler.read() - expected type code "+myShapeType+" but got "+shapeType);
}
else {
//read bbox
file.readDoubleLE();
file.readDoubleLE();
file.readDoubleLE();
file.readDoubleLE();
actualReadWords += 4*4;
int numpoints = file.readIntLE();
actualReadWords += 2;
Coordinate[] coords = new Coordinate[numpoints];
for (int t=0 ; t<numpoints ; t++) {
double x = file.readDoubleLE();
double y = file.readDoubleLE();
actualReadWords += 8;
coords[t] = new Coordinate(x,y);
}
if (myShapeType == 18) {
file.readDoubleLE(); //z min/max
file.readDoubleLE();
actualReadWords += 8;
for (int t=0 ; t<numpoints ; t++) {
double z = file.readDoubleLE();//z
actualReadWords += 4;
coords[t].z = z;
}
}
if (myShapeType >= 18) {
int fullLength;
if (myShapeType == 18) { //multipoint Z (with Z and M)
fullLength = 20 + (numpoints * 8) +8 +4*numpoints + 8 +4*numpoints;
}
else { //multipoint M (with M)
fullLength = 20 + (numpoints * 8) +8 +4*numpoints;
}
if (contentLength >= fullLength) { //is the M portion actually there?
file.readDoubleLE(); //m min/max
file.readDoubleLE();
actualReadWords += 8;
for (int t=0 ; t<numpoints ; t++) {
file.readDoubleLE();//m
actualReadWords += 4;
}
}
}
geom = geometryFactory.createMultiPoint(coords);
}
//verify that we have read everything we need
while (actualReadWords < contentLength) {
int junk2 = file.readShortBE();
actualReadWords += 1;
}
return geom;
}
double[] zMinMax(Geometry g) {
double zmin,zmax;
boolean validZFound = false;
Coordinate[] cs = g.getCoordinates();
double[] result = new double[2];
zmin = Double.NaN;
zmax = Double.NaN;
double z;
for (int t=0;t<cs.length; t++) {
z= cs[t].z ;
if (!(Double.isNaN(z))) {
if (validZFound) {
if (z < zmin) zmin = z;
if (z > zmax) zmax = z;
}
else {
validZFound = true;
zmin = z ;
zmax = z ;
}
}
}
result[0] = (zmin);
result[1] = (zmax);
return result;
}
public void write(Geometry geometry, EndianDataOutputStream file) throws IOException {
if (geometry.isEmpty()) {
file.writeIntLE(0);
return;
}
MultiPoint mp = (MultiPoint) geometry;
file.writeIntLE(getShapeType());
Envelope box = mp.getEnvelopeInternal();
file.writeDoubleLE(box.getMinX());
file.writeDoubleLE(box.getMinY());
file.writeDoubleLE(box.getMaxX());
file.writeDoubleLE(box.getMaxY());
int numParts = mp.getNumGeometries();
file.writeIntLE(numParts);
for (int t=0;t<mp.getNumGeometries(); t++) {
Coordinate c = (mp.getGeometryN(t)).getCoordinate();
file.writeDoubleLE(c.x);
file.writeDoubleLE(c.y);
}
if (myShapeType == 18) {
double[] zExtreame = zMinMax(mp);
if (Double.isNaN(zExtreame[0])) {
file.writeDoubleLE(0.0);
file.writeDoubleLE(0.0);
}
else {
file.writeDoubleLE(zExtreame[0]);
file.writeDoubleLE(zExtreame[1]);
}
for (int t=0;t<mp.getNumGeometries(); t++) {
Coordinate c = (mp.getGeometryN(t)).getCoordinate();
double z = c.z;
if (Double.isNaN(z)) {
file.writeDoubleLE(0.0);
}
else {
file.writeDoubleLE(z);
}
}
}
if (myShapeType >= 18) {
file.writeDoubleLE(-10E40);
file.writeDoubleLE(-10E40);
for (int t=0;t<mp.getNumGeometries(); t++) {
file.writeDoubleLE(-10E40);
}
}
}
/**
* Returns the shapefile shape type value for a point
* @return int Shapefile.POINT
*/
public int getShapeType() {
return myShapeType;
}
/**
* Calculates the record length of this object.
* @return int The length of the record that this shapepoint will take up in a shapefile
*/
public int getLength(Geometry geometry) {
if (geometry.isEmpty()) return 2;
MultiPoint mp = (MultiPoint) geometry;
if (myShapeType == 8) {
return mp.getNumGeometries() * 8 + 20;
}
else if (myShapeType == 28) {
return mp.getNumGeometries() * 8 + 20 +8 +4*mp.getNumGeometries();
}
else {
return mp.getNumGeometries() * 8 + 20 +8 +4*mp.getNumGeometries() + 8 +4*mp.getNumGeometries();
}
}
/**
* Return a empty geometry.
*/
public Geometry getEmptyGeometry(GeometryFactory factory) {
return factory.createMultiPoint(new Point[0]);
}
}