/// <inheritdocs/>
        protected override Shape GetShapeAtIndex(FileStream fs, ShapefileIndexFile shx, ShapefileHeader header, int shp, IEnvelope envelope)
        {
            // Read from the index file because some deleted records
            // might still exist in the .shp file.
            long offset = (shx.Shapes[shp].ByteOffset);
            fs.Seek(offset, SeekOrigin.Begin);
            Shape myShape = new Shape();
            // Position     Value               Type        Number      Byte Order
            ShapeRange shape = new ShapeRange(FeatureType.Line);
            //--------------------------------------------------------------------
            shape.RecordNumber = fs.ReadInt32(Endian.BigEndian);
            // Byte 0       Record Number       Integer     1           Big
            shape.ContentLength = fs.ReadInt32(Endian.BigEndian);
            // Byte 4       Content Length      Integer     1           Big
            shape.ShapeType = (ShapeType)fs.ReadInt32();
            // Byte 8       Shape Type          Integer     1           Little
            shape.StartIndex = 0;
            if (shape.ShapeType == ShapeType.NullShape)
            {
                return null;
            }

            myShape.Range = shape;

            //bbReader.Read(allBounds, shp*32, 32);
            double xMin = fs.ReadDouble(); // Byte 12      Xmin                Double      1           Little
            double yMin = fs.ReadDouble(); // Byte 20      Ymin                Double      1           Little
            double xMax = fs.ReadDouble(); // Byte 28      Xmax                Double      1           Little
            double yMax = fs.ReadDouble(); // Byte 36      Ymax                Double      1           Little
            shape.Extent = new Extent(xMin, yMin, xMax, yMax);
            // Don't add this shape to the result
            if (envelope != null)
            {
                if (!myShape.Range.Extent.Intersects(envelope))
                {
                    return null;
                }
            }

            shape.NumParts = fs.ReadInt32(); // Byte 44      NumParts            Integer     1           Little
            //feature.NumPoints = bbReader.ReadInt32();             // Byte 48      NumPoints           Integer     1           Little
            shape.NumPoints = fs.ReadInt32();

            // Create an envelope from the extents box in the file.
            //feature.Envelope = new Envelope(xMin, xMax, yMin, yMax);
            int[] partIndices = fs.ReadInt32(shape.NumParts);
            myShape.Vertices = fs.ReadDouble(shape.NumPoints * 2);

            if (header.ShapeType == ShapeType.PolyLineM)
            {
                // 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)
                {
                    myShape.MinM = fs.ReadDouble();
                    myShape.MaxM = fs.ReadDouble();

                    myShape.M = fs.ReadDouble(shape.NumPoints);
                    shape.Extent = new ExtentM(shape.Extent, myShape.MinM, myShape.MaxM);
                }
            }
            else if (header.ShapeType == ShapeType.PolyLineZ)
            {
                bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                myShape.MinZ = fs.ReadDouble();
                myShape.MaxZ = fs.ReadDouble();

                // For Z shapefiles, the Z part is not optional.
                myShape.Z = fs.ReadDouble(shape.NumPoints);

                // 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)
                {
                    myShape.MinM = fs.ReadDouble();
                    myShape.MaxM = fs.ReadDouble();
                    myShape.M = fs.ReadDouble(shape.NumPoints);
                    shape.Extent = new ExtentMZ(shape.Extent.MinX, shape.Extent.MinY, myShape.MinM, myShape.MinZ, shape.Extent.MaxX, shape.Extent.MaxY, myShape.MaxM, myShape.MaxZ);
                }
                else
                    shape.Extent = new ExtentMZ(shape.Extent.MinX, shape.Extent.MinY, double.MaxValue, myShape.MinZ, shape.Extent.MaxX, shape.Extent.MaxY, double.MinValue, myShape.MaxZ);
            }

            myShape.Range = shape;

            for (int part = 0; part < shape.NumParts; part++)
            {
                int partOff = partIndices[part];
                int pointCount = shape.NumPoints - partOff;
                if (part < shape.NumParts - 1)
                {
                    pointCount = partIndices[part + 1] - partOff;
                }
                PartRange partR = new PartRange(myShape.Vertices, 0, partOff, FeatureType.Line) { NumVertices = pointCount };
                shape.Parts.Add(partR);
            }
            return myShape;
        }
Ejemplo n.º 2
0
        internal static void FillLines(string fileName, IProgressHandler progressHandler, Shapefile shapefile,
            FeatureType featureType)
        {
            // Check to ensure the fileName is not null
            if (fileName == null)
            {
                throw new NullReferenceException(DataStrings.ArgumentNull_S.Replace("%S", "fileName"));
            }
            if (shapefile == null) throw new ArgumentNullException("shapefile");

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

            if (featureType != FeatureType.Line && featureType != FeatureType.Polygon)
            {
                throw new NotSupportedException();
            }

            var header = shapefile.Header;
            // Check to ensure that the fileName is the correct shape type
            switch (featureType)
            {
                case FeatureType.Line:
                    if (header.ShapeType != ShapeType.PolyLine &&
                        header.ShapeType != ShapeType.PolyLineM &&
                        header.ShapeType != ShapeType.PolyLineZ)
                    {
                        throw new ArgumentException(DataStrings.FileNotLines_S.Replace("%S", fileName));
                    }
                    break;
                case FeatureType.Polygon:
                    if (header.ShapeType != ShapeType.Polygon &&
                        header.ShapeType != ShapeType.PolygonM &&
                        header.ShapeType != ShapeType.PolygonZ)
                    {
                        throw new ArgumentException(DataStrings.FileNotLines_S.Replace("%S", fileName));
                    }
                    break;
            }

            if (new FileInfo(fileName).Length == 100)
            {
                // the file is empty so we are done reading
                return;
            }

            // Reading the headers gives us an easier way to track the number of shapes and their overall length etc.
            var shapeHeaders = shapefile.ReadIndexFile(fileName);
            int numShapes = shapeHeaders.Count;

            bool isM = false, isZ = false;
            switch (header.ShapeType)
            {
                case ShapeType.PolyLineM:
                case ShapeType.PolygonM:
                    isM = true;
                    break;
                case ShapeType.PolyLineZ:
                case ShapeType.PolygonZ:
                    isZ = true;
                    isM = true;
                    break;
            }

            int totalPointsCount = 0;
            int totalPartsCount = 0;
            var shapeIndices = new List<ShapeRange>(numShapes);

            var progressMeter = new ProgressMeter(progressHandler, "Reading from " + Path.GetFileName(fileName))
            {
                StepPercent = 5
            };
            using (var reader = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 65536))
            {
                var boundsBytes = new byte[4 * 8];
                var bounds = new double[4];
                for (int shp = 0; shp < numShapes; shp++)
                {
                    progressMeter.CurrentPercent = (int)(shp * 50.0 / numShapes);

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

                    var shape = new ShapeRange(featureType, shapefile.CoordinateType)
                    {
                        RecordNumber = reader.ReadInt32(Endian.BigEndian),
                        ContentLength = reader.ReadInt32(Endian.BigEndian),
                        ShapeType = (ShapeType)reader.ReadInt32(),
                        StartIndex = totalPointsCount
                    };
                    Debug.Assert(shape.RecordNumber == shp + 1);

                    if (shape.ShapeType != ShapeType.NullShape)
                    {
                        // Bounds
                        reader.Read(boundsBytes, 0, boundsBytes.Length);
                        Buffer.BlockCopy(boundsBytes, 0, bounds, 0, boundsBytes.Length);
                        shape.Extent.MinX = bounds[0];
                        shape.Extent.MinY = bounds[1];
                        shape.Extent.MaxX = bounds[2];
                        shape.Extent.MaxY = bounds[3];

                        // Num Parts
                        shape.NumParts = reader.ReadInt32();
                        totalPartsCount += shape.NumParts;

                        // Num Points
                        shape.NumPoints = reader.ReadInt32();
                        totalPointsCount += shape.NumPoints;
                    }

                    shapeIndices.Add(shape);
                }

                var vert = new double[totalPointsCount * 2];
                var vertInd = 0;

                var parts = new int[totalPartsCount];
                var partsInd = 0;

                double[] mArray = null, zArray = null;
                if (isM)
                {
                    mArray = new double[totalPointsCount];
                }
                int mArrayInd = 0;
                if (isZ)
                {
                    zArray = new double[totalPointsCount];
                }
                int zArrayInd = 0;

                int partsOffset = 0;
                for (int shp = 0; shp < numShapes; shp++)
                {
                    progressMeter.CurrentPercent = (int)(50 + shp * 50.0 / numShapes);

                    var shape = shapeIndices[shp];
                    if (shape.ShapeType == ShapeType.NullShape) continue;
                    reader.Seek(shapeHeaders[shp].ByteOffset, SeekOrigin.Begin);
                    reader.Seek(3 * 4 + 32 + 2 * 4, SeekOrigin.Current); // Skip first bytes

                    // Read parts
                    var partsBytes = reader.ReadBytes(4 * shape.NumParts);
                    Buffer.BlockCopy(partsBytes, 0, parts, partsInd, partsBytes.Length);
                    partsInd += 4 * shape.NumParts;

                    // Read points
                    var pointsBytes = reader.ReadBytes(8 * 2 * shape.NumPoints);
                    Buffer.BlockCopy(pointsBytes, 0, vert, vertInd, pointsBytes.Length);
                    vertInd += 8 * 2 * shape.NumPoints;

                    // Fill parts
                    shape.Parts.Capacity = shape.NumParts;
                    for (int part = 0; part < shape.NumParts; part++)
                    {
                        int endIndex = shape.NumPoints + shape.StartIndex;
                        int startIndex = parts[partsOffset + part] + shape.StartIndex;
                        if (part < shape.NumParts - 1)
                        {
                            endIndex = parts[partsOffset + part + 1] + shape.StartIndex;
                        }
                        int count = endIndex - startIndex;
                        var partR = new PartRange(vert, shape.StartIndex, parts[partsOffset + part], featureType)
                        {
                            NumVertices = count
                        };
                        shape.Parts.Add(partR);
                    }
                    partsOffset += shape.NumParts;

                    // Fill M and Z arrays
                    switch (header.ShapeType)
                    {
                        case ShapeType.PolyLineM:
                        case ShapeType.PolygonM:
                            if (shape.ContentLength * 2 > 44 + 4 * shape.NumParts + 16 * shape.NumPoints)
                            {
                                var mExt = (IExtentM)shape.Extent;
                                mExt.MinM = reader.ReadDouble();
                                mExt.MaxM = reader.ReadDouble();

                                var mBytes = reader.ReadBytes(8 * shape.NumPoints);
                                Buffer.BlockCopy(mBytes, 0, mArray, mArrayInd, mBytes.Length);
                                mArrayInd += 8 * shape.NumPoints;
                            }
                            break;
                        case ShapeType.PolyLineZ:
                        case ShapeType.PolygonZ:
                            var zExt = (IExtentZ)shape.Extent;
                            zExt.MinZ = reader.ReadDouble();
                            zExt.MaxZ = reader.ReadDouble();

                            var zBytes = reader.ReadBytes(8 * shape.NumPoints);
                            Buffer.BlockCopy(zBytes, 0, zArray, zArrayInd, zBytes.Length);
                            zArrayInd += 8 * shape.NumPoints;


                            // 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 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints)
                            {
                                goto case ShapeType.PolyLineM;
                            }

                            break;
                    }
                }

                if (isM) shapefile.M = mArray;
                if (isZ) shapefile.Z = zArray;
                shapefile.ShapeIndices = shapeIndices;
                shapefile.Vertex = vert;
            }

            progressMeter.Reset();
        }
        /// <inheritdocs/>
        protected override Shape GetShapeAtIndex(FileStream fs, ShapefileIndexFile shx, ShapefileHeader header, int shp, IEnvelope envelope)
        {
            // Read from the index file because some deleted records
            // might still exist in the .shp file.
            long offset = (shx.Shapes[shp].ByteOffset);
            fs.Seek(offset, SeekOrigin.Begin);
            Shape myShape = new Shape();
            // Position     Value               Type        Number      Byte Order
            ShapeRange shape = new ShapeRange(FeatureType.Point); //--------------------------------------------------------------------
            shape.RecordNumber = fs.ReadInt32(Endian.BigEndian);     // Byte 0       Record Number       Integer     1           Big
            shape.ContentLength = fs.ReadInt32(Endian.BigEndian);    // Byte 4       Content Length      Integer     1           Big
            ShapeType shapeType = (ShapeType)fs.ReadInt32(); // Byte 8       Shape Type          Integer     1           Little
            if (shapeType == ShapeType.NullShape)
            {
                return null;
            }
            double[] vertices = fs.ReadDouble(2);
            double x = vertices[0], y = vertices[1];
            // Don't add this shape to the result
            if (envelope != null)
            {
                if (!envelope.Contains(new Coordinate(x, y)))
                {
                    return null;
                }
            }

            shape.StartIndex = 0;
            shape.NumParts = 1;
            shape.NumPoints = 1;
            shape.ShapeType = shapeType;
            shape.Extent = new Extent(x, y, x, y);
            myShape.Range = shape;
            myShape.Vertices = vertices;

            if (header.ShapeType == ShapeType.PointM)
            {
                myShape.M = fs.ReadDouble(1);
                myShape.MinM = myShape.MaxM = myShape.M[0];
                shape.Extent = new ExtentM(shape.Extent, myShape.MinM, myShape.MaxM);
            }
            else if (header.ShapeType == ShapeType.PointZ)
            {
                // For Z shapefiles, the Z part is not optional.
                myShape.Z = fs.ReadDouble(1);
                myShape.MinZ = myShape.MaxZ = myShape.Z[0];
                myShape.M = fs.ReadDouble(1);
                myShape.MinM = myShape.MaxM = myShape.M[0];
                shape.Extent = new ExtentMZ(shape.Extent.MinX, shape.Extent.MinY, myShape.MinM, myShape.MinZ, shape.Extent.MaxX, shape.Extent.MaxY, myShape.MaxM, myShape.MaxZ);
            }

            PartRange partR = new PartRange(myShape.Vertices, 0, 0, FeatureType.Point) { NumVertices = 1 };
            shape.Parts.Add(partR);
            myShape.Range = shape;

            return myShape;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Obtains a typed list of ShapefilePoint structures with double values associated with the various coordinates.
        /// </summary>
        /// <param name="fileName">A string fileName</param>
        private void FillPoints(string fileName)
        {
            // Check to ensure the fileName is not null
            if (fileName == null)
            {
                throw new NullReferenceException(DataStrings.ArgumentNull_S.Replace("%S", fileName));
            }

            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException(DataStrings.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 = header.ToExtent();
            // Check to ensure that the fileName is the correct shape type
            if (header.ShapeType != ShapeType.Point && header.ShapeType != ShapeType.PointM
                && header.ShapeType != ShapeType.PointZ)
            {
                throw new ApplicationException(DataStrings.FileNotPoints_S.Replace("%S", fileName));
            }

            if (new FileInfo(fileName).Length == 100)
            {
                // the file is empty so we are done reading
                return;
            }

            var numShapes = shapeHeaders.Count;
            double[] m = null;
            double[] z = null;
            var vert = new double[2 * numShapes]; // X,Y

            if (header.ShapeType == ShapeType.PointM || header.ShapeType == ShapeType.PointZ)
            {
                m = new double[numShapes];
            }
            if (header.ShapeType == ShapeType.PointZ)
            {
                z = new double[numShapes];
            }

            using (var reader = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                for (var shp = 0; shp < numShapes; shp++)
                {
                    reader.Seek(shapeHeaders[shp].ByteOffset, SeekOrigin.Begin);

                    var recordNumber = reader.ReadInt32(Endian.BigEndian);
                    Debug.Assert(recordNumber == shp + 1);
                    var contentLen = reader.ReadInt32(Endian.BigEndian);
                    Debug.Assert(contentLen == shapeHeaders[shp].ContentLength);

                    var shapeType = (ShapeType) reader.ReadInt32(Endian.LittleEndian);
                    if (shapeType == ShapeType.NullShape)
                    {
                        if (m != null)
                        {
                            m[shp] = double.MinValue;
                        }
                        goto fin;
                    }

                    // Read X
                    var ind = 4;
                    vert[shp*2] = reader.ReadDouble(1, Endian.LittleEndian)[0];
                    ind += 8;

                    // Read Y
                    vert[shp*2 + 1] = reader.ReadDouble(1, Endian.LittleEndian)[0];
                    ind += 8;

                    // Read Z
                    if (z != null)
                    {
                        z[shp] = reader.ReadDouble(1, Endian.LittleEndian)[0];
                        ind += 8;
                    }

                    // Read M
                    if (m != null)
                    {
                        if (shapeHeaders[shp].ByteLength <= ind)
                        {
                            m[shp] = double.MinValue;
                        }
                        else
                        {
                            m[shp] = reader.ReadDouble(1, Endian.LittleEndian)[0];
                            ind += 8;
                        }
                    }

               fin:
                    var shape = new ShapeRange(FeatureType.Point)
                    {
                        StartIndex = shp,
                        ContentLength = shapeHeaders[shp].ContentLength,
                        NumPoints = 1,
                        NumParts = 1
                    };
                    ShapeIndices.Add(shape);
                    var part = new PartRange(vert, shp, 0, FeatureType.Point) {NumVertices = 1};
                    shape.Parts.Add(part);
                    shape.Extent = new Extent(new[] {vert[shp*2], vert[shp*2 + 1], vert[shp*2], vert[shp*2 + 1]});

                }
            }

            Vertex = vert;
            M = m;
            Z = z;
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Parses the first 100 bytes of a shapefile into the important values
        /// </summary>
        /// <param name="inFilename">The fileName to read</param>
        public void Open(string inFilename)
        {
            Filename = inFilename;

            //  Position        Field           Value       Type        ByteOrder
            //  --------------------------------------------------------------
            //  Byte 0          File Code       9994        Integer     Big
            //  Byte 4          Unused          0           Integer     Big
            //  Byte 8          Unused          0           Integer     Big
            //  Byte 12         Unused          0           Integer     Big
            //  Byte 16         Unused          0           Integer     Big
            //  Byte 20         Unused          0           Integer     Big
            //  Byte 24         File Length     File Length Integer     Big
            //  Byte 28         Version         1000        Integer     Little
            //  Byte 32         Shape Type      Shape Type  Integer     Little
            //  Byte 36         Bounding Box    Xmin        Double      Little
            //  Byte 44         Bounding Box    Ymin        Double      Little
            //  Byte 52         Bounding Box    Xmax        Double      Little
            //  Byte 60         Bounding Box    Ymax        Double      Little
            //  Byte 68         Bounding Box    Zmin        Double      Little
            //  Byte 76         Bounding Box    Zmax        Double      Little
            //  Byte 84         Bounding Box    Mmin        Double      Little
            //  Byte 92         Bounding Box    Mmax        Double      Little

            // This may throw an IOException if the file is already in use.
            using (var bbReader = new FileStream(inFilename, FileMode.Open))
            {

                // Reading BigEndian simply requires us to reverse the byte order.
                FileCode = bbReader.ReadInt32(Endian.BigEndian);

                // Skip the next 20 bytes because they are unused
                bbReader.Seek(20, SeekOrigin.Current);

                // Read the file length in reverse sequence
                FileLength = bbReader.ReadInt32(Endian.BigEndian);

                // From this point on, all the header values are in little Endean

                // Read the version
                Version = bbReader.ReadInt32();

                // Read in the shape type that should be the shape type for the whole shapefile
                ShapeType = (ShapeType) bbReader.ReadInt32();

                // Get the extents, each of which are double values.
                Xmin = bbReader.ReadDouble();
                Ymin = bbReader.ReadDouble();
                Xmax = bbReader.ReadDouble();
                Ymax = bbReader.ReadDouble();
                Zmin = bbReader.ReadDouble();
                Zmax = bbReader.ReadDouble();
                Mmin = bbReader.ReadDouble();
                Mmax = bbReader.ReadDouble();
            }
            
            var fi = new FileInfo(ShxFilename);
            if (fi.Exists)
            {
                ShxLength = Convert.ToInt32(fi.Length / 2); //length is in 16 bit words.
            }
        }