Example #1
0
        /// <summary>
        /// Creates a new "point" shape that has only the one point.
        /// </summary>
        /// <param name="v"></param>
        public ShapeRange(Vertex v)
        {
            FeatureType = FeatureTypes.Point;
            Parts = new List<PartRange>();
            _numParts = -1;
            double[] coords = new double[2];
            coords[0] = v.X;
            coords[1] = v.Y;
            PartRange prt = new PartRange(coords, 0,0, FeatureTypes.Point);
            prt.NumVertices = 1;
            Parts.Add(prt);

        }
Example #2
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)
 {
     _shapeRange = new ShapeRange(feature.FeatureType);
     _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;
     }
     int offset = 0;
     for(int ig = 0; ig < feature.NumGeometries; ig++)
     {
         IBasicGeometry g = feature.GetBasicGeometryN(ig);
         PartRange prt = new PartRange(_vertices, 0, offset, feature.FeatureType);
         _shapeRange.Parts.Add(prt);
         offset += g.NumPoints;
     }
 }
        /// <summary>
        /// Obtains a typed list of ShapefilePoint structures with double values associated with the various coordinates.
        /// </summary>
        /// <param name="filename">A string filename</param>
        /// <param name="progressHandler">A progress indicator</param>
        private void FillPoints(string filename, IProgressHandler progressHandler)
        {
            

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

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

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

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

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

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

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

                bbReader.Dispose();
            
            
            
  
        }
     private static void ReadMultiPolygon(Stream data, FeatureSetPack results)
     {
         int numPolygons = ReadInt32(data);
         ShapeRange lShp = new ShapeRange(FeatureTypes.Polygon);
         List<double[]> rings = new List<double[]>();
         int partOffset = 0;
         for (int iPoly = 0; iPoly < numPolygons; iPoly++ )
         {
             data.Seek(5, SeekOrigin.Current); // endian and geometry type
             int numRings = ReadInt32(data);
             for (int iRing = 0; iRing < numRings; iRing++)
             {
                 int numPoints = ReadInt32(data); // ring structures are like a linestring without the final point.
                 double[] coords = ReadDouble(data, 2 * numPoints);
                 if (iRing == 0)
                 {
                     // By shapefile standard, the shell should be clockwise
                     if (IsCounterClockwise(coords)) ReverseCoords(coords);
                 }
                 else
                 {
                     // By shapefile standard, the holes should be counter clockwise.
                     if (!IsCounterClockwise(coords)) ReverseCoords(coords);
                 }
                 PartRange lPrt = new PartRange(FeatureTypes.Polygon);
                 lPrt.PartOffset = partOffset;
                 lPrt.NumVertices = numPoints;
                 lShp.Parts.Add(lPrt);
                 partOffset += coords.Length / 2;
                 rings.Add(coords);
             }
         }
 
         double[] allVertices = new double[partOffset * 2];
         int offset = 0;
         foreach (double[] ring in rings)
         {
             Array.Copy(ring, 0, allVertices, offset, ring.Length);
             offset += ring.Length;
         }
         results.Add(allVertices, lShp);
     }
Example #5
0
        /// <summary>
        /// Without changing the feature type or anything else, simply update the local coordinates
        /// to include the new coordinates.  All the new coordinates will be considered one part.
        /// Since point and multi-point shapes don't have parts, they will just be appended to the
        /// original part.
        /// </summary>
        public void AddPart(IEnumerable<Coordinate> coordinates, CoordinateTypes coordType)
        {
            bool hasM = (coordType == CoordinateTypes.M || coordType == CoordinateTypes.Z);
            bool hasZ = (coordType == CoordinateTypes.Z);
            List<double> vertices = new List<double>();
            List<double> z = new List<double>();
            List<double> m = new List<double>();
            int numPoints = 0;
            int oldNumPoints = (_vertices != null) ? _vertices.Length/2: 0;
            foreach (Coordinate coordinate in coordinates)
            {
                if(_shapeRange.Extent == null)_shapeRange.Extent = new Extent();
                _shapeRange.Extent.ExpandToInclude(coordinate.X, coordinate.Y);
                vertices.Add(coordinate.X);
                vertices.Add(coordinate.Y);
                if(hasM)m.Add(coordinate.M);
                if(hasZ)z.Add(coordinate.Z);
                numPoints++;
            }
            // Using public accessor also updates individual part references
            Vertices = (_vertices != null) ? _vertices.Concat(vertices).ToArray() : vertices.ToArray();
            if(hasZ) _z = (_z != null) ? _z.Concat(z).ToArray() : z.ToArray();
            if(hasM) _m = (_m != null) ? _m.Concat(m).ToArray() : m.ToArray();

            if(_shapeRange.FeatureType == FeatureTypes.MultiPoint || _shapeRange.FeatureType == FeatureTypes.Point)
            {
                // Only one part exists
                _shapeRange.Parts[0].NumVertices += numPoints;
            }
            else
            {
                PartRange part = new PartRange(_vertices, _shapeRange.StartIndex, oldNumPoints, _shapeRange.FeatureType );
                part.NumVertices = numPoints;
                _shapeRange.Parts.Add(part);

            }    
        }
        /// <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>
        /// polygonshape and the shape extent is the same as the part extent.</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.
                double x1 = point.X;
                double y1 = point.Y;
                double x2 = ext.XMax;
                Segment ray = new Segment(point.X, point.Y, ext.XMax, 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;

                // Regardless of number of parts or holiness, 1 crossing can only be inside.
                if(totalCrosses == 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;
        }
 private static Shape ReadPolygon(Stream data)
 {
     Shape result = new Shape(FeatureTypes.Polygon);
     int numRings = ReadInt32(data);
     List<double[]> rings = new List<double[]>();
     int partOffset = 0;
     for (int iRing = 0; iRing < numRings; iRing++)
     {
         int numPoints = ReadInt32(data); // ring structures are like a linestring without the final point.
         double[] coords = ReadDouble(data, 2 * numPoints);
         if (iRing == 0)
         {
             // By shapefile standard, the shell should be clockwise
             if (IsCounterClockwise(coords)) ReverseCoords(coords);
         }
         else
         {
             // By shapefile standard, the holes should be counter clockwise.
             if (!IsCounterClockwise(coords)) ReverseCoords(coords);
         }
         PartRange lPrt = new PartRange(FeatureTypes.Polygon);
         lPrt.PartOffset = partOffset;
         lPrt.NumVertices = numPoints;
         result.Range.Parts.Add(lPrt);
         partOffset += coords.Length / 2;
         rings.Add(coords);
     }
     double[] allVertices = new double[partOffset * 2];
     int offset = 0;
     foreach (double[] ring in rings)
     {
         Array.Copy(ring, 0, allVertices, offset, ring.Length);
         offset += ring.Length;
     }
     result.Vertices = allVertices;
     return result;
 }
 private static Shape ReadLineString(Stream data)
 {
     Shape result = new Shape(FeatureTypes.Line);
     int count = ReadInt32(data);
     double[] coords = ReadDouble(data, 2 * count);
     PartRange lPrt = new PartRange(FeatureTypes.Line);
     lPrt.NumVertices = count;
     result.Range.Parts.Add(lPrt);
     result.Vertices = coords;
     return result;
 }
 private static void ReadLineString(Stream data, FeatureSetPack results)
 {
     int count = ReadInt32(data);
     double[] coords = ReadDouble(data, 2 * count);
     ShapeRange lShp = new ShapeRange(FeatureTypes.Line);
     PartRange lPrt = new PartRange(FeatureTypes.Line);
     lPrt.NumVertices = count;
     lShp.Parts.Add(lPrt);
     results.Add(coords, lShp);
 }
 /// <summary>
 /// Reads one multipoint shape from a data stream.  
 /// (this assumes that the two bytes (endian and type) have already been read.
 /// </summary>
 /// <param name="data"></param>
 /// <returns></returns>
 private static Shape ReadMultiPoint(Stream data)
 {
     Shape result = new Shape(FeatureTypes.MultiPoint);
     int count = ReadInt32(data);
     PartRange prt = new PartRange(FeatureTypes.MultiPoint);
     prt.NumVertices = count;
     result.Range.Parts.Add(prt);
     double[] vertices = new double[count * 2];
     for (int iPoint = 0; iPoint < count; iPoint++)
     {
         data.ReadByte(); // ignore endian
         ReadInt32(data); // ignore geometry type
         double[] coord = ReadDouble(data, 2);
         Array.Copy(coord, 0, vertices, iPoint * 2, 2);
     }
     result.Vertices = vertices;
     return result;
 }
 private static void ReadMultiPoint(Stream data, FeatureSetPack results)
 {
     int count = ReadInt32(data);
     ShapeRange sr = new ShapeRange(FeatureTypes.MultiPoint);
     PartRange prt = new PartRange(FeatureTypes.MultiPoint);
     prt.NumVertices = count;
     sr.Parts.Add(prt);
     double[] vertices = new double[count*2];
     for(int iPoint = 0; iPoint < count; iPoint++)
     {
         data.ReadByte(); // ignore endian
         ReadInt32(data); // ignore geometry type
         double[] coord = ReadDouble(data, 2);
         Array.Copy(coord, 0, vertices, iPoint*2, 2);
     }
     results.Add(vertices, sr);
 }
 /// <summary>
 /// This assumes that the byte order and shapetype have already been read.
 /// </summary>
 /// <param name="data"></param>
 /// <param name="results"></param>
 private static void ReadPoint(Stream data, FeatureSetPack results)
 {
     ShapeRange sr = new ShapeRange(FeatureTypes.MultiPoint);
     PartRange prt = new PartRange(FeatureTypes.MultiPoint);
     prt.NumVertices = 1;
     sr.Parts.Add(prt);
     double[] coord = ReadDouble(data, 2);
     results.Add(coord, sr);
 }
 /// <summary>
 /// This assumes that the byte order and shapetype have already been read.
 /// </summary>
 /// <param name="data"></param>
 public static Shape ReadPoint(Stream data)
 {
     Shape result = new Shape();
     result.Range = new ShapeRange(FeatureTypes.Point);
     PartRange prt = new PartRange(FeatureTypes.Point);
     prt.NumVertices = 1;
     result.Range.Parts.Add(prt);
     result.Vertices = ReadDouble(data, 2);
     return result;
 }
        // X Y MultiPoints: Total Length = 28 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number      Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big
        // Byte 8       Shape Type 8        Integer     1           Little
        // Byte 12      Xmin                Double      1           Little
        // Byte 20      Ymin                Double      1           Little
        // Byte 28      Xmax                Double      1           Little
        // Byte 36      Ymax                Double      1           Little
        // Byte 48      NumPoints           Integer     1           Little
        // Byte X       Points              Point       NumPoints   Little


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


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

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

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

            }

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


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

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


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

            int numShapes = shapeHeaders.Count;

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

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

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


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

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

                    // These are listed as "optional" but there isn't a good indicator of how to determine if they were added.
                    // To handle the "optional" M values, check the contentLength for the feature.
                    // The content length does not include the 8-byte record header and is listed in 16-bit words.
                    if (hasM)
                    {
                        double mMin = bbReader.ReadDouble();
                        double mMax = bbReader.ReadDouble();
                        
                        if (allM != null) allM.Read(shape.NumPoints * 8, bbReader);
                    }
                }
                // Now that we have read all the values, create the geometries from the points and parts arrays.
                ShapeIndices.Add(shape);
            }
            double[] vert = allCoords.ToDoubleArray();
            Vertex = vert;
            if (isM) M = allM.ToDoubleArray();
            if (isZ) Z = allZ.ToDoubleArray();
            Array.Reverse(bigEndians);
            List<ShapeRange> shapes = ShapeIndices;
            double[] bounds = new double[numShapes * 4];
            Buffer.BlockCopy(allBounds, 0, bounds, 0, allBounds.Length);
            for (int shp = 0; shp < numShapes; shp++)
            {
                ShapeRange shape = shapes[shp];
                shape.Extent = new Extent(bounds, shp * 4);
                int endIndex = shape.NumPoints + shape.StartIndex;
                int startIndex = shape.StartIndex;
                int count = endIndex - startIndex;
                PartRange partR = new PartRange(vert, shape.StartIndex, 0, FeatureTypes.MultiPoint);
                partR.NumVertices = count;
                shape.Parts.Add(partR);
            }
            GC.Collect();
            bbReader.Dispose();
        }
Example #15
0
        /// <summary>
        /// This creates a polygon shape from an extent. 
        /// </summary>
        /// <param name="ext">The extent to turn into a polygon shape.</param>
        public ShapeRange(Extent ext)
        {
            Extent = ext;
            Parts = new List<PartRange>();
            _numParts = -1;
            // Counter clockwise
            // 1 2
            // 4 3
            double[] coords = new double[8];
            // C1
            coords[0] = ext.XMin;
            coords[1] = ext.YMax;
            // C2
            coords[2] = ext.XMax;
            coords[3] = ext.YMax;
            // C3
            coords[4] = ext.XMax;
            coords[5] = ext.YMin;
            // C4
            coords[6] = ext.XMin;
            coords[7] = ext.YMin;

            FeatureType = FeatureTypes.Polygon;
            ShapeType = ShapeTypes.Polygon;
            PartRange pr = new PartRange(coords, 0,0, FeatureTypes.Polygon);
            pr.NumVertices = 4;
            Parts.Add(pr);
            
        }
 private static void ReadMultiLineString(Stream data, FeatureSetPack results)
 {
     int numLineStrings = ReadInt32(data);
     ShapeRange shp = new ShapeRange(FeatureTypes.Line);
     List<double[]> strings = new List<double[]>();
     int partOffset = 0;
     for(int iString = 0; iString < numLineStrings; iString++)
     {
         // Each of these needs to read a full WKBLineString
         data.Seek(5, SeekOrigin.Current); //ignore header
         int numPoints = ReadInt32(data);
         double[] coords = ReadDouble(data, 2*numPoints);
         PartRange lPrt = new PartRange(FeatureTypes.Line);
         lPrt.PartOffset = partOffset;
         lPrt.NumVertices = numPoints;
         shp.Parts.Add(lPrt);
         partOffset += coords.Length/2;
         strings.Add(coords);
     }
     double[] allVertices = new double[partOffset * 2];
     int offset = 0;
     foreach (double[] ring in strings)
     {
         Array.Copy(ring, 0, allVertices, offset, ring.Length);
         offset += ring.Length;
     }
     results.Add(allVertices, shp);
 }
Example #17
0
        /// <summary>
        /// Occurs when the vertices are being re-calculated.
        /// </summary>
        protected virtual void OnInitializeVertices()
        {
            int count = 0;
            foreach (IFeature f in _features)
            {
                count += f.NumPoints;
            }
            _vertices = new double[count*2];
            int i = 0;
            foreach(IFeature f in _features)
            {
                IList<Coordinate> coords = f.Coordinates; // this should be all the coordinates, for all parts of the geometry.

                if (coords == null) continue;
                foreach (Coordinate c in coords)
                {
                    _vertices[i*2] = c.X;
                    _vertices[i*2+1] = c.Y;
                    // vertexValues.Add(c.Values); // essentially add a reference pointer to the internal array of values
                    i++;
                }
            }
            //_vertices = vertexValues.ToArray(); // not sure, but I bet arrays a smidge faster at indexed access than lists

             
            _shapeIndices = new List<ShapeRange>();
            int vIndex = 0;
            for(int shp = 0; shp < _features.Count; shp++) 
            {
                IFeature f = _features[shp];
                

                ShapeRange shx = new ShapeRange(FeatureType);
                shx.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.
                shx.Parts = new List<PartRange>();
                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);
                            holex.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);
                }
                

            }
           // _vertices = vertexValues.ToArray();
            _verticesAreValid = true;
        }
        // X Y Poly Lines: Total Length = 28 Bytes
        // ---------------------------------------------------------
        // Position     Value               Type        Number      Byte Order
        // ---------------------------------------------------------
        // Byte 0       Record Number       Integer     1           Big
        // Byte 4       Content Length      Integer     1           Big
        // Byte 8       Shape Type 3        Integer     1           Little
        // Byte 12      Xmin                Double      1           Little
        // Byte 20      Ymin                Double      1           Little
        // Byte 28      Xmax                Double      1           Little
        // Byte 36      Ymax                Double      1           Little
        // Byte 44      NumParts            Integer     1           Little
        // Byte 48      NumPoints           Integer     1           Little
        // Byte 52      Parts               Integer     NumParts    Little
        // Byte X       Points              Point       NumPoints   Little


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

       


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

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

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

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

            }

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


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

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

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

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

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

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

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

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



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

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

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