-
Notifications
You must be signed in to change notification settings - Fork 193
Implement S2R2Rect #253
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
base: master
Are you sure you want to change the base?
Implement S2R2Rect #253
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,6 +114,16 @@ func (i Interval) ClampPoint(p float64) float64 { | |
| return math.Max(i.Lo, math.Min(i.Hi, p)) | ||
| } | ||
|
|
||
| func (i Interval) Project(p float64) float64 { | ||
| if p < i.Lo { | ||
|
Collaborator
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. |
||
| return i.Lo | ||
| } | ||
| if p > i.Hi { | ||
| return i.Hi | ||
| } | ||
| return p | ||
| } | ||
|
|
||
| // Expanded returns an interval that has been expanded on each side by margin. | ||
| // If margin is negative, then the function shrinks the interval on | ||
| // each side by margin instead. The resulting interval may be empty. Any | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,6 +122,13 @@ func (r Rect) Vertices() [4]Point { | |
| } | ||
| } | ||
|
|
||
| func (r Rect) Vertex(k int) Point { | ||
|
Collaborator
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. All public functions should be directly tested. |
||
| // Twiddle bits to return the points in CCW order (lower left, lower right, | ||
| // upper right, upper left). | ||
| j := (k >> 1) & 1 | ||
| return r.VertexIJ(j^(k&1), j) | ||
| } | ||
|
|
||
| // VertexIJ returns the vertex in direction i along the X-axis (0=left, 1=right) and | ||
| // direction j along the Y-axis (0=down, 1=up). | ||
| func (r Rect) VertexIJ(i, j int) Point { | ||
|
|
@@ -210,6 +217,10 @@ func (r Rect) ClampPoint(p Point) Point { | |
| return Point{r.X.ClampPoint(p.X), r.Y.ClampPoint(p.Y)} | ||
| } | ||
|
|
||
| func (r Rect) Project(p Point) Point { | ||
|
Collaborator
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. This function doesn't come from C++ as far as I can see. |
||
| return Point{r.X.Project(p.X), r.Y.Project(p.Y)} | ||
| } | ||
|
|
||
| // Expanded returns a rectangle that has been expanded in the x-direction | ||
| // by margin.X, and in y-direction by margin.Y. If either margin is empty, | ||
| // then shrink the interval on the corresponding sides instead. The resulting | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| package s2 | ||
|
|
||
| import "github.com/golang/geo/r2" | ||
|
|
||
| // R2Rect represents a closed axis-aligned rectangle in the (x,y) plane. | ||
| type R2Rect struct { | ||
| r2.Rect | ||
| } | ||
|
|
||
| // ContainsR2Point reports whether the rectangle contains the given point. | ||
| // Rectangles are closed regions, i.e. they contain their boundary. | ||
| func (r R2Rect) ContainsR2Point(p r2.Point) bool { | ||
| return r.Rect.ContainsPoint(p) | ||
| } | ||
|
|
||
| // Contains reports whether the rectangle contains the given rectangle. | ||
| func (r R2Rect) Contains(other R2Rect) bool { | ||
| return r.Rect.Contains(other.Rect) | ||
| } | ||
|
|
||
| // InteriorContainsPoint returns true iff the given point is contained in the interior | ||
| // of the region (i.e. the region excluding its boundary). | ||
| func (r R2Rect) InteriorContainsPoint(p r2.Point) bool { | ||
| return r.Rect.InteriorContainsPoint(p) | ||
| } | ||
|
|
||
| // InteriorContains reports whether the interior of this rectangle contains all of the | ||
| // points of the given other rectangle (including its boundary). | ||
| func (r R2Rect) InteriorContains(other R2Rect) bool { | ||
| return r.Rect.InteriorContains(other.Rect) | ||
| } | ||
|
|
||
| // Intersects reports whether this rectangle and the other rectangle have any points in common. | ||
| func (r R2Rect) Intersects(other R2Rect) bool { | ||
| return r.Rect.Intersects(other.Rect) | ||
| } | ||
|
|
||
| // InteriorIntersects reports whether the interior of this rectangle intersects | ||
| // any point (including the boundary) of the given other rectangle. | ||
| func (r R2Rect) InteriorIntersects(other R2Rect) bool { | ||
| return r.Rect.InteriorIntersects(other.Rect) | ||
| } | ||
|
|
||
| // Expanded returns a rectangle that has been expanded in the x-direction | ||
| // by margin.X, and in y-direction by margin.Y. If either margin is empty, | ||
| // then shrink the interval on the corresponding sides instead. The resulting | ||
| // rectangle may be empty. Any expansion of an empty rectangle remains empty. | ||
| func (r R2Rect) Expanded(margin r2.Point) R2Rect { | ||
| return R2Rect{r.Rect.Expanded(margin)} | ||
| } | ||
|
|
||
| // ExpandedByMargin returns a Rect that has been expanded by the amount on all sides. | ||
| func (r R2Rect) ExpandedByMargin(margin float64) R2Rect { | ||
| return R2Rect{r.Rect.ExpandedByMargin(margin)} | ||
| } | ||
|
|
||
| // Union returns the smallest rectangle containing the union of this rectangle and | ||
| // the given rectangle. | ||
| func (r R2Rect) Union(other R2Rect) R2Rect { | ||
| return R2Rect{r.Rect.Union(other.Rect)} | ||
| } | ||
|
|
||
| // Intersection returns the smallest rectangle containing the intersection of this | ||
| // rectangle and the given rectangle. | ||
| func (r R2Rect) Intersection(other R2Rect) R2Rect { | ||
| return R2Rect{r.Rect.Intersection(other.Rect)} | ||
| } | ||
|
|
||
| // ApproxEqual returns true if the x- and y-intervals of the two rectangles are | ||
| // the same up to the given tolerance. | ||
| func (r R2Rect) ApproxEqual(other R2Rect) bool { | ||
| return r.Rect.ApproxEqual(other.Rect) | ||
| } | ||
|
|
||
| // AddPoint expands the rectangle to include the given point. The rectangle is | ||
| // expanded by the minimum amount possible. | ||
| func (r R2Rect) AddPoint(p r2.Point) R2Rect { | ||
| return R2Rect{r.Rect.AddPoint(p)} | ||
| } | ||
|
|
||
| // AddRect expands the rectangle to include the given rectangle. This is the | ||
| // same as replacing the rectangle by the union of the two rectangles, but | ||
| // is more efficient. | ||
| func (r R2Rect) AddRect(other R2Rect) R2Rect { | ||
| return R2Rect{r.Rect.AddRect(other.Rect)} | ||
| } | ||
|
|
||
| // R2RectFromCell constructs a rectangle that corresponds to the boundary of the given cell | ||
| // in (s,t)-space. Such rectangles are always a subset of [0,1]x[0,1]. | ||
| func R2RectFromCell(cell Cell) R2Rect { | ||
| size := cell.SizeST() | ||
| return R2Rect{r2.RectFromCenterSize(cell.id.centerST(), r2.Point{X: size, Y: size})} | ||
| } | ||
|
|
||
| // R2RectFromCellID constructs a rectangle that corresponds to the boundary of the given cell ID | ||
| // in (s,t)-space. Such rectangles are always a subset of [0,1]x[0,1]. | ||
| func R2RectFromCellID(id CellID) R2Rect { | ||
| size := id.sizeST(id.Level()) | ||
| return R2Rect{r2.RectFromCenterSize(id.centerST(), r2.Point{X: size, Y: size})} | ||
| } | ||
|
|
||
| func toPoint(p r2.Point) Point { | ||
| return Point{faceUVToXYZ(0, stToUV(p.X), stToUV(p.Y)).Normalize()} | ||
| } | ||
|
|
||
| // CapBound returns a Cap that bounds this rectangle. | ||
| func (r R2Rect) CapBound() Cap { | ||
| if r.IsEmpty() { | ||
| return EmptyCap() | ||
| } | ||
|
|
||
| // The rectangle is a convex polygon on the sphere, since it is a subset of | ||
| // one cube face. Its bounding cap is also a convex region on the sphere, | ||
| // and therefore we can bound the rectangle by just bounding its vertices. | ||
| // We use the rectangle's center in (s,t)-space as the cap axis. This | ||
| // doesn't yield the minimal cap but it's pretty close. | ||
| cap := CapFromPoint(toPoint(r.Center())) | ||
| for k := 0; k < 4; k++ { | ||
|
Collaborator
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. range? |
||
| cap = cap.AddPoint(toPoint(r.Vertex(k))) | ||
| } | ||
|
|
||
| return cap | ||
| } | ||
|
|
||
| // RectBound returns a bounding latitude-longitude rectangle. | ||
| // The bounds are not guaranteed to be tight. | ||
| func (r R2Rect) RectBound() Rect { | ||
| return r.CapBound().RectBound() | ||
| } | ||
|
|
||
| // CellUnionBound computes a covering of the rectangle. In general the covering | ||
| // consists of at most 4 cells except for very large rectangles, which may need | ||
| // up to 6 cells. The output is not sorted. | ||
| func (r R2Rect) CellUnionBound() []CellID { | ||
| return r.CapBound().CellUnionBound() | ||
| } | ||
|
|
||
| // ContainsPoint reports whether the rectangle contains the given point. | ||
| // Rectangles are closed regions, i.e. they contain their boundary. | ||
| func (r R2Rect) ContainsPoint(p Point) bool { | ||
| if face(p.Vector) != 0 { | ||
| return false | ||
| } | ||
|
|
||
| u, v := validFaceXYZToUV(0, p.Vector) | ||
| return r.Rect.ContainsPoint(r2.Point{X: u, Y: v}) | ||
|
Collaborator
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. Where's the UVtoST call and why is no test failing? |
||
| } | ||
|
|
||
| // ContainsCell reports whether the rectangle contains the given cell. | ||
| func (r R2Rect) ContainsCell(cell Cell) bool { | ||
| if cell.Face() != 0 { | ||
| return false | ||
| } | ||
|
|
||
| return r.Rect.Contains(R2RectFromCell(cell).Rect) | ||
| } | ||
|
|
||
| // MayIntersect reports whether the rectangle may intersect the given cell. | ||
| func (r R2Rect) MayIntersect(cell Cell) bool { | ||
| if cell.Face() != 0 { | ||
| return false | ||
| } | ||
|
|
||
| return r.Rect.Intersects(R2RectFromCell(cell).Rect) | ||
| } | ||
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.
Document all public methods. You can take inspiration from the cpp implementation at https://github.com/google/s2geometry/blob/ac448e2e939863dfefdeb6500ea74fda92d8187c/src/s2/r1interval.h#L172, but make sure you follow https://go.dev/doc/comment#func.