using System; using System.IO; using Core.Gis.GeoApi.Geometries; using Core.GIS.NetTopologySuite.Geometries; namespace Core.GIS.NetTopologySuite.GeometriesGraph { /// /// /// public class DirectedEdge : EdgeEnd { /// /// /// protected bool isForward; /// /// The depth of each side (position) of this edge. /// The 0 element of the array is never used. /// private readonly int[] depth = { 0, -999, -999 }; /// /// /// /// /// public DirectedEdge(Edge edge, bool isForward) : base(edge) { Visited = false; InResult = false; this.isForward = isForward; if (isForward) { Init(edge.GetCoordinate(0), edge.GetCoordinate(1)); } else { int n = edge.NumPoints - 1; Init(edge.GetCoordinate(n), edge.GetCoordinate(n - 1)); } ComputeDirectedLabel(); } /// /// /// public bool InResult { get; set; } /// /// /// public bool IsInResult { get { return InResult; } } /// /// /// public bool Visited { get; set; } /// /// /// public bool IsVisited { get { return Visited; } } /// /// /// public EdgeRing EdgeRing { get; set; } /// /// /// public EdgeRing MinEdgeRing { get; set; } /// /// /// public int DepthDelta { get { int depthDelta = edge.DepthDelta; if (!IsForward) { depthDelta = -depthDelta; } return depthDelta; } } /// /// VisitedEdge get property returns true if bot Visited /// and Sym.Visited are true. /// VisitedEdge set property marks both DirectedEdges attached to a given Edge. /// This is used for edges corresponding to lines, which will only /// appear oriented in a single direction in the result. /// public bool VisitedEdge { get { return Visited && Sym.Visited; } set { Visited = value; Sym.Visited = value; } } /// /// /// public bool IsForward { get { return isForward; } } /// /// /// public DirectedEdge Sym { get; set; } /// /// /// public DirectedEdge Next { get; set; } /// /// /// public DirectedEdge NextMin { get; set; } /// /// This edge is a line edge if /// at least one of the labels is a line label /// any labels which are not line labels have all Locations = Exterior. /// public bool IsLineEdge { get { bool isLine = label.IsLine(0) || label.IsLine(1); bool isExteriorIfArea0 = !label.IsArea(0) || label.AllPositionsEqual(0, Locations.Exterior); bool isExteriorIfArea1 = !label.IsArea(1) || label.AllPositionsEqual(1, Locations.Exterior); return isLine && isExteriorIfArea0 && isExteriorIfArea1; } } /// /// This is an interior Area edge if /// its label is an Area label for both Geometries /// and for each Geometry both sides are in the interior. /// /// true if this is an interior Area edge. public bool IsInteriorAreaEdge { get { bool isInteriorAreaEdge = true; for (int i = 0; i < 2; i++) { if (!(label.IsArea(i) && label.GetLocation(i, Positions.Left) == Locations.Interior && label.GetLocation(i, Positions.Right) == Locations.Interior)) { isInteriorAreaEdge = false; } } return isInteriorAreaEdge; } } /// /// Computes the factor for the change in depth when moving from one location to another. /// E.g. if crossing from the Interior to the Exterior the depth decreases, so the factor is -1. /// public static int DepthFactor(Locations currLocation, Locations nextLocation) { if (currLocation == Locations.Exterior && nextLocation == Locations.Interior) { return 1; } else if (currLocation == Locations.Interior && nextLocation == Locations.Exterior) { return -1; } return 0; } /// /// /// /// /// public int GetDepth(Positions position) { return depth[(int) position]; } /// /// /// /// /// public void SetDepth(Positions position, int depthVal) { if (depth[(int) position] != -999) { if (depth[(int) position] != depthVal) { throw new TopologyException("assigned depths do not match", Coordinate); } } depth[(int) position] = depthVal; } /// /// Set both edge depths. /// One depth for a given side is provided. /// The other is computed depending on the Location /// transition and the depthDelta of the edge. /// /// /// public void SetEdgeDepths(Positions position, int depth) { // get the depth transition delta from R to Curve for this directed Edge int depthDelta = Edge.DepthDelta; if (!isForward) { depthDelta = -depthDelta; } // if moving from Curve to R instead of R to Curve must change sign of delta int directionFactor = 1; if (position == Positions.Left) { directionFactor = -1; } Positions oppositePos = Position.Opposite(position); int delta = depthDelta*directionFactor; int oppositeDepth = depth + delta; SetDepth(position, depth); SetDepth(oppositePos, oppositeDepth); } /// /// Set both edge depths. One depth for a given side is provided. The other is /// computed depending on the Location transition and the depthDelta of the edge. /// /// /// [Obsolete("Use SetEdgeDepths instead")] public void OLDSetEdgeDepths(Positions position, int depth) { int depthDelta = Edge.DepthDelta; Locations loc = label.GetLocation(0, position); Positions oppositePos = Position.Opposite(position); Locations oppositeLoc = label.GetLocation(0, oppositePos); int delta = Math.Abs(depthDelta)*DepthFactor(loc, oppositeLoc); int oppositeDepth = depth + delta; SetDepth(position, depth); SetDepth(oppositePos, oppositeDepth); } /// /// /// /// public void WriteEdge(StreamWriter outstream) { Write(outstream); outstream.Write(" "); if (isForward) { edge.Write(outstream); } else { edge.WriteReverse(outstream); } } /// /// /// /// public override void Write(StreamWriter outstream) { base.Write(outstream); outstream.Write(" " + depth[(int) Positions.Left] + "/" + depth[(int) Positions.Right]); outstream.Write(" (" + DepthDelta + ")"); if (InResult) { outstream.Write(" inResult"); } } /// /// Compute the label in the appropriate orientation for this DirEdge. /// private void ComputeDirectedLabel() { label = new Label(edge.Label); if (!isForward) { label.Flip(); } } } }