locode: Use quadtree to find continent #830

Closed
Nesterfifa wants to merge 6 commits from Nesterfifa/frostfs-node:782-use-quadtree into master
11 changed files with 53 additions and 14 deletions
Showing only changes of commit 7578fd46e5 - Show all commits

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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 {
fyrchik marked this conversation as resolved
Review

What about var multiPolygon orb.MultiPolygon? make(_, 0) is usually never needed: nil acts good enough as the default value.

What about `var multiPolygon orb.MultiPolygon`? `make(_, 0)` is usually never needed: `nil` acts good enough as the default value.
Review

Fixed

Fixed
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
}

View file

@ -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"