private static int MinDistToMapEdge(PlanarGraph graph, Node n, int limit) { if (n.Coordinate.X == 0 || n.Coordinate.X == Size || n.Coordinate.Y == 0 || n.Coordinate.Y == Size) return 0; int ret = int.MaxValue; Stack<Tuple<int, Node>> stack = new Stack<Tuple<int, Node>>(); HashSet<Node> visited = new HashSet<Node>(); stack.Push(new Tuple<int, Node>(0, n)); do { Tuple<int, Node> state = stack.Pop(); if (state.Item2.Coordinate.X == 0 || state.Item2.Coordinate.X == Size || state.Item2.Coordinate.Y == 0 || state.Item2.Coordinate.Y == Size) { if (state.Item1 < ret) ret = state.Item1; if (ret == 0) return 0; continue; } visited.Add(state.Item2); if (state.Item1 > limit) continue; foreach (EdgeEnd i in state.Item2.Edges) { Node node = graph.Find(i.DirectedCoordinate); if (!visited.Contains(node)) stack.Push(new Tuple<int, Node>(state.Item1 + 1, node)); } } while (stack.Count > 0); return ret; }
/// <summary> /// Constructs an instance to compute a single overlay operation /// for the given geometries. /// </summary> /// <param name="g0">The first geometry argument</param> /// <param name="g1">The second geometry argument</param> public OverlayOp(IGeometry g0, IGeometry g1) : base(g0, g1) { _graph = new PlanarGraph(new OverlayNodeFactory()); /* * Use factory of primary point. * Note that this does NOT handle mixed-precision arguments * where the second arg has greater precision than the first. */ _geomFact = g0.Factory; }
/// <summary> /// /// </summary> /// <returns></returns> public bool IsInteriorsConnected() { // node the edges, in case holes touch the shell IList<Edge> splitEdges = new List<Edge>(); _geomGraph.ComputeSplitEdges(splitEdges); // form the edges into rings PlanarGraph graph = new PlanarGraph(new OverlayNodeFactory()); graph.AddEdges(splitEdges); SetInteriorEdgesInResult(graph); graph.LinkResultDirectedEdges(); IList<EdgeRing> edgeRings = BuildEdgeRings(graph.EdgeEnds); /* * Mark all the edges for the edgeRings corresponding to the shells * of the input polygons. Note only ONE ring gets marked for each shell. */ VisitShellInteriors(this._geomGraph.Geometry, graph); /* * If there are any unvisited shell edges * (i.e. a ring which is not a hole and which has the interior * of the parent area on the RHS) * this means that one or more holes must have split the interior of the * polygon into at least two pieces. The polygon is thus invalid. */ return !HasUnvisitedShellEdge(edgeRings); }
/// <summary> /// Mark all the edges for the edgeRings corresponding to the shells of the input polygons. /// Only ONE ring gets marked for each shell - if there are others which remain unmarked /// this indicates a disconnected interior. /// </summary> /// <param name="g"></param> /// <param name="graph"></param> private void VisitShellInteriors(IGeometry g, PlanarGraph graph) { if (g is IPolygon) { IPolygon p = (IPolygon) g; VisitInteriorRing(p.Shell, graph); } if (g is IMultiPolygon) { IMultiPolygon mp = (IMultiPolygon) g; foreach (IPolygon p in mp.Geometries) VisitInteriorRing(p.Shell, graph); } }
/// <summary> /// /// </summary> /// <param name="ring"></param> /// <param name="graph"></param> private void VisitInteriorRing(ILineString ring, PlanarGraph graph) { Coordinate[] pts = ring.Coordinates; Coordinate pt0 = pts[0]; /* * Find first point in coord list different to initial point. * Need special check since the first point may be repeated. */ Coordinate pt1 = FindDifferentPoint(pts, pt0); Edge e = graph.FindEdgeInSameDirection(pt0, pt1); DirectedEdge de = (DirectedEdge) graph.FindEdgeEnd(e); DirectedEdge intDe = null; if (de.Label.GetLocation(0, Positions.Right) == Location.Interior) intDe = de; else if (de.Sym.Label.GetLocation(0, Positions.Right) == Location.Interior) intDe = de.Sym; Assert.IsTrue(intDe != null, "unable to find dirEdge with Interior on RHS"); VisitLinkedDirectedEdges(intDe); }
/// <summary> /// /// </summary> /// <param name="graph"></param> private static void SetInteriorEdgesInResult(PlanarGraph graph) { foreach (DirectedEdge de in graph.EdgeEnds) if (de.Label.GetLocation(0, Positions.Right) == Location.Interior) de.InResult = true; }
public void Generate(int pointCount) { //Generate random points var hashSet = new HashSet<Coordinate>(); { var rand = new Random(seed); while (hashSet.Count < pointCount) { var x = rand.NextDouble()*2 - 1; var y = rand.NextDouble()*2 - 1; if (x < -0.99 || y < -0.99 || x > 0.99 || y > 0.99) continue; hashSet.Add(new Coordinate(x, y)); } } //Optimize points { var points = hashSet.ToArray(); for (var i = 0; i < 2; i++) { var builder = new VoronoiDiagramBuilder(); builder.SetSites(points); VoronoiDiagram = builder.GetDiagram(new GeometryFactory()); for (var j = 0; j < points.Length; j++) { var poly = VoronoiDiagram[j] as Polygon; points[j] = new Coordinate(poly.Centroid.X, poly.Centroid.Y); } } } //Build graph PlanarGraph graph; { VoronoiDiagram = ClipGeometryCollection(VoronoiDiagram, new Envelope(-1, 1, -1, 1)); graph = new PlanarGraph(new OverlayNodeFactory()); var edges = new List<Edge>(); for (var i = 0; i < VoronoiDiagram.Count; i++) { var poly = VoronoiDiagram[i] as Polygon; var coords = poly.Coordinates; for (var j = 1; j < coords.Length; j++) { edges.Add(new Edge(new[] {coords[j - 1], coords[j]}, new Label(Location.Boundary))); } } graph.AddEdges(edges); } //Convert graph Dictionary<Node, MapNode> nodeDict; { var polys = new Dictionary<MapPolygon, HashSet<MapPolygon>>(); nodeDict = new Dictionary<Node, MapNode>(); var dats = new Dictionary<MapNode, Tuple<HashSet<MapPolygon>, HashSet<MapEdge>>>(); for (var i = 0; i < VoronoiDiagram.Count; i++) { var nodes = new List<MapNode>(); var poly = new MapPolygon { CentroidX = VoronoiDiagram[i].Centroid.X, CentroidY = VoronoiDiagram[i].Centroid.Y, Polygon = VoronoiDiagram[i] as Polygon }; foreach (var j in VoronoiDiagram[i].Coordinates.Skip(1)) { var n = graph.Find(j); MapNode mapNode; if (!nodeDict.TryGetValue(n, out mapNode)) { mapNode = new MapNode {X = j.X, Y = j.Y}; dats[mapNode] = new Tuple<HashSet<MapPolygon>, HashSet<MapEdge>>(new HashSet<MapPolygon> {poly}, new HashSet<MapEdge>()); } else dats[mapNode].Item1.Add(poly); nodes.Add(nodeDict[n] = mapNode); } poly.Nodes = nodes.ToArray(); polys.Add(poly, new HashSet<MapPolygon>()); } foreach (var i in nodeDict) { foreach (var j in dats[i.Value].Item1) foreach (var k in dats[i.Value].Item1) if (j != k) { polys[j].Add(k); polys[k].Add(j); } foreach (var j in i.Key.Edges) { var from = nodeDict[graph.Find(j.Coordinate)]; var to = nodeDict[graph.Find(j.DirectedCoordinate)]; dats[from].Item2.Add(new MapEdge {From = from, To = to}); } } var ftrh = dats.Count(_ => _.Value.Item2.Count == 0); foreach (var i in dats) i.Key.Edges = i.Value.Item2.ToArray(); var x = polys.ToArray(); for (var i = 0; i < x.Length; i++) { x[i].Key.Neighbour = x[i].Value.ToArray(); x[i].Key.Id = i; } Polygons = x.Select(_ => _.Key).ToArray(); } //Generate map DetermineLandmass(); FindOceans(); ComputeDistances(); RedistributeElevation(nodeDict.Values); FindLakesAndCoasts(); }
/// <summary> /// Add a complete graph. /// The graph is assumed to contain one or more polygons, /// possibly with holes. /// </summary> /// <param name="graph"></param> public void Add(PlanarGraph graph) { Add(graph.EdgeEnds, graph.Nodes); }
public IGeometry Buffer(IGeometry g, double distance) { IPrecisionModel precisionModel = _workingPrecisionModel; if (precisionModel == null) precisionModel = g.PrecisionModel; // factory must be the same as the one used by the input _geomFact = g.Factory; OffsetCurveBuilder curveBuilder = new OffsetCurveBuilder(precisionModel, _bufParams); OffsetCurveSetBuilder curveSetBuilder = new OffsetCurveSetBuilder(g, distance, curveBuilder); var bufferSegStrList = curveSetBuilder.GetCurves(); // short-circuit test if (bufferSegStrList.Count <= 0) { return CreateEmptyResultGeometry(); } ComputeNodedEdges(bufferSegStrList, precisionModel); _graph = new PlanarGraph(new OverlayNodeFactory()); _graph.AddEdges(_edgeList.Edges); IEnumerable<BufferSubgraph> subgraphList = CreateSubgraphs(_graph); PolygonBuilder polyBuilder = new PolygonBuilder(_geomFact); BuildSubgraphs(subgraphList, polyBuilder); var resultPolyList = polyBuilder.Polygons; // just in case... if (resultPolyList.Count <= 0) { return CreateEmptyResultGeometry(); } IGeometry resultGeom = _geomFact.BuildGeometry(resultPolyList); return resultGeom; }
private static IEnumerable<BufferSubgraph> CreateSubgraphs(PlanarGraph graph) { var subgraphList = new List<BufferSubgraph>(); foreach (Node node in graph.Nodes) { if (!node.IsVisited) { var subgraph = new BufferSubgraph(); subgraph.Create(node); subgraphList.Add(subgraph); } } /* * Sort the subgraphs in descending order of their rightmost coordinate. * This ensures that when the Polygons for the subgraphs are built, * subgraphs for shells will have been built before the subgraphs for * any holes they contain. */ subgraphList.Sort(); subgraphList.Reverse(); return subgraphList; }
public IGeometry Buffer(IGeometry g, double distance) { IPrecisionModel precisionModel = _workingPrecisionModel; if (precisionModel == null) precisionModel = g.PrecisionModel; // factory must be the same as the one used by the input _geomFact = g.Factory; OffsetCurveBuilder curveBuilder = new OffsetCurveBuilder(precisionModel, _bufParams); OffsetCurveSetBuilder curveSetBuilder = new OffsetCurveSetBuilder(g, distance, curveBuilder); var bufferSegStrList = curveSetBuilder.GetCurves(); // short-circuit test if (bufferSegStrList.Count <= 0) { return CreateEmptyResultGeometry(); } //BufferDebug.runCount++; //String filename = "run" + BufferDebug.runCount + "_curves"; //System.out.println("saving " + filename); //BufferDebug.saveEdges(bufferEdgeList, filename); // DEBUGGING ONLY //WKTWriter wktWriter = new WKTWriter(); //Debug.println("Rings: " + wktWriter.write(convertSegStrings(bufferSegStrList.iterator()))); //wktWriter.setMaxCoordinatesPerLine(10); //System.out.println(wktWriter.writeFormatted(convertSegStrings(bufferSegStrList.iterator()))); ComputeNodedEdges(bufferSegStrList, precisionModel); _graph = new PlanarGraph(new OverlayNodeFactory()); _graph.AddEdges(_edgeList.Edges); IEnumerable<BufferSubgraph> subgraphList = CreateSubgraphs(_graph); PolygonBuilder polyBuilder = new PolygonBuilder(_geomFact); BuildSubgraphs(subgraphList, polyBuilder); var resultPolyList = polyBuilder.Polygons; // just in case... if (resultPolyList.Count <= 0) { return CreateEmptyResultGeometry(); } IGeometry resultGeom = _geomFact.BuildGeometry(resultPolyList); return resultGeom; }