/// <summary>
 /// Creates a new instance of a PolygonShapefile for in-ram handling only.
 /// </summary>
 public PolygonShapefile():base(FeatureTypes.Polygon)
 {
     Attributes = new AttributeTable();
     Header = new ShapefileHeader();
     Header.FileLength = 100;
     Header.ShapeType = ShapeTypes.Polygon;
     FeatureType = FeatureTypes.Polygon;
 }
 /// <summary>
 /// Creates a new instance of a PointShapefile for in-ram handling only.
 /// </summary>
 public PointShapefile() : base(FeatureTypes.Point)
 {
     Attributes = new AttributeTable();
     Header = new ShapefileHeader();
     Header.FileLength = 100;
     Header.ShapeType = ShapeTypes.Point;
  
 }
 /// <summary>
 /// Creates a new instance of a LineShapefile for in-ram handling only.
 /// </summary>
 public LineShapefile()
 {
     Attributes = new AttributeTable();
     Header = new ShapefileHeader();
     Header.FileLength = 100;
     Header.ShapeType = ShapeTypes.PolyLine;
     FeatureType = FeatureTypes.Line;
 }
        /// <summary>
        /// Creates a new instance of a MultiPointShapefile for in-ram handling only.
        /// </summary>
        public MultiPointShapefile():base(FeatureTypes.MultiPoint)
        {
            _geometryFactory = new GeometryFactory();
            Attributes = new AttributeTable();
            Header = new ShapefileHeader();
            Header.FileLength = 100;
            Header.ShapeType = ShapeTypes.MultiPoint;

        }
 /// <summary>
 /// Opens a shapefile
 /// </summary>
 /// <param name="filename">The string filename of the point shapefile to load</param>
 /// <param name="progressHandler">Any valid implementation of the MapWindow.Main.IProgressHandler</param>
 public void Open(string filename, IProgressHandler progressHandler)
 {
     IndexMode = true;
     Filename = filename;
     Header = new ShapefileHeader(filename);
     CoordinateType = CoordinateTypes.Regular;
     if (Header.ShapeType == ShapeTypes.PointM)
     {
         CoordinateType = CoordinateTypes.M;
     }
     if (Header.ShapeType == ShapeTypes.PointZ)
     {
         CoordinateType = CoordinateTypes.Z;
     }
     base.Envelope = Header.ToEnvelope(); 
     Name = Path.GetFileNameWithoutExtension(filename);
     Attributes.Open(filename);
     FillPoints(filename, progressHandler);
     ReadProjection();
 }
 /// <summary>
 /// This tests the specified file in order to determine what type of vector the file contains.
 /// This returns unspecified if the file format is not supported by this provider.
 /// </summary>
 /// <param name="filename">The string filename to test</param>
 /// <returns>A FeatureType clarifying what sort of features are stored on the data type.</returns>
 public virtual FeatureTypes GetFeatureType(string filename)
 {
     ShapefileHeader sh = new ShapefileHeader(filename);
     if (sh.ShapeType == ShapeTypes.Polygon || sh.ShapeType == ShapeTypes.PolygonM || sh.ShapeType == ShapeTypes.PolygonZ)
     {
         return FeatureTypes.Polygon;
     }
     if (sh.ShapeType == ShapeTypes.PolyLine || sh.ShapeType == ShapeTypes.PolyLineM || sh.ShapeType == ShapeTypes.PolyLineZ)
     {
         return FeatureTypes.Line;
     }
     if (sh.ShapeType == ShapeTypes.Point || sh.ShapeType == ShapeTypes.PointM || sh.ShapeType == ShapeTypes.PointZ)
     {
         return FeatureTypes.Point;
     }
     if(sh.ShapeType == ShapeTypes.MultiPoint || sh.ShapeType == ShapeTypes.MultiPointM || sh.ShapeType == ShapeTypes.MultiPointZ)
     {
         return FeatureTypes.MultiPoint;
     }
     return FeatureTypes.Unspecified;
 }
        /// <summary>
        /// Obtains a typed list of ShapefilePoint structures with double values associated with the various coordinates.
        /// </summary>
        /// <param name="filename">A string filename</param>
        /// <param name="progressHandler">A progress indicator</param>
        private void FillPoints(string filename, IProgressHandler progressHandler)
        {
            

            // Check to ensure the filename is not null
            if (filename == null)
            {
                throw new NullReferenceException(MessageStrings.ArgumentNull_S.Replace("%S",filename));
            }

            if (File.Exists(filename) == false)
            {
                throw new FileNotFoundException(MessageStrings.FileNotFound_S.Replace("%S", filename));
            }

            // Reading the headers gives us an easier way to track the number of shapes and their overall length etc.
            List<ShapeHeader> shapeHeaders = ReadIndexFile(filename);

            // Get the basic header information.  
            ShapefileHeader header = new ShapefileHeader(filename);
            Extent = new Extent(new[] { header.Xmin, header.Ymin, header.Xmax, header.Ymax });
            Envelope = Extent.ToEnvelope();
            // Check to ensure that the filename is the correct shape type
            if (header.ShapeType != ShapeTypes.Point && header.ShapeType != ShapeTypes.PointM && header.ShapeType != ShapeTypes.PointZ)
            {
                throw new ApplicationException(MessageStrings.FileNotPoints_S.Replace("%S", filename));
            }

            // This will set up a reader so that we can read values in huge chunks, which is much faster than one value at a time.
            IO.BufferedBinaryReader bbReader = new IO.BufferedBinaryReader(filename, progressHandler);

            if (bbReader.FileLength == 100)
            {
                bbReader.Close();
                // the file is empty so we are done reading
                return;
            }

            // Skip the shapefile header by skipping the first 100 bytes in the shapefile
            bbReader.Seek(100, SeekOrigin.Begin);
            int numShapes = shapeHeaders.Count;
            byte[] bigEndian = new byte[numShapes * 8];
            byte[] allCoords = new byte[numShapes * 16];
            bool isM = false;
            bool isZ = false;
            if(header.ShapeType == ShapeTypes.PointM || header.ShapeType == ShapeTypes.PointZ)
            {
                isM = true;
            }
            if (header.ShapeType == ShapeTypes.PointZ)
            {
                isZ = true;
            }
            byte[] allM = new byte[8];
            if(isM) allM = new byte[numShapes * 8];
            byte[] allZ = new byte[8];
            if(isZ) allZ = new byte[numShapes * 8];
            for (int shp = 0; shp < numShapes; shp++)
            {
                // Read from the index file because some deleted records
                // might still exist in the .shp file.
                long offset = (shapeHeaders[shp].ByteOffset);
                bbReader.Seek(offset, SeekOrigin.Begin);
                bbReader.Read(bigEndian, shp * 8, 8);
                ShapeTypes type = (ShapeTypes)bbReader.ReadInt32();
                //bbReader.Seek(4, SeekOrigin.Current);
                bbReader.Read(allCoords, shp * 16, 16);
                if(isZ)
                {
                    bbReader.Read(allZ, shp*8, 8);
                }
                if (isM)
                {
                    bbReader.Read(allM, shp*8, 8);
                }
                ShapeRange shape = new ShapeRange(FeatureTypes.Point);
                shape.StartIndex = shp;
                shape.ContentLength = 8;
                shape.NumPoints = 1;
                shape.NumParts = 1;
                ShapeIndices.Add(shape);
            }
            double[] vert = new double[2 * numShapes];
            Buffer.BlockCopy(allCoords, 0, vert, 0, numShapes*16);
            Vertex = vert;
            if(isM)
            {
                double[] m = new double[numShapes];
                Buffer.BlockCopy(allM, 0, m, 0, numShapes * 8);
                M = m;
            }
            if(isZ)
            {
                double[] z = new double[numShapes];
                Buffer.BlockCopy(allZ, 0, z, 0, numShapes * 8);
                Z = z;
            }
            for (int shp = 0; shp < numShapes; shp++)
            {
                PartRange part = new PartRange(vert, shp, 0, FeatureTypes.Point);
                part.NumVertices = 1;
                ShapeRange shape = ShapeIndices[shp];
                shape.Parts.Add(part);
                shape.Extent = new Extent(new[] {vert[shp*2], vert[shp*2 + 1], vert[shp*2], vert[shp*2 + 1]});
            }

                bbReader.Dispose();
            
            
            
  
        }
 private void Configure()
 {
     Attributes = new AttributeTable();
     _header = new ShapefileHeader();
     IndexMode = true;
 }
        /// <summary>
        /// This will return the correct shapefile type by reading the filename.
        /// </summary>
        /// <param name="filename">A string specifying the file with the extension .shp to open.</param>
        /// <param name="progressHandler">recieves progress messages and overrides the ProgressHandler on the DataManager.DefaultDataManager</param>
        /// <returns>A correct shapefile object which is exclusively for reading the .shp data</returns>
        public new static Shapefile OpenFile(string filename, IProgressHandler progressHandler)
        {

            ShapefileHeader head = new ShapefileHeader();
            head.Open(filename);
            PointShapefile psf;
            LineShapefile lsf;
            PolygonShapefile pgsf;
            MultiPointShapefile mpsf;
            switch (head.ShapeType)
            {
                case ShapeTypes.MultiPatch:
                    throw new NotImplementedException("This shape type is not yet supported.");
                   // break;
                case ShapeTypes.MultiPoint:
                    mpsf = new MultiPointShapefile();
                    mpsf.Open(filename, progressHandler);
                    return mpsf;
                case ShapeTypes.MultiPointM:
                    mpsf = new MultiPointShapefile();
                    mpsf.Open(filename, progressHandler);
                    return mpsf;
                case ShapeTypes.MultiPointZ:
                    mpsf = new MultiPointShapefile();
                    mpsf.Open(filename, progressHandler);
                    return mpsf;
                case ShapeTypes.NullShape:
                    throw new NotImplementedException("This shape type is not yet supported.");
                  //  break;
                case ShapeTypes.Point:
                    
                    // Instantiate a new object to handle the point shapefile
                    psf = new PointShapefile();

                    // Open the geometric components of the data (but not the dbf components)
                    psf.Open(filename, progressHandler);

                    return psf;
                    
                   

                case ShapeTypes.PointM:
                    // Instantiate a new object to handle the point shapefile
                    psf = new PointShapefile();

                    // Open the geometric components of the data (but not the dbf components)
                    psf.Open(filename, progressHandler);

                    return psf;

                    

                case ShapeTypes.PointZ:

                    // Instantiate a new object to handle the point shapefile
                    psf = new PointShapefile();

                    // Open the geometric components of the data (but not the dbf components)
                    psf.Open(filename, progressHandler);

                    return psf;

                   

                case ShapeTypes.Polygon:
                    pgsf = new PolygonShapefile();
                    pgsf.Open(filename, progressHandler);
                    return pgsf;
                 
                case ShapeTypes.PolygonM:
                    pgsf = new PolygonShapefile();
                    pgsf.Open(filename, progressHandler);
                    return pgsf;

                case ShapeTypes.PolygonZ:
                    pgsf = new PolygonShapefile();
                    pgsf.Open(filename, progressHandler);
                    return pgsf;

                case ShapeTypes.PolyLine:
                    lsf = new LineShapefile();
                    lsf.Open(filename, progressHandler);
                    return lsf;

                case ShapeTypes.PolyLineM:
                    lsf = new LineShapefile();
                    lsf.Open(filename, progressHandler);
                    return lsf;

                case ShapeTypes.PolyLineZ:
                    lsf = new LineShapefile();
                    lsf.Open(filename, progressHandler);
                    return lsf;
            }
            
            
            return null;
        }
        // X Y MultiPoints: Total Length = 28 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number      Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big
        // Byte 8       Shape Type 8        Integer     1           Little
        // Byte 12      Xmin                Double      1           Little
        // Byte 20      Ymin                Double      1           Little
        // Byte 28      Xmax                Double      1           Little
        // Byte 36      Ymax                Double      1           Little
        // Byte 48      NumPoints           Integer     1           Little
        // Byte X       Points              Point       NumPoints   Little


        // X Y M MultiPoints: Total Length = 34 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number      Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big
        // Byte 8       Shape Type 28       Integer     1           Little
        // Byte 12      Box                 Double      4           Little
        // Byte 44      NumPoints           Integer     1           Little
        // Byte X       Points              Point       NumPoints   Little
        // Byte Y*      Mmin                Double      1           Little
        // Byte Y + 8*  Mmax                Double      1           Little
        // Byte Y + 16* Marray              Double      NumPoints   Little
       
       
        
        // X Y Z M MultiPoints: Total Length = 44 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number  Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big       
        // Byte 8       Shape Type 18       Integer     1           Little
        // Byte 12      Box                 Double      4           Little
        // Byte 44      NumPoints           Integer     1           Little
        // Byte X       Points              Point       NumPoints   Little
        // Byte Y       Zmin                Double      1           Little
        // Byte Y + 8   Zmax                Double      1           Little
        // Byte Y + 16  Zarray              Double      NumPoints   Little
        // Byte Z*      Mmin                Double      1           Little
        // Byte Z+8*    Mmax                Double      1           Little
        // Byte Z+16*   Marray              Double      NumPoints   Little


        private void FillPoints(string filename, IProgressHandler progressHandler)
        {
           
            // Check to ensure the filename is not null
            if (filename == null)
            {
                throw new NullReferenceException(MessageStrings.ArgumentNull_S.Replace("%S", filename));
            }

            if (File.Exists(filename) == false)
            {
                throw new FileNotFoundException(MessageStrings.FileNotFound_S.Replace("%S", filename));
            }

            // Get the basic header information.  
            ShapefileHeader header = new ShapefileHeader(filename);
            Extent = new Extent(new[] { header.Xmin, header.Ymin, header.Xmax, header.Ymax });
            // Check to ensure that the filename is the correct shape type
            if (header.ShapeType != ShapeTypes.MultiPoint &&
                 header.ShapeType != ShapeTypes.MultiPointM &&
                 header.ShapeType != ShapeTypes.MultiPointZ)
            {
                throw new ArgumentException(MessageStrings.FileNotLines_S.Replace("%S", filename));

            }

            // Reading the headers gives us an easier way to track the number of shapes and their overall length etc.
            List<ShapeHeader> shapeHeaders = ReadIndexFile(filename);


            // This will set up a reader so that we can read values in huge chunks, which is much faster than one value at a time.
            IO.BufferedBinaryReader bbReader = new IO.BufferedBinaryReader(filename, progressHandler);

            if (bbReader.FileLength == 100)
            {
                // The shapefile is empty so we can simply return here
                bbReader.Close();
                return;
            }


            // Skip the shapefile header by skipping the first 100 bytes in the shapefile
            bbReader.Seek(100, SeekOrigin.Begin);

            int numShapes = shapeHeaders.Count;

            byte[] bigEndians = new byte[numShapes * 8];
            byte[] allBounds = new byte[numShapes * 32];
        
            ByteBlock allCoords = new ByteBlock(BLOCKSIZE);
            bool isM = (header.ShapeType == ShapeTypes.MultiPointZ || header.ShapeType == ShapeTypes.MultiPointM);
            bool isZ = (header.ShapeType == ShapeTypes.PolyLineZ);
            ByteBlock allZ = null;
            ByteBlock allM = null;
            if (isZ)
            {
                allZ = new ByteBlock(BLOCKSIZE);
            }
            if (isM)
            {
                allM = new ByteBlock(BLOCKSIZE);
            }
            int pointOffset = 0;
            for (int shp = 0; shp < numShapes; shp++)
            {

                // Read from the index file because some deleted records
                // might still exist in the .shp file.
                long offset = (shapeHeaders[shp].ByteOffset);
                bbReader.Seek(offset, SeekOrigin.Begin);

                // time: 200 ms
                ShapeRange shape = new ShapeRange(FeatureTypes.MultiPoint);


                shape.RecordNumber = bbReader.ReadInt32(false);       // Byte 0       Record Number       Integer     1           Big
                shape.ContentLength = bbReader.ReadInt32(false);      // Byte 4       Content Length      Integer     1           Big
                //bbReader.Read(bigEndians, shp * 8, 8);
                shape.ShapeType = (ShapeTypes)bbReader.ReadInt32();     
                shape.StartIndex = pointOffset;
                if (shape.ShapeType == ShapeTypes.NullShape)
                {
                    continue;
                }
                bbReader.Read(allBounds, shp * 32, 32);
                shape.NumParts = 1;                                    
                shape.NumPoints = bbReader.ReadInt32();                 
                allCoords.Read(shape.NumPoints * 16, bbReader);
                pointOffset += shape.NumPoints;

                if (header.ShapeType == ShapeTypes.MultiPointM)
                {
                    // These are listed as "optional" but there isn't a good indicator of how to determine if they were added.
                    // To handle the "optional" M values, check the contentLength for the feature.
                    // The content length does not include the 8-byte record header and is listed in 16-bit words.
                    if (shape.ContentLength * 2 > 44 + 4 * shape.NumParts + 16 * shape.NumPoints)
                    {
                        double mMin = bbReader.ReadDouble();
                        double mMax = bbReader.ReadDouble();
                        //bbReader.Seek(16, SeekOrigin.Current);
                        if (allM != null) allM.Read(shape.NumPoints * 8, bbReader);
                    }
                }
                if (header.ShapeType == ShapeTypes.MultiPointZ)
                {
                    bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                    double zMin = bbReader.ReadDouble();
                    double zMax = bbReader.ReadDouble();
                    // For Z shapefiles, the Z part is not optional.
                    if (allZ != null) allZ.Read(shape.NumPoints * 8, bbReader);

                    // These are listed as "optional" but there isn't a good indicator of how to determine if they were added.
                    // To handle the "optional" M values, check the contentLength for the feature.
                    // The content length does not include the 8-byte record header and is listed in 16-bit words.
                    if (hasM)
                    {
                        double mMin = bbReader.ReadDouble();
                        double mMax = bbReader.ReadDouble();
                        
                        if (allM != null) allM.Read(shape.NumPoints * 8, bbReader);
                    }
                }
                // Now that we have read all the values, create the geometries from the points and parts arrays.
                ShapeIndices.Add(shape);
            }
            double[] vert = allCoords.ToDoubleArray();
            Vertex = vert;
            if (isM) M = allM.ToDoubleArray();
            if (isZ) Z = allZ.ToDoubleArray();
            Array.Reverse(bigEndians);
            List<ShapeRange> shapes = ShapeIndices;
            double[] bounds = new double[numShapes * 4];
            Buffer.BlockCopy(allBounds, 0, bounds, 0, allBounds.Length);
            for (int shp = 0; shp < numShapes; shp++)
            {
                ShapeRange shape = shapes[shp];
                shape.Extent = new Extent(bounds, shp * 4);
                int endIndex = shape.NumPoints + shape.StartIndex;
                int startIndex = shape.StartIndex;
                int count = endIndex - startIndex;
                PartRange partR = new PartRange(vert, shape.StartIndex, 0, FeatureTypes.MultiPoint);
                partR.NumVertices = count;
                shape.Parts.Add(partR);
            }
            GC.Collect();
            bbReader.Dispose();
        }
        // X Y Poly Lines: Total Length = 28 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number      Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big
        // Byte 8       Shape Type 3        Integer     1           Little
        // Byte 12      Xmin                Double      1           Little
        // Byte 20      Ymin                Double      1           Little
        // Byte 28      Xmax                Double      1           Little
        // Byte 36      Ymax                Double      1           Little
        // Byte 44      NumParts            Integer     1           Little
        // Byte 48      NumPoints           Integer     1           Little
        // Byte 52      Parts               Integer     NumParts    Little
        // Byte X       Points              Point       NumPoints   Little


        // X Y M Poly Lines: Total Length = 34 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number      Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big
        // Byte 8       Shape Type 23       Integer     1           Little
        // Byte 12      Box                 Double      4           Little
        // Byte 44      NumParts            Integer     1           Little
        // Byte 48      NumPoints           Integer     1           Little
        // Byte 52      Parts               Integer     NumParts    Little
        // Byte X       Points              Point       NumPoints   Little
        // Byte Y*      Mmin                Double      1           Little
        // Byte Y + 8*  Mmax                Double      1           Little
        // Byte Y + 16* Marray              Double      NumPoints   Little
       
       
        
        // X Y Z M Poly Lines: Total Length = 44 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number  Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big       
        // Byte 8       Shape Type 13       Integer     1           Little
        // Byte 12      Box                 Double      4           Little
        // Byte 44      NumParts            Integer     1           Little
        // Byte 48      NumPoints           Integer     1           Little
        // Byte 52      Parts               Integer     NumParts    Little
        // Byte X       Points              Point       NumPoints   Little
        // Byte Y       Zmin                Double      1           Little
        // Byte Y + 8   Zmax                Double      1           Little
        // Byte Y + 16  Zarray              Double      NumPoints   Little
        // Byte Z*      Mmin                Double      1           Little
        // Byte Z+8*    Mmax                Double      1           Little
        // Byte Z+16*   Marray              Double      NumPoints   Little

       


        private void FillPolygons(string filename, IProgressHandler progressHandler)
        {
           
            // Check to ensure the filename is not null
            if (filename == null)
            {
                throw new NullReferenceException(MessageStrings.ArgumentNull_S.Replace("%S", filename));
            }

            if (File.Exists(filename) == false)
            {
                throw new FileNotFoundException(MessageStrings.FileNotFound_S.Replace("%S", filename));
            }

            // Get the basic header information.  
            ShapefileHeader header = new ShapefileHeader(filename);
            Extent = new Extent(new[]{header.Xmin, header.Ymin, header.Xmax, header.Ymax});

            // Check to ensure that the filename is the correct shape type
            if (header.ShapeType != ShapeTypes.Polygon &&
                 header.ShapeType != ShapeTypes.PolygonM &&
                 header.ShapeType != ShapeTypes.PolygonZ)
            {
                throw new ArgumentException(MessageStrings.FileNotLines_S.Replace("%S", filename));

            }

            // Reading the headers gives us an easier way to track the number of shapes and their overall length etc.
            List<ShapeHeader> shapeHeaders = ReadIndexFile(filename);


            // This will set up a reader so that we can read values in huge chunks, which is much faster than one value at a time.
            IO.BufferedBinaryReader bbReader = new IO.BufferedBinaryReader(filename, progressHandler);

            if (bbReader.FileLength == 100)
            {
                // The shapefile is empty so we can simply return here
                bbReader.Close();
                return;
            }

            // Skip the shapefile header by skipping the first 100 bytes in the shapefile
            bbReader.Seek(100, SeekOrigin.Begin);

            int numShapes = shapeHeaders.Count;
            
            int [] partOffsets = new int[numShapes];
            byte[] bigEndians = new byte[numShapes * 8];
            byte[] allBounds = new byte[numShapes * 32];

            ByteBlock allParts = new ByteBlock(BLOCKSIZE); // probably all will be in one block, but use a byteBlock just in case.
            ByteBlock allCoords = new ByteBlock(BLOCKSIZE);
            bool isM = (header.ShapeType == ShapeTypes.PolyLineM || header.ShapeType == ShapeTypes.PolyLineZ);
            bool isZ = (header.ShapeType == ShapeTypes.PolyLineZ);
            ByteBlock allZ = null;
            ByteBlock allM = null;
            if (isZ)
            {
                allZ = new ByteBlock(BLOCKSIZE);
            }
            if (isM)
            {
                allM = new ByteBlock(BLOCKSIZE);
            }

            int pointOffset = 0;
            for (int shp = 0; shp < numShapes; shp++)
            {
                // Read from the index file because some deleted records
                // might still exist in the .shp file.
                long offset = (shapeHeaders[shp].ByteOffset);
                bbReader.Seek(offset, SeekOrigin.Begin);

                                                                    // Position     Value               Type        Number      Byte Order
                ShapeRange shape = new ShapeRange(FeatureTypes.Polygon); //-------------------------------------------------------------------- 
                shape.RecordNumber = bbReader.ReadInt32(false);     // Byte 0       Record Number       Integer     1           Big
                shape.ContentLength = bbReader.ReadInt32(false);    // Byte 4       Content Length      Integer     1           Big
                shape.ShapeType = (ShapeTypes)bbReader.ReadInt32(); // Byte 8       Shape Type          Integer     1           Little
                shape.StartIndex = pointOffset;
                if (shape.ShapeType == ShapeTypes.NullShape)
                {
                    continue;
                }
                bbReader.Read(allBounds, shp*32, 32);
                //double xMin = bbReader.ReadDouble();                // Byte 12      Xmin                Double      1           Little
               // double yMin = bbReader.ReadDouble();                // Byte 20      Ymin                Double      1           Little
                //double xMax = bbReader.ReadDouble();                // Byte 28      Xmax                Double      1           Little
                //double yMax = bbReader.ReadDouble();                // Byte 36      Ymax                Double      1           Little
                shape.NumParts = bbReader.ReadInt32();              // Byte 44      NumParts            Integer     1           Little
                //feature.NumPoints = bbReader.ReadInt32();             // Byte 48      NumPoints           Integer     1           Little
                shape.NumPoints = bbReader.ReadInt32();                                             
                
                // Create an envelope from the extents box in the file.
                //feature.Envelope = new Envelope(xMin, xMax, yMin, yMax);

                partOffsets[shp] = allParts.IntOffset();
                allParts.Read(shape.NumParts * 4, bbReader);
                allCoords.Read(shape.NumPoints * 16, bbReader);
                pointOffset += shape.NumPoints;



                if (header.ShapeType == ShapeTypes.PolygonM)
                {
                    // These are listed as "optional" but there isn't a good indicator of how to determine if they were added.
                    // To handle the "optional" M values, check the contentLength for the feature.
                    // The content length does not include the 8-byte record header and is listed in 16-bit words.
                    if (shape.ContentLength * 2 > 44 + 4 * shape.NumParts + 16 * shape.NumPoints)
                    {
                        double mMin = bbReader.ReadDouble();
                        double mMax = bbReader.ReadDouble();
                        
                        if(allM != null)allM.Read(shape.NumPoints * 8, bbReader);
                    }
                }

                if (header.ShapeType == ShapeTypes.PolygonZ)
                {
                    bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                    double zMin = bbReader.ReadDouble();
                    double zMax = bbReader.ReadDouble();
                   
                    
                    // For Z shapefiles, the Z part is not optional.  
                    if (allZ != null) allZ.Read(shape.NumPoints * 8, bbReader);
                   
                    // These are listed as "optional" but there isn't a good indicator of how to determine if they were added.
                    // To handle the "optional" M values, check the contentLength for the feature.
                    // The content length does not include the 8-byte record header and is listed in 16-bit words.
                    if (hasM)
                    {
                        double mMin = bbReader.ReadDouble();
                        double mMax = bbReader.ReadDouble();
                        if (allM != null) allM.Read(shape.NumPoints * 8, bbReader);
                    }
                    
                }
                ShapeIndices.Add(shape);
            }

            double[] vert = allCoords.ToDoubleArray();
            Vertex = vert;
            if (isM) M = allM.ToDoubleArray();
            if (isZ) Z = allZ.ToDoubleArray();
            List<ShapeRange> shapes = ShapeIndices;
            double[] bounds = new double[numShapes * 4];
            Buffer.BlockCopy(allBounds, 0, bounds, 0, allBounds.Length);
            int[] parts = allParts.ToIntArray();
            ProgressMeter = new ProgressMeter(ProgressHandler, "Testing Parts and Holes", numShapes);
            for (int shp = 0; shp < numShapes; shp++)
            {
                ShapeRange shape = shapes[shp];
                shape.Extent = new Extent(bounds, shp * 4);
                for (int part = 0; part < shape.NumParts; part++)
                {
                    int offset = partOffsets[shp];
                    int endIndex = shape.NumPoints + shape.StartIndex;
                    int startIndex = parts[offset + part] + shape.StartIndex;
                    if (part < shape.NumParts - 1) endIndex = parts[offset + part + 1] + shape.StartIndex;
                    int count = endIndex - startIndex;
                    PartRange partR = new PartRange(vert, shape.StartIndex, parts[offset + part], FeatureTypes.Polygon);
                    partR.NumVertices = count;
                    shape.Parts.Add(partR);
                }
                ProgressMeter.CurrentValue = shp;
            }
            ProgressMeter.Reset();
            GC.Collect();
        }