using System;
using System.IO;
using System.Text;
using Core.Gis.GeoApi.Geometries;
using Core.GIS.NetTopologySuite.Algorithm;
using Core.GIS.NetTopologySuite.Geometries;
using Core.GIS.NetTopologySuite.GeometriesGraph.Index;
namespace Core.GIS.NetTopologySuite.GeometriesGraph
{
///
///
///
public class Edge : GraphComponent
{
private IEnvelope env;
private readonly EdgeIntersectionList eiList = null;
private MonotoneChainEdge mce;
private bool isIsolated = true;
private readonly Depth depth = new Depth();
///
///
///
///
///
public Edge(ICoordinate[] pts, Label label)
{
DepthDelta = 0;
eiList = new EdgeIntersectionList(this);
Points = pts;
this.label = label;
}
///
///
///
///
public Edge(ICoordinate[] pts) : this(pts, null) {}
///
///
///
public override ICoordinate Coordinate
{
get
{
return Points.Length > 0 ? Points[0] : null;
}
}
///
///
///
public override bool IsIsolated
{
get
{
return isIsolated;
}
}
///
///
///
public ICoordinate[] Points { get; set; }
///
///
///
public int NumPoints
{
get
{
return Points.Length;
}
}
///
///
///
public string Name { get; set; }
///
///
///
public ICoordinate[] Coordinates
{
get
{
return Points;
}
}
///
///
///
public IEnvelope Envelope
{
get
{
// compute envelope lazily
if (env == null)
{
env = new Envelope();
for (var i = 0; i < Points.Length; i++)
{
env.ExpandToInclude(Points[i]);
}
}
return env;
}
}
///
///
///
public Depth Depth
{
get
{
return depth;
}
}
///
/// The depthDelta is the change in depth as an edge is crossed from R to L.
///
/// The change in depth as the edge is crossed from R to L.
public int DepthDelta { get; set; }
///
///
///
public int MaximumSegmentIndex
{
get
{
return Points.Length - 1;
}
}
///
///
///
public EdgeIntersectionList EdgeIntersectionList
{
get
{
return eiList;
}
}
///
///
///
public MonotoneChainEdge MonotoneChainEdge
{
get
{
if (mce == null)
{
mce = new MonotoneChainEdge(this);
}
return mce;
}
}
///
///
///
public bool IsClosed
{
get
{
return Points[0].Equals(Points[Points.Length - 1]);
}
}
///
/// An Edge is collapsed if it is an Area edge and it consists of
/// two segments which are equal and opposite (eg a zero-width V).
///
public bool IsCollapsed
{
get
{
if (!label.IsArea())
{
return false;
}
if (Points.Length != 3)
{
return false;
}
if (Points[0].Equals(Points[2]))
{
return true;
}
return false;
}
}
///
///
///
public Edge CollapsedEdge
{
get
{
var newPts = new ICoordinate[2];
newPts[0] = Points[0];
newPts[1] = Points[1];
var newe = new Edge(newPts, Label.ToLineLabel(label));
return newe;
}
}
///
///
///
public bool Isolated
{
get
{
return isIsolated;
}
set
{
isIsolated = value;
}
}
///
/// Updates an IM from the label for an edge.
/// Handles edges from both L and A geometries.
///
///
///
public static void UpdateIM(Label label, IntersectionMatrix im)
{
im.SetAtLeastIfValid(label.GetLocation(0, Positions.On), label.GetLocation(1, Positions.On), Dimensions.Curve);
if (label.IsArea())
{
im.SetAtLeastIfValid(label.GetLocation(0, Positions.Left), label.GetLocation(1, Positions.Left), Dimensions.Surface);
im.SetAtLeastIfValid(label.GetLocation(0, Positions.Right), label.GetLocation(1, Positions.Right), Dimensions.Surface);
}
}
///
///
///
///
///
public ICoordinate GetCoordinate(int i)
{
try
{
return Points[i];
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
///
/// Adds EdgeIntersections for one or both
/// intersections found for a segment of an edge to the edge intersection list.
///
///
///
///
public void AddIntersections(LineIntersector li, int segmentIndex, int geomIndex)
{
for (var i = 0; i < li.IntersectionNum; i++)
{
AddIntersection(li, segmentIndex, geomIndex, i);
}
}
///
/// Add an EdgeIntersection for intersection intIndex.
/// An intersection that falls exactly on a vertex of the edge is normalized
/// to use the higher of the two possible segmentIndexes.
///
///
///
///
///
public void AddIntersection(LineIntersector li, int segmentIndex, int geomIndex, int intIndex)
{
ICoordinate intPt = new Coordinate(li.GetIntersection(intIndex));
var normalizedSegmentIndex = segmentIndex;
var dist = li.GetEdgeDistance(geomIndex, intIndex);
// normalize the intersection point location
var nextSegIndex = normalizedSegmentIndex + 1;
if (nextSegIndex < Points.Length)
{
var nextPt = Points[nextSegIndex];
// Normalize segment index if intPt falls on vertex
// The check for point equality is 2D only - Z values are ignored
if (intPt.Equals2D(nextPt))
{
normalizedSegmentIndex = nextSegIndex;
dist = 0.0;
}
// Add the intersection point to edge intersection list.
EdgeIntersectionList.Add(intPt, normalizedSegmentIndex, dist);
}
}
///
///
///
///
///
///
public static bool operator ==(Edge obj1, Edge obj2)
{
return Equals(obj1, obj2);
}
///
///
///
///
///
///
public static bool operator !=(Edge obj1, Edge obj2)
{
return !(obj1 == obj2);
}
///
/// true if the coordinate sequences of the Edges are identical.
///
///
public bool IsPointwiseEqual(Edge e)
{
if (Points.Length != e.Points.Length)
{
return false;
}
for (var i = 0; i < Points.Length; i++)
{
if (!Points[i].Equals2D(e.Points[i]))
{
return false;
}
}
return true;
}
///
///
///
///
public void Write(TextWriter outstream)
{
outstream.Write("edge " + Name + ": ");
outstream.Write("LINESTRING (");
for (var i = 0; i < Points.Length; i++)
{
if (i > 0)
{
outstream.Write(",");
}
outstream.Write(Points[i].X + " " + Points[i].Y);
}
outstream.Write(") " + label + " " + DepthDelta);
}
///
///
///
///
public void WriteReverse(TextWriter outstream)
{
outstream.Write("edge " + Name + ": ");
for (var i = Points.Length - 1; i >= 0; i--)
{
outstream.Write(Points[i] + " ");
}
outstream.WriteLine(String.Empty);
}
///
/// Update the IM with the contribution for this component.
/// A component only contributes if it has a labelling for both parent geometries.
///
///
public override void ComputeIM(IntersectionMatrix im)
{
UpdateIM(label, im);
}
///
/// Equals is defined to be:
/// e1 equals e2
/// iff
/// the coordinates of e1 are the same or the reverse of the coordinates in e2.
///
///
public override bool Equals(object o)
{
if (o == null)
{
return false;
}
if (!(o is Edge))
{
return false;
}
return Equals(o as Edge);
}
///
///
///
///
public override int GetHashCode()
{
return base.GetHashCode();
}
///
///
///
///
public override string ToString()
{
var sb = new StringBuilder();
sb.Append("edge " + Name + ": ");
sb.Append("LINESTRING (");
for (var i = 0; i < Points.Length; i++)
{
if (i > 0)
{
sb.Append(",");
}
sb.Append(Points[i].X + " " + Points[i].Y);
}
sb.Append(") " + label + " " + DepthDelta);
return sb.ToString();
}
///
/// Equals is defined to be:
/// e1 equals e2
/// iff
/// the coordinates of e1 are the same or the reverse of the coordinates in e2.
///
///
protected bool Equals(Edge e)
{
if (Points.Length != e.Points.Length)
{
return false;
}
var isEqualForward = true;
var isEqualReverse = true;
var iRev = Points.Length;
for (var i = 0; i < Points.Length; i++)
{
if (!Points[i].Equals2D(e.Points[i]))
{
isEqualForward = false;
}
if (!Points[i].Equals2D(e.Points[--iRev]))
{
isEqualReverse = false;
}
if (!isEqualForward && !isEqualReverse)
{
return false;
}
}
return true;
}
}
}