using System;
using System.IO;
using Core.Gis.GeoApi.Geometries;
namespace Core.GIS.NetTopologySuite.IO
{
///
/// Writes a Well-Known Binary byte data representation of a Geometry.
///
///
/// WKBWriter stores X,Y,Z values if is not ,
/// otherwise value is discarded and only X,Y are stored.
///
// Thanks to Roberto Acioli for ICoordinate.Z patch
[Serializable]
public class WKBWriter
{
///
/// Standard byte size for each complex point.
/// Each complex point (LineString, Polygon, ...) contains:
/// 1 byte for ByteOrder and
/// 4 bytes for WKBType.
///
protected const int InitCount = 5;
protected ByteOrder encodingType;
///
/// Initializes writer with LittleIndian byte order.
///
public WKBWriter() :
this(ByteOrder.LittleEndian) {}
///
/// Initializes writer with the specified byte order.
///
/// Encoding type
public WKBWriter(ByteOrder encodingType)
{
this.encodingType = encodingType;
}
///
/// Writes a WKB representation of a given point.
///
///
///
public virtual byte[] Write(IGeometry geometry)
{
byte[] bytes = GetBytes(geometry);
Write(geometry, new MemoryStream(bytes));
return bytes;
}
///
/// Writes a WKB representation of a given point.
///
///
///
///
public virtual void Write(IGeometry geometry, Stream stream)
{
BinaryWriter writer = null;
try
{
writer = encodingType == ByteOrder.LittleEndian ? new BinaryWriter(stream) : new BEBinaryWriter(stream);
Write(geometry, writer);
}
finally
{
if (writer != null)
{
writer.Close();
}
}
}
///
///
///
///
///
protected void Write(IGeometry geometry, BinaryWriter writer)
{
if (geometry is IPoint)
{
Write(geometry as IPoint, writer);
}
else if (geometry is ILineString)
{
Write(geometry as ILineString, writer);
}
else if (geometry is IPolygon)
{
Write(geometry as IPolygon, writer);
}
else if (geometry is IMultiPoint)
{
Write(geometry as IMultiPoint, writer);
}
else if (geometry is IMultiLineString)
{
Write(geometry as IMultiLineString, writer);
}
else if (geometry is IMultiPolygon)
{
Write(geometry as IMultiPolygon, writer);
}
else if (geometry is IGeometryCollection)
{
Write(geometry as IGeometryCollection, writer);
}
else
{
throw new ArgumentException("Geometry not recognized: " + geometry.ToString());
}
}
///
/// Writes LittleIndian ByteOrder.
///
///
protected void WriteByteOrder(BinaryWriter writer)
{
writer.Write((byte) ByteOrder.LittleEndian);
}
///
///
///
///
///
protected void Write(ICoordinate coordinate, BinaryWriter writer)
{
writer.Write((double) coordinate.X);
writer.Write((double) coordinate.Y);
if (!Double.IsNaN(coordinate.Z))
{
writer.Write((double) coordinate.Z);
}
}
///
///
///
///
///
protected void Write(IPoint point, BinaryWriter writer)
{
WriteByteOrder(writer); // LittleIndian
writer.Write((int) (HasValidCoordinateZ(point) ? WKBGeometryTypes.WKBPointZ : WKBGeometryTypes.WKBPoint));
Write(point.Coordinate, writer);
}
///
///
///
///
///
protected void Write(ILineString lineString, BinaryWriter writer)
{
WriteByteOrder(writer); // LittleIndian
writer.Write((int) (HasValidCoordinateZ(lineString) ? WKBGeometryTypes.WKBLineStringZ : WKBGeometryTypes.WKBLineString));
writer.Write((int) lineString.NumPoints);
for (int i = 0; i < lineString.Coordinates.Length; i++)
{
Write(lineString.Coordinates[i], writer);
}
}
///
///
///
///
///
protected void Write(ILinearRing ring, BinaryWriter writer)
{
writer.Write((int) ring.NumPoints);
for (int i = 0; i < ring.Coordinates.Length; i++)
{
Write(ring.Coordinates[i], writer);
}
}
///
///
///
///
///
protected void Write(IPolygon polygon, BinaryWriter writer)
{
WriteByteOrder(writer); // LittleIndian
writer.Write((int) (HasValidCoordinateZ(polygon) ? WKBGeometryTypes.WKBPolygonZ : WKBGeometryTypes.WKBPolygon));
writer.Write((int) polygon.NumInteriorRings + 1);
Write(polygon.ExteriorRing as ILinearRing, writer);
for (int i = 0; i < polygon.NumInteriorRings; i++)
{
Write(polygon.InteriorRings[i] as ILinearRing, writer);
}
}
///
///
///
///
///
protected void Write(IMultiPoint multiPoint, BinaryWriter writer)
{
WriteByteOrder(writer); // LittleIndian
writer.Write((int) (HasValidCoordinateZ(multiPoint) ? WKBGeometryTypes.WKBMultiPointZ : WKBGeometryTypes.WKBMultiPoint));
writer.Write((int) multiPoint.NumGeometries);
for (int i = 0; i < multiPoint.NumGeometries; i++)
{
Write(multiPoint.Geometries[i] as IPoint, writer);
}
}
///
///
///
///
///
protected void Write(IMultiLineString multiLineString, BinaryWriter writer)
{
WriteByteOrder(writer); // LittleIndian
writer.Write((int) (HasValidCoordinateZ(multiLineString) ? WKBGeometryTypes.WKBMultiLineStringZ : WKBGeometryTypes.WKBMultiLineString));
writer.Write((int) multiLineString.NumGeometries);
for (int i = 0; i < multiLineString.NumGeometries; i++)
{
Write(multiLineString.Geometries[i] as ILineString, writer);
}
}
///
///
///
///
///
protected void Write(IMultiPolygon multiPolygon, BinaryWriter writer)
{
WriteByteOrder(writer); // LittleIndian
writer.Write((int) (HasValidCoordinateZ(multiPolygon) ? WKBGeometryTypes.WKBMultiPolygonZ : WKBGeometryTypes.WKBMultiPolygon));
writer.Write((int) multiPolygon.NumGeometries);
for (int i = 0; i < multiPolygon.NumGeometries; i++)
{
Write(multiPolygon.Geometries[i] as IPolygon, writer);
}
}
///
///
///
///
///
protected void Write(IGeometryCollection geomCollection, BinaryWriter writer)
{
WriteByteOrder(writer); // LittleIndian
writer.Write((int) (HasValidCoordinateZ(geomCollection) ? WKBGeometryTypes.WKBGeometryCollectionZ : WKBGeometryTypes.WKBGeometryCollection));
writer.Write((int) geomCollection.NumGeometries);
for (int i = 0; i < geomCollection.NumGeometries; i++)
{
Write(geomCollection.Geometries[i], writer);
}
}
///
/// Sets corrent length for Byte Stream.
///
///
///
protected byte[] GetBytes(IGeometry geometry)
{
if (geometry is IPoint)
{
return new byte[SetByteStream(geometry as IPoint)];
}
else if (geometry is ILineString)
{
return new byte[SetByteStream(geometry as ILineString)];
}
else if (geometry is IPolygon)
{
return new byte[SetByteStream(geometry as IPolygon)];
}
else if (geometry is IMultiPoint)
{
return new byte[SetByteStream(geometry as IMultiPoint)];
}
else if (geometry is IMultiLineString)
{
return new byte[SetByteStream(geometry as IMultiLineString)];
}
else if (geometry is IMultiPolygon)
{
return new byte[SetByteStream(geometry as IMultiPolygon)];
}
else if (geometry is IGeometryCollection)
{
return new byte[SetByteStream(geometry as IGeometryCollection)];
}
else
{
throw new ArgumentException("ShouldNeverReachHere");
}
}
///
/// Sets corrent length for Byte Stream.
///
///
///
protected virtual int SetByteStream(IGeometry geometry)
{
if (geometry is IPoint)
{
return SetByteStream(geometry as IPoint);
}
else if (geometry is ILineString)
{
return SetByteStream(geometry as ILineString);
}
else if (geometry is IPolygon)
{
return SetByteStream(geometry as IPolygon);
}
else if (geometry is IMultiPoint)
{
return SetByteStream(geometry as IMultiPoint);
}
else if (geometry is IMultiLineString)
{
return SetByteStream(geometry as IMultiLineString);
}
else if (geometry is IMultiPolygon)
{
return SetByteStream(geometry as IMultiPolygon);
}
else if (geometry is IGeometryCollection)
{
return SetByteStream(geometry as IGeometryCollection);
}
else
{
throw new ArgumentException("ShouldNeverReachHere");
}
}
///
///
///
///
///
protected int SetByteStream(IGeometryCollection geometry)
{
int count = InitCount;
count += 4;
foreach (IGeometry geom in geometry.Geometries)
{
count += SetByteStream(geom);
}
return count;
}
///
///
///
///
///
protected int SetByteStream(IMultiPolygon geometry)
{
int count = InitCount;
count += 4;
foreach (IPolygon geom in geometry.Geometries)
{
count += SetByteStream(geom);
}
return count;
}
///
///
///
///
///
protected int SetByteStream(IMultiLineString geometry)
{
int count = InitCount;
count += 4;
foreach (ILineString geom in geometry.Geometries)
{
count += SetByteStream(geom);
}
return count;
}
///
///
///
///
///
protected int SetByteStream(IMultiPoint geometry)
{
int count = InitCount;
count += 4; // NumPoints
foreach (IPoint geom in geometry.Geometries)
{
count += SetByteStream(geom);
}
return count;
}
///
///
///
///
///
protected int SetByteStream(IPolygon geometry)
{
int pointSize = HasValidCoordinateZ(geometry) ? 24 : 16;
int count = InitCount;
count += 4 + 4; // NumRings + NumPoints
count += 4*(geometry.NumInteriorRings + 1); // Index parts
count += geometry.NumPoints*pointSize; // Points in exterior and interior rings
return count;
}
///
///
///
///
///
protected int SetByteStream(ILineString geometry)
{
int pointSize = HasValidCoordinateZ(geometry) ? 24 : 16;
int numPoints = geometry.NumPoints;
int count = InitCount;
count += 4; // NumPoints
count += pointSize*numPoints;
return count;
}
///
///
///
///
///
protected int SetByteStream(IPoint geometry)
{
return HasValidCoordinateZ(geometry) ? 29 : 21;
}
// HACK: detect if geometry has Z coordinate, should be done somewhere in Geometry (e.g. HasZ, HasM)
private static bool HasValidCoordinateZ(IGeometry geometry)
{
return geometry.Coordinate != null && !Double.IsNaN(geometry.Coordinate.Z);
}
}
}