Class SegmentStringDissolver

  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.noding;
 13  
 14 import java.util.Collection;
 15 import java.util.Iterator;
 16 import java.util.Map;
 17 import java.util.TreeMap;
 18  
 19 import org.locationtech.jts.geom.CoordinateArrays;
 20  
 21 /**
 22  * Dissolves a noded collection of {@link SegmentString}s to produce
 23  * a set of merged linework with unique segments.
 24  * A custom {@link SegmentStringMerger} merging strategy
 25  * can be supplied.  
 26  * This strategy will be called when two identical (up to orientation)
 27  * strings are dissolved together.
 28  * The default merging strategy is simply to discard one of the merged strings.
 29  * <p>
 30  * A common use for this class is to merge noded edges
 31  * while preserving topological labelling.
 32  * This requires a custom merging strategy to be supplied 
 33  * to merge the topology labels appropriately.
 34  *
 35  * @version 1.7
 36  * @see SegmentStringMerger
 37  */
 38 public class SegmentStringDissolver
 39 {
 40     /**
 41      * A merging strategy which can be used to update the context data of {@link SegmentString}s 
 42      * which are merged during the dissolve process.
 43      * 
 44      * @author mbdavis
 45      *
 46      */
 47   public interface SegmentStringMerger 
 48   {
 49     /**
 50      * Updates the context data of a SegmentString
 51      * when an identical (up to orientation) one is found during dissolving.
 52      *
 53      * @param mergeTarget the segment string to update
 54      * @param ssToMerge the segment string being dissolved
 55      * @param isSameOrientation <code>true</code> if the strings are in the same direction,
 56      * <code>false</code> if they are opposite
 57      */
 58     void merge(SegmentString mergeTarget, SegmentString ssToMerge, boolean isSameOrientation);
 59   }
 60  
 61   private SegmentStringMerger merger;
 62   private Map ocaMap = new TreeMap();
 63  
 64   // testing only
 65   //private List testAddedSS = new ArrayList();
 66  
 67   /**
 68    * Creates a dissolver with a user-defined merge strategy.
 69    *
 70    * @param merger the merging strategy to use
 71    */
 72   public SegmentStringDissolver(SegmentStringMerger merger) {
 73     this.merger = merger;
 74   }
 75  
 76   /**
 77    * Creates a dissolver with the default merging strategy.
 78    */
 79   public SegmentStringDissolver() {
 80     this(null);
 81   }
 82  
 83   /**
 84    * Dissolve all {@link SegmentString}s in the input {@link Collection}
 85    * @param segStrings
 86    */
 87   public void dissolve(Collection segStrings)
 88   {
 89     for (Iterator i = segStrings.iterator(); i.hasNext(); ) {
 90       dissolve((SegmentString) i.next());
 91     }
 92   }
 93  
 94   private void add(OrientedCoordinateArray oca, SegmentString segString)
 95   {
 96     ocaMap.put(oca, segString);
 97     //testAddedSS.add(oca);
 98   }
 99  
100   /**
101    * Dissolve the given {@link SegmentString}.
102    *
103    * @param segString the string to dissolve
104    */
105   public void dissolve(SegmentString segString)
106   {
107     OrientedCoordinateArray oca = new OrientedCoordinateArray(segString.getCoordinates());
108     SegmentString existing = findMatching(oca, segString);
109     if (existing == null) {
110       add(oca, segString);
111     }
112     else {
113       if (merger != null) {
114         boolean isSameOrientation
115             = CoordinateArrays.equals(existing.getCoordinates(), segString.getCoordinates());
116         merger.merge(existing, segString, isSameOrientation);
117       }
118     }
119   }
120  
121   private SegmentString findMatching(OrientedCoordinateArray oca,
122                                     SegmentString segString)
123   {
124     SegmentString matchSS = (SegmentString) ocaMap.get(oca);
125     /*
126     boolean hasBeenAdded = checkAdded(oca);
127     if (matchSS == null && hasBeenAdded) {
128       System.out.println("added!");
129     }
130     */
131     return matchSS;
132   }
133  
134 /*
135
136   private boolean checkAdded(OrientedCoordinateArray oca)
137   {
138     for (Iterator i = testAddedSS.iterator(); i.hasNext(); ) {
139       OrientedCoordinateArray addedOCA = (OrientedCoordinateArray) i.next();
140       if (oca.compareTo(addedOCA) == 0)
141         return true;
142     }
143     return false;
144   }
145 */
146  
147   /**
148    * Gets the collection of dissolved (i.e. unique) {@link SegmentString}s
149    *
150    * @return the unique {@link SegmentString}s
151    */
152   public Collection getDissolved() { return ocaMap.values(); }
153 }
154  
155  
156  
157