using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;
namespace Deltares.Maps
{
public class Feature : NetTopologySuite.Features.Feature, IFeature
{
private string geomWkt;
private IGeometry geometry;
private int? oldHashCode;
private Guid id;
private Feature(string geomWkt)
{
this.geomWkt = geomWkt;
ParseGeometryString();
IntializeGeometry();
}
private Feature(IGeometry geometry)
{
this.geometry = geometry;
WriteWktString();
IntializeGeometry();
}
private void IntializeGeometry()
{
id = Guid.NewGuid();
Attributes = new AttributesDictionary();
}
public virtual string WktFormat
{
get
{
if (geometry == null)
{
if (string.IsNullOrEmpty(geomWkt))
{
WriteWktString();
}
}
return geomWkt;
}
}
///
/// Gets the geometry. It parses the geometry wkt string when needed
///
new public IGeometry Geometry
{
get
{
if (geometry == null)
{
if (!string.IsNullOrEmpty(geomWkt))
{
ParseGeometryString();
}
else
{
throw new InvalidOperationException(
"The internal state for this object is not valid. The internal geometry is empty.");
}
}
return geometry;
}
}
public virtual Guid Id
{
get { return id; }
protected set { id = value; }
}
public static Feature Create(string geomWkt, IEnumerable> attributes)
{
Feature feature = Create(geomWkt);
foreach (var attribute in attributes)
{
feature.AddAttribute(attribute.Key, attribute.Value);
}
return feature;
}
///
/// Creates a feature with a geometry parsed from the argument string
///
/// The well known geometry string
/// A feature
public static Feature Create(string geomWkt)
{
if (geomWkt == null)
{
throw new ArgumentNullException("geomWkt");
}
try
{
return new Feature(geomWkt);
}
catch (Exception exception)
{
if (exception.Message.Contains("','"))
{
throw new ArgumentException(
"There was an error parsing the WKT geometry string, maybe due to an incorrect culture format conversion",
"geomWkt",
exception);
}
}
throw new InvalidOperationException();
}
///
/// Creates an empty feature with a point geometry
///
///
///
///
private static Feature Create(double x, double y)
{
return new Feature(new Point(x, y));
}
public static Feature Create(double x, double y, IEnumerable> attributes)
{
Feature feature = Create(x, y);
foreach (var attribute in attributes)
{
feature.AddAttribute(attribute.Key, attribute.Value);
}
return feature;
}
public static Feature Create(Coordinate coordinate)
{
if (coordinate == null)
{
throw new ArgumentNullException("coordinate");
}
return new Feature(new Point(coordinate));
}
public static Feature Create(IGeometry geometry)
{
if (geometry == null)
{
throw new ArgumentNullException("geometry");
}
return new Feature(geometry);
}
private void WriteWktString()
{
var writer = new WKTWriter();
geomWkt = CultureHelper.InvokeWithUSCulture(() => writer.Write(geometry));
}
private void ParseGeometryString()
{
var reader = new WKTReader(GeometryFactory.Default);
geometry = reader.Read(geomWkt);
}
public override bool Equals(object obj)
{
var other = obj as Feature;
if (other == null)
{
return false;
}
// handle the case of comparing two NEW objects
bool otherIsTransient = Equals(other.Id, Guid.Empty);
bool thisIsTransient = Equals(Id, Guid.Empty);
if (otherIsTransient && thisIsTransient)
{
return ReferenceEquals(other, this);
}
return other.Id.Equals(Id);
}
public override int GetHashCode()
{
// Once we have a hash code we'll never change it
if (oldHashCode.HasValue)
{
return oldHashCode.Value;
}
bool thisIsTransient = Equals(Id, Guid.Empty);
// When this instance is transient, we use the base GetHashCode()
// and remember it, so an instance can NEVER change its hash code.
if (thisIsTransient)
{
oldHashCode = base.GetHashCode();
return oldHashCode.Value;
}
return Id.GetHashCode();
}
public static bool operator ==(Feature x, Feature y)
{
return Equals(x, y);
}
public static bool operator !=(Feature x, Feature y)
{
return !(x == y);
}
public void AddAttribute(string attributeName, object value)
{
try
{
Attributes.AddAttribute(attributeName, value);
}
catch (ArgumentException exception)
{
throw new ArgumentException(attributeName, exception);
}
}
public object this[string attributeName]
{
get { return Attributes[attributeName]; }
set { Attributes[attributeName] = value; }
}
public object Tag { get; set; }
}
}