/*
* Copyright (C) 2012 Dr. John Lindsay <jlindsay@uoguelph.ca>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package whitebox.geospatialfiles.shapefile;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import whitebox.structures.BoundingBox;
/**
*
* @author Dr. John Lindsay email: jlindsay@uoguelph.ca
*/
public class MultiPointM implements Geometry {
//private double[] box = new double[4];
private BoundingBox bb;
private int numPoints;
private double[][] points;
private double mMin;
private double mMax;
private double[] mArray;
private boolean mIncluded = false;
private double maxExtent;
//constructors
public MultiPointM(byte[] rawData) {
try {
ByteBuffer buf = ByteBuffer.wrap(rawData);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.rewind();
bb = new BoundingBox(buf.getDouble(0), buf.getDouble(8),
buf.getDouble(16), buf.getDouble(24));
maxExtent = bb.getMaxExtent();
numPoints = buf.getInt(32);
points = new double[numPoints][2];
for (int i = 0; i < numPoints; i++) {
points[i][0] = buf.getDouble(36 + i * 16); // x value
points[i][1] = buf.getDouble(36 + i * 16 + 8); // y value
}
int pos = 36 + numPoints * 16;
// m data is optional.
if (pos < buf.capacity()) {
mMin = buf.getDouble(pos);
mMax = buf.getDouble(pos + 8);
mArray = new double[numPoints];
pos += 16;
for (int i = 0; i < numPoints; i++) {
mArray[i] = buf.getDouble(pos + i * 8); // m value
}
mIncluded = true;
}
buf.clear();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
/**
* This is the constructor that is used when creating a new multipoint.
* @param points a double[][] array containing the point data. The first
* dimension of the array is the total number of points in the multipoint.
*/
public MultiPointM (double[][] points, double[] mArray) {
numPoints = points.length;
this.points = new double[numPoints][2];
this.mArray = new double[numPoints];
double minX = Float.POSITIVE_INFINITY;
double minY = Float.POSITIVE_INFINITY;
double maxX = Float.NEGATIVE_INFINITY;
double maxY = Float.NEGATIVE_INFINITY;
mMin = Float.POSITIVE_INFINITY;
mMax = Float.NEGATIVE_INFINITY;
for (int i = 0; i < numPoints; i++) {
this.points[i][0] = points[i][0];
this.points[i][1] = points[i][1];
this.mArray[i] = mArray[i];
if (points[i][0] < minX) { minX = points[i][0]; }
if (points[i][0] > maxX) { maxX = points[i][0]; }
if (points[i][1] < minY) { minY = points[i][1]; }
if (points[i][1] > maxY) { maxY = points[i][1]; }
if (points[i][1] < mMin) { mMin = points[i][1]; }
if (points[i][1] > mMax) { mMax = points[i][1]; }
}
bb = new BoundingBox(minX, minY, maxX, maxY);
maxExtent = bb.getMaxExtent();
}
// properties
@Override
public BoundingBox getBox() {
return bb;
}
public double getXMin() {
return bb.getMinX();
}
public double getYMin() {
return bb.getMinY();
}
public double getXMax() {
return bb.getMaxX();
}
public double getYMax() {
return bb.getMaxY();
}
public int getNumPoints() {
return numPoints;
}
@Override
public double[][] getPoints() {
return points;
}
public ArrayList<Integer> getIndicesOfPointsInExtent(BoundingBox extent) {
ArrayList<Integer> whichAreInExtent = new ArrayList<>();
for (int i = 0; i < points.length; i++) {
if (extent.isPointInBox(points[i][0], points[i][1])) {
whichAreInExtent.add(i);
}
}
return whichAreInExtent;
}
public int numberOfPointsInExtent(BoundingBox extent) {
int numPointsInExtent = 0;
for (int i = 0; i < points.length; i++) {
if (extent.isPointInBox(points[i][0], points[i][1])) {
numPointsInExtent++;
}
}
return numPointsInExtent;
}
@Override
public int[] getParts() {
return new int[0];
}
public double[] getmArray() {
return mArray;
}
public double getmMax() {
return mMax;
}
public double getmMin() {
return mMin;
}
public boolean isMDataIncluded() {
return mIncluded;
}
@Override
public int getLength() {
return 32 + 4 + numPoints * 16 + 16 + numPoints * 8;
}
@Override
public ByteBuffer toByteBuffer() {
ByteBuffer buf = ByteBuffer.allocate(getLength());
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.rewind();
// put the bounding box data in.
buf.putDouble(bb.getMinX());
buf.putDouble(bb.getMinY());
buf.putDouble(bb.getMaxX());
buf.putDouble(bb.getMaxY());
// put the numPoints in.
buf.putInt(numPoints);
// put the point data in.
for (int i = 0; i < numPoints; i++) {
buf.putDouble(points[i][0]);
buf.putDouble(points[i][1]);
}
// put the min and max m values in
buf.putDouble(mMin);
buf.putDouble(mMax);
// put the m values in
for (int i = 0; i < numPoints; i++) {
buf.putDouble(mArray[i]);
}
return buf;
}
@Override
public ShapeType getShapeType() {
return ShapeType.MULTIPOINTM;
}
@Override
public boolean isMappable(BoundingBox box, double minSize) {
return box.overlaps(bb) && maxExtent > minSize;
}
@Override
public boolean needsClipping(BoundingBox box) {
return (!bb.entirelyContainedWithin(box)) && (bb.overlaps(box));
}
@Override
public com.vividsolutions.jts.geom.Geometry[] getJTSGeometries() {
GeometryFactory factory = new GeometryFactory();
int a;
CoordinateArraySequence coordArray;
com.vividsolutions.jts.geom.Point[] pointArray = new com.vividsolutions.jts.geom.Point[numPoints];
for (a = 0; a < numPoints; a++) {
coordArray = new CoordinateArraySequence(1);
coordArray.setOrdinate(0, 0, points[a][0]);
coordArray.setOrdinate(0, 1, points[a][1]);
coordArray.setOrdinate(0, 2, mArray[a]);
pointArray[a] = factory.createPoint(coordArray);
}
return pointArray;
}
}