using System; using System.IO; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; namespace GisSharpBlog.NetTopologySuite.GeometriesGraph { /// /// /// public class DirectedEdge : EdgeEnd { /// /// 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; } /// /// /// protected bool isForward; private bool isInResult = false; private bool isVisited = false; private DirectedEdge sym; // the symmetric edge private DirectedEdge next; // the next edge in the edge ring for the polygon containing this edge private DirectedEdge nextMin; // the next edge in the MinimalEdgeRing that contains this edge private EdgeRing edgeRing; // the EdgeRing that this edge is part of private EdgeRing minEdgeRing; // the MinimalEdgeRing that this edge is part of /// /// The depth of each side (position) of this edge. /// The 0 element of the array is never used. /// private int[] depth = { 0, -999, -999 }; /// /// /// /// /// public DirectedEdge(Edge edge, bool isForward) : base(edge) { 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 { return isInResult; } set { isInResult = value; } } /// /// /// public bool IsInResult { get { return isInResult; } } /// /// /// public bool Visited { get { return isVisited; } set { isVisited = value; } } /// /// /// public bool IsVisited { get { return isVisited; } } /// /// /// public EdgeRing EdgeRing { get { return edgeRing; } set { edgeRing = value; } } /// /// /// public EdgeRing MinEdgeRing { get { return minEdgeRing; } set { minEdgeRing = value; } } /// /// /// /// /// 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; } /// /// /// 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 this.isForward; } } /// /// /// public DirectedEdge Sym { get { return this.sym; } set { sym = value; } } /// /// /// public DirectedEdge Next { get { return next; } set { next = value; } } /// /// /// public DirectedEdge NextMin { get { return nextMin; } set { nextMin = value; } } /// /// 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; } } /// /// Compute the label in the appropriate orientation for this DirEdge. /// private void ComputeDirectedLabel() { label = new Label(edge.Label); if (!isForward) label.Flip(); } /// /// 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 override void Write(StreamWriter outstream) { base.Write(outstream); outstream.Write(" " + depth[(int)Positions.Left] + "/" + depth[(int)Positions.Right]); outstream.Write(" (" + DepthDelta + ")"); if (isInResult) outstream.Write(" inResult"); } /// /// /// /// public void WriteEdge(StreamWriter outstream) { Write(outstream); outstream.Write(" "); if (isForward) edge.Write(outstream); else edge.WriteReverse(outstream); } } }