Exemple #1
0
        /// <summary>
        /// Creates a new multi-part polygon shape.  Winding order should control holes.
        /// </summary>
        /// <param name="allParts">The list of all the lists of coordinates.</param>
        /// <returns>A new Multi-Polygon Shape.</returns>
        public Shape CreateMultiPolygonFromCoordinates(IEnumerable<IEnumerable<Coordinate>> allParts)
        {
            Shape shp = new Shape(FeatureType.Polygon);
            List<Coordinate> allCoords = new List<Coordinate>();
            List<int> offsets = new List<int>();
            List<int> counts = new List<int>();
            int count = 0;
            int numParts = 0;
            foreach (List<Coordinate> part in allParts)
            {
                int coordinatecount = 0;
                foreach (Coordinate c in part)
                {
                    allCoords.Add(c);
                    count++;
                    coordinatecount++;
                }
                offsets.Add(count);
                counts.Add(coordinatecount);
                numParts++;
            }

            shp.Vertices = new double[allCoords.Count * 2];
            for (int i = 0; i < allCoords.Count; i++)
            {
                shp.Vertices[i * 2] = allCoords[i].X;
                shp.Vertices[i * 2 + 1] = allCoords[i].Y;
            }
            ShapeRange result = new ShapeRange(FeatureType.Polygon);

            for (int i = 0; i < numParts; i++)
            {
                PartRange prt = new PartRange(shp.Vertices, 0, offsets[i], FeatureType.Polygon);
                prt.NumVertices = counts[i];
                result.Parts.Add(prt);
            }
            return shp;
        }
Exemple #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ShapeRange"/> class.
        /// This creates a polygon shape from an extent.
        /// </summary>
        /// <param name="ext">The extent to turn into a polygon shape.</param>
        public ShapeRange(Extent ext)
        {
            Extent    = ext;
            Parts     = new List <PartRange>();
            _numParts = -1;

            // Counter clockwise
            // 1 2
            // 4 3
            double[] coords = new double[8];

            // C1
            coords[0] = ext.MinX;
            coords[1] = ext.MaxY;

            // C2
            coords[2] = ext.MaxX;
            coords[3] = ext.MaxY;

            // C3
            coords[4] = ext.MaxX;
            coords[5] = ext.MinY;

            // C4
            coords[6] = ext.MinX;
            coords[7] = ext.MinY;

            FeatureType = FeatureType.Polygon;
            ShapeType   = ShapeType.Polygon;
            PartRange pr = new PartRange(coords, 0, 0, FeatureType.Polygon)
            {
                NumVertices = 4
            };

            Parts.Add(pr);
        }
Exemple #3
0
        // 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(DataStrings.ArgumentNull_S.Replace("%S", fileName));
            }

            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException(DataStrings.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 != ShapeType.Polygon &&
                header.ShapeType != ShapeType.PolygonM &&
                header.ShapeType != ShapeType.PolygonZ)
            {
                throw new ArgumentException(DataStrings.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);

            // TO DO: replace with a normal reader.  We no longer need Buffered Binary reader as
            // the buffer can be set on the underlying file stream.
            BufferedBinaryReader bbReader = new 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[] allBounds = new byte[numShapes * 32];

            // probably all will be in one block, but use a byteBlock just in case.
            ByteBlock allParts  = new ByteBlock(BLOCKSIZE);
            ByteBlock allCoords = new ByteBlock(BLOCKSIZE);
            bool      isM       = (header.ShapeType == ShapeType.PolygonM || header.ShapeType == ShapeType.PolygonZ);
            bool      isZ       = (header.ShapeType == ShapeType.PolygonZ);
            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(FeatureType.Polygon); //------------------------------------
                shape.RecordNumber  = bbReader.ReadInt32(false);        // Byte 0   Record Integer   1     Big
                shape.ContentLength = bbReader.ReadInt32(false);        // Byte 4   Length Integer   1     Big

                // Setting shape type also controls extent class type.
                shape.ShapeType  = (ShapeType)bbReader.ReadInt32();     // Byte 8   Type   Integer   1     Little
                shape.StartIndex = pointOffset;
                if (shape.ShapeType == ShapeType.NullShape)
                {
                    continue;
                }
                shape.Extent.MinX = bbReader.ReadDouble();
                shape.Extent.MinY = bbReader.ReadDouble();
                shape.Extent.MaxX = bbReader.ReadDouble();
                shape.Extent.MaxY = bbReader.ReadDouble();
                shape.NumParts    = bbReader.ReadInt32();               // Byte 44  #Parts  Integer  1    Little
                shape.NumPoints   = bbReader.ReadInt32();               // Byte 48  #Points Integer  1    Little
                partOffsets[shp]  = allParts.IntOffset();
                allParts.Read(shape.NumParts * 4, bbReader);
                allCoords.Read(shape.NumPoints * 16, bbReader);
                pointOffset += shape.NumPoints;

                if (header.ShapeType == ShapeType.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)
                    {
                        IExtentM mExt = (IExtentM)shape.Extent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = bbReader.ReadDouble();

                        if (allM != null)
                        {
                            allM.Read(shape.NumPoints * 8, bbReader);
                        }
                    }
                }

                if (header.ShapeType == ShapeType.PolygonZ)
                {
                    bool     hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                    IExtentZ zExt = (IExtentZ)shape.Extent;
                    zExt.MinZ = bbReader.ReadDouble();
                    zExt.MaxZ = 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)
                    {
                        IExtentM mExt = (IExtentM)shape.Extent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = 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", shapes.Count);
            for (int shp = 0; shp < shapes.Count; 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], FeatureType.Polygon);
                    partR.NumVertices = count;
                    shape.Parts.Add(partR);
                }
                ProgressMeter.CurrentValue = shp;
            }
            ProgressMeter.Reset();
        }
Exemple #4
0
        /// <summary>
        /// Without changing the feature type or anything else, simply update the local coordinates
        /// to include the new coordinates.  All the new coordinates will be considered one part.
        /// Since point and multi-point shapes don't have parts, they will just be appended to the
        /// original part.
        /// </summary>
        public void AddPart(IEnumerable<Coordinate> coordinates, CoordinateType coordType)
        {
            bool hasM = (coordType == CoordinateType.M || coordType == CoordinateType.Z);
            bool hasZ = (coordType == CoordinateType.Z);
            List<double> vertices = new List<double>();
            List<double> z = new List<double>();
            List<double> m = new List<double>();
            int numPoints = 0;
            int oldNumPoints = (_vertices != null) ? _vertices.Length / 2 : 0;
            foreach (Coordinate coordinate in coordinates)
            {
                if (_shapeRange.Extent == null) _shapeRange.Extent = new Extent();
                _shapeRange.Extent.ExpandToInclude(coordinate.X, coordinate.Y);
                vertices.Add(coordinate.X);
                vertices.Add(coordinate.Y);
                if (hasM) m.Add(coordinate.M);
                if (hasZ) z.Add(coordinate.Z);
                numPoints++;
            }
            // Using public accessor also updates individual part references
            Vertices = (_vertices != null) ? _vertices.Concat(vertices).ToArray() : vertices.ToArray();
            if (hasZ) _z = (_z != null) ? _z.Concat(z).ToArray() : z.ToArray();
            if (hasM) _m = (_m != null) ? _m.Concat(m).ToArray() : m.ToArray();

            if (_shapeRange.FeatureType == FeatureType.MultiPoint || _shapeRange.FeatureType == FeatureType.Point)
            {
                // Only one part exists
                _shapeRange.Parts[0].NumVertices += numPoints;
            }
            else
            {
                PartRange part = new PartRange(_vertices, _shapeRange.StartIndex, oldNumPoints, _shapeRange.FeatureType);
                part.NumVertices = numPoints;
                _shapeRange.Parts.Add(part);
            }
        }
Exemple #5
0
        /// <summary>
        /// Creates a clockwise polygon shape from an envelope
        /// </summary>
        /// <param name="envelope"></param>
        public Shape(IEnvelope envelope)
        {
            if (Equals(envelope, null))
                throw new ArgumentNullException("envelope");

            _shapeRange = new ShapeRange(FeatureType.Polygon);
            _vertices = new double[8];
            double xMin = envelope.Minimum.X;
            double yMin = envelope.Minimum.Y;
            double xMax = envelope.Maximum.X;
            double yMax = envelope.Maximum.Y;
            _vertices[0] = xMin;
            _vertices[1] = yMax;
            _vertices[2] = xMax;
            _vertices[3] = yMax;
            _vertices[4] = xMax;
            _vertices[5] = yMin;
            _vertices[6] = xMin;
            _vertices[7] = yMin;
            const int offset = 0;
            PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Polygon);
            part.NumVertices = 4;
            _shapeRange.Parts.Add(part);
        }
Exemple #6
0
 /// <summary>
 /// Creates a point shape from a vertex
 /// </summary>
 /// <param name="coord"></param>
 public Shape(Vertex coord)
 {
     _shapeRange = new ShapeRange(FeatureType.Point);
     _vertices = new double[2];
     _vertices[0] = coord.X;
     _vertices[1] = coord.Y;
     const int offset = 0;
     PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Point);
     part.NumVertices = 1;
     _shapeRange.Parts.Add(part);
     _shapeRange.Extent = new Extent(coord.X, coord.Y, coord.X, coord.Y);
 }
Exemple #7
0
        /// <summary>
        /// For each coordinate in the other part, if it falls in the extent of this polygon, a
        /// ray crossing test is used for point in polygon testing.  If it is not in the extent,
        /// it is skipped.
        /// </summary>
        /// <param name="polygonShape">The part of the polygon to analyze polygon</param>
        /// <param name="otherPart">The other part</param>
        /// <returns>Boolean, true if any coordinate falls inside the polygon</returns>
        private static bool ContainsVertex(ShapeRange polygonShape, PartRange otherPart)
        {
            // Create an extent for faster checking in most cases
            Extent ext = polygonShape.Extent;

            foreach (Vertex point in otherPart)
            {
                // This extent check shortcut should help speed things up for large polygon parts
                if (!ext.Intersects(point)) continue;

                // Imagine a ray on the horizontal starting from point.X -> infinity.  (In practice this can be ext.XMax)
                // Count the intersections of segments with that line.  If the resulting count is odd, the point is inside.
                Segment ray = new Segment(point.X, point.Y, ext.MaxX, point.Y);
                int[] numCrosses = new int[polygonShape.NumParts]; // A cross is a complete cross.  Coincident doesn't count because it is either 0 or 2 crosses.
                int totalCrosses = 0;
                int iPart = 0;
                foreach (PartRange ring in polygonShape.Parts)
                {
                    foreach (Segment segment in ring.Segments)
                    {
                        if (segment.IntersectionCount(ray) != 1) continue;
                        numCrosses[iPart]++;
                        totalCrosses++;
                    }
                    iPart++;
                }

                // If we didn't actually have any polygons we cant intersect with anything
                if (polygonShape.NumParts < 1) return false;

                // For shapes with only one part, we don't need to test part-containment.
                if (polygonShape.NumParts == 1 && totalCrosses % 2 == 1) return true;

                // This used to check to see if totalCrosses == 1, but now checks to see if totalCrosses is an odd number.
                // This change was made to solve the issue described in HD Issue 8593 (http://hydrodesktop.codeplex.com/workitem/8593).
                if (totalCrosses % 2 == 1) return true;

                totalCrosses = 0;
                for (iPart = 0; iPart < numCrosses.Length; iPart++)
                {
                    int count = numCrosses[iPart];
                    // If this part does not contain the point, don't bother trying to figure out if the part is a hole or not.
                    if (count % 2 == 0) continue;

                    // If this particular part is a hole, subtract the total crosses by 1,  otherwise add one.
                    // This takes time, so we want to do this as few times as possible.
                    if (polygonShape.Parts[iPart].IsHole())
                    {
                        totalCrosses--;
                    }
                    else
                    {
                        totalCrosses++;
                    }
                }
                return totalCrosses > 0;
            }
            return false;
        }
        /// <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;
        }
        // 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(DataStrings.ArgumentNull_S.Replace("%S", fileName));
            }

            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException(DataStrings.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 != ShapeType.MultiPoint &&
                 header.ShapeType != ShapeType.MultiPointM &&
                 header.ShapeType != ShapeType.MultiPointZ)
            {
                throw new ArgumentException(DataStrings.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.
            BufferedBinaryReader bbReader = new 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 == ShapeType.MultiPointZ || header.ShapeType == ShapeType.MultiPointM);
            bool isZ = (header.ShapeType == ShapeType.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(FeatureType.MultiPoint)
                                   {
                                       RecordNumber = bbReader.ReadInt32(false),
                                       ContentLength = bbReader.ReadInt32(false),
                                       ShapeType = (ShapeType)bbReader.ReadInt32(),
                                       StartIndex = pointOffset
                                   };

                //bbReader.Read(bigEndians, shp * 8, 8);
                if (shape.ShapeType == ShapeType.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 == ShapeType.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)
                    {
                        IExtentM mExt = (IExtentM)MyExtent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = bbReader.ReadDouble();
                        if (allM != null) allM.Read(shape.NumPoints * 8, bbReader);
                    }
                }
                if (header.ShapeType == ShapeType.MultiPointZ)
                {
                    bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                    IExtentZ zExt = (IExtentZ)MyExtent;
                    zExt.MinZ = bbReader.ReadDouble();
                    zExt.MaxZ = 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)
                    {
                        IExtentM mExt = (IExtentM)MyExtent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = 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, FeatureType.MultiPoint) { NumVertices = count };
                shape.Parts.Add(partR);
            }

            bbReader.Dispose();
        }
 private static Shape ReadLineString(Stream data)
 {
     Shape result = new Shape(FeatureType.Line);
     int count = ReadInt32(data);
     double[] coords = ReadDouble(data, 2 * count);
     PartRange lPrt = new PartRange(FeatureType.Line);
     lPrt.NumVertices = count;
     result.Range.Parts.Add(lPrt);
     result.Vertices = coords;
     return result;
 }
 private static void ReadMultiPoint(Stream data, FeatureSetPack results)
 {
     int count = ReadInt32(data);
     ShapeRange sr = new ShapeRange(FeatureType.MultiPoint);
     PartRange prt = new PartRange(FeatureType.MultiPoint);
     prt.NumVertices = count;
     sr.Parts.Add(prt);
     double[] vertices = new double[count * 2];
     for (int iPoint = 0; iPoint < count; iPoint++)
     {
         data.ReadByte(); // ignore endian
         ReadInt32(data); // ignore geometry type
         double[] coord = ReadDouble(data, 2);
         Array.Copy(coord, 0, vertices, iPoint * 2, 2);
     }
     results.Add(vertices, sr);
 }
 /// <summary>
 /// Reads one multipoint shape from a data stream.
 /// (this assumes that the two bytes (endian and type) have already been read.
 /// </summary>
 /// <param name="data"></param>
 /// <returns></returns>
 private static Shape ReadMultiPoint(Stream data)
 {
     Shape result = new Shape(FeatureType.MultiPoint);
     int count = ReadInt32(data);
     PartRange prt = new PartRange(FeatureType.MultiPoint);
     prt.NumVertices = count;
     result.Range.Parts.Add(prt);
     double[] vertices = new double[count * 2];
     for (int iPoint = 0; iPoint < count; iPoint++)
     {
         data.ReadByte(); // ignore endian
         ReadInt32(data); // ignore geometry type
         double[] coord = ReadDouble(data, 2);
         Array.Copy(coord, 0, vertices, iPoint * 2, 2);
     }
     result.Vertices = vertices;
     return result;
 }
 /// <summary>
 /// This assumes that the byte order and shapetype have already been read.
 /// </summary>
 /// <param name="data"></param>
 /// <param name="results"></param>
 private static void ReadPoint(Stream data, FeatureSetPack results)
 {
     ShapeRange sr = new ShapeRange(FeatureType.MultiPoint);
     PartRange prt = new PartRange(FeatureType.MultiPoint);
     prt.NumVertices = 1;
     sr.Parts.Add(prt);
     double[] coord = ReadDouble(data, 2);
     results.Add(coord, sr);
 }
 /// <summary>
 /// This assumes that the byte order and shapetype have already been read.
 /// </summary>
 /// <param name="data"></param>
 public static Shape ReadPoint(Stream data)
 {
     Shape result = new Shape();
     result.Range = new ShapeRange(FeatureType.Point);
     PartRange prt = new PartRange(FeatureType.Point);
     prt.NumVertices = 1;
     result.Range.Parts.Add(prt);
     result.Vertices = ReadDouble(data, 2);
     return result;
 }
        /// <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(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);

            MyExtent = 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));
            }

            // 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.
            BufferedBinaryReader bbReader = new 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 == ShapeType.PointM || header.ShapeType == ShapeType.PointZ)
            {
                isM = true;
            }
            if (header.ShapeType == ShapeType.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);
                bbReader.ReadInt32(); // Skip ShapeType.  Null shapes may break this.
                //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(FeatureType.Point)
                {
                    StartIndex    = shp,
                    ContentLength = 8,
                    NumPoints     = 1,
                    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, FeatureType.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();
        }
        // 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(DataStrings.ArgumentNull_S.Replace("%S", fileName));
            }

            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException(DataStrings.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 != ShapeType.Polygon &&
                 header.ShapeType != ShapeType.PolygonM &&
                 header.ShapeType != ShapeType.PolygonZ)
            {
                throw new ArgumentException(DataStrings.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);

            // TO DO: replace with a normal reader.  We no longer need Buffered Binary reader as
            // the buffer can be set on the underlying file stream.
            BufferedBinaryReader bbReader = new 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[] allBounds = new byte[numShapes * 32];

            // probably all will be in one block, but use a byteBlock just in case.
            ByteBlock allParts = new ByteBlock(BLOCKSIZE);
            ByteBlock allCoords = new ByteBlock(BLOCKSIZE);
            bool isM = (header.ShapeType == ShapeType.PolygonM || header.ShapeType == ShapeType.PolygonZ);
            bool isZ = (header.ShapeType == ShapeType.PolygonZ);
            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(FeatureType.Polygon); //------------------------------------
                shape.RecordNumber = bbReader.ReadInt32(false);         // Byte 0   Record Integer   1     Big
                shape.ContentLength = bbReader.ReadInt32(false);        // Byte 4   Length Integer   1     Big

                // Setting shape type also controls extent class type.
                shape.ShapeType = (ShapeType)bbReader.ReadInt32();      // Byte 8   Type   Integer   1     Little
                shape.StartIndex = pointOffset;
                if (shape.ShapeType == ShapeType.NullShape)
                {
                    continue;
                }
                shape.Extent.MinX = bbReader.ReadDouble();
                shape.Extent.MinY = bbReader.ReadDouble();
                shape.Extent.MaxX = bbReader.ReadDouble();
                shape.Extent.MaxY = bbReader.ReadDouble();
                shape.NumParts = bbReader.ReadInt32();                  // Byte 44  #Parts  Integer  1    Little
                shape.NumPoints = bbReader.ReadInt32();                 // Byte 48  #Points Integer  1    Little
                partOffsets[shp] = allParts.IntOffset();
                allParts.Read(shape.NumParts * 4, bbReader);
                allCoords.Read(shape.NumPoints * 16, bbReader);
                pointOffset += shape.NumPoints;

                if (header.ShapeType == ShapeType.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)
                    {
                        IExtentM mExt = (IExtentM)shape.Extent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = bbReader.ReadDouble();

                        if (allM != null) allM.Read(shape.NumPoints * 8, bbReader);
                    }
                }

                if (header.ShapeType == ShapeType.PolygonZ)
                {
                    bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                    IExtentZ zExt = (IExtentZ)shape.Extent;
                    zExt.MinZ = bbReader.ReadDouble();
                    zExt.MaxZ = 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)
                    {
                        IExtentM mExt = (IExtentM)shape.Extent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = 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", shapes.Count);
            for (int shp = 0; shp < shapes.Count; 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], FeatureType.Polygon);
                    partR.NumVertices = count;
                    shape.Parts.Add(partR);
                }
                ProgressMeter.CurrentValue = shp;
            }
            ProgressMeter.Reset();
        }
Exemple #17
0
        /// <summary>
        /// Loads the shapes from the given file into the given shapefile.
        /// </summary>
        /// <param name="fileName">Name of the file whose shapes should get loaded.</param>
        /// <param name="progressHandler">ProgressHandler that shows the progress.</param>
        /// <param name="shapefile">Shapefile the shapes are loaded into.</param>
        /// <param name="featureType">FeatureType that should be inside the file.</param>
        /// <exception cref="ArgumentNullException">Throws an ArgumentNullException, if the shapefile is null.</exception>
        /// <exception cref="ArgumentException">Throws an ArgumentException, if the FeatureType is Line but the files doesn't contain lines or the FeatureType is Polygon and the file doesn't contain polygons.</exception>
        /// <exception cref="NotSupportedException">Throws a NotSupportedException, if a FeatureType other than Line or Polygon is passed.</exception>
        /// <exception cref="FileNotFoundException">Throws a FileNotFoundException, if the file whith the path from fileName doesn't exist.</exception>
        /// <exception cref="NullReferenceException">Throws a NullReferenceException, if the fileName is null.</exception>
        internal static void FillLines(string fileName, IProgressHandler progressHandler, Shapefile shapefile, FeatureType featureType)
        {
            // Check to ensure that the fileName is the correct shape type
            switch (featureType)
            {
            case FeatureType.Line:
                if (!CanBeRead(fileName, shapefile, ShapeType.PolyLine, ShapeType.PolyLineM, ShapeType.PolyLineZ))
                {
                    return;
                }

                break;

            case FeatureType.Polygon:
                if (!CanBeRead(fileName, shapefile, ShapeType.Polygon, ShapeType.PolygonM, ShapeType.PolygonZ))
                {
                    return;
                }
                break;

            default:
                throw new NotSupportedException(DataStrings.ShapeType0NotSupported);
            }

            // Reading the headers gives us an easier way to track the number of shapes and their overall length etc.
            var  header = shapefile.Header;
            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, "The shapes record number should equal" + 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 (Record Number, Content Length, Shapetype + BoundingBox + NumParts, NumPoints)

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

                    // Read points
                    var pointsBytes = reader.ReadBytes(8 * 2 * shape.NumPoints); // Numpoints * Point (X(8) + Y(8))
                    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();
        }
 private static void ReadLineString(Stream data, FeatureSetPack results)
 {
     int count = ReadInt32(data);
     double[] coords = ReadDouble(data, 2 * count);
     ShapeRange lShp = new ShapeRange(FeatureType.Line);
     PartRange lPrt = new PartRange(FeatureType.Line);
     lPrt.NumVertices = count;
     lShp.Parts.Add(lPrt);
     results.Add(coords, lShp);
 }
Exemple #19
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();
        }
 private static void ReadMultiLineString(Stream data, FeatureSetPack results)
 {
     int numLineStrings = ReadInt32(data);
     ShapeRange shp = new ShapeRange(FeatureType.Line);
     List<double[]> strings = new List<double[]>();
     int partOffset = 0;
     for (int iString = 0; iString < numLineStrings; iString++)
     {
         // Each of these needs to read a full WKBLineString
         data.Seek(5, SeekOrigin.Current); //ignore header
         int numPoints = ReadInt32(data);
         double[] coords = ReadDouble(data, 2 * numPoints);
         PartRange lPrt = new PartRange(FeatureType.Line);
         lPrt.PartOffset = partOffset;
         lPrt.NumVertices = numPoints;
         shp.Parts.Add(lPrt);
         partOffset += coords.Length / 2;
         strings.Add(coords);
     }
     double[] allVertices = new double[partOffset * 2];
     int offset = 0;
     foreach (double[] ring in strings)
     {
         Array.Copy(ring, 0, allVertices, offset, ring.Length);
         offset += ring.Length;
     }
     results.Add(allVertices, shp);
 }
Exemple #21
0
        // 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(DataStrings.ArgumentNull_S.Replace("%S", "fileName"));
            }

            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException(DataStrings.FileNotFound_S.Replace("%S", 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.MultiPoint &&
                header.ShapeType != ShapeType.MultiPointM &&
                header.ShapeType != ShapeType.MultiPointZ)
            {
                throw new ArgumentException(DataStrings.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.
            BufferedBinaryReader bbReader = new 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 == ShapeType.MultiPointZ || header.ShapeType == ShapeType.MultiPointM);
            bool      isZ       = (header.ShapeType == ShapeType.MultiPointZ);
            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(FeatureType.MultiPoint)
                {
                    RecordNumber  = bbReader.ReadInt32(false),
                    ContentLength = bbReader.ReadInt32(false),
                    ShapeType     = (ShapeType)bbReader.ReadInt32(),
                    StartIndex    = pointOffset
                };

                //bbReader.Read(bigEndians, shp * 8, 8);
                if (shape.ShapeType == ShapeType.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 == ShapeType.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)
                    {
                        IExtentM mExt = (IExtentM)MyExtent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = bbReader.ReadDouble();
                        if (allM != null)
                        {
                            allM.Read(shape.NumPoints * 8, bbReader);
                        }
                    }
                }
                if (header.ShapeType == ShapeType.MultiPointZ)
                {
                    bool     hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                    IExtentZ zExt = (IExtentZ)MyExtent;
                    zExt.MinZ = bbReader.ReadDouble();
                    zExt.MaxZ = 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)
                    {
                        IExtentM mExt = (IExtentM)MyExtent;
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = 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, FeatureType.MultiPoint)
                {
                    NumVertices = count
                };
                shape.Parts.Add(partR);
            }

            bbReader.Dispose();
        }
 private static Shape ReadPolygon(Stream data)
 {
     Shape result = new Shape(FeatureType.Polygon);
     int numRings = ReadInt32(data);
     List<double[]> rings = new List<double[]>();
     int partOffset = 0;
     for (int iRing = 0; iRing < numRings; iRing++)
     {
         int numPoints = ReadInt32(data); // ring structures are like a linestring without the final point.
         double[] coords = ReadDouble(data, 2 * numPoints);
         if (iRing == 0)
         {
             // By shapefile standard, the shell should be clockwise
             if (IsCounterClockwise(coords))
                 coords = ReverseCoords(coords);
         }
         else
         {
             // By shapefile standard, the holes should be counter clockwise.
             if (!IsCounterClockwise(coords))
                 coords = ReverseCoords(coords);
         }
         PartRange lPrt = new PartRange(FeatureType.Polygon);
         lPrt.PartOffset = partOffset;
         lPrt.NumVertices = numPoints;
         result.Range.Parts.Add(lPrt);
         partOffset += coords.Length / 2;
         rings.Add(coords);
     }
     double[] allVertices = new double[partOffset * 2];
     int offset = 0;
     foreach (double[] ring in rings)
     {
         Array.Copy(ring, 0, allVertices, offset, ring.Length);
         offset += ring.Length;
     }
     result.Vertices = allVertices;
     return result;
 }
Exemple #23
0
        /// <summary>
        /// Creates a point shape from a coordinate
        /// </summary>
        /// <param name="coord"></param>
        public Shape(Coordinate coord)
        {
            if (Equals(coord, null))
                throw new ArgumentNullException("coord");

            _shapeRange = new ShapeRange(FeatureType.Point);
            _vertices = new double[2];
            _vertices[0] = coord.X;
            _vertices[1] = coord.Y;
            if (!double.IsNaN(coord.Z))
            {
                _z = new double[1];
                _z[0] = coord.Z;
            }
            if (!double.IsNaN(coord.M))
            {
                _z = new double[1];
                _m[0] = coord.M;
            }
            const int offset = 0;
            PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Point);
            part.NumVertices = 1;
            _shapeRange.Parts.Add(part);
            _shapeRange.Extent = new Extent(coord.X, coord.Y, coord.X, coord.Y);
        }
        private static void ReadMultiPolygon(Stream data, FeatureSetPack results)
        {
            int numPolygons = ReadInt32(data);
            ShapeRange lShp = new ShapeRange(FeatureType.Polygon);
            List<double[]> rings = new List<double[]>();
            int partOffset = 0;
            for (int iPoly = 0; iPoly < numPolygons; iPoly++)
            {
                data.Seek(5, SeekOrigin.Current); // endian and geometry type
                int numRings = ReadInt32(data);
                for (int iRing = 0; iRing < numRings; iRing++)
                {
                    int numPoints = ReadInt32(data); // ring structures are like a linestring without the final point.
                    double[] coords = ReadDouble(data, 2 * numPoints);
                    if (iRing == 0)
                    {
                        // By shapefile standard, the shell should be clockwise
                        if (IsCounterClockwise(coords))
                            coords = ReverseCoords(coords);
                    }
                    else
                    {
                        // By shapefile standard, the holes should be counter clockwise.
                        if (!IsCounterClockwise(coords))
                            coords = ReverseCoords(coords);
                    }
                    PartRange lPrt = new PartRange(FeatureType.Polygon);
                    lPrt.PartOffset = partOffset;
                    lPrt.NumVertices = numPoints;
                    lShp.Parts.Add(lPrt);
                    partOffset += coords.Length / 2;
                    rings.Add(coords);
                }
            }

            double[] allVertices = new double[partOffset * 2];
            int offset = 0;
            foreach (double[] ring in rings)
            {
                Array.Copy(ring, 0, allVertices, offset, ring.Length);
                offset += ring.Length;
            }
            results.Add(allVertices, lShp);
        }
Exemple #25
0
        /// <summary>
        /// Creates a clockwise polygon shape from an extent
        /// </summary>
        /// <param name="extent"></param>
        public Shape(Extent extent)
        {
            if (Equals(extent, null))
                throw new ArgumentNullException("extent");

            _shapeRange = new ShapeRange(FeatureType.Polygon);
            _vertices = new double[8];
            double xMin = extent.MinX;
            double yMin = extent.MinY;
            double xMax = extent.MaxX;
            double yMax = extent.MaxY;
            _vertices[0] = xMin;
            _vertices[1] = yMax;
            _vertices[2] = xMax;
            _vertices[3] = yMax;
            _vertices[4] = xMax;
            _vertices[5] = yMin;
            _vertices[6] = xMin;
            _vertices[7] = yMin;
            const int offset = 0;
            PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Polygon);
            part.NumVertices = 4;
            _shapeRange.Parts.Add(part);
        }
Exemple #26
0
        /// <summary>
        /// For each coordinate in the other part, if it falls in the extent of this polygon, a
        /// ray crossing test is used for point in polygon testing.  If it is not in the extent,
        /// it is skipped.
        /// </summary>
        /// <param name="polygonShape">The part of the polygon to analyze polygon</param>
        /// <param name="otherPart">The other part</param>
        /// <returns>Boolean, true if any coordinate falls inside the polygon</returns>
        private static bool ContainsVertex(ShapeRange polygonShape, PartRange otherPart)
        {
            // Create an extent for faster checking in most cases
            Extent ext = polygonShape.Extent;

            foreach (Vertex point in otherPart)
            {
                // This extent check shortcut should help speed things up for large polygon parts
                if (!ext.Intersects(point))
                {
                    continue;
                }

                // Imagine a ray on the horizontal starting from point.X -> infinity.  (In practice this can be ext.XMax)
                // Count the intersections of segments with that line.  If the resulting count is odd, the point is inside.
                Segment ray          = new Segment(point.X, point.Y, ext.MaxX, point.Y);
                int[]   numCrosses   = new int[polygonShape.NumParts]; // A cross is a complete cross.  Coincident doesn't count because it is either 0 or 2 crosses.
                int     totalCrosses = 0;
                int     iPart        = 0;
                foreach (PartRange ring in polygonShape.Parts)
                {
                    foreach (Segment segment in ring.Segments)
                    {
                        if (segment.IntersectionCount(ray) != 1)
                        {
                            continue;
                        }
                        numCrosses[iPart]++;
                        totalCrosses++;
                    }
                    iPart++;
                }

                // If we didn't actually have any polygons we cant intersect with anything
                if (polygonShape.NumParts < 1)
                {
                    return(false);
                }

                // For shapes with only one part, we don't need to test part-containment.
                if (polygonShape.NumParts == 1 && totalCrosses % 2 == 1)
                {
                    return(true);
                }

                // This used to check to see if totalCrosses == 1, but now checks to see if totalCrosses is an odd number.
                // This change was made to solve the issue described in HD Issue 8593 (http://hydrodesktop.codeplex.com/workitem/8593).
                if (totalCrosses % 2 == 1)
                {
                    return(true);
                }

                totalCrosses = 0;
                for (iPart = 0; iPart < numCrosses.Length; iPart++)
                {
                    int count = numCrosses[iPart];
                    // If this part does not contain the point, don't bother trying to figure out if the part is a hole or not.
                    if (count % 2 == 0)
                    {
                        continue;
                    }

                    // If this particular part is a hole, subtract the total crosses by 1,  otherwise add one.
                    // This takes time, so we want to do this as few times as possible.
                    if (polygonShape.Parts[iPart].IsHole())
                    {
                        totalCrosses--;
                    }
                    else
                    {
                        totalCrosses++;
                    }
                }
                return(totalCrosses > 0);
            }
            return(false);
        }
Exemple #27
0
        /// <summary>
        /// Create a ShapeRange from a Geometry to use in constructing a Shape
        /// </summary>
        /// <param name="geometry"></param>
        /// <param name="vertices"></param>
        /// <param name="offset">offset into vertices array where this feature starts</param>
        /// <returns></returns>
        public static ShapeRange ShapeRangeFromGeometry(IBasicGeometry geometry, double[] vertices, int offset)
        {
            var featureType = geometry.FeatureType;
            ShapeRange shx = new ShapeRange(featureType) { Extent = new Extent(geometry.Envelope) };
            int vIndex = offset / 2;
            shx.Parts = new List<PartRange>();
            int shapeStart = vIndex;
            for (int part = 0; part < geometry.NumGeometries; part++)
            {
                PartRange prtx = new PartRange(vertices, shapeStart, vIndex - shapeStart, featureType);
                IBasicPolygon bp = geometry.GetBasicGeometryN(part) as IBasicPolygon;
                if (bp != null)
                {
                    // Account for the Shell
                    prtx.NumVertices = bp.Shell.NumPoints;

                    vIndex += bp.Shell.NumPoints;

                    // The part range should be adjusted to no longer include the holes
                    foreach (var hole in bp.Holes)
                    {
                        PartRange holex = new PartRange(vertices, shapeStart, vIndex - shapeStart, featureType)
                        {
                            NumVertices = hole.NumPoints
                        };
                        shx.Parts.Add(holex);
                        vIndex += hole.NumPoints;
                    }
                }
                else
                {
                    int numPoints = geometry.GetBasicGeometryN(part).NumPoints;

                    // This is not a polygon, so just add the number of points.
                    vIndex += numPoints;
                    prtx.NumVertices = numPoints;
                }

                shx.Parts.Add(prtx);
            }
            return shx;
        }
Exemple #28
0
        protected override Shape ReadShape(int shp, Stream reader)
        {
            int pointsNum = 0, numParts = 0;
            double xmin = 0, ymin = 0, xmax = 0, ymax = 0, zmin = 0, zmax = 0, mmin = 0, mmax = 0;
            double[] vert = null, m = null, z = null;
            int[] parts = null;

            var shapeHeaders = ShapeHeaders;
            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();
            if (shapeType == ShapeType.NullShape) goto fin;

            var byteLen = 4; // from shapeType read

            // Read bounding box
            xmin = reader.ReadDouble(); byteLen += 8;
            ymin = reader.ReadDouble(); byteLen += 8;
            xmax = reader.ReadDouble(); byteLen += 8;
            ymax = reader.ReadDouble(); byteLen += 8;

            // The number of parts in the PolyLine.
            numParts = reader.ReadInt32(); byteLen += 4;

            // The total number of points for all parts.
            pointsNum = reader.ReadInt32(); byteLen += 4;

            // Initialize arrays
            vert = new double[2 * pointsNum]; // X, Y
            parts = new int[numParts];
            if (CoordinateType == CoordinateType.M || CoordinateType == CoordinateType.Z)
            {
                m = Enumerable.Repeat(double.MinValue, pointsNum).ToArray();
            }
            if (CoordinateType == CoordinateType.Z)
            {
                z = new double[pointsNum];
            }

            var partsBytes = reader.ReadBytes(4 * numParts); byteLen += 4*numParts;
            Buffer.BlockCopy(partsBytes, 0, parts, 0, partsBytes.Length);

            var pointsBytes = reader.ReadBytes(8 * 2 * pointsNum); byteLen += 8*2*pointsNum;
            Buffer.BlockCopy(pointsBytes, 0, vert, 0, pointsBytes.Length);

            // Read Z
            if (z != null)
            {
                zmin = reader.ReadDouble(); byteLen += 8;
                zmax = reader.ReadDouble(); byteLen += 8;

                for (var i = 0; i < pointsNum; i++)
                {
                    z[i] = reader.ReadDouble(); byteLen += 8;
                }
            }

            // Read M
            if (m != null)
            {
                if (byteLen + 2 * 8 + pointsNum * 8 == shapeHeaders[shp].ByteLength) // mmin, mmax and pointsNum doubles
                {
                    mmin = reader.ReadDouble(); byteLen += 8;
                    mmax = reader.ReadDouble(); byteLen += 8;

                    for (var i = 0; i < pointsNum; i++)
                    {
                        m[i] = reader.ReadDouble(); byteLen += 8;
                    }
                }
            }

        fin:

            var shr = new ShapeRange(FeatureType)
            {
                RecordNumber = recordNumber,
                StartIndex = 0,
                ContentLength = shapeHeaders[shp].ContentLength,
                NumPoints = pointsNum,
                Extent = new Extent(xmin, ymin, xmax, ymax),
                ShapeType = shapeType,
            };
            if (vert != null)
            {
                for (var i = 0; i < numParts; i++)
                {
                    var numVertices = i == numParts - 1
                        ? vert.Length/2 - parts[i]
                        : parts[i + 1] - parts[i];
                    var partRange = new PartRange(vert, 0, parts[i], FeatureType) { NumVertices = numVertices };
                    shr.Parts.Add(partRange);    
                }
            }
            return new Shape(FeatureType)
            {
                Range = shr,
                M = m,
                Z = z,
                Vertices = vert,
                MaxM = mmax,
                MinM = mmin,
                MaxZ = zmax,
                MinZ = zmin
            };
        }
        /// <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(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);
            MyExtent = 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));
            }

            // 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.
            BufferedBinaryReader bbReader = new 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 == ShapeType.PointM || header.ShapeType == ShapeType.PointZ)
            {
                isM = true;
            }
            if (header.ShapeType == ShapeType.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);
                bbReader.ReadInt32(); // Skip ShapeType.  Null shapes may break this.
                //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(FeatureType.Point)
                                   {
                                       StartIndex = shp,
                                       ContentLength = 8,
                                       NumPoints = 1,
                                       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, FeatureType.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();
        }
Exemple #30
0
        // X Y MultiPoints
        // ---------------------------------------------------------
        // 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 44      NumPoints           Integer     1           Little
        // Byte 48      Points              Point       NumPoints   Little

        // X Y M MultiPoints
        // ---------------------------------------------------------
        // 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 (Xmin - Ymax)   Double      4           Little
        // Byte 44      NumPoints           Integer     1           Little
        // Byte 48      Points              Point       NumPoints   Little
        // Byte X*      Mmin                Double      1           Little
        // Byte X+8*    Mmax                Double      1           Little
        // Byte X+16*   Marray              Double      NumPoints   Little
        // X = 48 + (16 * NumPoints)
        // * = optional

        // X Y Z M MultiPoints
        // ---------------------------------------------------------
        // 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 48      Points              Point       NumPoints   Little
        // Byte X       Zmin                Double      1           Little
        // Byte X+8     Zmax                Double      1           Little
        // Byte X+16    Zarray              Double      NumPoints   Little
        // Byte Y*      Mmin                Double      1           Little
        // Byte Y+8*    Mmax                Double      1           Little
        // Byte Y+16*   Marray              Double      NumPoints   Little
        // X = 48 + (16 * NumPoints)
        // Y = X + 16 + (8 * NumPoints)
        // * = optional

        /// <summary>
        /// Obtains a typed list of MultiPoint structures with double values associated with the various coordinates.
        /// </summary>
        /// <param name="fileName">Name of the file that gets loaded.</param>
        /// <param name="progressHandler">Progress handler</param>
        private void FillPoints(string fileName, IProgressHandler progressHandler)
        {
            // Check whether file is empty or not all parameters are set correctly.
            if (!CanBeRead(fileName, this, ShapeType.MultiPoint, ShapeType.MultiPointM, ShapeType.MultiPointZ))
            {
                return;
            }

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

            bool isM = Header.ShapeType == ShapeType.MultiPointZ || Header.ShapeType == ShapeType.MultiPointM;
            bool isZ = Header.ShapeType == ShapeType.MultiPointZ;

            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.MultiPoint, CoordinateType)
                    {
                        RecordNumber  = reader.ReadInt32(Endian.BigEndian),
                        ContentLength = reader.ReadInt32(Endian.BigEndian),
                        ShapeType     = (ShapeType)reader.ReadInt32(),
                        StartIndex    = totalPointsCount,
                        NumParts      = 1
                    };
                    Debug.Assert(shape.RecordNumber == shp + 1, "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
                        totalPartsCount += 1;

                        // 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];

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

                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 + 4, SeekOrigin.Current); // Skip first bytes (Record Number, Content Length, Shapetype + BoundingBox + NumPoints)

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

                    // Fill parts
                    shape.Parts.Capacity = shape.NumParts;
                    for (int p = 0; p < shape.NumParts; p++)
                    {
                        int endIndex   = shape.NumPoints + shape.StartIndex;
                        int startIndex = parts[partsOffset + p] + shape.StartIndex;
                        if (p < shape.NumParts - 1)
                        {
                            endIndex = parts[partsOffset + p + 1] + shape.StartIndex;
                        }

                        int count = endIndex - startIndex;
                        var part  = new PartRange(vert, shape.StartIndex, parts[partsOffset + p], FeatureType.MultiPoint)
                        {
                            NumVertices = count
                        };
                        shape.Parts.Add(part);
                    }

                    partsOffset += shape.NumParts;

                    // Fill M and Z arrays
                    switch (Header.ShapeType)
                    {
                    case ShapeType.MultiPointM:
                        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.MultiPointZ:
                        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.MultiPointM;
                        }

                        break;
                    }
                }

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

            progressMeter.Reset();
        }
Exemple #31
0
        // X Y Points: 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 1        Integer     1           Little
        // Byte 12      X                   Double      1           Little
        // Byte 20      Y                   Double      1           Little

        // X Y M Points: Total Length = 36 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 21       Integer     1           Little
        // Byte 12      X                   Double      1           Little
        // Byte 20      Y                   Double      1           Little
        // Byte 28      M                   Double      1           Little

        // X Y Z M Points: 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 11       Integer     1           Little
        // Byte 12      X                   Double      1           Little
        // Byte 20      Y                   Double      1           Little
        // Byte 28      Z                   Double      1           Little
        // Byte 36      M                   Double      1           Little

        /// <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">Progress handler</param>
        private void FillPoints(string fileName, IProgressHandler progressHandler)
        {
            if (!CanBeRead(fileName, this, ShapeType.Point, ShapeType.PointM, ShapeType.PointZ))
            {
                return;
            }

            // Reading the headers gives us an easier way to track the number of shapes and their overall length etc.
            List <ShapeHeader> shapeHeaders = ReadIndexFile(fileName);
            var numShapes        = shapeHeaders.Count;
            var shapeIndices     = new List <ShapeRange>(numShapes);
            int totalPointsCount = 0;

            var progressMeter = new ProgressMeter(progressHandler, "Reading from " + Path.GetFileName(fileName))
            {
                StepPercent = 5
            };

            using (var reader = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                for (var shp = 0; shp < numShapes; shp++)
                {
                    progressMeter.CurrentPercent = (int)(shp * 50.0 / numShapes);

                    reader.Seek(shapeHeaders[shp].ByteOffset, SeekOrigin.Begin);

                    var shape = new ShapeRange(FeatureType.Point, CoordinateType)
                    {
                        RecordNumber  = reader.ReadInt32(Endian.BigEndian),
                        ContentLength = reader.ReadInt32(Endian.BigEndian),
                        StartIndex    = totalPointsCount,
                        ShapeType     = (ShapeType)reader.ReadInt32()
                    };

                    Debug.Assert(shape.RecordNumber == shp + 1, "The record number should equal " + shp + 1);
                    Debug.Assert(shape.ContentLength == shapeHeaders[shp].ContentLength, "The shapes content length should equals the shapeHeaders content length.");

                    if (shape.ShapeType == ShapeType.NullShape)
                    {
                        shape.NumPoints = 0;
                        shape.NumParts  = 0;
                    }
                    else
                    {
                        totalPointsCount += 1;
                        shape.NumPoints   = 1;
                        shape.NumParts    = 1;
                    }

                    shapeIndices.Add(shape);
                }

                double[] m    = null;
                double[] z    = null;
                var      vert = new double[2 * totalPointsCount]; // X,Y

                if (Header.ShapeType == ShapeType.PointM || Header.ShapeType == ShapeType.PointZ)
                {
                    m = new double[totalPointsCount];
                }

                if (Header.ShapeType == ShapeType.PointZ)
                {
                    z = new double[totalPointsCount];
                }

                int i = 0;
                for (var 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, SeekOrigin.Current); // Skip first bytes (Record Number, Content Length, Shapetype)

                    // Read X
                    var ind = 4;
                    vert[i * 2] = reader.ReadDouble();
                    ind        += 8;

                    // Read Y
                    vert[(i * 2) + 1] = reader.ReadDouble();
                    ind += 8;

                    // Read Z
                    if (z != null)
                    {
                        z[i] = reader.ReadDouble();
                        ind += 8;
                    }

                    // Read M
                    if (m != null)
                    {
                        if (shapeHeaders[shp].ByteLength <= ind)
                        {
                            m[i] = double.MinValue;
                        }
                        else
                        {
                            m[i] = reader.ReadDouble();
                        }
                    }

                    var part = new PartRange(vert, shape.StartIndex, 0, FeatureType.Point)
                    {
                        NumVertices = 1
                    };
                    shape.Parts.Add(part);
                    shape.Extent = new Extent(new[] { vert[i * 2], vert[(i * 2) + 1], vert[i * 2], vert[(i * 2) + 1] });
                    i++;
                }

                Vertex       = vert;
                M            = m;
                Z            = z;
                ShapeIndices = shapeIndices;
            }

            progressMeter.Reset();
        }
Exemple #32
0
        /// <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);
        }
        // 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 44      NumPoints           Integer     1           Little
        // Byte 48      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 (Xmin - Ymax)   Double      4           Little
        // Byte 44      NumPoints           Integer     1           Little
        // Byte 48      Points              Point       NumPoints   Little
        // Byte X*      Mmin                Double      1           Little
        // Byte X+8*    Mmax                Double      1           Little
        // Byte X+16*   Marray              Double      NumPoints   Little
        // X = 48 + (16 * NumPoints)
        // * = optional

        // 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 48      Points              Point       NumPoints   Little
        // Byte X       Zmin                Double      1           Little
        // Byte X+8     Zmax                Double      1           Little
        // Byte X+16    Zarray              Double      NumPoints   Little
        // Byte Y*      Mmin                Double      1           Little
        // Byte Y+8*    Mmax                Double      1           Little
        // Byte Y+16*   Marray              Double      NumPoints   Little
        // X = 48 + (16 * NumPoints)
        // Y = X + 16 + (8 * NumPoints)
        // * = optional
        private void FillPoints(string fileName, IProgressHandler progressHandler)
        {
            // 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));
            }

            // Get the basic header information.
            var header = this.Header;

            // Check to ensure that the fileName is the correct shape type
            if (header.ShapeType != ShapeType.MultiPoint &&
                header.ShapeType != ShapeType.MultiPointM &&
                header.ShapeType != ShapeType.MultiPointZ)
            {
                throw new ArgumentException(DataStrings.FileNotLines_S.Replace("%S", fileName));
            }

            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.
            List <ShapeHeader> shapeHeaders = ReadIndexFile(fileName);
            int numShapes = shapeHeaders.Count;

            bool isM = (header.ShapeType == ShapeType.MultiPointZ || header.ShapeType == ShapeType.MultiPointM);
            bool isZ = (header.ShapeType == ShapeType.MultiPointZ);

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


            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++)
                {
                    // 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.MultiPoint, CoordinateType)
                    {
                        RecordNumber  = reader.ReadInt32(Endian.BigEndian),
                        ContentLength = reader.ReadInt32(Endian.BigEndian),
                        ShapeType     = (ShapeType)reader.ReadInt32(),
                        StartIndex    = totalPointsCount,
                        NumParts      = 1
                    };
                    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 += 1;

                        // 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;

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

                int partsOffset = 0;
                for (int shp = 0; shp < numShapes; shp++)
                {
                    var shape = shapeIndices[shp];
                    if (shape.ShapeType == ShapeType.NullShape)
                    {
                        continue;
                    }
                    reader.Seek(shapeHeaders[shp].ByteOffset, SeekOrigin.Begin);
                    reader.Seek(3 * 4 + 32 + 4, SeekOrigin.Current); // Skip first bytes (Record Number, Content Length, Shapetype + BoundingBox + NumPoints)

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

                    // Read points
                    var pointsBytes = reader.ReadBytes(8 * 2 * shape.NumPoints); //Numpoints * Point (X(8) + Y(8))
                    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.MultiPoint)
                        {
                            NumVertices = count
                        };
                        shape.Parts.Add(partR);
                    }
                    partsOffset += shape.NumParts;

                    // Fill M and Z arrays
                    switch (header.ShapeType)
                    {
                    case ShapeType.MultiPointM:
                        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.MultiPointZ:
                        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.MultiPointM;
                        }

                        break;
                    }
                }

                if (isM)
                {
                    M = mArray;
                }
                if (isZ)
                {
                    Z = zArray;
                }
                ShapeIndices = shapeIndices;
                Vertex       = vert;
            }
        }
Exemple #34
0
        private void FillLines(string fileName, IProgressHandler progressHandler)
        {
            // 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));
            }

            // 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 != ShapeType.PolyLine &&
                header.ShapeType != ShapeType.PolyLineM &&
                header.ShapeType != ShapeType.PolyLineZ)
            {
                throw new ArgumentException(DataStrings.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.
            BufferedBinaryReader bbReader = new BufferedBinaryReader(fileName, progressHandler);

            if (bbReader.FileLength == 100)
            {
                // We have reached the end of the file so we can close the file
                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[] allBounds   = new byte[numShapes * 32];
            // probably all will be in one block, but use a byteBlock just in case.
            ByteBlock allParts  = new ByteBlock(BLOCKSIZE);
            ByteBlock allCoords = new ByteBlock(BLOCKSIZE);
            bool      isM       = (header.ShapeType == ShapeType.PolyLineM || header.ShapeType == ShapeType.PolyLineZ);
            bool      isZ       = (header.ShapeType == ShapeType.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);

                ShapeRange shape = new ShapeRange(FeatureType.Line)
                {
                    RecordNumber  = bbReader.ReadInt32(false),
                    ContentLength = bbReader.ReadInt32(false),
                    ShapeType     = (ShapeType)bbReader.ReadInt32(),
                    StartIndex    = pointOffset
                };

                if (shape.ShapeType == ShapeType.NullShape)
                {
                    goto fin;
                }
                bbReader.Read(allBounds, shp * 32, 32);
                shape.NumParts  = bbReader.ReadInt32();  // Byte 44      NumParts    Integer     1      Little
                shape.NumPoints = bbReader.ReadInt32();  // Byte 48      NumPoints   Integer     1      Little

                partOffsets[shp] = allParts.IntOffset();
                allParts.Read(shape.NumParts * 4, bbReader);

                allCoords.Read(shape.NumPoints * 16, bbReader);

                pointOffset += shape.NumPoints;

                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)
                    {
                        //mMin = bbReader.ReadDouble();
                        //mMax = bbReader.ReadDouble();
                        bbReader.Seek(16, SeekOrigin.Current);
                        if (allM != null)
                        {
                            allM.Read(shape.NumPoints * 8, bbReader);
                        }
                    }
                }
                if (header.ShapeType == ShapeType.PolyLineZ)
                {
                    bool     hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints;
                    IExtentZ zExt = (IExtentZ)shape.Extent;
                    zExt.MinZ = bbReader.ReadDouble();
                    zExt.MaxZ = bbReader.ReadDouble();
                    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.
                    IExtentM mExt = (IExtentM)shape.Extent;
                    if (hasM)
                    {
                        mExt.MinM = bbReader.ReadDouble();
                        mExt.MaxM = 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.
fin:
                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();
            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)
                    {
                        int prt = parts[offset + part + 1];
                        endIndex = prt + shape.StartIndex;
                    }
                    int       count = endIndex - startIndex;
                    PartRange partR = new PartRange(vert, shape.StartIndex, parts[offset + part], FeatureType.Line)
                    {
                        NumVertices = count
                    };
                    shape.Parts.Add(partR);
                }
            }

            bbReader.Dispose();
        }
Exemple #35
0
        /// <summary>
        /// Occurs when the vertices are being re-calculated.
        /// </summary>
        protected virtual void OnInitializeVertices()
        {
            if (_features == null)
                return;

            int count = _features.Sum(f => f.NumPoints);
            _vertices = new double[count * 2];
            int i = 0;
            foreach (IFeature f in _features)
            {
                // this should be all the coordinates, for all parts of the geometry.
                IList<Coordinate> coords = f.Coordinates;

                if (coords == null)
                {
                    continue;
                }

                foreach (Coordinate c in coords)
                {
                    _vertices[i * 2] = c.X;
                    _vertices[i * 2 + 1] = c.Y;

                    // essentially add a reference pointer to the internal array of values
                    i++;
                }
            }

            // not sure, but I bet arrays a smidge faster at indexed access than lists
            _shapeIndices = new List<ShapeRange>();
            int vIndex = 0;
            foreach (IFeature f in _features)
            {
                ShapeRange shx = new ShapeRange(FeatureType) { Extent = new Extent(f.Envelope) };
                _shapeIndices.Add(shx);
                f.ShapeIndex = shx;

                // for simplicity in looping, there is always at least one part.
                // That way, the shape range can be ignored and the parts loop used instead.
                int shapeStart = vIndex;
                for (int part = 0; part < f.NumGeometries; part++)
                {
                    PartRange prtx = new PartRange(_vertices, shapeStart, vIndex - shapeStart, FeatureType);
                    IBasicPolygon bp = f.GetBasicGeometryN(part) as IBasicPolygon;
                    if (bp != null)
                    {
                        // Account for the Shell
                        prtx.NumVertices = bp.Shell.NumPoints;

                        vIndex += bp.Shell.NumPoints;

                        // The part range should be adjusted to no longer include the holes
                        foreach (var hole in bp.Holes)
                        {
                            PartRange holex = new PartRange(_vertices, shapeStart, vIndex - shapeStart, FeatureType)
                            {
                                NumVertices = hole.NumPoints
                            };
                            shx.Parts.Add(holex);
                            vIndex += hole.NumPoints;
                        }
                    }
                    else
                    {
                        int numPoints = f.GetBasicGeometryN(part).NumPoints;

                        // This is not a polygon, so just add the number of points.
                        vIndex += numPoints;
                        prtx.NumVertices = numPoints;
                    }

                    shx.Parts.Add(prtx);
                }
            }
            _verticesAreValid = true;
        }
Exemple #36
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;
        }
Exemple #37
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>
        /// <param name="progressHandler">Progress handler</param>
        private void FillPoints(string fileName, IProgressHandler progressHandler)
        {
            // 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.
            var 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];
            }

            var progressMeter = new ProgressMeter(progressHandler, "Reading from " + Path.GetFileName(fileName))
            {
                StepPercent = 5
            };

            using (var reader = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                for (var shp = 0; shp < numShapes; shp++)
                {
                    progressMeter.CurrentPercent = (int)(shp * 100.0 / numShapes);

                    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();
                    if (shapeType == ShapeType.NullShape)
                    {
                        if (m != null)
                        {
                            m[shp] = double.MinValue;
                        }
                        goto fin;
                    }

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

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

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

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

fin:
                    var shape = new ShapeRange(FeatureType.Point)
                    {
                        RecordNumber  = recordNumber,
                        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;

            progressMeter.Reset();
        }
Exemple #38
0
 /// <summary>
 /// Creates a new "point" shape that has only the one point.
 /// </summary>
 /// <param name="v"></param>
 public ShapeRange(Vertex v)
 {
     FeatureType = FeatureType.Point;
     Parts = new List<PartRange>();
     _numParts = -1;
     double[] coords = new double[2];
     coords[0] = v.X;
     coords[1] = v.Y;
     PartRange prt = new PartRange(coords, 0, 0, FeatureType.Point);
     prt.NumVertices = 1;
     Extent = new Extent(v.X, v.Y, v.X, v.Y);
     Parts.Add(prt);
 }
Exemple #39
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SegmentRange"/> class.
 /// </summary>
 /// <param name="part">The part range.</param>
 /// <param name="featureType">The feature type.</param>
 public SegmentRange(PartRange part, FeatureType featureType)
 {
     FeatureType = featureType;
     Part        = part;
 }
Exemple #40
0
        /// <summary>
        /// This creates a polygon shape from an extent.
        /// </summary>
        /// <param name="ext">The extent to turn into a polygon shape.</param>
        public ShapeRange(Extent ext)
        {
            Extent = ext;
            Parts = new List<PartRange>();
            _numParts = -1;
            // Counter clockwise
            // 1 2
            // 4 3
            double[] coords = new double[8];
            // C1
            coords[0] = ext.MinX;
            coords[1] = ext.MaxY;
            // C2
            coords[2] = ext.MaxX;
            coords[3] = ext.MaxY;
            // C3
            coords[4] = ext.MaxX;
            coords[5] = ext.MinY;
            // C4
            coords[6] = ext.MinX;
            coords[7] = ext.MinY;

            FeatureType = FeatureType.Polygon;
            ShapeType = ShapeType.Polygon;
            PartRange pr = new PartRange(coords, 0, 0, FeatureType.Polygon);
            pr.NumVertices = 4;
            Parts.Add(pr);
        }
        /// <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);
            // Position     Value               Type        Number      Byte Order
            ShapeRange shape = new ShapeRange(FeatureType.Polygon); //--------------------------------------------------------------------

            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);
            }

            Shape myShape = new Shape();

            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.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)
                {
                    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.PolygonZ)
            {
                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.Polygon)
                {
                    NumVertices = pointCount
                };
                shape.Parts.Add(partR);
            }

            return(myShape);
        }
        /// <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;
        }