diff --git a/go.mod b/go.mod index 68b04be5..1461e761 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/golang/geo +module github.com/marco709394/geo go 1.12 diff --git a/s2/contains_point_query.go b/s2/contains_point_query.go index 3026f360..634fcf4a 100644 --- a/s2/contains_point_query.go +++ b/s2/contains_point_query.go @@ -75,13 +75,32 @@ func (q *ContainsPointQuery) Contains(p Point) bool { cell := q.iter.IndexCell() for _, clipped := range cell.shapes { - if q.shapeContains(clipped, q.iter.Center(), p) { + if q.shapeContains(clipped, q.iter.Center(), p) && + q.index.Shape(clipped.shapeID) != nil { return true } } return false } +// Contains reports whether any shape in the queries index contains the point p +// under the queries vertex model (Open, SemiOpen, or Closed). +func (q *ContainsPointQuery) ContainingShapeIds(p Point) []int32 { + ids := make([]int32, 0) + if !q.iter.LocatePoint(p) { + return ids + } + + cell := q.iter.IndexCell() + for _, clipped := range cell.shapes { + if q.shapeContains(clipped, q.iter.Center(), p) && + q.index.Shape(clipped.shapeID) != nil { + ids = append(ids, clipped.shapeID) + } + } + return ids +} + // shapeContains reports whether the clippedShape from the iterator's center position contains // the given point. func (q *ContainsPointQuery) shapeContains(clipped *clippedShape, center, p Point) bool { @@ -92,6 +111,10 @@ func (q *ContainsPointQuery) shapeContains(clipped *clippedShape, center, p Poin } shape := q.index.Shape(clipped.shapeID) + if shape == nil { + return false + } + if shape.Dimension() != 2 { // Points and polylines can be ignored unless the vertex model is Closed. if q.model != VertexModelClosed { @@ -187,4 +210,4 @@ func (q *ContainsPointQuery) ContainingShapes(p Point) []Shape { // TODO(roberts): Remaining methods from C++ // type edgeVisitorFunc func(shape ShapeEdge) bool -// func (q *ContainsPointQuery) visitIncidentEdges(p Point, v edgeVisitorFunc) bool +// func (q *ContainsPointQuery) VisitIncidentEdges(p Point, v edgeVisitorFunc) bool diff --git a/s2/polyline.go b/s2/polyline.go index b60c70f4..4c38e23d 100644 --- a/s2/polyline.go +++ b/s2/polyline.go @@ -556,6 +556,24 @@ func (p *Polyline) Interpolate(fraction float64) (Point, int) { return (*p)[len(*p)-1], len(*p) } +func (p *Polyline) UnInterpolate(target Point) (float64, int) { + point, vertex := p.Project(target) + if vertex == len(*p) { + return 1, vertex + } + + var length, totalLength s1.Angle + for i := 1; i < len(*p); i++ { + totalLength += (*p)[i-1].Distance((*p)[i]) + if i < vertex { + length = totalLength + } else if i == vertex { + length += point.Distance((*p)[i-1]) + } + } + return float64(length / totalLength), vertex +} + // TODO(roberts): Differences from C++. // UnInterpolate // NearlyCoversPolyline diff --git a/s2/shapeindex.go b/s2/shapeindex.go index 6f66c9f3..1077a023 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -191,6 +191,8 @@ const ( IteratorBegin ShapeIndexIteratorPos = iota // IteratorEnd specifies the iterator should be positioned at the end of the index. IteratorEnd + // IteratorUnpositioned specifies the iterator position is not changed. + IteratorUnpositioned ) // ShapeIndexIterator is an iterator that provides low-level access to @@ -223,6 +225,7 @@ func NewShapeIndexIterator(index *ShapeIndex, pos ...ShapeIndexIteratorPos) *Sha s.Begin() case IteratorEnd: s.End() + case IteratorUnpositioned: default: panic("unknown ShapeIndexIteratorPos value") } @@ -535,7 +538,14 @@ func (t *tracker) restoreStateBefore(limitShapeID int32) { // lowerBound returns the shapeID of the first entry x where x >= shapeID. func (t *tracker) lowerBound(shapeID int32) int32 { - panic("not implemented") + pos := 0 + for _, id := range t.shapeIDs { + if id >= shapeID { + break + } + pos++ + } + return int32(pos) } // removedShape represents a set of edges from the given shape that is queued for removal. @@ -737,9 +747,15 @@ func (s *ShapeIndex) Remove(shape Shape) { // The index updates itself lazily because it is much more efficient to // process additions and removals in batches. id := s.idForShape(shape) + if id < 0 { + return + } + s.RemoveById(id) +} - // If the shape wasn't found, it's already been removed or was not in the index. - if s.shapes[id] == nil { +func (s *ShapeIndex) RemoveById(id int32) { + shape, exist := s.shapes[id] + if !exist { return } @@ -757,7 +773,7 @@ func (s *ShapeIndex) Remove(shape Shape) { shapeID: id, hasInterior: shape.Dimension() == 2, containsTrackerOrigin: shape.ReferencePoint().Contained, - edges: make([]Edge, numEdges), + edges: make([]Edge, numEdges), } for e := 0; e < numEdges; e++ { @@ -824,7 +840,7 @@ func (s *ShapeIndex) applyUpdatesInternal() { s.removeShapeInternal(p, allEdges, t) } - for id := s.pendingAdditionsPos; id < int32(len(s.shapes)); id++ { + for id := s.pendingAdditionsPos; id < s.nextID; id++ { s.addShapeInternal(id, allEdges, t) } @@ -833,7 +849,7 @@ func (s *ShapeIndex) applyUpdatesInternal() { } s.pendingRemovals = s.pendingRemovals[:0] - s.pendingAdditionsPos = int32(len(s.shapes)) + s.pendingAdditionsPos = s.nextID // It is the caller's responsibility to update the index status. } @@ -952,7 +968,7 @@ func (s *ShapeIndex) shrinkToFit(pcell *PaddedCell, bound r2.Rect) CellID { if !s.isFirstUpdate() && shrunkID != pcell.CellID() { // Don't shrink any smaller than the existing index cells, since we need // to combine the new edges with those cells. - iter := s.Iterator() + iter := NewShapeIndexIterator(s, IteratorUnpositioned) if iter.LocateCellID(shrunkID) == Indexed { shrunkID = iter.CellID() } @@ -1006,7 +1022,7 @@ func (s *ShapeIndex) updateEdges(pcell *PaddedCell, edges []*clippedEdge, t *tra // There may be existing index cells contained inside pcell. If we // encounter such a cell, we need to combine the edges being updated with // the existing cell contents by absorbing the cell. - iter := s.Iterator() + iter := NewShapeIndexIterator(s, IteratorUnpositioned) r := iter.LocateCellID(pcell.id) if r == Disjoint { disjointFromIndex = true @@ -1189,7 +1205,7 @@ func (s *ShapeIndex) makeIndexCell(p *PaddedCell, edges []*clippedEdge, t *track eshapeID := int32(s.Len()) cshapeID := eshapeID // Sentinels - if eNext != len(edges) { + if eNext < len(edges) { eshapeID = edges[eNext].faceEdge.shapeID } if cNextIdx < len(cshapeIDs) {