Class SnapOverlayOp

  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.operation.overlay.snap;
 14  
 15 import org.locationtech.jts.geom.Geometry;
 16 import org.locationtech.jts.operation.overlay.OverlayOp;
 17 import org.locationtech.jts.precision.CommonBitsRemover;
 18  
 19 /**
 20  * Performs an overlay operation using snapping and enhanced precision
 21  * to improve the robustness of the result.
 22  * This class <i>always</i> uses snapping.  
 23  * This is less performant than the standard JTS overlay code, 
 24  * and may even introduce errors which were not present in the original data.
 25  * For this reason, this class should only be used 
 26  * if the standard overlay code fails to produce a correct result. 
 27  *  
 28  * @author Martin Davis
 29  * @version 1.7
 30  */
 31 public class SnapOverlayOp
 32 {
 33   public static Geometry overlayOp(Geometry g0, Geometry g1, int opCode)
 34   {
 35       SnapOverlayOp op = new SnapOverlayOp(g0, g1);
 36       return op.getResultGeometry(opCode);
 37   }
 38  
 39   public static Geometry intersection(Geometry g0, Geometry g1)
 40   {
 41      return overlayOp(g0, g1, OverlayOp.INTERSECTION);
 42   }
 43  
 44   public static Geometry union(Geometry g0, Geometry g1)
 45   {
 46      return overlayOp(g0, g1, OverlayOp.UNION);
 47   }
 48  
 49   public static Geometry difference(Geometry g0, Geometry g1)
 50   {
 51      return overlayOp(g0, g1, OverlayOp.DIFFERENCE);
 52   }
 53  
 54   public static Geometry symDifference(Geometry g0, Geometry g1)
 55   {
 56      return overlayOp(g0, g1, OverlayOp.SYMDIFFERENCE);
 57   }
 58   
 59  
 60   private Geometry[] geom = new Geometry[2];
 61   private double snapTolerance;
 62  
 63   public SnapOverlayOp(Geometry g1, Geometry g2)
 64   {
 65     geom[0] = g1;
 66     geom[1] = g2;
 67     computeSnapTolerance();
 68   }
 69   private void computeSnapTolerance() 
 70   {
 71         snapTolerance = GeometrySnapper.computeOverlaySnapTolerance(geom[0], geom[1]);
 72  
 73         // System.out.println("Snap tol = " + snapTolerance);
 74     }
 75  
 76   public Geometry getResultGeometry(int opCode)
 77   {
 78 //      Geometry[] selfSnapGeom = new Geometry[] { selfSnap(geom[0]), selfSnap(geom[1])};
 79     Geometry[] prepGeom = snap(geom);
 80     Geometry result = OverlayOp.overlayOp(prepGeom[0], prepGeom[1], opCode);
 81     return prepareResult(result);    
 82   }
 83   
 84   private Geometry selfSnap(Geometry geom)
 85   {
 86     GeometrySnapper snapper0 = new GeometrySnapper(geom);
 87     Geometry snapGeom = snapper0.snapTo(geom, snapTolerance);
 88     //System.out.println("Self-snapped: " + snapGeom);
 89     //System.out.println();
 90     return snapGeom;
 91   }
 92   
 93   private Geometry[] snap(Geometry[] geom)
 94   {
 95     Geometry[] remGeom = removeCommonBits(geom);
 96       
 97       // MD - testing only
 98 //      Geometry[] remGeom = geom;
 99     
100     Geometry[] snapGeom = GeometrySnapper.snap(remGeom[0], remGeom[1], snapTolerance);
101     // MD - may want to do this at some point, but it adds cycles
102 //    checkValid(snapGeom[0]);
103 //    checkValid(snapGeom[1]);
104  
105     /*
106     System.out.println("Snapped geoms: ");
107     System.out.println(snapGeom[0]);
108     System.out.println(snapGeom[1]);
109     */
110     return snapGeom;
111   }
112  
113   private Geometry prepareResult(Geometry geom)
114   {
115     cbr.addCommonBits(geom);
116     return geom;
117   }
118  
119   private CommonBitsRemover cbr;
120  
121   private Geometry[] removeCommonBits(Geometry[] geom)
122   {
123     cbr = new CommonBitsRemover();
124     cbr.add(geom[0]);
125     cbr.add(geom[1]);
126     Geometry remGeom[] = new Geometry[2];
127     remGeom[0] = cbr.removeCommonBits(geom[0].copy());
128     remGeom[1] = cbr.removeCommonBits(geom[1].copy());
129     return remGeom;
130   }
131   
132   private void checkValid(Geometry g)
133   {
134       if (! g.isValid()) {
135           System.out.println("Snapped geometry is invalid");
136       }
137   }
138 }
139