/*
* 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 java.nio.ByteBuffer;
import java.nio.ByteOrder;
import whitebox.structures.BoundingBox;
/**
*
* @author Dr. John Lindsay email: jlindsay@uoguelph.ca
*/
public class MultiPatch implements Geometry {
//private double[] box = new double[4];
private BoundingBox bb;
private int numParts;
private int numPoints;
private int[] parts;
private double[][] points;
private double mMin;
private double mMax;
private double[] mArray;
private double zMin;
private double zMax;
private double[] zArray;
private PartType[] partTypes;
private double maxExtent;
public MultiPatch(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();
numParts = buf.getInt(32);
numPoints = buf.getInt(36);
parts = new int[numParts];
for (int i = 0; i < numParts; i++) {
parts[i] = buf.getInt(40 + i * 4);
}
int pos = 40 + numParts * 4;
partTypes = new PartType[numParts];
for (int i = 0; i < numParts; i++) {
partTypes[i] = getPartTypeFromInt(buf.getInt(40 + i * 4));
}
pos += numParts * 4;
points = new double[numPoints][2];
for (int i = 0; i < numPoints; i++) {
points[i][0] = buf.getDouble(pos + i * 16); // x value
points[i][1] = buf.getDouble(pos + i * 16 + 8); // y value
}
pos += numPoints * 16;
zMin = buf.getDouble(pos);
zMax = buf.getDouble(pos + 8);
zArray = new double[numPoints];
pos += 16;
for (int i = 0; i < numPoints; i++) {
zArray[i] = buf.getDouble(pos + i * 8); // z value
}
pos += numPoints * 8;
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
}
buf.clear();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
// properties
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;
}
public double[][] getPoints() {
return points;
}
public int getNumParts() {
return numParts;
}
public int[] getParts() {
return parts;
}
public PartType[] getPartTypes() {
return partTypes;
}
public double[] getzArray() {
return zArray;
}
public double getzMax() {
return zMax;
}
public double getzMin() {
return zMin;
}
public double[] getmArray() {
return mArray;
}
public double getmMax() {
return mMax;
}
public double getmMin() {
return mMin;
}
// methods
private PartType[] pt = new PartType[]{PartType.TRIANGLE_STRIP, PartType.TRIANGLE_FAN,
PartType.OUTER_RING, PartType.INNER_RING, PartType.FIRST_RING, PartType.RING};
private PartType getPartTypeFromInt(int i) {
return pt[i];
}
private int getIntFromPartType(PartType pt) {
switch (pt) {
case TRIANGLE_STRIP:
return 0;
case TRIANGLE_FAN:
return 1;
case OUTER_RING:
return 2;
case INNER_RING:
return 3;
case FIRST_RING:
return 4;
case RING:
return 5;
}
return 0; // it should never get here.
}
@Override
public int getLength() {
return 32 + 8 + numParts * 4 + numPoints * 16 + 16 + numPoints * 8
+ 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 numParts and numPoints in.
buf.putInt(numParts);
buf.putInt(numPoints);
// put the part data in.
for (int i = 0; i < numParts; i++) {
buf.putInt(parts[i]);
}
// put in the part types.
for (int i = 0; i < numParts; i++) {
buf.putInt(getIntFromPartType(partTypes[i]));
}
// 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 z values in
buf.putDouble(zMin);
buf.putDouble(zMax);
// put the z values in
for (int i = 0; i < numPoints; i++) {
buf.putDouble(zArray[i]);
}
// 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.MULTIPATCH;
}
@Override
public boolean isMappable(BoundingBox box, double minSize) {
if (box.overlaps(bb) && maxExtent > minSize) {
return true;
} else {
return false;
}
}
@Override
public boolean needsClipping(BoundingBox box) {
if ((!bb.entirelyContainedWithin(box)) && (bb.overlaps(box))) {
return true;
} else {
return false;
}
}
@Override
public com.vividsolutions.jts.geom.Geometry[] getJTSGeometries() {
throw new UnsupportedOperationException("Not supported yet.");
}
}