private static void ComputeSegmentsInner(List <Segment> segments, Reach reach) { if (reach.HasDam) { foreach (var node in reach.Nodes) { if (node.Dam == null) { continue; } var segment = new Segment { Dam = node.Dam }; segment.UpstreamLength = ComputeSegmentLength(reach, node, segment.Id); segments.Add(segment); } } if (reach.UpstreamReaches != null) { foreach (var up in reach.UpstreamReaches) { ComputeSegmentsInner(segments, up); } } }
private static void AddSegmentIdToReach(Reach reach, int id) { if (reach.SegmentId == null) { reach.SegmentId = new List <int>(); } if (!reach.SegmentId.Contains(id)) { reach.SegmentId.Add(id); } }
private static void InitializeNetworkInner(List <Reach> reaches, Reach root) { // get the root reach // using the root reach, find the end node (first or last in list) // search the nodes for matches, get list of reaches that represent children // add list of reaches to root reach _inChecklist.Add(root.Id); foreach (var r in reaches) { if (_inChecklist.Contains(r.Id)) { continue; } if (root.Upstream.Location.Match(r.Downstream.Location, 5) || root.Upstream.Location.Match(r.Upstream.Location, 5)) { if (root.Upstream.Location.Match(r.Upstream.Location, 5)) { r.Nodes.Reverse(); } //Debug.Assert(root.Upstream.Location.Match(r.Downstream.Location)); if (root.UpstreamReaches == null) { root.UpstreamReaches = new List <Reach>(); } if (r.Id == root.DownstreamReach?.Id) { throw new ArgumentException("cycle in graph"); } _inChecklist.Add(r.Id); root.UpstreamReaches.Add(r); if (r.DownstreamReach != null) { throw new ArgumentException("initialization error"); } r.DownstreamReach = root; } Debug.Assert(!root.Downstream.Location.Match(r.Upstream.Location)); Debug.Assert(!root.Downstream.Location.Match(r.Downstream.Location)); } if (root.UpstreamReaches != null) { foreach (var u in root.UpstreamReaches) { InitializeNetworkInner(reaches, u); } } }
private static List <Segment> ComputeSegments(Reach outlet) { var segments = new List <Segment> { new Segment { UpstreamLength = ComputeSegmentLength(outlet, outlet.Downstream, 0) } }; ComputeSegmentsInner(segments, outlet); return(segments); }
private static double ComputeSegmentLengthInner(Reach reach, int id, double?fromDam = null) { _debugLevel++; var distance = 0.0; if (reach.UpstreamReaches != null) { foreach (var ur in reach.UpstreamReaches) { AddSegmentIdToReach(ur, id); Print($"{ur}"); if (ur.HasDam) { var toDam = 0.0; for (var i = 0; i < ur.Nodes.Count - 1; i++) { if (ur.Nodes[i].Dam != null) { break; } toDam += ur.Nodes[i].Location.Distance(ur.Nodes[i + 1].Location); ur.Nodes[i].SegmentId = id; } Print($" TO DAM: {toDam}"); distance += toDam; } else { distance += ComputeSegmentLengthInner(ur, id); } } } _debugLevel--; distance += fromDam ?? reach.Length; Print($"{reach.Id}: {distance}" + (fromDam != null ? $" FD:{fromDam}" : "")); return(distance); }
/// <summary> /// Compute the length of river in the given segment and mark each reach with the segment /// id for later creation of the segment network. /// </summary> private static double ComputeSegmentLength(Reach reach, Node node, int id) { AddSegmentIdToReach(reach, id); var index = reach.Nodes.IndexOf(node); var distance = 0.0; for (var i = index; i < reach.Nodes.Count - 1; i++) { if (i != index && reach.Nodes[i].Dam != null) // dam in the same reach { return(distance); } distance += reach.Nodes[i].Location.Distance(reach.Nodes[i + 1].Location); reach.Nodes[i].SegmentId = id; } Print($"SEGMENT: {id} - {reach}"); var rv = ComputeSegmentLengthInner(reach, id, distance); Print($"SEGMENT: {id} is {rv}"); return(rv); }
/// <summary> /// Parses the so-called "well known text" LINESTRING into a list of nodes. /// </summary> /// <param name="wkt">The well known text string</param> /// <param name="outlet">Location of the outlet</param> /// <param name="arcId">Id of the arc or "reach"</param> /// <returns></returns> private static Reach ParseLinestring(String wkt, string arcId, Location outlet) { var reach = new Reach(); var nodes = new List <Node>(); reach.Nodes = nodes; reach.Id = int.Parse(arcId); // todo: this is super-simplistic with no error checking/recovery. // LINESTRING ( x y, x y, ... ) var s1 = wkt.Replace("LINESTRING (", ""); var s2 = s1.Replace(")", ""); var s3 = s2.Split(','); var isOutlet = false; foreach (var s in s3) { var node = new Node(); var pt = s.Split(' '); node.Location.Longitude = Double.Parse(pt[0]); node.Location.Latitude = Double.Parse(pt[1]); if (node.Location.Match(outlet)) { isOutlet = true; } nodes.Add(node); } if (isOutlet && outlet.Match(reach.Upstream.Location)) { reach.Nodes.Reverse(); Debug.Assert(reach.Downstream.Location.Match(outlet)); } reach.Outlet = isOutlet; return(reach); }