using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Npgsql;
namespace NpgsqlTypes
{
#pragma warning disable 1591
///
/// Represents the identifier of the Well Known Binary representation of a geographical feature specified by the OGC.
/// http://portal.opengeospatial.org/files/?artifact_id=13227 Chapter 6.3.2.7
///
enum WkbIdentifier : uint
{
Point = 1,
LineString = 2,
Polygon = 3,
MultiPoint = 4,
MultiLineString = 5,
MultiPolygon = 6,
GeometryCollection = 7
}
///
/// The modifiers used by postgis to extend the geomtry's binary representation
///
[Flags]
enum EwkbModifier : uint
{
HasSRID = 0x20000000,
HasMDim = 0x40000000,
HasZDim = 0x80000000
}
///
/// A structure representing a 2D double precision floating point coordinate;
///
public struct Coordinate2D
{
///
/// X coordinate.
///
public double X;
///
/// Y coordinate.
///
public double Y;
///
/// Generates a new BBpoint with the specified coordinates.
///
/// X coordinate
/// Y coordinate
public Coordinate2D(double x, double y) { X = x; Y = y;}
public bool Equals(Coordinate2D c)
{
return X == c.X && Y == c.Y;
}
public override int GetHashCode()
{
return X.GetHashCode() ^ PGUtil.RotateShift(Y.GetHashCode(), sizeof(int) / 2);
}
}
///
/// Represents an Postgis feature.
///
public abstract class PostgisGeometry
{
///
/// returns the binary length of the data structure without header.
///
///
protected abstract int GetLenHelper();
internal abstract WkbIdentifier Identifier { get;}
internal int GetLen()
{
// header =
// 1 byte for the endianness of the structure
// + 4 bytes for the type identifier
// (+ 4 bytes for the SRID if present)
return 5 + (SRID == 0 ? 0 : 4) + GetLenHelper();
}
///
/// The Spatial Reference System Identifier of the geometry (0 if unspecified).
///
public uint SRID { get; set; }
}
///
/// Represents an Postgis 2D Point
///
public class PostgisPoint : PostgisGeometry, IEquatable
{
internal override WkbIdentifier Identifier => WkbIdentifier.Point;
Coordinate2D _coord;
protected override int GetLenHelper()
{
return 16;
}
public PostgisPoint(double x, double y)
{
_coord.X = x;
_coord.Y = y;
}
public double X
{
get { return _coord.X ; }
set { _coord.X = value; }
}
public double Y
{
get { return _coord.Y; }
set { _coord.Y = value; }
}
public bool Equals([CanBeNull] PostgisPoint other)
{
if (ReferenceEquals(other, null))
return false;
return _coord.Equals(other._coord);
}
public override bool Equals([CanBeNull] object obj)
{
return Equals(obj as PostgisPoint);
}
public static bool operator ==([CanBeNull] PostgisPoint x, [CanBeNull] PostgisPoint y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
return x.Equals(y);
}
public static bool operator !=(PostgisPoint x, PostgisPoint y)
{
return !(x == y);
}
public override int GetHashCode()
{
return X.GetHashCode() ^ PGUtil.RotateShift(Y.GetHashCode(), sizeof(int) / 2);
}
}
///
/// Represents an Ogc 2D LineString
///
public class PostgisLineString : PostgisGeometry, IEquatable, IEnumerable
{
readonly Coordinate2D[] _points;
internal override WkbIdentifier Identifier => WkbIdentifier.LineString;
protected override int GetLenHelper()
{
return 4 + _points.Length * 16;
}
public IEnumerator GetEnumerator()
{
return ((IEnumerable)_points).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Coordinate2D this[int index] => _points[index];
public PostgisLineString(IEnumerable points)
{
_points = points.ToArray();
}
public PostgisLineString(Coordinate2D[] points)
{
_points = points;
}
public int PointCount => _points.Length;
public bool Equals([CanBeNull] PostgisLineString other)
{
if (ReferenceEquals(other , null))
return false ;
if (_points.Length != other._points.Length) return false;
for (var i = 0; i < _points.Length; i++)
{
if (!_points[i].Equals(other._points[i]))
return false;
}
return true;
}
public override bool Equals([CanBeNull] object obj)
{
return Equals(obj as PostgisLineString);
}
public static bool operator ==(PostgisLineString x, PostgisLineString y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
return x.Equals(y);
}
public static bool operator !=(PostgisLineString x, PostgisLineString y)
{
return !(x == y);
}
public override int GetHashCode()
{
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _points.Length; i++)
{
ret ^= PGUtil.RotateShift(_points[i].GetHashCode(), ret % sizeof(int));
}
return ret;
}
}
///
/// Represents an Postgis 2D Polygon.
///
public class PostgisPolygon : PostgisGeometry, IEquatable
{
readonly Coordinate2D[][] _rings;
protected override int GetLenHelper()
{
return 4 + _rings.Length * 4 + TotalPointCount * 16;
}
internal override WkbIdentifier Identifier => WkbIdentifier.Polygon;
public Coordinate2D this[int ringIndex, int pointIndex] => _rings[ringIndex][pointIndex];
public Coordinate2D[] this[int ringIndex] => _rings[ringIndex];
public PostgisPolygon(Coordinate2D[][] rings)
{
_rings = rings;
}
public PostgisPolygon(IEnumerable> rings)
{
_rings = rings.Select(x => x.ToArray()).ToArray();
}
public bool Equals(PostgisPolygon other)
{
if (ReferenceEquals(other, null))
return false;
if (_rings.Length != other._rings.Length)
return false;
for (var i = 0; i < _rings.Length; i++)
{
if (_rings[i].Length != other._rings[i].Length)
return false;
for (var j = 0; j < _rings[i].Length; j++)
{
if (!_rings[i][j].Equals (other._rings[i][j]))
return false;
}
}
return true;
}
public override bool Equals([CanBeNull] object obj)
{
return Equals(obj as PostgisPolygon);
}
public static bool operator ==([CanBeNull] PostgisPolygon x, [CanBeNull] PostgisPolygon y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
return x.Equals(y);
}
public static bool operator !=(PostgisPolygon x, PostgisPolygon y)
{
return !(x == y);
}
public int RingCount => _rings.Length;
public int TotalPointCount
{
get
{
var r = 0;
for (var i = 0; i < _rings.Length; i++)
{
r += _rings[i].Length;
}
return r;
}
}
public override int GetHashCode()
{
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _rings.Length; i++)
{
for (int j = 0; j < _rings[i].Length; j++)
{
ret ^= PGUtil.RotateShift(_rings[i][j].GetHashCode(), ret % sizeof(int));
}
}
return ret;
}
}
///
/// Represents a Postgis 2D MultiPoint
///
public class PostgisMultiPoint : PostgisGeometry, IEquatable, IEnumerable
{
readonly Coordinate2D[] _points;
internal override WkbIdentifier Identifier => WkbIdentifier.MultiPoint;
protected override int GetLenHelper()
{
return 4 + _points.Length * 21; //each point of a multipoint is a postgispoint, not a building block point.
}
public IEnumerator GetEnumerator()
{
return ((IEnumerable)_points).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public PostgisMultiPoint (Coordinate2D[] points)
{
_points = points;
}
public PostgisMultiPoint(IEnumerable points)
{
_points = points.Select(x => new Coordinate2D(x.X, x.Y)).ToArray();
}
public PostgisMultiPoint(IEnumerable points)
{
_points = points.ToArray();
}
public Coordinate2D this[int indexer] => _points[indexer];
public bool Equals([CanBeNull] PostgisMultiPoint other)
{
if (ReferenceEquals(other ,null))
return false ;
if (_points.Length != other._points.Length)
return false;
for (var i = 0; i < _points.Length; i++)
{
if (!_points[i].Equals(other._points[i]))
return false;
}
return true;
}
public override bool Equals([CanBeNull] object obj)
{
return Equals(obj as PostgisMultiPoint);
}
public static bool operator ==([CanBeNull] PostgisMultiPoint x, [CanBeNull] PostgisMultiPoint y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
return x.Equals(y);
}
public static bool operator !=(PostgisMultiPoint x, PostgisMultiPoint y)
{
return !(x == y);
}
public override int GetHashCode()
{
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _points.Length; i++)
{
ret ^= PGUtil.RotateShift(_points[i].GetHashCode(), ret % sizeof(int));
}
return ret;
}
public int PointCount => _points.Length;
}
///
/// Represents a Postgis 2D MultiLineString
///
public class PostgisMultiLineString : PostgisGeometry, IEquatable, IEnumerable
{
readonly PostgisLineString[] _lineStrings;
internal PostgisMultiLineString(Coordinate2D[][] pointArray)
{
_lineStrings = new PostgisLineString[pointArray.Length];
for (var i = 0; i < pointArray.Length; i++)
{
_lineStrings[i] = new PostgisLineString(pointArray[i]);
}
}
internal override WkbIdentifier Identifier => WkbIdentifier.MultiLineString;
protected override int GetLenHelper()
{
var n = 4;
for (var i = 0; i < _lineStrings.Length; i++)
{
n += _lineStrings[i].GetLen();
}
return n;
}
public IEnumerator GetEnumerator()
{
return ((IEnumerable)_lineStrings).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public PostgisMultiLineString(PostgisLineString[] linestrings)
{
_lineStrings = linestrings;
}
public PostgisMultiLineString(IEnumerable linestrings)
{
_lineStrings = linestrings.ToArray();
}
public PostgisLineString this[int index] => _lineStrings[index];
public PostgisMultiLineString(IEnumerable> pointList)
{
_lineStrings = pointList.Select(x => new PostgisLineString(x)).ToArray();
}
public bool Equals([CanBeNull] PostgisMultiLineString other)
{
if (ReferenceEquals(other ,null))
return false ;
if (_lineStrings.Length != other._lineStrings.Length) return false;
for (var i = 0; i < _lineStrings.Length; i++)
{
if (_lineStrings[i] != other._lineStrings[i]) return false;
}
return true;
}
public override bool Equals([CanBeNull] object obj)
{
return Equals(obj as PostgisMultiLineString);
}
public static bool operator ==([CanBeNull] PostgisMultiLineString x, [CanBeNull] PostgisMultiLineString y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
return x.Equals(y);
}
public static bool operator !=(PostgisMultiLineString x, PostgisMultiLineString y)
{
return !(x == y);
}
public override int GetHashCode()
{
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _lineStrings.Length; i++)
{
ret ^= PGUtil.RotateShift(_lineStrings[i].GetHashCode(), ret % sizeof(int));
}
return ret;
}
public int LineCount => _lineStrings.Length;
}
///
/// Represents a Postgis 2D MultiPolygon.
///
public class PostgisMultiPolygon : PostgisGeometry, IEquatable, IEnumerable
{
readonly PostgisPolygon[] _polygons;
public IEnumerator GetEnumerator()
{
return ((IEnumerable)_polygons).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal override WkbIdentifier Identifier => WkbIdentifier.MultiPolygon;
public PostgisPolygon this[int index] => _polygons[index];
public PostgisMultiPolygon(PostgisPolygon[] polygons)
{
_polygons = polygons;
}
public PostgisMultiPolygon(IEnumerable polygons)
{
_polygons = polygons.ToArray();
}
public PostgisMultiPolygon(IEnumerable>> ringList)
{
_polygons = ringList.Select(x => new PostgisPolygon(x)).ToArray();
}
public bool Equals(PostgisMultiPolygon other)
{
if (_polygons.Length != other._polygons.Length) return false;
for (var i = 0; i < _polygons.Length; i++)
{
if (_polygons[i] != other._polygons[i]) return false;
}
return true;
}
public override bool Equals(object obj)
{
return obj is PostgisMultiPolygon && Equals((PostgisMultiPolygon)obj);
}
public static bool operator ==(PostgisMultiPolygon x, PostgisMultiPolygon y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
return x.Equals(y);
}
public static bool operator !=(PostgisMultiPolygon x, PostgisMultiPolygon y)
{
return !(x == y);
}
public override int GetHashCode()
{
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _polygons.Length; i++)
{
ret ^= PGUtil.RotateShift(_polygons[i].GetHashCode(), ret % sizeof(int));
}
return ret;
}
protected override int GetLenHelper()
{
var n = 4;
for (var i = 0; i < _polygons.Length; i++)
{
n += _polygons[i].GetLen();
}
return n;
}
public int PolygonCount => _polygons.Length;
}
///
/// Represents a collection of Postgis feature.
///
public class PostgisGeometryCollection : PostgisGeometry, IEquatable, IEnumerable
{
readonly PostgisGeometry[] _geometries;
public PostgisGeometry this[int index] => _geometries[index];
internal override WkbIdentifier Identifier => WkbIdentifier.GeometryCollection;
public IEnumerator GetEnumerator()
{
return ((IEnumerable)_geometries).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public PostgisGeometryCollection(PostgisGeometry[] geometries)
{
_geometries = geometries;
}
public PostgisGeometryCollection(IEnumerable geometries)
{
_geometries = geometries.ToArray();
}
public bool Equals([CanBeNull] PostgisGeometryCollection other)
{
if (ReferenceEquals(other, null))
return false;
if (_geometries.Length != other._geometries.Length) return false;
for (var i = 0; i < _geometries.Length; i++)
{
if (!_geometries[i].Equals(other._geometries[i])) return false;
}
return true;
}
public override bool Equals([CanBeNull] object obj)
{
return Equals(obj as PostgisGeometryCollection);
}
public static bool operator ==([CanBeNull] PostgisGeometryCollection x, [CanBeNull] PostgisGeometryCollection y)
{
if (ReferenceEquals(x, null))
return ReferenceEquals(y, null);
return x.Equals(y);
}
public static bool operator !=(PostgisGeometryCollection x, PostgisGeometryCollection y)
{
return !(x == y);
}
public override int GetHashCode()
{
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _geometries.Length; i++)
{
ret ^= PGUtil.RotateShift(_geometries[i].GetHashCode(), ret % sizeof(int));
}
return ret;
}
protected override int GetLenHelper()
{
var n = 4;
for (var i = 0; i < _geometries.Length; i++)
{
n += _geometries[i].GetLen();
}
return n;
}
public int GeometryCount => _geometries.Length;
}
}