/// <summary> /// Initializes a new instance of the ShapefileHeader class with values read in from the stream. /// </summary> /// <remarks>Reads the header information from the stream.</remarks> /// <param name="shpBinaryReader">BigEndianBinaryReader stream to the shapefile.</param> public ShapefileHeader(BigEndianBinaryReader shpBinaryReader) { if (shpBinaryReader == null) throw new ArgumentNullException("shpBinaryReader"); _fileCode = shpBinaryReader.ReadInt32BE(); if (_fileCode != Shapefile.ShapefileId) throw new ShapefileException("The first four bytes of this file indicate this is not a shape file."); // skip 5 unsed bytes shpBinaryReader.ReadInt32BE(); shpBinaryReader.ReadInt32BE(); shpBinaryReader.ReadInt32BE(); shpBinaryReader.ReadInt32BE(); shpBinaryReader.ReadInt32BE(); _fileLength = shpBinaryReader.ReadInt32BE(); _version = shpBinaryReader.ReadInt32(); Debug.Assert(_version == 1000, "Shapefile version", String.Format("Expecting only one version (1000), but got {0}",_version)); int shapeType = shpBinaryReader.ReadInt32(); _shapeType = (ShapeGeometryTypes) Enum.Parse(typeof(ShapeGeometryTypes), shapeType.ToString()); //read in and store the bounding box double[] coords = new double[4]; for (int i = 0; i < 4; i++) coords[i] = shpBinaryReader.ReadDouble(); _bounds = new Envelope(coords[0], coords[2], coords[1], coords[3]); // skip z and m bounding boxes. for (int i = 0; i < 4; i++) shpBinaryReader.ReadDouble(); }
/// <summary> /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// </summary> /// <param name="file">The stream to read.</param> /// <param name="geometryFactory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public override IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory) { int shapeTypeNum = file.ReadInt32(); ShapeGeometryTypes shapeType = (ShapeGeometryTypes) Enum.Parse(typeof(ShapeGeometryTypes), shapeTypeNum.ToString()); if (shapeType == ShapeGeometryTypes.NullShape) return null; if ( ! ( shapeType == ShapeGeometryTypes.Point || shapeType == ShapeGeometryTypes.PointM || shapeType == ShapeGeometryTypes.PointZ || shapeType == ShapeGeometryTypes.PointZM )) throw new ShapefileException("Attempting to load a point as point."); double x= file.ReadDouble(); double y= file.ReadDouble(); ICoordinate external = new Coordinate(x,y); geometryFactory.PrecisionModel.MakePrecise( external); return geometryFactory.CreatePoint(external); }
/// <summary> /// Initializes a new instance of the Shapefile class with the given parameters. /// </summary> /// <param name="filename">The filename of the shape file to read (with .shp).</param> /// <param name="geometryFactory">The GeometryFactory to use when creating Geometry objects.</param> public ShapefileReader(string filename, IGeometryFactory geometryFactory) { if (filename == null) throw new ArgumentNullException("filename"); if (geometryFactory == null) throw new ArgumentNullException("geometryFactory"); _filename = filename; _geometryFactory = geometryFactory; // read header information. note, we open the file, read the header information and then // close the file. This means the file is not opened again until GetEnumerator() is requested. // For each call to GetEnumerator() a new BinaryReader is created. FileStream stream = new FileStream(filename, System.IO.FileMode.Open, FileAccess.Read, FileShare.Read); BigEndianBinaryReader shpBinaryReader = new BigEndianBinaryReader(stream); _mainHeader = new ShapefileHeader(shpBinaryReader); shpBinaryReader.Close(); }
/// <summary> /// Reads Polygon shapefile /// </summary> /// <param name="stream"></param> /// <returns></returns> protected IList ReadPolygonData(Stream stream) { IList list = new ArrayList(); // Jump to first header stream.Seek(100, SeekOrigin.Begin); // Read big endian informations using (BigEndianBinaryReader beReader = new BigEndianBinaryReader(stream)) { // Read little endian informations using (BinaryReader reader = new BinaryReader(stream)) { // For each header while (stream.Position < stream.Length) { ReadFeatureHeader(beReader); shapeReader.ReadBoundingBox(reader); int[] indexParts = null; int numParts = shapeReader.ReadNumParts(reader); int numPoints = shapeReader.ReadNumPoints(reader); indexParts = shapeReader.ReadIndexParts(reader, numParts); ICoordinate[] coordinates = shapeReader.ReadCoordinates(reader, numPoints); if (numParts == 1) { list.Add(shapeReader.CreateSimpleSinglePolygon(coordinates)); } else { list.Add(shapeReader.CreateSingleOrMultiPolygon(numPoints, indexParts, coordinates)); } } } } return(list); }
/// <summary> /// Reads a stream and converts the shapefile record to an equilivant geometry object. /// </summary> /// <param name="file">The stream to read.</param> /// <param name="geometryFactory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public override IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory) { int shapeTypeNum = file.ReadInt32(); ShapeGeometryTypes shapeType = (ShapeGeometryTypes) Enum.Parse(typeof(ShapeGeometryTypes), shapeTypeNum.ToString()); if (shapeType == ShapeGeometryTypes.NullShape) return null; if ( ! ( shapeType == ShapeGeometryTypes.MultiPoint || shapeType == ShapeGeometryTypes.MultiPointM || shapeType == ShapeGeometryTypes.MultiPointZ || shapeType == ShapeGeometryTypes.MultiPointZM)) throw new ShapefileException("Attempting to load a non-multipoint as multipoint."); // Read and for now ignore bounds. double[] box = new double[4]; for (int i = 0; i < 4; i++) box[i] = file.ReadDouble(); // Read points int numPoints = file.ReadInt32(); IPoint[] points = new IPoint[numPoints]; for (int i = 0; i < numPoints; i++) points[i] = geometryFactory.CreatePoint(new Coordinate(file.ReadDouble(), file.ReadDouble())); return geometryFactory.CreateMultiPoint(points); }
/// <summary> /// Initializes a new instance of the Shapefile class with the given parameters. /// </summary> /// <param name="filename">The filename of the shape file to read (with .shp).</param> /// <param name="geometryFactory">The GeometryFactory to use when creating Geometry objects.</param> public ShapefileReader(string filename, IGeometryFactory geometryFactory) { if (filename == null) { throw new ArgumentNullException("filename"); } if (geometryFactory == null) { throw new ArgumentNullException("geometryFactory"); } _filename = filename; _geometryFactory = geometryFactory; // read header information. note, we open the file, read the header information and then // close the file. This means the file is not opened again until GetEnumerator() is requested. // For each call to GetEnumerator() a new BinaryReader is created. FileStream stream = new FileStream(filename, System.IO.FileMode.Open, FileAccess.Read, FileShare.Read); BigEndianBinaryReader shpBinaryReader = new BigEndianBinaryReader(stream); _mainHeader = new ShapefileHeader(shpBinaryReader); shpBinaryReader.Close(); }
/// <summary> /// Reads a generic stream containing geographic data saved as shapefile structure, /// and returns a collection of all the features contained. /// Since NTS Geometry Model not support Z and M data, those informations are ignored if presents in shapefile. /// </summary> /// <param name="stream">Shapefile data stream.</param> /// <returns><c>GeometryCollection</c> containing all geometries in shapefile.</returns> protected IGeometryCollection Read(Stream stream) { // Read big endian values using (BigEndianBinaryReader beReader = new BigEndianBinaryReader(stream)) { // Verify File Code int fileCode = beReader.ReadInt32BE(); Debug.Assert(fileCode == 9994); stream.Seek(20, SeekOrigin.Current); length = beReader.ReadInt32BE(); // Read little endian values using (BinaryReader leReader = new BinaryReader(stream)) { ArrayList list = null; // Verify Version int version = leReader.ReadInt32(); Debug.Assert(version == 1000); // ShapeTypes int shapeType = leReader.ReadInt32(); switch ((ShapeGeometryTypes) shapeType) { case ShapeGeometryTypes.Point: case ShapeGeometryTypes.PointZ: case ShapeGeometryTypes.PointM: case ShapeGeometryTypes.PointZM: list = new ArrayList(ReadPointData(stream)); break; case ShapeGeometryTypes.LineString: case ShapeGeometryTypes.LineStringZ: case ShapeGeometryTypes.LineStringM: case ShapeGeometryTypes.LineStringZM: list = new ArrayList(ReadLineStringData(stream)); break; case ShapeGeometryTypes.Polygon: case ShapeGeometryTypes.PolygonZ: case ShapeGeometryTypes.PolygonM: case ShapeGeometryTypes.PolygonZM: list = new ArrayList(ReadPolygonData(stream)); break; case ShapeGeometryTypes.MultiPoint: case ShapeGeometryTypes.MultiPointZ: case ShapeGeometryTypes.MultiPointM: case ShapeGeometryTypes.MultiPointZM: list = new ArrayList(ReadMultiPointData(stream)); break; case ShapeGeometryTypes.MultiPatch: throw new NotImplementedException("FeatureType " + shapeType + " not supported."); default: throw new ArgumentOutOfRangeException("FeatureType " + shapeType + " not recognized by the system"); } IGeometryCollection collection = shapeReader.CreateGeometryCollection(list); return collection; } } }
/// <summary> /// /// </summary> /// <param name="beReader"></param> private void ReadFeatureHeader(BigEndianBinaryReader beReader) { int recordNumber = beReader.ReadInt32BE(); int contentLength = beReader.ReadInt32BE(); int shapeType = beReader.ReadInt32(); }
/// <summary> /// Reads Polygon shapefile /// </summary> /// <param name="stream"></param> /// <returns></returns> protected IList ReadPolygonData(Stream stream) { IList list = new ArrayList(); // Jump to first header stream.Seek(100, SeekOrigin.Begin); // Read big endian informations using (BigEndianBinaryReader beReader = new BigEndianBinaryReader(stream)) { // Read little endian informations using (BinaryReader reader = new BinaryReader(stream)) { // For each header while (stream.Position < stream.Length) { ReadFeatureHeader(beReader); shapeReader.ReadBoundingBox(reader); int[] indexParts = null; int numParts = shapeReader.ReadNumParts(reader); int numPoints = shapeReader.ReadNumPoints(reader); indexParts = shapeReader.ReadIndexParts(reader, numParts); ICoordinate[] coordinates = shapeReader.ReadCoordinates(reader, numPoints); if (numParts == 1) list.Add(shapeReader.CreateSimpleSinglePolygon(coordinates)); else list.Add(shapeReader.CreateSingleOrMultiPolygon(numPoints, indexParts, coordinates)); } } } return list; }
/// <summary> /// Reads Point shapefile /// </summary> /// <param name="stream"></param> protected IList ReadPointData(Stream stream) { IList list = new ArrayList(); // Jump to first header stream.Seek(100, SeekOrigin.Begin); // Read big endian informations using (BigEndianBinaryReader beReader = new BigEndianBinaryReader(stream)) { // Read little endian informations using (BinaryReader leReader = new BinaryReader(stream)) { // For each header while (stream.Position < stream.Length) { ReadFeatureHeader(beReader); ICoordinate coordinate = shapeReader.ReadCoordinate(leReader); IGeometry point = shapeReader.CreatePoint(coordinate); list.Add(point); } } } return list; }
/// <summary> /// Reads MultiPoint shapefile /// </summary> /// <param name="stream"></param> /// <returns></returns> protected IList ReadMultiPointData(Stream stream) { IList list = new ArrayList(); // Jump to first header stream.Seek(100, SeekOrigin.Begin); // Read big endian informations using (BigEndianBinaryReader beReader = new BigEndianBinaryReader(stream)) { // Read little endian informations using (BinaryReader reader = new BinaryReader(stream)) { // For each header while (stream.Position < stream.Length) { ReadFeatureHeader(beReader); shapeReader.ReadBoundingBox(reader); int numPoints = shapeReader.ReadNumPoints(reader); ICoordinate[] coords = new ICoordinate[numPoints]; for (int i = 0; i < numPoints; i++) coords[i] = shapeReader.ReadCoordinate(reader); list.Add(shapeReader.CreateMultiPoint(coords)); } } } return list; }
/// <summary> /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// </summary> /// <param name="file">The stream to read.</param> /// <param name="geometryFactory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public abstract IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory);
/// <summary> /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// </summary> /// <param name="file">The stream to read.</param> /// <param name="geometryFactory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public override IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory) { int shapeTypeNum = file.ReadInt32(); ShapeGeometryTypes shapeType = (ShapeGeometryTypes)Enum.Parse(typeof(ShapeGeometryTypes), shapeTypeNum.ToString()); if (shapeType == ShapeGeometryTypes.NullShape) return null; if( ! ( shapeType == ShapeGeometryTypes.LineString || shapeType == ShapeGeometryTypes.LineStringM || shapeType == ShapeGeometryTypes.LineStringZ || shapeType == ShapeGeometryTypes.LineStringZM )) throw new ShapefileException("Attempting to load a non-arc as arc."); //read and for now ignore bounds. double[] box = new double[4]; for (int i = 0; i < 4; i++) { double d= file.ReadDouble(); box[i] =d; } int numParts = file.ReadInt32(); int numPoints = file.ReadInt32(); int[] partOffsets = new int[numParts]; for (int i = 0; i < numParts; i++) partOffsets[i] = file.ReadInt32(); ILineString[] lines = new ILineString[numParts]; int start, finish, length; for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) finish = numPoints; else finish = partOffsets[part + 1]; length = finish - start; CoordinateList points = new CoordinateList(); points.Capacity=length; ICoordinate external; for (int i = 0; i < length; i++) { external = new Coordinate(file.ReadDouble(),file.ReadDouble()); geometryFactory.PrecisionModel.MakePrecise( external); points.Add(external); } if (numPoints < 2) lines[part] = geometryFactory.CreateLineString(null as Topology.Geometries.ICoordinate[]); else lines[part] = geometryFactory.CreateLineString(points.ToArray()); } //If we have Z-coordinates, read them.. if (shapeType == ShapeGeometryTypes.LineStringZ || shapeType == ShapeGeometryTypes.LineStringZM) { //z-Bounds double zMin = file.ReadDouble(); double zMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) finish = numPoints; else finish = partOffsets[part + 1]; length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); if (numPoints > 1) { lines[part].Coordinates[i].Z = val; } } } } //If we have M-coordinates, read them.. if (shapeType == ShapeGeometryTypes.LineStringM || shapeType == ShapeGeometryTypes.LineStringZM) { //m-Bounds double mMin = file.ReadDouble(); double mMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) finish = numPoints; else finish = partOffsets[part + 1]; length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); //dont store.. } } } return geometryFactory.CreateMultiLineString(lines); }
public void Dispose() { if (_shpBinaryReader != null) { _shpBinaryReader.Close(); _shpBinaryReader = null; } }
/// <summary> /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// </summary> /// <param name="file">The stream to read.</param> /// <param name="geometryFactory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public override IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory) { int shapeTypeNum = file.ReadInt32(); ShapeGeometryTypes shapeType = (ShapeGeometryTypes)Enum.Parse(typeof(ShapeGeometryTypes), shapeTypeNum.ToString()); if (shapeType == ShapeGeometryTypes.NullShape) { return(null); } if (!(shapeType == ShapeGeometryTypes.LineString || shapeType == ShapeGeometryTypes.LineStringM || shapeType == ShapeGeometryTypes.LineStringZ || shapeType == ShapeGeometryTypes.LineStringZM)) { throw new ShapefileException("Attempting to load a non-arc as arc."); } //read and for now ignore bounds. double[] box = new double[4]; for (int i = 0; i < 4; i++) { double d = file.ReadDouble(); box[i] = d; } int numParts = file.ReadInt32(); int numPoints = file.ReadInt32(); int[] partOffsets = new int[numParts]; for (int i = 0; i < numParts; i++) { partOffsets[i] = file.ReadInt32(); } ILineString[] lines = new ILineString[numParts]; int start, finish, length; for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) { finish = numPoints; } else { finish = partOffsets[part + 1]; } length = finish - start; CoordinateList points = new CoordinateList(); points.Capacity = length; ICoordinate external; for (int i = 0; i < length; i++) { external = new Coordinate(file.ReadDouble(), file.ReadDouble()); geometryFactory.PrecisionModel.MakePrecise(external); points.Add(external); } if (numPoints < 2) { lines[part] = geometryFactory.CreateLineString(null as Topology.Geometries.ICoordinate[]); } else { lines[part] = geometryFactory.CreateLineString(points.ToArray()); } } //If we have Z-coordinates, read them.. if (shapeType == ShapeGeometryTypes.LineStringZ || shapeType == ShapeGeometryTypes.LineStringZM) { //z-Bounds double zMin = file.ReadDouble(); double zMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) { finish = numPoints; } else { finish = partOffsets[part + 1]; } length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); if (numPoints > 1) { lines[part].Coordinates[i].Z = val; } } } } //If we have M-coordinates, read them.. if (shapeType == ShapeGeometryTypes.LineStringM || shapeType == ShapeGeometryTypes.LineStringZM) { //m-Bounds double mMin = file.ReadDouble(); double mMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) { finish = numPoints; } else { finish = partOffsets[part + 1]; } length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); //dont store.. } } } return(geometryFactory.CreateMultiLineString(lines)); }
/// <summary> /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// </summary> /// <param name="file">The stream to read.</param> /// <param name="geometryFactory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public override IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory) { int shapeTypeNum = file.ReadInt32(); ShapeGeometryTypes shapeType = (ShapeGeometryTypes)Enum.Parse(typeof(ShapeGeometryTypes), shapeTypeNum.ToString()); if (shapeType == ShapeGeometryTypes.NullShape) return null; if ( ! ( shapeType == ShapeGeometryTypes.Polygon || shapeType == ShapeGeometryTypes.PolygonM || shapeType == ShapeGeometryTypes.PolygonZ || shapeType == ShapeGeometryTypes.PolygonZM)) throw new ShapefileException("Attempting to load a non-polygon as polygon."); // Read and for now ignore bounds. double[] box = new double[4]; for (int i = 0; i < 4; i++) box[i] = file.ReadDouble(); int[] partOffsets; int numParts = file.ReadInt32(); int numPoints = file.ReadInt32(); partOffsets = new int[numParts]; for (int i = 0; i < numParts; i++) partOffsets[i] = file.ReadInt32(); ArrayList shells = new ArrayList(); ArrayList holes = new ArrayList(); int start, finish, length; for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) finish = numPoints; else finish = partOffsets[part + 1]; length = finish - start; CoordinateList points = new CoordinateList(); points.Capacity = length; for (int i = 0; i < length; i++) { ICoordinate external = new Coordinate(file.ReadDouble(), file.ReadDouble() ); geometryFactory.PrecisionModel.MakePrecise( external); ICoordinate internalCoord = external; // Thanks to Abhay Menon! if (!Double.IsNaN(internalCoord.Y) && !Double.IsNaN(internalCoord.X)) points.Add(internalCoord); } if (points.Count > 0) // Thanks to Abhay Menon! { ILinearRing ring = geometryFactory.CreateLinearRing(points.ToArray()); // If shape have only a part, jump orientation check and add to shells if (numParts == 1) shells.Add(ring); else { // Orientation check if (CGAlgorithms.IsCCW(points.ToArray())) holes.Add(ring); else shells.Add(ring); } } } // Now we have a list of all shells and all holes ArrayList holesForShells = new ArrayList(shells.Count); for (int i = 0; i < shells.Count; i++) holesForShells.Add(new ArrayList()); // Find holes for (int i = 0; i < holes.Count; i++) { ILinearRing testRing = (ILinearRing) holes[i]; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; ICoordinate testPt = testRing.GetCoordinateN(0); ILinearRing tryRing; for (int j = 0; j < shells.Count; j++) { tryRing = (ILinearRing) shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) minEnv = minShell.EnvelopeInternal; bool isContained = false; CoordinateList coordList = new CoordinateList(tryRing.Coordinates); if (tryEnv.Contains(testEnv) && (CGAlgorithms.IsPointInRing(testPt, coordList.ToArray()) || (PointInList(testPt, coordList)))) isContained = true; // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) minShell = tryRing; // Suggested by Brian Macomber and added 3/28/2006: // holes were being found but never added to the holesForShells array // so when converted to geometry by the factory, the inner rings were never created. ArrayList holesForThisShell = (ArrayList) holesForShells[j]; holesForThisShell.Add(testRing); } } } //If we have Z-coordinates, read them.. if (shapeType == ShapeGeometryTypes.PolygonZ || shapeType == ShapeGeometryTypes.PolygonZM) { //z-Bounds double zMin = file.ReadDouble(); double zMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) finish = numPoints; else finish = partOffsets[part + 1]; length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); //lines[part].Coordinates[i].Z = val; } } } //If we have M-coordinates, read them.. if (shapeType == ShapeGeometryTypes.PolygonM || shapeType == ShapeGeometryTypes.PolygonZM) { //m-Bounds double mMin = file.ReadDouble(); double mMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) finish = numPoints; else finish = partOffsets[part + 1]; length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); //dont store.. } } } IPolygon[] polygons = new IPolygon[shells.Count]; for (int i = 0; i < shells.Count; i++) polygons[i] = (geometryFactory.CreatePolygon((ILinearRing) shells[i], (ILinearRing[]) ((ArrayList)holesForShells[i]).ToArray(typeof(ILinearRing)))); if (polygons.Length == 1) return polygons[0]; // It's a multi part return geometryFactory.CreateMultiPolygon(polygons); }
/// <summary> /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// </summary> /// <param name="file">The stream to read.</param> /// <param name="geometryFactory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public override IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory) { int shapeTypeNum = file.ReadInt32(); ShapeGeometryTypes shapeType = (ShapeGeometryTypes)Enum.Parse(typeof(ShapeGeometryTypes), shapeTypeNum.ToString()); if (shapeType == ShapeGeometryTypes.NullShape) { return(null); } if (!(shapeType == ShapeGeometryTypes.Polygon || shapeType == ShapeGeometryTypes.PolygonM || shapeType == ShapeGeometryTypes.PolygonZ || shapeType == ShapeGeometryTypes.PolygonZM)) { throw new ShapefileException("Attempting to load a non-polygon as polygon."); } // Read and for now ignore bounds. double[] box = new double[4]; for (int i = 0; i < 4; i++) { box[i] = file.ReadDouble(); } int[] partOffsets; int numParts = file.ReadInt32(); int numPoints = file.ReadInt32(); partOffsets = new int[numParts]; for (int i = 0; i < numParts; i++) { partOffsets[i] = file.ReadInt32(); } ArrayList shells = new ArrayList(); ArrayList holes = new ArrayList(); int start, finish, length; for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) { finish = numPoints; } else { finish = partOffsets[part + 1]; } length = finish - start; CoordinateList points = new CoordinateList(); points.Capacity = length; for (int i = 0; i < length; i++) { ICoordinate external = new Coordinate(file.ReadDouble(), file.ReadDouble()); geometryFactory.PrecisionModel.MakePrecise(external); ICoordinate internalCoord = external; // Thanks to Abhay Menon! if (!Double.IsNaN(internalCoord.Y) && !Double.IsNaN(internalCoord.X)) { points.Add(internalCoord); } } if (points.Count > 0) // Thanks to Abhay Menon! { ILinearRing ring = geometryFactory.CreateLinearRing(points.ToArray()); // If shape have only a part, jump orientation check and add to shells if (numParts == 1) { shells.Add(ring); } else { // Orientation check if (CGAlgorithms.IsCCW(points.ToArray())) { holes.Add(ring); } else { shells.Add(ring); } } } } // Now we have a list of all shells and all holes ArrayList holesForShells = new ArrayList(shells.Count); for (int i = 0; i < shells.Count; i++) { holesForShells.Add(new ArrayList()); } // Find holes for (int i = 0; i < holes.Count; i++) { ILinearRing testRing = (ILinearRing)holes[i]; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; ICoordinate testPt = testRing.GetCoordinateN(0); ILinearRing tryRing; for (int j = 0; j < shells.Count; j++) { tryRing = (ILinearRing)shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.EnvelopeInternal; } bool isContained = false; CoordinateList coordList = new CoordinateList(tryRing.Coordinates); if (tryEnv.Contains(testEnv) && (CGAlgorithms.IsPointInRing(testPt, coordList.ToArray()) || (PointInList(testPt, coordList)))) { isContained = true; } // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryRing; } // Suggested by Brian Macomber and added 3/28/2006: // holes were being found but never added to the holesForShells array // so when converted to geometry by the factory, the inner rings were never created. ArrayList holesForThisShell = (ArrayList)holesForShells[j]; holesForThisShell.Add(testRing); } } } //If we have Z-coordinates, read them.. if (shapeType == ShapeGeometryTypes.PolygonZ || shapeType == ShapeGeometryTypes.PolygonZM) { //z-Bounds double zMin = file.ReadDouble(); double zMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) { finish = numPoints; } else { finish = partOffsets[part + 1]; } length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); //lines[part].Coordinates[i].Z = val; } } } //If we have M-coordinates, read them.. if (shapeType == ShapeGeometryTypes.PolygonM || shapeType == ShapeGeometryTypes.PolygonZM) { //m-Bounds double mMin = file.ReadDouble(); double mMax = file.ReadDouble(); for (int part = 0; part < numParts; part++) { start = partOffsets[part]; if (part == numParts - 1) { finish = numPoints; } else { finish = partOffsets[part + 1]; } length = finish - start; for (int i = 0; i < length; i++) { double val = file.ReadDouble(); //dont store.. } } } IPolygon[] polygons = new IPolygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = (geometryFactory.CreatePolygon((ILinearRing)shells[i], (ILinearRing[])((ArrayList)holesForShells[i]).ToArray(typeof(ILinearRing)))); } if (polygons.Length == 1) { return(polygons[0]); } // It's a multi part return(geometryFactory.CreateMultiPolygon(polygons)); }
/// <summary> /// Reads a generic stream containing geographic data saved as shapefile structure, /// and returns a collection of all the features contained. /// Since NTS Geometry Model not support Z and M data, those informations are ignored if presents in shapefile. /// </summary> /// <param name="stream">Shapefile data stream.</param> /// <returns><c>GeometryCollection</c> containing all geometries in shapefile.</returns> protected IGeometryCollection Read(Stream stream) { // Read big endian values using (BigEndianBinaryReader beReader = new BigEndianBinaryReader(stream)) { // Verify File Code int fileCode = beReader.ReadInt32BE(); Debug.Assert(fileCode == 9994); stream.Seek(20, SeekOrigin.Current); length = beReader.ReadInt32BE(); // Read little endian values using (BinaryReader leReader = new BinaryReader(stream)) { ArrayList list = null; // Verify Version int version = leReader.ReadInt32(); Debug.Assert(version == 1000); // ShapeTypes int shapeType = leReader.ReadInt32(); switch ((ShapeGeometryTypes)shapeType) { case ShapeGeometryTypes.Point: case ShapeGeometryTypes.PointZ: case ShapeGeometryTypes.PointM: case ShapeGeometryTypes.PointZM: list = new ArrayList(ReadPointData(stream)); break; case ShapeGeometryTypes.LineString: case ShapeGeometryTypes.LineStringZ: case ShapeGeometryTypes.LineStringM: case ShapeGeometryTypes.LineStringZM: list = new ArrayList(ReadLineStringData(stream)); break; case ShapeGeometryTypes.Polygon: case ShapeGeometryTypes.PolygonZ: case ShapeGeometryTypes.PolygonM: case ShapeGeometryTypes.PolygonZM: list = new ArrayList(ReadPolygonData(stream)); break; case ShapeGeometryTypes.MultiPoint: case ShapeGeometryTypes.MultiPointZ: case ShapeGeometryTypes.MultiPointM: case ShapeGeometryTypes.MultiPointZM: list = new ArrayList(ReadMultiPointData(stream)); break; case ShapeGeometryTypes.MultiPatch: throw new NotImplementedException("FeatureType " + shapeType + " not supported."); default: throw new ArgumentOutOfRangeException("FeatureType " + shapeType + " not recognized by the system"); } IGeometryCollection collection = shapeReader.CreateGeometryCollection(list); return(collection); } } }
/// <summary> /// Initializes a new instance of the ShapefileEnumerator class. /// </summary> /// <param name="shapefile"></param> public ShapefileEnumerator(ShapefileReader shapefile) { _parent = shapefile; // create a file stream for each enumerator that is given out. This allows the same file // to have one or more enumerator. If we used the parents stream - than only one IEnumerator // could be given out. FileStream stream = new FileStream(_parent._filename, System.IO.FileMode.Open, FileAccess.Read, FileShare.Read); _shpBinaryReader = new BigEndianBinaryReader(stream); // skip header - since parent has already read this. _shpBinaryReader.ReadBytes(100); ShapeGeometryTypes type = _parent._mainHeader.ShapeType; _handler = Shapefile.GetShapeHandler(type); if (_handler == null) throw new NotSupportedException("Unsuported shape type:" + type); }