Catfood.Shapefile.Shape.ParsePolyLineOrPolygon C# (CSharp) Method

ParsePolyLineOrPolygon() protected method

The PolyLine and Polygon shapes share the same structure, this method parses the bounding box and list of parts for both
protected ParsePolyLineOrPolygon ( 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 ParsePolyLineOrPolygon(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  3 or 5      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
            //
            // Note: X = 44 + 4 * NumParts

            // 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))
            {
                throw new InvalidOperationException("Invalid shape data");
            }

            // now extract the parts
            int partsOffset = 52 + (4 * numParts);
            parts = new List<PointD[]>(numParts);
            for (int part = 0; part < numParts; part++)
            {
                // this is the index of the start of the part in the points array
                int 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
                    int 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
                int numPointsInPart = numBytes / 16;

                PointD[] points = new PointD[numPointsInPart];
                for (int 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);
            }
        }