 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			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>
		
			
				
	
	
		
			360 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2019 Google Inc. All rights reserved.
 | |
| //
 | |
| // 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 s2
 | |
| 
 | |
| import (
 | |
| 	"math"
 | |
| 
 | |
| 	"github.com/blevesearch/geo/s1"
 | |
| )
 | |
| 
 | |
| // minDistance implements distance interface to find closest distance types.
 | |
| type minDistance s1.ChordAngle
 | |
| 
 | |
| func (m minDistance) chordAngle() s1.ChordAngle { return s1.ChordAngle(m) }
 | |
| func (m minDistance) zero() distance            { return minDistance(0) }
 | |
| func (m minDistance) negative() distance        { return minDistance(s1.NegativeChordAngle) }
 | |
| func (m minDistance) infinity() distance        { return minDistance(s1.InfChordAngle()) }
 | |
| func (m minDistance) less(other distance) bool  { return m.chordAngle() < other.chordAngle() }
 | |
| func (m minDistance) sub(other distance) distance {
 | |
| 	return minDistance(m.chordAngle() - other.chordAngle())
 | |
| }
 | |
| func (m minDistance) chordAngleBound() s1.ChordAngle {
 | |
| 	return m.chordAngle().Expanded(m.chordAngle().MaxAngleError())
 | |
| }
 | |
| 
 | |
| // updateDistance updates its own value if the other value is less() than it is,
 | |
| // and reports if it updated.
 | |
| func (m minDistance) updateDistance(dist distance) (distance, bool) {
 | |
| 	if dist.less(m) {
 | |
| 		m = minDistance(dist.chordAngle())
 | |
| 		return m, true
 | |
| 	}
 | |
| 	return m, false
 | |
| }
 | |
| 
 | |
| func (m minDistance) fromChordAngle(o s1.ChordAngle) distance {
 | |
| 	return minDistance(o)
 | |
| }
 | |
| 
 | |
| // MinDistanceToPointTarget is a type for computing the minimum distance to a Point.
 | |
| type MinDistanceToPointTarget struct {
 | |
| 	point Point
 | |
| 	dist  distance
 | |
| }
 | |
| 
 | |
| // NewMinDistanceToPointTarget returns a new target for the given Point.
 | |
| func NewMinDistanceToPointTarget(point Point) *MinDistanceToPointTarget {
 | |
| 	m := minDistance(0)
 | |
| 	return &MinDistanceToPointTarget{point: point, dist: &m}
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToPointTarget) capBound() Cap {
 | |
| 	return CapFromCenterChordAngle(m.point, s1.ChordAngle(0))
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToPointTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
 | |
| 	var ok bool
 | |
| 	dist, ok = dist.updateDistance(minDistance(ChordAngleBetweenPoints(p, m.point)))
 | |
| 	return dist, ok
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToPointTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
 | |
| 	if d, ok := UpdateMinDistance(m.point, edge.V0, edge.V1, dist.chordAngle()); ok {
 | |
| 		dist, _ = dist.updateDistance(minDistance(d))
 | |
| 		return dist, true
 | |
| 	}
 | |
| 	return dist, false
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToPointTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
 | |
| 	var ok bool
 | |
| 	dist, ok = dist.updateDistance(minDistance(cell.Distance(m.point)))
 | |
| 	return dist, ok
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToPointTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
 | |
| 	// For furthest points, we visit the polygons whose interior contains
 | |
| 	// the antipode of the target point. These are the polygons whose
 | |
| 	// distance to the target is maxDistance.zero()
 | |
| 	q := NewContainsPointQuery(index, VertexModelSemiOpen)
 | |
| 	return q.visitContainingShapes(m.point, func(shape Shape) bool {
 | |
| 		return v(shape, m.point)
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToPointTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
 | |
| func (m *MinDistanceToPointTarget) maxBruteForceIndexSize() int           { return 30 }
 | |
| func (m *MinDistanceToPointTarget) distance() distance                    { return m.dist }
 | |
| 
 | |
| // ----------------------------------------------------------
 | |
| 
 | |
| // MinDistanceToEdgeTarget is a type for computing the minimum distance to an Edge.
 | |
| type MinDistanceToEdgeTarget struct {
 | |
| 	e    Edge
 | |
| 	dist distance
 | |
| }
 | |
| 
 | |
| // NewMinDistanceToEdgeTarget returns a new target for the given Edge.
 | |
| func NewMinDistanceToEdgeTarget(e Edge) *MinDistanceToEdgeTarget {
 | |
| 	m := minDistance(0)
 | |
| 	return &MinDistanceToEdgeTarget{e: e, dist: m}
 | |
| }
 | |
| 
 | |
| // capBound returns a Cap that bounds the antipode of the target. (This
 | |
| // is the set of points whose maxDistance to the target is maxDistance.zero)
 | |
| func (m *MinDistanceToEdgeTarget) capBound() Cap {
 | |
| 	// The following computes a radius equal to half the edge length in an
 | |
| 	// efficient and numerically stable way.
 | |
| 	d2 := float64(ChordAngleBetweenPoints(m.e.V0, m.e.V1))
 | |
| 	r2 := (0.5 * d2) / (1 + math.Sqrt(1-0.25*d2))
 | |
| 	return CapFromCenterChordAngle(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()}, s1.ChordAngleFromSquaredLength(r2))
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToEdgeTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
 | |
| 	if d, ok := UpdateMinDistance(p, m.e.V0, m.e.V1, dist.chordAngle()); ok {
 | |
| 		dist, _ = dist.updateDistance(minDistance(d))
 | |
| 		return dist, true
 | |
| 	}
 | |
| 	return dist, false
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToEdgeTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
 | |
| 	if d, ok := updateEdgePairMinDistance(m.e.V0, m.e.V1, edge.V0, edge.V1, dist.chordAngle()); ok {
 | |
| 		dist, _ = dist.updateDistance(minDistance(d))
 | |
| 		return dist, true
 | |
| 	}
 | |
| 	return dist, false
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToEdgeTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
 | |
| 	return dist.updateDistance(minDistance(cell.DistanceToEdge(m.e.V0, m.e.V1)))
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToEdgeTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
 | |
| 	// We test the center of the edge in order to ensure that edge targets AB
 | |
| 	// and BA yield identical results (which is not guaranteed by the API but
 | |
| 	// users might expect).  Other options would be to test both endpoints, or
 | |
| 	// return different results for AB and BA in some cases.
 | |
| 	target := NewMinDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()})
 | |
| 	return target.visitContainingShapes(index, v)
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToEdgeTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
 | |
| func (m *MinDistanceToEdgeTarget) maxBruteForceIndexSize() int           { return 30 }
 | |
| func (m *MinDistanceToEdgeTarget) distance() distance                    { return m.dist }
 | |
| 
 | |
| // ----------------------------------------------------------
 | |
| 
 | |
| // MinDistanceToCellTarget is a type for computing the minimum distance to a Cell.
 | |
| type MinDistanceToCellTarget struct {
 | |
| 	cell Cell
 | |
| 	dist distance
 | |
| }
 | |
| 
 | |
| // NewMinDistanceToCellTarget returns a new target for the given Cell.
 | |
| func NewMinDistanceToCellTarget(cell Cell) *MinDistanceToCellTarget {
 | |
| 	m := minDistance(0)
 | |
| 	return &MinDistanceToCellTarget{cell: cell, dist: m}
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellTarget) capBound() Cap {
 | |
| 	return m.cell.CapBound()
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
 | |
| 	return dist.updateDistance(minDistance(m.cell.Distance(p)))
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
 | |
| 	return dist.updateDistance(minDistance(m.cell.DistanceToEdge(edge.V0, edge.V1)))
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
 | |
| 	return dist.updateDistance(minDistance(m.cell.DistanceToCell(cell)))
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
 | |
| 	// The simplest approach is simply to return the polygons that contain the
 | |
| 	// cell center.  Alternatively, if the index cell is smaller than the target
 | |
| 	// cell then we could return all polygons that are present in the
 | |
| 	// shapeIndexCell, but since the index is built conservatively this may
 | |
| 	// include some polygons that don't quite intersect the cell.  So we would
 | |
| 	// either need to recheck for intersection more accurately, or weaken the
 | |
| 	// VisitContainingShapes contract so that it only guarantees approximate
 | |
| 	// intersection, neither of which seems like a good tradeoff.
 | |
| 	target := NewMinDistanceToPointTarget(m.cell.Center())
 | |
| 	return target.visitContainingShapes(index, v)
 | |
| }
 | |
| func (m *MinDistanceToCellTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
 | |
| func (m *MinDistanceToCellTarget) maxBruteForceIndexSize() int           { return 30 }
 | |
| func (m *MinDistanceToCellTarget) distance() distance                    { return m.dist }
 | |
| 
 | |
| // ----------------------------------------------------------
 | |
| 
 | |
| /*
 | |
| // MinDistanceToCellUnionTarget is a type for computing the minimum distance to a CellUnion.
 | |
| type MinDistanceToCellUnionTarget struct {
 | |
| 	cu    CellUnion
 | |
| 	query *ClosestCellQuery
 | |
| 	dist  distance
 | |
| }
 | |
| 
 | |
| // NewMinDistanceToCellUnionTarget returns a new target for the given CellUnion.
 | |
| func NewMinDistanceToCellUnionTarget(cu CellUnion) *MinDistanceToCellUnionTarget {
 | |
| 	m := minDistance(0)
 | |
| 	return &MinDistanceToCellUnionTarget{cu: cu, dist: m}
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellUnionTarget) capBound() Cap {
 | |
| 	return m.cu.CapBound()
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellUnionTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
 | |
| 	m.query.opts.DistanceLimit = dist.chordAngle()
 | |
| 	target := NewMinDistanceToPointTarget(p)
 | |
| 	r := m.query.findEdge(target)
 | |
| 	if r.ShapeID < 0 {
 | |
| 		return dist, false
 | |
| 	}
 | |
| 	return minDistance(r.Distance), true
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToCellUnionTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
 | |
| 	// We test the center of the edge in order to ensure that edge targets AB
 | |
| 	// and BA yield identical results (which is not guaranteed by the API but
 | |
| 	// users might expect).  Other options would be to test both endpoints, or
 | |
| 	// return different results for AB and BA in some cases.
 | |
| 	target := NewMinDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()})
 | |
| 	return target.visitContainingShapes(index, v)
 | |
| }
 | |
| func (m *MinDistanceToCellUnionTarget) setMaxError(maxErr s1.ChordAngle) bool {
 | |
| 	m.query.opts.MaxError = maxErr
 | |
| 	return true
 | |
| }
 | |
| func (m *MinDistanceToCellUnionTarget) maxBruteForceIndexSize() int           { return 30 }
 | |
| func (m *MinDistanceToCellUnionTarget) distance() distance                    { return m.dist }
 | |
| */
 | |
| 
 | |
| // ----------------------------------------------------------
 | |
| 
 | |
| // MinDistanceToShapeIndexTarget is a type for computing the minimum distance to a ShapeIndex.
 | |
| type MinDistanceToShapeIndexTarget struct {
 | |
| 	index *ShapeIndex
 | |
| 	query *EdgeQuery
 | |
| 	dist  distance
 | |
| }
 | |
| 
 | |
| // NewMinDistanceToShapeIndexTarget returns a new target for the given ShapeIndex.
 | |
| func NewMinDistanceToShapeIndexTarget(index *ShapeIndex) *MinDistanceToShapeIndexTarget {
 | |
| 	m := minDistance(0)
 | |
| 	return &MinDistanceToShapeIndexTarget{
 | |
| 		index: index,
 | |
| 		dist:  m,
 | |
| 		query: NewClosestEdgeQuery(index, NewClosestEdgeQueryOptions()),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToShapeIndexTarget) capBound() Cap {
 | |
| 	c := m.index.Region().CapBound()
 | |
| 	return CapFromCenterAngle(Point{c.Center().Mul(-1)}, c.Radius())
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToShapeIndexTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
 | |
| 	m.query.opts.distanceLimit = dist.chordAngle()
 | |
| 	target := NewMinDistanceToPointTarget(p)
 | |
| 	r := m.query.findEdge(target, m.query.opts)
 | |
| 	if r.shapeID < 0 {
 | |
| 		return dist, false
 | |
| 	}
 | |
| 	return r.distance, true
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToShapeIndexTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
 | |
| 	m.query.opts.distanceLimit = dist.chordAngle()
 | |
| 	target := NewMinDistanceToEdgeTarget(edge)
 | |
| 	r := m.query.findEdge(target, m.query.opts)
 | |
| 	if r.shapeID < 0 {
 | |
| 		return dist, false
 | |
| 	}
 | |
| 	return r.distance, true
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToShapeIndexTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
 | |
| 	m.query.opts.distanceLimit = dist.chordAngle()
 | |
| 	target := NewMinDistanceToCellTarget(cell)
 | |
| 	r := m.query.findEdge(target, m.query.opts)
 | |
| 	if r.shapeID < 0 {
 | |
| 		return dist, false
 | |
| 	}
 | |
| 	return r.distance, true
 | |
| }
 | |
| 
 | |
| // For target types consisting of multiple connected components (such as this one),
 | |
| // this method should return the polygons containing the antipodal reflection of
 | |
| // *any* connected component. (It is sufficient to test containment of one vertex per
 | |
| // connected component, since this allows us to also return any polygon whose
 | |
| // boundary has distance.zero() to the target.)
 | |
| func (m *MinDistanceToShapeIndexTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
 | |
| 	// It is sufficient to find the set of chain starts in the target index
 | |
| 	// (i.e., one vertex per connected component of edges) that are contained by
 | |
| 	// the query index, except for one special case to handle full polygons.
 | |
| 	//
 | |
| 	// TODO(roberts): Do this by merge-joining the two ShapeIndexes.
 | |
| 	for _, shape := range m.index.shapes {
 | |
| 		numChains := shape.NumChains()
 | |
| 		// Shapes that don't have any edges require a special case (below).
 | |
| 		testedPoint := false
 | |
| 		for c := 0; c < numChains; c++ {
 | |
| 			chain := shape.Chain(c)
 | |
| 			if chain.Length == 0 {
 | |
| 				continue
 | |
| 			}
 | |
| 			testedPoint = true
 | |
| 			target := NewMinDistanceToPointTarget(shape.ChainEdge(c, 0).V0)
 | |
| 			if !target.visitContainingShapes(index, v) {
 | |
| 				return false
 | |
| 			}
 | |
| 		}
 | |
| 		if !testedPoint {
 | |
| 			// Special case to handle full polygons.
 | |
| 			ref := shape.ReferencePoint()
 | |
| 			if !ref.Contained {
 | |
| 				continue
 | |
| 			}
 | |
| 			target := NewMinDistanceToPointTarget(ref.Point)
 | |
| 			if !target.visitContainingShapes(index, v) {
 | |
| 				return false
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (m *MinDistanceToShapeIndexTarget) setMaxError(maxErr s1.ChordAngle) bool {
 | |
| 	m.query.opts.maxError = maxErr
 | |
| 	return true
 | |
| }
 | |
| func (m *MinDistanceToShapeIndexTarget) maxBruteForceIndexSize() int { return 25 }
 | |
| func (m *MinDistanceToShapeIndexTarget) distance() distance          { return m.dist }
 | |
| func (m *MinDistanceToShapeIndexTarget) setIncludeInteriors(b bool) {
 | |
| 	m.query.opts.includeInteriors = b
 | |
| }
 | |
| func (m *MinDistanceToShapeIndexTarget) setUseBruteForce(b bool) { m.query.opts.useBruteForce = b }
 | |
| 
 | |
| // TODO(roberts): Remaining methods
 | |
| //
 | |
| // CellUnionTarget
 |