From 7578fd46e594188666120dbe20a94fd59bb2ea7f Mon Sep 17 00:00:00 2001 From: nesterfifa Date: Tue, 28 Nov 2023 12:33:42 +0100 Subject: [PATCH] [#782] pkg: use quadtree to find continent Signed-off-by: nesterfifa --- pkg/services/control/ir/service.pb.go | 5 +- pkg/services/control/ir/service_grpc.pb.go | 1 + pkg/services/control/ir/types.pb.go | 5 +- pkg/services/control/service.pb.go | 5 +- pkg/services/control/service_grpc.pb.go | 1 + pkg/services/control/types.pb.go | 5 +- pkg/services/tree/service.pb.go | 5 +- pkg/services/tree/service_grpc.pb.go | 1 + pkg/services/tree/types.pb.go | 5 +- .../locode/db/continents/geojson/calls.go | 64 +++++++++++++++---- pkg/util/locode/db/continents/geojson/db.go | 3 + 11 files changed, 74 insertions(+), 26 deletions(-) diff --git a/pkg/services/control/ir/service.pb.go b/pkg/services/control/ir/service.pb.go index bec74a3be..a138bbd84 100644 --- a/pkg/services/control/ir/service.pb.go +++ b/pkg/services/control/ir/service.pb.go @@ -7,10 +7,11 @@ package control import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/pkg/services/control/ir/service_grpc.pb.go b/pkg/services/control/ir/service_grpc.pb.go index 6ba214da0..74a6c9f17 100644 --- a/pkg/services/control/ir/service_grpc.pb.go +++ b/pkg/services/control/ir/service_grpc.pb.go @@ -8,6 +8,7 @@ package control import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" diff --git a/pkg/services/control/ir/types.pb.go b/pkg/services/control/ir/types.pb.go index 8107b917e..cf7b946b0 100644 --- a/pkg/services/control/ir/types.pb.go +++ b/pkg/services/control/ir/types.pb.go @@ -7,10 +7,11 @@ package control import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/pkg/services/control/service.pb.go b/pkg/services/control/service.pb.go index b1bebb1e2..3126379e4 100644 --- a/pkg/services/control/service.pb.go +++ b/pkg/services/control/service.pb.go @@ -7,10 +7,11 @@ package control import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/pkg/services/control/service_grpc.pb.go b/pkg/services/control/service_grpc.pb.go index 8afc6086a..781471769 100644 --- a/pkg/services/control/service_grpc.pb.go +++ b/pkg/services/control/service_grpc.pb.go @@ -8,6 +8,7 @@ package control import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" diff --git a/pkg/services/control/types.pb.go b/pkg/services/control/types.pb.go index d2ee50770..31940c8f3 100644 --- a/pkg/services/control/types.pb.go +++ b/pkg/services/control/types.pb.go @@ -7,10 +7,11 @@ package control import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/pkg/services/tree/service.pb.go b/pkg/services/tree/service.pb.go index 63f3e714a..74adec45a 100644 --- a/pkg/services/tree/service.pb.go +++ b/pkg/services/tree/service.pb.go @@ -10,10 +10,11 @@ package tree import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/pkg/services/tree/service_grpc.pb.go b/pkg/services/tree/service_grpc.pb.go index 2c0828951..f05ab11ed 100644 --- a/pkg/services/tree/service_grpc.pb.go +++ b/pkg/services/tree/service_grpc.pb.go @@ -11,6 +11,7 @@ package tree import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" diff --git a/pkg/services/tree/types.pb.go b/pkg/services/tree/types.pb.go index b4d6981ef..873780ec6 100644 --- a/pkg/services/tree/types.pb.go +++ b/pkg/services/tree/types.pb.go @@ -10,10 +10,11 @@ package tree import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/pkg/util/locode/db/continents/geojson/calls.go b/pkg/util/locode/db/continents/geojson/calls.go index 34467d5a2..5cd0820a7 100644 --- a/pkg/util/locode/db/continents/geojson/calls.go +++ b/pkg/util/locode/db/continents/geojson/calls.go @@ -4,6 +4,8 @@ import ( "fmt" "os" + "github.com/paulmach/orb/quadtree" + locodedb "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/locode/db" "github.com/paulmach/orb" "github.com/paulmach/orb/geojson" @@ -36,22 +38,24 @@ func (db *DB) PointContinent(point *locodedb.Point) (*locodedb.Continent, error) minDst float64 ) - for _, feature := range db.features { - if multiPolygon, ok := feature.Geometry.(orb.MultiPolygon); ok { - if planar.MultiPolygonContains(multiPolygon, planarPoint) { + pointer := db.tree.Matching(planarPoint, func(p orb.Pointer) bool { + return planar.PolygonContains( + p.(*geojson.Feature).Geometry.(orb.Polygon), + planarPoint, + ) + }) + + if pointer != nil { + continent = pointer.(*geojson.Feature).Properties.MustString(continentProperty) + } + + if continent == "" { + for _, feature := range db.features { + distance := planar.DistanceFrom(feature.Geometry, planarPoint) + if minDst == 0 || minDst > distance { + minDst = distance continent = feature.Properties.MustString(continentProperty) - break } - } else if polygon, ok := feature.Geometry.(orb.Polygon); ok { - if planar.PolygonContains(polygon, planarPoint) { - continent = feature.Properties.MustString(continentProperty) - break - } - } - distance := planar.DistanceFrom(feature.Geometry, planarPoint) - if minDst == 0 || minDst > distance { - minDst = distance - continent = feature.Properties.MustString(continentProperty) } } @@ -73,6 +77,38 @@ func (db *DB) init() error { db.features = features.Features + err = db.buildQuadtree() + if err != nil { + return fmt.Errorf("could not build quadtree: %w", err) + } + + return nil +} + +func (db *DB) buildQuadtree() error { + db.tree = quadtree.New(orb.Bound{ + Min: orb.Point{-180, -180}, + Max: orb.Point{180, 180}, + }) + + for _, feature := range db.features { + if multiPolygon, ok := feature.Geometry.(orb.MultiPolygon); ok { + for _, polygon := range multiPolygon { + newFeature := geojson.NewFeature(polygon) + newFeature.Properties = feature.Properties.Clone() + err := db.tree.Add(newFeature) + if err != nil { + return err + } + } + } else if _, ok := feature.Geometry.(orb.Polygon); ok { + err := db.tree.Add(feature) + if err != nil { + return err + } + } + } + return nil } diff --git a/pkg/util/locode/db/continents/geojson/db.go b/pkg/util/locode/db/continents/geojson/db.go index ee43bd810..244da024f 100644 --- a/pkg/util/locode/db/continents/geojson/db.go +++ b/pkg/util/locode/db/continents/geojson/db.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/paulmach/orb/geojson" + "github.com/paulmach/orb/quadtree" ) // Prm groups the required parameters of the DB's constructor. @@ -31,6 +32,8 @@ type DB struct { once sync.Once features []*geojson.Feature + + tree *quadtree.Quadtree } const invalidPrmValFmt = "invalid parameter %s (%T):%v"