Shapefile.Shape.ParsePolygonZ C# (CSharp) Method

ParsePolygonZ() protected method

The PolygonZ shape share the same structure, this method parses the bounding box and list of parts for both
protected ParsePolygonZ ( byte shapeData, RectangleD &boundingBox, List &parts ) : void
shapeData byte The shape record as a byte array
boundingBox RectangleD Returns the bounding box
parts List Returns the list of parts
return void
        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);
            }
        }