From befc75fa313effc6727628a6d971bf2cc4a8b6c5 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 19 Jun 2018 21:48:17 +0800 Subject: [PATCH 01/11] add ContainingShapeIds for returning all matched shape IDs in contains point query --- s2/contains_point_query.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/s2/contains_point_query.go b/s2/contains_point_query.go index d018f2ea..8ee2ea07 100644 --- a/s2/contains_point_query.go +++ b/s2/contains_point_query.go @@ -80,6 +80,23 @@ func (q *ContainsPointQuery) Contains(p Point) bool { 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 { + var ids []int32 + if !q.iter.LocatePoint(p) { + return ids + } + + cell := q.iter.IndexCell() + for _, clipped := range cell.shapes { + if q.shapeContains(clipped, q.iter.Center(), p) { + 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 { From 8c5c6d7066cc84eb6cfd02f001b36d3f712f9a23 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 19 Jun 2018 21:49:18 +0800 Subject: [PATCH 02/11] support remove by shape ID --- s2/shapeindex.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/s2/shapeindex.go b/s2/shapeindex.go index 718d1178..cfeeefcf 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -713,9 +713,16 @@ 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 } @@ -733,7 +740,7 @@ func (s *ShapeIndex) Remove(shape Shape) { shapeID: id, hasInterior: shape.HasInterior(), containsTrackerOrigin: shape.ReferencePoint().Contained, - edges: make([]Edge, numEdges), + edges: make([]Edge, numEdges), } for e := 0; e < numEdges; e++ { From f476f2bbca54d503b467ba44a48bd5e88c89d020 Mon Sep 17 00:00:00 2001 From: Marco Lee Date: Tue, 19 Jun 2018 16:39:38 +0800 Subject: [PATCH 03/11] add remove by shapeID --- s2/shapeindex.go | 1 - 1 file changed, 1 deletion(-) diff --git a/s2/shapeindex.go b/s2/shapeindex.go index cfeeefcf..9ea359d3 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -716,7 +716,6 @@ func (s *ShapeIndex) Remove(shape Shape) { if id < 0 { return } - s.RemoveById(id) } From 9dc7b9f03162f145c5624d54b5ddc03e51de48b7 Mon Sep 17 00:00:00 2001 From: Marco Lee Date: Tue, 19 Jun 2018 16:39:46 +0800 Subject: [PATCH 04/11] add containing shapeIDs query --- s2/contains_point_query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/s2/contains_point_query.go b/s2/contains_point_query.go index 8ee2ea07..506f07d8 100644 --- a/s2/contains_point_query.go +++ b/s2/contains_point_query.go @@ -83,7 +83,7 @@ func (q *ContainsPointQuery) Contains(p Point) bool { // 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 { - var ids []int32 + ids := make([]int32, 0) if !q.iter.LocatePoint(p) { return ids } From 1baeef042b6305ac8d2bacde1dc5af9e6a2bc397 Mon Sep 17 00:00:00 2001 From: Marco Lee Date: Wed, 20 Jun 2018 18:29:02 +0800 Subject: [PATCH 05/11] prevent index overflow --- s2/shapeindex.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/s2/shapeindex.go b/s2/shapeindex.go index 9ea359d3..a0c6c579 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -1172,10 +1172,10 @@ func (s *ShapeIndex) makeIndexCell(p *PaddedCell, edges []*clippedEdge, t *track eshapeID := int32(s.Len()) cshapeID := int32(eshapeID) // Sentinels - if eNext != len(edges) { + if eNext < len(edges) { eshapeID = edges[eNext].faceEdge.shapeID } - if cNextIdx != len(cshapeIDs) { + if cNextIdx < len(cshapeIDs) { cshapeID = cshapeIDs[cNextIdx] } eBegin := eNext From 8ec6733ba66d004fc6220c15acf68363c7b0b08a Mon Sep 17 00:00:00 2001 From: Marco Lee Date: Wed, 20 Jun 2018 18:38:31 +0800 Subject: [PATCH 06/11] use NewShapeIndexIterator in shapeindex functions to prevent deadlock --- s2/shapeindex.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/s2/shapeindex.go b/s2/shapeindex.go index a0c6c579..5f952f63 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -189,6 +189,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 @@ -221,6 +223,7 @@ func NewShapeIndexIterator(index *ShapeIndex, pos ...ShapeIndexIteratorPos) *Sha s.Begin() case IteratorEnd: s.End() + case IteratorUnpositioned: default: panic("unknown ShapeIndexIteratorPos value") } @@ -935,7 +938,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() } @@ -989,7 +992,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 From b33ed176a07222798453a9c8c82b62d7fa6e72c0 Mon Sep 17 00:00:00 2001 From: Marco Lee Date: Wed, 20 Jun 2018 19:16:51 +0800 Subject: [PATCH 07/11] implement shapeindex tracker lowerBound --- s2/shapeindex.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/s2/shapeindex.go b/s2/shapeindex.go index 5f952f63..0a0dbb0d 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -536,7 +536,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. From 9ad1b486bdaf78a04f0b8d8604ad47614278aa2b Mon Sep 17 00:00:00 2001 From: Marco Date: Wed, 27 Jun 2018 10:15:05 +0800 Subject: [PATCH 08/11] fix add shape id range when apply update internal --- s2/contains_point_query.go | 4 ++++ s2/shapeindex.go | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/s2/contains_point_query.go b/s2/contains_point_query.go index 506f07d8..52db091c 100644 --- a/s2/contains_point_query.go +++ b/s2/contains_point_query.go @@ -107,6 +107,10 @@ func (q *ContainsPointQuery) shapeContains(clipped *clippedShape, center, p Poin } shape := q.index.Shape(clipped.shapeID) + if shape == nil { + return false + } + if !shape.HasInterior() { // Points and polylines can be ignored unless the vertex model is Closed. if q.model != VertexModelClosed { diff --git a/s2/shapeindex.go b/s2/shapeindex.go index 0a0dbb0d..f7a52f27 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -816,7 +816,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) } @@ -825,7 +825,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. } From e04a96731365c0af987831a57ad2762cff0e0260 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 7 Sep 2018 10:20:53 +0800 Subject: [PATCH 09/11] fix returning non-exist shapeID of shapeIndex in contains query --- s2/contains_point_query.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/s2/contains_point_query.go b/s2/contains_point_query.go index 52db091c..3d692d05 100644 --- a/s2/contains_point_query.go +++ b/s2/contains_point_query.go @@ -73,7 +73,8 @@ 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 } } @@ -90,7 +91,8 @@ func (q *ContainsPointQuery) ContainingShapeIds(p Point) []int32 { 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 { ids = append(ids, clipped.shapeID) } } @@ -176,3 +178,4 @@ func (q *ContainsPointQuery) ShapeContains(shape Shape, p Point) bool { // func (q *ContainsPointQuery) VisitContainingShapes(p Point, v shapeVisitorFunc) bool // type edgeVisitorFunc func(shape ShapeEdge) bool // func (q *ContainsPointQuery) VisitIncidentEdges(p Point, v edgeVisitorFunc) bool + From 67c88425bfa7002b8b7d7a765e1cf4aad7e948f5 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 3 Sep 2019 01:02:01 +0800 Subject: [PATCH 10/11] add Polyline UnInterpolate function --- s2/polyline.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 From 820f34a3ec16e1cea69ae8d5aab105f74846b6cf Mon Sep 17 00:00:00 2001 From: Marco Lee Date: Wed, 15 Apr 2020 13:01:45 +0800 Subject: [PATCH 11/11] fix import path --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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