/// <summary> /// Reads the header of a Shapefile /// </summary> /// <param name="reader">The Shapefile stream</param> /// <returns>The shapefile header</returns> private void ReadFileHeader(BinaryReader reader, out ShapefileShapeType shapeType, out BoundingBox bounds) { // Read File Code. int FileCode = NumberReader.ReadIntBE(reader); //Verify that the file has the correct file code (9994) if (FileCode != 9994) { throw new FormatException("Invalid FileCode encountered. Expecting a file code of 9994."); } //Skip unused section reader.BaseStream.Seek(20, SeekOrigin.Current); // Read the File Length. long fileLength = NumberReader.ReadIntBE(reader); // Skip the Version number of the shapefile. reader.BaseStream.Seek(4, SeekOrigin.Current); // Get the shape type of the shapefile. Note that shapefiles can only contain one type of shape per file shapeType = (ShapefileShapeType)NumberReader.ReadIntLE(reader); // Get the bounding box of the Bounding Box. bounds = ReadBoundingBox(reader); }
/// <summary> /// Reads LineString shapefile /// </summary> /// <param name="reader">The shapefile stream</param> /// <returns>A list of Geometry objects</returns> private async Task <List <Geometry> > ReadLineStringData(BinaryReader reader) { var items = new List <Geometry>(); int numParts, numPoints; while (reader.BaseStream.Position < reader.BaseStream.Length) { Geometry item; // Read Record Header. int id = ReadRecordHeader(reader); var boundingBox = ReadBoundingBox(reader); // Read the number of Parts and Points in the shape. numParts = NumberReader.ReadIntLE(reader); numPoints = NumberReader.ReadIntLE(reader); int[] parts = ReadParts(reader, numParts, numPoints); //First read all the rings var rings = new List <CoordinateCollection>(); var multiline = new MultiLineString(); for (int ringID = 0; ringID < numParts; ringID++) { var line = new LineString(); for (int i = parts[ringID]; i < parts[ringID + 1]; i++) { line.Vertices.Add(ReadCoordinate(reader)); } if (optimize) { line.Vertices = await SpatialTools.VertexReductionAsync(line.Vertices, tolerance); } multiline.Geometries.Add(line); } if (numParts == 1) { item = (Geometry)multiline.Geometries[0]; } else { item = multiline; } item.Metadata.ID = id.ToString(); item.Metadata.Properties.Add("BoundingBox", boundingBox); items.Add(item); } return(items); }
/// <summary> /// Read the Parts index array for a record /// </summary> /// <param name="reader">The Shapefile stream</param> /// <param name="numParts">The number of parts in the array</param> /// <param name="numPoints">The number of points in total</param> /// <returns>An array of part indexes</returns> private int[] ReadParts(BinaryReader reader, int numParts, int numPoints) { int[] parts = new int[numParts + 1]; for (int i = 0; i < numParts; i++) { parts[i] = NumberReader.ReadIntLE(reader); } parts[numParts] = numPoints; return(parts); }
/// <summary> /// Reads MultiPoint shapefile /// </summary> /// <param name="reader">The Shapefile stream</param> /// <returns>A list of Geometry objects</returns> private List <Geometry> ReadMultiPointData(BinaryReader reader) { var items = new List <Geometry>(); int numPoints; // For each header while (reader.BaseStream.Position < reader.BaseStream.Length) { Geometry item; // Read Record Header. int id = ReadRecordHeader(reader); var boundingBox = ReadBoundingBox(reader); // Num Points. numPoints = NumberReader.ReadIntLE(reader); if (numPoints == 1) //if there is only one point then create a point geography { item = new Point(ReadCoordinate(reader)); } else { MultiPoint mp = new MultiPoint(numPoints); // Read in all the Points. for (int i = 0; i < numPoints; i++) { mp.Geometries.Add(new Point(ReadCoordinate(reader))); } item = mp; } item.Metadata.ID = id.ToString(); item.Metadata.Properties.Add("Bounding Box", boundingBox); items.Add(item); } return(items); }
/// <summary> /// Read a shapefile Polygon record. /// </summary> /// <param name="reader">The Shapefile stream</param> /// <returns>A list of Geometry objects</returns> private List <Geometry> ReadPolygonData(BinaryReader reader) { var items = new List <Geometry>(); int numParts, numPoints; while (reader.BaseStream.Position < reader.BaseStream.Length) { Geometry item; // Read Record Header. int id = ReadRecordHeader(reader); var boundingBox = ReadBoundingBox(reader); // Read the number of Parts and Points in the shape. numParts = NumberReader.ReadIntLE(reader); numPoints = NumberReader.ReadIntLE(reader); int[] parts = ReadParts(reader, numParts, numPoints); //First read all the rings var rings = new List <CoordinateCollection>(); for (int ringID = 0; ringID < numParts; ringID++) { var ring = new CoordinateCollection(); for (int i = parts[ringID]; i < parts[ringID + 1]; i++) { ring.Add(ReadCoordinate(reader)); } if (optimize) { ring = SpatialTools.VertexReduction(ring, tolerance); } rings.Add(ring); } // Vertices for a single, ringed polygon are always in clockwise order. // Rings defining holes in these polygons have a counterclockwise orientation. bool[] IsCounterClockWise = new bool[rings.Count]; int PolygonCount = 0; //determine the orientation of each ring. for (int i = 0; i < rings.Count; i++) { IsCounterClockWise[i] = rings[i].IsCCW(); if (!IsCounterClockWise[i]) { PolygonCount++; //count the number of polygons } } //if the polygon count is 1 then there is only one polygon to create. if (PolygonCount == 1) { Polygon polygon = new Polygon(); polygon.ExteriorRing = rings[0]; if (rings.Count > 1) { for (int i = 1; i < rings.Count; i++) { polygon.InteriorRings.Add(rings[i]); } } item = polygon; } else { MultiPolygon multPolygon = new MultiPolygon(); Polygon poly = new Polygon(); poly.ExteriorRing = rings[0]; for (int i = 1; i < rings.Count; i++) { if (!IsCounterClockWise[i]) { multPolygon.Geometries.Add(poly); poly = new Polygon(rings[i]); } else { poly.InteriorRings.Add(rings[i]); } } multPolygon.Geometries.Add(poly); item = multPolygon; } item.Metadata.ID = id.ToString(); item.Metadata.Properties.Add("Bounding Box", boundingBox); items.Add(item); } return(items); }