/// <summary> /// /// </summary> /// <param name="g0"></param> /// <param name="g1"></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; }
private IList CreateSubgraphs(PlanarGraph graph) { ArrayList subgraphList = new ArrayList(); foreach(object obj in graph.Nodes) { Node node = (Node)obj; if (!node.IsVisited) { BufferSubgraph 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; }
/// <summary> /// /// </summary> /// <param name="g"></param> /// <param name="distance"></param> /// <returns></returns> 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, quadrantSegments); curveBuilder.EndCapStyle = endCapStyle; OffsetCurveSetBuilder curveSetBuilder = new OffsetCurveSetBuilder(g, distance, curveBuilder); IList bufferSegStrList = curveSetBuilder.GetCurves(); // short-circuit test if (bufferSegStrList.Count <= 0) { IGeometry emptyGeom = geomFact.CreateGeometryCollection(new IGeometry[0]); return emptyGeom; } ComputeNodedEdges(bufferSegStrList, precisionModel); graph = new PlanarGraph(new OverlayNodeFactory()); graph.AddEdges(edgeList.Edges); IList subgraphList = CreateSubgraphs(graph); PolygonBuilder polyBuilder = new PolygonBuilder(geomFact); BuildSubgraphs(subgraphList, polyBuilder); IList resultPolyList = polyBuilder.Polygons; IGeometry resultGeom = geomFact.BuildGeometry(resultPolyList); return resultGeom; }
/// <summary> /// /// </summary> /// <returns></returns> public bool IsInteriorsConnected() { // node the edges, in case holes touch the shell IList splitEdges = new ArrayList(); geomGraph.ComputeSplitEdges(splitEdges); // form the edges into rings PlanarGraph graph = new PlanarGraph(new OverlayNodeFactory()); graph.AddEdges(splitEdges); SetInteriorEdgesInResult(graph); graph.LinkResultDirectedEdges(); IList 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((IGeometry) 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) { ICoordinate[] pts = ring.Coordinates; ICoordinate pt0 = pts[0]; /* * Find first point in coord list different to initial point. * Need special check since the first point may be repeated. */ ICoordinate 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) == Locations.Interior) intDe = de; else if (de.Sym.Label.GetLocation(0, Positions.Right) == Locations.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 void SetInteriorEdgesInResult(PlanarGraph graph) { foreach (DirectedEdge de in graph.EdgeEnds) if (de.Label.GetLocation(0, Positions.Right) == Locations.Interior) de.InResult = true; }
/// <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); }