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;
}
}
}