using System; using System.IO; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; namespace GisSharpBlog.NetTopologySuite.IO.Handlers { /// /// Converts a Shapefile multi-line to a OGIS LineString/MultiLineString. /// public class MultiLineHandler : ShapeHandler { /// /// Returns the ShapeType the handler handles. /// public override ShapeGeometryType ShapeType { get { return ShapeGeometryType.LineString; } } /// /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// /// The stream to read. /// The geometry factory to use when making the object. /// The Geometry object that represents the shape file record. public override IGeometry Read(BigEndianBinaryReader file, IGeometryFactory geometryFactory) { int shapeTypeNum = file.ReadInt32(); type = (ShapeGeometryType) Enum.Parse(typeof(ShapeGeometryType), shapeTypeNum.ToString()); if (type == ShapeGeometryType.NullShape) return geometryFactory.CreateMultiLineString(null); if (!(type == ShapeGeometryType.LineString || type == ShapeGeometryType.LineStringM || type == ShapeGeometryType.LineStringZ || type == ShapeGeometryType.LineStringZM)) throw new ShapefileException("Attempting to load a non-arc as arc."); // Read and for now ignore bounds. int bblength = GetBoundingBoxLength(); bbox = new double[bblength]; for (; bbindex < 4; bbindex++) { double d = file.ReadDouble(); bbox[bbindex] = 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]; for (int part = 0; part < numParts; part++) { int start, finish, length; 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++) { double x = file.ReadDouble(); double y = file.ReadDouble(); ICoordinate external = new Coordinate(x, y); geometryFactory.PrecisionModel.MakePrecise(external); points.Add(external); } ILineString line = geometryFactory.CreateLineString(points.ToArray()); lines[part] = line; } geom = geometryFactory.CreateMultiLineString(lines); GrabZMValues(file); return geom; } /// /// Writes to the given stream the equilivent shape file record given a Geometry object. /// /// The geometry object to write. /// The stream to write to. /// The geometry factory to use. public override void Write(IGeometry geometry, BinaryWriter file, IGeometryFactory geometryFactory) { // Force to use a MultiGeometry IMultiLineString multi; if (geometry is IGeometryCollection) multi = (IMultiLineString) geometry; else multi = geometryFactory.CreateMultiLineString(new ILineString[] { (ILineString) geometry }); file.Write(int.Parse(Enum.Format(typeof(ShapeGeometryType), ShapeType, "d"))); IEnvelope box = multi.EnvelopeInternal; file.Write(box.MinX); file.Write(box.MinY); file.Write(box.MaxX); file.Write(box.MaxY); int numParts = multi.NumGeometries; int numPoints = multi.NumPoints; file.Write(numParts); file.Write(numPoints); // Write the offsets int offset=0; for (int i = 0; i < numParts; i++) { IGeometry g = multi.GetGeometryN(i); file.Write( offset ); offset = offset + g.NumPoints; } for (int part = 0; part < numParts; part++) { CoordinateList points = new CoordinateList(multi.GetGeometryN(part).Coordinates); for (int i = 0; i < points.Count; i++) { ICoordinate external = points[i]; file.Write(external.X); file.Write(external.Y); } } } /// /// Gets the length in bytes the Geometry will need when written as a shape file record. /// /// The Geometry object to use. /// The length in bytes the Geometry will use when represented as a shape file record. public override int GetLength(IGeometry geometry) { int numParts = GetNumParts(geometry); return (22 + (2 * numParts) + geometry.NumPoints * 8); // 22 => shapetype(2) + bbox(4*4) + numparts(2) + numpoints(2) } /// /// /// /// /// private int GetNumParts(IGeometry geometry) { int numParts=1; if (geometry is IMultiLineString) numParts = ((IMultiLineString) geometry).Geometries.Length; return numParts; } } }