From c7b48fdcaf4bbec84cea0a1a2f24d96e35ca09ed Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Thu, 21 Jan 2016 16:09:44 +0100 Subject: [PATCH 01/42] Change to APL 2 license --- LICENSE | 172 ++++-------------------------------------------------- README.md | 3 +- 2 files changed, 12 insertions(+), 163 deletions(-) diff --git a/LICENSE b/LICENSE index 65c5ca88..3439d71b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,165 +1,13 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 +Copyright 2016 Silvio Heuberger and contributors - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index 5cd41071..69643294 100644 --- a/README.md +++ b/README.md @@ -139,5 +139,6 @@ Version 1.0.1 License ------- -This code has been placed under the LGPL. See the LICENSE file for more information. +This code has been placed under the Apache 2 License. +See the LICENSE file for more information. Please contribute improvements and bug fixes back via github. From 322de775e5168d40a67a3997d34136ded8379ee6 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Thu, 21 Jan 2016 16:12:29 +0100 Subject: [PATCH 02/42] [maven-release-plugin] prepare release 1.2.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e74a79f7..e64b36d6 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ jar ch.hsr geohash - 1.1.1-SNAPSHOT + 1.2.0 geohash-java An implementation of Geohashes in pure Java. @@ -20,7 +20,7 @@ scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git - HEAD + 1.2.0 org.sonatype.oss From 86faf6a0fef2c494a737768cd12fea55e6c4eadc Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Thu, 21 Jan 2016 16:12:29 +0100 Subject: [PATCH 03/42] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e64b36d6..fc2f62a3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ jar ch.hsr geohash - 1.2.0 + 1.2.1-SNAPSHOT geohash-java An implementation of Geohashes in pure Java. @@ -20,7 +20,7 @@ scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git - 1.2.0 + HEAD org.sonatype.oss From 758a161b96bddea4e875b0377b0a976917646f2d Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Fri, 22 Jan 2016 13:00:33 +0100 Subject: [PATCH 04/42] Also change the license in the pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fc2f62a3..bdac7e13 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ https://github.com/kungfoo/geohash-java - LGPL 3.0 + Apache License, Version 2.0 https://raw.github.com/kungfoo/geohash-java/master/LICENSE repo From c9957767bbf95c7d4e7f7e6c0c8bfd732a8bea3c Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Fri, 22 Jan 2016 13:06:01 +0100 Subject: [PATCH 05/42] Change license notice in source files --- README.md | 2 +- benchmark/ch/hsr/geohash/GeoHashDecodingBenchmark.java | 4 ++-- benchmark/ch/hsr/geohash/GeoHashEncodingBenchmark.java | 4 ++-- src/main/java/ch/hsr/geohash/BoundingBox.java | 4 ++-- src/main/java/ch/hsr/geohash/GeoHash.java | 4 ++-- src/main/java/ch/hsr/geohash/WGS84Point.java | 4 ++-- .../java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java | 4 ++-- src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java | 4 ++-- src/main/java/ch/hsr/geohash/util/GeoHashSizeTable.java | 4 ++-- src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java | 4 ++-- src/test/java/ch/hsr/geohash/BoundingBoxTest.java | 4 ++-- .../java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java | 4 ++-- src/test/java/ch/hsr/geohash/GeoHashTest.java | 4 ++-- src/test/java/ch/hsr/geohash/WGS84PointTest.java | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 69643294..33cbbca7 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,6 @@ Version 1.0.1 License ------- -This code has been placed under the Apache 2 License. +This code has been placed under the Apache License 2.0. See the LICENSE file for more information. Please contribute improvements and bug fixes back via github. diff --git a/benchmark/ch/hsr/geohash/GeoHashDecodingBenchmark.java b/benchmark/ch/hsr/geohash/GeoHashDecodingBenchmark.java index 2ba41c0b..c4749118 100644 --- a/benchmark/ch/hsr/geohash/GeoHashDecodingBenchmark.java +++ b/benchmark/ch/hsr/geohash/GeoHashDecodingBenchmark.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/benchmark/ch/hsr/geohash/GeoHashEncodingBenchmark.java b/benchmark/ch/hsr/geohash/GeoHashEncodingBenchmark.java index 2b93bb18..1f628235 100644 --- a/benchmark/ch/hsr/geohash/GeoHashEncodingBenchmark.java +++ b/benchmark/ch/hsr/geohash/GeoHashEncodingBenchmark.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/src/main/java/ch/hsr/geohash/BoundingBox.java b/src/main/java/ch/hsr/geohash/BoundingBox.java index e901f0c5..636dc2ff 100644 --- a/src/main/java/ch/hsr/geohash/BoundingBox.java +++ b/src/main/java/ch/hsr/geohash/BoundingBox.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index e9a83be6..e692a1c1 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/src/main/java/ch/hsr/geohash/WGS84Point.java b/src/main/java/ch/hsr/geohash/WGS84Point.java index 595a7b0e..9802f015 100644 --- a/src/main/java/ch/hsr/geohash/WGS84Point.java +++ b/src/main/java/ch/hsr/geohash/WGS84Point.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java index 7f067d0a..4ae206fe 100644 --- a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java +++ b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash.queries; diff --git a/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java b/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java index 32ed6fba..32db87ac 100644 --- a/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java +++ b/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash.queries; diff --git a/src/main/java/ch/hsr/geohash/util/GeoHashSizeTable.java b/src/main/java/ch/hsr/geohash/util/GeoHashSizeTable.java index 62084d55..66f85c34 100644 --- a/src/main/java/ch/hsr/geohash/util/GeoHashSizeTable.java +++ b/src/main/java/ch/hsr/geohash/util/GeoHashSizeTable.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash.util; diff --git a/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java b/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java index 027e626a..f54f9d3b 100644 --- a/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java +++ b/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash.util; diff --git a/src/test/java/ch/hsr/geohash/BoundingBoxTest.java b/src/test/java/ch/hsr/geohash/BoundingBoxTest.java index b431aa41..47163989 100644 --- a/src/test/java/ch/hsr/geohash/BoundingBoxTest.java +++ b/src/test/java/ch/hsr/geohash/BoundingBoxTest.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java b/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java index c55dafa8..fd6ff2d4 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/src/test/java/ch/hsr/geohash/GeoHashTest.java b/src/test/java/ch/hsr/geohash/GeoHashTest.java index 0ad3bcec..d4070b3d 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashTest.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; diff --git a/src/test/java/ch/hsr/geohash/WGS84PointTest.java b/src/test/java/ch/hsr/geohash/WGS84PointTest.java index c12cc9c6..b8f2b1c5 100644 --- a/src/test/java/ch/hsr/geohash/WGS84PointTest.java +++ b/src/test/java/ch/hsr/geohash/WGS84PointTest.java @@ -1,10 +1,10 @@ /* * Copyright 2010, Silvio Heuberger @ IFS www.ifs.hsr.ch * - * This code is release under the LGPL license. + * This code is release under the Apache License 2.0. * You should have received a copy of the license * in the LICENSE file. If you have not, see - * http://www.gnu.org/licenses/lgpl-3.0.txt + * http://www.apache.org/licenses/LICENSE-2.0 */ package ch.hsr.geohash; From 410dd9e64a7ce9b42ab9fb1d35fb4f61178b1ff6 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Fri, 22 Jan 2016 13:09:59 +0100 Subject: [PATCH 06/42] [maven-release-plugin] prepare release 1.3.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bdac7e13..f19c0869 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ jar ch.hsr geohash - 1.2.1-SNAPSHOT + 1.3.0 geohash-java An implementation of Geohashes in pure Java. @@ -20,7 +20,7 @@ scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git - HEAD + 1.3.0 org.sonatype.oss From 83adfa640b8c03a07b74853aff1bf8d99283561a Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Fri, 22 Jan 2016 13:09:59 +0100 Subject: [PATCH 07/42] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f19c0869..fe85a686 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ jar ch.hsr geohash - 1.3.0 + 1.3.1-SNAPSHOT geohash-java An implementation of Geohashes in pure Java. @@ -20,7 +20,7 @@ scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git - 1.3.0 + HEAD org.sonatype.oss From 0541956c7bd3605f33525bb140e7984132bbd899 Mon Sep 17 00:00:00 2001 From: Robert Pyke Date: Wed, 5 Oct 2016 22:48:07 -0700 Subject: [PATCH 08/42] Update GeoHashBoundingBoxQuery.java minor: Fixes a typo --- .../java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java index 4ae206fe..f2d2ffcf 100644 --- a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java +++ b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java @@ -19,7 +19,7 @@ /** * This class returns the hashes covering a certain bounding box. There are - * either 1,2 or 4 susch hashes, depending on the position of the bounding box + * either 1,2 or 4 such hashes, depending on the position of the bounding box * on the geohash grid. */ public class GeoHashBoundingBoxQuery implements GeoHashQuery, Serializable { From b0b5f5a80a65ba36f9d286ae004a9fef13656549 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Fri, 14 Jul 2017 18:34:28 +0200 Subject: [PATCH 09/42] Fix issue #28 in VincentyGeodesy --- src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java b/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java index f54f9d3b..0b0fa292 100644 --- a/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java +++ b/src/main/java/ch/hsr/geohash/util/VincentyGeodesy.java @@ -77,7 +77,7 @@ public static WGS84Point moveInDirection(WGS84Point point, double bearingInDegre double newLat = lat2 / degToRad; double newLon = point.getLongitude() + L / degToRad; - newLon = (newLon > 180.0 ? 360.0 - newLon : newLon); + newLon = (newLon > 180.0 ? newLon - 360 : newLon); newLon = (newLon < -180.0 ? 360.0 + newLon : newLon); return new WGS84Point(newLat, newLon); From 2735392c4672484f58ac5eec3160a5ab09c54d8b Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Mon, 5 Mar 2018 13:26:16 +0100 Subject: [PATCH 10/42] Fix the fact that there is no more oraclejdk7 for travis nodes --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b2168ad3..7957a820 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: java jdk: - oraclejdk8 - - oraclejdk7 - openjdk7 From 3b2098e183427a0650f2622efb2e3f3f75a43f56 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Mon, 5 Mar 2018 14:21:29 +0100 Subject: [PATCH 11/42] Update README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 33cbbca7..7a70030b 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,11 @@ Current development involves getting the following things to run: Last important changes ---------------------- +Version 1.3.0 +----------------------- + +This version switches the license over to Apache Software License 2.0 + Version 1.1.0 ----------------------- From 81982b1cf28cd7d7d653a33d7aed815e8c6610bb Mon Sep 17 00:00:00 2001 From: martin-mfg <2026226+martin-mfg@users.noreply.github.com> Date: Tue, 29 Jan 2019 19:01:18 +0100 Subject: [PATCH 12/42] fix typo in README This simply changes "mayn" -> "many" in the README.md. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a70030b..d056281c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Getting the library ------------------- As of today, new releases are made available via maven Central. -Thus you can use the artifacts in various build systems like maven, ivy, gradle, sbt and mayn more. +Thus you can use the artifacts in various build systems like maven, ivy, gradle, sbt and many more. Find the current versions here: From 376f5edb443465ff6cc2bac0bbd69d62967b0c27 Mon Sep 17 00:00:00 2001 From: Nikolay Mikheev Date: Tue, 7 May 2019 09:15:22 -0400 Subject: [PATCH 13/42] Fix infinite loop in BoundingBoxGeoHashIterator --- .../util/BoundingBoxGeoHashIterator.java | 22 +++-- .../util/BoundingBoxGeoHashIteratorTest.java | 89 +++++++++++++++---- 2 files changed, 84 insertions(+), 27 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java index e1e30b2d..1f9a660a 100644 --- a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java +++ b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java @@ -1,10 +1,10 @@ package ch.hsr.geohash.util; +import ch.hsr.geohash.GeoHash; + import java.util.Iterator; import java.util.NoSuchElementException; -import ch.hsr.geohash.GeoHash; - /** * Iterate over all of the values within a bounding box at a particular * resolution @@ -24,19 +24,25 @@ public TwoGeoHashBoundingBox getBoundingBox() { @Override public boolean hasNext() { - return current.compareTo(boundingBox.getTopRight()) <= 0; + return current != null; } @Override public GeoHash next() { - GeoHash rv = current; if (!hasNext()) { throw new NoSuchElementException(); } - current = rv.next(); - while (hasNext() && !boundingBox.getBoundingBox().contains(current.getPoint())) { - current = current.next(); - } + + GeoHash rv = current; + if (rv.equals(boundingBox.getTopRight())) { + current = null; + } else { + current = rv.next(); + while (hasNext() && !boundingBox.getBoundingBox().contains(current.getPoint())) { + current = current.next(); + } + } + return rv; } diff --git a/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java b/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java index ef666415..5237a5e9 100644 --- a/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java +++ b/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java @@ -1,13 +1,19 @@ package ch.hsr.geohash.util; -import java.util.ArrayList; -import java.util.List; - +import ch.hsr.geohash.BoundingBox; +import ch.hsr.geohash.GeoHash; import org.junit.Assert; import org.junit.Test; -import ch.hsr.geohash.BoundingBox; -import ch.hsr.geohash.GeoHash; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsCollectionContaining.hasItem; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertThat; /** * Created by IntelliJ IDEA. User: kevin Date: Jan 6, 2011 Time: 3:05:43 PM @@ -18,20 +24,7 @@ public void testIter() { BoundingBox box = new BoundingBox(37.7, 37.84, -122.52, -122.35); BoundingBoxGeoHashIterator iter = new BoundingBoxGeoHashIterator( TwoGeoHashBoundingBox.withBitPrecision(box, 10)); - BoundingBox newBox = iter.getBoundingBox().getBoundingBox(); - List hashes = new ArrayList<>(); - while (iter.hasNext()) { - hashes.add(iter.next()); - } - GeoHash prev = null; - for (GeoHash gh : hashes) { - if (prev != null) { - Assert.assertTrue(prev.compareTo(gh) < 0); - } - Assert.assertTrue(newBox.contains(gh.getPoint())); - prev = gh; - } - + checkIterator(iter); } @Test @@ -39,11 +32,68 @@ public void testIter2() { BoundingBox box = new BoundingBox(37.7, 37.84, -122.52, -122.35); BoundingBoxGeoHashIterator iter = new BoundingBoxGeoHashIterator( TwoGeoHashBoundingBox.withBitPrecision(box, 35)); + checkIterator(iter); + } + + @Test + public void testIter3() { + BoundingBox box = new BoundingBox(28.5, 67.15, -33.2, 44.5); + BoundingBoxGeoHashIterator iter = new BoundingBoxGeoHashIterator( + TwoGeoHashBoundingBox.withCharacterPrecision(box, 2)); + List hashes = checkIterator(iter); + assertThat(hashes.size(), is(49)); + } + + @Test + public void testEndlessIterator() { + BoundingBox box = new BoundingBox(72.28907f, 88.62655f, -50.976562f, 170.50781f); + TwoGeoHashBoundingBox twoGeoHashBoundingBox = TwoGeoHashBoundingBox.withCharacterPrecision(box, 2); + BoundingBoxGeoHashIterator iterator = new BoundingBoxGeoHashIterator(twoGeoHashBoundingBox); + + Set hashes = new HashSet<>(); + while (iterator.hasNext()) { + GeoHash hash = iterator.next(); + assertThat("Hash has been already produced by the iterator once: " + hash, hashes, not(hasItem(hash))); + hashes.add(hash); + } + } + + @Test + public void testAllCells() { + BoundingBox box = new BoundingBox(-90, 90, -180, 180); + TwoGeoHashBoundingBox twoGeoHashBoundingBox = TwoGeoHashBoundingBox.withCharacterPrecision(box, 2); + BoundingBoxGeoHashIterator iterator = new BoundingBoxGeoHashIterator(twoGeoHashBoundingBox); + + Set hashes = new HashSet<>(); + while (iterator.hasNext()) { + GeoHash hash = iterator.next(); + hashes.add(hash); + } + + assertThat(hashes.size(), is(1024)); + } + + @Test + public void testTopRightCorner() { + BoundingBox box = new BoundingBox(84.4, 84.9, 169.3, 179.6); // all in ZZ cell + TwoGeoHashBoundingBox twoGeoHashBoundingBox = TwoGeoHashBoundingBox.withCharacterPrecision(box, 2); + BoundingBoxGeoHashIterator iterator = new BoundingBoxGeoHashIterator(twoGeoHashBoundingBox); + + Set hashes = new HashSet<>(); + while (iterator.hasNext()) { + GeoHash hash = iterator.next(); + assertThat("Hash has been already produced by the iterator once: " + hash, hashes, not(hasItem(hash))); + hashes.add(hash); + } + } + + private List checkIterator(BoundingBoxGeoHashIterator iter) { BoundingBox newBox = iter.getBoundingBox().getBoundingBox(); List hashes = new ArrayList<>(); while (iter.hasNext()) { hashes.add(iter.next()); } + GeoHash prev = null; for (GeoHash gh : hashes) { if (prev != null) { @@ -53,5 +103,6 @@ public void testIter2() { prev = gh; } + return hashes; } } From 833706976c63927b2a12f1a91d842d3ee07ed615 Mon Sep 17 00:00:00 2001 From: b14ck1 Date: Wed, 13 Nov 2019 13:40:11 +0100 Subject: [PATCH 14/42] Implemented 180-Meridian-crossing BoundingBox, added tests --- src/main/java/ch/hsr/geohash/BoundingBox.java | 239 ++++++++++++++---- src/main/java/ch/hsr/geohash/GeoHash.java | 4 +- .../queries/GeoHashBoundingBoxQuery.java | 93 +++++-- .../util/BoundingBoxGeoHashIterator.java | 6 +- .../hsr/geohash/util/BoundingBoxSampler.java | 6 +- .../geohash/util/TwoGeoHashBoundingBox.java | 42 ++- .../java/ch/hsr/geohash/BoundingBoxTest.java | 49 +++- .../geohash/GeoHashBoundingBoxSearchTest.java | 39 ++- .../hsr/geohash/GeoHashCircleQueryTest.java | 23 ++ 9 files changed, 388 insertions(+), 113 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/BoundingBox.java b/src/main/java/ch/hsr/geohash/BoundingBox.java index 636dc2ff..04b8d2d0 100644 --- a/src/main/java/ch/hsr/geohash/BoundingBox.java +++ b/src/main/java/ch/hsr/geohash/BoundingBox.java @@ -12,43 +12,115 @@ public class BoundingBox implements Serializable { private static final long serialVersionUID = -7145192134410261076L; - private double minLat; - private double maxLat; - private double minLon; - private double maxLon; + private double southLatitude; + private double northLatitude; + private double westLongitude; + private double eastLongitude; + private boolean intersects180Meridian; /** * create a bounding box defined by two coordinates */ - public BoundingBox(WGS84Point p1, WGS84Point p2) { - this(p1.getLatitude(), p2.getLatitude(), p1.getLongitude(), p2.getLongitude()); + public BoundingBox(WGS84Point southWest, WGS84Point northEast) { + this(southWest.getLatitude(), northEast.getLatitude(), southWest.getLongitude(), northEast.getLongitude()); } - public BoundingBox(double y1, double y2, double x1, double x2) { - minLon = Math.min(x1, x2); - maxLon = Math.max(x1, x2); - minLat = Math.min(y1, y2); - maxLat = Math.max(y1, y2); + /** + * Create a bounding box with the specified latitudes and longitudes. This constructor takes the order of the points into account. + * + * @param northLatitude + * @param southLatitude + * @param westLongitude + * @param eastLongitude + * + * @throws IllegalArgumentException + * When the defined BoundingBox would go over one of the poles. This kind of box is not supported. + */ + public BoundingBox(double southLatitude, double northLatitude, double westLongitude, double eastLongitude) { + if (southLatitude > northLatitude) + throw new IllegalArgumentException("The southLatitude must not be greater than the northLatitude"); + + if (Math.abs(southLatitude) > 90 || Math.abs(northLatitude) > 90 || Math.abs(westLongitude) > 180 || Math.abs(eastLongitude) > 180) { + throw new IllegalArgumentException("The supplied coordinates are out of range."); + } + + this.northLatitude = northLatitude; + this.westLongitude = westLongitude; + + this.southLatitude = southLatitude; + this.eastLongitude = eastLongitude; + + intersects180Meridian = eastLongitude < westLongitude; } + /** + * Clone constructor + * + * @param that + */ public BoundingBox(BoundingBox that) { - this(that.minLat, that.maxLat, that.minLon, that.maxLon); + this(that.southLatitude, that.northLatitude, that.westLongitude, that.eastLongitude); } - public WGS84Point getUpperLeft() { - return new WGS84Point(maxLat, minLon); + /** + * Returns the NorthWestPoint of this BoundingBox as a new Point. + * + * @return + */ + public WGS84Point getNorthWestPoint() { + return new WGS84Point(northLatitude, westLongitude); } - public WGS84Point getLowerRight() { - return new WGS84Point(minLat, maxLon); + /** + * Returns the NorthEastPoint of this BoundingBox as a new Point. + * + * @return + */ + public WGS84Point getNorthEastPoint() { + return new WGS84Point(northLatitude, eastLongitude); } + /** + * Returns the SouthEastPoint of this BoundingBox as a new Point. + * + * @return + */ + public WGS84Point getSouthEastPoint() { + return new WGS84Point(southLatitude, eastLongitude); + } + + /** + * Returns the SouthWestPoint of this BoundingBox as a new Point. + * + * @return + */ + public WGS84Point getSouthWestPoint() { + return new WGS84Point(southLatitude, westLongitude); + } + + /** + * Returns the size of the bounding box in degrees of latitude. The value returned will always be positive. + * + * @return + */ public double getLatitudeSize() { - return maxLat - minLat; + return northLatitude - southLatitude; } + /** + * Returns the size of the bounding box in degrees of longitude. The value returned will always be positive. + * + * @return + */ public double getLongitudeSize() { - return maxLon - minLon; + if (eastLongitude == 180.0 && westLongitude == -180.0) + return 360.0; + double size = (eastLongitude - westLongitude) % 360; + + // Remainder fix for earlier java versions + if (size < 0) + size += 360.0; + return size; } @Override @@ -58,7 +130,7 @@ public boolean equals(Object obj) { } if (obj instanceof BoundingBox) { BoundingBox that = (BoundingBox) obj; - return minLat == that.minLat && minLon == that.minLon && maxLat == that.maxLat && maxLon == that.maxLon; + return southLatitude == that.southLatitude && westLongitude == that.westLongitude && northLatitude == that.northLatitude && eastLongitude == that.eastLongitude; } else { return false; } @@ -67,10 +139,10 @@ public boolean equals(Object obj) { @Override public int hashCode() { int result = 17; - result = 37 * result + hashCode(minLat); - result = 37 * result + hashCode(maxLat); - result = 37 * result + hashCode(minLon); - result = 37 * result + hashCode(maxLon); + result = 37 * result + hashCode(southLatitude); + result = 37 * result + hashCode(northLatitude); + result = 37 * result + hashCode(westLongitude); + result = 37 * result + hashCode(eastLongitude); return result; } @@ -80,53 +152,130 @@ private static int hashCode(double x) { } public boolean contains(WGS84Point point) { - return (point.getLatitude() >= minLat) && (point.getLongitude() >= minLon) && (point.getLatitude() <= maxLat) - && (point.getLongitude() <= maxLon); + return containsLatitude(point.getLatitude()) && containsLongitude(point.getLongitude()); } public boolean intersects(BoundingBox other) { - return !(other.minLon > maxLon || other.maxLon < minLon || other.minLat > maxLat || other.maxLat < minLat); + // Check latitude first cause it's the same for all cases + if (other.southLatitude > northLatitude || other.northLatitude < southLatitude) { + return false; + } else { + if (!intersects180Meridian && !other.intersects180Meridian) { + return !(other.eastLongitude < westLongitude || other.westLongitude > eastLongitude); + } else if (intersects180Meridian && !other.intersects180Meridian) { + return !(eastLongitude < other.westLongitude && westLongitude > other.eastLongitude); + } else if (!intersects180Meridian && other.intersects180Meridian) { + return !(westLongitude > other.eastLongitude && eastLongitude < other.westLongitude); + } else + return true; + } } @Override public String toString() { - return getUpperLeft() + " -> " + getLowerRight(); + return getNorthWestPoint() + " -> " + getSouthEastPoint(); } public WGS84Point getCenterPoint() { - double centerLatitude = (minLat + maxLat) / 2; - double centerLongitude = (minLon + maxLon) / 2; + double centerLatitude = (southLatitude + northLatitude) / 2; + double centerLongitude = (westLongitude + eastLongitude) / 2; + + // This can happen if the bBox crosses the 180-Meridian + if (centerLongitude > 180) + centerLongitude -= 360; + return new WGS84Point(centerLatitude, centerLongitude); } + /** + * Expands this bounding box to include the provided bounding box. The expansion is done in the direction with the minimal distance. If both distances are the same it'll expand + * in east direction. It will not cross poles, but it will cross the 180-Meridian, if thats the shortest distance.
+ * If a precise specification of the northEast and southWest points is needed, please create a new bounding box where you can specify the points separately. + * + * @param other + */ public void expandToInclude(BoundingBox other) { - if (other.minLon < minLon) { - minLon = other.minLon; + + // Expand Latitude + if (other.southLatitude < southLatitude) { + southLatitude = other.southLatitude; } - if (other.maxLon > maxLon) { - maxLon = other.maxLon; + if (other.northLatitude > northLatitude) { + northLatitude = other.northLatitude; } - if (other.minLat < minLat) { - minLat = other.minLat; + + // Expand Longitude + // At first check whether the two boxes contain each other or not + boolean thisContainsOther = containsLongitude(other.eastLongitude) && containsLongitude(other.westLongitude); + boolean otherContainsThis = other.containsLongitude(eastLongitude) && other.containsLongitude(westLongitude); + + // The new box needs to span the whole globe + if (thisContainsOther && otherContainsThis) { + eastLongitude = 180.0; + westLongitude = -180.0; + intersects180Meridian = false; + return; } - if (other.maxLat > maxLat) { - maxLat = other.maxLat; + // Already done in this case + if (thisContainsOther) + return; + // Expand to match the bigger box + if (otherContainsThis) { + eastLongitude = other.eastLongitude; + westLongitude = other.westLongitude; + intersects180Meridian = eastLongitude < westLongitude; + return; } + + // If this is not the case compute the distance between the endpoints in east direction + double distanceEastToOtherEast = (other.eastLongitude - eastLongitude) % 360; + double distanceOtherWestToWest = (westLongitude - other.westLongitude) % 360; + + // Fix for lower java versions, since the remainder-operator (%) changed in one version, idk which one + if (distanceEastToOtherEast < 0) + distanceEastToOtherEast += 360; + if (distanceOtherWestToWest < 0) + distanceOtherWestToWest += 360; + + // The minimal distance needs to be extended + if (distanceEastToOtherEast <= distanceOtherWestToWest) { + eastLongitude = other.eastLongitude; + } else { + westLongitude = other.westLongitude; + } + + intersects180Meridian = eastLongitude < westLongitude; + } + + private boolean containsLatitude(double latitude) { + return latitude >= southLatitude && latitude <= northLatitude; + } + + private boolean containsLongitude(double longitude) { + if (intersects180Meridian) { + return longitude <= eastLongitude || longitude >= westLongitude; + } else { + return longitude >= westLongitude && longitude <= eastLongitude; + } + } + + public double getEastLongitude() { + return eastLongitude; } - public double getMinLon() { - return minLon; + public double getWestLongitude() { + return westLongitude; } - public double getMinLat() { - return minLat; + public double getNorthLatitude() { + return northLatitude; } - public double getMaxLat() { - return maxLat; + public double getSouthLatitude() { + return southLatitude; } - public double getMaxLon() { - return maxLon; + public boolean intersects180Meridian() { + return intersects180Meridian; } } diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index e692a1c1..27eda240 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -182,9 +182,7 @@ private GeoHash(double latitude, double longitude, int desiredPrecision) { } private static void setBoundingBox(GeoHash hash, double[] latitudeRange, double[] longitudeRange) { - hash.boundingBox = new BoundingBox(new WGS84Point(latitudeRange[0], longitudeRange[0]), new WGS84Point( - latitudeRange[1], - longitudeRange[1])); + hash.boundingBox = new BoundingBox(latitudeRange[0], latitudeRange[1], longitudeRange[0], longitudeRange[1]); } public GeoHash next(int step) { diff --git a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java index f2d2ffcf..5e7ae2a9 100644 --- a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java +++ b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java @@ -24,45 +24,101 @@ */ public class GeoHashBoundingBoxQuery implements GeoHashQuery, Serializable { private static final long serialVersionUID = 9223256928940522683L; - /* there's not going to be more than 4 hashes. */ - private List searchHashes = new ArrayList<>(4); + /* there can be up to 8 hashes since it can be 2 separate queries */ + private List searchHashes = new ArrayList<>(8); /* the combined bounding box of those hashes. */ private BoundingBox boundingBox; public GeoHashBoundingBoxQuery(BoundingBox bbox) { + if (!bbox.intersects180Meridian()) { + // In this case one query is enough + generateSearchHashes(bbox); + } else { + // In this case we need two queries + BoundingBox eastBox = new BoundingBox(bbox.getSouthLatitude(), bbox.getNorthLatitude(), bbox.getWestLongitude(), 180); + BoundingBox westBox = new BoundingBox(bbox.getSouthLatitude(), bbox.getNorthLatitude(), -180, bbox.getEastLongitude()); + + generateSearchHashes(eastBox); + generateSearchHashes(westBox); + } + + // Finally create the combined bounding box + for (GeoHash hash : searchHashes) { + if (boundingBox == null) + boundingBox = new BoundingBox(hash.getBoundingBox()); + else + boundingBox.expandToInclude(hash.getBoundingBox()); + } + + // Check the search hashes on a query over the full planet + for (GeoHash hash : searchHashes) { + if (hash.significantBits() == 0) { + searchHashes.clear(); + searchHashes.add(hash); + return; + } + } + + // Check the search hashes on possible duplicates + List toRemove = new ArrayList(searchHashes.size() - 1); + for (GeoHash hash : searchHashes) { + for (GeoHash hashToCompare : searchHashes) { + if (hashToCompare.significantBits() < hash.significantBits()) { + long hashCopy = hash.longValue(); + long hashCompareCopy = hashToCompare.longValue(); + int equalBits = 0; + while ((hashCompareCopy & GeoHash.FIRST_BIT_FLAGGED) == (hashCopy & GeoHash.FIRST_BIT_FLAGGED)) { + hashCompareCopy <<= 1; + hashCopy <<= 1; + equalBits++; + } + + if (equalBits == hashToCompare.significantBits()) { + toRemove.add(hash); + break; + } + } + } + } + for (GeoHash hash : toRemove) { + searchHashes.remove(hash); + } + } + + private void generateSearchHashes(BoundingBox bbox) { int fittingBits = GeoHashSizeTable.numberOfBitsForOverlappingGeoHash(bbox); WGS84Point center = bbox.getCenterPoint(); GeoHash centerHash = GeoHash.withBitPrecision(center.getLatitude(), center.getLongitude(), fittingBits); - if (hashFits(centerHash, bbox)) { - addSearchHash(centerHash); + if (hashContainsBoundingBox(centerHash, bbox)) { + // If the centerHash completly fits into the provided bounding box, just add the hash and continue + searchHashes.add(centerHash); } else { + // Else the search has to be extended to the adjacent geohashes expandSearch(centerHash, bbox); } } - private void addSearchHash(GeoHash hash) { - if (boundingBox == null) { - boundingBox = new BoundingBox(hash.getBoundingBox()); - } else { - boundingBox.expandToInclude(hash.getBoundingBox()); - } - searchHashes.add(hash); - } - private void expandSearch(GeoHash centerHash, BoundingBox bbox) { - addSearchHash(centerHash); + searchHashes.add(centerHash); for (GeoHash adjacent : centerHash.getAdjacent()) { BoundingBox adjacentBox = adjacent.getBoundingBox(); if (adjacentBox.intersects(bbox) && !searchHashes.contains(adjacent)) { - addSearchHash(adjacent); + searchHashes.add(adjacent); } } } - private boolean hashFits(GeoHash hash, BoundingBox bbox) { - return hash.contains(bbox.getUpperLeft()) && hash.contains(bbox.getLowerRight()); + /** + * Checks if the provided hash completely(!) contains the provided bounding box + * + * @param hash + * @param bbox + * @return + */ + private boolean hashContainsBoundingBox(GeoHash hash, BoundingBox bbox) { + return hash.contains(bbox.getNorthWestPoint()) && hash.contains(bbox.getSouthEastPoint()); } @Override @@ -96,7 +152,6 @@ public String toString() { @Override public String getWktBox() { - return "BOX(" + boundingBox.getMinLon() + " " + boundingBox.getMinLat() + "," + boundingBox.getMaxLon() + " " - + boundingBox.getMaxLat() + ")"; + return "BOX(" + boundingBox.getWestLongitude() + " " + boundingBox.getSouthLatitude() + "," + boundingBox.getEastLongitude() + " " + boundingBox.getNorthLatitude() + ")"; } } diff --git a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java index e1e30b2d..79ff50d9 100644 --- a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java +++ b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java @@ -14,8 +14,8 @@ public class BoundingBoxGeoHashIterator implements Iterator { private GeoHash current; public BoundingBoxGeoHashIterator(TwoGeoHashBoundingBox bbox) { - this.boundingBox = bbox; - this.current = bbox.getBottomLeft(); + boundingBox = bbox; + current = bbox.getSouthEast(); } public TwoGeoHashBoundingBox getBoundingBox() { @@ -24,7 +24,7 @@ public TwoGeoHashBoundingBox getBoundingBox() { @Override public boolean hasNext() { - return current.compareTo(boundingBox.getTopRight()) <= 0; + return current.compareTo(boundingBox.getNorthWest()) <= 0; } @Override diff --git a/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java b/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java index 18aa5779..5572cdec 100644 --- a/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java +++ b/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java @@ -22,8 +22,8 @@ public class BoundingBoxSampler { * exceeds Integer.MAX_VALUE */ public BoundingBoxSampler(TwoGeoHashBoundingBox bbox) { - this.boundingBox = bbox; - long maxSamplesLong = GeoHash.stepsBetween(bbox.getBottomLeft(), bbox.getTopRight()); + boundingBox = bbox; + long maxSamplesLong = GeoHash.stepsBetween(bbox.getSouthEast(), bbox.getNorthWest()); if (maxSamplesLong > Integer.MAX_VALUE) { throw new IllegalArgumentException("This bounding box is too big too sample using this algorithm"); } @@ -51,7 +51,7 @@ public GeoHash next() { idx = rand.nextInt(maxSamples + 1); } alreadyUsed.add(idx); - GeoHash gh = boundingBox.getBottomLeft().next(idx); + GeoHash gh = boundingBox.getSouthEast().next(idx); if (!boundingBox.getBoundingBox().contains(gh.getPoint())) { return next(); } diff --git a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java index 571f416b..747a7544 100644 --- a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java +++ b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java @@ -8,51 +8,49 @@ */ public class TwoGeoHashBoundingBox { private BoundingBox boundingBox; - private GeoHash bottomLeft; - private GeoHash topRight; + private GeoHash southEast; + private GeoHash northWest; public static TwoGeoHashBoundingBox withCharacterPrecision(BoundingBox bbox, int numberOfCharacters) { - GeoHash bottomLeft = GeoHash.withCharacterPrecision(bbox.getMinLat(), bbox.getMinLon(), numberOfCharacters); - GeoHash topRight = GeoHash.withCharacterPrecision(bbox.getMaxLat(), bbox.getMaxLon(), numberOfCharacters); + GeoHash bottomLeft = GeoHash.withCharacterPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfCharacters); + GeoHash topRight = GeoHash.withCharacterPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfCharacters); return new TwoGeoHashBoundingBox(bottomLeft, topRight); } public static TwoGeoHashBoundingBox withBitPrecision(BoundingBox bbox, int numberOfBits) { - GeoHash bottomLeft = GeoHash.withBitPrecision(bbox.getMinLat(), bbox.getMinLon(), numberOfBits); - GeoHash topRight = GeoHash.withBitPrecision(bbox.getMaxLat(), bbox.getMaxLon(), numberOfBits); + GeoHash bottomLeft = GeoHash.withBitPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfBits); + GeoHash topRight = GeoHash.withBitPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfBits); return new TwoGeoHashBoundingBox(bottomLeft, topRight); } public static TwoGeoHashBoundingBox fromBase32(String base32) { - String bottomLeft = base32.substring(0, 7); - String topRight = base32.substring(7); - return new TwoGeoHashBoundingBox(GeoHash.fromGeohashString(bottomLeft), GeoHash.fromGeohashString(topRight)); + String southWestBase32 = base32.substring(0, 7); + String northEastBase32 = base32.substring(7); + return new TwoGeoHashBoundingBox(GeoHash.fromGeohashString(southWestBase32), GeoHash.fromGeohashString(northEastBase32)); } - public TwoGeoHashBoundingBox(GeoHash bottomLeft, GeoHash topRight) { - if (bottomLeft.significantBits() != topRight.significantBits()) { - throw new IllegalArgumentException( - "Does it make sense to iterate between hashes that have different precisions?"); + public TwoGeoHashBoundingBox(GeoHash southEast, GeoHash northWest) { + if (southEast.significantBits() != northWest.significantBits()) { + throw new IllegalArgumentException("Does it make sense to iterate between hashes that have different precisions?"); } - this.bottomLeft = GeoHash.fromLongValue(bottomLeft.longValue(), bottomLeft.significantBits()); - this.topRight = GeoHash.fromLongValue(topRight.longValue(), topRight.significantBits()); - this.boundingBox = this.bottomLeft.getBoundingBox(); - this.boundingBox.expandToInclude(this.topRight.getBoundingBox()); + this.southEast = GeoHash.fromLongValue(southEast.longValue(), southEast.significantBits()); + this.northWest = GeoHash.fromLongValue(northWest.longValue(), northWest.significantBits()); + boundingBox = new BoundingBox(southEast.getBoundingBox().getSouthLatitude(), northWest.getBoundingBox().getNorthLatitude(), northWest.getBoundingBox().getWestLongitude(), southEast.getBoundingBox().getEastLongitude()); } public BoundingBox getBoundingBox() { return boundingBox; } - public GeoHash getBottomLeft() { - return bottomLeft; + public GeoHash getSouthEast() { + return southEast; } - public GeoHash getTopRight() { - return topRight; + public GeoHash getNorthWest() { + return northWest; } public String toBase32() { - return bottomLeft.toBase32() + topRight.toBase32(); + return southEast.toBase32() + northWest.toBase32(); } } diff --git a/src/test/java/ch/hsr/geohash/BoundingBoxTest.java b/src/test/java/ch/hsr/geohash/BoundingBoxTest.java index 47163989..da873b55 100644 --- a/src/test/java/ch/hsr/geohash/BoundingBoxTest.java +++ b/src/test/java/ch/hsr/geohash/BoundingBoxTest.java @@ -21,12 +21,16 @@ public class BoundingBoxTest { private BoundingBox a; private BoundingBox b; private BoundingBox c; + private BoundingBox d; + private BoundingBox e; @Before public void setUp() { - a = new BoundingBox(new WGS84Point(30, 20), new WGS84Point(21, 31)); + a = new BoundingBox(new WGS84Point(21, 20), new WGS84Point(30, 31)); b = new BoundingBox(a); - c = new BoundingBox(new WGS84Point(45, -170), new WGS84Point(-45, 170)); + c = new BoundingBox(new WGS84Point(-45, -170), new WGS84Point(45, 170)); + d = new BoundingBox(new WGS84Point(-45, 170), new WGS84Point(-45, -170)); + e = new BoundingBox(d); } @Test @@ -40,13 +44,24 @@ public void testEqualsObject() { assertEquals(a, b); assertEquals(b, a); assertFalse(a.equals(c)); + assertEquals(d, e); + assertEquals(e, d); + assertFalse(c.equals(d)); + assertFalse(c.equals(a)); } @Test public void testContains() { - BoundingBox bbox = new BoundingBox(45, 46, 121, 120); + BoundingBox bbox = new BoundingBox(45, 46, 120, 121); assertContains(bbox, new WGS84Point(45.5, 120.5)); assertNotContains(bbox, new WGS84Point(90, 90)); + + // Testing bounding box over 180-Meridian + bbox = new BoundingBox(45, 46, 170, -170); + assertContains(bbox, new WGS84Point(45.5, 175)); + assertContains(bbox, new WGS84Point(45.5, -175)); + assertNotContains(bbox, new WGS84Point(45.5, -165)); + assertNotContains(bbox, new WGS84Point(45.5, 165)); } @Test @@ -57,9 +72,14 @@ public void testSize() { bbox = new BoundingBox(-45, 45, -22.5, 30); assertHeightIs(bbox, 90); assertWidthIs(bbox, 52.5); - bbox = new BoundingBox(-44, -46.1, -127.2, -128); + bbox = new BoundingBox(-46.1, -44, -128, -127.2); assertHeightIs(bbox, 2.1); assertWidthIs(bbox, 0.8); + + // Testing bounding box over 180-Meridian + bbox = new BoundingBox(45, 90, 170, -170); + assertHeightIs(bbox, 45); + assertWidthIs(bbox, 20); } private void assertWidthIs(BoundingBox bbox, double width) { @@ -72,9 +92,24 @@ private void assertHeightIs(BoundingBox bbox, double height) { @Test public void testIntersects() { - BoundingBox bbox = new BoundingBox(10, -10, 41, 40); - assertIntersects(bbox, new BoundingBox(5, -15, 40.5, 43)); - assertDoesNotIntersect(bbox, new BoundingBox(5, -15, 42, 43)); + BoundingBox bbox = new BoundingBox(-10, 10, 40, 41); + assertIntersects(bbox, new BoundingBox(-15, 5, 40.5, 43)); + assertDoesNotIntersect(bbox, new BoundingBox(-15, 5, 42, 43)); + + // Testing bounding box over 180-Meridian + bbox = new BoundingBox(45, 90, 170, -170); + assertIntersects(bbox, new BoundingBox(50, 55, 175, 176)); + assertIntersects(bbox, new BoundingBox(50, 55, 160, 176)); + assertIntersects(bbox, new BoundingBox(50, 55, -175, -176)); + assertIntersects(bbox, new BoundingBox(50, 55, -160, -176)); + assertIntersects(bbox, new BoundingBox(50, 55, 175, -175)); + assertIntersects(bbox, new BoundingBox(50, 55, -175, 175)); + + assertDoesNotIntersect(bbox, new BoundingBox(-15, 5, 42, 43)); + assertDoesNotIntersect(bbox, new BoundingBox(-15, 5, 175, 176)); + assertDoesNotIntersect(bbox, new BoundingBox(-15, 5, 175, -175)); + assertDoesNotIntersect(bbox, new BoundingBox(50, 55, 160, 169)); + assertDoesNotIntersect(bbox, new BoundingBox(50, 55, -169, -160)); } private void assertDoesNotIntersect(BoundingBox bbox, BoundingBox boundingBox) { diff --git a/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java b/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java index fd6ff2d4..2c40d9d8 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashBoundingBoxSearchTest.java @@ -21,29 +21,46 @@ public class GeoHashBoundingBoxSearchTest { @Test public void testSeveralBoundingBoxes() { checkSearchYieldsCorrectNumberOfHashes(40.2090980098, 40.21982983232432, -22.523432424324, -22.494234232442); - checkSearchYieldsCorrectNumberOfHashes(41.23452234, 40.09872762, 31.23432, 30.0113312322); - checkSearchYieldsCorrectHashes(47.447907, 47.300200, 8.760941, 8.471276, "u0qj"); + checkSearchYieldsCorrectNumberOfHashes(40.09872762, 41.23452234, 30.0113312322, 31.23432); + + checkSearchYieldsCorrectHashes(47.300200, 47.447907, 8.471276, 8.760941, "u0qj"); checkSearchYieldsCorrectHashes(47.157502, 47.329727, 8.562244, 8.859215, "u0qj", "u0qm", "u0qh", "u0qk"); + + // Testing bounding box over 180-Meridian + checkSearchYieldsCorrectNumberOfHashes(40.2090980098, 40.21982983232432, 170.523432424324, -170.494234232442); + checkSearchYieldsCorrectNumberOfHashes(40.2090980098, 40.21982983232432, 170.523432424324, 160.494234232442); + + checkSearchYieldsCorrectHashes(40.2090980098, 40.21982983232432, 170.523432424324, -170.494234232442, "xz", "8p"); + checkSearchYieldsCorrectBinaryHashes(47.157502, 47.329727, 179.062244, -179.859215, "1111101010101111", "010100000000010100000", "010100000000010100010"); + + // Check duplicate handling + checkSearchYieldsCorrectBinaryHashes(47.157502, 47.329727, 179.062244, 160, ""); + checkSearchYieldsCorrectBinaryHashes(47.157502, 47.329727, 179.062244, -1, "01", "1111101010101111"); } - private void checkSearchYieldsCorrectNumberOfHashes(double minLat, double maxLat, double minLon, double maxLon) { - GeoHashQuery search = new GeoHashBoundingBoxQuery(new BoundingBox(minLat, maxLat, minLon, maxLon)); + private void checkSearchYieldsCorrectNumberOfHashes(double southLat, double northLat, double westLon, double eastLon) { + GeoHashQuery search = new GeoHashBoundingBoxQuery(new BoundingBox(southLat, northLat, westLon, eastLon)); assertRightNumberOfSearchHashes(search); } - private void checkSearchYieldsCorrectHashes(double minLat, double maxLat, double minLon, double maxLon, - String... hashes) { - GeoHashQuery search = new GeoHashBoundingBoxQuery(new BoundingBox(minLat, maxLat, minLon, maxLon)); + private void checkSearchYieldsCorrectHashes(double southLat, double northLat, double westLon, double eastLon, String... hashes) { + GeoHashQuery search = new GeoHashBoundingBoxQuery(new BoundingBox(southLat, northLat, westLon, eastLon)); + assertEquals(hashes.length, search.getSearchHashes().size()); + for (String expectedHash : hashes) { + assertTrue("search hashes should contain '" + expectedHash + "':'" + GeoHash.fromGeohashString(expectedHash) + "'. Saved hashes:\n " + search, search.getSearchHashes().contains(GeoHash.fromGeohashString(expectedHash))); + } + } + + private void checkSearchYieldsCorrectBinaryHashes(double southLat, double northLat, double westLon, double eastLon, String... hashes) { + GeoHashQuery search = new GeoHashBoundingBoxQuery(new BoundingBox(southLat, northLat, westLon, eastLon)); assertEquals(hashes.length, search.getSearchHashes().size()); for (String expectedHash : hashes) { - assertTrue("search hashes should contain " + expectedHash + " is: " + search, search.getSearchHashes() - .contains( - GeoHash.fromGeohashString(expectedHash))); + assertTrue("search hashes should contain '" + expectedHash + "':'" + GeoHash.fromBinaryString(expectedHash) + "'. Saved hashes:\n " + search, search.getSearchHashes().contains(GeoHash.fromBinaryString(expectedHash))); } } private void assertRightNumberOfSearchHashes(GeoHashQuery search) { int size = search.getSearchHashes().size(); - assertTrue(size == 1 || size == 2 || size == 4); + assertTrue(size <= 8 && size > 0); } } diff --git a/src/test/java/ch/hsr/geohash/GeoHashCircleQueryTest.java b/src/test/java/ch/hsr/geohash/GeoHashCircleQueryTest.java index 6e976685..ec4f2527 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashCircleQueryTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashCircleQueryTest.java @@ -1,5 +1,6 @@ package ch.hsr.geohash; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -16,8 +17,30 @@ public void testIssue3WithCircleQuery() throws Exception { WGS84Point test1 = new WGS84Point(39.8648866576058, 116.378465869303); // the distance between center and test2 is about 510 meters WGS84Point test2 = new WGS84Point(39.8664787092599, 116.378552856158); + // the distance between center and test2 is about 600 meters + WGS84Point test3 = new WGS84Point(39.8786787092599, 116.378552856158); assertTrue(query.contains(test1)); assertTrue(query.contains(test2)); + assertFalse(query.contains(test3)); + } + + @Test + public void test180MeridianCircleQuery() throws Exception { + // Test query over 180-Meridian + WGS84Point center = new WGS84Point(39.86391280373075, 179.98356590048701); + GeoHashCircleQuery query = new GeoHashCircleQuery(center, 3000); + + WGS84Point test1 = new WGS84Point(39.8648866576058, 180); + WGS84Point test2 = new WGS84Point(39.8664787092599, -180); + WGS84Point test3 = new WGS84Point(39.8686787092599, -179.9957861565146); + WGS84Point test4 = new WGS84Point(39.8686787092599, 179.0057861565146); + WGS84Point test5 = new WGS84Point(39.8686787092599, -179.0); + + assertTrue(query.contains(test1)); + assertTrue(query.contains(test2)); + assertTrue(query.contains(test3)); + assertFalse(query.contains(test4)); + assertFalse(query.contains(test5)); } } From 01f89c904e4cea9dd14e91daf6cfb4562f9e10b5 Mon Sep 17 00:00:00 2001 From: b14ck1 Date: Wed, 13 Nov 2019 13:41:30 +0100 Subject: [PATCH 15/42] Fixed toString() to include leading zeros of binary geohash representation --- src/main/java/ch/hsr/geohash/GeoHash.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index 27eda240..cc866d97 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -458,12 +458,16 @@ protected final void addOffBitToEnd() { @Override public String toString() { if (significantBits % 5 == 0) { - return String.format("%s -> %s -> %s", Long.toBinaryString(bits), boundingBox, toBase32()); + return String.format("%s -> %s -> %s", padLeft(Long.toBinaryString(bits), 64, "0"), boundingBox, toBase32()); } else { - return String.format("%s -> %s, bits: %d", Long.toBinaryString(bits), boundingBox, significantBits); + return String.format("%s -> %s, bits: %d", padLeft(Long.toBinaryString(bits), 64, "0"), boundingBox, significantBits); } } + private static String padLeft(String s, int n, String pad) { + return String.format("%" + n + "s", s).replace(" ", pad); + } + public String toBinaryString() { StringBuilder bui = new StringBuilder(); long bitsCopy = bits; From d4f95b5d8f169c29565bb01f31e169b160a7093f Mon Sep 17 00:00:00 2001 From: b14ck1 Date: Wed, 13 Nov 2019 13:44:42 +0100 Subject: [PATCH 16/42] Fixed method renamings --- src/test/java/ch/hsr/geohash/GeoHashTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/ch/hsr/geohash/GeoHashTest.java b/src/test/java/ch/hsr/geohash/GeoHashTest.java index d4070b3d..74e51099 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashTest.java @@ -502,14 +502,14 @@ public void testStepsBetween() { } boolean latIsMore = false; boolean latIsLess = false; - if (idx.getPoint().getLatitude() > iterBbox.getMaxLat()) { + if (idx.getPoint().getLatitude() > iterBbox.getNorthLatitude()) { latIsMore = true; latMore++; - } else if (idx.getPoint().getLatitude() < iterBbox.getMinLat()) { + } else if (idx.getPoint().getLatitude() < iterBbox.getSouthLatitude()) { latIsLess = true; latLess++; } - if (idx.getPoint().getLongitude() > iterBbox.getMaxLon()) { + if (idx.getPoint().getLongitude() > iterBbox.getEastLongitude()) { lonMore++; if (latIsMore) { bothMore++; @@ -517,7 +517,7 @@ public void testStepsBetween() { if (latIsLess) { latLessLonMore++; } - } else if (idx.getPoint().getLongitude() < iterBbox.getMinLon()) { + } else if (idx.getPoint().getLongitude() < iterBbox.getWestLongitude()) { lonLess++; if (latIsLess) { bothLess++; From 18cd11d673633c33261526656411d50220970579 Mon Sep 17 00:00:00 2001 From: b14ck1 Date: Wed, 13 Nov 2019 14:00:30 +0100 Subject: [PATCH 17/42] Fixed wrong parameter order --- .../geohash/queries/GeoHashCircleQuery.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java b/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java index 32db87ac..4823b387 100644 --- a/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java +++ b/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java @@ -26,20 +26,17 @@ public class GeoHashCircleQuery implements GeoHashQuery, Serializable { private GeoHashBoundingBoxQuery query; private WGS84Point center; - /** - * create a {@link GeoHashCircleQuery} with the given center point and a - * radius in meters. - */ - public GeoHashCircleQuery(WGS84Point center, double radius) { - this.radius = radius; - this.center = center; - WGS84Point northEast = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 0, radius), 90, - radius); - WGS84Point southWest = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 180, radius), - 270, radius); - BoundingBox bbox = new BoundingBox(northEast, southWest); - query = new GeoHashBoundingBoxQuery(bbox); - } + /** + * create a {@link GeoHashCircleQuery} with the given center point and a radius in meters. + */ + public GeoHashCircleQuery(WGS84Point center, double radius) { + this.radius = radius; + this.center = center; + WGS84Point northEast = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 0, radius), 90, radius); + WGS84Point southWest = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 180, radius), 270, radius); + BoundingBox bbox = new BoundingBox(southWest, northEast); + query = new GeoHashBoundingBoxQuery(bbox); + } @Override public boolean contains(GeoHash hash) { From 409b5e075124b38e4f5d7465d8f2244b334cf6c1 Mon Sep 17 00:00:00 2001 From: bl4ck <34554655+b14ck1@users.noreply.github.com> Date: Wed, 13 Nov 2019 14:11:48 +0100 Subject: [PATCH 18/42] Moving to openjdk8 from oraclejdk8 OracleJDK8 is no longer supported on travis nodes. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7957a820..e1e9bd71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: java jdk: - - oraclejdk8 + - openjdk8 - openjdk7 From 5363b0312e0ef93f1a7b246df37e8b8de13cfbca Mon Sep 17 00:00:00 2001 From: bl4ck <34554655+b14ck1@users.noreply.github.com> Date: Wed, 13 Nov 2019 14:14:45 +0100 Subject: [PATCH 19/42] Removing openjdk7 Seems like OpenJDK7 is no longer supported on travis. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e1e9bd71..b179f30c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ language: java jdk: - openjdk8 - - openjdk7 From 5a56166721c2b7c0238954938357b2535741110e Mon Sep 17 00:00:00 2001 From: bl4ck <34554655+b14ck1@users.noreply.github.com> Date: Wed, 13 Nov 2019 14:23:08 +0100 Subject: [PATCH 20/42] Fixed wrong parameter ordering --- src/test/java/ch/hsr/geohash/util/GeoHashSizeTableTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/ch/hsr/geohash/util/GeoHashSizeTableTest.java b/src/test/java/ch/hsr/geohash/util/GeoHashSizeTableTest.java index 10c3cab5..0fb30e2b 100644 --- a/src/test/java/ch/hsr/geohash/util/GeoHashSizeTableTest.java +++ b/src/test/java/ch/hsr/geohash/util/GeoHashSizeTableTest.java @@ -63,7 +63,7 @@ public BoundingBox generate(int bits) { // make the bounding box a little smaller than dLat/dLon double dLat = GeoHashSizeTable.dLat(bits) - DELTA; double dLon = GeoHashSizeTable.dLon(bits) - DELTA; - return new BoundingBox(45 - dLat, 45, 30, 30 - dLon); + return new BoundingBox(45 - dLat, 45, 30 - dLon, 30); } @Override From 3d67eb53b8a937240d0e875561dde95e6f350752 Mon Sep 17 00:00:00 2001 From: b14ck1 Date: Wed, 13 Nov 2019 14:51:42 +0100 Subject: [PATCH 21/42] Changed parameters to be consistent with boundingBox-corners (southWest/northEast) --- .../util/BoundingBoxGeoHashIterator.java | 4 +- .../hsr/geohash/util/BoundingBoxSampler.java | 4 +- .../geohash/util/TwoGeoHashBoundingBox.java | 92 +++++++++---------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java index 79ff50d9..e0ee19a3 100644 --- a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java +++ b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java @@ -15,7 +15,7 @@ public class BoundingBoxGeoHashIterator implements Iterator { public BoundingBoxGeoHashIterator(TwoGeoHashBoundingBox bbox) { boundingBox = bbox; - current = bbox.getSouthEast(); + current = bbox.getSouthWest(); } public TwoGeoHashBoundingBox getBoundingBox() { @@ -24,7 +24,7 @@ public TwoGeoHashBoundingBox getBoundingBox() { @Override public boolean hasNext() { - return current.compareTo(boundingBox.getNorthWest()) <= 0; + return current.compareTo(boundingBox.getNorthEast()) <= 0; } @Override diff --git a/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java b/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java index 5572cdec..bb1c2bba 100644 --- a/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java +++ b/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java @@ -23,7 +23,7 @@ public class BoundingBoxSampler { */ public BoundingBoxSampler(TwoGeoHashBoundingBox bbox) { boundingBox = bbox; - long maxSamplesLong = GeoHash.stepsBetween(bbox.getSouthEast(), bbox.getNorthWest()); + long maxSamplesLong = GeoHash.stepsBetween(bbox.getSouthWest(), bbox.getNorthEast()); if (maxSamplesLong > Integer.MAX_VALUE) { throw new IllegalArgumentException("This bounding box is too big too sample using this algorithm"); } @@ -51,7 +51,7 @@ public GeoHash next() { idx = rand.nextInt(maxSamples + 1); } alreadyUsed.add(idx); - GeoHash gh = boundingBox.getSouthEast().next(idx); + GeoHash gh = boundingBox.getSouthWest().next(idx); if (!boundingBox.getBoundingBox().contains(gh.getPoint())) { return next(); } diff --git a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java index 747a7544..490b0ab7 100644 --- a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java +++ b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java @@ -7,50 +7,50 @@ * Created by IntelliJ IDEA. User: kevin Date: Jan 17, 2011 Time: 12:03:47 PM */ public class TwoGeoHashBoundingBox { - private BoundingBox boundingBox; - private GeoHash southEast; - private GeoHash northWest; - - public static TwoGeoHashBoundingBox withCharacterPrecision(BoundingBox bbox, int numberOfCharacters) { - GeoHash bottomLeft = GeoHash.withCharacterPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfCharacters); - GeoHash topRight = GeoHash.withCharacterPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfCharacters); - return new TwoGeoHashBoundingBox(bottomLeft, topRight); - } - - public static TwoGeoHashBoundingBox withBitPrecision(BoundingBox bbox, int numberOfBits) { - GeoHash bottomLeft = GeoHash.withBitPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfBits); - GeoHash topRight = GeoHash.withBitPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfBits); - return new TwoGeoHashBoundingBox(bottomLeft, topRight); - } - - public static TwoGeoHashBoundingBox fromBase32(String base32) { - String southWestBase32 = base32.substring(0, 7); - String northEastBase32 = base32.substring(7); - return new TwoGeoHashBoundingBox(GeoHash.fromGeohashString(southWestBase32), GeoHash.fromGeohashString(northEastBase32)); - } - - public TwoGeoHashBoundingBox(GeoHash southEast, GeoHash northWest) { - if (southEast.significantBits() != northWest.significantBits()) { - throw new IllegalArgumentException("Does it make sense to iterate between hashes that have different precisions?"); - } - this.southEast = GeoHash.fromLongValue(southEast.longValue(), southEast.significantBits()); - this.northWest = GeoHash.fromLongValue(northWest.longValue(), northWest.significantBits()); - boundingBox = new BoundingBox(southEast.getBoundingBox().getSouthLatitude(), northWest.getBoundingBox().getNorthLatitude(), northWest.getBoundingBox().getWestLongitude(), southEast.getBoundingBox().getEastLongitude()); - } - - public BoundingBox getBoundingBox() { - return boundingBox; - } - - public GeoHash getSouthEast() { - return southEast; - } - - public GeoHash getNorthWest() { - return northWest; - } - - public String toBase32() { - return southEast.toBase32() + northWest.toBase32(); - } + private BoundingBox boundingBox; + private GeoHash southWest; + private GeoHash northEast; + + public static TwoGeoHashBoundingBox withCharacterPrecision(BoundingBox bbox, int numberOfCharacters) { + GeoHash southWest = GeoHash.withCharacterPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfCharacters); + GeoHash northEast = GeoHash.withCharacterPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfCharacters); + return new TwoGeoHashBoundingBox(southWest, northEast); + } + + public static TwoGeoHashBoundingBox withBitPrecision(BoundingBox bbox, int numberOfBits) { + GeoHash southWest = GeoHash.withBitPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfBits); + GeoHash northEast = GeoHash.withBitPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfBits); + return new TwoGeoHashBoundingBox(southWest, northEast); + } + + public static TwoGeoHashBoundingBox fromBase32(String base32) { + String southWestBase32 = base32.substring(0, 7); + String northEastBase32 = base32.substring(7); + return new TwoGeoHashBoundingBox(GeoHash.fromGeohashString(southWestBase32), GeoHash.fromGeohashString(northEastBase32)); + } + + public TwoGeoHashBoundingBox(GeoHash southWest, GeoHash northEast) { + if (southWest.significantBits() != northEast.significantBits()) { + throw new IllegalArgumentException("Does it make sense to iterate between hashes that have different precisions?"); + } + this.southWest = GeoHash.fromLongValue(southWest.longValue(), southWest.significantBits()); + this.northEast = GeoHash.fromLongValue(northEast.longValue(), northEast.significantBits()); + boundingBox = new BoundingBox(southWest.getBoundingBox().getSouthLatitude(), northEast.getBoundingBox().getNorthLatitude(), southWest.getBoundingBox().getWestLongitude(), northEast.getBoundingBox().getEastLongitude()); + } + + public BoundingBox getBoundingBox() { + return boundingBox; + } + + public GeoHash getSouthWest() { + return southWest; + } + + public GeoHash getNorthEast() { + return northEast; + } + + public String toBase32() { + return southWest.toBase32() + northEast.toBase32(); + } } From efbc6d6c141b1706edb438853ec55c3e8342ec01 Mon Sep 17 00:00:00 2001 From: b14ck1 Date: Wed, 13 Nov 2019 14:53:18 +0100 Subject: [PATCH 22/42] Removing unnecessary constructor. Not used, documented, or useful. One should use the standard constructor and supply 2 different geohashes. --- .../java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java index 490b0ab7..539f738a 100644 --- a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java +++ b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java @@ -23,12 +23,6 @@ public static TwoGeoHashBoundingBox withBitPrecision(BoundingBox bbox, int numbe return new TwoGeoHashBoundingBox(southWest, northEast); } - public static TwoGeoHashBoundingBox fromBase32(String base32) { - String southWestBase32 = base32.substring(0, 7); - String northEastBase32 = base32.substring(7); - return new TwoGeoHashBoundingBox(GeoHash.fromGeohashString(southWestBase32), GeoHash.fromGeohashString(northEastBase32)); - } - public TwoGeoHashBoundingBox(GeoHash southWest, GeoHash northEast) { if (southWest.significantBits() != northEast.significantBits()) { throw new IllegalArgumentException("Does it make sense to iterate between hashes that have different precisions?"); From d6e4854361abeab2166cad8f6df6e342d1e3a599 Mon Sep 17 00:00:00 2001 From: b14ck1 Date: Mon, 18 Nov 2019 13:14:08 +0100 Subject: [PATCH 23/42] Renamed methods and fields to be more precise --- src/main/java/ch/hsr/geohash/BoundingBox.java | 24 +++--- src/main/java/ch/hsr/geohash/GeoHash.java | 8 +- .../queries/GeoHashBoundingBoxQuery.java | 4 +- .../geohash/queries/GeoHashCircleQuery.java | 22 ++--- .../util/BoundingBoxGeoHashIterator.java | 6 +- .../hsr/geohash/util/BoundingBoxSampler.java | 8 +- .../geohash/util/TwoGeoHashBoundingBox.java | 80 +++++++++---------- src/test/java/ch/hsr/geohash/GeoHashTest.java | 18 ++--- .../util/BoundingBoxGeoHashIteratorTest.java | 4 +- .../geohash/util/BoundingBoxSamplerTest.java | 2 +- 10 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/BoundingBox.java b/src/main/java/ch/hsr/geohash/BoundingBox.java index 04b8d2d0..83a49c80 100644 --- a/src/main/java/ch/hsr/geohash/BoundingBox.java +++ b/src/main/java/ch/hsr/geohash/BoundingBox.java @@ -21,8 +21,8 @@ public class BoundingBox implements Serializable { /** * create a bounding box defined by two coordinates */ - public BoundingBox(WGS84Point southWest, WGS84Point northEast) { - this(southWest.getLatitude(), northEast.getLatitude(), southWest.getLongitude(), northEast.getLongitude()); + public BoundingBox(WGS84Point southWestCorner, WGS84Point northEastCorner) { + this(southWestCorner.getLatitude(), northEastCorner.getLatitude(), southWestCorner.getLongitude(), northEastCorner.getLongitude()); } /** @@ -63,38 +63,38 @@ public BoundingBox(BoundingBox that) { } /** - * Returns the NorthWestPoint of this BoundingBox as a new Point. + * Returns the NorthWestCorner of this BoundingBox as a new Point. * * @return */ - public WGS84Point getNorthWestPoint() { + public WGS84Point getNorthWestCorner() { return new WGS84Point(northLatitude, westLongitude); } /** - * Returns the NorthEastPoint of this BoundingBox as a new Point. + * Returns the NorthEastCorner of this BoundingBox as a new Point. * * @return */ - public WGS84Point getNorthEastPoint() { + public WGS84Point getNorthEastCorner() { return new WGS84Point(northLatitude, eastLongitude); } /** - * Returns the SouthEastPoint of this BoundingBox as a new Point. + * Returns the SouthEastCorner of this BoundingBox as a new Point. * * @return */ - public WGS84Point getSouthEastPoint() { + public WGS84Point getSouthEastCorner() { return new WGS84Point(southLatitude, eastLongitude); } /** - * Returns the SouthWestPoint of this BoundingBox as a new Point. + * Returns the SouthWestCorner of this BoundingBox as a new Point. * * @return */ - public WGS84Point getSouthWestPoint() { + public WGS84Point getSouthWestCorner() { return new WGS84Point(southLatitude, westLongitude); } @@ -173,10 +173,10 @@ public boolean intersects(BoundingBox other) { @Override public String toString() { - return getNorthWestPoint() + " -> " + getSouthEastPoint(); + return getNorthWestCorner() + " -> " + getSouthEastCorner(); } - public WGS84Point getCenterPoint() { + public WGS84Point getCenter() { double centerLatitude = (southLatitude + northLatitude) / 2; double centerLongitude = (westLongitude + eastLongitude) / 2; diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index cc866d97..b1f6938a 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -334,7 +334,7 @@ public boolean contains(WGS84Point point) { * If it was built from a base32-{@link String}, this is the center point of * the bounding box. */ - public WGS84Point getPoint() { + public WGS84Point getOriginatingPoint() { return point; } @@ -343,8 +343,8 @@ public WGS84Point getPoint() { * the same point that was used to build the hash. */ // TODO: make sure this method works as intented for corner cases! - public WGS84Point getBoundingBoxCenterPoint() { - return boundingBox.getCenterPoint(); + public WGS84Point getBoundingBoxCenter() { + return boundingBox.getCenter(); } public BoundingBox getBoundingBox() { @@ -375,7 +375,7 @@ protected GeoHash recombineLatLonBitsToHash(long[] latBits, long[] lonBits) { } hash.bits <<= (MAX_BIT_PRECISION - hash.significantBits); setBoundingBox(hash, latitudeRange, longitudeRange); - hash.point = hash.boundingBox.getCenterPoint(); + hash.point = hash.boundingBox.getCenter(); return hash; } diff --git a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java index 5e7ae2a9..c76813e8 100644 --- a/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java +++ b/src/main/java/ch/hsr/geohash/queries/GeoHashBoundingBoxQuery.java @@ -87,7 +87,7 @@ public GeoHashBoundingBoxQuery(BoundingBox bbox) { private void generateSearchHashes(BoundingBox bbox) { int fittingBits = GeoHashSizeTable.numberOfBitsForOverlappingGeoHash(bbox); - WGS84Point center = bbox.getCenterPoint(); + WGS84Point center = bbox.getCenter(); GeoHash centerHash = GeoHash.withBitPrecision(center.getLatitude(), center.getLongitude(), fittingBits); if (hashContainsBoundingBox(centerHash, bbox)) { @@ -118,7 +118,7 @@ private void expandSearch(GeoHash centerHash, BoundingBox bbox) { * @return */ private boolean hashContainsBoundingBox(GeoHash hash, BoundingBox bbox) { - return hash.contains(bbox.getNorthWestPoint()) && hash.contains(bbox.getSouthEastPoint()); + return hash.contains(bbox.getNorthWestCorner()) && hash.contains(bbox.getSouthEastCorner()); } @Override diff --git a/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java b/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java index 4823b387..81fe47cf 100644 --- a/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java +++ b/src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java @@ -26,17 +26,17 @@ public class GeoHashCircleQuery implements GeoHashQuery, Serializable { private GeoHashBoundingBoxQuery query; private WGS84Point center; - /** - * create a {@link GeoHashCircleQuery} with the given center point and a radius in meters. - */ - public GeoHashCircleQuery(WGS84Point center, double radius) { - this.radius = radius; - this.center = center; - WGS84Point northEast = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 0, radius), 90, radius); - WGS84Point southWest = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 180, radius), 270, radius); - BoundingBox bbox = new BoundingBox(southWest, northEast); - query = new GeoHashBoundingBoxQuery(bbox); - } + /** + * create a {@link GeoHashCircleQuery} with the given center point and a radius in meters. + */ + public GeoHashCircleQuery(WGS84Point center, double radius) { + this.radius = radius; + this.center = center; + WGS84Point northEastCorner = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 0, radius), 90, radius); + WGS84Point southWestCorner = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 180, radius), 270, radius); + BoundingBox bbox = new BoundingBox(southWestCorner, northEastCorner); + query = new GeoHashBoundingBoxQuery(bbox); + } @Override public boolean contains(GeoHash hash) { diff --git a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java index e0ee19a3..5bd47fab 100644 --- a/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java +++ b/src/main/java/ch/hsr/geohash/util/BoundingBoxGeoHashIterator.java @@ -15,7 +15,7 @@ public class BoundingBoxGeoHashIterator implements Iterator { public BoundingBoxGeoHashIterator(TwoGeoHashBoundingBox bbox) { boundingBox = bbox; - current = bbox.getSouthWest(); + current = bbox.getSouthWestCorner(); } public TwoGeoHashBoundingBox getBoundingBox() { @@ -24,7 +24,7 @@ public TwoGeoHashBoundingBox getBoundingBox() { @Override public boolean hasNext() { - return current.compareTo(boundingBox.getNorthEast()) <= 0; + return current.compareTo(boundingBox.getNorthEastCorner()) <= 0; } @Override @@ -34,7 +34,7 @@ public GeoHash next() { throw new NoSuchElementException(); } current = rv.next(); - while (hasNext() && !boundingBox.getBoundingBox().contains(current.getPoint())) { + while (hasNext() && !boundingBox.getBoundingBox().contains(current.getOriginatingPoint())) { current = current.next(); } return rv; diff --git a/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java b/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java index bb1c2bba..6b353f95 100644 --- a/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java +++ b/src/main/java/ch/hsr/geohash/util/BoundingBoxSampler.java @@ -23,7 +23,7 @@ public class BoundingBoxSampler { */ public BoundingBoxSampler(TwoGeoHashBoundingBox bbox) { boundingBox = bbox; - long maxSamplesLong = GeoHash.stepsBetween(bbox.getSouthWest(), bbox.getNorthEast()); + long maxSamplesLong = GeoHash.stepsBetween(bbox.getSouthWestCorner(), bbox.getNorthEastCorner()); if (maxSamplesLong > Integer.MAX_VALUE) { throw new IllegalArgumentException("This bounding box is too big too sample using this algorithm"); } @@ -32,7 +32,7 @@ public BoundingBoxSampler(TwoGeoHashBoundingBox bbox) { public BoundingBoxSampler(TwoGeoHashBoundingBox bbox, long seed) { this(bbox); - this.rand = new Random(seed); + rand = new Random(seed); } public TwoGeoHashBoundingBox getBoundingBox() { @@ -51,8 +51,8 @@ public GeoHash next() { idx = rand.nextInt(maxSamples + 1); } alreadyUsed.add(idx); - GeoHash gh = boundingBox.getSouthWest().next(idx); - if (!boundingBox.getBoundingBox().contains(gh.getPoint())) { + GeoHash gh = boundingBox.getSouthWestCorner().next(idx); + if (!boundingBox.getBoundingBox().contains(gh.getOriginatingPoint())) { return next(); } return gh; diff --git a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java index 539f738a..300a69c3 100644 --- a/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java +++ b/src/main/java/ch/hsr/geohash/util/TwoGeoHashBoundingBox.java @@ -7,44 +7,44 @@ * Created by IntelliJ IDEA. User: kevin Date: Jan 17, 2011 Time: 12:03:47 PM */ public class TwoGeoHashBoundingBox { - private BoundingBox boundingBox; - private GeoHash southWest; - private GeoHash northEast; - - public static TwoGeoHashBoundingBox withCharacterPrecision(BoundingBox bbox, int numberOfCharacters) { - GeoHash southWest = GeoHash.withCharacterPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfCharacters); - GeoHash northEast = GeoHash.withCharacterPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfCharacters); - return new TwoGeoHashBoundingBox(southWest, northEast); - } - - public static TwoGeoHashBoundingBox withBitPrecision(BoundingBox bbox, int numberOfBits) { - GeoHash southWest = GeoHash.withBitPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfBits); - GeoHash northEast = GeoHash.withBitPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfBits); - return new TwoGeoHashBoundingBox(southWest, northEast); - } - - public TwoGeoHashBoundingBox(GeoHash southWest, GeoHash northEast) { - if (southWest.significantBits() != northEast.significantBits()) { - throw new IllegalArgumentException("Does it make sense to iterate between hashes that have different precisions?"); - } - this.southWest = GeoHash.fromLongValue(southWest.longValue(), southWest.significantBits()); - this.northEast = GeoHash.fromLongValue(northEast.longValue(), northEast.significantBits()); - boundingBox = new BoundingBox(southWest.getBoundingBox().getSouthLatitude(), northEast.getBoundingBox().getNorthLatitude(), southWest.getBoundingBox().getWestLongitude(), northEast.getBoundingBox().getEastLongitude()); - } - - public BoundingBox getBoundingBox() { - return boundingBox; - } - - public GeoHash getSouthWest() { - return southWest; - } - - public GeoHash getNorthEast() { - return northEast; - } - - public String toBase32() { - return southWest.toBase32() + northEast.toBase32(); - } + private BoundingBox boundingBox; + private GeoHash southWestCorner; + private GeoHash northEastCorner; + + public static TwoGeoHashBoundingBox withCharacterPrecision(BoundingBox bbox, int numberOfCharacters) { + GeoHash southWestCorner = GeoHash.withCharacterPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfCharacters); + GeoHash northEastCorner = GeoHash.withCharacterPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfCharacters); + return new TwoGeoHashBoundingBox(southWestCorner, northEastCorner); + } + + public static TwoGeoHashBoundingBox withBitPrecision(BoundingBox bbox, int numberOfBits) { + GeoHash southWestCorner = GeoHash.withBitPrecision(bbox.getSouthLatitude(), bbox.getWestLongitude(), numberOfBits); + GeoHash northEastCorner = GeoHash.withBitPrecision(bbox.getNorthLatitude(), bbox.getEastLongitude(), numberOfBits); + return new TwoGeoHashBoundingBox(southWestCorner, northEastCorner); + } + + public TwoGeoHashBoundingBox(GeoHash southWestCorner, GeoHash northEastCorner) { + if (southWestCorner.significantBits() != northEastCorner.significantBits()) { + throw new IllegalArgumentException("Does it make sense to iterate between hashes that have different precisions?"); + } + this.southWestCorner = GeoHash.fromLongValue(southWestCorner.longValue(), southWestCorner.significantBits()); + this.northEastCorner = GeoHash.fromLongValue(northEastCorner.longValue(), northEastCorner.significantBits()); + boundingBox = new BoundingBox(southWestCorner.getBoundingBox().getSouthLatitude(), northEastCorner.getBoundingBox().getNorthLatitude(), southWestCorner.getBoundingBox().getWestLongitude(), northEastCorner.getBoundingBox().getEastLongitude()); + } + + public BoundingBox getBoundingBox() { + return boundingBox; + } + + public GeoHash getSouthWestCorner() { + return southWestCorner; + } + + public GeoHash getNorthEastCorner() { + return northEastCorner; + } + + public String toBase32() { + return southWestCorner.toBase32() + northEastCorner.toBase32(); + } } diff --git a/src/test/java/ch/hsr/geohash/GeoHashTest.java b/src/test/java/ch/hsr/geohash/GeoHashTest.java index 74e51099..1ff4c3d3 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashTest.java @@ -78,7 +78,7 @@ public void testDecode() { for (GeoHash gh : RandomGeohashes.fullRange()) { BoundingBox bbox = gh.getBoundingBox(); GeoHash decodedHash = GeoHash.fromGeohashString(gh.toBase32()); - WGS84Point decodedCenter = decodedHash.getBoundingBoxCenterPoint(); + WGS84Point decodedCenter = decodedHash.getBoundingBoxCenter(); assertTrue("bbox " + bbox + " should contain the decoded center value " + decodedCenter, bbox .contains(decodedCenter)); @@ -348,8 +348,8 @@ public void testThatAdjacentHashesHavePointInitialized() { GeoHash[] adjacentHashes = geohash.getAdjacent(); for (GeoHash adjacentHash : adjacentHashes) { assertNotNull(adjacentHash.getBoundingBox()); - assertNotNull(adjacentHash.getBoundingBoxCenterPoint()); - assertNotNull(adjacentHash.getPoint()); + assertNotNull(adjacentHash.getBoundingBoxCenter()); + assertNotNull(adjacentHash.getOriginatingPoint()); } } @@ -405,7 +405,7 @@ public void testSimpleWithin() { } private void printBoundingBox(GeoHash hash) { - System.out.println("Bounding Box: \ncenter =" + hash.getBoundingBoxCenterPoint()); + System.out.println("Bounding Box: \ncenter =" + hash.getBoundingBoxCenter()); System.out.print("corners="); System.out.println(hash.getBoundingBox()); } @@ -497,19 +497,19 @@ public void testStepsBetween() { while (idx.compareTo(ur) < 0) { idx = idx.next(); allHashes++; - if (iterBbox.contains(idx.getPoint())) { + if (iterBbox.contains(idx.getOriginatingPoint())) { inBbox++; } boolean latIsMore = false; boolean latIsLess = false; - if (idx.getPoint().getLatitude() > iterBbox.getNorthLatitude()) { + if (idx.getOriginatingPoint().getLatitude() > iterBbox.getNorthLatitude()) { latIsMore = true; latMore++; - } else if (idx.getPoint().getLatitude() < iterBbox.getSouthLatitude()) { + } else if (idx.getOriginatingPoint().getLatitude() < iterBbox.getSouthLatitude()) { latIsLess = true; latLess++; } - if (idx.getPoint().getLongitude() > iterBbox.getEastLongitude()) { + if (idx.getOriginatingPoint().getLongitude() > iterBbox.getEastLongitude()) { lonMore++; if (latIsMore) { bothMore++; @@ -517,7 +517,7 @@ public void testStepsBetween() { if (latIsLess) { latLessLonMore++; } - } else if (idx.getPoint().getLongitude() < iterBbox.getWestLongitude()) { + } else if (idx.getOriginatingPoint().getLongitude() < iterBbox.getWestLongitude()) { lonLess++; if (latIsLess) { bothLess++; diff --git a/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java b/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java index ef666415..98cb9a85 100644 --- a/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java +++ b/src/test/java/ch/hsr/geohash/util/BoundingBoxGeoHashIteratorTest.java @@ -28,7 +28,7 @@ public void testIter() { if (prev != null) { Assert.assertTrue(prev.compareTo(gh) < 0); } - Assert.assertTrue(newBox.contains(gh.getPoint())); + Assert.assertTrue(newBox.contains(gh.getOriginatingPoint())); prev = gh; } @@ -49,7 +49,7 @@ public void testIter2() { if (prev != null) { Assert.assertTrue(prev.compareTo(gh) < 0); } - Assert.assertTrue(newBox.contains(gh.getPoint())); + Assert.assertTrue(newBox.contains(gh.getOriginatingPoint())); prev = gh; } diff --git a/src/test/java/ch/hsr/geohash/util/BoundingBoxSamplerTest.java b/src/test/java/ch/hsr/geohash/util/BoundingBoxSamplerTest.java index 58481a61..75a2415a 100644 --- a/src/test/java/ch/hsr/geohash/util/BoundingBoxSamplerTest.java +++ b/src/test/java/ch/hsr/geohash/util/BoundingBoxSamplerTest.java @@ -28,7 +28,7 @@ public void testSampler() { GeoHash prev = null; while (gh != null) { - assertTrue(bbox.contains(gh.getPoint())); + assertTrue(bbox.contains(gh.getOriginatingPoint())); assertFalse(hashes.contains(gh.toBase32())); hashes.add(gh.toBase32()); if (prev != null) { From 157b9fc9561877b064c22c319c1c485cb3931f79 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Tue, 10 Dec 2019 13:44:14 +0100 Subject: [PATCH 24/42] Update pom.xml to reflect breaking changes --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fe85a686..4adfb3d0 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ jar ch.hsr geohash - 1.3.1-SNAPSHOT + 1.4.0-SNAPSHOT geohash-java An implementation of Geohashes in pure Java. From 9f65d440ec199bf89a016e9be9b879a43321c1e2 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Tue, 10 Dec 2019 13:58:37 +0100 Subject: [PATCH 25/42] Update README so it explains the changes between 1.3.x. and 1.4.x --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index d056281c..34d4f0d1 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,32 @@ Current development involves getting the following things to run: Last important changes ---------------------- +Version 1.4.0 +----------------------- + +This version adds support for `BoundingBox`es to go over the 180 meridian, which enables +searching and querying by covering them with `Geohash`es. +This was a much requested feature that made it into the library now, but depending on how +you construct `BoundingBox`es and how you use the library, this is a _breaking change_. + +In this version you need to provide `latitude` and `longitude` to `BoundingBox` +in a specific order for this wo work: + +````java +new BoundingBox(south, north, west, east); +```` + +This breaking change enables creating bounding boxes that go over the 180 +meridian which can then be used in coverage queries. + +This version also changes the `toString()` implementation of `GeoHash` to +always include leading zeroes, so if your code actually relies on that, +you will also need to change things downstream that potentially use a prefix +query for matching points in a `GeoHash`s `BoundingBox`. + +Fo now, we will continue to backport other fixes to the `1.3.x` branch, so you can +keep on using that version as well. + Version 1.3.0 ----------------------- From 20759d303cabf2aa57a08c3f4ee726889702ae43 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Tue, 10 Dec 2019 14:07:38 +0100 Subject: [PATCH 26/42] Ignore eclipse files for now --- .classpath | 26 ------------------------- .gitignore | 5 +++++ .project | 29 ---------------------------- .settings/org.eclipse.jdt.core.prefs | 8 -------- 4 files changed, 5 insertions(+), 63 deletions(-) delete mode 100644 .classpath delete mode 100644 .project delete mode 100644 .settings/org.eclipse.jdt.core.prefs diff --git a/.classpath b/.classpath deleted file mode 100644 index 1e5d9864..00000000 --- a/.classpath +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.gitignore b/.gitignore index 9fe9a578..1c604cd3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,8 @@ release *.new *.old /.idea + +.project/* +.classpath +.settings/* +.vscode diff --git a/.project b/.project deleted file mode 100644 index a72749df..00000000 --- a/.project +++ /dev/null @@ -1,29 +0,0 @@ - - - ch.hsr.geohash - NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse. - - - - - org.eclipse.jdt.core.javabuilder - - - - - net.sourceforge.metrics.builder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.jdt.core.javanature - net.sourceforge.metrics.nature - - diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 443e0859..00000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.7 From faa4ee08de7f93dcfdcf4d786419fb7f599d5d72 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Tue, 10 Dec 2019 14:18:19 +0100 Subject: [PATCH 27/42] [maven-release-plugin] prepare release 1.4.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4adfb3d0..363f1dd2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ jar ch.hsr geohash - 1.4.0-SNAPSHOT + 1.4.0 geohash-java An implementation of Geohashes in pure Java. @@ -20,7 +20,7 @@ scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git - HEAD + 1.4.0 org.sonatype.oss From 7e839eb8896f9a11ab240d1025fcb8cb77631523 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Wed, 11 Dec 2019 17:52:42 +0100 Subject: [PATCH 28/42] Migrate to new plugins since the old parent pom is unsupported --- pom.xml | 166 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 59 deletions(-) diff --git a/pom.xml b/pom.xml index 363f1dd2..975d1441 100644 --- a/pom.xml +++ b/pom.xml @@ -16,70 +16,118 @@ repo
- + scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git 1.4.0 - - org.sonatype.oss - oss-parent - 7 - - - - kungfoo - - - github contributors - - - - UTF-8 - UTF-8 - - - - junit - junit - 4.12 - test - - - - - - maven-release-plugin - 2.4.2 + + + kungfoo + + + github contributors + + + + UTF-8 + UTF-8 + + + + junit + junit + 4.12 + test + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + - - @{project.version} - false - true - false - release - deploy - + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.8.1 - - - + + maven-release-plugin + 2.4.2 - - org.apache.maven.plugins - maven-compiler-plugin - 3.0 - - 1.7 - 1.7 - - - - - + + @{project.version} + false + true + false + release + deploy + + + + + org.apache.maven.scm + maven-scm-provider-gitexe + 1.8.1 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.7 + 1.7 + + + + + From 3f88fcc43a2e833b49a8ec2a5b07ec90e287d7ae Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Thu, 12 Dec 2019 10:35:20 +0100 Subject: [PATCH 29/42] Fix maven publishing with new plugins for sonatype ossrh --- pom.xml | 84 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/pom.xml b/pom.xml index 975d1441..c6910c2b 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,12 @@ test + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + @@ -57,45 +63,45 @@ - org.apache.maven.plugins - maven-source-plugin - 2.2.1 - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - - sign-artifacts - verify - - sign - - - - + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + maven-release-plugin From d40989eb8c31eb89cceb1d3782f43b6cf5bdf594 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Thu, 12 Dec 2019 10:36:22 +0100 Subject: [PATCH 30/42] Adjust release.sh script for new release plugin --- release.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/release.sh b/release.sh index 22694272..d5baa4d6 100755 --- a/release.sh +++ b/release.sh @@ -1,4 +1,3 @@ #!/bin/bash - -mvn release:clean release:prepare -mvn release:perform \ No newline at end of file +mvn clean deploy +mvn nexus-staging:release From 2fc9d073c06ce10fbea8cb79b7bd24d7ca89729e Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Wed, 11 Dec 2019 17:52:42 +0100 Subject: [PATCH 31/42] Migrate to new plugins since the old parent pom is unsupported --- pom.xml | 166 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 59 deletions(-) diff --git a/pom.xml b/pom.xml index 363f1dd2..975d1441 100644 --- a/pom.xml +++ b/pom.xml @@ -16,70 +16,118 @@ repo - + scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git 1.4.0 - - org.sonatype.oss - oss-parent - 7 - - - - kungfoo - - - github contributors - - - - UTF-8 - UTF-8 - - - - junit - junit - 4.12 - test - - - - - - maven-release-plugin - 2.4.2 + + + kungfoo + + + github contributors + + + + UTF-8 + UTF-8 + + + + junit + junit + 4.12 + test + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + - - @{project.version} - false - true - false - release - deploy - + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.8.1 - - - + + maven-release-plugin + 2.4.2 - - org.apache.maven.plugins - maven-compiler-plugin - 3.0 - - 1.7 - 1.7 - - - - - + + @{project.version} + false + true + false + release + deploy + + + + + org.apache.maven.scm + maven-scm-provider-gitexe + 1.8.1 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.7 + 1.7 + + + + + From 36135d19b08b077b1efa3aa0c2b2eb8948b6f24d Mon Sep 17 00:00:00 2001 From: KK4SBB Date: Thu, 7 May 2020 11:16:09 +0800 Subject: [PATCH 32/42] Update README.md add precision table --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 34d4f0d1..26c77af9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,20 @@ Maven targets are the usual suspects. - test - package # pack a versioned jar containing the compiled class files +Digits and precision in km +-------------------------- +| geohash length | lat bits | lng bits | lat error | lng error | km error | +|----------------|----------|----------|-----------|------------|-----------| +| 1 | 2 | 3 | ±23 | ±23 | ±2500 | +| 2 | 5 | 5 | ±2.8 | ±5.6 | ±630 | +| 3 | 7 | 8 | ±0.70 | ±0.70 | ±78 | +| 4 | 10 | 10 | ±0.087 | ±0.18 | ±20 | +| 5 | 12 | 13 | ±0.022 | ±0.022 | ±2.4 | +| 6 | 15 | 15 | ±0.0027 | ±0.0055 | ±0.61 | +| 7 | 17 | 18 | ±0.00068 | ±0.00068 | ±0.076 | +| 8 | 20 | 20 | ±0.000085 | ±0.00017 | ±0.019 | + + Compatibility ------------------------- This branch ditches 1.6 compatibility. If you need that look at the release-1.0 branch From 338dc7506e82ffd2f89646ea35a382725a97daef Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Tue, 12 May 2020 12:19:40 +0200 Subject: [PATCH 33/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26c77af9..15f7ef5a 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Maven targets are the usual suspects. Digits and precision in km -------------------------- -| geohash length | lat bits | lng bits | lat error | lng error | km error | +| geohash length | lat bits | lng bits | lat error | lng error | ~km error | |----------------|----------|----------|-----------|------------|-----------| | 1 | 2 | 3 | ±23 | ±23 | ±2500 | | 2 | 5 | 5 | ±2.8 | ±5.6 | ±630 | From a255c79eef4fb2d23c9d9c47d60b93988466bf9d Mon Sep 17 00:00:00 2001 From: vinerich <34554655+vinerich@users.noreply.github.com> Date: Wed, 20 May 2020 16:16:31 +0200 Subject: [PATCH 34/42] Added ability to expand bboxes to include points --- src/main/java/ch/hsr/geohash/BoundingBox.java | 42 ++++++++++++--- .../java/ch/hsr/geohash/util/DoubleUtil.java | 17 ++++++ .../java/ch/hsr/geohash/BoundingBoxTest.java | 52 +++++++++++++++++++ .../ch/hsr/geohash/util/DoubleUtilTest.java | 20 +++++++ 4 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 src/main/java/ch/hsr/geohash/util/DoubleUtil.java create mode 100644 src/test/java/ch/hsr/geohash/util/DoubleUtilTest.java diff --git a/src/main/java/ch/hsr/geohash/BoundingBox.java b/src/main/java/ch/hsr/geohash/BoundingBox.java index 83a49c80..31aac295 100644 --- a/src/main/java/ch/hsr/geohash/BoundingBox.java +++ b/src/main/java/ch/hsr/geohash/BoundingBox.java @@ -9,6 +9,7 @@ package ch.hsr.geohash; import java.io.Serializable; +import ch.hsr.geohash.util.DoubleUtil; public class BoundingBox implements Serializable { private static final long serialVersionUID = -7145192134410261076L; @@ -186,6 +187,37 @@ public WGS84Point getCenter() { return new WGS84Point(centerLatitude, centerLongitude); } + + /** + * Expands this bounding box to include the provided point. The expansion is done in the direction with the minimal distance. If both distances are the same it'll expand + * in east direction. It will not cross poles, but it will cross the 180-Meridian, if thats the shortest distance.
+ * + * @param point The point to include + */ + public void expandToInclude(WGS84Point point) { + + // Expand Latitude + if(point.getLatitude() < southLatitude) + southLatitude = point.getLatitude(); + else if(point.getLatitude() > northLatitude) + northLatitude = point.getLatitude(); + + // Already done in this case + if(containsLongitude(point.getLongitude())) + return; + + // If this is not the case compute the distance between the endpoints in east direction + double distanceEastToPoint = DoubleUtil.remainderWithFix(point.getLongitude() - eastLongitude, 360); + double distancePointToWest = DoubleUtil.remainderWithFix(westLongitude - point.getLongitude(), 360); + + // The minimal distance needs to be extended + if(distanceEastToPoint <= distancePointToWest) + eastLongitude = point.getLongitude(); + else + westLongitude = point.getLongitude(); + + intersects180Meridian = eastLongitude < westLongitude; + } /** * Expands this bounding box to include the provided bounding box. The expansion is done in the direction with the minimal distance. If both distances are the same it'll expand @@ -228,14 +260,8 @@ public void expandToInclude(BoundingBox other) { } // If this is not the case compute the distance between the endpoints in east direction - double distanceEastToOtherEast = (other.eastLongitude - eastLongitude) % 360; - double distanceOtherWestToWest = (westLongitude - other.westLongitude) % 360; - - // Fix for lower java versions, since the remainder-operator (%) changed in one version, idk which one - if (distanceEastToOtherEast < 0) - distanceEastToOtherEast += 360; - if (distanceOtherWestToWest < 0) - distanceOtherWestToWest += 360; + double distanceEastToOtherEast = DoubleUtil.remainderWithFix(other.eastLongitude - eastLongitude, 360); + double distanceOtherWestToWest = DoubleUtil.remainderWithFix(westLongitude - other.westLongitude, 360); // The minimal distance needs to be extended if (distanceEastToOtherEast <= distanceOtherWestToWest) { diff --git a/src/main/java/ch/hsr/geohash/util/DoubleUtil.java b/src/main/java/ch/hsr/geohash/util/DoubleUtil.java new file mode 100644 index 00000000..65a01f53 --- /dev/null +++ b/src/main/java/ch/hsr/geohash/util/DoubleUtil.java @@ -0,0 +1,17 @@ +package ch.hsr.geohash.util; + +public class DoubleUtil { + + /** + * Utility function to consistently compute the remainder over all java versions + * @param value + * @param remainder + * @return + */ + public static double remainderWithFix(double value, int remainder) { + double res = value % remainder; + + // Fix for lower java versions, since the remainder-operator (%) changed in one version, idk which one + return res < 0 ? res += remainder : res; + } +} diff --git a/src/test/java/ch/hsr/geohash/BoundingBoxTest.java b/src/test/java/ch/hsr/geohash/BoundingBoxTest.java index da873b55..96dec1b2 100644 --- a/src/test/java/ch/hsr/geohash/BoundingBoxTest.java +++ b/src/test/java/ch/hsr/geohash/BoundingBoxTest.java @@ -111,6 +111,58 @@ public void testIntersects() { assertDoesNotIntersect(bbox, new BoundingBox(50, 55, 160, 169)); assertDoesNotIntersect(bbox, new BoundingBox(50, 55, -169, -160)); } + + @Test + public void testExpandToIncludePoint() { + // expand east + BoundingBox bbox = new BoundingBox(-10, 10, 40, 41); + WGS84Point point = new WGS84Point(0, 45); + bbox.expandToInclude(point); + assertContains(bbox, point); + assertExpandToInclude(bbox, -10, 10, 40, 45); + + bbox = new BoundingBox(-10, 10, 40, 41); + point = new WGS84Point(0, -140); + bbox.expandToInclude(point); + assertContains(bbox, point); + assertExpandToInclude(bbox, -10, 10, 40, -140); + assertEquals(true, bbox.intersects180Meridian()); + + // expand west + bbox = new BoundingBox(-10, 10, 40, 41); + point = new WGS84Point(0, 35); + bbox.expandToInclude(point); + assertContains(bbox, point); + assertExpandToInclude(bbox, -10, 10, 35, 41); + + bbox = new BoundingBox(-10, 10, 40, 41); + point = new WGS84Point(0, -139); + bbox.expandToInclude(point); + assertContains(bbox, point); + assertExpandToInclude(bbox, -10, 10, -139, 41); + assertEquals(false, bbox.intersects180Meridian()); + + // expand south + bbox = new BoundingBox(-10, 10, 40, 41); + point = new WGS84Point(-20, 40); + bbox.expandToInclude(point); + assertContains(bbox, point); + assertExpandToInclude(bbox, -20, 10, 40, 41); + + // expand north + bbox = new BoundingBox(-10, 10, 40, 41); + point = new WGS84Point(20, 40); + bbox.expandToInclude(point); + assertContains(bbox, point); + assertExpandToInclude(bbox, -10, 20, 40, 41); + } + + private void assertExpandToInclude(BoundingBox bbox, double southLatitude, double northLatitude, double westLongitude, double eastLongitude) { + assertEquals(southLatitude, bbox.getSouthLatitude(), DELTA); + assertEquals(northLatitude, bbox.getNorthLatitude(), DELTA); + assertEquals(westLongitude, bbox.getWestLongitude(), DELTA); + assertEquals(eastLongitude, bbox.getEastLongitude(), DELTA); + } private void assertDoesNotIntersect(BoundingBox bbox, BoundingBox boundingBox) { assertFalse(bbox + " should NOT intersect " + boundingBox, bbox.intersects(boundingBox)); diff --git a/src/test/java/ch/hsr/geohash/util/DoubleUtilTest.java b/src/test/java/ch/hsr/geohash/util/DoubleUtilTest.java new file mode 100644 index 00000000..e967c884 --- /dev/null +++ b/src/test/java/ch/hsr/geohash/util/DoubleUtilTest.java @@ -0,0 +1,20 @@ +package ch.hsr.geohash.util; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class DoubleUtilTest { + + @Test + public void testPositiveValue() { + assertEquals(58.1541,DoubleUtil.remainderWithFix(58.1541, 360), 0.00001); + assertEquals(93.1541,DoubleUtil.remainderWithFix(453.1541, 360), 0.00001); + } + + @Test + public void testNegativeValue() { + assertEquals(301.8459,DoubleUtil.remainderWithFix(-58.1541, 360), 0.00001); + assertEquals(266.8459,DoubleUtil.remainderWithFix(-453.1541, 360), 0.00001); + } +} From 13a06a19c8cb899b5d0908b28b36b6812d1084d6 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Tue, 26 May 2020 12:01:46 +0200 Subject: [PATCH 35/42] Make max length constants public --- src/main/java/ch/hsr/geohash/GeoHash.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index b1f6938a..99eacdd3 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -14,8 +14,8 @@ @SuppressWarnings("javadoc") public final class GeoHash implements Comparable, Serializable { - private static final int MAX_BIT_PRECISION = 64; - private static final int MAX_CHARACTER_PRECISION = 12; + public static final int MAX_BIT_PRECISION = 64; + public static final int MAX_CHARACTER_PRECISION = 12; private static final long serialVersionUID = -8553214249630252175L; private static final int[] BITS = { 16, 8, 4, 2, 1 }; From a6291bde52f954cbdff0bf397f05a2f8262f62e6 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Tue, 26 May 2020 16:00:44 +0200 Subject: [PATCH 36/42] Throw an IllegalArgumentException if using illegal characters in geohash --- src/main/java/ch/hsr/geohash/GeoHash.java | 20 +++++++++++-------- src/test/java/ch/hsr/geohash/GeoHashTest.java | 5 +++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index b1f6938a..219b25e4 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -100,15 +100,19 @@ public static GeoHash fromGeohashString(String geohash) { GeoHash hash = new GeoHash(); for (int i = 0; i < geohash.length(); i++) { - int cd = decodeMap.get(geohash.charAt(i)); - for (int j = 0; j < BASE32_BITS; j++) { - int mask = BITS[j]; - if (isEvenBit) { - divideRangeDecode(hash, longitudeRange, (cd & mask) != 0); - } else { - divideRangeDecode(hash, latitudeRange, (cd & mask) != 0); + if(decodeMap.containsKey(geohash.charAt(i))) { + int cd = decodeMap.get(geohash.charAt(i)); + for (int j = 0; j < BASE32_BITS; j++) { + int mask = BITS[j]; + if (isEvenBit) { + divideRangeDecode(hash, longitudeRange, (cd & mask) != 0); + } else { + divideRangeDecode(hash, latitudeRange, (cd & mask) != 0); + } + isEvenBit = !isEvenBit; } - isEvenBit = !isEvenBit; + } else { + throw new IllegalArgumentException("Invalid character character '" + geohash.charAt(i) + "' in geohash '"+geohash+"'!"); } } diff --git a/src/test/java/ch/hsr/geohash/GeoHashTest.java b/src/test/java/ch/hsr/geohash/GeoHashTest.java index 1ff4c3d3..3610fd3f 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashTest.java @@ -456,6 +456,11 @@ public void testGetCharacterPrecisionThrows() throws Exception { hash.getCharacterPrecision(); } + @Test(expected = IllegalArgumentException.class) + public void itShouldThrowANiceExceptionOnIllegalCharacters() { + GeoHash.fromGeohashString("abba"); + } + @Test public void testGetCharacterPrecisionWorksWhenPrecisionIsMultipleOfFive() throws Exception { GeoHash hash = GeoHash.withBitPrecision(37.7, -122.52, 60); From 6544c2f582eb676e9f312337f12611c67add9ffa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 09:49:22 +0000 Subject: [PATCH 37/42] Bump junit from 4.12 to 4.13.1 Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c6910c2b..3f1eded1 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ junit junit - 4.12 + 4.13.1 test From 3ed60d6321bd8c13fbb5df472ab48ccca014c1db Mon Sep 17 00:00:00 2001 From: Vincent PERICART Date: Mon, 28 Dec 2020 15:36:19 +0900 Subject: [PATCH 38/42] use array for decoding --- src/main/java/ch/hsr/geohash/GeoHash.java | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index 93a57a69..35fe6348 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -9,8 +9,7 @@ package ch.hsr.geohash; import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; +import java.util.Arrays; @SuppressWarnings("javadoc") public final class GeoHash implements Comparable, Serializable { @@ -24,12 +23,13 @@ public final class GeoHash implements Comparable, Serializable { private static final char[] base32 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; - private final static Map decodeMap = new HashMap<>(); + private static final int[] decodeArray = new int['z' + 1]; static { + Arrays.fill(decodeArray, -1); int sz = base32.length; for (int i = 0; i < sz; i++) { - decodeMap.put(base32[i], i); + decodeArray[base32[i]] = i; } } @@ -100,19 +100,19 @@ public static GeoHash fromGeohashString(String geohash) { GeoHash hash = new GeoHash(); for (int i = 0; i < geohash.length(); i++) { - if(decodeMap.containsKey(geohash.charAt(i))) { - int cd = decodeMap.get(geohash.charAt(i)); - for (int j = 0; j < BASE32_BITS; j++) { - int mask = BITS[j]; - if (isEvenBit) { - divideRangeDecode(hash, longitudeRange, (cd & mask) != 0); - } else { - divideRangeDecode(hash, latitudeRange, (cd & mask) != 0); - } - isEvenBit = !isEvenBit; + char c = geohash.charAt(i); + int cd; + if (c >= decodeArray.length || (cd = decodeArray[c]) < 0) { + throw new IllegalArgumentException("Invalid character character '" + c + "' in geohash '"+geohash+"'!"); + } + for (int j = 0; j < BASE32_BITS; j++) { + int mask = BITS[j]; + if (isEvenBit) { + divideRangeDecode(hash, longitudeRange, (cd & mask) != 0); + } else { + divideRangeDecode(hash, latitudeRange, (cd & mask) != 0); } - } else { - throw new IllegalArgumentException("Invalid character character '" + geohash.charAt(i) + "' in geohash '"+geohash+"'!"); + isEvenBit = !isEvenBit; } } From 707503f24a457b83fcde097683831e2cde3b0af2 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Fri, 12 Nov 2021 10:49:42 +0100 Subject: [PATCH 39/42] Update README and pom for release of 1.5.0 --- README.md | 6 ++++++ pom.xml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 15f7ef5a..d8f0ac6d 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,12 @@ Current development involves getting the following things to run: Last important changes ---------------------- +Version 1.5.0 +----------------------- + +This version adds support to expand `BoundingBox` to include another `Wgs84Point`. +It also merges a bunch of fixes in bounding box iterators. + Version 1.4.0 ----------------------- diff --git a/pom.xml b/pom.xml index 3f1eded1..8e73ac12 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ jar ch.hsr geohash - 1.4.0 + 1.5.0 geohash-java An implementation of Geohashes in pure Java. @@ -20,7 +20,7 @@ scm:git:git@github.com:kungfoo/geohash-java.git scm:git:git@github.com:kungfoo/geohash-java.git git@github.com:kungfoo/geohash-java.git - 1.4.0 + 1.5.0
From 7ed853642e2fbd2199b08ffe8f482638e385fc26 Mon Sep 17 00:00:00 2001 From: Silvio Heuberger Date: Fri, 12 Nov 2021 11:06:28 +0100 Subject: [PATCH 40/42] Move to new staging/release repositories --- pom.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8e73ac12..5f39ffcf 100644 --- a/pom.xml +++ b/pom.xml @@ -45,8 +45,12 @@ ossrh - https://oss.sonatype.org/content/repositories/snapshots + https://s01.oss.sonatype.org/content/repositories/snapshots + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + @@ -57,7 +61,7 @@ true ossrh - https://oss.sonatype.org/ + https://s01.oss.sonatype.org/ true From 2b45dc9eae6bb86521c55c9c70526a82bcf59420 Mon Sep 17 00:00:00 2001 From: satorg Date: Sat, 19 Feb 2022 17:44:29 -0800 Subject: [PATCH 41/42] add validation for negative values in GeoHash.withBitPrecision for numberOfBits --- src/main/java/ch/hsr/geohash/GeoHash.java | 3 +++ src/test/java/ch/hsr/geohash/GeoHashTest.java | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/ch/hsr/geohash/GeoHash.java b/src/main/java/ch/hsr/geohash/GeoHash.java index 35fe6348..fc48fb76 100644 --- a/src/main/java/ch/hsr/geohash/GeoHash.java +++ b/src/main/java/ch/hsr/geohash/GeoHash.java @@ -61,6 +61,9 @@ public static GeoHash withCharacterPrecision(double latitude, double longitude, * at the same time defines this hash's bounding box. */ public static GeoHash withBitPrecision(double latitude, double longitude, int numberOfBits) { + if (numberOfBits < 0) { + throw new IllegalArgumentException("A Geohash can't be of negative bits long!"); + } if (numberOfBits > MAX_BIT_PRECISION) { throw new IllegalArgumentException("A Geohash can only be " + MAX_BIT_PRECISION + " bits long!"); } diff --git a/src/test/java/ch/hsr/geohash/GeoHashTest.java b/src/test/java/ch/hsr/geohash/GeoHashTest.java index 3610fd3f..f3ff45cd 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashTest.java @@ -116,11 +116,21 @@ private void assertWithin(GeoHash hash, GeoHash bbox) { assertTrue(hash + " should be within " + bbox, hash.within(bbox)); } + @Test + public void itShouldCreateAHashWithMinimumPrecisionOf0Bits() { + GeoHash.withBitPrecision(10.0, 10.0, 0); + } + @Test public void itShouldCreateAHashWithMaximumPrecisionOf64Bits() { GeoHash.withBitPrecision(10.0, 10.0, 64); } + @Test(expected = IllegalArgumentException.class) + public void itShouldThrowWhenTheBitPrecisionIsLessThan0Bits() { + GeoHash.withBitPrecision(46.0, 8.0, -1); + } + @Test(expected = IllegalArgumentException.class) public void itShouldThrowWhenTheBitPrecisionIsMoreThan64Bits() { GeoHash.withBitPrecision(46.0, 8.0, 70); From 2cb753df20f4eb51f95840db27ff856562370f45 Mon Sep 17 00:00:00 2001 From: satorg Date: Mon, 21 Feb 2022 18:20:55 -0800 Subject: [PATCH 42/42] make tests for `withBitPrecision` more meaningful --- src/test/java/ch/hsr/geohash/GeoHashTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/ch/hsr/geohash/GeoHashTest.java b/src/test/java/ch/hsr/geohash/GeoHashTest.java index f3ff45cd..baf29119 100644 --- a/src/test/java/ch/hsr/geohash/GeoHashTest.java +++ b/src/test/java/ch/hsr/geohash/GeoHashTest.java @@ -118,12 +118,18 @@ private void assertWithin(GeoHash hash, GeoHash bbox) { @Test public void itShouldCreateAHashWithMinimumPrecisionOf0Bits() { - GeoHash.withBitPrecision(10.0, 10.0, 0); + GeoHash geoHash = GeoHash.withBitPrecision(10.0, 10.0, 0); + assertEquals(0, geoHash.significantBits()); + assertEquals(0, geoHash.longValue()); + assertEquals(new WGS84Point(10.0, 10.0), geoHash.getOriginatingPoint()); } @Test public void itShouldCreateAHashWithMaximumPrecisionOf64Bits() { - GeoHash.withBitPrecision(10.0, 10.0, 64); + GeoHash geoHash = GeoHash.withBitPrecision(10.0, 10.0, 64); + assertEquals(64, geoHash.significantBits()); + assertEquals(0xc07e07e07e07e07eL, geoHash.longValue()); + assertEquals(new WGS84Point(10.0, 10.0), geoHash.getOriginatingPoint()); } @Test(expected = IllegalArgumentException.class)