-
Notifications
You must be signed in to change notification settings - Fork 189
Add incidentEdgeTracker and indexCellData types and tests #180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rsned
wants to merge
10
commits into
golang:master
Choose a base branch
from
rsned:internal
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 7 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
40abfda
Add incidentEdgeTracker and indexCellData types and tests
rsned db83ebf
remove some extraneous bits
rsned 394b634
Fix LaxPolygon to properly order vertices between shells and holes.
rsned 8aa64ba
Merge branch 'golang:master' into internal
rsned 475ef64
Update s2/index_cell_data.go
rsned 2b1704c
Update s2/index_cell_data_test.go
rsned 9dd01a8
Add missing body for laxPolygonFromLoops and missing test messages.
rsned d1c19d1
Merge branch 'internal' of ssh://github.com/rsned/geo into internal
rsned cbe002a
Update index_cell_data with review requests. Updated tests.
rsned 8e8bb75
Updated comments based on Javas clearer comments.
rsned File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,22 +14,17 @@ | |
|
||
package s2 | ||
|
||
import ( | ||
"sync" | ||
"sync/atomic" | ||
) | ||
|
||
// indexCellRegion represents a simple pair for defining an integer valued region. | ||
type indexCellRegion struct { | ||
// indexCellRange represents a simple pair for defining an integer valued range. | ||
type indexCellRange struct { | ||
start int | ||
size int | ||
} | ||
|
||
// shapeRegion is a mapping from shape id to the region of the edges array | ||
// shapeRange is a mapping from shapeID to the range of the edges array | ||
// it's stored in. | ||
type shapeRegion struct { | ||
id int32 | ||
region indexCellRegion | ||
type shapeRange struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this one too generic? Would |
||
id int32 | ||
cellRange indexCellRange | ||
} | ||
|
||
// edgeAndIDChain is an extension of Edge with fields for the edge id, | ||
|
@@ -82,16 +77,16 @@ type edgeAndIDChain struct { | |
// shapes _within a dimension_ are in the same order they are in the index | ||
// itself, and the edges _within a shape_ are similarly in the same order. | ||
type indexCellData struct { | ||
// index is the ShapeIndex the currently loaded Cell belongs to. | ||
index *ShapeIndex | ||
indexCell *ShapeIndexCell | ||
cellID CellID | ||
|
||
// Computing the cell center and Cell can cost as much as looking up the | ||
// edges themselves, so defer doing it until needed. | ||
mu sync.Mutex | ||
s2CellSet atomic.Bool | ||
s2CellSet bool | ||
s2Cell Cell | ||
centerSet atomic.Bool | ||
centerSet bool | ||
cellCenter Point | ||
|
||
// Dimensions that we wish to decode, the default is all of them. | ||
|
@@ -100,11 +95,11 @@ type indexCellData struct { | |
// Storage space for edges of the current cell. | ||
edges []edgeAndIDChain | ||
|
||
// Mapping from shape id to the region of the edges array it's stored in. | ||
shapeRegions []shapeRegion | ||
// Mapping from shape id to the ranges of the edges array it's stored in. | ||
shapeRanges []shapeRange | ||
|
||
// Region for each dimension we might encounter. | ||
dimRegions [3]indexCellRegion | ||
// Range for each dimension we might encounter. | ||
dimRanges [3]indexCellRange | ||
} | ||
|
||
// newIndexCellData creates a new indexCellData with the expected defaults. | ||
|
@@ -114,7 +109,7 @@ func newIndexCellData() *indexCellData { | |
} | ||
} | ||
|
||
// newindexCellDataFromCell creates a new indexCellData and loads the given | ||
// newIndexCellDataFromCell creates a new indexCellData and loads the given | ||
// cell data. | ||
func newIndexCellDataFromCell(index *ShapeIndex, id CellID, cell *ShapeIndexCell) *indexCellData { | ||
d := newIndexCellData() | ||
|
@@ -129,7 +124,7 @@ func (d *indexCellData) reset() { | |
d.index = nil | ||
d.indexCell = nil | ||
d.edges = d.edges[:0] | ||
d.shapeRegions = d.shapeRegions[:0] | ||
d.shapeRanges = d.shapeRanges[:0] | ||
d.dimWanted = [3]bool{true, true, true} | ||
} | ||
|
||
|
@@ -144,27 +139,21 @@ func (d *indexCellData) setDimWanted(dim int, wanted bool) { | |
// cell returns the S2 Cell for the current index cell, loading it if it | ||
// was not already set. | ||
func (d *indexCellData) cell() Cell { | ||
if !d.s2CellSet.Load() { | ||
d.mu.Lock() | ||
if !d.s2CellSet.Load() { | ||
d.s2Cell = CellFromCellID(d.cellID) | ||
d.s2CellSet.Store(true) | ||
} | ||
d.mu.Unlock() | ||
// TODO(rsned): Consider if we need to add mutex here for thread safety. | ||
if !d.s2CellSet { | ||
d.s2Cell = CellFromCellID(d.cellID) | ||
d.s2CellSet = true | ||
} | ||
return d.s2Cell | ||
} | ||
|
||
// center returns the center point of the current index cell, loading it | ||
// if it was not already set. | ||
func (d *indexCellData) center() Point { | ||
if !d.centerSet.Load() { | ||
d.mu.Lock() | ||
if !d.centerSet.Load() { | ||
d.cellCenter = d.cellID.Point() | ||
d.centerSet.Store(true) | ||
} | ||
d.mu.Unlock() | ||
// TODO(rsned): Consider if we need to add mutex here for thread safety. | ||
if !d.centerSet { | ||
d.cellCenter = d.cellID.Point() | ||
d.centerSet = true | ||
} | ||
return d.cellCenter | ||
} | ||
|
@@ -177,7 +166,7 @@ func (d *indexCellData) center() Point { | |
// loadCell, loading is not performed since we already have the data decoded. | ||
func (d *indexCellData) loadCell(index *ShapeIndex, id CellID, cell *ShapeIndexCell) { | ||
// If this is still the same ShapeIndexCell as last time, then we are good. | ||
if d.index == index && d.cellID == id { | ||
if d.index == index && d.cellID == id && cell == d.indexCell { | ||
return | ||
} | ||
|
||
|
@@ -187,17 +176,17 @@ func (d *indexCellData) loadCell(index *ShapeIndex, id CellID, cell *ShapeIndexC | |
d.indexCell = cell | ||
d.cellID = id | ||
|
||
// Reset atomic flags so we'll recompute cached values. | ||
d.s2CellSet.Store(false) | ||
d.centerSet.Store(false) | ||
// Reset flags so we'll recompute cached values. | ||
d.s2CellSet = false | ||
d.centerSet = false | ||
|
||
// Clear previous edges | ||
d.edges = d.edges[:0] | ||
d.shapeRegions = d.shapeRegions[:0] | ||
d.shapeRanges = d.shapeRanges[:0] | ||
|
||
// Reset per-dimension region information. | ||
for i := range d.dimRegions { | ||
d.dimRegions[i] = indexCellRegion{} | ||
// Reset per-dimension range information. | ||
for i := range d.dimRanges { | ||
d.dimRanges[i] = indexCellRange{} | ||
} | ||
|
||
minDim := 0 | ||
|
@@ -239,7 +228,7 @@ func (d *indexCellData) loadCell(index *ShapeIndex, id CellID, cell *ShapeIndexC | |
|
||
// Materialize clipped shape edges into the edges | ||
// slice. Track where we start so we can add | ||
// information about the region for this shape. | ||
// information about the range for this shape. | ||
shapeStart := len(d.edges) | ||
for _, edgeID := range clipped.edges { | ||
// Looking up an edge requires looking up | ||
|
@@ -258,17 +247,17 @@ func (d *indexCellData) loadCell(index *ShapeIndex, id CellID, cell *ShapeIndexC | |
} | ||
|
||
// Note which block of edges belongs to the shape. | ||
d.shapeRegions = append(d.shapeRegions, shapeRegion{ | ||
d.shapeRanges = append(d.shapeRanges, shapeRange{ | ||
id: shapeID, | ||
region: indexCellRegion{ | ||
cellRange: indexCellRange{ | ||
start: shapeStart, | ||
size: len(d.edges) - shapeStart, | ||
}, | ||
}) | ||
} | ||
|
||
// Save region information for the current dimension. | ||
d.dimRegions[dim] = indexCellRegion{ | ||
// Save range information for the current dimension. | ||
d.dimRanges[dim] = indexCellRange{ | ||
start: dimStart, | ||
size: len(d.edges) - dimStart, | ||
} | ||
|
@@ -277,11 +266,11 @@ func (d *indexCellData) loadCell(index *ShapeIndex, id CellID, cell *ShapeIndexC | |
|
||
// shapeEdges returns a slice of the edges in the current cell for a given shape. | ||
func (d *indexCellData) shapeEdges(shapeID int32) []edgeAndIDChain { | ||
for _, sr := range d.shapeRegions { | ||
for _, sr := range d.shapeRanges { | ||
if sr.id == shapeID { | ||
region := sr.region | ||
if region.start < len(d.edges) { | ||
return d.edges[region.start : region.start+region.size] | ||
cellRange := sr.cellRange | ||
if cellRange.start < len(d.edges) { | ||
return d.edges[cellRange.start : cellRange.start+cellRange.size] | ||
} | ||
return nil | ||
} | ||
|
@@ -296,9 +285,9 @@ func (d *indexCellData) dimEdges(dim int) []edgeAndIDChain { | |
return nil | ||
} | ||
|
||
region := d.dimRegions[dim] | ||
if region.start < len(d.edges) { | ||
return d.edges[region.start : region.start+region.size] | ||
dimRange := d.dimRanges[dim] | ||
if dimRange.start < len(d.edges) { | ||
return d.edges[dimRange.start : dimRange.start+dimRange.size] | ||
} | ||
return nil | ||
} | ||
|
@@ -310,12 +299,12 @@ func (d *indexCellData) dimRangeEdges(dim0, dim1 int) []edgeAndIDChain { | |
return nil | ||
} | ||
|
||
start := d.dimRegions[dim0].start | ||
start := d.dimRanges[dim0].start | ||
size := 0 | ||
|
||
for dim := dim0; dim <= dim1; dim++ { | ||
start = minInt(start, d.dimRegions[dim].start) | ||
size += d.dimRegions[dim].size | ||
start = minInt(start, d.dimRanges[dim].start) | ||
size += d.dimRanges[dim].size | ||
} | ||
|
||
if start < len(d.edges) { | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error handling across these functions is pretty bad. Here, you silently drop edges. There's no checking to ensure that calls are made in the right sequence. Should we re-examine the API to make erroneous usage more difficult? All the internal calls to the C++ version look like:
So we could have an interface that looks like:
This would also remove the need for a "nursery" and the associated type, resolving one of my other comments.