public static List<IFeature> Select(this IFeatureSet self, Shape shape, SpatialPredicate predicate = SpatialPredicate.Intersects) { var result = new List<IFeature>(); var pg = new NetTopologySuite.Geometries.Prepared.PreparedGeometryFactory().Create(shape.ToGeoAPI()); foreach (var feat in self.Features) { var valid = false; var tryShape = feat.ToShape().ToGeoAPI(); switch (predicate) { case SpatialPredicate.Intersects: valid = pg.Intersects(tryShape); break; case SpatialPredicate.Overlaps: valid = pg.Overlaps(tryShape); break; case SpatialPredicate.Touches: valid = pg.Touches(tryShape); break; case SpatialPredicate.Within: valid = pg.Within(tryShape); break; case SpatialPredicate.Contains: valid = pg.Contains(tryShape); break; case SpatialPredicate.ContainsProperly: valid = pg.ContainsProperly(tryShape); break; case SpatialPredicate.Covers: valid = pg.Covers(tryShape); break; case SpatialPredicate.CoveredBy: valid = pg.CoveredBy(tryShape); break; case SpatialPredicate.Disjoint: valid = pg.Disjoint(tryShape); break; } if (valid) result.Add(feat); } return result; }
/// <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; }
/// <summary> /// Finish the shape. /// </summary> /// <param name="sender">The object sender.</param> /// <param name="e">An empty EventArgs class.</param> public void FinishShape(object sender, EventArgs e) { if (_featureSet != null && !_featureSet.IsDisposed) { Feature f = null; if (_featureSet.FeatureType == FeatureType.MultiPoint) { f = new Feature(new MultiPoint(_coordinates)); } if (_featureSet.FeatureType == FeatureType.Line || _featureSet.FeatureType == FeatureType.Polygon) { FinishPart(sender, e); Shape shp = new Shape(_featureSet.FeatureType); foreach (List<Coordinate> part in _parts) { if (part.Count >= 2) { shp.AddPart(part, _featureSet.CoordinateType); } } f = new Feature(shp); } if (f != null) { _featureSet.Features.Add(f); } _featureSet.InvalidateVertices(); _featureSet.UpdateExtent(); } _coordinates = new List<Coordinate>(); _parts = new List<List<Coordinate>>(); }
/// <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; }
/// <inheritdoc/> public void AddShape(Shape shape) { IFeature addedFeature; // This first section controls the indices which need to happen regardless // because drawing uses indices even if editors like working with features. int count = (_vertices != null) ? _vertices.Length / 2 : 0; // Original number of points int totalCount = shape.Range.NumPoints + count; int start = shape.Range.StartIndex; int num = shape.Range.NumPoints; double[] vertices = new double[totalCount * 2]; if (_vertices != null) { Array.Copy(_vertices, 0, vertices, 0, _vertices.Length); } if (shape.Vertices != null) { Array.Copy(shape.Vertices, start * 2, vertices, count * 2, num * 2); if (_m != null || shape.M != null) { double[] m = new double[totalCount]; if (_m != null) { Array.Copy(_m, 0, m, 0, _m.Length); } if (shape.M != null) { Array.Copy(shape.Vertices, start, m, count, num); } _m = m; } if (_z != null || shape.Z != null) { double[] z = new double[totalCount]; if (_z != null) { Array.Copy(_z, 0, z, 0, _z.Length); } if (shape.Z != null) { Array.Copy(shape.Vertices, start, z, count, num); } _z = z; } } shape.Range.StartIndex = count; ShapeIndices.Add(shape.Range); Vertex = vertices; if (Extent == null) { Extent = new Extent(); } Extent.ExpandToInclude(shape.Range.Extent); if (!IndexMode) { // Just add a new feature addedFeature = new Feature(shape); Features.Add(addedFeature); addedFeature.DataRow = AddAttributes(shape); if (!shape.Range.Extent.IsEmpty()) { Extent.ExpandToInclude(new Extent(addedFeature.Envelope)); } } }
/// <summary> /// handles the attributes while adding a shape /// </summary> /// <param name="shape"> /// </param> /// <returns> /// A data row, but only if attributes are populated /// </returns> private DataRow AddAttributes(Shape shape) { // Handle attributes if the array is not null. Assumes compatible schema. if (shape.Attributes != null) { DataColumn[] columns = GetColumns(); Dictionary<string, object> rowContent = new Dictionary<string, object>(); object[] fixedContent = new object[columns.Length]; DataRow addedRow; if (shape.Attributes.Length != columns.Length) { throw new ArgumentException("Attribute column count mismatch."); } for (int iField = 0; iField < columns.Length; iField++) { object value = shape.Attributes[iField]; if (value != null) { if (columns[iField].DataType != value.GetType()) { // this may throw an exception if the type casting fails value = Convert.ChangeType(value, columns[iField].DataType); } fixedContent[iField] = value; rowContent.Add(columns[iField].ColumnName, value); } } if (AttributesPopulated) { // just add a new DataRow addedRow = _dataTable.NewRow(); addedRow.ItemArray = fixedContent; return addedRow; } // Insert a new row in the source AddRow(rowContent); } return null; }
/// <inheritdoc/> public virtual Shape GetShape(int index, bool getAttributes) { if (IndexMode == false) { return new Shape(Features[index]); } Shape result = new Shape(FeatureType); // This will also deep copy the parts, attributes and vertices ShapeRange range = ShapeIndices[index]; result.Range = range.Copy(); int start = range.StartIndex; int numPoints = range.NumPoints; if (_z != null && (_z.Length - start) >= numPoints) { result.Z = new double[numPoints]; Array.Copy(_z, start, result.Z, 0, numPoints); } if (_m != null && (_m.Length - start) >= numPoints) { result.M = new double[numPoints]; Array.Copy(_m, start, result.M, 0, numPoints); } double[] vertices = new double[numPoints * 2]; Array.Copy(_vertices, start * 2, vertices, 0, numPoints * 2); result.Vertices = vertices; // There is presumed to be only a single shape in the output array. result.Range.StartIndex = 0; if (AttributesPopulated) { if (getAttributes) { result.Attributes = DataTable.Rows[index].ItemArray; } } else { DataTable dt = GetAttributes(index, 1); if (dt != null && dt.Rows.Count > 0) { result.Attributes = dt.Rows[0].ItemArray; } } return result; }
/// <inheritdocs/> public Shape[] GetShapes(int[] indices) { Shape[] result = new Shape[indices.Length]; ShapefileIndexFile shx = CacheShapeIndexFile(); // Check to ensure the fileName is not null if (Filename == null) { throw new NullReferenceException(Filename); } if (File.Exists(Filename) == false) { throw new FileNotFoundException(Filename); } // Get the basic header information. ShapefileHeader header = new ShapefileHeader(Filename); // Check to ensure that the fileName is the correct shape type if (header.ShapeType != ShapeType && header.ShapeType != ShapeTypeM && header.ShapeType != ShapeTypeZ) { throw new ArgumentException("Wrong feature type."); } FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.Read); try { if (fs.Length == 100) { // The shapefile is empty so we can simply return here return result; } int numShapes = shx.Shapes.Count; for (int j = 0; j < indices.Length; j++) { int index = indices[j]; if (index < numShapes) result[j] = GetShapeAtIndex(fs, shx, header, index, null); } return result; } finally { fs.Close(); } }
/// <summary> /// Tests the intersection with a shape /// </summary> /// <param name="shape"></param> /// <returns></returns> public bool Intersects(Shape shape) { return Intersects(shape.Range); }
private static Shape ReadMultiPolygon(Stream data) { Shape result = new Shape(FeatureType.Polygon); int numPolygons = ReadInt32(data); 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)) coords = ReverseCoords(coords); } else { // By shapefile standard, the holes should be counter clockwise. if (!IsCounterClockwise(coords)) coords = ReverseCoords(coords); } PartRange lPrt = new PartRange(FeatureType.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 ReadMultiLineString(Stream data) { Shape result = new Shape(FeatureType.Line); int numLineStrings = ReadInt32(data); 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(FeatureType.Line); lPrt.PartOffset = partOffset; lPrt.NumVertices = numPoints; result.Range.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; } result.Vertices = allVertices; return result; }
private static Shape ReadLineString(Stream data) { Shape result = new Shape(FeatureType.Line); int count = ReadInt32(data); double[] coords = ReadDouble(data, 2 * count); PartRange lPrt = new PartRange(FeatureType.Line); lPrt.NumVertices = count; result.Range.Parts.Add(lPrt); result.Vertices = coords; return result; }
/// <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(FeatureType.MultiPoint); int count = ReadInt32(data); PartRange prt = new PartRange(FeatureType.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; }
/// <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(FeatureType.Point); PartRange prt = new PartRange(FeatureType.Point); prt.NumVertices = 1; result.Range.Parts.Add(prt); result.Vertices = ReadDouble(data, 2); return result; }
/// <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; }