Class GeometryCombiner

  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  
 13 package org.locationtech.jts.geom.util;
 14  
 15 import java.util.ArrayList;
 16 import java.util.Collection;
 17 import java.util.Iterator;
 18 import java.util.List;
 19  
 20 import org.locationtech.jts.geom.Geometry;
 21 import org.locationtech.jts.geom.GeometryCollection;
 22 import org.locationtech.jts.geom.GeometryFactory;
 23 import org.locationtech.jts.geom.Polygonal;
 24  
 25  
 26 /**
 27  * Combines {@link Geometry}s
 28  * to produce a {@link GeometryCollection} of the most appropriate type.
 29  * Input geometries which are already collections
 30  * will have their elements extracted first.
 31  * No validation of the result geometry is performed.
 32  * (The only case where invalidity is possible is where {@link Polygonal} geometries
 33  * are combined and result in a self-intersection).
 34  * 
 35  * @author mbdavis
 36  * @see GeometryFactory#buildGeometry
 37  */
 38 public class GeometryCombiner 
 39 {
 40     /**
 41      * Combines a collection of geometries.
 42      * 
 43      * @param geoms the geometries to combine
 44      * @return the combined geometry
 45      */
 46     public static Geometry combine(Collection geoms)
 47     {
 48         GeometryCombiner combiner = new GeometryCombiner(geoms);
 49         return combiner.combine();
 50     }
 51     
 52     /**
 53      * Combines two geometries.
 54      * 
 55      * @param g0 a geometry to combine
 56      * @param g1 a geometry to combine
 57      * @return the combined geometry
 58      */
 59     public static Geometry combine(Geometry g0, Geometry g1)
 60     {
 61         GeometryCombiner combiner = new GeometryCombiner(createList(g0, g1));
 62         return combiner.combine();
 63     }
 64     
 65     /**
 66      * Combines three geometries.
 67      * 
 68      * @param g0 a geometry to combine
 69      * @param g1 a geometry to combine
 70      * @param g2 a geometry to combine
 71      * @return the combined geometry
 72      */
 73     public static Geometry combine(Geometry g0, Geometry g1, Geometry g2)
 74     {
 75         GeometryCombiner combiner = new GeometryCombiner(createList(g0, g1, g2));
 76         return combiner.combine();
 77     }
 78     
 79     /**
 80      * Creates a list from two items
 81      * 
 82      * @param obj0
 83      * @param obj1
 84      * @return a List containing the two items
 85      */
 86   private static List createList(Object obj0, Object obj1)
 87   {
 88         List list = new ArrayList();
 89         list.add(obj0);
 90         list.add(obj1);
 91         return list;
 92   }
 93   
 94     /**
 95      * Creates a list from two items
 96      * 
 97      * @param obj0
 98      * @param obj1
 99      * @return a List containing the two items
100      */
101   private static List createList(Object obj0, Object obj1, Object obj2)
102   {
103         List list = new ArrayList();
104         list.add(obj0);
105         list.add(obj1);
106         list.add(obj2);
107         return list;
108   }
109   
110     private GeometryFactory geomFactory;
111     private boolean skipEmpty = false;
112     private Collection inputGeoms;
113         
114     /**
115      * Creates a new combiner for a collection of geometries
116      * 
117      * @param geoms the geometries to combine
118      */
119     public GeometryCombiner(Collection geoms)
120     {
121         geomFactory = extractFactory(geoms);
122         this.inputGeoms = geoms;
123     }
124     
125     /**
126      * Extracts the GeometryFactory used by the geometries in a collection
127      * 
128      * @param geoms
129      * @return a GeometryFactory
130      */
131     public static GeometryFactory extractFactory(Collection geoms) {
132         if (geoms.isEmpty())
133             return null;
134         return ((Geometry) geoms.iterator().next()).getFactory();
135     }
136     
137     /**
138      * Computes the combination of the input geometries
139      * to produce the most appropriate {@link Geometry} or {@link GeometryCollection}
140      * 
141      * @return a Geometry which is the combination of the inputs
142      */
143   public Geometry combine()
144   {
145       List elems = new ArrayList();
146       for (Iterator i = inputGeoms.iterator(); i.hasNext(); ) {
147           Geometry g = (Geometry) i.next();
148           extractElements(g, elems);
149       }
150     
151     if (elems.size() == 0) {
152         if (geomFactory != null) {
153       // return an empty GC
154             return geomFactory.createGeometryCollection();
155         }
156         return null;
157     }
158     // return the "simplest possible" geometry
159     return geomFactory.buildGeometry(elems);
160   }
161   
162   private void extractElements(Geometry geom, List elems)
163   {
164     if (geom == null)
165       return;
166     
167     for (int i = 0; i < geom.getNumGeometries(); i++) {
168       Geometry elemGeom = geom.getGeometryN(i);
169       if (skipEmpty && elemGeom.isEmpty())
170         continue;
171       elems.add(elemGeom);
172     }
173   }
174  
175 }
176