Class CommonBitsRemover

  1  
  2 /*
  3  * Copyright (c) 2016 Vivid Solutions.
  4  *
  5  * All rights reserved. This program and the accompanying materials
  6  * are made available under the terms of the Eclipse Public License 2.0
  7  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  8  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  9  * and the Eclipse Distribution License is available at
 10  *
 11  * http://www.eclipse.org/org/documents/edl-v10.php.
 12  */
 13 package org.locationtech.jts.precision;
 14  
 15 import org.locationtech.jts.geom.Coordinate;
 16 import org.locationtech.jts.geom.CoordinateFilter;
 17 import org.locationtech.jts.geom.CoordinateSequence;
 18 import org.locationtech.jts.geom.CoordinateSequenceFilter;
 19 import org.locationtech.jts.geom.Geometry;
 20  
 21 /**
 22  * Removes common most-significant mantissa bits 
 23  * from one or more {@link Geometry}s.
 24  * <p>
 25  * The CommonBitsRemover "scavenges" precision 
 26  * which is "wasted" by a large displacement of the geometry 
 27  * from the origin.  
 28  * For example, if a small geometry is displaced from the origin 
 29  * by a large distance, 
 30  * the displacement increases the significant figures in the coordinates, 
 31  * but does not affect the <i>relative</i> topology of the geometry.  
 32  * Thus the geometry can be translated back to the origin 
 33  * without affecting its topology.
 34  * In order to compute the translation without affecting 
 35  * the full precision of the coordinate values, 
 36  * the translation is performed at the bit level by
 37  * removing the common leading mantissa bits.
 38  * <p>
 39  * If the geometry envelope already contains the origin, 
 40  * the translation procedure cannot be applied.  
 41  * In this case, the common bits value is computed as zero.
 42  * <p>
 43  * If the geometry crosses the Y axis but not the X axis 
 44  * (and <i>mutatis mutandum</i>), 
 45  * the common bits for Y are zero, 
 46  * but the common bits for X are non-zero.
 47  *
 48  * @version 1.7
 49  */
 50 public class CommonBitsRemover
 51 {
 52   private Coordinate commonCoord;
 53   private CommonCoordinateFilter ccFilter = new CommonCoordinateFilter();
 54  
 55   public CommonBitsRemover()
 56   {
 57   }
 58  
 59   /**
 60    * Add a geometry to the set of geometries whose common bits are
 61    * being computed.  After this method has executed the
 62    * common coordinate reflects the common bits of all added
 63    * geometries.
 64    *
 65    * @param geom a Geometry to test for common bits
 66    */
 67   public void add(Geometry geom)
 68   {
 69     geom.apply(ccFilter);
 70     commonCoord = ccFilter.getCommonCoordinate();
 71   }
 72  
 73   /**
 74    * The common bits of the Coordinates in the supplied Geometries.
 75    */
 76   public Coordinate getCommonCoordinate() { return commonCoord; }
 77  
 78   /**
 79    * Removes the common coordinate bits from a Geometry.
 80    * The coordinates of the Geometry are changed.
 81    *
 82    * @param geom the Geometry from which to remove the common coordinate bits
 83    * @return the shifted Geometry
 84    */
 85   public Geometry removeCommonBits(Geometry geom)
 86   {
 87     if (commonCoord.x == 0.0 && commonCoord.y == 0.0)
 88       return geom;
 89     Coordinate invCoord = new Coordinate(commonCoord);
 90     invCoord.x = -invCoord.x;
 91     invCoord.y = -invCoord.y;
 92     Translater trans = new Translater(invCoord);
 93     geom.apply(trans);
 94     geom.geometryChanged();
 95     return geom;
 96   }
 97  
 98   /**
 99    * Adds the common coordinate bits back into a Geometry.
100    * The coordinates of the Geometry are changed.
101    *
102    * @param geom the Geometry to which to add the common coordinate bits
103    */
104   public void addCommonBits(Geometry geom)
105   {
106     Translater trans = new Translater(commonCoord);
107     geom.apply(trans);
108     geom.geometryChanged();
109   }
110  
111   static class CommonCoordinateFilter
112       implements CoordinateFilter
113   {
114     private CommonBits commonBitsX = new CommonBits();
115     private CommonBits commonBitsY = new CommonBits();
116  
117     public void filter(Coordinate coord)
118     {
119       commonBitsX.add(coord.x);
120       commonBitsY.add(coord.y);
121     }
122  
123     public Coordinate getCommonCoordinate()
124     {
125       return new Coordinate(
126           commonBitsX.getCommon(),
127           commonBitsY.getCommon());
128     }
129   }
130  
131   static class Translater
132       implements CoordinateSequenceFilter
133   {
134     Coordinate trans = null;
135  
136     public Translater(Coordinate trans)
137     {
138       this.trans = trans;
139     }
140  
141     public void filter(CoordinateSequence seq, int i) {
142       double xp = seq.getOrdinate(i, 0) + trans.x;
143       double yp = seq.getOrdinate(i, 1) + trans.y;
144       seq.setOrdinate(i, 0, xp);
145       seq.setOrdinate(i, 1, yp);  
146     }
147  
148     public boolean isDone() {
149      return false;
150     }
151  
152     public boolean isGeometryChanged() {
153       return true;
154     }
155  
156   }
157  
158 }
159