Exemplo n.º 1
0
        /// <summary>
        /// Calculates the intersection of a polygon shape without relying on the NTS geometry
        /// </summary>
        /// <param name="polygonShape"></param>
        /// <param name="otherShape"></param>
        /// <returns></returns>
        public static bool Intersects(ShapeRange polygonShape, ShapeRange otherShape)
        {
            if (polygonShape.FeatureType != FeatureType.Polygon)
            {
                throw new ArgumentException("The First parameter should be a point shape, but it was featuretype:" + polygonShape.FeatureType);
            }

            // Extents will have already been tested by this point.
            // Regardless of what the other shapetype is, a coordinate inside this polygon indicates a hit.
            if (ContainsVertex(polygonShape, otherShape)) return true;

            // There is no other way for this polygon to intersect the other points
            if (otherShape.FeatureType == FeatureType.Point || otherShape.FeatureType == FeatureType.MultiPoint)
                return false;

            // For lines and polygons, if any segment intersects any segment of this polygon shape, return true.
            // This is essentially looking for the rare case of crossing in and crossing out again with
            // no actual points inside this polygonShape.
            if (LineShape.SegmentsIntersect(polygonShape, otherShape)) return true;

            // There is no other way for this polygon to intersect the other lines
            if (otherShape.FeatureType == FeatureType.Line) return false;

            // If the other polygon completely contains this polygon every other test has returned false,
            // but this will test for that case with only a single point.
            Vertex v = polygonShape.First();
            ShapeRange onlyFirstPoint = new ShapeRange(v);
            return ContainsVertex(otherShape, onlyFirstPoint);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Calculates the intersection of a polygon shape without relying on the NTS geometry
        /// </summary>
        /// <param name="lineShape"></param>
        /// <param name="otherShape"></param>
        /// <returns></returns>
        public static bool Intersects(ShapeRange lineShape, ShapeRange otherShape)
        {
            if (lineShape.FeatureType != FeatureType.Line)
            {
                throw new ArgumentException("The First parameter should be a point shape, but it was featuretype:" + lineShape.FeatureType);
            }

            // Implmented in PolygonShape
            if (otherShape.FeatureType == FeatureType.Polygon)
            {
                return otherShape.Intersects(lineShape);
            }

            // Test for point on a line
            if (otherShape.FeatureType == FeatureType.Point || otherShape.FeatureType == FeatureType.MultiPoint)
            {
                return IntersectsVertex(lineShape, otherShape);
            }

            // There is no other way for this polygon to intersect the other points
            if (otherShape.FeatureType == FeatureType.Point || otherShape.FeatureType == FeatureType.MultiPoint)
                return false;

            // For lines and polygons, if any segment intersects any segment of this polygon shape, return true.
            // This is essentially looking for the rare case of crossing in and crossing out again with
            // no actual points inside this polygonShape.
            return SegmentsIntersect(lineShape, otherShape);
        }
Exemplo n.º 3
0
 /// <summary>
 /// Tests to see if any vertices from the other shape are coincident with a segment from this line shape.
 /// </summary>
 /// <param name="lineShape"></param>
 /// <param name="otherShape"></param>
 /// <returns></returns>
 public static bool IntersectsVertex(ShapeRange lineShape, ShapeRange otherShape)
 {
     return lineShape.Parts
         .Any(part => part.Segments
             .Any(segment => otherShape.Parts
                 .Any(oPart => oPart
                     .Any(segment.IntersectsVertex))));
 }
Exemplo n.º 4
0
 /// <summary>
 /// Returns true if any vertices overlap
 /// </summary>
 /// <returns></returns>
 public static bool VerticesIntersect(ShapeRange pointShape, ShapeRange otherPointShape)
 {
     return pointShape.Parts
         .Any(part => otherPointShape.Parts
             .Any(oPart => part
                 .Any(v1 => oPart
                     .Any(v2 => v1 == v2))));
 }
Exemplo n.º 5
0
 /// <summary>
 /// This cycles through all the vertices, which are stored as {X1, Y1, X2, Y2...Xn, Yn} and tests
 /// if any of those vertices falls within the polygon shape.
 /// </summary>
 /// <param name="polygonShape"></param>
 /// <param name="otherShape"></param>
 /// <returns></returns>
 public static bool ContainsVertex(ShapeRange polygonShape, ShapeRange otherShape)
 {
     foreach (PartRange otherPart in otherShape.Parts)
     {
         if (ContainsVertex(polygonShape, otherPart))
         {
             return true;
         }
     }
     return false;
 }
Exemplo n.º 6
0
        /// <summary>
        /// Returns true if any segment from a line or polygon shape interesect any segments from the line or polygon shape.
        /// </summary>
        /// <param name="lineShape">A Line or Polygon shape</param>
        /// <param name="otherShape">Another line or polygon shape</param>
        /// <returns></returns>
        public static bool SegmentsIntersect(ShapeRange lineShape, ShapeRange otherShape)
        {
            if (lineShape.FeatureType != FeatureType.Line && lineShape.FeatureType != FeatureType.Polygon)
                throw new ArgumentException("Expected lineShape to be a line or polygon feature type, got " + lineShape.FeatureType);
            if (otherShape.FeatureType != FeatureType.Line && otherShape.FeatureType != FeatureType.Polygon)
                throw new ArgumentException("Expected otherShape to be a line or polygon feature type, got " + otherShape.FeatureType);

            return lineShape.Parts
                .Any(part => part.Segments
                    .Any(segment => otherShape.Parts
                        .Any(oPart => oPart.Segments
                            .Any(segment.Intersects))));
        }
Exemplo n.º 7
0
        /// <summary>
        /// Calculates the intersection of a polygon shape without relying on the NTS geometry
        /// </summary>
        /// <param name="pointShape"></param>
        /// <param name="otherShape"></param>
        /// <returns></returns>
        public static bool Intersects(ShapeRange pointShape, ShapeRange otherShape)
        {
            if (pointShape.FeatureType != FeatureType.Point && pointShape.FeatureType != FeatureType.MultiPoint)
            {
                throw new ArgumentException("The First parameter should be a point shape, but it was featuretype:" + pointShape.FeatureType);
            }

            // Implmented in PolygonShape or line shape.  Point shape is the simplest and just looks for overlapping coordinates.
            if (otherShape.FeatureType == FeatureType.Polygon || otherShape.FeatureType == FeatureType.Line)
            {
                return otherShape.Intersects(pointShape);
            }

            // For two point-type shapes, test if any vertex from one overlaps with any vertex of the other within Epsilon tollerance
            return VerticesIntersect(pointShape, otherShape);
        }
Exemplo n.º 8
0
 /// <summary>
 /// Tests to see if any vertices from the other shape are coincident with a segment from this line shape.
 /// </summary>
 /// <param name="lineShape"></param>
 /// <param name="otherShape"></param>
 /// <returns></returns>
 public static bool IntersectsVertex(ShapeRange lineShape, ShapeRange otherShape)
 {
     foreach (PartRange part in lineShape.Parts)
     {
         foreach (Segment segment in part.Segments)
         {
             foreach (PartRange oPart in otherShape.Parts)
             {
                 foreach (Vertex v in oPart)
                 {
                     if (segment.IntersectsVertex(v)) return true;
                 }
             }
         }
     }
     return false;
 }
Exemplo n.º 9
0
 /// <summary>
 /// Returns true if any vertices overlap
 /// </summary>
 /// <returns></returns>
 public static bool VerticesIntersect(ShapeRange pointShape, ShapeRange otherPointShape)
 {
     foreach (PartRange part in pointShape.Parts)
     {
         foreach (PartRange oPart in otherPointShape.Parts)
         {
             foreach (Vertex v1 in part)
             {
                 foreach (Vertex v2 in oPart)
                 {
                     if (v1 == v2) return true;
                 }
             }
         }
     }
     return false;
 }
Exemplo n.º 10
0
        /// <summary>
        /// Calculates the intersection of a polygon shape without relying on the NTS geometry.
        /// </summary>
        /// <param name="polygonShape">Polygon shape used for calculation.</param>
        /// <param name="otherShape">Other shape of any feature type.</param>
        /// <returns>True, if the given shape ranges intersect.</returns>
        public static bool Intersects(ShapeRange polygonShape, ShapeRange otherShape)
        {
            if (polygonShape.FeatureType != FeatureType.Polygon)
            {
                throw new ArgumentException(string.Format(DataStrings.Shape_WrongFeatureType, "polygonShape", "polygon", polygonShape.FeatureType));
            }

            // Extents will have already been tested by this point.
            // Regardless of what the other shapetype is, a coordinate inside this polygon indicates a hit.
            if (ContainsVertex(polygonShape, otherShape))
            {
                return(true);
            }

            // There is no other way for this polygon to intersect the other points
            if (otherShape.FeatureType == FeatureType.Point || otherShape.FeatureType == FeatureType.MultiPoint)
            {
                return(false);
            }

            // For lines and polygons, if any segment intersects any segment of this polygon shape, return true.
            // This is essentially looking for the rare case of crossing in and crossing out again with
            // no actual points inside this polygonShape.
            if (LineShape.SegmentsIntersect(polygonShape, otherShape))
            {
                return(true);
            }

            // There is no other way for this polygon to intersect the other lines
            if (otherShape.FeatureType == FeatureType.Line)
            {
                return(false);
            }

            // If the other polygon completely contains this polygon every other test has returned false,
            // but this will test for that case with only a single point.
            Vertex     v = polygonShape.First();
            ShapeRange onlyFirstPoint = new(v);

            return(ContainsVertex(otherShape, onlyFirstPoint));
        }
Exemplo n.º 11
0
        /// <summary>
        /// Tests to see if any vertices from the other shape are coincident with a segment from this line shape.
        /// </summary>
        /// <param name="lineShape">LineShape used for calculation.</param>
        /// <param name="otherShape">Other shape of any feature type.</param>
        /// <returns>True, if the shapes intersect.</returns>
        public static bool IntersectsVertex(ShapeRange lineShape, ShapeRange otherShape)
        {
            foreach (PartRange part in lineShape.Parts)
            {
                foreach (Segment segment in part.Segments)
                {
                    foreach (PartRange oPart in otherShape.Parts)
                    {
                        foreach (Vertex v in oPart)
                        {
                            if (segment.IntersectsVertex(v))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 12
0
        private static void ReadMultiPoint(Stream data, FeatureSetPack results)
        {
            int        count = ReadInt32(data);
            ShapeRange sr    = new ShapeRange(FeatureType.MultiPoint);
            PartRange  prt   = new PartRange(FeatureType.MultiPoint)
            {
                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);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Returns true if any vertices overlap.
        /// </summary>
        /// <param name="pointShape">First point shape used for checking.</param>
        /// <param name="otherPointShape">Second point shape used for checking.</param>
        /// <returns>True if any vertices overlap.</returns>
        public static bool VerticesIntersect(ShapeRange pointShape, ShapeRange otherPointShape)
        {
            foreach (PartRange part in pointShape.Parts)
            {
                foreach (PartRange oPart in otherPointShape.Parts)
                {
                    foreach (Vertex v1 in part)
                    {
                        foreach (Vertex v2 in oPart)
                        {
                            if (v1 == v2)
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 14
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 (var 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);
        }
Exemplo n.º 15
0
        /// <summary>
        /// Creates a shape based on the specified geometry.  This shape will be standing alone,
        /// all by itself.  The attributes will be null.
        /// </summary>
        /// <param name="geometry">The geometry to create a shape from.</param>
        public Shape(IGeometry geometry)
        {
            if (Equals(geometry, null))
            {
                throw new ArgumentNullException("geometry");
            }

            IList <Coordinate> coords = geometry.Coordinates;

            _vertices = new double[geometry.NumPoints * 2];
            _z        = new double[geometry.NumPoints];
            _m        = new double[geometry.NumPoints];
            for (int i = 0; i < coords.Count; i++)
            {
                Coordinate c = coords[i];
                _vertices[i * 2]     = c.X;
                _vertices[i * 2 + 1] = c.Y;
                _z[i] = c.Z;
                _m[i] = c.M;
            }
            _shapeRange = ShapeRangeFromGeometry(geometry, _vertices, 0);
        }
Exemplo n.º 16
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;
        }
Exemplo n.º 17
0
        /// <summary>
        /// Creates a point shape from a coordinate.
        /// </summary>
        /// <param name="coord">Coordinate used for creating the point shape.</param>
        public Shape(Coordinate coord)
        {
            if (Equals(coord, null))
            {
                throw new ArgumentNullException("coord");
            }

            if (!double.IsNaN(coord.Z))
            {
                _z = new[] { coord.Z };
            }
            if (!double.IsNaN(coord.M))
            {
                _m = new[] { coord.M };
            }

            _shapeRange = new ShapeRange(FeatureType.Point);
            _vertices   = new[] { coord.X, coord.Y };
            _shapeRange.Parts.Add(new PartRange(_vertices, 0, 0, FeatureType.Point)
            {
                NumVertices = 1
            });
            _shapeRange.Extent = new Extent(coord.X, coord.Y, coord.X, coord.Y);
        }
Exemplo n.º 18
0
 /// <summary>
 /// Adds the shape.  Assumes that the "part" indices are created with a 0 base, and the number of
 /// vertices is specified.  The start range of each part will be updated with the new shape range.
 /// The vertices array itself iwll be updated during hte stop editing step.
 /// </summary>
 /// <param name="shapeVertices"></param>
 /// <param name="shape"></param>
 public void Add(double[] shapeVertices, ShapeRange shape)
 {
     if (shape.FeatureType == FeatureType.Point || shape.FeatureType == FeatureType.MultiPoint)
     {
         _pointVertices.Add(shapeVertices);
         shape.StartIndex = _pointLength / 2; // point offset, not double offset
         Points.ShapeIndices.Add(shape);
         _pointLength += shapeVertices.Length;
     }
     if (shape.FeatureType == FeatureType.Line)
     {
         _lineVertices.Add(shapeVertices);
         shape.StartIndex = _lineLength / 2; // point offset
         Lines.ShapeIndices.Add(shape);
         _lineLength += shapeVertices.Length;
     }
     if (shape.FeatureType == FeatureType.Polygon)
     {
         _polygonVertices.Add(shapeVertices);
         shape.StartIndex = _polygonLength / 2; // point offset
         Polygons.ShapeIndices.Add(shape);
         _polygonLength += shapeVertices.Length / 2;
     }
 }
Exemplo n.º 19
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();
        }
Exemplo n.º 20
0
        /// <inheritdoc/>
        public virtual List<IFeature> Select(Extent region, out Extent affectedRegion)
        {
            var result = new List<IFeature>();
            affectedRegion = new Extent();

            if (IndexMode)
            {
                var aoi = new ShapeRange(region);
                var shapes = ShapeIndices;
                for (var shp = 0; shp < shapes.Count; shp++)
                {
                    if (!shapes[shp].Intersects(aoi))
                    {
                        continue;
                    }

                    var feature = GetFeature(shp);
                    affectedRegion.ExpandToInclude(feature.Envelope.ToExtent());
                    result.Add(feature);
                }
            }
            else
            {
                foreach (var feature in Features)
                {
                    if (!region.Intersects(feature.Envelope) ||
                       !feature.Intersects(region.ToEnvelope()))
                    {
                        continue;
                    }
                  
                    result.Add(feature);
                    affectedRegion.ExpandToInclude(feature.Envelope.ToExtent());
                }
            }

            return result;
        }
Exemplo n.º 21
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();
        }
Exemplo n.º 22
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">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();
        }
Exemplo n.º 23
0
        /// <summary>
        /// Creates a shape based on the specified feature.  This shape will be standing alone,
        /// all by itself.  The fieldnames and field types will be null.
        /// </summary>
        /// <param name="feature"></param>
        public Shape(IFeature feature)
        {
            if (Equals(feature, null))
                throw new ArgumentNullException("feature");

            if (feature.NumPoints == 0)
                throw new ArgumentOutOfRangeException("The IFeature.NumPoints of the parameter feature must be greater than 0.");

            _attributes = feature.DataRow.ItemArray;
            IList<Coordinate> coords = feature.Coordinates;
            _vertices = new double[feature.NumPoints * 2];
            _z = new double[feature.NumPoints];
            _m = new double[feature.NumPoints];
            for (int i = 0; i < coords.Count; i++)
            {
                Coordinate c = coords[i];
                _vertices[i * 2] = c.X;
                _vertices[i * 2 + 1] = c.Y;
                _z[i] = c.Z;
                _m[i] = c.M;
            }
            _shapeRange = ShapeRangeFromFeature(feature, _vertices);
        }
Exemplo n.º 24
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();
        }
Exemplo n.º 25
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();
        }
Exemplo n.º 26
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);
        }
Exemplo n.º 27
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Shape"/> class where the shaperange exists and has a type specified.
 /// </summary>
 /// <param name="featureType">Feature type of the shape range.</param>
 public Shape(FeatureType featureType)
 {
     Range = new ShapeRange(featureType);
 }
Exemplo n.º 28
0
 /// <summary>
 /// Creates a new shape type where the shaperange exists and has a type specified.
 /// </summary>
 /// <param name="type"></param>
 public Shape(FeatureType type)
 {
     _shapeRange = new ShapeRange(type);
 }
Exemplo n.º 29
0
        internal static void BuildLineString(GraphicsPath path, double[] vertices, ShapeRange shpx, MapArgs args, Rectangle clipRect)
        {
            double minX = args.MinX;
            double maxY = args.MaxY;
            double dx = args.Dx;
            double dy = args.Dy;
            for (int prt = 0; prt < shpx.Parts.Count; prt++)
            {
                PartRange prtx = shpx.Parts[prt];
                int start = prtx.StartIndex;
                int end = prtx.EndIndex;
                List<double[]> points = new List<double[]>();

                for (int i = start; i <= end; i++)
                {
                    double[] pt = new double[2];
                    pt[X] = (vertices[i * 2] - minX) * dx;
                    pt[Y] = (maxY - vertices[i * 2 + 1]) * dy;
                    points.Add(pt);
                }

                List<List<double[]>> multiLinestrings;
                if (!shpx.Extent.Within(args.GeographicExtents))
                {
                    multiLinestrings = CohenSutherland.ClipLinestring(points, clipRect.Left, clipRect.Top,
                                                                      clipRect.Right, clipRect.Bottom);
                }
                else
                {
                    multiLinestrings = new List<List<double[]>>();
                    multiLinestrings.Add(points);
                }

                foreach (List<double[]> linestring in multiLinestrings)
                {
                    List<Point> intPoints = DuplicationPreventer.Clean(linestring);
                    if (intPoints.Count < 2)
                    {
                        points.Clear();
                        continue;
                    }
                    path.StartFigure();
                    Point[] pointArray = intPoints.ToArray();
                    path.AddLines(pointArray);
                }
            }
        }
        /// <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;
        }
Exemplo n.º 31
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">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();
        }
Exemplo n.º 32
0
 /// <summary>
 /// Creates a new shape type where the shaperange exists and has a type specified
 /// </summary>
 /// <param name="type"></param>
 public Shape(FeatureType type)
 {
     _shapeRange = new ShapeRange(type);
 }
Exemplo n.º 33
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;
        }
Exemplo n.º 34
0
        /// <summary>
        /// Creates a shape based on the specified geometry.  This shape will be standing alone,
        /// all by itself.  The attributes will be null.
        /// </summary>
        /// <param name="geometry">The geometry to create a shape from.</param>
        public Shape(IGeometry geometry)
        {
            if (Equals(geometry, null))
                throw new ArgumentNullException("geometry");

            IList<Coordinate> coords = geometry.Coordinates;
            _vertices = new double[geometry.NumPoints * 2];
            _z = new double[geometry.NumPoints];
            _m = new double[geometry.NumPoints];
            for (int i = 0; i < coords.Count; i++)
            {
                Coordinate c = coords[i];
                _vertices[i * 2] = c.X;
                _vertices[i * 2 + 1] = c.Y;
                _z[i] = c.Z;
                _m[i] = c.M;
            }
            _shapeRange = ShapeRangeFromGeometry(geometry, _vertices, 0);
        }
Exemplo n.º 35
0
        /// <inheritdoc/>
        public virtual List<IFeature> Select(Extent region, out Extent affectedRegion)
        {
            List<IFeature> result = new List<IFeature>();
            if (IndexMode)
            {
                ShapeRange aoi = new ShapeRange(region);
                Extent affected = new Extent();
                List<ShapeRange> shapes = ShapeIndices;
                if (shapes != null)
                {
                    //ProgressMeter = new ProgressMeter(ProgressHandler, "Selecting shapes", shapes.Count);
                    for (int shp = 0; shp < shapes.Count; shp++)
                    {
                        //ProgressMeter.Next();
                        if (!shapes[shp].Intersects(aoi))
                        {
                            continue;
                        }

                        IFeature f = GetFeature(shp);
                        affected.ExpandToInclude(shapes[shp].Extent);
                        result.Add(f);
                    }
                    //ProgressMeter.Reset();
                }

                affectedRegion = affected;
                return result;
            }

            affectedRegion = new Extent();

            bool useProgress = (Features.Count > 10000);
            //ProgressMeter = new ProgressMeter(ProgressHandler, "Selecting Features", Features.Count);
            foreach (IFeature feature in Features)
            {
                //if (useProgress)
                //    ProgressMeter.Next();
                if (!region.Intersects(feature.Envelope))
                {
                    continue;
                }
                if (!feature.Intersects(region.ToEnvelope()))
                {
                    continue;
                }
                result.Add(feature);
                affectedRegion.ExpandToInclude(feature.Envelope.ToExtent());
            }
            //if (useProgress)
            //    ProgressMeter.Reset();

            return result;
        }
Exemplo n.º 36
0
 public Shape(ShapeRange shapeRange)
 {
     Range = shapeRange;
 }
Exemplo n.º 37
0
        /// <summary>
        /// Appends the specified polygon to the graphics path.
        /// </summary>
        private static void BuildPolygon(double[] vertices, ShapeRange shpx, GraphicsPath borderPath, MapArgs args, SoutherlandHodgman shClip)
        {
            double minX = args.MinX;
            double maxY = args.MaxY;
            double dx = args.Dx;
            double dy = args.Dy;

            for (int prt = 0; prt < shpx.Parts.Count; prt++)
            {
                PartRange prtx = shpx.Parts[prt];
                int start = prtx.StartIndex;
                int end = prtx.EndIndex;
                var points = new List<double[]>(end - start + 1);

                for (int i = start; i <= end; i++)
                {
                    var pt = new[]
                    {
                        (vertices[i*2] - minX)*dx,
                        (maxY - vertices[i*2 + 1])*dy
                    };
                    points.Add(pt);
                }
                if (null != shClip)
                {
                    points = shClip.Clip(points);
                }
                var intPoints = DuplicationPreventer.Clean(points).ToArray();
                if (intPoints.Length < 2)
                {
                    continue;
                }

                borderPath.StartFigure();
                borderPath.AddLines(intPoints);
            }
        }
Exemplo n.º 38
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();
        }
Exemplo n.º 39
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();
        }
Exemplo n.º 40
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();
        }
Exemplo n.º 41
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();
        }
Exemplo n.º 42
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 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;
            }
        }
Exemplo n.º 43
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);
        }
Exemplo n.º 44
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;
        }
Exemplo n.º 45
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);
 }
Exemplo n.º 46
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 = 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();
        }
Exemplo n.º 47
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);
        }
Exemplo n.º 48
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();
        }
Exemplo n.º 49
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);
        }
Exemplo n.º 50
0
        private static void FastBuildLine(GraphicsPath graphPath, double[] vertices, ShapeRange shpx, double minX, double maxY, double dx, double dy)
        {
            for (int prt = 0; prt < shpx.Parts.Count; prt++)
            {
                PartRange prtx = shpx.Parts[prt];
                int start = prtx.StartIndex;
                int end = prtx.EndIndex;
                List<Point> partPoints = new List<Point>();
                Point previousPoint = new Point();
                for (int i = start; i <= end; i++)
                {
                    if (double.IsNaN(vertices[i * 2]) || double.IsNaN(vertices[i * 2 + 1])) continue;
                    Point pt = new Point();
                    pt.X = Convert.ToInt32((vertices[i * 2] - minX) * dx);
                    pt.Y = Convert.ToInt32((maxY - vertices[i * 2 + 1]) * dy);

                    if (i == 0 || (pt.X != previousPoint.X || pt.Y != previousPoint.Y))
                    {
                        // Don't add the same point twice
                        partPoints.Add(pt);
                        previousPoint = pt;
                    }
                }
                if (partPoints.Count < 2) continue; // we need two distinct points to make a line
                graphPath.StartFigure();
                graphPath.AddLines(partPoints.ToArray());
            }
        }
Exemplo n.º 51
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;
        }
        /// <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);
        }
Exemplo n.º 53
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);
        }