Class LineBuilder

  1 /*
  2  * Copyright (c) 2016 Vivid Solutions.
  3  *
  4  * All rights reserved. This program and the accompanying materials
  5  * are made available under the terms of the Eclipse Public License 2.0
  6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  8  * and the Eclipse Distribution License is available at
  9  *
 10  * http://www.eclipse.org/org/documents/edl-v10.php.
 11  */
 12 package org.locationtech.jts.operation.overlay;
 13  
 14 import java.util.ArrayList;
 15 import java.util.Iterator;
 16 import java.util.List;
 17  
 18 import org.locationtech.jts.algorithm.PointLocator;
 19 import org.locationtech.jts.geom.GeometryFactory;
 20 import org.locationtech.jts.geom.LineString;
 21 import org.locationtech.jts.geomgraph.DirectedEdge;
 22 import org.locationtech.jts.geomgraph.DirectedEdgeStar;
 23 import org.locationtech.jts.geomgraph.Edge;
 24 import org.locationtech.jts.geomgraph.Label;
 25 import org.locationtech.jts.geomgraph.Node;
 26 import org.locationtech.jts.util.Assert;
 27  
 28 /**
 29  * Forms JTS LineStrings out of a the graph of {@link DirectedEdge}s
 30  * created by an {@link OverlayOp}.
 31  *
 32  * @version 1.7
 33  */
 34 public class LineBuilder {
 35   private OverlayOp op;
 36   private GeometryFactory geometryFactory;
 37   private PointLocator ptLocator;
 38  
 39   private List lineEdgesList    = new ArrayList();
 40   private List resultLineList   = new ArrayList();
 41  
 42   public LineBuilder(OverlayOp op, GeometryFactory geometryFactory, PointLocator ptLocator) {
 43     this.op = op;
 44     this.geometryFactory = geometryFactory;
 45     this.ptLocator = ptLocator;
 46   }
 47   /**
 48    * @return a list of the LineStrings in the result of the specified overlay operation
 49    */
 50   public List build(int opCode)
 51   {
 52     findCoveredLineEdges();
 53     collectLines(opCode);
 54     //labelIsolatedLines(lineEdgesList);
 55     buildLines(opCode);
 56     return resultLineList;
 57   }
 58   /**
 59    * Find and mark L edges which are "covered" by the result area (if any).
 60    * L edges at nodes which also have A edges can be checked by checking
 61    * their depth at that node.
 62    * L edges at nodes which do not have A edges can be checked by doing a
 63    * point-in-polygon test with the previously computed result areas.
 64    */
 65   private void findCoveredLineEdges()
 66   {
 67     // first set covered for all L edges at nodes which have A edges too
 68     for (Iterator nodeit = op.getGraph().getNodes().iterator(); nodeit.hasNext(); ) {
 69       Node node = (Node) nodeit.next();
 70 //node.print(System.out);
 71       ((DirectedEdgeStar) node.getEdges()).findCoveredLineEdges();
 72     }
 73  
 74     /**
 75      * For all L edges which weren't handled by the above,
 76      * use a point-in-poly test to determine whether they are covered
 77      */
 78     for (Iterator it = op.getGraph().getEdgeEnds().iterator(); it.hasNext(); ) {
 79       DirectedEdge de = (DirectedEdge) it.next();
 80       Edge e = de.getEdge();
 81       if (de.isLineEdge() && ! e.isCoveredSet()) {
 82         boolean isCovered = op.isCoveredByA(de.getCoordinate());
 83         e.setCovered(isCovered);
 84       }
 85     }
 86   }
 87  
 88   private void collectLines(int opCode)
 89   {
 90     for (Iterator it = op.getGraph().getEdgeEnds().iterator(); it.hasNext(); ) {
 91       DirectedEdge de = (DirectedEdge) it.next();
 92       collectLineEdge(de, opCode, lineEdgesList);
 93       collectBoundaryTouchEdge(de, opCode, lineEdgesList);
 94     }
 95   }
 96  
 97   /**
 98    * Collect line edges which are in the result.
 99    * Line edges are in the result if they are not part of
100    * an area boundary, if they are in the result of the overlay operation,
101    * and if they are not covered by a result area.
102    *
103    * @param de the directed edge to test
104    * @param opCode the overlap operation
105    * @param edges the list of included line edges
106    */
107   private void collectLineEdge(DirectedEdge de, int opCode, List edges)
108   {
109     Label label = de.getLabel();
110     Edge e = de.getEdge();
111     // include L edges which are in the result
112     if (de.isLineEdge()) {
113       if (! de.isVisited() && OverlayOp.isResultOfOp(label, opCode) && ! e.isCovered()) {
114 //Debug.println("de: " + de.getLabel());
115 //Debug.println("edge: " + e.getLabel());
116  
117         edges.add(e);
118         de.setVisitedEdge(true);
119       }
120     }
121   }
122  
123   /**
124    * Collect edges from Area inputs which should be in the result but
125    * which have not been included in a result area.
126    * This happens ONLY:
127    * <ul>
128    * <li>during an intersection when the boundaries of two
129    * areas touch in a line segment
130    * <li> OR as a result of a dimensional collapse.
131    * </ul>
132    */
133   private void collectBoundaryTouchEdge(DirectedEdge de, int opCode, List edges)
134   {
135     Label label = de.getLabel();
136     if (de.isLineEdge()) return;  // only interested in area edges
137     if (de.isVisited()) return;  // already processed
138     if (de.isInteriorAreaEdge()) return;  // added to handle dimensional collapses
139     if (de.getEdge().isInResult()) return;  // if the edge linework is already included, don't include it again
140  
141     // sanity check for labelling of result edgerings
142     Assert.isTrue(! (de.isInResult() || de.getSym().isInResult()) || ! de.getEdge().isInResult());
143  
144     // include the linework if it's in the result of the operation
145     if (OverlayOp.isResultOfOp(label, opCode)
146           && opCode == OverlayOp.INTERSECTION)
147     {
148       edges.add(de.getEdge());
149       de.setVisitedEdge(true);
150     }
151   }
152  
153   private void buildLines(int opCode)
154   {
155     for (Iterator it = lineEdgesList.iterator(); it.hasNext(); ) {
156       Edge e = (Edge) it.next();
157       // Label label = e.getLabel();
158         LineString line = geometryFactory.createLineString(e.getCoordinates());
159         resultLineList.add(line);
160         e.setInResult(true);
161     }
162   }
163  
164   private void labelIsolatedLines(List edgesList)
165   {
166     for (Iterator it = edgesList.iterator(); it.hasNext(); ) {
167       Edge e = (Edge) it.next();
168       Label label = e.getLabel();
169 //n.print(System.out);
170       if (e.isIsolated()) {
171         if (label.isNull(0))
172           labelIsolatedLine(e, 0);
173         else
174           labelIsolatedLine(e, 1);
175       }
176     }
177   }
178   /**
179    * Label an isolated node with its relationship to the target geometry.
180    */
181   private void labelIsolatedLine(Edge e, int targetIndex)
182   {
183     int loc = ptLocator.locate(e.getCoordinate(), op.getArgGeometry(targetIndex));
184     e.getLabel().setLocation(targetIndex, loc);
185   }
186  
187  
188 }
189