/// <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, GeometryFactory 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 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.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++) { Coordinate external = new Coordinate(file.ReadDouble(), file.ReadDouble()); new PrecisionModel(geometryFactory.PrecisionModel).MakePrecise(external); Coordinate internalCoord = external; points.Add(internalCoord); } ILinearRing ring = geometryFactory.CreateLinearRing((Coordinate[])points.ToArray(typeof(Coordinate))); // 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((Coordinate[])points.ToArray(typeof(Coordinate)))) { 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++) { LinearRing testRing = (LinearRing)holes[i]; LinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; ICoordinate testPt = testRing.GetCoordinateN(0); LinearRing tryRing; for (int j = 0; j < shells.Count; j++) { tryRing = (LinearRing)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, (Coordinate[])coordList.ToArray(typeof(Coordinate))) || (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(holes[i]); } } } IPolygon[] polygons = new Polygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = geometryFactory.CreatePolygon((LinearRing)shells[i], (LinearRing[])((ArrayList)holesForShells[i]).ToArray(typeof(LinearRing))); } if (polygons.Length == 1) { return(polygons[0]); } // It's a multi part return(geometryFactory.CreateMultiPolygon(polygons)); }
/// <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 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 virtual 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> /// 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);