120 lines
3.1 KiB
Go
120 lines
3.1 KiB
Go
package admin
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/blevesearch/geo/s2"
|
|
"github.com/paulmach/orb"
|
|
"github.com/paulmach/orb/geojson"
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
type AdminMemoryS2Index struct {
|
|
Layers []string
|
|
Indexes map[string]*s2.ShapeIndex
|
|
Documents map[string]map[string]*geojson.Feature
|
|
}
|
|
|
|
func NewAdminMemoryS2Index(cfg *viper.Viper) (*AdminMemoryS2Index, error) {
|
|
storage := &AdminMemoryS2Index{
|
|
Indexes: map[string]*s2.ShapeIndex{},
|
|
Documents: map[string]map[string]*geojson.Feature{},
|
|
}
|
|
|
|
layers := cfg.GetStringMapString("data.layers")
|
|
for layer, url := range layers {
|
|
storage.IndexLayer(layer, url)
|
|
}
|
|
|
|
return storage, nil
|
|
}
|
|
|
|
func (s *AdminMemoryS2Index) IndexLayer(layer, url string) error {
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("get request failed")
|
|
return err
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("cound not read response")
|
|
return err
|
|
}
|
|
|
|
data, err := geojson.UnmarshalFeatureCollection(body)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("could not read input data")
|
|
return err
|
|
}
|
|
s.Indexes[layer] = s2.NewShapeIndex()
|
|
s.Documents[layer] = map[string]*geojson.Feature{}
|
|
s.Layers = append(s.Layers, layer)
|
|
for _, feature := range data.Features {
|
|
if feature.Geometry.GeoJSONType() == "Polygon" {
|
|
poly, ok := feature.Geometry.(orb.Polygon)
|
|
if !ok {
|
|
log.Error().Str("name", feature.Properties.MustString("nom")).Msg("could not index layer")
|
|
break
|
|
}
|
|
s2Poly, err := orbToS2Polygon(&poly)
|
|
if err != nil {
|
|
log.Error().Err(err).Str("featurename", feature.Properties.MustString("nom")).Msg("could not convert polygon to S2")
|
|
break
|
|
}
|
|
|
|
s.Indexes[layer].Add(s2Poly)
|
|
|
|
s.Documents[layer][feature.Properties.MustString("code")] = feature
|
|
}
|
|
}
|
|
s.Indexes[layer].Build()
|
|
return nil
|
|
}
|
|
|
|
func (s *AdminMemoryS2Index) GeoSearch(feature *geojson.Feature) (map[string][]*geojson.Feature, error) {
|
|
// results := map[string][]*geojson.Feature
|
|
// point := feature.Point()
|
|
// for _, layer := s.Layers {
|
|
// query := s2.ContainsPointQuery{s.Indexes[layer], s2.VertexModelClosed}
|
|
// p := s2.PointFromLatLng(s2.LatLngFromDegrees(point.Lat(), point.Lon()))
|
|
// shapes := query.ContainingShapes(p)
|
|
// features := slices.Collect(func(yield func(*geojson.Feature)){
|
|
// for _, sh := range shapes {
|
|
// sh.
|
|
// if !yield()
|
|
// }
|
|
// })
|
|
// }
|
|
return nil, errors.New("unimplemented")
|
|
}
|
|
|
|
func orbToS2Polygon(poly *orb.Polygon) (*s2.Polygon, error) {
|
|
loops := []*s2.Loop{}
|
|
if poly == nil {
|
|
return nil, errors.New("polygon is nil")
|
|
}
|
|
for _, ring := range *poly {
|
|
points := []s2.Point{}
|
|
for _, point := range ring {
|
|
points = append(points, s2.PointFromLatLng(s2.LatLngFromDegrees(point.Lat(), point.Lon())))
|
|
}
|
|
loop := s2.LoopFromPoints(points)
|
|
loops = append(loops, loop)
|
|
}
|
|
polygon := s2.PolygonFromLoops(loops)
|
|
|
|
return polygon, nil
|
|
}
|
|
|
|
func (s *AdminMemoryS2Index) Find(layer, id string) (*geojson.Feature, error) {
|
|
result, ok := s.Documents["layer"][id]
|
|
if !ok || result == nil {
|
|
return nil, errors.New("admin not found")
|
|
}
|
|
return result, nil
|
|
}
|