Integrate BACKBEAT SDK and resolve KACHING license validation
Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
332
vendor/github.com/blevesearch/geo/geojson/geojson_s2_util.go
generated
vendored
Normal file
332
vendor/github.com/blevesearch/geo/geojson/geojson_s2_util.go
generated
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
// Copyright (c) 2022 Couchbase, Inc.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
|
||||
package geojson
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
index "github.com/blevesearch/bleve_index_api"
|
||||
"github.com/blevesearch/geo/s1"
|
||||
"github.com/blevesearch/geo/s2"
|
||||
)
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// project the point to all of the linestrings and check if
|
||||
// any of the projections are equal to the point.
|
||||
func polylineIntersectsPoint(pls []*s2.Polyline,
|
||||
point *s2.Point) bool {
|
||||
for _, pl := range pls {
|
||||
closest, _ := pl.Project(*point)
|
||||
if closest.ApproxEqual(*point) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// check if any of the polyline vertices lie inside or
|
||||
// on the boundary of any of the polygons. Then check if
|
||||
// any of the polylines intersect with any of the edges of
|
||||
// the polygons
|
||||
func polylineIntersectsPolygons(pls []*s2.Polyline,
|
||||
s2pgns []*s2.Polygon) bool {
|
||||
idx := s2.NewShapeIndex()
|
||||
for _, pgn := range s2pgns {
|
||||
idx.Add(pgn)
|
||||
}
|
||||
|
||||
containsQuery := s2.NewContainsPointQuery(idx, s2.VertexModelClosed)
|
||||
for _, pl := range pls {
|
||||
for _, point := range *pl {
|
||||
|
||||
// Precheck points within the bounds of the polygon
|
||||
// and for small polygons, check if the point is contained
|
||||
for _, s2pgn := range s2pgns {
|
||||
if !s2pgn.PointWithinBound(point) {
|
||||
continue
|
||||
}
|
||||
|
||||
if small, inside := s2pgn.SmallPolygonContainsPoint(point); small {
|
||||
if inside {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if containsQuery.Contains(point) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, pl := range pls {
|
||||
for _, s2pgn := range s2pgns {
|
||||
for i := 0; i < s2pgn.NumEdges(); i++ {
|
||||
edgeB := s2pgn.Edge(i)
|
||||
latLng1 := s2.LatLngFromPoint(edgeB.V0)
|
||||
latLng2 := s2.LatLngFromPoint(edgeB.V1)
|
||||
pl2 := s2.PolylineFromLatLngs([]s2.LatLng{latLng1, latLng2})
|
||||
|
||||
if pl.Intersects(pl2) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// check if the point is contained within the polygon.
|
||||
// polygon contains point will consider vertices to be outside
|
||||
// so we create a shape index and query it instead
|
||||
// s2.VertexModelClosed will not consider points on the edges, so
|
||||
// behaviour there is arbitrary
|
||||
func polygonsIntersectsPoint(s2pgns []*s2.Polygon,
|
||||
point *s2.Point) bool {
|
||||
idx := s2.NewShapeIndex()
|
||||
for _, pgn := range s2pgns {
|
||||
if !pgn.PointWithinBound(*point) {
|
||||
continue
|
||||
}
|
||||
|
||||
// We don't early exit here because the point may be contained
|
||||
// on the vertices of the polygon, which is not considered
|
||||
if small, inside := pgn.SmallPolygonContainsPoint(*point); small {
|
||||
if inside {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
idx.Add(pgn)
|
||||
}
|
||||
|
||||
if idx.Len() == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return s2.NewContainsPointQuery(idx, s2.VertexModelClosed).Contains(*point)
|
||||
}
|
||||
|
||||
func geometryCollectionIntersectsShape(gc *GeometryCollection,
|
||||
shapeIn index.GeoJSON) bool {
|
||||
for _, shape := range gc.Members() {
|
||||
intersects, err := shapeIn.Intersects(shape)
|
||||
if err == nil && intersects {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func polygonsContainsLineStrings(s2pgns []*s2.Polygon,
|
||||
pls []*s2.Polyline) bool {
|
||||
linesWithIn := make(map[int]struct{})
|
||||
checker := s2.NewCrossingEdgeQuery(s2.NewShapeIndex())
|
||||
nextLine:
|
||||
for lineIndex, pl := range pls {
|
||||
for i := 0; i < len(*pl)-1; i++ {
|
||||
start := (*pl)[i]
|
||||
end := (*pl)[i+1]
|
||||
|
||||
for _, s2pgn := range s2pgns {
|
||||
containsStart := s2pgn.ContainsPoint(start)
|
||||
containsEnd := s2pgn.ContainsPoint(end)
|
||||
if containsStart && containsEnd {
|
||||
crossings := checker.Crossings(start, end, s2pgn, s2.CrossingTypeInterior)
|
||||
if len(crossings) > 0 {
|
||||
continue nextLine
|
||||
}
|
||||
linesWithIn[lineIndex] = struct{}{}
|
||||
continue nextLine
|
||||
} else {
|
||||
for _, loop := range s2pgn.Loops() {
|
||||
for i := 0; i < loop.NumVertices(); i++ {
|
||||
if !containsStart && start.ApproxEqual(loop.Vertex(i)) {
|
||||
containsStart = true
|
||||
} else if !containsEnd && end.ApproxEqual(loop.Vertex(i)) {
|
||||
containsEnd = true
|
||||
}
|
||||
if containsStart && containsEnd {
|
||||
linesWithIn[lineIndex] = struct{}{}
|
||||
continue nextLine
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len(pls) == len(linesWithIn)
|
||||
}
|
||||
|
||||
func rectangleIntersectsWithPolygons(s2rect *s2.Rect,
|
||||
s2pgns []*s2.Polygon) bool {
|
||||
s2pgnFromRect := s2PolygonFromS2Rectangle(s2rect)
|
||||
for _, s2pgn := range s2pgns {
|
||||
if s2pgn.Intersects(s2pgnFromRect) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func rectangleIntersectsWithLineStrings(s2rect *s2.Rect,
|
||||
polylines []*s2.Polyline) bool {
|
||||
s2pgnFromRect := s2PolygonFromS2Rectangle(s2rect)
|
||||
return polylineIntersectsPolygons(polylines, []*s2.Polygon{s2pgnFromRect})
|
||||
}
|
||||
|
||||
func s2PolygonFromCoordinates(coordinates [][][]float64) *s2.Polygon {
|
||||
loops := make([]*s2.Loop, 0, len(coordinates))
|
||||
for _, loop := range coordinates {
|
||||
var points []s2.Point
|
||||
if loop[0][0] == loop[len(loop)-1][0] && loop[0][1] == loop[len(loop)-1][1] {
|
||||
loop = loop[:len(loop)-1]
|
||||
}
|
||||
for _, point := range loop {
|
||||
p := s2.PointFromLatLng(s2.LatLngFromDegrees(point[1], point[0]))
|
||||
points = append(points, p)
|
||||
}
|
||||
s2loop := s2.LoopFromPoints(points)
|
||||
loops = append(loops, s2loop)
|
||||
}
|
||||
|
||||
rv := s2.PolygonFromOrientedLoops(loops)
|
||||
return rv
|
||||
}
|
||||
|
||||
func s2PolygonFromS2Rectangle(s2rect *s2.Rect) *s2.Polygon {
|
||||
loops := make([]*s2.Loop, 0, 1)
|
||||
var points []s2.Point
|
||||
for j := 0; j < 4; j++ {
|
||||
points = append(points, s2.PointFromLatLng(s2rect.Vertex(j%4)))
|
||||
}
|
||||
|
||||
loops = append(loops, s2.LoopFromPoints(points))
|
||||
return s2.PolygonFromLoops(loops)
|
||||
}
|
||||
|
||||
func DeduplicateTerms(terms []string) []string {
|
||||
var rv []string
|
||||
hash := make(map[string]struct{}, len(terms))
|
||||
for _, term := range terms {
|
||||
if _, exists := hash[term]; !exists {
|
||||
rv = append(rv, term)
|
||||
hash[term] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
var earthRadiusInMeter = 6378137.0
|
||||
|
||||
func radiusInMetersToS1Angle(radius float64) s1.Angle {
|
||||
return s1.Angle(radius / earthRadiusInMeter)
|
||||
}
|
||||
|
||||
func s2PolylinesFromCoordinates(coordinates [][][]float64) []*s2.Polyline {
|
||||
var polylines []*s2.Polyline
|
||||
for _, lines := range coordinates {
|
||||
var latlngs []s2.LatLng
|
||||
for _, line := range lines {
|
||||
v := s2.LatLngFromDegrees(line[1], line[0])
|
||||
latlngs = append(latlngs, v)
|
||||
}
|
||||
polylines = append(polylines, s2.PolylineFromLatLngs(latlngs))
|
||||
}
|
||||
return polylines
|
||||
}
|
||||
|
||||
func s2RectFromBounds(topLeft, bottomRight []float64) *s2.Rect {
|
||||
rect := s2.EmptyRect()
|
||||
rect = rect.AddPoint(s2.LatLngFromDegrees(topLeft[1], topLeft[0]))
|
||||
rect = rect.AddPoint(s2.LatLngFromDegrees(bottomRight[1], bottomRight[0]))
|
||||
return &rect
|
||||
}
|
||||
|
||||
func s2Cap(vertices []float64, radiusInMeter float64) *s2.Cap {
|
||||
cp := s2.PointFromLatLng(s2.LatLngFromDegrees(vertices[1], vertices[0]))
|
||||
angle := radiusInMetersToS1Angle(float64(radiusInMeter))
|
||||
cap := s2.CapFromCenterAngle(cp, angle)
|
||||
return &cap
|
||||
}
|
||||
|
||||
func StripCoveringTerms(terms []string) []string {
|
||||
rv := make([]string, 0, len(terms))
|
||||
for _, term := range terms {
|
||||
if strings.HasPrefix(term, "$") {
|
||||
rv = append(rv, term[1:])
|
||||
continue
|
||||
}
|
||||
rv = append(rv, term)
|
||||
}
|
||||
return DeduplicateTerms(rv)
|
||||
}
|
||||
|
||||
type distanceUnit struct {
|
||||
conv float64
|
||||
suffixes []string
|
||||
}
|
||||
|
||||
var inch = distanceUnit{0.0254, []string{"in", "inch"}}
|
||||
var yard = distanceUnit{0.9144, []string{"yd", "yards"}}
|
||||
var feet = distanceUnit{0.3048, []string{"ft", "feet"}}
|
||||
var kilom = distanceUnit{1000, []string{"km", "kilometers"}}
|
||||
var nauticalm = distanceUnit{1852.0, []string{"nm", "nauticalmiles"}}
|
||||
var millim = distanceUnit{0.001, []string{"mm", "millimeters"}}
|
||||
var centim = distanceUnit{0.01, []string{"cm", "centimeters"}}
|
||||
var miles = distanceUnit{1609.344, []string{"mi", "miles"}}
|
||||
var meters = distanceUnit{1, []string{"m", "meters"}}
|
||||
|
||||
var distanceUnits = []*distanceUnit{
|
||||
&inch, &yard, &feet, &kilom, &nauticalm, &millim, ¢im, &miles, &meters,
|
||||
}
|
||||
|
||||
// ParseDistance attempts to parse a distance string and return distance in
|
||||
// meters. Example formats supported:
|
||||
// "5in" "5inch" "7yd" "7yards" "9ft" "9feet" "11km" "11kilometers"
|
||||
// "3nm" "3nauticalmiles" "13mm" "13millimeters" "15cm" "15centimeters"
|
||||
// "17mi" "17miles" "19m" "19meters"
|
||||
// If the unit cannot be determined, the entire string is parsed and the
|
||||
// unit of meters is assumed.
|
||||
// If the number portion cannot be parsed, 0 and the parse error are returned.
|
||||
func ParseDistance(d string) (float64, error) {
|
||||
for _, unit := range distanceUnits {
|
||||
for _, unitSuffix := range unit.suffixes {
|
||||
if strings.HasSuffix(d, unitSuffix) {
|
||||
parsedNum, err := strconv.ParseFloat(d[0:len(d)-len(unitSuffix)], 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return parsedNum * unit.conv, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// no unit matched, try assuming meters?
|
||||
parsedNum, err := strconv.ParseFloat(d, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return parsedNum, nil
|
||||
}
|
||||
1827
vendor/github.com/blevesearch/geo/geojson/geojson_shapes_impl.go
generated
vendored
Normal file
1827
vendor/github.com/blevesearch/geo/geojson/geojson_shapes_impl.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
616
vendor/github.com/blevesearch/geo/geojson/geojson_shapes_util.go
generated
vendored
Normal file
616
vendor/github.com/blevesearch/geo/geojson/geojson_shapes_util.go
generated
vendored
Normal file
@@ -0,0 +1,616 @@
|
||||
// Copyright (c) 2022 Couchbase, Inc.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
|
||||
package geojson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
index "github.com/blevesearch/bleve_index_api"
|
||||
"github.com/blevesearch/geo/s2"
|
||||
jsoniterator "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
var jsoniter = jsoniterator.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
type GeoShape struct {
|
||||
// Type of the shape
|
||||
Type string
|
||||
|
||||
// Coordinates of the shape
|
||||
// Used for all shapes except Circles
|
||||
Coordinates [][][][]float64
|
||||
|
||||
// Radius of the circle
|
||||
Radius string
|
||||
|
||||
// Center of the circle
|
||||
Center []float64
|
||||
}
|
||||
|
||||
// FilterGeoShapesOnRelation extracts the shapes in the document, apply
|
||||
// the `relation` filter and confirms whether the shape in the document
|
||||
// satisfies the given relation.
|
||||
func FilterGeoShapesOnRelation(shape index.GeoJSON, targetShapeBytes []byte,
|
||||
relation string, reader **bytes.Reader, bufPool *s2.GeoBufferPool) (bool, error) {
|
||||
|
||||
shapeInDoc, err := extractShapesFromBytes(targetShapeBytes, reader, bufPool)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return filterShapes(shape, shapeInDoc, relation)
|
||||
}
|
||||
|
||||
// extractShapesFromBytes unmarshal the bytes to retrieve the
|
||||
// embedded geojson shape.
|
||||
func extractShapesFromBytes(targetShapeBytes []byte, r **bytes.Reader, bufPool *s2.GeoBufferPool) (
|
||||
index.GeoJSON, error) {
|
||||
if (*r) == nil {
|
||||
*r = bytes.NewReader(targetShapeBytes[1:])
|
||||
} else {
|
||||
(*r).Reset(targetShapeBytes[1:])
|
||||
}
|
||||
|
||||
switch targetShapeBytes[0] {
|
||||
case PointTypePrefix:
|
||||
point := &Point{s2point: &s2.Point{}}
|
||||
err := point.s2point.Decode(*r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return point, nil
|
||||
|
||||
case MultiPointTypePrefix:
|
||||
var numPoints int32
|
||||
err := binary.Read(*r, binary.BigEndian, &numPoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
multipoint := &MultiPoint{
|
||||
s2points: make([]*s2.Point, 0, numPoints),
|
||||
}
|
||||
for i := 0; i < int(numPoints); i++ {
|
||||
s2point := s2.Point{}
|
||||
err := s2point.Decode((*r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
multipoint.s2points = append(multipoint.s2points, &s2point)
|
||||
}
|
||||
|
||||
return multipoint, nil
|
||||
|
||||
case LineStringTypePrefix:
|
||||
ls := &LineString{pl: &s2.Polyline{}}
|
||||
err := ls.pl.Decode(*r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ls, nil
|
||||
|
||||
case MultiLineStringTypePrefix:
|
||||
var numLineStrings int32
|
||||
err := binary.Read(*r, binary.BigEndian, &numLineStrings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mls := &MultiLineString{pls: make([]*s2.Polyline, 0, numLineStrings)}
|
||||
|
||||
for i := 0; i < int(numLineStrings); i++ {
|
||||
pl := &s2.Polyline{}
|
||||
err := pl.Decode(*r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mls.pls = append(mls.pls, pl)
|
||||
}
|
||||
|
||||
return mls, nil
|
||||
|
||||
case PolygonTypePrefix:
|
||||
pgn := &Polygon{s2pgn: &s2.Polygon{BufPool: bufPool}}
|
||||
err := pgn.s2pgn.Decode(*r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pgn, nil
|
||||
|
||||
case MultiPolygonTypePrefix:
|
||||
var numPolygons int32
|
||||
err := binary.Read(*r, binary.BigEndian, &numPolygons)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mpgns := &MultiPolygon{s2pgns: make([]*s2.Polygon, 0, numPolygons)}
|
||||
for i := 0; i < int(numPolygons); i++ {
|
||||
pgn := &s2.Polygon{}
|
||||
err := pgn.Decode(*r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mpgns.s2pgns = append(mpgns.s2pgns, pgn)
|
||||
}
|
||||
|
||||
return mpgns, nil
|
||||
|
||||
case GeometryCollectionTypePrefix:
|
||||
var numShapes int32
|
||||
err := binary.Read(*r, binary.BigEndian, &numShapes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lengths := make([]int32, numShapes)
|
||||
for i := int32(0); i < numShapes; i++ {
|
||||
var length int32
|
||||
err := binary.Read(*r, binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lengths[i] = length
|
||||
}
|
||||
|
||||
inputBytes := targetShapeBytes[len(targetShapeBytes)-(*r).Len():]
|
||||
gc := &GeometryCollection{Shapes: make([]index.GeoJSON, numShapes)}
|
||||
|
||||
for i := int32(0); i < numShapes; i++ {
|
||||
shape, err := extractShapesFromBytes(inputBytes[:lengths[i]], r, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gc.Shapes[i] = shape
|
||||
inputBytes = inputBytes[lengths[i]:]
|
||||
}
|
||||
|
||||
return gc, nil
|
||||
|
||||
case CircleTypePrefix:
|
||||
c := &Circle{s2cap: &s2.Cap{}}
|
||||
err := c.s2cap.Decode(*r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
||||
case EnvelopeTypePrefix:
|
||||
e := &Envelope{r: &s2.Rect{}}
|
||||
err := e.r.Decode(*r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown geo shape type: %v", targetShapeBytes[0])
|
||||
}
|
||||
|
||||
// filterShapes applies the given relation between the query shape
|
||||
// and the shape in the document.
|
||||
func filterShapes(shape index.GeoJSON,
|
||||
shapeInDoc index.GeoJSON, relation string) (bool, error) {
|
||||
|
||||
if relation == "intersects" {
|
||||
return shape.Intersects(shapeInDoc)
|
||||
}
|
||||
|
||||
if relation == "contains" {
|
||||
return shapeInDoc.Contains(shape)
|
||||
}
|
||||
|
||||
if relation == "within" {
|
||||
return shape.Contains(shapeInDoc)
|
||||
}
|
||||
|
||||
if relation == "disjoint" {
|
||||
intersects, err := shape.Intersects(shapeInDoc)
|
||||
return !intersects, err
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("unknown relation: %s", relation)
|
||||
}
|
||||
|
||||
// ParseGeoJSONShape unmarshals the geojson/circle/envelope shape
|
||||
// embedded in the given bytes.
|
||||
func ParseGeoJSONShape(input []byte) (index.GeoJSON, error) {
|
||||
var sType string
|
||||
var tmp struct {
|
||||
Typ string `json:"type"`
|
||||
}
|
||||
err := jsoniter.Unmarshal(input, &tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sType = strings.ToLower(tmp.Typ)
|
||||
|
||||
switch sType {
|
||||
case PolygonType:
|
||||
var rv Polygon
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
case MultiPolygonType:
|
||||
var rv MultiPolygon
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
case PointType:
|
||||
var rv Point
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
case MultiPointType:
|
||||
var rv MultiPoint
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
case LineStringType:
|
||||
var rv LineString
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
case MultiLineStringType:
|
||||
var rv MultiLineString
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
case GeometryCollectionType:
|
||||
var rv GeometryCollection
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rv, nil
|
||||
|
||||
case CircleType:
|
||||
var rv Circle
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
case EnvelopeType:
|
||||
var rv Envelope
|
||||
err := jsoniter.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv.init()
|
||||
return &rv, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown shape type: %s", sType)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// NewGeoJsonShape instantiate a geojson shape/circle or
|
||||
// an envelope from the given coordinates and type.
|
||||
func NewGeoJsonShape(coordinates [][][][]float64, typ string) (
|
||||
index.GeoJSON, []byte, error) {
|
||||
if len(coordinates) == 0 {
|
||||
return nil, nil, fmt.Errorf("missing coordinates")
|
||||
}
|
||||
|
||||
typ = strings.ToLower(typ)
|
||||
|
||||
switch typ {
|
||||
case PointType:
|
||||
point := NewGeoJsonPoint(coordinates[0][0][0])
|
||||
value, err := point.(s2Serializable).Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return point, value, nil
|
||||
|
||||
case MultiPointType:
|
||||
multipoint := NewGeoJsonMultiPoint(coordinates[0][0])
|
||||
value, err := multipoint.(s2Serializable).Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return multipoint, value, nil
|
||||
|
||||
case LineStringType:
|
||||
linestring := NewGeoJsonLinestring(coordinates[0][0])
|
||||
value, err := linestring.(s2Serializable).Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return linestring, value, nil
|
||||
|
||||
case MultiLineStringType:
|
||||
multilinestring := NewGeoJsonMultilinestring(coordinates[0])
|
||||
value, err := multilinestring.(s2Serializable).Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return multilinestring, value, nil
|
||||
|
||||
case PolygonType:
|
||||
polygon := NewGeoJsonPolygon(coordinates[0])
|
||||
value, err := polygon.(s2Serializable).Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return polygon, value, nil
|
||||
|
||||
case MultiPolygonType:
|
||||
multipolygon := NewGeoJsonMultiPolygon(coordinates)
|
||||
value, err := multipolygon.(s2Serializable).Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return multipolygon, value, nil
|
||||
|
||||
case EnvelopeType:
|
||||
envelope := NewGeoEnvelope(coordinates[0][0])
|
||||
value, err := envelope.(s2Serializable).Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return envelope, value, nil
|
||||
}
|
||||
|
||||
return nil, nil, fmt.Errorf("unknown shape type: %s", typ)
|
||||
}
|
||||
|
||||
// GlueBytes primarily for quicker filtering of docvalues
|
||||
// during the filtering phase.
|
||||
var GlueBytes = []byte("##")
|
||||
|
||||
// NewGeometryCollection instantiate a geometrycollection
|
||||
// and prefix the byte contents with certain glue bytes that
|
||||
// can be used later while filering the doc values.
|
||||
func NewGeometryCollection(shapes []*GeoShape) (
|
||||
index.GeoJSON, []byte, error) {
|
||||
for _, shape := range shapes {
|
||||
if shape == nil {
|
||||
return nil, nil, fmt.Errorf("nil shape")
|
||||
}
|
||||
if shape.Type == CircleType && shape.Radius == "" && shape.Center == nil {
|
||||
return nil, nil, fmt.Errorf("missing radius or center information for some circles")
|
||||
}
|
||||
if shape.Type != CircleType && shape.Coordinates == nil {
|
||||
return nil, nil, fmt.Errorf("missing coordinates for some shapes")
|
||||
}
|
||||
}
|
||||
|
||||
childShapes := make([]index.GeoJSON, 0, len(shapes))
|
||||
|
||||
for _, shape := range shapes {
|
||||
if shape.Type == CircleType {
|
||||
circle, _, err := NewGeoCircleShape(shape.Center, shape.Radius)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
childShapes = append(childShapes, circle)
|
||||
} else {
|
||||
geoShape, _, err := NewGeoJsonShape(shape.Coordinates, shape.Type)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
childShapes = append(childShapes, geoShape)
|
||||
}
|
||||
}
|
||||
|
||||
var gc GeometryCollection
|
||||
gc.Typ = GeometryCollectionType
|
||||
gc.Shapes = childShapes
|
||||
vbytes, err := gc.Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &gc, vbytes, nil
|
||||
}
|
||||
|
||||
// NewGeoCircleShape instantiate a circle shape and
|
||||
// prefix the byte contents with certain glue bytes that
|
||||
// can be used later while filering the doc values.
|
||||
func NewGeoCircleShape(cp []float64,
|
||||
radius string) (*Circle, []byte, error) {
|
||||
r, err := ParseDistance(radius)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
rv := &Circle{Typ: CircleType, Vertices: cp,
|
||||
Radius: radius,
|
||||
radiusInMeters: r}
|
||||
|
||||
vbytes, err := rv.Marshal()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return rv, vbytes, nil
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (p *Point) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
p.init()
|
||||
terms := s.GetIndexTermsForPoint(*p.s2point, "")
|
||||
return StripCoveringTerms(terms)
|
||||
}
|
||||
|
||||
func (p *Point) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
p.init()
|
||||
terms := s.GetQueryTermsForPoint(*p.s2point, "")
|
||||
return StripCoveringTerms(terms)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (mp *MultiPoint) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
mp.init()
|
||||
var rv []string
|
||||
for _, s2point := range mp.s2points {
|
||||
terms := s.GetIndexTermsForPoint(*s2point, "")
|
||||
rv = append(rv, terms...)
|
||||
}
|
||||
return StripCoveringTerms(rv)
|
||||
}
|
||||
|
||||
func (mp *MultiPoint) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
mp.init()
|
||||
var rv []string
|
||||
for _, s2point := range mp.s2points {
|
||||
terms := s.GetQueryTermsForPoint(*s2point, "")
|
||||
rv = append(rv, terms...)
|
||||
}
|
||||
|
||||
return StripCoveringTerms(rv)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (ls *LineString) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
ls.init()
|
||||
terms := s.GetIndexTermsForRegion(ls.pl.CapBound(), "")
|
||||
return StripCoveringTerms(terms)
|
||||
}
|
||||
|
||||
func (ls *LineString) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
ls.init()
|
||||
terms := s.GetQueryTermsForRegion(ls.pl.CapBound(), "")
|
||||
return StripCoveringTerms(terms)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (mls *MultiLineString) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
mls.init()
|
||||
var rv []string
|
||||
for _, ls := range mls.pls {
|
||||
terms := s.GetIndexTermsForRegion(ls.CapBound(), "")
|
||||
rv = append(rv, terms...)
|
||||
}
|
||||
|
||||
return StripCoveringTerms(rv)
|
||||
}
|
||||
|
||||
func (mls *MultiLineString) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
mls.init()
|
||||
|
||||
var rv []string
|
||||
for _, ls := range mls.pls {
|
||||
terms := s.GetQueryTermsForRegion(ls.CapBound(), "")
|
||||
rv = append(rv, terms...)
|
||||
}
|
||||
|
||||
return StripCoveringTerms(rv)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (mp *MultiPolygon) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
mp.init()
|
||||
|
||||
var rv []string
|
||||
for _, s2pgn := range mp.s2pgns {
|
||||
terms := s.GetIndexTermsForRegion(s2pgn.CapBound(), "")
|
||||
rv = append(rv, terms...)
|
||||
}
|
||||
|
||||
return StripCoveringTerms(rv)
|
||||
}
|
||||
|
||||
func (mp *MultiPolygon) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
mp.init()
|
||||
|
||||
var rv []string
|
||||
for _, s2pgn := range mp.s2pgns {
|
||||
terms := s.GetQueryTermsForRegion(s2pgn.CapBound(), "")
|
||||
rv = append(rv, terms...)
|
||||
}
|
||||
|
||||
return StripCoveringTerms(rv)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (pgn *Polygon) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
pgn.init()
|
||||
terms := s.GetIndexTermsForRegion(
|
||||
pgn.s2pgn.CapBound(), "")
|
||||
return StripCoveringTerms(terms)
|
||||
}
|
||||
|
||||
func (pgn *Polygon) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
pgn.init()
|
||||
terms := s.GetQueryTermsForRegion(
|
||||
pgn.s2pgn.CapBound(), "")
|
||||
return StripCoveringTerms(terms)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (c *Circle) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
c.init()
|
||||
return StripCoveringTerms(s.GetIndexTermsForRegion(c.s2cap.CapBound(), ""))
|
||||
}
|
||||
|
||||
func (c *Circle) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
c.init()
|
||||
return StripCoveringTerms(s.GetQueryTermsForRegion(c.s2cap.CapBound(), ""))
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
func (e *Envelope) IndexTokens(s *s2.RegionTermIndexer) []string {
|
||||
e.init()
|
||||
return StripCoveringTerms(s.GetIndexTermsForRegion(e.r.CapBound(), ""))
|
||||
}
|
||||
|
||||
func (e *Envelope) QueryTokens(s *s2.RegionTermIndexer) []string {
|
||||
e.init()
|
||||
return StripCoveringTerms(s.GetQueryTermsForRegion(e.r.CapBound(), ""))
|
||||
}
|
||||
Reference in New Issue
Block a user