/// <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="totalRecordLength">Total length of the record we are about to read</param> /// <param name="factory">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, int totalRecordLength, IGeometryFactory factory) { int totalRead = 0; int shapeTypeNum = ReadInt32(file, totalRecordLength, ref totalRead); var type = (ShapeGeometryType)EnumUtility.Parse(typeof(ShapeGeometryType), shapeTypeNum.ToString()); if (type == ShapeGeometryType.NullShape) { return(factory.CreateMultiPoint(new IPoint[] { })); } if (type != ShapeType) { throw new ShapefileException(string.Format("Encountered a '{0}' instead of a '{1}'", type, ShapeType)); } // Read and for now ignore bounds. int bblength = GetBoundingBoxLength(); boundingBox = new double[bblength]; for (; boundingBoxIndex < 4; boundingBoxIndex++) { double d = ReadDouble(file, totalRecordLength, ref totalRead); boundingBox[boundingBoxIndex] = d; } // Read points var numPoints = ReadInt32(file, totalRecordLength, ref totalRead); var buffer = new CoordinateBuffer(numPoints, NoDataBorderValue, true); var points = new IPoint[numPoints]; var pm = factory.PrecisionModel; for (var i = 0; i < numPoints; i++) { var x = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); var y = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); buffer.AddCoordinate(x, y); buffer.AddMarker(); } // Trond Benum: We have now read all the points, let's read optional Z and M values GetZMValues(file, totalRecordLength, ref totalRead, buffer); var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); for (var i = 0; i < numPoints; i++) { points[i] = factory.CreatePoint(sequences[i]); } geom = factory.CreateMultiPoint(points); return(geom); }
/// <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="totalRecordLength">Total length of the record we are about 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, int totalRecordLength, IGeometryFactory geometryFactory) { int totalRead = 0; int shapeTypeNum = ReadInt32(file, totalRecordLength, ref totalRead); var type = (ShapeGeometryType) EnumUtility.Parse(typeof(ShapeGeometryType), shapeTypeNum.ToString()); if (type == ShapeGeometryType.NullShape) return geometryFactory.CreateMultiPoint(new IPoint[] { }); if (type != ShapeType) throw new ShapefileException(string.Format("Encountered a '{0}' instead of a '{1}'", type, ShapeType)); // Read and for now ignore bounds. int bblength = GetBoundingBoxLength(); boundingBox = new double[bblength]; for (; boundingBoxIndex < 4; boundingBoxIndex++) { double d = ReadDouble(file, totalRecordLength, ref totalRead); boundingBox[boundingBoxIndex] = d; } // Read points var numPoints = ReadInt32(file, totalRecordLength, ref totalRead); var buffer = new CoordinateBuffer(numPoints, NoDataBorderValue, true); var points = new IPoint[numPoints]; var pm = geometryFactory.PrecisionModel; for (var i = 0; i < numPoints; i++) { var x = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); var y = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); buffer.AddCoordinate(x, y); buffer.AddMarker(); } // Trond Benum: We have now read all the points, let's read optional Z and M values GetZMValues(file, totalRecordLength, ref totalRead, buffer); var sequences = buffer.ToSequences(geometryFactory.CoordinateSequenceFactory); for (var i = 0; i < numPoints; i++) points[i] = geometryFactory.CreatePoint(sequences[i]); geom = geometryFactory.CreateMultiPoint(points); return geom; }
/// <summary> /// Method to read the coordinates block /// </summary> /// <param name="reader">The reader</param> /// <param name="numPoints">The total number of points to read</param> /// <param name="markers">The markers</param> /// <param name="ordinates">The ordinates to read</param> /// <param name="buffer">The buffer to add the coordinates to.</param> private static void ReadCoordinates(BinaryReader reader, int numPoints, int[] markers, Ordinates ordinates, CoordinateBuffer buffer) { var offset = buffer.Count; var j = 0; // Add x- and y-ordinates for (var i = 0; i < numPoints; i++) { //Read x- and y- ordinates buffer.AddCoordinate(reader.ReadDouble(), reader.ReadDouble()); //Check if we have reached a marker if (i != markers[j]) { continue; } //Add a marker buffer.AddMarker(); j++; } // are there any z-ordinates if ((ordinates & Ordinates.Z) == Ordinates.Z) { //Read zInterval /*var zInterval = */ ReadInterval(reader); //Set the z-values for (var i = 0; i < numPoints; i++) { buffer.SetZ(offset + i, reader.ReadDouble()); } } if ((ordinates & Ordinates.M) == Ordinates.M) { //Read m-interval /*var mInterval = */ ReadInterval(reader); //Set the m-values for (var i = 0; i < numPoints; i++) { buffer.SetZ(offset + i, reader.ReadDouble()); } } }
public void TestAddMarkers() { var cb = new CoordinateBuffer(10); for (var i = 0; i < 10; i++) { if (i > 0 && i % 5 == 0) { cb.AddMarker(); } cb.AddCoordinate(i, i); } //cb.AddMarker(); var seqs = cb.ToSequences(); Assert.AreEqual(2, seqs.Length); Assert.AreEqual(5, seqs[0].Count); Assert.AreEqual(5, seqs[1].Count); }
/// <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="totalRecordLength">Total length of the record we are about to read</param> /// <param name="factory">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, int totalRecordLength, IGeometryFactory factory) { int totalRead = 0; var type = (ShapeGeometryType)ReadInt32(file, totalRecordLength, ref totalRead); if (type == ShapeGeometryType.NullShape) return factory.CreatePolygon(null, null); if (type != ShapeType) throw new ShapefileException(string.Format("Encountered a '{0}' instead of a '{1}'", type, ShapeType)); // Read and for now ignore bounds. var bblength = GetBoundingBoxLength(); boundingBox = new double[bblength]; for (; boundingBoxIndex < 4; boundingBoxIndex++) boundingBox[boundingBoxIndex] = ReadDouble(file, totalRecordLength, ref totalRead); var numParts = ReadInt32(file, totalRecordLength, ref totalRead); var numPoints = ReadInt32(file, totalRecordLength, ref totalRead); var partOffsets = new int[numParts]; for (var i = 0; i < numParts; i++) partOffsets[i] = ReadInt32(file, totalRecordLength, ref totalRead); var skippedList = new HashSet<int>(); //var allPoints = new List<Coordinate>(); var buffer = new CoordinateBuffer(numPoints, NoDataBorderValue, true); var pm = factory.PrecisionModel; for (var part = 0; part < numParts; part++) { var start = partOffsets[part]; var finish = (part == numParts - 1) ? numPoints : partOffsets[part + 1]; var length = finish - start; for (var i = 0; i < length; i++) { var x = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); var y = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); // Thanks to Abhay Menon! if (!(Coordinate.NullOrdinate.Equals(x) || Coordinate.NullOrdinate.Equals(y))) buffer.AddCoordinate(x, y); else skippedList.Add(start + i); } //Add a marker that we have finished one part of the geometry buffer.AddMarker(); } // Trond Benum: We have now read all the parts, let's read optional Z and M values // and populate Z in the coordinate before we start manipulating the segments // We have to track corresponding optional M values and set them up in the // Geometries via ICoordinateSequence further down. GetZMValues(file, totalRecordLength, ref totalRead, buffer, skippedList); // Get the resulting sequences var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); var shells = new List<ILinearRing>(); var holes = new List<ILinearRing>(); for (var i = 0; i < sequences.Length; i++) { //Skip garbage input data with 0 points if (sequences[i].Count < 1) continue; var tmp = EnsureClosedSequence(sequences[i], factory.CoordinateSequenceFactory); var ring = factory.CreateLinearRing(tmp); if (ring.IsCCW) holes.Add(ring); else shells.Add(ring); } // Ensure the ring is encoded right if (shells.Count == 0 && holes.Count == 1) { shells.Add(factory.CreateLinearRing(holes[0].CoordinateSequence.Reversed())); holes.Clear(); } // Now we have lists of all shells and all holes var holesForShells = new List<List<ILinearRing>>(shells.Count); for (var i = 0; i < shells.Count; i++) holesForShells.Add(new List<ILinearRing>()); //Thanks to Bruno.Labrecque //Sort shells by area, rings should only be added to the smallest shell, that contains the ring shells.Sort(ProbeLinearRing); // Find holes foreach (var testHole in holes) { var testEnv = testHole.EnvelopeInternal; var testPt = testHole.GetCoordinateN(0); //We have the shells sorted for (var j = 0; j < shells.Count; j++) { var tryShell = shells[j]; var tryEnv = tryShell.EnvelopeInternal; var isContained = tryEnv.Contains(testEnv) && CGAlgorithms.IsPointInRing(testPt, tryShell.Coordinates); // Check if this new containing ring is smaller than the current minimum ring if (isContained) { // 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. var holesForThisShell = holesForShells[j]; holesForThisShell.Add(testHole); //Suggested by Bruno.Labrecque //A LinearRing should only be added to one outer shell break; } } } var polygons = new IPolygon[shells.Count]; for (var i = 0; i < shells.Count; i++) polygons[i] = (factory.CreatePolygon(shells[i], holesForShells[i].ToArray())); if (polygons.Length == 1) geom = polygons[0]; else geom = factory.CreateMultiPolygon(polygons); return geom; }
/// <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="totalRecordLength">Total length of the record we are about to read</param> /// <param name="factory">The geometry factory to use when making the object.</param> /// <returns>The Geometry object that represents the shape file record.</returns> public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, GeometryFactory factory) { int totalRead = 0; var type = (ShapeGeometryType)ReadInt32(file, totalRecordLength, ref totalRead); if (type == ShapeGeometryType.NullShape) { return(factory.CreateMultiLineString(null)); } if (type != ShapeType) { throw new ShapefileException(string.Format("Encountered a '{0}' instead of a '{1}'", type, ShapeType)); } // Read and for now ignore bounds. int bblength = GetBoundingBoxLength(); boundingBox = new double[bblength]; for (; boundingBoxIndex < 4; boundingBoxIndex++) { double d = ReadDouble(file, totalRecordLength, ref totalRead); boundingBox[boundingBoxIndex] = d; } int numParts = ReadInt32(file, totalRecordLength, ref totalRead); int numPoints = ReadInt32(file, totalRecordLength, ref totalRead); int[] partOffsets = new int[numParts]; for (int i = 0; i < numParts; i++) { partOffsets[i] = ReadInt32(file, totalRecordLength, ref totalRead); } var lines = new List <LineString>(numParts); var buffer = new CoordinateBuffer(numPoints, NoDataBorderValue, true); var pm = factory.PrecisionModel; for (int part = 0; part < numParts; part++) { int start = partOffsets[part]; int finish = part == numParts - 1 ? numPoints : partOffsets[part + 1]; int length = finish - start; for (int i = 0; i < length; i++) { double x = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); double y = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); buffer.AddCoordinate(x, y); } buffer.AddMarker(); } // Trond Benum: We have now read all the parts, let's read optional Z and M values // and populate Z in the coordinate before we start manipulating the segments // We have to track corresponding optional M values and set them up in the // Geometries via CoordinateSequence further down. GetZMValues(file, totalRecordLength, ref totalRead, buffer); var sequences = new List <CoordinateSequence>(buffer.ToSequences(factory.CoordinateSequenceFactory)); for (int s = 0; s < sequences.Count; s++) { var points = sequences[s]; //Skip garbage input data with 0 points if (points.Count < 1) { continue; } bool createLineString = true; if (points.Count == 1) { switch (GeometryInstantiationErrorHandling) { case GeometryInstantiationErrorHandlingOption.ThrowException: break; case GeometryInstantiationErrorHandlingOption.Empty: sequences[s] = factory.CoordinateSequenceFactory.Create(0, points.Ordinates); break; case GeometryInstantiationErrorHandlingOption.TryFix: sequences[s] = AddCoordinateToSequence(points, factory.CoordinateSequenceFactory, points.GetX(0), points.GetY(0), points.GetZ(0), points.GetM(0)); break; case GeometryInstantiationErrorHandlingOption.Null: createLineString = false; break; } } if (createLineString) { // Grabs m values if we have them var line = factory.CreateLineString(points); lines.Add(line); } } geom = (lines.Count != 1) ? (Geometry)factory.CreateMultiLineString(lines.ToArray()) : lines[0]; return(geom); }
/// <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="totalRecordLength">Total length of the record we are about 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, int totalRecordLength, IGeometryFactory geometryFactory) { int totalRead = 0; var type = (ShapeGeometryType)ReadInt32(file, totalRecordLength, ref totalRead); if (type == ShapeGeometryType.NullShape) { return(geometryFactory.CreatePolygon(null, null)); } if (type != ShapeType) { throw new ShapefileException(string.Format("Encountered a '{0}' instead of a '{1}'", type, ShapeType)); } // Read and for now ignore bounds. var bblength = GetBoundingBoxLength(); boundingBox = new double[bblength]; for (; boundingBoxIndex < 4; boundingBoxIndex++) { boundingBox[boundingBoxIndex] = ReadDouble(file, totalRecordLength, ref totalRead); } var numParts = ReadInt32(file, totalRecordLength, ref totalRead); var numPoints = ReadInt32(file, totalRecordLength, ref totalRead); var partOffsets = new int[numParts]; for (var i = 0; i < numParts; i++) { partOffsets[i] = ReadInt32(file, totalRecordLength, ref totalRead); } var skippedList = new HS(); //var allPoints = new List<Coordinate>(); var buffer = new CoordinateBuffer(numPoints, NoDataBorderValue, true); var pm = geometryFactory.PrecisionModel; for (var part = 0; part < numParts; part++) { var start = partOffsets[part]; var finish = (part == numParts - 1) ? numPoints : partOffsets[part + 1]; var length = finish - start; for (var i = 0; i < length; i++) { var x = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); var y = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); // Thanks to Abhay Menon! if (!(Coordinate.NullOrdinate.Equals(x) || Coordinate.NullOrdinate.Equals(y))) { buffer.AddCoordinate(x, y); } else { skippedList.Add(start + i); } } //Add a marker that we have finished one part of the geometry buffer.AddMarker(); } // Trond Benum: We have now read all the parts, let's read optional Z and M values // and populate Z in the coordinate before we start manipulating the segments // We have to track corresponding optional M values and set them up in the // Geometries via ICoordinateSequence further down. GetZMValues(file, totalRecordLength, ref totalRead, buffer, skippedList); // Get the resulting sequences var sequences = buffer.ToSequences(geometryFactory.CoordinateSequenceFactory); var shells = new List <ILinearRing>(); var holes = new List <ILinearRing>(); for (var i = 0; i < sequences.Length; i++) { var tmp = EnsureClosedSequence(sequences[i], geometryFactory.CoordinateSequenceFactory); var ring = geometryFactory.CreateLinearRing(tmp); if (ring.IsCCW) { holes.Add(ring); } else { shells.Add(ring); } } // Ensure the ring is encoded right if (shells.Count == 0 && holes.Count == 1) { shells.Add(geometryFactory.CreateLinearRing(holes[0].CoordinateSequence.Reversed())); holes.Clear(); } // Now we have lists of all shells and all holes var holesForShells = new List <List <ILinearRing> >(shells.Count); for (var i = 0; i < shells.Count; i++) { holesForShells.Add(new List <ILinearRing>()); } //Thanks to Bruno.Labrecque //Sort shells by area, rings should only be added to the smallest shell, that contains the ring shells.Sort(ProbeLinearRing); // Find holes foreach (var testHole in holes) { var testEnv = testHole.EnvelopeInternal; var testPt = testHole.GetCoordinateN(0); //We have the shells sorted for (var j = 0; j < shells.Count; j++) { var tryShell = shells[j]; var tryEnv = tryShell.EnvelopeInternal; var isContained = tryEnv.Contains(testEnv) && CGAlgorithms.IsPointInRing(testPt, tryShell.Coordinates); // Check if this new containing ring is smaller than the current minimum ring if (isContained) { // 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. var holesForThisShell = holesForShells[j]; holesForThisShell.Add(testHole); //Suggested by Bruno.Labrecque //A LinearRing should only be added to one outer shell break; } } } var polygons = new IPolygon[shells.Count]; for (var i = 0; i < shells.Count; i++) { polygons[i] = (geometryFactory.CreatePolygon(shells[i], holesForShells[i].ToArray())); } if (polygons.Length == 1) { geom = polygons[0]; } else { geom = geometryFactory.CreateMultiPolygon(polygons); } return(geom); }
/// <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="totalRecordLength">Total length of the record we are about 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, int totalRecordLength, IGeometryFactory geometryFactory) { int totalRead = 0; var type = (ShapeGeometryType)ReadInt32(file, totalRecordLength, ref totalRead); if (type == ShapeGeometryType.NullShape) return geometryFactory.CreateMultiLineString(null); if (type != ShapeType) throw new ShapefileException(string.Format("Encountered a '{0}' instead of a '{1}'", type, ShapeType)); // Read and for now ignore bounds. int bblength = GetBoundingBoxLength(); boundingBox = new double[bblength]; for (; boundingBoxIndex < 4; boundingBoxIndex++) { double d = ReadDouble(file, totalRecordLength, ref totalRead); boundingBox[boundingBoxIndex] = d; } int numParts = ReadInt32(file, totalRecordLength, ref totalRead); int numPoints = ReadInt32(file, totalRecordLength, ref totalRead); int[] partOffsets = new int[numParts]; for (int i = 0; i < numParts; i++) partOffsets[i] = ReadInt32(file, totalRecordLength, ref totalRead); var lines = new List<ILineString>(numParts); var buffer = new CoordinateBuffer(numPoints, NoDataBorderValue, true); var pm = geometryFactory.PrecisionModel; for (var part = 0; part < numParts; part++) { var start = partOffsets[part]; var finish = part == numParts - 1 ? numPoints : partOffsets[part + 1]; var length = finish - start; for (var i = 0; i < length; i++) { var x = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); var y = pm.MakePrecise(ReadDouble(file, totalRecordLength, ref totalRead)); buffer.AddCoordinate(x, y); } buffer.AddMarker(); } // Trond Benum: We have now read all the parts, let's read optional Z and M values // and populate Z in the coordinate before we start manipulating the segments // We have to track corresponding optional M values and set them up in the // Geometries via ICoordinateSequence further down. GetZMValues(file, totalRecordLength, ref totalRead, buffer); var sequences = new List<ICoordinateSequence>(buffer.ToSequences(geometryFactory.CoordinateSequenceFactory)); for (var s = 0; s < sequences.Count; s++) { var points = sequences[s]; //Skip garbage input data with 0 points if (points.Count < 1) continue; var createLineString = true; if (points.Count == 1) { switch (GeometryInstantiationErrorHandling) { case GeometryInstantiationErrorHandlingOption.ThrowException: break; case GeometryInstantiationErrorHandlingOption.Empty: sequences[s] = geometryFactory.CoordinateSequenceFactory.Create(0, points.Ordinates); break; case GeometryInstantiationErrorHandlingOption.TryFix: sequences[s] = AddCoordinateToSequence(points, geometryFactory.CoordinateSequenceFactory, points.GetOrdinate(0, Ordinate.X), points.GetOrdinate(0, Ordinate.Y), points.GetOrdinate(0, Ordinate.Z), points.GetOrdinate(0, Ordinate.M)); break; case GeometryInstantiationErrorHandlingOption.Null: createLineString = false; break; } } if (createLineString) { // Grabs m values if we have them var line = geometryFactory.CreateLineString(points); lines.Add(line); } } geom = (lines.Count != 1) ? (IGeometry)geometryFactory.CreateMultiLineString(lines.ToArray()) : lines[0]; return geom; }
public void TestAddMarkers() { var cb = new CoordinateBuffer(10); for (var i = 0; i < 10; i++) { if (i > 0 && i % 5 == 0) cb.AddMarker(); cb.AddCoordinate(i, i); } //cb.AddMarker(); var seqs = cb.ToSequences(); Assert.AreEqual(2, seqs.Length); Assert.AreEqual(5, seqs[0].Count); Assert.AreEqual(5, seqs[1].Count); }
/// <summary> /// Method to read the coordinates block /// </summary> /// <param name="reader">The reader</param> /// <param name="numPoints">The total number of points to read</param> /// <param name="markers">The markers</param> /// <param name="ordinates">The ordinates to read</param> /// <param name="buffer">The buffer to add the coordinates to.</param> private static void ReadCoordinates(BinaryReader reader, int numPoints, int[] markers, Ordinates ordinates, CoordinateBuffer buffer) { var offset = buffer.Count; var j = 0; // Add x- and y-ordinates for (var i = 0; i < numPoints; i++) { //Read x- and y- ordinates buffer.AddCoordinate(reader.ReadDouble(), reader.ReadDouble()); //Check if we have reached a marker if (i != markers[j]) continue; //Add a marker buffer.AddMarker(); j++; } // are there any z-ordinates if ((ordinates & Ordinates.Z) == Ordinates.Z) { //Read zInterval /*var zInterval = */ ReadInterval(reader); //Set the z-values for (var i = 0; i < numPoints; i++) buffer.SetZ(offset + i, reader.ReadDouble()); } if ((ordinates & Ordinates.M) == Ordinates.M) { //Read m-interval /*var mInterval = */ ReadInterval(reader); //Set the m-values for (var i = 0; i < numPoints; i++) buffer.SetZ(offset + i, reader.ReadDouble()); } }