@@ -43,7 +43,6 @@ public long encode(double x, double y) {
4343
4444 @ Override
4545 public int setValues (GeoShapeCellValues values , GeoShapeValues .GeoShapeValue geoValue ) throws IOException {
46-
4746 if (precision == 0 ) {
4847 return 1 ;
4948 }
@@ -52,60 +51,65 @@ public int setValues(GeoShapeCellValues values, GeoShapeValues.GeoShapeValue geo
5251
5352 // When the shape represents a point, we compute the hash directly as we do it for GeoPoint
5453 if (bounds .minX () == bounds .maxX () && bounds .minY () == bounds .maxY ()) {
55- return setValue (values , geoValue , bounds );
54+ return setValue (values , geoValue , Geohash .stringEncode (bounds .minX (), bounds .minY (), precision ), 0 );
55+ }
56+ final long dX = (long ) Math .ceil ((bounds .maxX () - bounds .minX ()) / Geohash .lonWidthInDegrees (precision ));
57+ final long dY = (long ) Math .ceil ((bounds .maxY () - bounds .minY ()) / Geohash .latHeightInDegrees (precision ));
58+ if (dX * dY <= 32L * precision ) {
59+ return setValuesByBruteForceScan (values , geoValue , bounds );
60+ } else {
61+ return setValuesByRasterization ("" , values , 0 , geoValue );
5662 }
57- // TODO: optimize for when a shape fits in a single tile an
58- // for when brute-force is expected to be faster than rasterization, which
59- // is when the number of tiles expected is less than the precision
60- return setValuesByRasterization ("" , values , 0 , geoValue );
6163 }
6264
65+ /**
66+ * Checks all hashes between minX/maxX and minY/maxY
67+ */
68+ // pkg protected for testing
6369 int setValuesByBruteForceScan (GeoShapeCellValues values , GeoShapeValues .GeoShapeValue geoValue , GeoShapeValues .BoundingBox bounds )
6470 throws IOException {
65- // TODO: This way to discover cells inside of a bounding box seems not to work as expected. I can
66- // see that eventually we will be visiting twice the same cell which should not happen.
71+ final String stop = Geohash .stringEncode (bounds .maxX (), bounds .maxY (), precision );
72+ String firstInRow = null ;
73+ String lastInRow = null ;
6774 int idx = 0 ;
68- String min = Geohash .stringEncode (bounds .minX (), bounds .minY (), precision );
69- String max = Geohash .stringEncode (bounds .maxX (), bounds .maxY (), precision );
70- String minNeighborBelow = Geohash .getNeighbor (min , precision , 0 , -1 );
71- double minY = Geohash .decodeLatitude ((minNeighborBelow == null ) ? min : minNeighborBelow );
72- double minX = Geohash .decodeLongitude (min );
73- double maxY = Geohash .decodeLatitude (max );
74- double maxX = Geohash .decodeLongitude (max );
75- for (double i = minX ; i <= maxX ; i += Geohash .lonWidthInDegrees (precision )) {
76- for (double j = minY ; j <= maxY ; j += Geohash .latHeightInDegrees (precision )) {
77- String hash = Geohash .stringEncode (i , j , precision );
78- GeoRelation relation = relateTile (geoValue , hash );
79- if (relation != GeoRelation .QUERY_DISJOINT ) {
80- values .resizeCell (idx + 1 );
81- values .add (idx ++, encode (i , j ));
75+ do {
76+ lastInRow = moveDown (lastInRow , precision , bounds .maxX (), bounds .minY ());
77+ String current = null ;
78+ do {
79+ if (current == null ) {
80+ firstInRow = moveDown (firstInRow , precision , bounds .minX (), bounds .minY ());
81+ current = firstInRow ;
82+ } else {
83+ current = Geohash .getNeighbor (current , precision , 1 , 0 );
8284 }
83- }
84- }
85+ idx = setValue (values , geoValue , current , idx );
86+ } while (current .equals (lastInRow ) == false );
87+ } while (lastInRow .equals (stop ) == false );
8588 return idx ;
8689 }
8790
91+ private static String moveDown (String hash , int precision , double x , double y ) {
92+ return hash == null ? Geohash .stringEncode (x , y , precision ) : Geohash .getNeighbor (hash , precision , 0 , 1 );
93+ }
94+
8895 /**
8996 * Sets a singular doc-value for the {@link GeoShapeValues.GeoShapeValue}.
9097 */
91- private int setValue (GeoShapeCellValues docValues , GeoShapeValues .GeoShapeValue geoValue , GeoShapeValues .BoundingBox bounds )
92- throws IOException {
93- String hash = Geohash .stringEncode (bounds .minX (), bounds .minY (), precision );
98+ private int setValue (GeoShapeCellValues docValues , GeoShapeValues .GeoShapeValue geoValue , String hash , int idx ) throws IOException {
9499 if (relateTile (geoValue , hash ) != GeoRelation .QUERY_DISJOINT ) {
95- docValues .resizeCell (1 );
96- docValues .add (0 , Geohash .longEncode (hash ));
97- return 1 ;
100+ docValues .resizeCell (idx + 1 );
101+ docValues .add (idx ++, Geohash .longEncode (hash ));
98102 }
99- return 0 ;
103+ return idx ;
100104 }
101105
102106 private GeoRelation relateTile (GeoShapeValues .GeoShapeValue geoValue , String hash ) throws IOException {
103107 if (validHash (hash )) {
104108 final Rectangle rectangle = Geohash .toBoundingBox (hash );
105- int minX = GeoEncodingUtils .encodeLongitude (rectangle .getMinLon ());
106- int minY = GeoEncodingUtils .encodeLatitude (rectangle .getMinLat ());
107- int maxX = GeoEncodingUtils .encodeLongitude (rectangle .getMaxLon ());
108- int maxY = GeoEncodingUtils .encodeLatitude (rectangle .getMaxLat ());
109+ final int minX = GeoEncodingUtils .encodeLongitude (rectangle .getMinLon ());
110+ final int minY = GeoEncodingUtils .encodeLatitude (rectangle .getMinLat ());
111+ final int maxX = GeoEncodingUtils .encodeLongitude (rectangle .getMaxLon ());
112+ final int maxY = GeoEncodingUtils .encodeLatitude (rectangle .getMaxLat ());
109113 return geoValue .relate (minX , maxX == Integer .MAX_VALUE ? maxX : maxX - 1 , minY , maxY == Integer .MAX_VALUE ? maxY : maxY - 1 );
110114 }
111115 return GeoRelation .QUERY_DISJOINT ;
0 commit comments