using System.Collections;
using Core.Gis.GeoApi.Geometries;
using Core.GIS.NetTopologySuite.Algorithm;
using Core.GIS.NetTopologySuite.Geometries;
using Core.GIS.NetTopologySuite.Utilities;
namespace Core.GIS.NetTopologySuite.GeometriesGraph
{
///
///
///
public abstract class EdgeRing
{
///
/// The directed edge which starts the list of edges for this EdgeRing.
///
protected DirectedEdge startDe;
///
///
///
protected IGeometryFactory geometryFactory;
private int maxNodeDegree = -1;
private readonly IList edges = new ArrayList(); // the DirectedEdges making up this EdgeRing
private readonly IList pts = new ArrayList();
private readonly Label label = new Label(Locations.Null); // label stores the locations of each point on the face surrounded by this ring
private EdgeRing shell; // if non-null, the ring is a hole and this EdgeRing is its containing shell
private readonly ArrayList holes = new ArrayList(); // a list of EdgeRings which are holes in this EdgeRing
///
///
///
///
///
public EdgeRing(DirectedEdge start, IGeometryFactory geometryFactory)
{
this.geometryFactory = geometryFactory;
ComputePoints(start);
ComputeRing();
}
///
///
///
public bool IsIsolated
{
get
{
return label.GeometryCount == 1;
}
}
///
///
///
public bool IsHole { get; private set; }
///
///
///
public ILinearRing LinearRing { get; private set; }
///
///
///
public Label Label
{
get
{
return label;
}
}
///
///
///
public bool IsShell
{
get
{
return shell == null;
}
}
///
///
///
public EdgeRing Shell
{
get
{
return shell;
}
set
{
shell = value;
if (value != null)
{
shell.AddHole(this);
}
}
}
///
/// Returns the list of DirectedEdges that make up this EdgeRing.
///
public IList Edges
{
get
{
return edges;
}
}
///
///
///
public int MaxNodeDegree
{
get
{
if (maxNodeDegree < 0)
{
ComputeMaxNodeDegree();
}
return maxNodeDegree;
}
}
///
///
///
///
///
public ICoordinate GetCoordinate(int i)
{
return (ICoordinate) pts[i];
}
///
///
///
///
public void AddHole(EdgeRing ring)
{
holes.Add(ring);
}
///
///
///
///
///
public IPolygon ToPolygon(IGeometryFactory geometryFactory)
{
ILinearRing[] holeLR = new ILinearRing[holes.Count];
for (int i = 0; i < holes.Count; i++)
{
holeLR[i] = ((EdgeRing) holes[i]).LinearRing;
}
IPolygon poly = geometryFactory.CreatePolygon(LinearRing, holeLR);
return poly;
}
///
/// Compute a LinearRing from the point list previously collected.
/// Test if the ring is a hole (i.e. if it is CCW) and set the hole flag
/// accordingly.
///
public void ComputeRing()
{
if (LinearRing != null)
{
return; // don't compute more than once
}
ICoordinate[] coord = new ICoordinate[pts.Count];
for (int i = 0; i < pts.Count; i++)
{
coord[i] = (ICoordinate) pts[i];
}
LinearRing = geometryFactory.CreateLinearRing(coord);
IsHole = CGAlgorithms.IsCCW(LinearRing.Coordinates);
}
///
///
///
///
///
public abstract DirectedEdge GetNext(DirectedEdge de);
///
///
///
///
///
public abstract void SetEdgeRing(DirectedEdge de, EdgeRing er);
///
///
///
public void SetInResult()
{
DirectedEdge de = startDe;
do
{
de.Edge.InResult = true;
de = de.Next;
} while (de != startDe);
}
///
/// This method will cause the ring to be computed.
/// It will also check any holes, if they have been assigned.
///
///
public bool ContainsPoint(ICoordinate p)
{
ILinearRing shell = LinearRing;
IEnvelope env = shell.EnvelopeInternal;
if (!env.Contains(p))
{
return false;
}
if (!CGAlgorithms.IsPointInRing(p, shell.Coordinates))
{
return false;
}
for (IEnumerator i = holes.GetEnumerator(); i.MoveNext();)
{
EdgeRing hole = (EdgeRing) i.Current;
if (hole.ContainsPoint(p))
{
return false;
}
}
return true;
}
///
/// Collect all the points from the DirectedEdges of this ring into a contiguous list.
///
///
protected void ComputePoints(DirectedEdge start)
{
startDe = start;
DirectedEdge de = start;
bool isFirstEdge = true;
do
{
Assert.IsTrue(de != null, "found null Directed Edge");
if (de.EdgeRing == this)
{
throw new TopologyException("Directed Edge visited twice during ring-building at " + de.Coordinate);
}
edges.Add(de);
Label label = de.Label;
Assert.IsTrue(label.IsArea());
MergeLabel(label);
AddPoints(de.Edge, de.IsForward, isFirstEdge);
isFirstEdge = false;
SetEdgeRing(de, this);
de = GetNext(de);
} while (de != startDe);
}
///
///
///
///
protected void MergeLabel(Label deLabel)
{
MergeLabel(deLabel, 0);
MergeLabel(deLabel, 1);
}
///
/// Merge the RHS label from a DirectedEdge into the label for this EdgeRing.
/// The DirectedEdge label may be null. This is acceptable - it results
/// from a node which is NOT an intersection node between the Geometries
/// (e.g. the end node of a LinearRing). In this case the DirectedEdge label
/// does not contribute any information to the overall labelling, and is simply skipped.
///
///
///
protected void MergeLabel(Label deLabel, int geomIndex)
{
Locations loc = deLabel.GetLocation(geomIndex, Positions.Right);
// no information to be had from this label
if (loc == Locations.Null)
{
return;
}
// if there is no current RHS value, set it
if (label.GetLocation(geomIndex) == Locations.Null)
{
label.SetLocation(geomIndex, loc);
return;
}
}
///
///
///
///
///
///
protected void AddPoints(Edge edge, bool isForward, bool isFirstEdge)
{
ICoordinate[] edgePts = edge.Coordinates;
if (isForward)
{
int startIndex = 1;
if (isFirstEdge)
{
startIndex = 0;
}
for (int i = startIndex; i < edgePts.Length; i++)
{
pts.Add(edgePts[i]);
}
}
else
{
// is backward
int startIndex = edgePts.Length - 2;
if (isFirstEdge)
{
startIndex = edgePts.Length - 1;
}
for (int i = startIndex; i >= 0; i--)
{
pts.Add(edgePts[i]);
}
}
}
///
///
///
private void ComputeMaxNodeDegree()
{
maxNodeDegree = 0;
DirectedEdge de = startDe;
do
{
Node node = de.Node;
int degree = ((DirectedEdgeStar) node.Edges).GetOutgoingDegree(this);
if (degree > maxNodeDegree)
{
maxNodeDegree = degree;
}
de = GetNext(de);
} while (de != startDe);
maxNodeDegree *= 2;
}
}
}