private void ReadPolyLineZ(Byte[] dataStream, int streamPosition)
        {
            var pl = new PolyLineZ();
            pl.BoundingBox = new Double[4];
            pl.BoundingBox[0] = ReadDoubleLittleEndian(dataStream, streamPosition);
            pl.BoundingBox[1] = ReadDoubleLittleEndian(dataStream, streamPosition + 8);
            pl.BoundingBox[2] = ReadDoubleLittleEndian(dataStream, streamPosition + 16);
            pl.BoundingBox[3] = ReadDoubleLittleEndian(dataStream, streamPosition + 24);
            var numberOfParts = ReadIntLittleEndian(dataStream, streamPosition + 32);
            var numberOfPoints = ReadIntLittleEndian(dataStream, streamPosition + 36);
            pl.Lines = new LineZ[numberOfParts];
            var parts = new int[numberOfParts];
            var pos = streamPosition + 40;

            for (var i = 1; i < numberOfParts; i++)
            {
                parts[i - 1] = ReadIntLittleEndian(dataStream, pos + (i * 4)) - 1;
            }

            parts[numberOfParts - 1] = numberOfPoints - 1;
            pos = pos + 4 * numberOfParts;
            var z = 0;
            int lineEndsAt;
            var ln = new LineZ();
            var pts = new List<PointZ>();
            for (var i = 0; i < numberOfPoints; i++)
            {
                lineEndsAt = parts[z];
                if (i == lineEndsAt)
                {
                    // End of line, add the last point and wrap up
                    var p = new PointZ();
                    p.X = ReadDoubleLittleEndian(dataStream, pos + (i * 16));
                    p.Y = ReadDoubleLittleEndian(dataStream, pos + (i * 16) + 8);
                    pts.Add(p);
                    ln.Points = pts.ToArray();
                    pts.Clear();
                    pl.Lines[z] = ln;
                    ln = new LineZ();
                    if (z < numberOfParts - 1) z++;
                }
                else
                {
                    // Keep adding the points
                    var p = new PointZ();
                    p.X = ReadDoubleLittleEndian(dataStream, pos + (i * 16));
                    p.Y = ReadDoubleLittleEndian(dataStream, pos + (i * 16) + 8);
                    pts.Add(p);
                }

            }
            pos = pos + numberOfPoints * 16;

            pl.ZMin = ReadDoubleLittleEndian(dataStream, pos);
            pl.ZMax = ReadDoubleLittleEndian(dataStream, pos + 8);
            var pointIndex = 0;
            for (var i = 0; i < pl.Lines.Length; i++)
            {
                for (var k = 0; k < pl.Lines[i].Points.Length; k++)
                {
                    pl.Lines[i].Points[k].Z = ReadDoubleLittleEndian(dataStream, pos + 16 + (pointIndex * 8));
                    pointIndex++;
                }
            }
            pos = pos + 16 + numberOfPoints * 8;

            pl.MMin = ReadDoubleLittleEndian(dataStream, pos);
            pl.MMax = ReadDoubleLittleEndian(dataStream, pos + 8);
            pointIndex = 0;
            for (var i = 0; i < pl.Lines.Length; i++)
            {
                for (var k = 0; k < pl.Lines[i].Points.Length; k++)
                {
                    pl.Lines[i].Points[k].M = ReadDoubleLittleEndian(dataStream, pos + 16 + (pointIndex * 8));
                    pointIndex++;
                }
            }

            Shapes.Add(pl);
        }
 private void ReadPointZ(Byte[] dataStream, int streamPosition)
 {
     var p = new PointZ();
     p.X = ReadDoubleLittleEndian(dataStream, streamPosition);
     p.Y = ReadDoubleLittleEndian(dataStream, streamPosition + 8);
     p.Z = ReadDoubleLittleEndian(dataStream, streamPosition + 16);
     p.M = ReadDoubleLittleEndian(dataStream, streamPosition + 24);
     Shapes.Add(p);
 }
        private void ReadPolygonZ(Byte[] dataStream, int streamPosition)
        {
            var pg = new PolygonZ();
            pg.BoundingBox = new Double[4];
            pg.BoundingBox[0] = ReadDoubleLittleEndian(dataStream, streamPosition);
            pg.BoundingBox[1] = ReadDoubleLittleEndian(dataStream, streamPosition + 8);
            pg.BoundingBox[2] = ReadDoubleLittleEndian(dataStream, streamPosition + 16);
            pg.BoundingBox[3] = ReadDoubleLittleEndian(dataStream, streamPosition + 24);
            var numberOfParts = ReadIntLittleEndian(dataStream, streamPosition + 32);
            var numberOfPoints = ReadIntLittleEndian(dataStream, streamPosition + 36);
            pg.Rings = new RingZ[numberOfParts];
            var parts = new int[numberOfParts];
            var pos = streamPosition + 40;

            // Convert starting indices to ending indices for the geometry. Skip first record.
            for (var i = 1; i < numberOfParts; i++)
            {
                parts[i - 1] = ReadIntLittleEndian(dataStream, pos + (i * 4)) - 1;
            }

            // Add the final record as the end of last "part".
            parts[numberOfParts - 1] = numberOfPoints - 1;

            pos = pos + 4 * numberOfParts;
            var z = 0;
            int lineEndsAt;
            var rng = new RingZ();
            var pts = new List<PointZ>();
            for (var i = 0; i < numberOfPoints; i++)
            {
                lineEndsAt = parts[z];
                if (i == lineEndsAt)
                {
                    // End of polygon. Add the last point and wrap up.
                    var p = new PointZ();
                    p.X = ReadDoubleLittleEndian(dataStream, pos + (i * 16));
                    p.Y = ReadDoubleLittleEndian(dataStream, pos + (i * 16) + 8);
                    pts.Add(p);
                    rng.Points = pts.ToArray();
                    pts.Clear();
                    pg.Rings[z] = rng;
                    rng = new RingZ();
                    if (z < numberOfParts - 1) z++;
                }
                else
                {
                    var p = new PointZ();
                    p.X = ReadDoubleLittleEndian(dataStream, pos + (i * 16));
                    p.Y = ReadDoubleLittleEndian(dataStream, pos + (i * 16) + 8);
                    pts.Add(p);
                }

            }

            pos = pos + numberOfPoints * 16;

            pg.ZMin = ReadDoubleLittleEndian(dataStream, pos);
            pg.ZMax = ReadDoubleLittleEndian(dataStream, pos + 8);
            var pointIndex = 0;
            for (var i = 0; i < pg.Rings.Length; i++)
            {
                for (var k = 0; k < pg.Rings[i].Points.Length; k++)
                {
                    pg.Rings[i].Points[k].Z = ReadDoubleLittleEndian(dataStream, pos + 16 + (pointIndex * 8));
                    pointIndex++;
                }
            }

            pos = pos + 16 + numberOfPoints * 8;

            pg.MMin = ReadDoubleLittleEndian(dataStream, pos);
            pg.MMax = ReadDoubleLittleEndian(dataStream, pos + 8);
            pointIndex = 0;
            for (var i = 0; i < pg.Rings.Length; i++)
            {
                for (var k = 0; k < pg.Rings[i].Points.Length; k++)
                {
                    pg.Rings[i].Points[k].M = ReadDoubleLittleEndian(dataStream, pos + 16 + (pointIndex * 8));
                    pointIndex++;
                }
            }

            Shapes.Add(pg);
        }
        private void ReadMultiPatch(Byte[] dataStream, int streamPosition)
        {
            var mp = new MultiPatch();
            mp.BoundingBox = new Double[4];
            mp.BoundingBox[0] = ReadDoubleLittleEndian(dataStream, streamPosition);
            mp.BoundingBox[1] = ReadDoubleLittleEndian(dataStream, streamPosition + 8);
            mp.BoundingBox[2] = ReadDoubleLittleEndian(dataStream, streamPosition + 16);
            mp.BoundingBox[3] = ReadDoubleLittleEndian(dataStream, streamPosition + 24);
            var numberOfParts = ReadIntLittleEndian(dataStream, streamPosition + 32);
            var numberOfPoints = ReadIntLittleEndian(dataStream, streamPosition + 36);
            mp.Parts = new MultiPatchElement[numberOfParts];
            var parts = new int[numberOfParts];
            var partTypes = new int[numberOfParts];
            var pos = streamPosition + 40;

            // Convert starting indices to ending indices for the geometry. Skip first record.
            for (var i = 1; i < numberOfParts; i++)
            {
                parts[i - 1] = ReadIntLittleEndian(dataStream, pos + (i * 4)) - 1;
            }

            // Add the final record as the end of last "part".
            parts[numberOfParts - 1] = numberOfPoints - 1;

            pos = pos + 4 * numberOfParts;

            // Convert starting indices to ending indices for the geometry. Skip first record.
            for (var i = 0; i < numberOfParts; i++)
            {
                partTypes[i] = ReadIntLittleEndian(dataStream, pos + (i * 4));
            }

            pos = pos + 4 * numberOfParts;

            var z = 0;
            int lineEndsAt;
            MultiPatchElement sh;
            var pts = new List<PointZ>();
            for (var i = 0; i < numberOfPoints; i++)
            {
                lineEndsAt = parts[z];
                if (i == lineEndsAt)
                {
                    var p = new PointZ();
                    p.X = ReadDoubleLittleEndian(dataStream, pos + (i * 16));
                    p.Y = ReadDoubleLittleEndian(dataStream, pos + (i * 16) + 8);
                    sh = CreateMultiPatchGeometry(partTypes[z]);
                    pts.Add(p);
                    sh.Points = pts.ToArray();
                    pts.Clear();
                    if (z < numberOfParts - 1) z++;
                    sh = CreateMultiPatchGeometry(partTypes[z]);
                }
                else
                {

                    var p = new PointZ();
                    p.X = ReadDoubleLittleEndian(dataStream, pos + (i * 16));
                    p.Y = ReadDoubleLittleEndian(dataStream, pos + (i * 16) + 8);
                    pts.Add(p);
                }

            }

            pos = pos + numberOfPoints * 16;

            mp.ZMin = ReadDoubleLittleEndian(dataStream, pos);
            mp.ZMax = ReadDoubleLittleEndian(dataStream, pos + 8);
            var pointIndex = 0;
            for (var i = 0; i < mp.Parts.Length; i++)
            {
                for (var k = 0; k < mp.Parts[i].Points.Length; k++)
                {
                    mp.Parts[i].Points[k].Z = ReadDoubleLittleEndian(dataStream, pos + 16 + (pointIndex * 8));
                    pointIndex++;
                }
            }

            pos = pos + 16 + numberOfPoints * 8;

            mp.MMin = ReadDoubleLittleEndian(dataStream, pos);
            mp.MMax = ReadDoubleLittleEndian(dataStream, pos + 8);
            pointIndex = 0;
            for (var i = 0; i < mp.Parts.Length; i++)
            {
                for (var k = 0; k < mp.Parts[i].Points.Length; k++)
                {
                    mp.Parts[i].Points[k].M = ReadDoubleLittleEndian(dataStream, pos + 16 + (pointIndex * 8));
                    pointIndex++;
                }
            }

            Shapes.Add(mp);
        }