summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorArne Juul <arnej@verizonmedia.com>2020-07-13 12:30:24 +0000
committerArne Juul <arnej@verizonmedia.com>2020-07-15 15:39:23 +0000
commit909c3b8f302cbe615d38139d202e809c9f6079a4 (patch)
treef53d49c4a7a0a26f7ae250d9f47e8d3da5c584b1 /searchlib
parentc1fb9ece30ea0bc233cf1b8a3ddd310dc269e111 (diff)
immutable GeoLocation struct
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/vespa/searchlib/common/CMakeLists.txt1
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location.cpp174
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location.h89
3 files changed, 264 insertions, 0 deletions
diff --git a/searchlib/src/vespa/searchlib/common/CMakeLists.txt b/searchlib/src/vespa/searchlib/common/CMakeLists.txt
index fd99f31aec8..f3b891bb55a 100644
--- a/searchlib/src/vespa/searchlib/common/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/common/CMakeLists.txt
@@ -12,6 +12,7 @@ vespa_add_library(searchlib_common OBJECT
featureset.cpp
fileheadercontext.cpp
gatecallback.cpp
+ geo_location.cpp
geo_location_spec.cpp
growablebitvector.cpp
indexmetainfo.cpp
diff --git a/searchlib/src/vespa/searchlib/common/geo_location.cpp b/searchlib/src/vespa/searchlib/common/geo_location.cpp
new file mode 100644
index 00000000000..7f7aff55779
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/common/geo_location.cpp
@@ -0,0 +1,174 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "geo_location.h"
+
+using vespalib::geo::ZCurve;
+
+namespace search::common {
+
+namespace {
+
+ZCurve::BoundingBox to_z(GeoLocation::Box box) {
+ return ZCurve::BoundingBox(box.x.lo, box.x.hi,
+ box.y.lo, box.y.hi);
+}
+
+GeoLocation::Box
+adjust_bounding_box(GeoLocation::Box orig, GeoLocation::Point point, uint32_t radius, GeoLocation::Aspect x_aspect)
+{
+ uint32_t maxdx = radius;
+ if (x_aspect.active()) {
+ uint64_t maxdx2 = ((static_cast<uint64_t>(radius) << 32) + 0xffffffffu) / x_aspect.multiplier;
+ if (maxdx2 >= 0xffffffffu)
+ maxdx = 0xffffffffu;
+ else
+ maxdx = static_cast<uint32_t>(maxdx2);
+ }
+ int64_t implied_max_x = int64_t(point.x) + int64_t(maxdx);
+ int64_t implied_min_x = int64_t(point.x) - int64_t(maxdx);
+
+ int64_t implied_max_y = int64_t(point.y) + int64_t(radius);
+ int64_t implied_min_y = int64_t(point.y) - int64_t(radius);
+
+ int32_t max_x = orig.x.hi;
+ int32_t min_x = orig.x.lo;
+
+ int32_t max_y = orig.y.hi;
+ int32_t min_y = orig.y.lo;
+
+ if (implied_max_x < max_x) max_x = implied_max_x;
+ if (implied_min_x > min_x) min_x = implied_min_x;
+
+ if (implied_max_y < max_y) max_y = implied_max_y;
+ if (implied_min_y > min_y) min_y = implied_min_y;
+
+ return GeoLocation::Box{GeoLocation::Range{min_x, max_x},
+ GeoLocation::Range{min_y, max_y}};
+}
+
+} // namespace <unnamed>
+
+GeoLocation::GeoLocation()
+ : has_point(false),
+ point{0, 0},
+ radius(radius_inf),
+ x_aspect(),
+ bounding_box(no_box),
+ _sq_radius(sq_radius_inf),
+ _zBoundingBox(0,0,0,0)
+{}
+
+GeoLocation::GeoLocation(Point p)
+ : has_point(true),
+ point(p),
+ radius(radius_inf),
+ x_aspect(),
+ bounding_box(no_box),
+ _sq_radius(sq_radius_inf),
+ _zBoundingBox(0,0,0,0)
+{}
+
+GeoLocation::GeoLocation(Point p, Aspect xa)
+ : has_point(true),
+ point(p),
+ radius(radius_inf),
+ x_aspect(xa),
+ bounding_box(no_box),
+ _sq_radius(sq_radius_inf),
+ _zBoundingBox(0,0,0,0)
+{}
+
+GeoLocation::GeoLocation(Point p, uint32_t r)
+ : has_point(true),
+ point(p),
+ radius(r),
+ x_aspect(),
+ bounding_box(adjust_bounding_box(no_box, p, r, Aspect())),
+ _sq_radius(uint64_t(r) * uint64_t(r)),
+ _zBoundingBox(to_z(bounding_box))
+{}
+
+GeoLocation::GeoLocation(Point p, uint32_t r, Aspect xa)
+ : has_point(true),
+ point(p),
+ radius(r),
+ x_aspect(),
+ bounding_box(adjust_bounding_box(no_box, p, r, xa)),
+ _sq_radius(uint64_t(r) * uint64_t(r)),
+ _zBoundingBox(to_z(bounding_box))
+{}
+
+GeoLocation::GeoLocation(Box b)
+ : has_point(false),
+ point{0, 0},
+ radius(radius_inf),
+ x_aspect(),
+ bounding_box(b),
+ _sq_radius(sq_radius_inf),
+ _zBoundingBox(to_z(bounding_box))
+{}
+
+GeoLocation::GeoLocation(Box b, Point p)
+ : has_point(true),
+ point(p),
+ radius(radius_inf),
+ x_aspect(),
+ bounding_box(b),
+ _sq_radius(sq_radius_inf),
+ _zBoundingBox(to_z(bounding_box))
+{}
+
+GeoLocation::GeoLocation(Box b, Point p, Aspect xa)
+ : has_point(true),
+ point(p),
+ radius(radius_inf),
+ x_aspect(xa),
+ bounding_box(b),
+ _sq_radius(sq_radius_inf),
+ _zBoundingBox(to_z(bounding_box))
+{}
+
+GeoLocation::GeoLocation(Box b, Point p, uint32_t r)
+ : has_point(true),
+ point(p),
+ radius(r),
+ x_aspect(),
+ bounding_box(adjust_bounding_box(b, p, r, Aspect())),
+ _sq_radius(uint64_t(r) * uint64_t(r)),
+ _zBoundingBox(to_z(bounding_box))
+{}
+
+GeoLocation::GeoLocation(Box b, Point p, uint32_t r, Aspect xa)
+ : has_point(true),
+ point(p),
+ radius(r),
+ x_aspect(xa),
+ bounding_box(adjust_bounding_box(b, p, r, xa)),
+ _sq_radius(uint64_t(r) * uint64_t(r)),
+ _zBoundingBox(to_z(bounding_box))
+{}
+
+uint64_t GeoLocation::sq_distance_to(Point p) const {
+ if (has_point) {
+ uint64_t dx = (p.x > point.x) ? (p.x - point.x) : (point.x - p.x);
+ if (x_aspect.active()) {
+ dx = (dx * x_aspect.multiplier) >> 32;
+ }
+ uint64_t dy = (p.y > point.y) ? (p.y - point.y) : (point.y - p.y);
+ return dx*dx + dy*dy;
+ }
+ return 0;
+}
+
+bool GeoLocation::inside_limit(Point p) const {
+ if (p.x < bounding_box.x.lo) return false;
+ if (p.x > bounding_box.x.hi) return false;
+
+ if (p.y < bounding_box.y.lo) return false;
+ if (p.y > bounding_box.y.hi) return false;
+
+ uint64_t sq_dist = sq_distance_to(p);
+ return sq_dist <= _sq_radius;
+}
+
+} // namespace search::common
diff --git a/searchlib/src/vespa/searchlib/common/geo_location.h b/searchlib/src/vespa/searchlib/common/geo_location.h
new file mode 100644
index 00000000000..874b6d3470c
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/common/geo_location.h
@@ -0,0 +1,89 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <string>
+#include <cstdint>
+#include <limits>
+#include <vespa/vespalib/geo/zcurve.h>
+
+namespace search::common {
+
+/**
+ * An immutable struct for a (geo) location.
+ * Contains a point with optional radius, a bounding box, or both.
+ **/
+struct GeoLocation
+{
+ // contained structs and helper constants:
+ static constexpr int32_t range_lo = std::numeric_limits<int32_t>::min();
+ static constexpr int32_t range_hi = std::numeric_limits<int32_t>::max();
+ static constexpr uint32_t radius_inf = std::numeric_limits<uint32_t>::max();
+ struct Point {
+ const int32_t x;
+ const int32_t y;
+ Point() = delete;
+ };
+ struct Aspect {
+ uint32_t multiplier;
+ Aspect() : multiplier(0) {}
+ bool active() const { return multiplier != 0; }
+ };
+ struct Range {
+ const int32_t lo;
+ const int32_t hi;
+ bool active() const {
+ return (lo != range_lo) || (hi != range_hi);
+ }
+ };
+ static constexpr Range no_range = {range_lo, range_hi};
+ struct Box {
+ const Range x;
+ const Range y;
+ bool active() const { return x.active() || y.active(); }
+ };
+ static constexpr Box no_box = {no_range, no_range};
+
+ // actual content of struct:
+ const bool has_point;
+ Point point;
+ uint32_t radius;
+ Aspect x_aspect;
+ Box bounding_box;
+ GeoLocation();
+
+ // constructors:
+ GeoLocation(Point p);
+ GeoLocation(Point p, Aspect xa);
+ GeoLocation(Point p, uint32_t r);
+ GeoLocation(Point p, uint32_t r, Aspect xa);
+ GeoLocation(Box b);
+ GeoLocation(Box b, Point p);
+ GeoLocation(Box b, Point p, Aspect xa);
+ GeoLocation(Box b, Point p, uint32_t r);
+ GeoLocation(Box b, Point p, uint32_t r, Aspect xa);
+
+ // helper methods:
+ bool has_radius() const { return radius != radius_inf; }
+ bool valid() const { return has_point || bounding_box.active(); }
+ bool can_limit() const { return bounding_box.active(); }
+
+ uint64_t sq_distance_to(Point p) const;
+ bool inside_limit(Point p) const;
+
+ bool inside_limit(int64_t zcurve_encoded_xy) const {
+ if (_zBoundingBox.getzFailBoundingBoxTest(zcurve_encoded_xy)) return false;
+ int32_t x = 0;
+ int32_t y = 0;
+ vespalib::geo::ZCurve::decode(zcurve_encoded_xy, &x, &y);
+ return inside_limit(Point{x, y});
+ }
+
+private:
+ // constants for implementation of helper methods:
+ static constexpr uint64_t sq_radius_inf = std::numeric_limits<uint64_t>::max();
+ const uint64_t _sq_radius;
+ const vespalib::geo::ZCurve::BoundingBox _zBoundingBox;
+};
+
+} // namespace