protected void ParsePolygonZ(byte[] shapeData, out RectangleD boundingBox, out List<PointD[]> parts)
{
boundingBox = new RectangleD();
parts = null;
// metadata is validated by the base class
if (shapeData == null)
{
throw new ArgumentNullException("shapeData");
}
// Note, shapeData includes an 8 byte header so positions below are +8
// Position Field Value Type Number Order
// Byte 0 Shape Type 25 Integer 1 Little
// Byte 4 Box Box Double 4 Little
// Byte 36 NumParts NumParts Integer 1 Little
// Byte 40 NumPoints NumPoints Integer 1 Little
// Byte 44 Parts Parts Integer NumParts Little
// Byte X Points Points Point NumPoints Little
// Byte Y Zmin Zmin Double 1 Little
// Byte Y+8 Zmax Zmax Double 1 Little
// Byte Y+16 Zarray Zarray Double NumPoints Little
// Byte Z* Mmin Mmin Double 1 Little
// Byte Z+8* Mmax Mmax Double 1 Little
// Byte Z+16* Marray Marray Double NumPoints Little
// Byte M* Mmin Mmin Double 1 Little
// Byte Z+8* Mmax Mmax Double 1 Little
// Byte Z+16* Marray Marray Double NumPoints Little
//
// Note: X = 44 + (4 * NumParts), Y = X + (16 * NumPoints), Z = Y + 16 + (8 * NumPoints)
// * optional
// validation step 1 - must have at least 8 + 4 + (4*8) + 4 + 4 bytes = 52
if (shapeData.Length < 44)
{
throw new InvalidOperationException("Invalid shape data");
}
// extract bounding box, number of parts and number of points
boundingBox = ParseBoundingBox(shapeData, 12, ProvidedOrder.Little);
int numParts = EndianBitConverter.ToInt32(shapeData, 44, ProvidedOrder.Little);
int numPoints = EndianBitConverter.ToInt32(shapeData, 48, ProvidedOrder.Little);
// validation step 2 - we're expecting 4 * numParts + 16 * numPoints + 52 bytes total
if (shapeData.Length != 52 + (4 * numParts) + (16 * numPoints) &&
shapeData.Length != 52 + (4 * numParts) + (16 * numPoints) + 16 + (8 * numPoints) &&
shapeData.Length != 52 + (4 * numParts) + (16 * numPoints) + 16 + (8 * numPoints) + 16 + (8 * numPoints))
{
throw new InvalidOperationException("Invalid shape data");
}
// now extract the parts
int partsOffset = 52 + (4 * numParts);
parts = new List<PointD[]>(numParts);
for (var part = 0; part < numParts; part++)
{
// this is the index of the start of the part in the points array
var startPart = (EndianBitConverter.ToInt32(shapeData, 52 + (4 * part), ProvidedOrder.Little) * 16) + partsOffset;
int numBytes;
if (part == numParts - 1)
{
// it's the last part so we go to the end of the point array
numBytes = shapeData.Length - startPart;
}
else
{
// we need to get the next part
var nextPart = (EndianBitConverter.ToInt32(shapeData, 52 + (4 * (part + 1)), ProvidedOrder.Little) * 16) + partsOffset;
numBytes = nextPart - startPart;
}
// the number of 16-byte points to read for this segment
var numPointsInPart = Math.Min(numBytes / 16, numPoints);
var points = new PointD[numPointsInPart];
for (var point = 0; point < numPointsInPart; point++)
{
points[point] = new PointD(EndianBitConverter.ToDouble(shapeData, startPart + (16 * point), ProvidedOrder.Little),
EndianBitConverter.ToDouble(shapeData, startPart + 8 + (16 * point), ProvidedOrder.Little));
}
parts.Add(points);
}
}