diff --git a/go.mod b/go.mod index 9ce5f351..d44e04f5 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/golang/geo -go 1.18 +go 1.21 + +require github.com/google/go-cmp v0.7.0 // indirect diff --git a/s1/chordangle.go b/s1/chordangle.go index fa2c409c..48de2228 100644 --- a/s1/chordangle.go +++ b/s1/chordangle.go @@ -29,7 +29,7 @@ import ( // There are several different ways to measure this error, including the // representational error (i.e., how accurately ChordAngle can represent // angles near π radians), the conversion error (i.e., how much precision is -// lost when an Angle is converted to an ChordAngle), and the measurement +// lost when an Angle is converted to a ChordAngle), and the measurement // error (i.e., how accurate the ChordAngle(a, b) constructor is when the // points A and B are separated by angles close to π radians). All of these // errors differ by a small constant factor. diff --git a/s2/builder_snapper.go b/s2/builder_snapper.go index 7def29d7..18ecba03 100644 --- a/s2/builder_snapper.go +++ b/s2/builder_snapper.go @@ -231,7 +231,7 @@ func (sf CellIDSnapper) minSnapRadiusForLevel(level int) s1.Angle { // snapRadius needs to be an upper bound on the true distance that a // point can move when snapped, taking into account numerical errors. // - // The maximum error when converting from an Point to a CellID is + // The maximum error when converting from a Point to a CellID is // MaxDiagMetric.Deriv * dblEpsilon. The maximum error when converting a // CellID center back to a Point is 1.5 * dblEpsilon. These add up to // just slightly less than 4 * dblEpsilon. @@ -248,7 +248,7 @@ func (sf CellIDSnapper) minSnapRadiusForLevel(level int) s1.Angle { // // sf := CellIDSnapperForLevel(f.levelForMaxSnapRadius(distance)); func (sf CellIDSnapper) levelForMaxSnapRadius(snapRadius s1.Angle) int { - // When choosing a level, we need to acount for the error bound of + // When choosing a level, we need to account for the error bound of // 4 * dblEpsilon that is added by MinSnapRadiusForLevel. return MaxDiagMetric.MinLevel(2 * (snapRadius.Radians() - 4*dblEpsilon)) } @@ -310,7 +310,7 @@ func (sf CellIDSnapper) MinEdgeVertexSeparation() s1.Angle { // (b) Otherwise, for arbitrary snap radii the worst-case configuration // in the plane has an edge-vertex separation of sqrt(3/19) * // MinDiagMetric.Value(level), where sqrt(3/19) is about 0.3973597071. The unit - // test verifies that the bound is slighty better on the sphere: + // test verifies that the bound is slightly better on the sphere: // 0.3973595687 * MinDiagMetric.Value(level). // // 2. Proportional bound: In the plane, the worst-case configuration has an @@ -434,7 +434,7 @@ func (sf IntLatLngSnapper) minSnapRadiusForExponent(exponent int) s1.Angle { // exponent for snapping. The return value is always a valid exponent (out of // range values are silently clamped). func (sf IntLatLngSnapper) exponentForMaxSnapRadius(snapRadius s1.Angle) int { - // When choosing an exponent, we need to acount for the error bound of + // When choosing an exponent, we need to account for the error bound of // (9 * sqrt(2) + 1.5) * dblEpsilon added by minSnapRadiusForExponent. snapRadius -= (9*math.Sqrt2 + 1.5) * dblEpsilon snapRadius = s1.Angle(math.Max(float64(snapRadius), 1e-30)) diff --git a/s2/cap_test.go b/s2/cap_test.go index 0331a156..2edd57f8 100644 --- a/s2/cap_test.go +++ b/s2/cap_test.go @@ -35,8 +35,8 @@ var ( fullHeight = 2.0 emptyHeight = -1.0 - xAxisPt = Point{r3.Vector{1, 0, 0}} - yAxisPt = Point{r3.Vector{0, 1, 0}} + xAxisPt = Point{r3.Vector{X: 1, Y: 0, Z: 0}} + yAxisPt = Point{r3.Vector{X: 0, Y: 1, Z: 0}} xAxis = CapFromPoint(xAxisPt) yAxis = CapFromPoint(yAxisPt) @@ -157,14 +157,14 @@ func TestCapContains(t *testing.T) { } func TestCapContainsPoint(t *testing.T) { - tangent := tiny.center.Cross(r3.Vector{3, 2, 1}).Normalize() + tangent := tiny.center.Cross(r3.Vector{X: 3, Y: 2, Z: 1}).Normalize() tests := []struct { c Cap p Point want bool }{ {xAxis, xAxisPt, true}, - {xAxis, Point{r3.Vector{1, 1e-20, 0}}, false}, + {xAxis, Point{r3.Vector{X: 1, Y: 1e-20, Z: 0}}, false}, {yAxis, xAxis.center, false}, {xComp, xAxis.center, true}, {xComp.Complement(), xAxis.center, false}, @@ -208,9 +208,9 @@ func TestCapInteriorIntersects(t *testing.T) { } func TestCapInteriorContains(t *testing.T) { - if hemi.InteriorContainsPoint(Point{r3.Vector{1, 0, -(1 + epsilon)}}) { + if hemi.InteriorContainsPoint(Point{r3.Vector{X: 1, Y: 0, Z: -(1 + epsilon)}}) { t.Errorf("hemi (%v) should not contain point just past half way(%v)", hemi, - Point{r3.Vector{1, 0, -(1 + epsilon)}}) + Point{r3.Vector{X: 1, Y: 0, Z: -(1 + epsilon)}}) } } @@ -316,7 +316,7 @@ func TestCapRectBounds(t *testing.T) { }, { "The eastern hemisphere.", - CapFromCenterAngle(Point{r3.Vector{0, 1, 0}}, s1.Radian*(math.Pi/2+2e-16)), + CapFromCenterAngle(Point{r3.Vector{X: 0, Y: 1, Z: 0}}, s1.Radian*(math.Pi/2+2e-16)), -90, 90, -180, 180, true, }, { @@ -376,34 +376,34 @@ func TestCapAddPoint(t *testing.T) { {yAxis, yAxisPt, yAxis}, // Cap plus opposite point equals full. - {xAxis, Point{r3.Vector{-1, 0, 0}}, fullCap}, - {yAxis, Point{r3.Vector{0, -1, 0}}, fullCap}, + {xAxis, Point{r3.Vector{X: -1, Y: 0, Z: 0}}, fullCap}, + {yAxis, Point{r3.Vector{X: 0, Y: -1, Z: 0}}, fullCap}, // Cap plus orthogonal axis equals half cap. - {xAxis, Point{r3.Vector{0, 0, 1}}, CapFromCenterAngle(xAxisPt, s1.Angle(math.Pi/2.0))}, - {xAxis, Point{r3.Vector{0, 0, -1}}, CapFromCenterAngle(xAxisPt, s1.Angle(math.Pi/2.0))}, + {xAxis, Point{r3.Vector{X: 0, Y: 0, Z: 1}}, CapFromCenterAngle(xAxisPt, s1.Angle(math.Pi/2.0))}, + {xAxis, Point{r3.Vector{X: 0, Y: 0, Z: -1}}, CapFromCenterAngle(xAxisPt, s1.Angle(math.Pi/2.0))}, // The 45 degree angled hemisphere plus some points. { hemi, PointFromCoords(0, 1, -1), - CapFromCenterAngle(Point{r3.Vector{1, 0, 1}}, + CapFromCenterAngle(Point{r3.Vector{X: 1, Y: 0, Z: 1}}, s1.Angle(120.0)*s1.Degree), }, { hemi, PointFromCoords(0, -1, -1), - CapFromCenterAngle(Point{r3.Vector{1, 0, 1}}, + CapFromCenterAngle(Point{r3.Vector{X: 1, Y: 0, Z: 1}}, s1.Angle(120.0)*s1.Degree), }, { hemi, PointFromCoords(-1, -1, -1), - CapFromCenterAngle(Point{r3.Vector{1, 0, 1}}, + CapFromCenterAngle(Point{r3.Vector{X: 1, Y: 0, Z: 1}}, s1.Angle(math.Acos(-math.Sqrt(2.0/3.0)))), }, - {hemi, Point{r3.Vector{0, 1, 1}}, hemi}, - {hemi, Point{r3.Vector{1, 0, 0}}, hemi}, + {hemi, Point{r3.Vector{X: 0, Y: 1, Z: 1}}, hemi}, + {hemi, Point{r3.Vector{X: 1, Y: 0, Z: 0}}, hemi}, } for _, test := range tests { @@ -684,8 +684,8 @@ func TestCapUnion(t *testing.T) { t.Errorf("%v.Radius = %v, want %v", aUnionE, got, want) } - p1 := Point{r3.Vector{0, 0, 1}} - p2 := Point{r3.Vector{0, 1, 0}} + p1 := Point{r3.Vector{X: 0, Y: 0, Z: 1}} + p2 := Point{r3.Vector{X: 0, Y: 1, Z: 0}} // Two very large caps, whose radius sums to in excess of 180 degrees, and // whose centers are not antipodal. f := CapFromCenterAngle(p1, s1.Degree*150) diff --git a/s2/cell.go b/s2/cell.go index 323167a3..6deb92f8 100644 --- a/s2/cell.go +++ b/s2/cell.go @@ -337,17 +337,17 @@ func (c Cell) RectBound() Rect { var bound Rect switch c.face { case 0: - bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{-math.Pi / 4, math.Pi / 4}} + bound = Rect{r1.Interval{Lo: -math.Pi / 4, Hi: math.Pi / 4}, s1.Interval{Lo: -math.Pi / 4, Hi: math.Pi / 4}} case 1: - bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{math.Pi / 4, 3 * math.Pi / 4}} + bound = Rect{r1.Interval{Lo: -math.Pi / 4, Hi: math.Pi / 4}, s1.Interval{Lo: math.Pi / 4, Hi: 3 * math.Pi / 4}} case 2: - bound = Rect{r1.Interval{poleMinLat, math.Pi / 2}, s1.FullInterval()} + bound = Rect{r1.Interval{Lo: poleMinLat, Hi: math.Pi / 2}, s1.FullInterval()} case 3: - bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{3 * math.Pi / 4, -3 * math.Pi / 4}} + bound = Rect{r1.Interval{Lo: -math.Pi / 4, Hi: math.Pi / 4}, s1.Interval{Lo: 3 * math.Pi / 4, Hi: -3 * math.Pi / 4}} case 4: - bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{-3 * math.Pi / 4, -math.Pi / 4}} + bound = Rect{r1.Interval{Lo: -math.Pi / 4, Hi: math.Pi / 4}, s1.Interval{Lo: -3 * math.Pi / 4, Hi: -math.Pi / 4}} default: - bound = Rect{r1.Interval{-math.Pi / 2, -poleMinLat}, s1.FullInterval()} + bound = Rect{r1.Interval{Lo: -math.Pi / 2, Hi: -poleMinLat}, s1.FullInterval()} } // Finally, we expand the bound to account for the error when a point P is @@ -456,8 +456,8 @@ func (c Cell) uEdgeIsClosest(p Point, vHi bool) bool { } // These are the normals to the planes that are perpendicular to the edge // and pass through one of its two endpoints. - dir0 := r3.Vector{v*v + 1, -u0 * v, -u0} - dir1 := r3.Vector{v*v + 1, -u1 * v, -u1} + dir0 := r3.Vector{X: v*v + 1, Y: -u0 * v, Z: -u0} + dir1 := r3.Vector{X: v*v + 1, Y: -u1 * v, Z: -u1} return p.Dot(dir0) > 0 && p.Dot(dir1) < 0 } @@ -470,8 +470,8 @@ func (c Cell) vEdgeIsClosest(p Point, uHi bool) bool { if uHi { u = c.uv.X.Hi } - dir0 := r3.Vector{-u * v0, u*u + 1, -v0} - dir1 := r3.Vector{-u * v1, u*u + 1, -v1} + dir0 := r3.Vector{X: -u * v0, Y: u*u + 1, Z: -v0} + dir1 := r3.Vector{X: -u * v1, Y: u*u + 1, Z: -v1} return p.Dot(dir0) > 0 && p.Dot(dir1) < 0 } @@ -682,7 +682,7 @@ func (c Cell) MaxDistanceToCell(target Cell) s1.ChordAngle { // Need to check the antipodal target for intersection with the cell. If it // intersects, the distance is the straight ChordAngle. // antipodalUV is the transpose of the original UV, interpreted within the opposite face. - antipodalUV := r2.Rect{target.uv.Y, target.uv.X} + antipodalUV := r2.Rect{X: target.uv.Y, Y: target.uv.X} if int(c.face) == oppositeFace(int(target.face)) && c.uv.Intersects(antipodalUV) { return s1.StraightChordAngle } diff --git a/s2/cell_test.go b/s2/cell_test.go index bb112981..56896042 100644 --- a/s2/cell_test.go +++ b/s2/cell_test.go @@ -236,11 +236,11 @@ func testCellChildren(t *testing.T, cell Cell) { // where the cell size at a given level is maximal. maxSizeUV := 0.3964182625366691 specialUV := []r2.Point{ - {dblEpsilon, dblEpsilon}, // Face center - {dblEpsilon, 1}, // Edge midpoint - {1, 1}, // Face corner - {maxSizeUV, maxSizeUV}, // Largest cell area - {dblEpsilon, maxSizeUV}, // Longest edge/diagonal + {X: dblEpsilon, Y: dblEpsilon}, // Face center + {X: dblEpsilon, Y: 1}, // Edge midpoint + {X: 1, Y: 1}, // Face corner + {X: maxSizeUV, Y: maxSizeUV}, // Largest cell area + {X: dblEpsilon, Y: maxSizeUV}, // Longest edge/diagonal } forceSubdivide := false for _, uv := range specialUV { diff --git a/s2/cellid.go b/s2/cellid.go index 46e27d79..218dceeb 100644 --- a/s2/cellid.go +++ b/s2/cellid.go @@ -650,7 +650,7 @@ func stToIJ(s float64) int { // // is always true. func cellIDFromPoint(p Point) CellID { - f, u, v := xyzToFaceUV(r3.Vector{p.X, p.Y, p.Z}) + f, u, v := xyzToFaceUV(r3.Vector{X: p.X, Y: p.Y, Z: p.Z}) i := stToIJ(uvToST(u)) j := stToIJ(uvToST(v)) return cellIDFromFaceIJ(f, i, j) @@ -788,7 +788,7 @@ func (ci CellID) Advance(steps int64) CellID { // centerST return the center of the CellID in (s,t)-space. func (ci CellID) centerST() r2.Point { _, si, ti := ci.faceSiTi() - return r2.Point{siTiToST(si), siTiToST(ti)} + return r2.Point{X: siTiToST(si), Y: siTiToST(ti)} } // sizeST returns the edge length of this CellID in (s,t)-space at the given level. @@ -799,7 +799,7 @@ func (ci CellID) sizeST(level int) float64 { // boundST returns the bound of this CellID in (s,t)-space. func (ci CellID) boundST() r2.Rect { s := ci.sizeST(ci.Level()) - return r2.RectFromCenterSize(ci.centerST(), r2.Point{s, s}) + return r2.RectFromCenterSize(ci.centerST(), r2.Point{X: s, Y: s}) } // centerUV returns the center of this CellID in (u,v)-space. Note that @@ -808,7 +808,7 @@ func (ci CellID) boundST() r2.Rect { // the (u,v) rectangle covered by the cell. func (ci CellID) centerUV() r2.Point { _, si, ti := ci.faceSiTi() - return r2.Point{stToUV(siTiToST(si)), stToUV(siTiToST(ti))} + return r2.Point{X: stToUV(siTiToST(si)), Y: stToUV(siTiToST(ti))} } // boundUV returns the bound of this CellID in (u,v)-space. @@ -837,7 +837,7 @@ func expandEndpoint(u, maxV, sinDist float64) float64 { // of the boundary. // // Distances are measured *on the sphere*, not in (u,v)-space. For example, -// you can use this method to expand the (u,v)-bound of an CellID so that +// you can use this method to expand the (u,v)-bound of a CellID so that // it contains all points within 5km of the original cell. You can then // test whether a point lies within the expanded bounds like this: // @@ -862,10 +862,10 @@ func expandedByDistanceUV(uv r2.Rect, distance s1.Angle) r2.Rect { maxV := math.Max(math.Abs(uv.Y.Lo), math.Abs(uv.Y.Hi)) sinDist := math.Sin(float64(distance)) return r2.Rect{ - X: r1.Interval{expandEndpoint(uv.X.Lo, maxV, -sinDist), - expandEndpoint(uv.X.Hi, maxV, sinDist)}, - Y: r1.Interval{expandEndpoint(uv.Y.Lo, maxU, -sinDist), - expandEndpoint(uv.Y.Hi, maxU, sinDist)}} + X: r1.Interval{Lo: expandEndpoint(uv.X.Lo, maxV, -sinDist), + Hi: expandEndpoint(uv.X.Hi, maxV, sinDist)}, + Y: r1.Interval{Lo: expandEndpoint(uv.Y.Lo, maxU, -sinDist), + Hi: expandEndpoint(uv.Y.Hi, maxU, sinDist)}} } // MaxTile returns the largest cell with the same RangeMin such that diff --git a/s2/cellid_test.go b/s2/cellid_test.go index beec1e47..923b57df 100644 --- a/s2/cellid_test.go +++ b/s2/cellid_test.go @@ -428,81 +428,81 @@ func TestIJLevelToBoundUV(t *testing.T) { // What should be out of bounds values, but passes the C++ code as well. { -1, -1, 0, - r2.RectFromPoints(r2.Point{-5, -5}, r2.Point{-1, -1}), + r2.RectFromPoints(r2.Point{X: -5, Y: -5}, r2.Point{X: -1, Y: -1}), }, { -1 * maxIJ, -1 * maxIJ, 0, - r2.RectFromPoints(r2.Point{-5, -5}, r2.Point{-1, -1}), + r2.RectFromPoints(r2.Point{X: -5, Y: -5}, r2.Point{X: -1, Y: -1}), }, { -1, -1, MaxLevel, - r2.RectFromPoints(r2.Point{-1.0000000024835267, -1.0000000024835267}, - r2.Point{-1, -1}), + r2.RectFromPoints(r2.Point{X: -1.0000000024835267, Y: -1.0000000024835267}, + r2.Point{X: -1, Y: -1}), }, { 0, 0, MaxLevel + 1, - r2.RectFromPoints(r2.Point{-1, -1}, r2.Point{-1, -1}), + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, r2.Point{X: -1, Y: -1}), }, // Minimum i,j at different levels { 0, 0, 0, - r2.RectFromPoints(r2.Point{-1, -1}, r2.Point{1, 1}), + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, r2.Point{X: 1, Y: 1}), }, { 0, 0, MaxLevel / 2, - r2.RectFromPoints(r2.Point{-1, -1}, - r2.Point{-0.999918621033430099, -0.999918621033430099}), + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, + r2.Point{X: -0.999918621033430099, Y: -0.999918621033430099}), }, { 0, 0, MaxLevel, - r2.RectFromPoints(r2.Point{-1, -1}, - r2.Point{-0.999999997516473060, -0.999999997516473060}), + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, + r2.Point{X: -0.999999997516473060, Y: -0.999999997516473060}), }, // Just a hair off the outer bounds at different levels. { 1, 1, 0, - r2.RectFromPoints(r2.Point{-1, -1}, r2.Point{1, 1}), + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, r2.Point{X: 1, Y: 1}), }, { 1, 1, MaxLevel / 2, - r2.RectFromPoints(r2.Point{-1, -1}, - r2.Point{-0.999918621033430099, -0.999918621033430099}), + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, + r2.Point{X: -0.999918621033430099, Y: -0.999918621033430099}), }, { 1, 1, MaxLevel, - r2.RectFromPoints(r2.Point{-0.9999999975164731, -0.9999999975164731}, - r2.Point{-0.9999999950329462, -0.9999999950329462}), + r2.RectFromPoints(r2.Point{X: -0.9999999975164731, Y: -0.9999999975164731}, + r2.Point{X: -0.9999999950329462, Y: -0.9999999950329462}), }, // Center point of the i,j space at different levels. { maxIJ / 2, maxIJ / 2, 0, - r2.RectFromPoints(r2.Point{-1, -1}, r2.Point{1, 1})}, + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, r2.Point{X: 1, Y: 1})}, { maxIJ / 2, maxIJ / 2, MaxLevel / 2, - r2.RectFromPoints(r2.Point{-0.000040691345930099, -0.000040691345930099}, - r2.Point{0, 0})}, + r2.RectFromPoints(r2.Point{X: -0.000040691345930099, Y: -0.000040691345930099}, + r2.Point{X: 0, Y: 0})}, { maxIJ / 2, maxIJ / 2, MaxLevel, - r2.RectFromPoints(r2.Point{-0.000000001241763433, -0.000000001241763433}, - r2.Point{0, 0})}, + r2.RectFromPoints(r2.Point{X: -0.000000001241763433, Y: -0.000000001241763433}, + r2.Point{X: 0, Y: 0})}, // Maximum i, j at different levels. { maxIJ, maxIJ, 0, - r2.RectFromPoints(r2.Point{-1, -1}, r2.Point{1, 1}), + r2.RectFromPoints(r2.Point{X: -1, Y: -1}, r2.Point{X: 1, Y: 1}), }, { maxIJ, maxIJ, MaxLevel / 2, - r2.RectFromPoints(r2.Point{0.999918621033430099, 0.999918621033430099}, - r2.Point{1, 1}), + r2.RectFromPoints(r2.Point{X: 0.999918621033430099, Y: 0.999918621033430099}, + r2.Point{X: 1, Y: 1}), }, { maxIJ, maxIJ, MaxLevel, - r2.RectFromPoints(r2.Point{0.999999997516473060, 0.999999997516473060}, - r2.Point{1, 1}), + r2.RectFromPoints(r2.Point{X: 0.999999997516473060, Y: 0.999999997516473060}, + r2.Point{X: 1, Y: 1}), }, } @@ -855,16 +855,16 @@ func projectToBoundary(u, v float64, rect r2.Rect) r2.Point { dmin := math.Min(math.Min(du0, du1), math.Min(dv0, dv1)) if du0 == dmin { - return r2.Point{rect.X.Lo, rect.Y.ClampPoint(v)} + return r2.Point{X: rect.X.Lo, Y: rect.Y.ClampPoint(v)} } if du1 == dmin { - return r2.Point{rect.X.Hi, rect.Y.ClampPoint(v)} + return r2.Point{X: rect.X.Hi, Y: rect.Y.ClampPoint(v)} } if dv0 == dmin { - return r2.Point{rect.X.ClampPoint(u), rect.Y.Lo} + return r2.Point{X: rect.X.ClampPoint(u), Y: rect.Y.Lo} } - return r2.Point{rect.X.ClampPoint(u), rect.Y.Hi} + return r2.Point{X: rect.X.ClampPoint(u), Y: rect.Y.Hi} } func TestCellIDExpandedByDistanceUV(t *testing.T) { @@ -890,7 +890,7 @@ func TestCellIDExpandedByDistanceUV(t *testing.T) { continue } - uv := r2.Point{u, v} + uv := r2.Point{X: u, Y: v} closestUV := projectToBoundary(u, v, bound) closest := faceUVToXYZ(face, closestUV.X, closestUV.Y).Normalize() actualDist := p.Distance(Point{closest}) diff --git a/s2/cellunion_test.go b/s2/cellunion_test.go index 193c0b01..16219b6a 100644 --- a/s2/cellunion_test.go +++ b/s2/cellunion_test.go @@ -585,8 +585,8 @@ func TestCellUnionRectBound(t *testing.T) { { &CellUnion{CellIDFromFace(1)}, Rect{ - r1.Interval{-math.Pi / 4, math.Pi / 4}, - s1.Interval{math.Pi / 4, 3 * math.Pi / 4}, + r1.Interval{Lo: -math.Pi / 4, Hi: math.Pi / 4}, + s1.Interval{Lo: math.Pi / 4, Hi: 3 * math.Pi / 4}, }, }, { @@ -595,12 +595,12 @@ func TestCellUnionRectBound(t *testing.T) { }, Rect{ r1.Interval{ - float64(s1.Degree * 34.644220547108482), - float64(s1.Degree * 38.011928357226651), + Lo: float64(s1.Degree * 34.644220547108482), + Hi: float64(s1.Degree * 38.011928357226651), }, s1.Interval{ - float64(s1.Degree * -124.508522987668428), - float64(s1.Degree * -121.628309835221216), + Lo: float64(s1.Degree * -124.508522987668428), + Hi: float64(s1.Degree * -121.628309835221216), }, }, }, @@ -610,12 +610,12 @@ func TestCellUnionRectBound(t *testing.T) { }, Rect{ r1.Interval{ - float64(s1.Degree * 38.794595155857657), - float64(s1.Degree * 41.747046884651063), + Lo: float64(s1.Degree * 38.794595155857657), + Hi: float64(s1.Degree * 41.747046884651063), }, s1.Interval{ - float64(s1.Degree * -76.456308667788633), - float64(s1.Degree * -73.465162142654819), + Lo: float64(s1.Degree * -76.456308667788633), + Hi: float64(s1.Degree * -73.465162142654819), }, }, }, @@ -626,12 +626,12 @@ func TestCellUnionRectBound(t *testing.T) { }, Rect{ r1.Interval{ - float64(s1.Degree * 34.644220547108482), - float64(s1.Degree * 41.747046884651063), + Lo: float64(s1.Degree * 34.644220547108482), + Hi: float64(s1.Degree * 41.747046884651063), }, s1.Interval{ - float64(s1.Degree * -124.508522987668428), - float64(s1.Degree * -73.465162142654819), + Lo: float64(s1.Degree * -124.508522987668428), + Hi: float64(s1.Degree * -73.465162142654819), }, }, }, diff --git a/s2/centroids.go b/s2/centroids.go index e8a91c44..0e4e95cb 100644 --- a/s2/centroids.go +++ b/s2/centroids.go @@ -89,12 +89,12 @@ func TrueCentroid(a, b, c Point) Point { // This code still isn't as numerically stable as it could be. // The biggest potential improvement is to compute B-A and C-A more // accurately so that (B-A)x(C-A) is always inside triangle ABC. - x := r3.Vector{a.X, b.X - a.X, c.X - a.X} - y := r3.Vector{a.Y, b.Y - a.Y, c.Y - a.Y} - z := r3.Vector{a.Z, b.Z - a.Z, c.Z - a.Z} - r := r3.Vector{ra, rb - ra, rc - ra} + x := r3.Vector{X: a.X, Y: b.X - a.X, Z: c.X - a.X} + y := r3.Vector{X: a.Y, Y: b.Y - a.Y, Z: c.Y - a.Y} + z := r3.Vector{X: a.Z, Y: b.Z - a.Z, Z: c.Z - a.Z} + r := r3.Vector{X: ra, Y: rb - ra, Z: rc - ra} - return Point{r3.Vector{y.Cross(z).Dot(r), z.Cross(x).Dot(r), x.Cross(y).Dot(r)}.Mul(0.5)} + return Point{r3.Vector{X: y.Cross(z).Dot(r), Y: z.Cross(x).Dot(r), Z: x.Cross(y).Dot(r)}.Mul(0.5)} } // EdgeTrueCentroid returns the true centroid of the spherical geodesic edge AB diff --git a/s2/centroids_test.go b/s2/centroids_test.go index 2841b007..1cf82754 100644 --- a/s2/centroids_test.go +++ b/s2/centroids_test.go @@ -28,17 +28,17 @@ func TestCentroidsPlanarCentroid(t *testing.T) { }{ { name: "xyz axis", - p0: Point{r3.Vector{0, 0, 1}}, - p1: Point{r3.Vector{0, 1, 0}}, - p2: Point{r3.Vector{1, 0, 0}}, - want: Point{r3.Vector{1. / 3, 1. / 3, 1. / 3}}, + p0: Point{r3.Vector{X: 0, Y: 0, Z: 1}}, + p1: Point{r3.Vector{X: 0, Y: 1, Z: 0}}, + p2: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + want: Point{r3.Vector{X: 1. / 3, Y: 1. / 3, Z: 1. / 3}}, }, { name: "Same point", - p0: Point{r3.Vector{1, 0, 0}}, - p1: Point{r3.Vector{1, 0, 0}}, - p2: Point{r3.Vector{1, 0, 0}}, - want: Point{r3.Vector{1, 0, 0}}, + p0: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + p1: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + p2: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + want: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, }, } diff --git a/s2/crossing_edge_query.go b/s2/crossing_edge_query.go index 51852dab..bf2dde9c 100644 --- a/s2/crossing_edge_query.go +++ b/s2/crossing_edge_query.go @@ -356,7 +356,7 @@ func (c *CrossingEdgeQuery) clipVAxis(edgeBound r2.Rect, center float64, i int, } } -// splitUBound returns the bound for two children as a result of spliting the +// splitUBound returns the bound for two children as a result of splitting the // current edge at the given value U. func (c *CrossingEdgeQuery) splitUBound(edgeBound r2.Rect, u float64) [2]r2.Rect { v := edgeBound.Y.ClampPoint(interpolateFloat64(u, c.a.X, c.b.X, c.a.Y, c.b.Y)) @@ -369,7 +369,7 @@ func (c *CrossingEdgeQuery) splitUBound(edgeBound r2.Rect, u float64) [2]r2.Rect return splitBound(edgeBound, 0, diag, u, v) } -// splitVBound returns the bound for two children as a result of spliting the +// splitVBound returns the bound for two children as a result of splitting the // current edge into two child edges at the given value V. func (c *CrossingEdgeQuery) splitVBound(edgeBound r2.Rect, v float64) [2]r2.Rect { u := edgeBound.X.ClampPoint(interpolateFloat64(v, c.a.Y, c.b.Y, c.a.X, c.b.X)) @@ -380,7 +380,7 @@ func (c *CrossingEdgeQuery) splitVBound(edgeBound r2.Rect, v float64) [2]r2.Rect return splitBound(edgeBound, diag, 0, u, v) } -// splitBound returns the bounds for the two childrenn as a result of spliting +// splitBound returns the bounds for the two childrenn as a result of splitting // the current edge into two child edges at the given point (u,v). uEnd and vEnd // indicate which bound endpoints of the first child will be updated. func splitBound(edgeBound r2.Rect, uEnd, vEnd int, u, v float64) [2]r2.Rect { diff --git a/s2/edge_clipping.go b/s2/edge_clipping.go index 4389139d..d4ce20ea 100644 --- a/s2/edge_clipping.go +++ b/s2/edge_clipping.go @@ -89,7 +89,7 @@ func ClipToPaddedFace(a, b Point, f int, padding float64) (aUV, bUV r2.Point, in if face(a.Vector) == f && face(b.Vector) == f { au, av := validFaceXYZToUV(f, a.Vector) bu, bv := validFaceXYZToUV(f, b.Vector) - return r2.Point{au, av}, r2.Point{bu, bv}, true + return r2.Point{X: au, Y: av}, r2.Point{X: bu, Y: bv}, true } // Convert everything into the (u,v,w) coordinates of the given face. Note @@ -283,14 +283,14 @@ func (p pointUVW) exitPoint(a axis) r2.Point { if p.Y > 0 { u = 1.0 } - return r2.Point{u, (-u*p.X - p.Z) / p.Y} + return r2.Point{X: u, Y: (-u*p.X - p.Z) / p.Y} } v := -1.0 if p.X < 0 { v = 1.0 } - return r2.Point{(-v*p.Y - p.Z) / p.X, v} + return r2.Point{X: (-v*p.Y - p.Z) / p.X, Y: v} } // clipDestination returns a score which is used to indicate if the clipped edge AB @@ -310,7 +310,7 @@ func clipDestination(a, b, scaledN, aTan, bTan pointUVW, scaleUV float64) (r2.Po // Optimization: if B is within the safe region of the face, use it. maxSafeUVCoord := 1 - faceClipErrorUVCoord if b.Z > 0 { - uv = r2.Point{b.X / b.Z, b.Y / b.Z} + uv = r2.Point{X: b.X / b.Z, Y: b.Y / b.Z} if math.Max(math.Abs(uv.X), math.Abs(uv.Y)) <= maxSafeUVCoord { return uv, 0 } @@ -319,7 +319,7 @@ func clipDestination(a, b, scaledN, aTan, bTan pointUVW, scaleUV float64) (r2.Po // Otherwise find the point B' where the line AB exits the face. uv = scaledN.exitPoint(scaledN.exitAxis()).Mul(scaleUV) - p := pointUVW(Point{r3.Vector{uv.X, uv.Y, 1.0}}) + p := pointUVW(Point{r3.Vector{X: uv.X, Y: uv.Y, Z: 1.0}}) // Determine if the exit point B' is contained within the segment. We do this // by computing the dot products with two inward-facing tangent vectors at A @@ -351,7 +351,7 @@ func clipDestination(a, b, scaledN, aTan, bTan pointUVW, scaleUV float64) (r2.Po if b.Z <= 0 { score = 3 // B cannot be projected onto this face. } else { - uv = r2.Point{b.X / b.Z, b.Y / b.Z} + uv = r2.Point{X: b.X / b.Z, Y: b.Y / b.Z} } } @@ -475,7 +475,7 @@ func clipEdgeBound(a, b r2.Point, clip, bound r2.Rect) (r2.Rect, bool) { } b1y, b1x, up2 := clipBoundAxis(a.Y, b.Y, b0y, a.X, b.X, b0x, negSlope, clip.Y) if !up2 { - return r2.Rect{b0x, b0y}, false + return r2.Rect{X: b0x, Y: b0y}, false } return r2.Rect{X: b1x, Y: b1y}, true } @@ -563,7 +563,7 @@ func FaceSegments(a, b Point) []FaceSegment { face = nextFace(face, segment.b, exitAxis, n, bFace) exitUvw := faceXYZtoUVW(face, Point{exitXyz}) segment.face = face - segment.a = r2.Point{exitUvw.X, exitUvw.Y} + segment.a = r2.Point{X: exitUvw.X, Y: exitUvw.Y} } // Finish the last segment. segment.b = bSaved diff --git a/s2/edge_clipping_test.go b/s2/edge_clipping_test.go index addd6f53..3b530a55 100644 --- a/s2/edge_clipping_test.go +++ b/s2/edge_clipping_test.go @@ -30,12 +30,12 @@ func TestEdgeClippingIntersectsFace(t *testing.T) { a pointUVW want bool }{ - {pointUVW{r3.Vector{2.05335e-06, 3.91604e-22, 2.90553e-06}}, false}, - {pointUVW{r3.Vector{-3.91604e-22, -2.05335e-06, -2.90553e-06}}, false}, - {pointUVW{r3.Vector{0.169258, -0.169258, 0.664013}}, false}, - {pointUVW{r3.Vector{0.169258, -0.169258, -0.664013}}, false}, - {pointUVW{r3.Vector{math.Sqrt(2.0 / 3.0), -math.Sqrt(2.0 / 3.0), 3.88578e-16}}, true}, - {pointUVW{r3.Vector{-3.88578e-16, -math.Sqrt(2.0 / 3.0), math.Sqrt(2.0 / 3.0)}}, true}, + {pointUVW{r3.Vector{X: 2.05335e-06, Y: 3.91604e-22, Z: 2.90553e-06}}, false}, + {pointUVW{r3.Vector{X: -3.91604e-22, Y: -2.05335e-06, Z: -2.90553e-06}}, false}, + {pointUVW{r3.Vector{X: 0.169258, Y: -0.169258, Z: 0.664013}}, false}, + {pointUVW{r3.Vector{X: 0.169258, Y: -0.169258, Z: -0.664013}}, false}, + {pointUVW{r3.Vector{X: math.Sqrt(2.0 / 3.0), Y: -math.Sqrt(2.0 / 3.0), Z: 3.88578e-16}}, true}, + {pointUVW{r3.Vector{X: -3.88578e-16, Y: -math.Sqrt(2.0 / 3.0), Z: math.Sqrt(2.0 / 3.0)}}, true}, } for _, test := range tests { @@ -50,14 +50,14 @@ func TestEdgeClippingIntersectsOppositeEdges(t *testing.T) { a pointUVW want bool }{ - {pointUVW{r3.Vector{0.169258, -0.169258, 0.664013}}, false}, - {pointUVW{r3.Vector{0.169258, -0.169258, -0.664013}}, false}, + {pointUVW{r3.Vector{X: 0.169258, Y: -0.169258, Z: 0.664013}}, false}, + {pointUVW{r3.Vector{X: 0.169258, Y: -0.169258, Z: -0.664013}}, false}, - {pointUVW{r3.Vector{-math.Sqrt(4.0 / 3.0), 0, -math.Sqrt(4.0 / 3.0)}}, true}, - {pointUVW{r3.Vector{math.Sqrt(4.0 / 3.0), 0, math.Sqrt(4.0 / 3.0)}}, true}, + {pointUVW{r3.Vector{X: -math.Sqrt(4.0 / 3.0), Y: 0, Z: -math.Sqrt(4.0 / 3.0)}}, true}, + {pointUVW{r3.Vector{X: math.Sqrt(4.0 / 3.0), Y: 0, Z: math.Sqrt(4.0 / 3.0)}}, true}, - {pointUVW{r3.Vector{-math.Sqrt(2.0 / 3.0), -math.Sqrt(2.0 / 3.0), 1.66533453694e-16}}, false}, - {pointUVW{r3.Vector{math.Sqrt(2.0 / 3.0), math.Sqrt(2.0 / 3.0), -1.66533453694e-16}}, false}, + {pointUVW{r3.Vector{X: -math.Sqrt(2.0 / 3.0), Y: -math.Sqrt(2.0 / 3.0), Z: 1.66533453694e-16}}, false}, + {pointUVW{r3.Vector{X: math.Sqrt(2.0 / 3.0), Y: math.Sqrt(2.0 / 3.0), Z: -1.66533453694e-16}}, false}, } for _, test := range tests { if got := test.a.intersectsOppositeEdges(); got != test.want { @@ -71,13 +71,13 @@ func TestEdgeClippingExitAxis(t *testing.T) { a pointUVW want axis }{ - {pointUVW{r3.Vector{0, -math.Sqrt(2.0 / 3.0), math.Sqrt(2.0 / 3.0)}}, axisU}, - {pointUVW{r3.Vector{0, math.Sqrt(4.0 / 3.0), -math.Sqrt(4.0 / 3.0)}}, axisU}, - {pointUVW{r3.Vector{-math.Sqrt(4.0 / 3.0), -math.Sqrt(4.0 / 3.0), 0}}, axisV}, - {pointUVW{r3.Vector{math.Sqrt(4.0 / 3.0), math.Sqrt(4.0 / 3.0), 0}}, axisV}, - {pointUVW{r3.Vector{math.Sqrt(2.0 / 3.0), -math.Sqrt(2.0 / 3.0), 0}}, axisV}, - {pointUVW{r3.Vector{1.67968702783622, 0, 0.870988820096491}}, axisV}, - {pointUVW{r3.Vector{0, math.Sqrt2, math.Sqrt2}}, axisU}, + {pointUVW{r3.Vector{X: 0, Y: -math.Sqrt(2.0 / 3.0), Z: math.Sqrt(2.0 / 3.0)}}, axisU}, + {pointUVW{r3.Vector{X: 0, Y: math.Sqrt(4.0 / 3.0), Z: -math.Sqrt(4.0 / 3.0)}}, axisU}, + {pointUVW{r3.Vector{X: -math.Sqrt(4.0 / 3.0), Y: -math.Sqrt(4.0 / 3.0), Z: 0}}, axisV}, + {pointUVW{r3.Vector{X: math.Sqrt(4.0 / 3.0), Y: math.Sqrt(4.0 / 3.0), Z: 0}}, axisV}, + {pointUVW{r3.Vector{X: math.Sqrt(2.0 / 3.0), Y: -math.Sqrt(2.0 / 3.0), Z: 0}}, axisV}, + {pointUVW{r3.Vector{X: 1.67968702783622, Y: 0, Z: 0.870988820096491}}, axisV}, + {pointUVW{r3.Vector{X: 0, Y: math.Sqrt2, Z: math.Sqrt2}}, axisU}, } for _, test := range tests { @@ -93,10 +93,10 @@ func TestEdgeClippingExitPoint(t *testing.T) { exitAxis axis want r2.Point }{ - {pointUVW{r3.Vector{-3.88578058618805e-16, -math.Sqrt(2.0 / 3.0), math.Sqrt(2.0 / 3.0)}}, axisU, r2.Point{-1, 1}}, - {pointUVW{r3.Vector{math.Sqrt(4.0 / 3.0), -math.Sqrt(4.0 / 3.0), 0}}, axisV, r2.Point{-1, -1}}, - {pointUVW{r3.Vector{-math.Sqrt(4.0 / 3.0), -math.Sqrt(4.0 / 3.0), 0}}, axisV, r2.Point{-1, 1}}, - {pointUVW{r3.Vector{-6.66134e-16, math.Sqrt(4.0 / 3.0), -math.Sqrt(4.0 / 3.0)}}, axisU, r2.Point{1, 1}}, + {pointUVW{r3.Vector{X: -3.88578058618805e-16, Y: -math.Sqrt(2.0 / 3.0), Z: math.Sqrt(2.0 / 3.0)}}, axisU, r2.Point{X: -1, Y: 1}}, + {pointUVW{r3.Vector{X: math.Sqrt(4.0 / 3.0), Y: -math.Sqrt(4.0 / 3.0), Z: 0}}, axisV, r2.Point{X: -1, Y: -1}}, + {pointUVW{r3.Vector{X: -math.Sqrt(4.0 / 3.0), Y: -math.Sqrt(4.0 / 3.0), Z: 0}}, axisV, r2.Point{X: -1, Y: 1}}, + {pointUVW{r3.Vector{X: -6.66134e-16, Y: math.Sqrt(4.0 / 3.0), Z: -math.Sqrt(4.0 / 3.0)}}, axisU, r2.Point{X: 1, Y: 1}}, } for _, test := range tests { @@ -128,7 +128,7 @@ func testClipToPaddedFace(t *testing.T, a, b Point) { t.Errorf("FaceSegments(%v, %v) should have generated at least one entry", a, b) } - biunit := r2.Rect{r1.Interval{-1, 1}, r1.Interval{-1, 1}} + biunit := r2.Rect{X: r1.Interval{Lo: -1, Hi: 1}, Y: r1.Interval{Lo: -1, Hi: 1}} const errorRadians = faceClipErrorRadians // The first and last vertices should approximately equal A and B. @@ -190,9 +190,9 @@ func testClipToPaddedFace(t *testing.T, a, b Point) { // Given the points A and B, we expect all angles generated from the clipping // to fall within this range. - expectedAngles := s1.Interval{0, float64(a.Angle(b.Vector))} + expectedAngles := s1.Interval{Lo: 0, Hi: float64(a.Angle(b.Vector))} if expectedAngles.IsInverted() { - expectedAngles = s1.Interval{expectedAngles.Hi, expectedAngles.Lo} + expectedAngles = s1.Interval{Lo: expectedAngles.Hi, Hi: expectedAngles.Lo} } maxAngles := expectedAngles.Expanded(faceClipErrorRadians) var actualAngles s1.Interval @@ -234,7 +234,7 @@ func testClipToPaddedFace(t *testing.T, a, b Point) { // which is okay since the interval length is much less than math.Pi. faceAngles := s1.IntervalFromEndpoints(aAngle, bAngle) if faceAngles.IsInverted() { - faceAngles = s1.Interval{faceAngles.Hi, faceAngles.Lo} + faceAngles = s1.Interval{Lo: faceAngles.Hi, Hi: faceAngles.Lo} } if !maxAngles.ContainsInterval(faceAngles) { t.Errorf("%s %v.ContainsInterval(%v) = false, but should have contained this interval", desc, maxAngles, faceAngles) @@ -249,24 +249,24 @@ func testClipToPaddedFace(t *testing.T, a, b Point) { func TestEdgeClippingClipToPaddedFace(t *testing.T) { // Start with a few simple cases. // An edge that is entirely contained within one cube face: - testClipToPaddedFace(t, Point{r3.Vector{1, -0.5, -0.5}}, Point{r3.Vector{1, 0.5, 0.5}}) - testClipToPaddedFace(t, Point{r3.Vector{1, 0.5, 0.5}}, Point{r3.Vector{1, -0.5, -0.5}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 1, Y: -0.5, Z: -0.5}}, Point{r3.Vector{X: 1, Y: 0.5, Z: 0.5}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 1, Y: 0.5, Z: 0.5}}, Point{r3.Vector{X: 1, Y: -0.5, Z: -0.5}}) // An edge that crosses one cube edge: - testClipToPaddedFace(t, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, 1, 0}}) - testClipToPaddedFace(t, Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{1, 0, 0}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 1, Y: 0, Z: 0}}, Point{r3.Vector{X: 0, Y: 1, Z: 0}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 0, Y: 1, Z: 0}}, Point{r3.Vector{X: 1, Y: 0, Z: 0}}) // An edge that crosses two opposite edges of face 0: - testClipToPaddedFace(t, Point{r3.Vector{0.75, 0, -1}}, Point{r3.Vector{0.75, 0, 1}}) - testClipToPaddedFace(t, Point{r3.Vector{0.75, 0, 1}}, Point{r3.Vector{0.75, 0, -1}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 0.75, Y: 0, Z: -1}}, Point{r3.Vector{X: 0.75, Y: 0, Z: 1}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 0.75, Y: 0, Z: 1}}, Point{r3.Vector{X: 0.75, Y: 0, Z: -1}}) // An edge that crosses two adjacent edges of face 2: - testClipToPaddedFace(t, Point{r3.Vector{1, 0, 0.75}}, Point{r3.Vector{0, 1, 0.75}}) - testClipToPaddedFace(t, Point{r3.Vector{0, 1, 0.75}}, Point{r3.Vector{1, 0, 0.75}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 1, Y: 0, Z: 0.75}}, Point{r3.Vector{X: 0, Y: 1, Z: 0.75}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 0, Y: 1, Z: 0.75}}, Point{r3.Vector{X: 1, Y: 0, Z: 0.75}}) // An edges that crosses three cube edges (four faces): - testClipToPaddedFace(t, Point{r3.Vector{1, 0.9, 0.95}}, Point{r3.Vector{-1, 0.95, 0.9}}) - testClipToPaddedFace(t, Point{r3.Vector{-1, 0.95, 0.9}}, Point{r3.Vector{1, 0.9, 0.95}}) + testClipToPaddedFace(t, Point{r3.Vector{X: 1, Y: 0.9, Z: 0.95}}, Point{r3.Vector{X: -1, Y: 0.95, Z: 0.9}}) + testClipToPaddedFace(t, Point{r3.Vector{X: -1, Y: 0.95, Z: 0.9}}, Point{r3.Vector{X: 1, Y: 0.9, Z: 0.95}}) // Comprehensively test edges that are difficult to handle, especially those // that nearly follow one of the 12 cube edges. - biunit := r2.Rect{r1.Interval{-1, 1}, r1.Interval{-1, 1}} + biunit := r2.Rect{X: r1.Interval{Lo: -1, Hi: 1}, Y: r1.Interval{Lo: -1, Hi: 1}} for i := 0; i < 1000; i++ { // Choose two adjacent cube corners P and Q. @@ -330,7 +330,7 @@ func chooseRectEndpoint(clip r2.Rect) r2.Point { t := randomUniformFloat64(-1, 2) return clip.Vertices()[diag].Mul(1 - t).Add(clip.Vertices()[diag+2].Mul(t)) } - return r2.Point{randomPointFromInterval(clip.X), randomPointFromInterval(clip.Y)} + return r2.Point{X: randomPointFromInterval(clip.X), Y: randomPointFromInterval(clip.Y)} } // Choose a random point in the rectangle defined by points A and B, sometimes @@ -346,7 +346,7 @@ func choosePointInRect(a, b r2.Point) r2.Point { if oneIn(3) { return a.Add(b.Sub(a).Mul(randomFloat64())) } - return r2.Point{randomUniformFloat64(a.X, b.X), randomUniformFloat64(a.Y, b.Y)} + return r2.Point{X: randomUniformFloat64(a.X, b.X), Y: randomUniformFloat64(a.Y, b.Y)} } // Given a point P representing a possibly clipped endpoint A of an edge AB, @@ -357,7 +357,7 @@ func checkPointOnBoundary(t *testing.T, p, a r2.Point, clip r2.Rect) { t.Errorf("%v.ContainsPoint(%v) = %v, want true", clip, p, got) } if p != a { - p1 := r2.Point{math.Nextafter(p.X, a.X), math.Nextafter(p.Y, a.Y)} + p1 := r2.Point{X: math.Nextafter(p.X, a.X), Y: math.Nextafter(p.Y, a.Y)} if got := clip.ContainsPoint(p1); got { t.Errorf("%v.ContainsPoint(%v) = %v, want false", clip, p1, got) } @@ -371,26 +371,26 @@ func TestEdgeClippingClipEdge(t *testing.T) { testRects := []r2.Rect{ // Test clipping against random rectangles. r2.RectFromPoints( - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}, - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}), + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}, + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}), r2.RectFromPoints( - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}, - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}), + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}, + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}), r2.RectFromPoints( - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}, - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}), + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}, + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}), r2.RectFromPoints( - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}, - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}), + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}, + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}), r2.RectFromPoints( - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}, - r2.Point{randomUniformFloat64(-1, 1), randomUniformFloat64(-1, 1)}), + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}, + r2.Point{X: randomUniformFloat64(-1, 1), Y: randomUniformFloat64(-1, 1)}), // Also clip against one-dimensional, singleton, and empty rectangles. - {r1.Interval{-0.7, -0.7}, r1.Interval{0.3, 0.35}}, - {r1.Interval{0.2, 0.5}, r1.Interval{0.3, 0.3}}, - {r1.Interval{-0.7, 0.3}, r1.Interval{0, 0}}, - r2.RectFromPoints(r2.Point{0.3, 0.8}), + {X: r1.Interval{Lo: -0.7, Hi: -0.7}, Y: r1.Interval{Lo: 0.3, Hi: 0.35}}, + {X: r1.Interval{Lo: 0.2, Hi: 0.5}, Y: r1.Interval{Lo: 0.3, Hi: 0.3}}, + {X: r1.Interval{Lo: -0.7, Hi: 0.3}, Y: r1.Interval{Lo: 0, Hi: 0}}, + r2.RectFromPoints(r2.Point{X: 0.3, Y: 0.8}), r2.EmptyRect(), } diff --git a/s2/edge_crosser_test.go b/s2/edge_crosser_test.go index 73c0400f..c15f4817 100644 --- a/s2/edge_crosser_test.go +++ b/s2/edge_crosser_test.go @@ -34,55 +34,55 @@ func TestEdgeCrosserCrossings(t *testing.T) { }{ { msg: "two regular edges that cross", - a: Point{r3.Vector{1, 2, 1}}, - b: Point{r3.Vector{1, -3, 0.5}}, - c: Point{r3.Vector{1, -0.5, -3}}, - d: Point{r3.Vector{0.1, 0.5, 3}}, + a: Point{r3.Vector{X: 1, Y: 2, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -3, Z: 0.5}}, + c: Point{r3.Vector{X: 1, Y: -0.5, Z: -3}}, + d: Point{r3.Vector{X: 0.1, Y: 0.5, Z: 3}}, robust: Cross, edgeOrVertex: true, }, { msg: "two regular edges that intersect antipodal points", - a: Point{r3.Vector{1, 2, 1}}, - b: Point{r3.Vector{1, -3, 0.5}}, - c: Point{r3.Vector{-1, 0.5, 3}}, - d: Point{r3.Vector{-0.1, -0.5, -3}}, + a: Point{r3.Vector{X: 1, Y: 2, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -3, Z: 0.5}}, + c: Point{r3.Vector{X: -1, Y: 0.5, Z: 3}}, + d: Point{r3.Vector{X: -0.1, Y: -0.5, Z: -3}}, robust: DoNotCross, edgeOrVertex: false, }, { msg: "two edges on the same great circle that start at antipodal points", - a: Point{r3.Vector{0, 0, -1}}, - b: Point{r3.Vector{0, 1, 0}}, - c: Point{r3.Vector{0, 0, 1}}, - d: Point{r3.Vector{0, 1, 1}}, + a: Point{r3.Vector{X: 0, Y: 0, Z: -1}}, + b: Point{r3.Vector{X: 0, Y: 1, Z: 0}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: 1}}, + d: Point{r3.Vector{X: 0, Y: 1, Z: 1}}, robust: DoNotCross, edgeOrVertex: false, }, { msg: "two edges that cross where one vertex is the OriginPoint", - a: Point{r3.Vector{1, 0, 0}}, + a: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, b: OriginPoint(), - c: Point{r3.Vector{1, -0.1, 1}}, - d: Point{r3.Vector{1, 1, -0.1}}, + c: Point{r3.Vector{X: 1, Y: -0.1, Z: 1}}, + d: Point{r3.Vector{X: 1, Y: 1, Z: -0.1}}, robust: Cross, edgeOrVertex: true, }, { msg: "two edges that intersect antipodal points where one vertex is the OriginPoint", - a: Point{r3.Vector{1, 0, 0}}, + a: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, b: OriginPoint(), - c: Point{r3.Vector{1, 0.1, -1}}, - d: Point{r3.Vector{1, 1, -0.1}}, + c: Point{r3.Vector{X: 1, Y: 0.1, Z: -1}}, + d: Point{r3.Vector{X: 1, Y: 1, Z: -0.1}}, robust: DoNotCross, edgeOrVertex: false, }, { msg: "two edges that cross antipodal points", - a: Point{r3.Vector{1, 0, 0}}, - b: Point{r3.Vector{0, 1, 0}}, - c: Point{r3.Vector{0, 0, -1}}, - d: Point{r3.Vector{-1, -1, 1}}, + a: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + b: Point{r3.Vector{X: 0, Y: 1, Z: 0}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: -1}}, + d: Point{r3.Vector{X: -1, Y: -1, Z: 1}}, robust: DoNotCross, edgeOrVertex: false, }, @@ -90,10 +90,10 @@ func TestEdgeCrosserCrossings(t *testing.T) { // The Ortho() direction is (-4,0,2) and edge CD // is further CCW around (2,3,4) than AB. msg: "two edges that share an endpoint", - a: Point{r3.Vector{2, 3, 4}}, - b: Point{r3.Vector{-1, 2, 5}}, - c: Point{r3.Vector{7, -2, 3}}, - d: Point{r3.Vector{2, 3, 4}}, + a: Point{r3.Vector{X: 2, Y: 3, Z: 4}}, + b: Point{r3.Vector{X: -1, Y: 2, Z: 5}}, + c: Point{r3.Vector{X: 7, Y: -2, Z: 3}}, + d: Point{r3.Vector{X: 2, Y: 3, Z: 4}}, robust: MaybeCross, edgeOrVertex: false, }, @@ -101,19 +101,19 @@ func TestEdgeCrosserCrossings(t *testing.T) { // The edge AB is approximately in the x=y plane, while CD is approximately // perpendicular to it and ends exactly at the x=y plane. msg: "two edges that barely cross near the middle of one edge", - a: Point{r3.Vector{1, 1, 1}}, - b: Point{r3.Vector{1, na1, -1}}, - c: Point{r3.Vector{11, -12, -1}}, - d: Point{r3.Vector{10, 10, 1}}, + a: Point{r3.Vector{X: 1, Y: 1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: na1, Z: -1}}, + c: Point{r3.Vector{X: 11, Y: -12, Z: -1}}, + d: Point{r3.Vector{X: 10, Y: 10, Z: 1}}, robust: Cross, edgeOrVertex: true, }, { msg: "two edges that barely cross near the middle separated by a distance of about 1e-15", - a: Point{r3.Vector{1, 1, 1}}, - b: Point{r3.Vector{1, na2, -1}}, - c: Point{r3.Vector{1, -1, 0}}, - d: Point{r3.Vector{1, 1, 0}}, + a: Point{r3.Vector{X: 1, Y: 1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: na2, Z: -1}}, + c: Point{r3.Vector{X: 1, Y: -1, Z: 0}}, + d: Point{r3.Vector{X: 1, Y: 1, Z: 0}}, robust: DoNotCross, edgeOrVertex: false, }, @@ -121,19 +121,19 @@ func TestEdgeCrosserCrossings(t *testing.T) { // This example cannot be handled using regular double-precision // arithmetic due to floating-point underflow. msg: "two edges that barely cross each other near the end of both edges", - a: Point{r3.Vector{0, 0, 1}}, - b: Point{r3.Vector{2, -1e-323, 1}}, - c: Point{r3.Vector{1, -1, 1}}, - d: Point{r3.Vector{1e-323, 0, 1}}, + a: Point{r3.Vector{X: 0, Y: 0, Z: 1}}, + b: Point{r3.Vector{X: 2, Y: -1e-323, Z: 1}}, + c: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, + d: Point{r3.Vector{X: 1e-323, Y: 0, Z: 1}}, robust: Cross, edgeOrVertex: true, }, { msg: "two edges that barely cross each other near the end separated by a distance of about 1e-640", - a: Point{r3.Vector{0, 0, 1}}, - b: Point{r3.Vector{2, 1e-323, 1}}, - c: Point{r3.Vector{1, -1, 1}}, - d: Point{r3.Vector{1e-323, 0, 1}}, + a: Point{r3.Vector{X: 0, Y: 0, Z: 1}}, + b: Point{r3.Vector{X: 2, Y: 1e-323, Z: 1}}, + c: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, + d: Point{r3.Vector{X: 1e-323, Y: 0, Z: 1}}, robust: DoNotCross, edgeOrVertex: false, }, @@ -141,19 +141,19 @@ func TestEdgeCrosserCrossings(t *testing.T) { msg: "two edges that barely cross each other near the middle of one edge", // Computing the exact determinant of some of the triangles in this test // requires more than 2000 bits of precision. - a: Point{r3.Vector{1, -1e-323, -1e-323}}, - b: Point{r3.Vector{1e-323, 1, 1e-323}}, - c: Point{r3.Vector{1, -1, 1e-323}}, - d: Point{r3.Vector{1, 1, 0}}, + a: Point{r3.Vector{X: 1, Y: -1e-323, Z: -1e-323}}, + b: Point{r3.Vector{X: 1e-323, Y: 1, Z: 1e-323}}, + c: Point{r3.Vector{X: 1, Y: -1, Z: 1e-323}}, + d: Point{r3.Vector{X: 1, Y: 1, Z: 0}}, robust: Cross, edgeOrVertex: true, }, { msg: "two edges that barely cross each other near the middle separated by a distance of about 1e-640", - a: Point{r3.Vector{1, 1e-323, -1e-323}}, - b: Point{r3.Vector{-1e-323, 1, 1e-323}}, - c: Point{r3.Vector{1, -1, 1e-323}}, - d: Point{r3.Vector{1, 1, 0}}, + a: Point{r3.Vector{X: 1, Y: 1e-323, Z: -1e-323}}, + b: Point{r3.Vector{X: -1e-323, Y: 1, Z: 1e-323}}, + c: Point{r3.Vector{X: 1, Y: -1, Z: 1e-323}}, + d: Point{r3.Vector{X: 1, Y: 1, Z: 0}}, robust: DoNotCross, edgeOrVertex: false, }, diff --git a/s2/edge_crossings.go b/s2/edge_crossings.go index 9d263a98..2c601901 100644 --- a/s2/edge_crossings.go +++ b/s2/edge_crossings.go @@ -185,7 +185,7 @@ func Intersection(a0, a1, b0, b1 Point) Point { // error. // // - intersectionExact computes the intersection point using precision - // arithmetic and converts the final result back to an Point. + // arithmetic and converts the final result back to a Point. pt, ok := intersectionStable(a0, a1, b0, b1) if !ok { pt = intersectionExact(a0, a1, b0, b1) @@ -374,7 +374,7 @@ func intersectionExact(a0, a1, b0, b1 Point) Point { // "crossing" because of simulation of simplicity. Out of the four // endpoints, exactly two lie in the interior of the other edge. Of // those two we return the one that is lexicographically smallest. - x = r3.Vector{10, 10, 10} // Greater than any valid S2Point + x = r3.Vector{X: 10, Y: 10, Z: 10} // Greater than any valid S2Point aNorm := Point{aNormP.Vector()} bNorm := Point{bNormP.Vector()} diff --git a/s2/edge_distances_test.go b/s2/edge_distances_test.go index 4a3c37f3..fdea1374 100644 --- a/s2/edge_distances_test.go +++ b/s2/edge_distances_test.go @@ -29,108 +29,108 @@ func TestEdgeDistancesCheckDistance(t *testing.T) { want r3.Vector }{ { - x: r3.Vector{1, 0, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 0, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: 0, - want: r3.Vector{1, 0, 0}, + want: r3.Vector{X: 1, Y: 0, Z: 0}, }, { - x: r3.Vector{0, 1, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 0, Y: 1, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: 0, - want: r3.Vector{0, 1, 0}, + want: r3.Vector{X: 0, Y: 1, Z: 0}, }, { - x: r3.Vector{1, 3, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 3, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: 0, - want: r3.Vector{1, 3, 0}, + want: r3.Vector{X: 1, Y: 3, Z: 0}, }, { - x: r3.Vector{0, 0, 1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 0, Y: 0, Z: 1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Pi / 2, - want: r3.Vector{1, 0, 0}, + want: r3.Vector{X: 1, Y: 0, Z: 0}, }, { - x: r3.Vector{0, 0, -1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 0, Y: 0, Z: -1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Pi / 2, - want: r3.Vector{1, 0, 0}, + want: r3.Vector{X: 1, Y: 0, Z: 0}, }, { - x: r3.Vector{-1, -1, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: -1, Y: -1, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: 0.75 * math.Pi, - want: r3.Vector{1, 0, 0}, + want: r3.Vector{X: 1, Y: 0, Z: 0}, }, { - x: r3.Vector{0, 1, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{1, 1, 0}, + x: r3.Vector{X: 0, Y: 1, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 1, Y: 1, Z: 0}, distRad: math.Pi / 4, - want: r3.Vector{1, 1, 0}, + want: r3.Vector{X: 1, Y: 1, Z: 0}, }, { - x: r3.Vector{0, -1, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{1, 1, 0}, + x: r3.Vector{X: 0, Y: -1, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 1, Y: 1, Z: 0}, distRad: math.Pi / 2, - want: r3.Vector{1, 0, 0}, + want: r3.Vector{X: 1, Y: 0, Z: 0}, }, { - x: r3.Vector{0, -1, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{-1, 1, 0}, + x: r3.Vector{X: 0, Y: -1, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: -1, Y: 1, Z: 0}, distRad: math.Pi / 2, - want: r3.Vector{1, 0, 0}, + want: r3.Vector{X: 1, Y: 0, Z: 0}, }, { - x: r3.Vector{-1, -1, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{-1, 1, 0}, + x: r3.Vector{X: -1, Y: -1, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: -1, Y: 1, Z: 0}, distRad: math.Pi / 2, - want: r3.Vector{-1, 1, 0}, + want: r3.Vector{X: -1, Y: 1, Z: 0}, }, { - x: r3.Vector{1, 1, 1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 1, Z: 1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Asin(math.Sqrt(1.0 / 3.0)), - want: r3.Vector{1, 1, 0}, + want: r3.Vector{X: 1, Y: 1, Z: 0}, }, { - x: r3.Vector{1, 1, -1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 1, Z: -1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Asin(math.Sqrt(1.0 / 3.0)), - want: r3.Vector{1, 1, 0}}, + want: r3.Vector{X: 1, Y: 1, Z: 0}}, { - x: r3.Vector{-1, 0, 0}, - a: r3.Vector{1, 1, 0}, - b: r3.Vector{1, 1, 0}, + x: r3.Vector{X: -1, Y: 0, Z: 0}, + a: r3.Vector{X: 1, Y: 1, Z: 0}, + b: r3.Vector{X: 1, Y: 1, Z: 0}, distRad: 0.75 * math.Pi, - want: r3.Vector{1, 1, 0}, + want: r3.Vector{X: 1, Y: 1, Z: 0}, }, { - x: r3.Vector{0, 0, -1}, - a: r3.Vector{1, 1, 0}, - b: r3.Vector{1, 1, 0}, + x: r3.Vector{X: 0, Y: 0, Z: -1}, + a: r3.Vector{X: 1, Y: 1, Z: 0}, + b: r3.Vector{X: 1, Y: 1, Z: 0}, distRad: math.Pi / 2, - want: r3.Vector{1, 1, 0}, + want: r3.Vector{X: 1, Y: 1, Z: 0}, }, { - x: r3.Vector{-1, 0, 0}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{1, 0, 0}, + x: r3.Vector{X: -1, Y: 0, Z: 0}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 1, Y: 0, Z: 0}, distRad: math.Pi, - want: r3.Vector{1, 0, 0}, + want: r3.Vector{X: 1, Y: 0, Z: 0}, }, } @@ -198,23 +198,23 @@ func TestEdgeDistancesUpdateMinInteriorDistanceRejectionTestIsConservative(t *te }{ { - x: Point{r3.Vector{1, -4.6547732744037044e-11, -5.6374428459823598e-89}}, - a: Point{r3.Vector{1, -8.9031850507928352e-11, 0}}, - b: Point{r3.Vector{-0.99999999999996347, 2.7030110029169596e-07, 1.555092348806121e-99}}, + x: Point{r3.Vector{X: 1, Y: -4.6547732744037044e-11, Z: -5.6374428459823598e-89}}, + a: Point{r3.Vector{X: 1, Y: -8.9031850507928352e-11, Z: 0}}, + b: Point{r3.Vector{X: -0.99999999999996347, Y: 2.7030110029169596e-07, Z: 1.555092348806121e-99}}, minDist: minDist, want: false, }, { - x: Point{r3.Vector{1, -4.7617930898495072e-13, 0}}, - a: Point{r3.Vector{-1, -1.6065916409055676e-10, 0}}, - b: Point{r3.Vector{1, 0, 9.9964883247706732e-35}}, + x: Point{r3.Vector{X: 1, Y: -4.7617930898495072e-13, Z: 0}}, + a: Point{r3.Vector{X: -1, Y: -1.6065916409055676e-10, Z: 0}}, + b: Point{r3.Vector{X: 1, Y: 0, Z: 9.9964883247706732e-35}}, minDist: minDist, want: false, }, { - x: Point{r3.Vector{1, 0, 0}}, - a: Point{r3.Vector{1, -8.4965026896454536e-11, 0}}, - b: Point{r3.Vector{-0.99999999999966138, 8.2297529603339328e-07, 9.6070344113320997e-21}}, + x: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + a: Point{r3.Vector{X: 1, Y: -8.4965026896454536e-11, Z: 0}}, + b: Point{r3.Vector{X: -0.99999999999966138, Y: 8.2297529603339328e-07, Z: 9.6070344113320997e-21}}, minDist: minDist, want: false, }, @@ -233,75 +233,75 @@ func TestEdgeDistancesCheckMaxDistance(t *testing.T) { distRad float64 }{ { - x: r3.Vector{1, 0, 1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 0, Z: 1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Pi / 2, }, { - x: r3.Vector{1, 0, -1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 0, Z: -1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Pi / 2, }, { - x: r3.Vector{0, 1, 1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 0, Y: 1, Z: 1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Pi / 2, }, { - x: r3.Vector{0, 1, -1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 0, Y: 1, Z: -1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Pi / 2, }, { - x: r3.Vector{1, 1, 1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 1, Z: 1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Asin(math.Sqrt(2. / 3)), }, { - x: r3.Vector{1, 1, -1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{0, 1, 0}, + x: r3.Vector{X: 1, Y: 1, Z: -1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 0, Y: 1, Z: 0}, distRad: math.Asin(math.Sqrt(2. / 3)), }, { - x: r3.Vector{1, 0, 0}, - a: r3.Vector{1, 1, 0}, - b: r3.Vector{1, -1, 0}, + x: r3.Vector{X: 1, Y: 0, Z: 0}, + a: r3.Vector{X: 1, Y: 1, Z: 0}, + b: r3.Vector{X: 1, Y: -1, Z: 0}, distRad: math.Pi / 4, }, { - x: r3.Vector{0, 1, 0}, - a: r3.Vector{1, 1, 0}, - b: r3.Vector{1, 1, 0}, + x: r3.Vector{X: 0, Y: 1, Z: 0}, + a: r3.Vector{X: 1, Y: 1, Z: 0}, + b: r3.Vector{X: 1, Y: 1, Z: 0}, distRad: math.Pi / 4, }, { - x: r3.Vector{0, 0, 1}, - a: r3.Vector{0, 1, 1}, - b: r3.Vector{0, -1, 1}, + x: r3.Vector{X: 0, Y: 0, Z: 1}, + a: r3.Vector{X: 0, Y: 1, Z: 1}, + b: r3.Vector{X: 0, Y: -1, Z: 1}, distRad: math.Pi / 4, }, { - x: r3.Vector{0, 0, 1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{1, 0, -1}, + x: r3.Vector{X: 0, Y: 0, Z: 1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 1, Y: 0, Z: -1}, distRad: 3 * math.Pi / 4, }, { - x: r3.Vector{0, 0, 1}, - a: r3.Vector{1, 0, 0}, - b: r3.Vector{1, 1, -math.Sqrt2}, + x: r3.Vector{X: 0, Y: 0, Z: 1}, + a: r3.Vector{X: 1, Y: 0, Z: 0}, + b: r3.Vector{X: 1, Y: 1, Z: -math.Sqrt2}, distRad: 3 * math.Pi / 4, }, { - x: r3.Vector{0, 0, 1}, - a: r3.Vector{0, 0, -1}, - b: r3.Vector{0, 0, -1}, + x: r3.Vector{X: 0, Y: 0, Z: 1}, + a: r3.Vector{X: 0, Y: 0, Z: -1}, + b: r3.Vector{X: 0, Y: 0, Z: -1}, distRad: math.Pi, }, } @@ -354,41 +354,41 @@ func TestEdgeDistancesInterpolate(t *testing.T) { // Test that interpolation is done using distances on the sphere // rather than linear distances. { - Point{r3.Vector{1, 0, 0}}, - Point{r3.Vector{0, 1, 0}}, + Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + Point{r3.Vector{X: 0, Y: 1, Z: 0}}, 1.0 / 3.0, - Point{r3.Vector{math.Sqrt(3), 1, 0}}, + Point{r3.Vector{X: math.Sqrt(3), Y: 1, Z: 0}}, }, { - Point{r3.Vector{1, 0, 0}}, - Point{r3.Vector{0, 1, 0}}, + Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + Point{r3.Vector{X: 0, Y: 1, Z: 0}}, 2.0 / 3.0, - Point{r3.Vector{1, math.Sqrt(3), 0}}, + Point{r3.Vector{X: 1, Y: math.Sqrt(3), Z: 0}}, }, // InterpolateCanExtrapolate checks // Initial vectors at 90 degrees. - {i, j, 0, Point{r3.Vector{1, 0, 0}}}, - {i, j, 1, Point{r3.Vector{0, 1, 0}}}, - {i, j, 1.5, Point{r3.Vector{-1, 1, 0}}}, - {i, j, 2, Point{r3.Vector{-1, 0, 0}}}, - {i, j, 3, Point{r3.Vector{0, -1, 0}}}, - {i, j, 4, Point{r3.Vector{1, 0, 0}}}, + {i, j, 0, Point{r3.Vector{X: 1, Y: 0, Z: 0}}}, + {i, j, 1, Point{r3.Vector{X: 0, Y: 1, Z: 0}}}, + {i, j, 1.5, Point{r3.Vector{X: -1, Y: 1, Z: 0}}}, + {i, j, 2, Point{r3.Vector{X: -1, Y: 0, Z: 0}}}, + {i, j, 3, Point{r3.Vector{X: 0, Y: -1, Z: 0}}}, + {i, j, 4, Point{r3.Vector{X: 1, Y: 0, Z: 0}}}, // Negative values of t. - {i, j, -1, Point{r3.Vector{0, -1, 0}}}, - {i, j, -2, Point{r3.Vector{-1, 0, 0}}}, - {i, j, -3, Point{r3.Vector{0, 1, 0}}}, - {i, j, -4, Point{r3.Vector{1, 0, 0}}}, + {i, j, -1, Point{r3.Vector{X: 0, Y: -1, Z: 0}}}, + {i, j, -2, Point{r3.Vector{X: -1, Y: 0, Z: 0}}}, + {i, j, -3, Point{r3.Vector{X: 0, Y: 1, Z: 0}}}, + {i, j, -4, Point{r3.Vector{X: 1, Y: 0, Z: 0}}}, // Initial vectors at 45 degrees. - {i, Point{r3.Vector{1, 1, 0}}, 2, Point{r3.Vector{0, 1, 0}}}, - {i, Point{r3.Vector{1, 1, 0}}, 3, Point{r3.Vector{-1, 1, 0}}}, - {i, Point{r3.Vector{1, 1, 0}}, 4, Point{r3.Vector{-1, 0, 0}}}, + {i, Point{r3.Vector{X: 1, Y: 1, Z: 0}}, 2, Point{r3.Vector{X: 0, Y: 1, Z: 0}}}, + {i, Point{r3.Vector{X: 1, Y: 1, Z: 0}}, 3, Point{r3.Vector{X: -1, Y: 1, Z: 0}}}, + {i, Point{r3.Vector{X: 1, Y: 1, Z: 0}}, 4, Point{r3.Vector{X: -1, Y: 0, Z: 0}}}, // Initial vectors at 135 degrees. - {i, Point{r3.Vector{-1, 1, 0}}, 2, Point{r3.Vector{0, -1, 0}}}, + {i, Point{r3.Vector{X: -1, Y: 1, Z: 0}}, 2, Point{r3.Vector{X: 0, Y: -1, Z: 0}}}, // Test that we should get back where we started by interpolating // the 1/1000th by 1000. diff --git a/s2/edge_query.go b/s2/edge_query.go index 8d25d10d..b4402f29 100644 --- a/s2/edge_query.go +++ b/s2/edge_query.go @@ -214,7 +214,7 @@ type EdgeQuery struct { // testedEdges tracks the set of shape and edges that have already been tested. testedEdges map[ShapeEdgeID]uint32 - // For the optimized algorihm we precompute the top-level CellIDs that + // For the optimized algorithm we precompute the top-level CellIDs that // will be added to the priority queue. There can be at most 6 of these // cells. Essentially this is just a covering of the indexed edges, except // that we also store pointers to the corresponding ShapeIndexCells to diff --git a/s2/edge_query_closest_test.go b/s2/edge_query_closest_test.go index f4e3bcc6..a376290d 100644 --- a/s2/edge_query_closest_test.go +++ b/s2/edge_query_closest_test.go @@ -108,8 +108,8 @@ func TestClosestEdgeQueryTrueDistanceLessThanChordAngleDistance(t *testing.T) { // true distance is slightly less than the one computed by ChordAngle. // // The points below had the worst error from among 100,000 random pairs. - p0 := Point{r3.Vector{0.78516762584829192, -0.50200400690845970, -0.36263449417782678}} - p1 := Point{r3.Vector{0.78563011732429433, -0.50187655940493503, -0.36180828883938054}} + p0 := Point{r3.Vector{X: 0.78516762584829192, Y: -0.50200400690845970, Z: -0.36263449417782678}} + p1 := Point{r3.Vector{X: 0.78563011732429433, Y: -0.50187655940493503, Z: -0.36180828883938054}} pv := &PointVector{p0} index := NewShapeIndex() diff --git a/s2/edge_query_test.go b/s2/edge_query_test.go index fff885fe..969f1af1 100644 --- a/s2/edge_query_test.go +++ b/s2/edge_query_test.go @@ -27,7 +27,7 @@ import ( var ( // The edge query benchmarks scale up the number of edges each time in the - // benchmarking loop. This flag allows for chaning up or down the number + // benchmarking loop. This flag allows for changing up or down the number // of scalings that occur in benchmarking. The default value gets to // ~50k edges in the test, and completes in a reasonable amount of time. // Sometimes though there is a need to push the limits on the benchmarks diff --git a/s2/edge_tessellator_test.go b/s2/edge_tessellator_test.go index 50706ec5..622158cc 100644 --- a/s2/edge_tessellator_test.go +++ b/s2/edge_tessellator_test.go @@ -39,7 +39,7 @@ func TestEdgeTessellatorUnprojectedNoTessellation(t *testing.T) { tess := NewEdgeTessellator(proj, 0.01*s1.Degree) var vertices []Point - vertices = tess.AppendUnprojected(r2.Point{0, 30}, r2.Point{0, 50}, vertices) + vertices = tess.AppendUnprojected(r2.Point{X: 0, Y: 30}, r2.Point{X: 0, Y: 50}, vertices) if len(vertices) != 2 { t.Errorf("2 points which don't need tessellation should only end with 2 points. got %d points", len(vertices)) @@ -53,7 +53,7 @@ func TestEdgeTessellatorUnprojectedWrapping(t *testing.T) { tess := NewEdgeTessellator(proj, 0.01*s1.Degree) var vertices []Point - vertices = tess.AppendUnprojected(r2.Point{-170, 0}, r2.Point{170, 80}, vertices) + vertices = tess.AppendUnprojected(r2.Point{X: -170, Y: 0}, r2.Point{X: 170, Y: 80}, vertices) for i, v := range vertices { if got := math.Abs(longitude(v).Degrees()); got < 170 { t.Errorf("unprojected segment %d should be close to the meridian. got %v, want >= 170", i, got) @@ -87,10 +87,10 @@ func TestEdgeTessellatorUnprojectedWrappingMultipleCrossings(t *testing.T) { var vertices []Point for lat := 1.0; lat <= 60; lat += 1.0 { - vertices = tess.AppendUnprojected(r2.Point{180 - 0.03*lat, lat}, - r2.Point{-180 + 0.07*lat, lat}, vertices) - vertices = tess.AppendUnprojected(r2.Point{-180 + 0.07*lat, lat}, - r2.Point{180 - 0.03*(lat+1), lat + 1}, vertices) + vertices = tess.AppendUnprojected(r2.Point{X: 180 - 0.03*lat, Y: lat}, + r2.Point{X: -180 + 0.07*lat, Y: lat}, vertices) + vertices = tess.AppendUnprojected(r2.Point{X: -180 + 0.07*lat, Y: lat}, + r2.Point{X: 180 - 0.03*(lat+1), Y: lat + 1}, vertices) } for i, v := range vertices { diff --git a/s2/encode_test.go b/s2/encode_test.go index 685bc88c..9372b49b 100644 --- a/s2/encode_test.go +++ b/s2/encode_test.go @@ -194,7 +194,7 @@ func TestEncodeDecode(t *testing.T) { {encodedCellIDInvalid, cidPtr(CellID(0))}, // Cells - {encodedCellFromPoint, cellPtr(CellFromPoint(Point{r3.Vector{1, 2, 3}}))}, + {encodedCellFromPoint, cellPtr(CellFromPoint(Point{r3.Vector{X: 1, Y: 2, Z: 3}}))}, // Lake Tahoe CA/NV border corner {encodedCellFromLatLng, cellPtr(CellFromLatLng(LatLngFromDegrees(39.0, -120.0)))}, {encodedCellFromFacePosLevel, cellPtr(CellFromCellID(CellIDFromFacePosLevel(3, 0x12345678, MaxLevel-4)))}, diff --git a/s2/latlng.go b/s2/latlng.go index a750304a..310c36e9 100644 --- a/s2/latlng.go +++ b/s2/latlng.go @@ -79,14 +79,14 @@ func longitude(p Point) s1.Angle { return s1.Angle(math.Atan2(p.Y, p.X)) * s1.Radian } -// PointFromLatLng returns an Point for the given LatLng. +// PointFromLatLng returns a Point for the given LatLng. // The maximum error in the result is 1.5 * dblEpsilon. (This does not // include the error of converting degrees, E5, E6, or E7 into radians.) func PointFromLatLng(ll LatLng) Point { phi := ll.Lat.Radians() theta := ll.Lng.Radians() cosphi := math.Cos(phi) - return Point{r3.Vector{math.Cos(theta) * cosphi, math.Sin(theta) * cosphi, math.Sin(phi)}} + return Point{r3.Vector{X: math.Cos(theta) * cosphi, Y: math.Sin(theta) * cosphi, Z: math.Sin(phi)}} } // LatLngFromPoint returns an LatLng for a given Point. diff --git a/s2/loop.go b/s2/loop.go index 73cb67c1..59378c56 100644 --- a/s2/loop.go +++ b/s2/loop.go @@ -200,15 +200,15 @@ func (l *Loop) initBound() { } b := bounder.RectBound() - if l.ContainsPoint(Point{r3.Vector{0, 0, 1}}) { - b = Rect{r1.Interval{b.Lat.Lo, math.Pi / 2}, s1.FullInterval()} + if l.ContainsPoint(Point{r3.Vector{X: 0, Y: 0, Z: 1}}) { + b = Rect{r1.Interval{Lo: b.Lat.Lo, Hi: math.Pi / 2}, s1.FullInterval()} } // If a loop contains the south pole, then either it wraps entirely // around the sphere (full longitude range), or it also contains the // north pole in which case b.Lng.IsFull() due to the test above. // Either way, we only need to do the south pole containment test if // b.Lng.IsFull(). - if b.Lng.IsFull() && l.ContainsPoint(Point{r3.Vector{0, 0, -1}}) { + if b.Lng.IsFull() && l.ContainsPoint(Point{r3.Vector{X: 0, Y: 0, Z: -1}}) { b.Lat.Lo = -math.Pi / 2 } l.bound = b @@ -1553,7 +1553,7 @@ func (l *loopCrosser) cellCrossesAnySubcell(aClipped *clippedShape, bID CellID) // correct index cells more efficiently. bRoot := PaddedCellFromCellID(bID, 0) for _, aj := range aClipped.edges { - // Use an CrossingEdgeQuery starting at bRoot to find the index cells + // Use a CrossingEdgeQuery starting at bRoot to find the index cells // of B that might contain crossing edges. l.bCells = l.bQuery.getCells(l.a.Vertex(aj), l.a.Vertex(aj+1), bRoot) if len(l.bCells) == 0 { diff --git a/s2/loop_test.go b/s2/loop_test.go index 8683e7f6..53e5e51b 100644 --- a/s2/loop_test.go +++ b/s2/loop_test.go @@ -312,7 +312,7 @@ func TestLoopRectBound(t *testing.T) { if !southHemi.RectBound().Lng.IsFull() { t.Errorf("south hemi loop's RectBound should have a full longitude range") } - if got, want := southHemi.RectBound().Lat, (r1.Interval{-math.Pi / 2, 0}); !r1IntervalsApproxEqual(got, want, rectError.Lat.Radians()) { + if got, want := southHemi.RectBound().Lat, (r1.Interval{Lo: -math.Pi / 2, Hi: 0}); !r1IntervalsApproxEqual(got, want, rectError.Lat.Radians()) { t.Errorf("south hemi loop's RectBound latitude interval (%v) should be %v", got, want) } @@ -393,13 +393,13 @@ func rotate(l *Loop) *Loop { } func TestLoopContainsPoint(t *testing.T) { - north := Point{r3.Vector{0, 0, 1}} - south := Point{r3.Vector{0, 0, -1}} + north := Point{r3.Vector{X: 0, Y: 0, Z: 1}} + south := Point{r3.Vector{X: 0, Y: 0, Z: -1}} east := PointFromCoords(0, 1, 0) west := PointFromCoords(0, -1, 0) if EmptyLoop().ContainsPoint(north) { - t.Errorf("empty loop should not not have any points") + t.Errorf("empty loop should not have any points") } if !FullLoop().ContainsPoint(south) { t.Errorf("full loop should have full point vertex") @@ -491,10 +491,10 @@ func TestLoopVertex(t *testing.T) { vertex int want Point }{ - {EmptyLoop(), 0, Point{r3.Vector{0, 0, 1}}}, - {EmptyLoop(), 1, Point{r3.Vector{0, 0, 1}}}, - {FullLoop(), 0, Point{r3.Vector{0, 0, -1}}}, - {FullLoop(), 1, Point{r3.Vector{0, 0, -1}}}, + {EmptyLoop(), 0, Point{r3.Vector{X: 0, Y: 0, Z: 1}}}, + {EmptyLoop(), 1, Point{r3.Vector{X: 0, Y: 0, Z: 1}}}, + {FullLoop(), 0, Point{r3.Vector{X: 0, Y: 0, Z: -1}}}, + {FullLoop(), 1, Point{r3.Vector{X: 0, Y: 0, Z: -1}}}, {arctic80, 0, parsePoint("80:-150")}, {arctic80, 1, parsePoint("80:-30")}, {arctic80, 2, parsePoint("80:90")}, @@ -553,8 +553,8 @@ func TestLoopEdge(t *testing.T) { { loop: farHemi, edge: 2, - wantA: Point{r3.Vector{0, 0, -1}}, - wantB: Point{r3.Vector{0, -1, 0}}, + wantA: Point{r3.Vector{X: 0, Y: 0, Z: -1}}, + wantB: Point{r3.Vector{X: 0, Y: -1, Z: 0}}, }, { loop: candyCane, @@ -725,7 +725,7 @@ func TestLoopContainsMatchesCrossingSign(t *testing.T) { // be inside the bound of L. // Start with a cell that ends up producing the problem. - cellID := cellIDFromPoint(Point{r3.Vector{1, 1, 1}}).Parent(21) + cellID := cellIDFromPoint(Point{r3.Vector{X: 1, Y: 1, Z: 1}}).Parent(21) children, ok := CellFromCellID(cellID).Children() if !ok { t.Fatalf("error subdividing cell") @@ -1750,18 +1750,18 @@ func TestLoopValidateDetectsInvalidLoops(t *testing.T) { // Ensure points are not normalized. msg: "loop with non-normalized vertices", points: []Point{ - {r3.Vector{2, 0, 0}}, - {r3.Vector{0, 1, 0}}, - {r3.Vector{0, 0, 1}}, + {r3.Vector{X: 2, Y: 0, Z: 0}}, + {r3.Vector{X: 0, Y: 1, Z: 0}}, + {r3.Vector{X: 0, Y: 0, Z: 1}}, }, }, { // Adjacent antipodal vertices msg: "loop with antipodal points", points: []Point{ - {r3.Vector{1, 0, 0}}, - {r3.Vector{-1, 0, 0}}, - {r3.Vector{0, 0, 1}}, + {r3.Vector{X: 1, Y: 0, Z: 0}}, + {r3.Vector{X: -1, Y: 0, Z: 0}}, + {r3.Vector{X: 0, Y: 0, Z: 1}}, }, }, } diff --git a/s2/matrix3x3.go b/s2/matrix3x3.go index 6d1432ac..5524a0d4 100644 --- a/s2/matrix3x3.go +++ b/s2/matrix3x3.go @@ -27,12 +27,12 @@ type matrix3x3 [3][3]float64 // col returns the given column as a Point. func (m *matrix3x3) col(col int) Point { - return Point{r3.Vector{m[0][col], m[1][col], m[2][col]}} + return Point{r3.Vector{X: m[0][col], Y: m[1][col], Z: m[2][col]}} } // row returns the given row as a Point. func (m *matrix3x3) row(row int) Point { - return Point{r3.Vector{m[row][0], m[row][1], m[row][2]}} + return Point{r3.Vector{X: m[row][0], Y: m[row][1], Z: m[row][2]}} } // setCol sets the specified column to the value in the given Point. @@ -66,9 +66,9 @@ func (m *matrix3x3) scale(f float64) *matrix3x3 { // resulting 1x3 matrix into a Point. func (m *matrix3x3) mul(p Point) Point { return Point{r3.Vector{ - float64(m[0][0]*p.X) + float64(m[0][1]*p.Y) + float64(m[0][2]*p.Z), - float64(m[1][0]*p.X) + float64(m[1][1]*p.Y) + float64(m[1][2]*p.Z), - float64(m[2][0]*p.X) + float64(m[2][1]*p.Y) + float64(m[2][2]*p.Z), + X: float64(m[0][0]*p.X) + float64(m[0][1]*p.Y) + float64(m[0][2]*p.Z), + Y: float64(m[1][0]*p.X) + float64(m[1][1]*p.Y) + float64(m[1][2]*p.Z), + Z: float64(m[2][0]*p.X) + float64(m[2][1]*p.Y) + float64(m[2][2]*p.Z), }} } diff --git a/s2/matrix3x3_test.go b/s2/matrix3x3_test.go index e8f76f33..0bcfb695 100644 --- a/s2/matrix3x3_test.go +++ b/s2/matrix3x3_test.go @@ -35,7 +35,7 @@ func TestCol(t *testing.T) { {7, 8, 9}, }, 0, - Point{r3.Vector{1, 4, 7}}, + Point{r3.Vector{X: 1, Y: 4, Z: 7}}, }, { &matrix3x3{ @@ -44,7 +44,7 @@ func TestCol(t *testing.T) { {7, 8, 9}, }, 2, - Point{r3.Vector{3, 6, 9}}, + Point{r3.Vector{X: 3, Y: 6, Z: 9}}, }, } @@ -69,7 +69,7 @@ func TestRow(t *testing.T) { {7, 8, 9}, }, 0, - Point{r3.Vector{1, 2, 3}}, + Point{r3.Vector{X: 1, Y: 2, Z: 3}}, }, { &matrix3x3{ @@ -78,7 +78,7 @@ func TestRow(t *testing.T) { {7, 8, 9}, }, 2, - Point{r3.Vector{7, 8, 9}}, + Point{r3.Vector{X: 7, Y: 8, Z: 9}}, }, } @@ -99,7 +99,7 @@ func TestSetCol(t *testing.T) { { &matrix3x3{}, 0, - Point{r3.Vector{1, 1, 0}}, + Point{r3.Vector{X: 1, Y: 1, Z: 0}}, &matrix3x3{ {1, 0, 0}, {1, 0, 0}, @@ -113,7 +113,7 @@ func TestSetCol(t *testing.T) { {7, 8, 9}, }, 2, - Point{r3.Vector{1, 1, 0}}, + Point{r3.Vector{X: 1, Y: 1, Z: 0}}, &matrix3x3{ {1, 2, 1}, {4, 5, 1}, @@ -139,7 +139,7 @@ func TestSetRow(t *testing.T) { { &matrix3x3{}, 0, - Point{r3.Vector{1, 1, 0}}, + Point{r3.Vector{X: 1, Y: 1, Z: 0}}, &matrix3x3{ {1, 1, 0}, {0, 0, 0}, @@ -153,7 +153,7 @@ func TestSetRow(t *testing.T) { {7, 8, 9}, }, 2, - Point{r3.Vector{1, 1, 0}}, + Point{r3.Vector{X: 1, Y: 1, Z: 0}}, &matrix3x3{ {1, 2, 3}, {4, 5, 6}, @@ -269,8 +269,8 @@ func TestMul(t *testing.T) { {0, 1, 0}, {0, 0, 1}, }, - Point{r3.Vector{1, 2, 3}}, - Point{r3.Vector{1, 2, 3}}, + Point{r3.Vector{X: 1, Y: 2, Z: 3}}, + Point{r3.Vector{X: 1, Y: 2, Z: 3}}, }, { &matrix3x3{ @@ -278,8 +278,8 @@ func TestMul(t *testing.T) { {4, 5, 6}, {7, 8, 9}, }, - Point{r3.Vector{1, 1, 1}}, - Point{r3.Vector{6, 15, 24}}, + Point{r3.Vector{X: 1, Y: 1, Z: 1}}, + Point{r3.Vector{X: 6, Y: 15, Z: 24}}, }, } for _, test := range tests { @@ -475,13 +475,13 @@ func TestFrames(t *testing.T) { }{ {m.col(2), z}, - {toFrame(m, m.col(0)), Point{r3.Vector{1, 0, 0}}}, - {toFrame(m, m.col(1)), Point{r3.Vector{0, 1, 0}}}, - {toFrame(m, m.col(2)), Point{r3.Vector{0, 0, 1}}}, + {toFrame(m, m.col(0)), Point{r3.Vector{X: 1, Y: 0, Z: 0}}}, + {toFrame(m, m.col(1)), Point{r3.Vector{X: 0, Y: 1, Z: 0}}}, + {toFrame(m, m.col(2)), Point{r3.Vector{X: 0, Y: 0, Z: 1}}}, - {fromFrame(m, Point{r3.Vector{1, 0, 0}}), m.col(0)}, - {fromFrame(m, Point{r3.Vector{0, 1, 0}}), m.col(1)}, - {fromFrame(m, Point{r3.Vector{0, 0, 1}}), m.col(2)}, + {fromFrame(m, Point{r3.Vector{X: 1, Y: 0, Z: 0}}), m.col(0)}, + {fromFrame(m, Point{r3.Vector{X: 0, Y: 1, Z: 0}}), m.col(1)}, + {fromFrame(m, Point{r3.Vector{X: 0, Y: 0, Z: 1}}), m.col(2)}, } for _, test := range tests { diff --git a/s2/paddedcell.go b/s2/paddedcell.go index 8f7677a9..1fb65666 100644 --- a/s2/paddedcell.go +++ b/s2/paddedcell.go @@ -44,8 +44,8 @@ func PaddedCellFromCellID(id CellID, padding float64) *PaddedCell { // Fast path for constructing a top-level face (the most common case). if id.isFace() { limit := padding + 1 - p.bound = r2.Rect{r1.Interval{-limit, limit}, r1.Interval{-limit, limit}} - p.middle = r2.Rect{r1.Interval{-padding, padding}, r1.Interval{-padding, padding}} + p.bound = r2.Rect{X: r1.Interval{Lo: -limit, Hi: limit}, Y: r1.Interval{Lo: -limit, Hi: limit}} + p.middle = r2.Rect{X: r1.Interval{Lo: -padding, Hi: padding}, Y: r1.Interval{Lo: -padding, Hi: padding}} p.orientation = id.Face() & 1 return p } @@ -131,8 +131,8 @@ func (p *PaddedCell) Middle() r2.Rect { u := stToUV(siTiToST(uint32(2*p.iLo + ijSize))) v := stToUV(siTiToST(uint32(2*p.jLo + ijSize))) p.middle = r2.Rect{ - r1.Interval{u - p.padding, u + p.padding}, - r1.Interval{v - p.padding, v + p.padding}, + X: r1.Interval{Lo: u - p.padding, Hi: u + p.padding}, + Y: r1.Interval{Lo: v - p.padding, Hi: v + p.padding}, } } return p.middle diff --git a/s2/paddedcell_test.go b/s2/paddedcell_test.go index a844ec24..371625f3 100644 --- a/s2/paddedcell_test.go +++ b/s2/paddedcell_test.go @@ -146,12 +146,12 @@ func TestPaddedCellShrinkToFit(t *testing.T) { // Start with a random subset of the maximum rectangle. a := r2.Point{ - randomUniformFloat64(maxRect.X.Lo, maxRect.X.Hi), - randomUniformFloat64(maxRect.Y.Lo, maxRect.Y.Hi), + X: randomUniformFloat64(maxRect.X.Lo, maxRect.X.Hi), + Y: randomUniformFloat64(maxRect.Y.Lo, maxRect.Y.Hi), } b := r2.Point{ - randomUniformFloat64(maxRect.X.Lo, maxRect.X.Hi), - randomUniformFloat64(maxRect.Y.Lo, maxRect.Y.Hi), + X: randomUniformFloat64(maxRect.X.Lo, maxRect.X.Hi), + Y: randomUniformFloat64(maxRect.Y.Lo, maxRect.Y.Hi), } if !result.IsLeaf() { @@ -167,7 +167,7 @@ func TestPaddedCellShrinkToFit(t *testing.T) { // Find the range of coordinates that are shared between child cells // along that axis. - shared := r1.Interval{center - padding, center + padding} + shared := r1.Interval{Lo: center - padding, Hi: center + padding} if useY { shared = shared.Intersection(maxRect.Y) } else { diff --git a/s2/point.go b/s2/point.go index 577203aa..848e2589 100644 --- a/s2/point.go +++ b/s2/point.go @@ -53,7 +53,7 @@ func PointFromCoords(x, y, z float64) Point { if x == 0 && y == 0 && z == 0 { return OriginPoint() } - return Point{r3.Vector{x, y, z}.Normalize()} + return Point{r3.Vector{X: x, Y: y, Z: z}.Normalize()} } // OriginPoint returns a unique "origin" on the sphere for operations that need a fixed @@ -65,7 +65,7 @@ func PointFromCoords(x, y, z float64) Point { // north and south poles). It should also not be on the boundary of any // low-level S2Cell for the same reason. func OriginPoint() Point { - return Point{r3.Vector{-0.0099994664350250197, 0.0025924542609324121, 0.99994664350250195}} + return Point{r3.Vector{X: -0.0099994664350250197, Y: 0.0025924542609324121, Z: 0.99994664350250195}} } // PointCross returns a Point that is orthogonal to both p and op. This is similar to @@ -164,7 +164,7 @@ func regularPointsForFrame(frame matrix3x3, radius s1.Angle, numVertices int) [] for i := 0; i < numVertices; i++ { angle := float64(i) * radianStep - p := Point{r3.Vector{r * math.Cos(angle), r * math.Sin(angle), z}} + p := Point{r3.Vector{X: r * math.Cos(angle), Y: r * math.Sin(angle), Z: z}} vertices = append(vertices, Point{fromFrame(frame, p).Normalize()}) } @@ -248,7 +248,7 @@ func (p *Point) decode(d *decoder) { // coordinates that are zero. (This is a performance optimization that // reduces the amount of time spent in functions that handle degeneracies.) func Ortho(a Point) Point { - temp := r3.Vector{0.012, 0.0053, 0.00457} + temp := r3.Vector{X: 0.012, Y: 0.0053, Z: 0.00457} switch a.LargestComponent() { case r3.XAxis: temp.Z = 1 diff --git a/s2/point_measures_test.go b/s2/point_measures_test.go index 367d2d10..15007364 100644 --- a/s2/point_measures_test.go +++ b/s2/point_measures_test.go @@ -23,17 +23,17 @@ import ( ) var ( - pz = Point{r3.Vector{0, 0, 1}} - p000 = Point{r3.Vector{1, 0, 0}} - p045 = Point{r3.Vector{1, 1, 0}.Normalize()} - p090 = Point{r3.Vector{0, 1, 0}} - p180 = Point{r3.Vector{-1, 0, 0}} + pz = Point{r3.Vector{X: 0, Y: 0, Z: 1}} + p000 = Point{r3.Vector{X: 1, Y: 0, Z: 0}} + p045 = Point{r3.Vector{X: 1, Y: 1, Z: 0}.Normalize()} + p090 = Point{r3.Vector{X: 0, Y: 1, Z: 0}} + p180 = Point{r3.Vector{X: -1, Y: 0, Z: 0}} // Degenerate triangles. - pr = Point{r3.Vector{0.257, -0.5723, 0.112}} - pq = Point{r3.Vector{-0.747, 0.401, 0.2235}} + pr = Point{r3.Vector{X: 0.257, Y: -0.5723, Z: 0.112}} + pq = Point{r3.Vector{X: -0.747, Y: 0.401, Z: 0.2235}} // For testing the Girard area fall through case. - g1 = Point{r3.Vector{1, 1, 1}} + g1 = Point{r3.Vector{X: 1, Y: 1, Z: 1}} g2 = Point{g1.Add(pr.Mul(1e-15)).Normalize()} g3 = Point{g1.Add(pq.Mul(1e-15)).Normalize()} ) @@ -50,13 +50,13 @@ func TestPointMeasuresPointArea(t *testing.T) { {p000, p090, pz, math.Pi / 2.0, 0}, {p045, pz, p180, 3.0 * math.Pi / 4.0, 0}, // Make sure that Area has good *relative* accuracy even for very small areas. - {Point{r3.Vector{eps, 0, 1}.Normalize()}, Point{r3.Vector{0, eps, 1}.Normalize()}, pz, exp1, 1e-14 * exp1}, + {Point{r3.Vector{X: eps, Y: 0, Z: 1}.Normalize()}, Point{r3.Vector{X: 0, Y: eps, Z: 1}.Normalize()}, pz, exp1, 1e-14 * exp1}, // Make sure that it can handle degenerate triangles. {pr, pr, pr, 0.0, 0}, {pr, pq, pr, 0.0, 1e-15}, {p000, p045, p090, 0.0, 0}, // Try a very long and skinny triangle. - {p000, Point{r3.Vector{1, 1, eps}.Normalize()}, p090, exp2, 1e-9 * exp2}, + {p000, Point{r3.Vector{X: 1, Y: 1, Z: eps}.Normalize()}, p090, exp2, 1e-9 * exp2}, } for d, test := range tests { @@ -164,12 +164,12 @@ func TestPointMeasuresAngleMethods(t *testing.T) { // returned an area on the order of 1e-14 and the real area is ~1e-21, 7 orders // of magnitude relative error. Check that they return zero now. func TestPointMeasuresPointAreaRegression(t *testing.T) { - a := Point{r3.Vector{-1.705424004316021258e-01, -8.242696197922716461e-01, - 5.399026611737816062e-01}} - b := Point{r3.Vector{-1.706078905422188652e-01, -8.246067119418969416e-01, - 5.393669607095969987e-01}} - c := Point{r3.Vector{-1.705800600596222294e-01, -8.244634596153025408e-01, - 5.395947061167500891e-01}} + a := Point{r3.Vector{X: -1.705424004316021258e-01, Y: -8.242696197922716461e-01, + Z: 5.399026611737816062e-01}} + b := Point{r3.Vector{X: -1.706078905422188652e-01, Y: -8.246067119418969416e-01, + Z: 5.393669607095969987e-01}} + c := Point{r3.Vector{X: -1.705800600596222294e-01, Y: -8.244634596153025408e-01, + Z: 5.395947061167500891e-01}} if area := PointArea(a, b, c); area != 0 { t.Errorf("PointArea(%v, %v, %v) should have been 0, got %v", a, b, c, area) } diff --git a/s2/point_test.go b/s2/point_test.go index 48224618..2e36af5f 100644 --- a/s2/point_test.go +++ b/s2/point_test.go @@ -33,7 +33,7 @@ func TestOriginPoint(t *testing.T) { // Cells. (The line of longitude through the chosen point is always 1/3 // or 2/3 of the way across any Cell with longitudinal edges that it // passes through.) - p := Point{r3.Vector{-0.01, 0.01 * stToUV(2.0/3), 1}} + p := Point{r3.Vector{X: -0.01, Y: 0.01 * stToUV(2.0/3), Z: 1}} if !p.ApproxEqual(OriginPoint()) { t.Errorf("Origin point should fall in the Siberian Sea, but does not.") } @@ -54,8 +54,8 @@ func TestPointCross(t *testing.T) { {1, 2, 3, -4, 5, -6, 2 * math.Sqrt(934)}, } for _, test := range tests { - p1 := Point{r3.Vector{test.p1x, test.p1y, test.p1z}} - p2 := Point{r3.Vector{test.p2x, test.p2y, test.p2z}} + p1 := Point{r3.Vector{X: test.p1x, Y: test.p1y, Z: test.p1z}} + p2 := Point{r3.Vector{X: test.p2x, Y: test.p2y, Z: test.p2z}} result := p1.PointCross(p2) if !float64Eq(result.Norm(), test.norm) { t.Errorf("|%v ⨯ %v| = %v, want %v", p1, p2, result.Norm(), test.norm) @@ -82,8 +82,8 @@ func TestPointDistance(t *testing.T) { {1, 2, 3, 2, 3, -1, 1.2055891055045298}, } for _, test := range tests { - p1 := Point{r3.Vector{test.x1, test.y1, test.z1}} - p2 := Point{r3.Vector{test.x2, test.y2, test.z2}} + p1 := Point{r3.Vector{X: test.x1, Y: test.y1, Z: test.z1}} + p2 := Point{r3.Vector{X: test.x2, Y: test.y2, Z: test.z2}} if a := p1.Distance(p2).Radians(); !float64Eq(a, test.want) { t.Errorf("%v.Distance(%v) = %v, want %v", p1, p2, a, test.want) } @@ -136,8 +136,8 @@ func TestPointApproxEqual(t *testing.T) { {1, epsilon, 0, 1, -epsilon, epsilon, false}, } for _, test := range tests { - p1 := Point{r3.Vector{test.x1, test.y1, test.z1}} - p2 := Point{r3.Vector{test.x2, test.y2, test.z2}} + p1 := Point{r3.Vector{X: test.x1, Y: test.y1, Z: test.z1}} + p2 := Point{r3.Vector{X: test.x2, Y: test.y2, Z: test.z2}} if got := p1.ApproxEqual(p2); got != test.want { t.Errorf("%v.ApproxEqual(%v), got %v want %v", p1, p2, got, test.want) } @@ -254,8 +254,8 @@ func TestPointRegularPoints(t *testing.T) { } func TestPointRegion(t *testing.T) { - p := Point{r3.Vector{1, 0, 0}} - r := Point{r3.Vector{1, 0, 0}} + p := Point{r3.Vector{X: 1, Y: 0, Z: 0}} + r := Point{r3.Vector{X: 1, Y: 0, Z: 0}} if !r.Contains(p) { t.Errorf("%v.Contains(%v) = false, want true", r, p) } @@ -268,7 +268,7 @@ func TestPointRegion(t *testing.T) { if !r.ContainsPoint(r) { t.Errorf("%v.ContainsPoint(%v) = false, want true", r, r) } - if s := (Point{r3.Vector{1, 0, 1}}); r.Contains(s) { + if s := (Point{r3.Vector{X: 1, Y: 0, Z: 1}}); r.Contains(s) { t.Errorf("%v.Contains(%v) = true, want false", r, s) } if got, want := r.CapBound(), CapFromPoint(p); !got.ApproxEqual(want) { diff --git a/s2/polyline_test.go b/s2/polyline_test.go index 056e8a9b..c6cd39d1 100644 --- a/s2/polyline_test.go +++ b/s2/polyline_test.go @@ -48,7 +48,7 @@ func TestPolylineBasics(t *testing.T) { t.Errorf("semiEquator.Interpolate(0.5) = %v, want %v", got, want) } semiEquator.Reverse() - if got, want := (*semiEquator)[2], (Point{r3.Vector{1, 0, 0}}); !got.ApproxEqual(want) { + if got, want := (*semiEquator)[2], (Point{r3.Vector{X: 1, Y: 0, Z: 0}}); !got.ApproxEqual(want) { t.Errorf("semiEquator[2] = %v, want %v", got, want) } } @@ -137,8 +137,8 @@ func TestPolylineLengthAndCentroid(t *testing.T) { func TestPolylineIntersectsCell(t *testing.T) { pline := Polyline{ - Point{r3.Vector{1, -1.1, 0.8}.Normalize()}, - Point{r3.Vector{1, -0.8, 1.1}.Normalize()}, + Point{r3.Vector{X: 1, Y: -1.1, Z: 0.8}.Normalize()}, + Point{r3.Vector{X: 1, Y: -0.8, Z: 1.1}.Normalize()}, } for face := 0; face < 6; face++ { @@ -364,7 +364,7 @@ func TestPolylineValidate(t *testing.T) { p1 := Polyline([]Point{ PointFromCoords(0, 1, 0), - {r3.Vector{10, 3, 7}}, + {r3.Vector{X: 10, Y: 3, Z: 7}}, PointFromCoords(0, 0, 1), }) diff --git a/s2/predicates_test.go b/s2/predicates_test.go index 256c8bde..34f7ef3a 100644 --- a/s2/predicates_test.go +++ b/s2/predicates_test.go @@ -63,9 +63,9 @@ func TestPredicatesSign(t *testing.T) { } for _, test := range tests { - p1 := Point{r3.Vector{test.p1x, test.p1y, test.p1z}} - p2 := Point{r3.Vector{test.p2x, test.p2y, test.p2z}} - p3 := Point{r3.Vector{test.p3x, test.p3y, test.p3z}} + p1 := Point{r3.Vector{X: test.p1x, Y: test.p1y, Z: test.p1z}} + p2 := Point{r3.Vector{X: test.p2x, Y: test.p2y, Z: test.p2z}} + p3 := Point{r3.Vector{X: test.p3x, Y: test.p3y, Z: test.p3z}} result := Sign(p1, p2, p3) if result != test.want { t.Errorf("Sign(%v, %v, %v) = %v, want %v", p1, p2, p3, result, test.want) @@ -86,26 +86,26 @@ var ( // approximate tangent to the surface of the unit sphere. In fact, C is the // exact midpoint of the line segment AB. All of these points are close // enough to unit length to satisfy r3.Vector.IsUnit(). - poA = Point{r3.Vector{0.72571927877036835, 0.46058825605889098, 0.51106749730504852}} - poB = Point{r3.Vector{0.7257192746638208, 0.46058826573818168, 0.51106749441312738}} - poC = Point{r3.Vector{0.72571927671709457, 0.46058826089853633, 0.51106749585908795}} + poA = Point{r3.Vector{X: 0.72571927877036835, Y: 0.46058825605889098, Z: 0.51106749730504852}} + poB = Point{r3.Vector{X: 0.7257192746638208, Y: 0.46058826573818168, Z: 0.51106749441312738}} + poC = Point{r3.Vector{X: 0.72571927671709457, Y: 0.46058826089853633, Z: 0.51106749585908795}} // The points "x1" and "x2" are exactly proportional, i.e. they both lie // on a common line through the origin. Both points are considered to be // normalized, and in fact they both satisfy (x == x.Normalize()). // Therefore the triangle (x1, x2, -x1) consists of three distinct points // that all lie on a common line through the origin. - x1 = Point{r3.Vector{0.99999999999999989, 1.4901161193847655e-08, 0}} - x2 = Point{r3.Vector{1, 1.4901161193847656e-08, 0}} + x1 = Point{r3.Vector{X: 0.99999999999999989, Y: 1.4901161193847655e-08, Z: 0}} + x2 = Point{r3.Vector{X: 1, Y: 1.4901161193847656e-08, Z: 0}} // Here are two more points that are distinct, exactly proportional, and // that satisfy (x == x.Normalize()). - x3 = Point{r3.Vector{1, 1, 1}.Normalize()} + x3 = Point{r3.Vector{X: 1, Y: 1, Z: 1}.Normalize()} x4 = Point{x3.Mul(0.99999999999999989)} // The following three points demonstrate that Normalize() is not idempotent, i.e. // y0.Normalize() != y0.Normalize().Normalize(). Both points are exactly proportional. - y0 = Point{r3.Vector{1, 1, 0}} + y0 = Point{r3.Vector{X: 1, Y: 1, Z: 0}} y1 = Point{y0.Normalize()} y2 = Point{y1.Normalize()} ) @@ -133,9 +133,9 @@ func TestPredicatesRobustSignEqualities(t *testing.T) { } func TestPredicatesRobustSign(t *testing.T) { - x := Point{r3.Vector{1, 0, 0}} - y := Point{r3.Vector{0, 1, 0}} - z := Point{r3.Vector{0, 0, 1}} + x := Point{r3.Vector{X: 1, Y: 0, Z: 0}} + y := Point{r3.Vector{X: 0, Y: 1, Z: 0}} + z := Point{r3.Vector{X: 0, Y: 0, Z: 1}} tests := []struct { p1, p2, p3 Point @@ -291,96 +291,96 @@ func TestPredicatesSymbolicallyPerturbedSign(t *testing.T) { }{ { // det(M_1) = b0*c1 - b1*c0 - a: Point{r3.Vector{-3, -1, 0}}, - b: Point{r3.Vector{-2, 1, 0}}, - c: Point{r3.Vector{1, -2, 0}}, + a: Point{r3.Vector{X: -3, Y: -1, Z: 0}}, + b: Point{r3.Vector{X: -2, Y: 1, Z: 0}}, + c: Point{r3.Vector{X: 1, Y: -2, Z: 0}}, want: CounterClockwise, }, { // det(M_2) = b2*c0 - b0*c2 want: CounterClockwise, - a: Point{r3.Vector{-6, 3, 3}}, - b: Point{r3.Vector{-4, 2, -1}}, - c: Point{r3.Vector{-2, 1, 4}}, + a: Point{r3.Vector{X: -6, Y: 3, Z: 3}}, + b: Point{r3.Vector{X: -4, Y: 2, Z: -1}}, + c: Point{r3.Vector{X: -2, Y: 1, Z: 4}}, }, { // det(M_3) = b1*c2 - b2*c1 want: CounterClockwise, - a: Point{r3.Vector{0, -1, -1}}, - b: Point{r3.Vector{0, 1, -2}}, - c: Point{r3.Vector{0, 2, 1}}, + a: Point{r3.Vector{X: 0, Y: -1, Z: -1}}, + b: Point{r3.Vector{X: 0, Y: 1, Z: -2}}, + c: Point{r3.Vector{X: 0, Y: 2, Z: 1}}, }, // From this point onward, B or C must be zero, or B is proportional to C. { // det(M_4) = c0*a1 - c1*a0 want: CounterClockwise, - a: Point{r3.Vector{-1, 2, 7}}, - b: Point{r3.Vector{2, 1, -4}}, - c: Point{r3.Vector{4, 2, -8}}, + a: Point{r3.Vector{X: -1, Y: 2, Z: 7}}, + b: Point{r3.Vector{X: 2, Y: 1, Z: -4}}, + c: Point{r3.Vector{X: 4, Y: 2, Z: -8}}, }, { // det(M_5) = c0 want: CounterClockwise, - a: Point{r3.Vector{-4, -2, 7}}, - b: Point{r3.Vector{2, 1, -4}}, - c: Point{r3.Vector{4, 2, -8}}, + a: Point{r3.Vector{X: -4, Y: -2, Z: 7}}, + b: Point{r3.Vector{X: 2, Y: 1, Z: -4}}, + c: Point{r3.Vector{X: 4, Y: 2, Z: -8}}, }, { // det(M_6) = -c1 want: CounterClockwise, - a: Point{r3.Vector{0, -5, 7}}, - b: Point{r3.Vector{0, -4, 8}}, - c: Point{r3.Vector{0, -2, 4}}, + a: Point{r3.Vector{X: 0, Y: -5, Z: 7}}, + b: Point{r3.Vector{X: 0, Y: -4, Z: 8}}, + c: Point{r3.Vector{X: 0, Y: -2, Z: 4}}, }, { // det(M_7) = c2*a0 - c0*a2 want: CounterClockwise, - a: Point{r3.Vector{-5, -2, 7}}, - b: Point{r3.Vector{0, 0, -2}}, - c: Point{r3.Vector{0, 0, -1}}, + a: Point{r3.Vector{X: -5, Y: -2, Z: 7}}, + b: Point{r3.Vector{X: 0, Y: 0, Z: -2}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: -1}}, }, { // det(M_8) = c2 want: CounterClockwise, - a: Point{r3.Vector{0, -2, 7}}, - b: Point{r3.Vector{0, 0, 1}}, - c: Point{r3.Vector{0, 0, 2}}, + a: Point{r3.Vector{X: 0, Y: -2, Z: 7}}, + b: Point{r3.Vector{X: 0, Y: 0, Z: 1}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: 2}}, }, // From this point onward, C must be zero. { // det(M_9) = a0*b1 - a1*b0 want: CounterClockwise, - a: Point{r3.Vector{-3, 1, 7}}, - b: Point{r3.Vector{-1, -4, 1}}, - c: Point{r3.Vector{0, 0, 0}}, + a: Point{r3.Vector{X: -3, Y: 1, Z: 7}}, + b: Point{r3.Vector{X: -1, Y: -4, Z: 1}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: 0}}, }, { // det(M_10) = -b0 want: CounterClockwise, - a: Point{r3.Vector{-6, -4, 7}}, - b: Point{r3.Vector{-3, -2, 1}}, - c: Point{r3.Vector{0, 0, 0}}, + a: Point{r3.Vector{X: -6, Y: -4, Z: 7}}, + b: Point{r3.Vector{X: -3, Y: -2, Z: 1}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: 0}}, }, { // det(M_11) = b1 want: Clockwise, - a: Point{r3.Vector{0, -4, 7}}, - b: Point{r3.Vector{0, -2, 1}}, - c: Point{r3.Vector{0, 0, 0}}, + a: Point{r3.Vector{X: 0, Y: -4, Z: 7}}, + b: Point{r3.Vector{X: 0, Y: -2, Z: 1}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: 0}}, }, { // det(M_12) = a0 want: Clockwise, - a: Point{r3.Vector{-1, -4, 5}}, - b: Point{r3.Vector{0, 0, -3}}, - c: Point{r3.Vector{0, 0, 0}}, + a: Point{r3.Vector{X: -1, Y: -4, Z: 5}}, + b: Point{r3.Vector{X: 0, Y: 0, Z: -3}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: 0}}, }, { // det(M_13) = 1 want: CounterClockwise, - a: Point{r3.Vector{0, -4, 5}}, - b: Point{r3.Vector{0, 0, -5}}, - c: Point{r3.Vector{0, 0, 0}}, + a: Point{r3.Vector{X: 0, Y: -4, Z: 5}}, + b: Point{r3.Vector{X: 0, Y: 0, Z: -5}}, + c: Point{r3.Vector{X: 0, Y: 0, Z: 0}}, }, } // Given 3 points A, B, C that are exactly coplanar with the origin and where @@ -475,9 +475,9 @@ func TestPredicatesCompareDistancesCoverage(t *testing.T) { wantPrec: doublePrecision, }, { - x: Point{r3.Vector{2, 0, 0}}, - a: Point{r3.Vector{2, -1, 0}}, - b: Point{r3.Vector{2, 1, 1e-100}}, + x: Point{r3.Vector{X: 2, Y: 0, Z: 0}}, + a: Point{r3.Vector{X: 2, Y: -1, Z: 0}}, + b: Point{r3.Vector{X: 2, Y: 1, Z: 1e-100}}, distFunc: triageCompareSin2Distances, wantSign: -1, wantPrec: exactPrecision, @@ -938,9 +938,9 @@ func TestPredicatesCompareDistanceConsistency(t *testing.T) { } func BenchmarkSign(b *testing.B) { - p1 := Point{r3.Vector{-3, -1, 4}} - p2 := Point{r3.Vector{2, -1, -3}} - p3 := Point{r3.Vector{1, -2, 0}} + p1 := Point{r3.Vector{X: -3, Y: -1, Z: 4}} + p2 := Point{r3.Vector{X: 2, Y: -1, Z: -3}} + p3 := Point{r3.Vector{X: 1, Y: -2, Z: 0}} for i := 0; i < b.N; i++ { Sign(p1, p2, p3) } @@ -949,9 +949,9 @@ func BenchmarkSign(b *testing.B) { // BenchmarkRobustSignSimple runs the benchmark for points that satisfy the first // checks in RobustSign to compare the performance to that of Sign(). func BenchmarkRobustSignSimple(b *testing.B) { - p1 := Point{r3.Vector{-3, -1, 4}} - p2 := Point{r3.Vector{2, -1, -3}} - p3 := Point{r3.Vector{1, -2, 0}} + p1 := Point{r3.Vector{X: -3, Y: -1, Z: 4}} + p2 := Point{r3.Vector{X: 2, Y: -1, Z: -3}} + p3 := Point{r3.Vector{X: 1, Y: -2, Z: 0}} for i := 0; i < b.N; i++ { RobustSign(p1, p2, p3) } diff --git a/s2/projections.go b/s2/projections.go index f7273609..ea3ac578 100644 --- a/s2/projections.go +++ b/s2/projections.go @@ -134,7 +134,7 @@ func (p *PlateCarreeProjection) Interpolate(f float64, a, b r2.Point) r2.Point { // WrapDistance reports the coordinate wrapping distance along each axis. func (p *PlateCarreeProjection) WrapDistance() r2.Point { - return r2.Point{p.xWrap, 0} + return r2.Point{X: p.xWrap, Y: 0} } // WrapDestination wraps the points if needed to get the shortest edge. @@ -191,7 +191,7 @@ func (p *MercatorProjection) FromLatLng(ll LatLng) r2.Point { // Note that latitudes of +/- 90 degrees yield "y" values of +/- infinity. sinPhi := math.Sin(float64(ll.Lat)) y := 0.5 * math.Log((1+sinPhi)/(1-sinPhi)) - return r2.Point{p.fromRadians * float64(ll.Lng), p.fromRadians * y} + return r2.Point{X: p.fromRadians * float64(ll.Lng), Y: p.fromRadians * y} } // ToLatLng returns the LatLng projected from the given R2 Point. @@ -216,7 +216,7 @@ func (p *MercatorProjection) Interpolate(f float64, a, b r2.Point) r2.Point { // WrapDistance reports the coordinate wrapping distance along each axis. func (p *MercatorProjection) WrapDistance() r2.Point { - return r2.Point{p.xWrap, 0} + return r2.Point{X: p.xWrap, Y: 0} } // WrapDestination wraps the points if needed to get the shortest edge. @@ -237,5 +237,5 @@ func wrapDestination(a, b r2.Point, wrapDistance func() r2.Point) r2.Point { if wrap.Y > 0 && math.Abs(y-a.Y) > 0.5*wrap.Y { y = a.Y + math.Remainder(y-a.Y, wrap.Y) } - return r2.Point{x, y} + return r2.Point{X: x, Y: y} } diff --git a/s2/projections_test.go b/s2/projections_test.go index 88eeea8f..7dfe5f7c 100644 --- a/s2/projections_test.go +++ b/s2/projections_test.go @@ -23,8 +23,8 @@ import ( ) func TestPlateCarreeProjectionInterpolate(t *testing.T) { - a := r2.Point{1.234, -5.456e-20} - b := r2.Point{2.1234e-20, 7.456} + a := r2.Point{X: 1.234, Y: -5.456e-20} + b := r2.Point{X: 2.1234e-20, Y: 7.456} tests := []struct { dist float64 a, b r2.Point @@ -33,16 +33,16 @@ func TestPlateCarreeProjectionInterpolate(t *testing.T) { { // Test that coordinates and/or arguments are not accidentally reversed. 0.25, - r2.Point{1, 5}, - r2.Point{3, 9}, - r2.Point{1.5, 6}, + r2.Point{X: 1, Y: 5}, + r2.Point{X: 3, Y: 9}, + r2.Point{X: 1.5, Y: 6}, }, { // Test extrapolation. -2, - r2.Point{1, 0}, - r2.Point{3, 0}, - r2.Point{-3, 0}, + r2.Point{X: 1, Y: 0}, + r2.Point{X: 3, Y: 0}, + r2.Point{X: -3, Y: 0}, }, // Check that interpolation is exact at both endpoints. {0, a, b, a}, @@ -62,12 +62,12 @@ func TestPlateCarreeProjectionProjectUnproject(t *testing.T) { have Point want r2.Point }{ - {Point{r3.Vector{1, 0, 0}}, r2.Point{0, 0}}, - {Point{r3.Vector{-1, 0, 0}}, r2.Point{180, 0}}, - {Point{r3.Vector{0, 1, 0}}, r2.Point{90, 0}}, - {Point{r3.Vector{0, -1, 0}}, r2.Point{-90, 0}}, - {Point{r3.Vector{0, 0, 1}}, r2.Point{0, 90}}, - {Point{r3.Vector{0, 0, -1}}, r2.Point{0, -90}}, + {Point{r3.Vector{X: 1, Y: 0, Z: 0}}, r2.Point{X: 0, Y: 0}}, + {Point{r3.Vector{X: -1, Y: 0, Z: 0}}, r2.Point{X: 180, Y: 0}}, + {Point{r3.Vector{X: 0, Y: 1, Z: 0}}, r2.Point{X: 90, Y: 0}}, + {Point{r3.Vector{X: 0, Y: -1, Z: 0}}, r2.Point{X: -90, Y: 0}}, + {Point{r3.Vector{X: 0, Y: 0, Z: 1}}, r2.Point{X: 0, Y: 90}}, + {Point{r3.Vector{X: 0, Y: 0, Z: -1}}, r2.Point{X: 0, Y: -90}}, } proj := NewPlateCarreeProjection(180) @@ -87,12 +87,12 @@ func TestMercatorProjectionProjectUnproject(t *testing.T) { have Point want r2.Point }{ - {Point{r3.Vector{1, 0, 0}}, r2.Point{0, 0}}, - {Point{r3.Vector{-1, 0, 0}}, r2.Point{180, 0}}, - {Point{r3.Vector{0, 1, 0}}, r2.Point{90, 0}}, - {Point{r3.Vector{0, -1, 0}}, r2.Point{-90, 0}}, + {Point{r3.Vector{X: 1, Y: 0, Z: 0}}, r2.Point{X: 0, Y: 0}}, + {Point{r3.Vector{X: -1, Y: 0, Z: 0}}, r2.Point{X: 180, Y: 0}}, + {Point{r3.Vector{X: 0, Y: 1, Z: 0}}, r2.Point{X: 90, Y: 0}}, + {Point{r3.Vector{X: 0, Y: -1, Z: 0}}, r2.Point{X: -90, Y: 0}}, // Test one arbitrary point as a sanity check. - {PointFromLatLng(LatLng{1, 0}), r2.Point{0, 70.255578967830246}}, + {PointFromLatLng(LatLng{1, 0}), r2.Point{X: 0, Y: 70.255578967830246}}, } proj := NewMercatorProjection(180) @@ -112,8 +112,8 @@ func TestMercatorProjectionProjectUnproject(t *testing.T) { have Point want r2.Point }{ - {Point{r3.Vector{0, 0, 1}}, r2.Point{0, math.Inf(1)}}, - {Point{r3.Vector{0, 0, -1}}, r2.Point{0, math.Inf(-1)}}, + {Point{r3.Vector{X: 0, Y: 0, Z: 1}}, r2.Point{X: 0, Y: math.Inf(1)}}, + {Point{r3.Vector{X: 0, Y: 0, Z: -1}}, r2.Point{X: 0, Y: math.Inf(-1)}}, } for _, test := range testsInf { got := proj.Project(test.have) diff --git a/s2/rect.go b/s2/rect.go index 84083485..8634b157 100644 --- a/s2/rect.go +++ b/s2/rect.go @@ -31,7 +31,7 @@ type Rect struct { } var ( - validRectLatRange = r1.Interval{-math.Pi / 2, math.Pi / 2} + validRectLatRange = r1.Interval{Lo: -math.Pi / 2, Hi: math.Pi / 2} validRectLngRange = s1.FullInterval() ) @@ -44,8 +44,8 @@ func FullRect() Rect { return Rect{validRectLatRange, validRectLngRange} } // RectFromLatLng constructs a rectangle containing a single point p. func RectFromLatLng(p LatLng) Rect { return Rect{ - Lat: r1.Interval{p.Lat.Radians(), p.Lat.Radians()}, - Lng: s1.Interval{p.Lng.Radians(), p.Lng.Radians()}, + Lat: r1.Interval{Lo: p.Lat.Radians(), Hi: p.Lat.Radians()}, + Lng: s1.Interval{Lo: p.Lng.Radians(), Hi: p.Lng.Radians()}, } } @@ -240,7 +240,7 @@ func (r Rect) CapBound() Cap { poleZ = 1 poleAngle = math.Pi/2 - r.Lat.Lo } - poleCap := CapFromCenterAngle(Point{r3.Vector{0, 0, poleZ}}, s1.Angle(poleAngle)*s1.Radian) + poleCap := CapFromCenterAngle(Point{r3.Vector{X: 0, Y: 0, Z: poleZ}}, s1.Angle(poleAngle)*s1.Radian) // For bounding rectangles that span 180 degrees or less in longitude, the // maximum cap size is achieved at one of the rectangle vertices. For @@ -310,7 +310,7 @@ func intersectsLatEdge(a, b Point, lat s1.Angle, lng s1.Interval) bool { } // Extend this to an orthonormal frame (x,y,z) where x is the direction - // where the great circle through AB achieves its maximium latitude. + // where the great circle through AB achieves its maximum latitude. y := Point{z.PointCross(PointFromCoords(0, 0, 1)).Normalize()} x := y.Cross(z.Vector) @@ -588,13 +588,13 @@ func directedHausdorffDistance(lngDiff s1.Angle, a, b r1.Interval) s1.Angle { // Case B3. if pLat > s1.Angle(a.Lo) { - intDist, ok := interiorMaxDistance(r1.Interval{a.Lo, math.Min(float64(pLat), a.Hi)}, bLo) + intDist, ok := interiorMaxDistance(r1.Interval{Lo: a.Lo, Hi: math.Min(float64(pLat), a.Hi)}, bLo) if ok { maxDistance = maxAngle(maxDistance, intDist) } } if pLat < s1.Angle(a.Hi) { - intDist, ok := interiorMaxDistance(r1.Interval{math.Max(float64(pLat), a.Lo), a.Hi}, bHi) + intDist, ok := interiorMaxDistance(r1.Interval{Lo: math.Max(float64(pLat), a.Lo), Hi: a.Hi}, bHi) if ok { maxDistance = maxAngle(maxDistance, intDist) } @@ -635,7 +635,7 @@ func bisectorIntersection(lat r1.Interval, lng s1.Angle) Point { } // A vector orthogonal to longitude 0. - orthoLng := Point{r3.Vector{0, -1, 0}} + orthoLng := Point{r3.Vector{X: 0, Y: -1, Z: 0}} return orthoLng.PointCross(PointFromLatLng(orthoBisector)) } @@ -706,7 +706,7 @@ func (r Rect) Centroid() Point { lng := r.Lng.Center() z := alpha * (z2 + z1) * (z2 - z1) // scaled by the area - return Point{r3.Vector{r0 * math.Cos(lng), r0 * math.Sin(lng), z}} + return Point{r3.Vector{X: r0 * math.Cos(lng), Y: r0 * math.Sin(lng), Z: z}} } // BUG: The major differences from the C++ version are: diff --git a/s2/rect_bounder.go b/s2/rect_bounder.go index a4a68349..7196f3c9 100644 --- a/s2/rect_bounder.go +++ b/s2/rect_bounder.go @@ -132,7 +132,7 @@ func (r *RectBounder) AddPoint(b Point) { // and B attains its minimum and maximum latitudes). To test whether AB // crosses this plane, we compute a vector M perpendicular to this // plane and then project A and B onto it. - m := n.Cross(r3.Vector{0, 0, 1}) + m := n.Cross(r3.Vector{X: 0, Y: 0, Z: 1}) mA := m.Dot(r.a.Vector) mB := m.Dot(b.Vector) diff --git a/s2/rect_bounder_test.go b/s2/rect_bounder_test.go index bd8c34cc..593060ae 100644 --- a/s2/rect_bounder_test.go +++ b/s2/rect_bounder_test.go @@ -41,13 +41,13 @@ func TestRectBounderMaxLatitudeSimple(t *testing.T) { }{ // Check cases where the min/max latitude is attained at a vertex. { - a: Point{r3.Vector{1, 1, 1}}, - b: Point{r3.Vector{1, -1, -1}}, + a: Point{r3.Vector{X: 1, Y: 1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: -1}}, want: cubeLatRect, }, { - a: Point{r3.Vector{1, -1, 1}}, - b: Point{r3.Vector{1, 1, -1}}, + a: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: 1, Z: -1}}, want: cubeLatRect, }, } @@ -71,32 +71,32 @@ func TestRectBounderMaxLatitudeEdgeInterior(t *testing.T) { // Max latitude, CW edge { math.Pi/4 + 0.5*rectErrorLat, - rectBoundForPoints(Point{r3.Vector{1, 1, 1}}, Point{r3.Vector{1, -1, 1}}).Lat.Hi, + rectBoundForPoints(Point{r3.Vector{X: 1, Y: 1, Z: 1}}, Point{r3.Vector{X: 1, Y: -1, Z: 1}}).Lat.Hi, }, // Min latitude, CW edge { -math.Pi/4 - 0.5*rectErrorLat, - rectBoundForPoints(Point{r3.Vector{1, -1, -1}}, Point{r3.Vector{-1, -1, -1}}).Lat.Lo, + rectBoundForPoints(Point{r3.Vector{X: 1, Y: -1, Z: -1}}, Point{r3.Vector{X: -1, Y: -1, Z: -1}}).Lat.Lo, }, // Max latitude, CCW edge { math.Pi/4 + 0.5*rectErrorLat, - rectBoundForPoints(Point{r3.Vector{1, -1, 1}}, Point{r3.Vector{1, 1, 1}}).Lat.Hi, + rectBoundForPoints(Point{r3.Vector{X: 1, Y: -1, Z: 1}}, Point{r3.Vector{X: 1, Y: 1, Z: 1}}).Lat.Hi, }, // Min latitude, CCW edge { -math.Pi/4 - 0.5*rectErrorLat, - rectBoundForPoints(Point{r3.Vector{-1, 1, -1}}, Point{r3.Vector{-1, -1, -1}}).Lat.Lo, + rectBoundForPoints(Point{r3.Vector{X: -1, Y: 1, Z: -1}}, Point{r3.Vector{X: -1, Y: -1, Z: -1}}).Lat.Lo, }, // Check cases where the edge passes through one of the poles. { math.Pi / 2, - rectBoundForPoints(Point{r3.Vector{.3, .4, 1}}, Point{r3.Vector{-.3, -.4, 1}}).Lat.Hi, + rectBoundForPoints(Point{r3.Vector{X: .3, Y: .4, Z: 1}}, Point{r3.Vector{X: -.3, Y: -.4, Z: 1}}).Lat.Hi, }, { -math.Pi / 2, - rectBoundForPoints(Point{r3.Vector{.3, .4, -1}}, Point{r3.Vector{-.3, -.4, -1}}).Lat.Lo, + rectBoundForPoints(Point{r3.Vector{X: .3, Y: .4, Z: -1}}, Point{r3.Vector{X: -.3, Y: -.4, Z: -1}}).Lat.Lo, }, } @@ -212,11 +212,11 @@ func TestRectBounderExpandForSubregions(t *testing.T) { xLat, xLng, yLat, yLng float64 wantRect Rect }{ - {1.5, -math.Pi / 2, 1.5, math.Pi/2 - 2e-16, Rect{r1.Interval{1.5, 1.5}, s1.FullInterval()}}, - {1.5, -math.Pi / 2, 1.5, math.Pi/2 - 7e-16, Rect{r1.Interval{1.5, 1.5}, s1.Interval{-math.Pi / 2, math.Pi/2 - 7e-16}}}, + {1.5, -math.Pi / 2, 1.5, math.Pi/2 - 2e-16, Rect{r1.Interval{Lo: 1.5, Hi: 1.5}, s1.FullInterval()}}, + {1.5, -math.Pi / 2, 1.5, math.Pi/2 - 7e-16, Rect{r1.Interval{Lo: 1.5, Hi: 1.5}, s1.Interval{Lo: -math.Pi / 2, Hi: math.Pi/2 - 7e-16}}}, // Check for cases where the bound is expanded to include one of the poles - {-math.Pi/2 + 1e-15, 0, -math.Pi/2 + 1e-15, 0, Rect{r1.Interval{-math.Pi / 2, -math.Pi/2 + 1e-15}, s1.FullInterval()}}, - {math.Pi/2 - 1e-15, 0, math.Pi/2 - 1e-15, 0, Rect{r1.Interval{math.Pi/2 - 1e-15, math.Pi / 2}, s1.FullInterval()}}, + {-math.Pi/2 + 1e-15, 0, -math.Pi/2 + 1e-15, 0, Rect{r1.Interval{Lo: -math.Pi / 2, Hi: -math.Pi/2 + 1e-15}, s1.FullInterval()}}, + {math.Pi/2 - 1e-15, 0, math.Pi/2 - 1e-15, 0, Rect{r1.Interval{Lo: math.Pi/2 - 1e-15, Hi: math.Pi / 2}, s1.FullInterval()}}, } for _, tc := range rectTests { diff --git a/s2/rect_test.go b/s2/rect_test.go index 30c59406..0dd15168 100644 --- a/s2/rect_test.go +++ b/s2/rect_test.go @@ -59,7 +59,7 @@ func TestRectArea(t *testing.T) { }{ {Rect{}, 0}, {FullRect(), 4 * math.Pi}, - {Rect{r1.Interval{0, math.Pi / 2}, s1.Interval{0, math.Pi / 2}}, math.Pi / 2}, + {Rect{r1.Interval{Lo: 0, Hi: math.Pi / 2}, s1.Interval{Lo: 0, Hi: math.Pi / 2}}, math.Pi / 2}, } for _, test := range tests { if got := test.rect.Area(); !float64Eq(got, test.want) { @@ -164,7 +164,7 @@ func TestRectAddPoint(t *testing.T) { } } func TestRectVertex(t *testing.T) { - r1 := Rect{r1.Interval{0, math.Pi / 2}, s1.IntervalFromEndpoints(-math.Pi, 0)} + r1 := Rect{r1.Interval{Lo: 0, Hi: math.Pi / 2}, s1.IntervalFromEndpoints(-math.Pi, 0)} tests := []struct { r Rect i int @@ -187,10 +187,10 @@ func TestRectVertexCCWOrder(t *testing.T) { lat := math.Pi / 4 * float64(i-2) lng := math.Pi/2*float64(i-2) + 0.2 r := Rect{ - r1.Interval{lat, lat + math.Pi/4}, + r1.Interval{Lo: lat, Hi: lat + math.Pi/4}, s1.Interval{ - math.Remainder(lng, 2*math.Pi), - math.Remainder(lng+math.Pi/2, 2*math.Pi), + Lo: math.Remainder(lng, 2*math.Pi), + Hi: math.Remainder(lng+math.Pi/2, 2*math.Pi), }, } @@ -385,15 +385,15 @@ func TestRectCapBound(t *testing.T) { }{ { // Bounding cap at center is smaller. rectFromDegrees(-45, -45, 45, 45), - CapFromCenterHeight(Point{r3.Vector{1, 0, 0}}, 0.5), + CapFromCenterHeight(Point{r3.Vector{X: 1, Y: 0, Z: 0}}, 0.5), }, { // Bounding cap at north pole is smaller. rectFromDegrees(88, -80, 89, 80), - CapFromCenterAngle(Point{r3.Vector{0, 0, 1}}, s1.Angle(2)*s1.Degree), + CapFromCenterAngle(Point{r3.Vector{X: 0, Y: 0, Z: 1}}, s1.Angle(2)*s1.Degree), }, { // Longitude span > 180 degrees. rectFromDegrees(-30, -150, -10, 50), - CapFromCenterAngle(Point{r3.Vector{0, 0, -1}}, s1.Angle(80)*s1.Degree), + CapFromCenterAngle(Point{r3.Vector{X: 0, Y: 0, Z: -1}}, s1.Angle(80)*s1.Degree), }, } for _, test := range tests { @@ -535,7 +535,7 @@ func TestRectIntervalOps(t *testing.T) { } func TestRectCellOps(t *testing.T) { - cell0 := CellFromPoint(Point{r3.Vector{1 + 1e-12, 1, 1}}) + cell0 := CellFromPoint(Point{r3.Vector{X: 1 + 1e-12, Y: 1, Z: 1}}) v0 := LatLngFromPoint(cell0.Vertex(0)) cell202 := CellFromCellID(CellIDFromFacePosLevel(2, 0, 2)) @@ -685,8 +685,8 @@ func TestRectContainsPoint(t *testing.T) { p Point want bool }{ - {r1, Point{r3.Vector{0.5, -0.3, 0.1}}, true}, - {r1, Point{r3.Vector{0.5, 0.2, 0.1}}, false}, + {r1, Point{r3.Vector{X: 0.5, Y: -0.3, Z: 0.1}}, true}, + {r1, Point{r3.Vector{X: 0.5, Y: 0.2, Z: 0.1}}, false}, } for _, test := range tests { if got, want := test.r.ContainsPoint(test.p), test.want; got != want { @@ -704,56 +704,56 @@ func TestRectIntersectsLatEdge(t *testing.T) { want bool }{ { - a: Point{r3.Vector{-1, -1, 1}}, - b: Point{r3.Vector{1, -1, 1}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, lat: 41 * s1.Degree, lngLo: -87 * s1.Degree, lngHi: -79 * s1.Degree, want: false, }, { - a: Point{r3.Vector{-1, -1, 1}}, - b: Point{r3.Vector{1, -1, 1}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, lat: 42 * s1.Degree, lngLo: -87 * s1.Degree, lngHi: -79 * s1.Degree, want: false, }, { - a: Point{r3.Vector{-1, -1, -1}}, - b: Point{r3.Vector{1, 1, 0}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: -1}}, + b: Point{r3.Vector{X: 1, Y: 1, Z: 0}}, lat: -3 * s1.Degree, lngLo: -1 * s1.Degree, lngHi: 23 * s1.Degree, want: false, }, { - a: Point{r3.Vector{1, 0, 1}}, - b: Point{r3.Vector{1, -1, 0}}, + a: Point{r3.Vector{X: 1, Y: 0, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 0}}, lat: -28 * s1.Degree, lngLo: 69 * s1.Degree, lngHi: 115 * s1.Degree, want: false, }, { - a: Point{r3.Vector{0, 1, 0}}, - b: Point{r3.Vector{1, -1, -1}}, + a: Point{r3.Vector{X: 0, Y: 1, Z: 0}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: -1}}, lat: 44 * s1.Degree, lngLo: 60 * s1.Degree, lngHi: 177 * s1.Degree, want: false, }, { - a: Point{r3.Vector{0, 1, 1}}, - b: Point{r3.Vector{0, 1, -1}}, + a: Point{r3.Vector{X: 0, Y: 1, Z: 1}}, + b: Point{r3.Vector{X: 0, Y: 1, Z: -1}}, lat: -25 * s1.Degree, lngLo: -74 * s1.Degree, lngHi: -165 * s1.Degree, want: true, }, { - a: Point{r3.Vector{1, 0, 0}}, - b: Point{r3.Vector{0, 0, -1}}, + a: Point{r3.Vector{X: 1, Y: 0, Z: 0}}, + b: Point{r3.Vector{X: 0, Y: 0, Z: -1}}, lat: -4 * s1.Degree, lngLo: -152 * s1.Degree, lngHi: 171 * s1.Degree, @@ -761,8 +761,8 @@ func TestRectIntersectsLatEdge(t *testing.T) { }, // from a bug report { - a: Point{r3.Vector{-0.589375791872893683986945, 0.583248451588733285433364, 0.558978908075738245564423}}, - b: Point{r3.Vector{-0.587388131301997518107783, 0.581281455376392863776402, 0.563104832905072516524569}}, + a: Point{r3.Vector{X: -0.589375791872893683986945, Y: 0.583248451588733285433364, Z: 0.558978908075738245564423}}, + b: Point{r3.Vector{X: -0.587388131301997518107783, Y: 0.581281455376392863776402, Z: 0.563104832905072516524569}}, lat: 34.2572864 * s1.Degree, lngLo: 2.3608609 * s1.Radian, lngHi: 2.3614230 * s1.Radian, @@ -771,7 +771,7 @@ func TestRectIntersectsLatEdge(t *testing.T) { } for _, test := range tests { - if got := intersectsLatEdge(test.a, test.b, test.lat, s1.Interval{float64(test.lngLo), float64(test.lngHi)}); got != test.want { + if got := intersectsLatEdge(test.a, test.b, test.lat, s1.Interval{Lo: float64(test.lngLo), Hi: float64(test.lngHi)}); got != test.want { t.Errorf("intersectsLatEdge(%v, %v, %v, {%v, %v}) = %t, want %t", test.a, test.b, test.lat, test.lngLo, test.lngHi, got, test.want) } @@ -787,64 +787,64 @@ func TestRectIntersectsLngEdge(t *testing.T) { want bool }{ { - a: Point{r3.Vector{-1, -1, 1}}, - b: Point{r3.Vector{1, -1, 1}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, latLo: 41 * s1.Degree, latHi: 42 * s1.Degree, lng: -79 * s1.Degree, want: false, }, { - a: Point{r3.Vector{-1, -1, 1}}, - b: Point{r3.Vector{1, -1, 1}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, latLo: 41 * s1.Degree, latHi: 42 * s1.Degree, lng: -87 * s1.Degree, want: false, }, { - a: Point{r3.Vector{-1, -1, 1}}, - b: Point{r3.Vector{1, -1, 1}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, latLo: 42 * s1.Degree, latHi: 41 * s1.Degree, lng: 79 * s1.Degree, want: false, }, { - a: Point{r3.Vector{-1, -1, 1}}, - b: Point{r3.Vector{1, -1, 1}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: 1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, latLo: 41 * s1.Degree, latHi: 42 * s1.Degree, lng: 87 * s1.Degree, want: false, }, { - a: Point{r3.Vector{0, -1, -1}}, - b: Point{r3.Vector{-1, 0, -1}}, + a: Point{r3.Vector{X: 0, Y: -1, Z: -1}}, + b: Point{r3.Vector{X: -1, Y: 0, Z: -1}}, latLo: -87 * s1.Degree, latHi: 13 * s1.Degree, lng: -143 * s1.Degree, want: true, }, { - a: Point{r3.Vector{1, 1, -1}}, - b: Point{r3.Vector{1, -1, 1}}, + a: Point{r3.Vector{X: 1, Y: 1, Z: -1}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: 1}}, latLo: -64 * s1.Degree, latHi: 13 * s1.Degree, lng: 40 * s1.Degree, want: true, }, { - a: Point{r3.Vector{1, 1, 0}}, - b: Point{r3.Vector{-1, 0, -1}}, + a: Point{r3.Vector{X: 1, Y: 1, Z: 0}}, + b: Point{r3.Vector{X: -1, Y: 0, Z: -1}}, latLo: -64 * s1.Degree, latHi: 56 * s1.Degree, lng: 151 * s1.Degree, want: true, }, { - a: Point{r3.Vector{-1, -1, 0}}, - b: Point{r3.Vector{1, -1, -1}}, + a: Point{r3.Vector{X: -1, Y: -1, Z: 0}}, + b: Point{r3.Vector{X: 1, Y: -1, Z: -1}}, latLo: -50 * s1.Degree, latHi: 18 * s1.Degree, lng: -84 * s1.Degree, @@ -853,7 +853,7 @@ func TestRectIntersectsLngEdge(t *testing.T) { } for _, test := range tests { - if got := intersectsLngEdge(test.a, test.b, r1.Interval{float64(test.latLo), float64(test.latHi)}, test.lng); got != test.want { + if got := intersectsLngEdge(test.a, test.b, r1.Interval{Lo: float64(test.latLo), Hi: float64(test.latHi)}, test.lng); got != test.want { t.Errorf("intersectsLngEdge(%v, %v, {%v, %v}, %v) = %v, want %v", test.a, test.b, test.latLo, test.latHi, test.lng, got, test.want) } @@ -1147,12 +1147,12 @@ func testRectCentroidSplitting(t *testing.T, r Rect, leftSplits int) { var child0, child1 Rect if oneIn(2) { lat := randomUniformFloat64(r.Lat.Lo, r.Lat.Hi) - child0 = Rect{r1.Interval{r.Lat.Lo, lat}, r.Lng} - child1 = Rect{r1.Interval{lat, r.Lat.Hi}, r.Lng} + child0 = Rect{r1.Interval{Lo: r.Lat.Lo, Hi: lat}, r.Lng} + child1 = Rect{r1.Interval{Lo: lat, Hi: r.Lat.Hi}, r.Lng} } else { lng := randomUniformFloat64(r.Lng.Lo, r.Lng.Hi) - child0 = Rect{r.Lat, s1.Interval{r.Lng.Lo, lng}} - child1 = Rect{r.Lat, s1.Interval{lng, r.Lng.Hi}} + child0 = Rect{r.Lat, s1.Interval{Lo: r.Lng.Lo, Hi: lng}} + child1 = Rect{r.Lat, s1.Interval{Lo: lng, Hi: r.Lng.Hi}} } if got, want := r.Centroid().Sub(child0.Centroid().Vector).Sub(child1.Centroid().Vector).Norm(), 1e-15; got > want { @@ -1169,12 +1169,12 @@ func TestRectCentroidFullRange(t *testing.T) { for i := 0; i < 100; i++ { lat1 := randomUniformFloat64(-math.Pi/2, math.Pi/2) lat2 := randomUniformFloat64(-math.Pi/2, math.Pi/2) - r := Rect{r1.Interval{lat1, lat2}, s1.FullInterval()} + r := Rect{r1.Interval{Lo: lat1, Hi: lat2}, s1.FullInterval()} centroid := r.Centroid() if want := 0.5 * (math.Sin(lat1) + math.Sin(lat2)) * r.Area(); !float64Near(want, centroid.Z, epsilon) { t.Errorf("%v.Centroid().Z was %v, want %v", r, centroid.Z, want) } - if got := (r2.Point{centroid.X, centroid.Y}.Norm()); got > epsilon { + if got := (r2.Point{X: centroid.X, Y: centroid.Y}.Norm()); got > epsilon { t.Errorf("%v.Centroid().Norm() was %v, want > %v ", r, got, epsilon) } } @@ -1183,7 +1183,7 @@ func TestRectCentroidFullRange(t *testing.T) { for i := 0; i < 100; i++ { lat1 := randomUniformFloat64(-math.Pi, math.Pi) lat2 := randomUniformFloat64(-math.Pi, math.Pi) - r := Rect{r1.Interval{-math.Pi / 2, math.Pi / 2}, s1.Interval{lat1, lat2}} + r := Rect{r1.Interval{Lo: -math.Pi / 2, Hi: math.Pi / 2}, s1.Interval{Lo: lat1, Hi: lat2}} centroid := r.Centroid() if got, want := math.Abs(centroid.Z), epsilon; got > want { @@ -1195,7 +1195,7 @@ func TestRectCentroidFullRange(t *testing.T) { } alpha := 0.5 * r.Lng.Length() - if got, want := (r2.Point{centroid.X, centroid.Y}.Norm()), (0.25 * math.Pi * math.Sin(alpha) / alpha * r.Area()); !float64Near(got, want, epsilon) { + if got, want := (r2.Point{X: centroid.X, Y: centroid.Y}.Norm()), (0.25 * math.Pi * math.Sin(alpha) / alpha * r.Area()); !float64Near(got, want, epsilon) { t.Errorf("%v.Centroid().Norm() = %v, want ~%v", got, want, epsilon) } } @@ -1204,5 +1204,5 @@ func TestRectCentroidFullRange(t *testing.T) { // the centroids of the pieces add to give the centroid of their parent. // To make the code simpler we avoid rectangles that cross the 180 degree // line of longitude. - testRectCentroidSplitting(t, Rect{r1.Interval{-math.Pi / 2, math.Pi / 2}, s1.Interval{-math.Pi, math.Pi}}, 10) + testRectCentroidSplitting(t, Rect{r1.Interval{Lo: -math.Pi / 2, Hi: math.Pi / 2}, s1.Interval{Lo: -math.Pi, Hi: math.Pi}}, 10) } diff --git a/s2/s2_test.go b/s2/s2_test.go index c370156c..e07077f7 100644 --- a/s2/s2_test.go +++ b/s2/s2_test.go @@ -401,7 +401,7 @@ type fractal struct { minLevel int // dimension of the fractal. A value of approximately 1.26 corresponds - // to the stardard Koch curve. The value must lie in the range [1.0, 2.0). + // to the standard Koch curve. The value must lie in the range [1.0, 2.0). dimension float64 // The ratio of the sub-edge length to the original edge length at each @@ -509,9 +509,9 @@ func (f *fractal) generateR2Vertices() []r2.Point { // The Koch "snowflake" consists of three Koch curves whose initial edges // form an equilateral triangle. - v0 := r2.Point{1.0, 0.0} - v1 := r2.Point{-0.5, math.Sqrt(3) / 2} - v2 := r2.Point{-0.5, -math.Sqrt(3) / 2} + v0 := r2.Point{X: 1.0, Y: 0.0} + v1 := r2.Point{X: -0.5, Y: math.Sqrt(3) / 2} + v2 := r2.Point{X: -0.5, Y: -math.Sqrt(3) / 2} vertices = append(vertices, f.r2VerticesHelper(v0, v1, 0)...) vertices = append(vertices, f.r2VerticesHelper(v1, v2, 0)...) vertices = append(vertices, f.r2VerticesHelper(v2, v0, 0)...) diff --git a/s2/s2intersect/s2intersect_test.go b/s2/s2intersect/s2intersect_test.go index 5ae558e9..f64126fc 100644 --- a/s2/s2intersect/s2intersect_test.go +++ b/s2/s2intersect/s2intersect_test.go @@ -14,8 +14,507 @@ package s2intersect -import "math/rand" +import ( + "sort" + "testing" -func init() { - rand.Seed(1) + "github.com/golang/geo/s1" + "github.com/golang/geo/s2" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +// capCoverings returns coverings for a set of overlapping s2.Caps. +func capCoverings(rc *s2.RegionCoverer) []s2.CellUnion { + var cus []s2.CellUnion + for _, centre := range []s2.LatLng{ + s2.LatLngFromDegrees(-26.210955, 28.041440), + s2.LatLngFromDegrees(-26.257569, 28.459799), + s2.LatLngFromDegrees(-26.297932, 28.323583), + s2.LatLngFromDegrees(-26.157067, 28.370976), + } { + cap := s2.CapFromCenterAngle(s2.PointFromLatLng(centre), s1.Degree/3) + cus = append(cus, rc.Covering(cap)) + } + return cus +} + +func BenchmarkPair(b *testing.B) { + rc := &s2.RegionCoverer{ + MaxLevel: 14, + MaxCells: 100, + } + cus := capCoverings(rc)[:2] + + b.Run("Find", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Find(cus) + } + }) + + b.Run("CellUnionFromIntersection", func(b *testing.B) { + for i := 0; i < b.N; i++ { + s2.CellUnionFromIntersection(cus[0], cus[1]) + } + }) +} + +func TestFind(t *testing.T) { + // Create Caps from arbitrary centres, cover them, and then compare + // intersections returned by Find() to those from a brute force method using + // s2.CellUnionFromIntersection(). Although this adds logic to a test, it's + // still clearer than looking at arbitrary lists of CellIDs. + rc := &s2.RegionCoverer{ + MaxLevel: 14, + MaxCells: 100, + } + testInput := capCoverings(rc) + + // Manual means of computing an intersection from the built-in + // s2.CellUnionFromIntersection() function. + intersection := func(indices []int) s2.CellUnion { + if len(indices) == 0 { + return nil + } + result := testInput[indices[0]] + for _, idx := range indices[1:] { + result = s2.CellUnionFromIntersection(result, testInput[idx]) + } + return result + } + // Brute-force calculation of the Intersections requires subtraction of those + // Cells assigned to super-set Intersections. See Find() re mutually exclusive + // output. + bruteForce := func(indices []int, subtract [][]int) Intersection { + i := intersection(indices) + for _, s := range subtract { + i = s2.CellUnionFromDifference(i, intersection(s)) + } + return Intersection{ + Indices: indices, + Intersection: i, + } + } + got := Find(testInput) + want := []Intersection{ + // Iterate over the elements of the power set of {0,1,2,3} that have >=2 + // elements in them. + // + // For each, the []int slice is the actual set of indices we are expecting, + // whereas the 2d [][]int slice captures the other intersections that + // "steal" from the value because they have a super set of indices. + bruteForce([]int{0, 1}, [][]int{{0, 1, 2}, {0, 1, 3}, {0, 1, 2, 3}}), + bruteForce([]int{0, 2}, [][]int{{0, 1, 2}, {0, 2, 3}, {0, 1, 2, 3}}), + bruteForce([]int{0, 3}, [][]int{{0, 1, 3}, {0, 2, 3}, {0, 1, 2, 3}}), + bruteForce([]int{1, 2}, [][]int{{0, 1, 2}, {1, 2, 3}, {0, 1, 2, 3}}), + bruteForce([]int{1, 3}, [][]int{{0, 1, 3}, {1, 2, 3}, {0, 1, 2, 3}}), + bruteForce([]int{2, 3}, [][]int{{0, 2, 3}, {1, 2, 3}, {0, 1, 2, 3}}), + bruteForce([]int{0, 1, 2}, [][]int{{0, 1, 2, 3}}), + bruteForce([]int{0, 1, 3}, [][]int{{0, 1, 2, 3}}), + bruteForce([]int{0, 2, 3}, [][]int{{0, 1, 2, 3}}), + bruteForce([]int{1, 2, 3}, [][]int{{0, 1, 2, 3}}), + bruteForce([]int{0, 1, 2, 3}, nil), + } + + // Some of the manual calculation may have resulted in empty intersecting + // CellUnions (i.e. not actually an Intersection). This is merely because + // we're iterating over every single option by hand. + var wantNonEmpty []Intersection + for _, w := range want { + if len(w.Intersection) > 0 { + wantNonEmpty = append(wantNonEmpty, w) + } + } + + sortIntersections(t, got) + sortIntersections(t, wantNonEmpty) + + if diff := cmp.Diff(wantNonEmpty, got); diff != "" { + t.Errorf("Find([four caps; see code] diff (-want +got):\n%s)", diff) + } +} + +func TestFindLeaves(t *testing.T) { + leaf := func(idx int64) s2.CellID { + return sydney.RangeMin().Advance(idx) + } + + cus := []s2.CellUnion{ + /* + * The cell leaf(0) is denoted with #. + * Note that this is constructed such that (a) [1] starts where [2] ends, + * and ends where [0] begins again; and (b) it includes intervals of length + * 1. Both scenarios failed prior to the changes made along with this test. + * + * # + * 0: |====| = =| + * 1: | ==|== =| + * 2: | == | =| + * ABC C B + */ + { + leaf(-4), leaf(-3), leaf(-2), leaf(-1), + leaf(1), leaf(3), + }, + { + leaf(-2), leaf(-1), leaf(0), leaf(1), leaf(3), + }, + { + leaf(-3), leaf(-2), leaf(3), + }, + } + + got := Find(cus) + want := []Intersection{ + // A + { + Indices: []int{0, 2}, + Intersection: s2.CellUnion{leaf(-3)}, + }, + // B + { + Indices: []int{0, 1, 2}, + Intersection: s2.CellUnion{leaf(-2), leaf(3)}, + }, + // C + { + Indices: []int{0, 1}, + Intersection: s2.CellUnion{leaf(-1), leaf(1)}, + }, + } + + sortIntersections(t, got) + sortIntersections(t, want) + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("Find([overlaps with leaf Cells; see code] diff (-want +got):\n%s)", diff) + } +} + +// sorts lexicographically by Indices slice. +func sortIntersections(t *testing.T, ints []Intersection) { + t.Helper() + + sort.Slice(ints, func(i, j int) bool { + iI, iJ := ints[i], ints[j] + if nI, nJ := len(iI.Indices), len(iJ.Indices); nI != nJ { + return nI < nJ + } + + for k, idx := range iI.Indices { + if idx != iJ.Indices[k] { + return idx < iJ.Indices[k] + } + } + + t.Fatalf("Sorting %T found two elements with identical Indices %d", ints, iI.Indices) + return true + }) +} + +// Improves error output. +func (t limitType) String() string { + if t == start { + return "start" + } + return "end" +} + +func TestEmptyOutput(t *testing.T) { + tests := []struct { + name string + cus []s2.CellUnion + }{ + { + name: "nil input", + cus: nil, + }, + { + name: "non-nil but empty input", + cus: []s2.CellUnion{}, + }, + { + name: "single CellUnion input", + cus: []s2.CellUnion{{sydney}}, + }, + { + name: "disjoint CellUnion input", + cus: []s2.CellUnion{{sydney.Prev()}, {sydney.Next()}}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Find(tt.cus); len(got) != 0 { + t.Errorf("Find(%v) got %+v; want empty slice", tt.cus, got) + } + }) + } +} + +const sydney = s2.CellID(0x6b12b00000000000) + +func TestCellUnionToIntervalLimits(t *testing.T) { + tests := []struct { + name string + cu s2.CellUnion + want []*limit // Note that limit.indices are ignored + }{ + { + name: "empty", + want: nil, + }, + { + name: "single Cell", + cu: s2.CellUnion{sydney}, + want: []*limit{ + { + leaf: sydney.RangeMin(), + typ: start, + }, + { + leaf: sydney.RangeMax(), + typ: end, + }, + }, + }, + { + name: "two contiguous Cells are merged into single interval", + cu: s2.CellUnion{sydney, sydney.Next()}, + want: []*limit{ + { + leaf: sydney.RangeMin(), + typ: start, + }, + { + leaf: sydney.Next().RangeMax(), + typ: end, + }, + }, + }, + { + name: "three contiguous Cells are merged into single interval", + cu: s2.CellUnion{sydney.Prev(), sydney, sydney.Next()}, + want: []*limit{ + { + leaf: sydney.Prev().RangeMin(), + typ: start, + }, + { + leaf: sydney.Next().RangeMax(), + typ: end, + }, + }, + }, + { + name: "two contiguous Cells at different levels are merged into single interval", + cu: s2.CellUnion{sydney, sydney.Next().ChildBegin()}, + want: []*limit{ + { + leaf: sydney.RangeMin(), + typ: start, + }, + { + leaf: sydney.Next().ChildBegin().RangeMax(), + typ: end, + }, + }, + }, + { + name: "non-contiguous Cells are separate intervals", + cu: s2.CellUnion{sydney.Prev(), sydney.Next()}, + want: []*limit{ + { + leaf: sydney.Prev().RangeMin(), + typ: start, + }, + { + leaf: sydney.Prev().RangeMax(), + typ: end, + }, + { + leaf: sydney.Next().RangeMin(), + typ: start, + }, + { + leaf: sydney.Next().RangeMax(), + typ: end, + }, + }, + }, + { + name: "mix of contiguous and non-contiguous Cells", + cu: s2.CellUnion{ + // Those expected to be grouped into a single interval are on the same line + sydney.Prev().Prev(), // A + sydney, sydney.Next().Children()[0], sydney.Next().Children()[1], // B + // Note the gap that excludes Children()[2] + sydney.Next().Children()[3], sydney.Next().Next(), // C + }, + want: []*limit{ + // A + { + leaf: sydney.Prev().Prev().RangeMin(), + typ: start, + }, + { + leaf: sydney.Prev().Prev().RangeMax(), + typ: end, + }, + // B + { + leaf: sydney.RangeMin(), + typ: start, + }, + { + leaf: sydney.Next().Children()[1].RangeMax(), + typ: end, + }, + // C + { + leaf: sydney.Next().Children()[3].RangeMin(), + typ: start, + }, + { + leaf: sydney.Next().Next().RangeMax(), + typ: end, + }, + }, + }, + } + + opts := []cmp.Option{ + cmp.AllowUnexported(limit{}), + cmpopts.IgnoreFields(limit{}, "indices"), + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := cellUnionToIntervalLimits(tt.cu, 0) + if diff := cmp.Diff(tt.want, got, opts...); diff != "" { + t.Errorf("cellUnionToIntervalLimits(%v) diff (-want +got):\n%s", tt.cu, diff) + } + }) + } +} + +func TestCellUnionsToOverlaps(t *testing.T) { + tests := []struct { + name string + cus []s2.CellUnion + want []overlap + }{ + { + name: "same Cell", + cus: []s2.CellUnion{ + {sydney}, + {sydney}, + }, + want: []overlap{ + { + indices: []int{0, 1}, + start: sydney.RangeMin(), + end: sydney.RangeMax(), + }, + }, + }, + { + name: "same 2 Cells", + cus: []s2.CellUnion{ + {sydney, sydney.Next()}, + {sydney, sydney.Next()}, + }, + want: []overlap{ + { + indices: []int{0, 1}, + start: sydney.RangeMin(), + end: sydney.Next().RangeMax(), + }, + }, + }, + { + name: "partial overlap between two CellUnions", + cus: []s2.CellUnion{ + {sydney}, + {sydney.Prev(), sydney, sydney.Next()}, + }, + want: []overlap{ + { + indices: []int{0, 1}, + start: sydney.RangeMin(), + end: sydney.RangeMax(), + }, + }, + }, + { + name: "arbitrary mix (see code comments for diagram)", + /* + * 0: |====| ==| | + * 1: |== | =|=== | + * 2: |====|====| ==| + * AABB CD E + */ + cus: []s2.CellUnion{ + { + sydney.Prev(), + sydney.Children()[2], sydney.Children()[3], + }, + { + sydney.Prev().Children()[0], sydney.Prev().Children()[1], + sydney.Children()[3], + sydney.Next().Children()[0], sydney.Next().Children()[1], sydney.Next().Children()[2], + }, + { + sydney.Prev(), + sydney, + sydney.Next().Children()[2], sydney.Next().Children()[3], + }, + }, + want: []overlap{ + // A + { + indices: []int{0, 1, 2}, + start: sydney.Prev().RangeMin(), + end: sydney.Prev().Children()[1].RangeMax(), + }, + // B + { + indices: []int{0, 2}, + start: sydney.Prev().Children()[2].RangeMin(), + end: sydney.Prev().Children()[3].RangeMax(), + }, + // C + { + indices: []int{0, 2}, + start: sydney.Children()[2].RangeMin(), + end: sydney.Children()[2].RangeMax(), + }, + // D + { + indices: []int{0, 1, 2}, + start: sydney.Children()[3].RangeMin(), + end: sydney.Children()[3].RangeMax(), + }, + // E + { + indices: []int{1, 2}, + start: sydney.Next().Children()[2].RangeMin(), + end: sydney.Next().Children()[2].RangeMax(), + }, + }, + }, + } + + opts := []cmp.Option{ + cmp.AllowUnexported(overlap{}), + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := cellUnionsToOverlaps(tt.cus) + if diff := cmp.Diff(tt.want, got, opts...); diff != "" { + t.Errorf("cellUnionsToOverlaps(%v) diff (-want +got):\n%s", tt.cus, diff) + } + }) + } } diff --git a/s2/shapeindex.go b/s2/shapeindex.go index 045c28f9..3e2bc5be 100644 --- a/s2/shapeindex.go +++ b/s2/shapeindex.go @@ -604,7 +604,7 @@ type ShapeIndex struct { // the amount of entities added grows. // - Often the index will never be queried, in which case we can save both // the time and memory required to build it. Examples: - // + Loops that are created simply to pass to an Polygon. (We don't + // + Loops that are created simply to pass to a Polygon. (We don't // need the Loop index, because Polygon builds its own index.) // + Applications that load a database of geometry and then query only // a small fraction of it. @@ -892,9 +892,9 @@ func (s *ShapeIndex) addFaceEdge(fe faceEdge, allEdges [][]faceEdge) { // the edge of the face that they don't intersect any (padded) adjacent face. if aFace == face(fe.edge.V1.Vector) { x, y := validFaceXYZToUV(aFace, fe.edge.V0.Vector) - fe.a = r2.Point{x, y} + fe.a = r2.Point{X: x, Y: y} x, y = validFaceXYZToUV(aFace, fe.edge.V1.Vector) - fe.b = r2.Point{x, y} + fe.b = r2.Point{X: x, Y: y} maxUV := 1 - cellPadding if math.Abs(fe.a.X) <= maxUV && math.Abs(fe.a.Y) <= maxUV && @@ -1035,7 +1035,7 @@ func (s *ShapeIndex) updateEdges(pcell *PaddedCell, edges []*clippedEdge, t *tra indexCellAbsorbed = true disjointFromIndex = true } else { - // DCHECK_EQ(SUBDIVIDED, r) + // ABSL_DCHECK_EQ(SUBDIVIDED, r) } } diff --git a/s2/shapeindex_test.go b/s2/shapeindex_test.go index ab0a7017..1f4f2691 100644 --- a/s2/shapeindex_test.go +++ b/s2/shapeindex_test.go @@ -430,7 +430,7 @@ func TestShapeIndexManyTinyEdges(t *testing.T) { // Construct two points in the same leaf cell. a := cellIDFromPoint(PointFromCoords(1, 0, 0)).Point() - b := Point{a.Add(r3.Vector{0, 1e-12, 0}).Normalize()} + b := Point{a.Add(r3.Vector{X: 0, Y: 1e-12, Z: 0}).Normalize()} shape := &edgeVectorShape{} for i := 0; i < 100; i++ { shape.Add(a, b) diff --git a/s2/stuv.go b/s2/stuv.go index 261bdd80..02e70bd5 100644 --- a/s2/stuv.go +++ b/s2/stuv.go @@ -41,7 +41,7 @@ import ( // id, the following coordinate systems are used: // // (id) -// An CellID is a 64-bit encoding of a face and a Hilbert curve position +// A CellID is a 64-bit encoding of a face and a Hilbert curve position // on that face. The Hilbert curve position implicitly encodes both the // position of a cell and its subdivision level (see s2cellid.go). // @@ -151,7 +151,7 @@ const ( ) // siTiToST converts an si- or ti-value to the corresponding s- or t-value. -// Value is capped at 1.0 because there is no DCHECK in Go. +// Value is capped at 1.0 because there is no ABSL_DCHECK in Go. func siTiToST(si uint32) float64 { if si > maxSiTi { return 1.0 @@ -236,17 +236,17 @@ func xyzToFaceUV(r r3.Vector) (f int, u, v float64) { func faceUVToXYZ(face int, u, v float64) r3.Vector { switch face { case 0: - return r3.Vector{1, u, v} + return r3.Vector{X: 1, Y: u, Z: v} case 1: - return r3.Vector{-u, 1, v} + return r3.Vector{X: -u, Y: 1, Z: v} case 2: - return r3.Vector{-u, -v, 1} + return r3.Vector{X: -u, Y: -v, Z: 1} case 3: - return r3.Vector{-1, -v, -u} + return r3.Vector{X: -1, Y: -v, Z: -u} case 4: - return r3.Vector{v, -1, -u} + return r3.Vector{X: v, Y: -1, Z: -u} default: - return r3.Vector{v, u, -1} + return r3.Vector{X: v, Y: u, Z: -1} } } @@ -291,17 +291,17 @@ func faceXYZtoUVW(face int, p Point) Point { // axes for the given face (see faceUVWAxes). switch face { case 0: - return Point{r3.Vector{p.Y, p.Z, p.X}} + return Point{r3.Vector{X: p.Y, Y: p.Z, Z: p.X}} case 1: - return Point{r3.Vector{-p.X, p.Z, p.Y}} + return Point{r3.Vector{X: -p.X, Y: p.Z, Z: p.Y}} case 2: - return Point{r3.Vector{-p.X, -p.Y, p.Z}} + return Point{r3.Vector{X: -p.X, Y: -p.Y, Z: p.Z}} case 3: - return Point{r3.Vector{-p.Z, -p.Y, -p.X}} + return Point{r3.Vector{X: -p.Z, Y: -p.Y, Z: -p.X}} case 4: - return Point{r3.Vector{-p.Z, p.X, -p.Y}} + return Point{r3.Vector{X: -p.Z, Y: p.X, Z: -p.Y}} default: - return Point{r3.Vector{p.Y, p.X, -p.Z}} + return Point{r3.Vector{X: p.Y, Y: p.X, Z: -p.Z}} } } @@ -346,17 +346,17 @@ func xyzToFaceSiTi(p Point) (face int, si, ti uint32, level int) { func uNorm(face int, u float64) r3.Vector { switch face { case 0: - return r3.Vector{u, -1, 0} + return r3.Vector{X: u, Y: -1, Z: 0} case 1: - return r3.Vector{1, u, 0} + return r3.Vector{X: 1, Y: u, Z: 0} case 2: - return r3.Vector{1, 0, u} + return r3.Vector{X: 1, Y: 0, Z: u} case 3: - return r3.Vector{-u, 0, 1} + return r3.Vector{X: -u, Y: 0, Z: 1} case 4: - return r3.Vector{0, -u, 1} + return r3.Vector{X: 0, Y: -u, Z: 1} default: - return r3.Vector{0, -1, -u} + return r3.Vector{X: 0, Y: -1, Z: -u} } } @@ -366,28 +366,28 @@ func uNorm(face int, u float64) r3.Vector { func vNorm(face int, v float64) r3.Vector { switch face { case 0: - return r3.Vector{-v, 0, 1} + return r3.Vector{X: -v, Y: 0, Z: 1} case 1: - return r3.Vector{0, -v, 1} + return r3.Vector{X: 0, Y: -v, Z: 1} case 2: - return r3.Vector{0, -1, -v} + return r3.Vector{X: 0, Y: -1, Z: -v} case 3: - return r3.Vector{v, -1, 0} + return r3.Vector{X: v, Y: -1, Z: 0} case 4: - return r3.Vector{1, v, 0} + return r3.Vector{X: 1, Y: v, Z: 0} default: - return r3.Vector{1, 0, v} + return r3.Vector{X: 1, Y: 0, Z: v} } } // faceUVWAxes are the U, V, and W axes for each face. var faceUVWAxes = [6][3]Point{ - {Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{1, 0, 0}}}, - {Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{0, 1, 0}}}, - {Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{0, 0, 1}}}, - {Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{-1, 0, 0}}}, - {Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, -1, 0}}}, - {Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, 0, -1}}}, + {Point{r3.Vector{X: 0, Y: 1, Z: 0}}, Point{r3.Vector{X: 0, Y: 0, Z: 1}}, Point{r3.Vector{X: 1, Y: 0, Z: 0}}}, + {Point{r3.Vector{X: -1, Y: 0, Z: 0}}, Point{r3.Vector{X: 0, Y: 0, Z: 1}}, Point{r3.Vector{X: 0, Y: 1, Z: 0}}}, + {Point{r3.Vector{X: -1, Y: 0, Z: 0}}, Point{r3.Vector{X: 0, Y: -1, Z: 0}}, Point{r3.Vector{X: 0, Y: 0, Z: 1}}}, + {Point{r3.Vector{X: 0, Y: 0, Z: -1}}, Point{r3.Vector{X: 0, Y: -1, Z: 0}}, Point{r3.Vector{X: -1, Y: 0, Z: 0}}}, + {Point{r3.Vector{X: 0, Y: 0, Z: -1}}, Point{r3.Vector{X: 1, Y: 0, Z: 0}}, Point{r3.Vector{X: 0, Y: -1, Z: 0}}}, + {Point{r3.Vector{X: 0, Y: 1, Z: 0}}, Point{r3.Vector{X: 1, Y: 0, Z: 0}}, Point{r3.Vector{X: 0, Y: 0, Z: -1}}}, } // faceUVWFaces are the precomputed neighbors of each face. diff --git a/s2/stuv_test.go b/s2/stuv_test.go index 2d4a4dca..5af8dc0d 100644 --- a/s2/stuv_test.go +++ b/s2/stuv_test.go @@ -87,15 +87,15 @@ func TestFaceUVToXYZ(t *testing.T) { } // Adding up the absolute value all all the face normals should equal 2 on each axis. - if !sum.ApproxEqual(r3.Vector{2, 2, 2}) { - t.Errorf("sum of the abs of the 6 face norms should = %v, got %v", r3.Vector{2, 2, 2}, sum) + if !sum.ApproxEqual(r3.Vector{X: 2, Y: 2, Z: 2}) { + t.Errorf("sum of the abs of the 6 face norms should = %v, got %v", r3.Vector{X: 2, Y: 2, Z: 2}, sum) } } func TestFaceXYZToUV(t *testing.T) { var ( - point = Point{r3.Vector{1.1, 1.2, 1.3}} - pointNeg = Point{r3.Vector{-1.1, -1.2, -1.3}} + point = Point{r3.Vector{X: 1.1, Y: 1.2, Z: 1.3}} + pointNeg = Point{r3.Vector{X: -1.1, Y: -1.2, Z: -1.3}} ) tests := []struct { @@ -128,13 +128,13 @@ func TestFaceXYZToUV(t *testing.T) { func TestFaceXYZtoUVW(t *testing.T) { var ( - origin = Point{r3.Vector{0, 0, 0}} - posX = Point{r3.Vector{1, 0, 0}} - negX = Point{r3.Vector{-1, 0, 0}} - posY = Point{r3.Vector{0, 1, 0}} - negY = Point{r3.Vector{0, -1, 0}} - posZ = Point{r3.Vector{0, 0, 1}} - negZ = Point{r3.Vector{0, 0, -1}} + origin = Point{r3.Vector{X: 0, Y: 0, Z: 0}} + posX = Point{r3.Vector{X: 1, Y: 0, Z: 0}} + negX = Point{r3.Vector{X: -1, Y: 0, Z: 0}} + posY = Point{r3.Vector{X: 0, Y: 1, Z: 0}} + negY = Point{r3.Vector{X: 0, Y: -1, Z: 0}} + posZ = Point{r3.Vector{X: 0, Y: 0, Z: 1}} + negZ = Point{r3.Vector{X: 0, Y: 0, Z: -1}} ) for face := 0; face < 6; face++ { @@ -246,7 +246,7 @@ func TestXYZToFaceSiTi(t *testing.T) { } // Test a point near the cell center but not equal to it. - pMoved := ci.Point().Add(r3.Vector{1e-13, 1e-13, 1e-13}) + pMoved := ci.Point().Add(r3.Vector{X: 1e-13, Y: 1e-13, Z: 1e-13}) fMoved, siMoved, tiMoved, gotLevel := xyzToFaceSiTi(Point{pMoved}) if gotLevel != -1 { @@ -323,33 +323,33 @@ func TestSTUVFace(t *testing.T) { v r3.Vector want int }{ - {r3.Vector{-1, -1, -1}, 5}, - {r3.Vector{-1, -1, 0}, 4}, - {r3.Vector{-1, -1, 1}, 2}, - {r3.Vector{-1, 0, -1}, 5}, - {r3.Vector{-1, 0, 0}, 3}, - {r3.Vector{-1, 0, 1}, 2}, - {r3.Vector{-1, 1, -1}, 5}, - {r3.Vector{-1, 1, 0}, 1}, - {r3.Vector{-1, 1, 1}, 2}, - {r3.Vector{0, -1, -1}, 5}, - {r3.Vector{0, -1, 0}, 4}, - {r3.Vector{0, -1, 1}, 2}, - {r3.Vector{0, 0, -1}, 5}, - {r3.Vector{0, 0, 0}, 2}, - {r3.Vector{0, 0, 1}, 2}, - {r3.Vector{0, 1, -1}, 5}, - {r3.Vector{0, 1, 0}, 1}, - {r3.Vector{0, 1, 1}, 2}, - {r3.Vector{1, -1, -1}, 5}, - {r3.Vector{1, -1, 0}, 4}, - {r3.Vector{1, -1, 1}, 2}, - {r3.Vector{1, 0, -1}, 5}, - {r3.Vector{1, 0, 0}, 0}, - {r3.Vector{1, 0, 1}, 2}, - {r3.Vector{1, 1, -1}, 5}, - {r3.Vector{1, 1, 0}, 1}, - {r3.Vector{1, 1, 1}, 2}, + {r3.Vector{X: -1, Y: -1, Z: -1}, 5}, + {r3.Vector{X: -1, Y: -1, Z: 0}, 4}, + {r3.Vector{X: -1, Y: -1, Z: 1}, 2}, + {r3.Vector{X: -1, Y: 0, Z: -1}, 5}, + {r3.Vector{X: -1, Y: 0, Z: 0}, 3}, + {r3.Vector{X: -1, Y: 0, Z: 1}, 2}, + {r3.Vector{X: -1, Y: 1, Z: -1}, 5}, + {r3.Vector{X: -1, Y: 1, Z: 0}, 1}, + {r3.Vector{X: -1, Y: 1, Z: 1}, 2}, + {r3.Vector{X: 0, Y: -1, Z: -1}, 5}, + {r3.Vector{X: 0, Y: -1, Z: 0}, 4}, + {r3.Vector{X: 0, Y: -1, Z: 1}, 2}, + {r3.Vector{X: 0, Y: 0, Z: -1}, 5}, + {r3.Vector{X: 0, Y: 0, Z: 0}, 2}, + {r3.Vector{X: 0, Y: 0, Z: 1}, 2}, + {r3.Vector{X: 0, Y: 1, Z: -1}, 5}, + {r3.Vector{X: 0, Y: 1, Z: 0}, 1}, + {r3.Vector{X: 0, Y: 1, Z: 1}, 2}, + {r3.Vector{X: 1, Y: -1, Z: -1}, 5}, + {r3.Vector{X: 1, Y: -1, Z: 0}, 4}, + {r3.Vector{X: 1, Y: -1, Z: 1}, 2}, + {r3.Vector{X: 1, Y: 0, Z: -1}, 5}, + {r3.Vector{X: 1, Y: 0, Z: 0}, 0}, + {r3.Vector{X: 1, Y: 0, Z: 1}, 2}, + {r3.Vector{X: 1, Y: 1, Z: -1}, 5}, + {r3.Vector{X: 1, Y: 1, Z: 0}, 1}, + {r3.Vector{X: 1, Y: 1, Z: 1}, 2}, } for _, test := range tests { diff --git a/s2/textformat_test.go b/s2/textformat_test.go index df789365..74fe0677 100644 --- a/s2/textformat_test.go +++ b/s2/textformat_test.go @@ -62,7 +62,7 @@ func parsePoint(s string) Point { return p[0] } - return Point{r3.Vector{0, 0, 0}} + return Point{r3.Vector{X: 0, Y: 0, Z: 0}} } // pointToString returns a string representation suitable for reconstruction diff --git a/s2/textformat_test_test.go b/s2/textformat_test_test.go index 1a2184c9..2fb71732 100644 --- a/s2/textformat_test_test.go +++ b/s2/textformat_test_test.go @@ -110,19 +110,19 @@ func TestTextFormatParsePointRoundtrip(t *testing.T) { have string want Point }{ - {"0:0", Point{r3.Vector{1, 0, 0}}}, - {"90:0", Point{r3.Vector{6.123233995736757e-17, 0, 1}}}, - {"-45:0", Point{r3.Vector{0.7071067811865476, 0, -0.7071067811865475}}}, - {"0:0.01", Point{r3.Vector{0.9999999847691292, 0.00017453292431333684, 0}}}, - {"0:30", Point{r3.Vector{0.8660254037844387, 0.49999999999999994, 0}}}, - {"0:45", Point{r3.Vector{0.7071067811865476, 0.7071067811865475, 0}}}, - {"0:90", Point{r3.Vector{6.123233995736757e-17, 1, 0}}}, - {"30:30", Point{r3.Vector{0.7500000000000001, 0.4330127018922193, 0.49999999999999994}}}, - {"-30:30", Point{r3.Vector{0.7500000000000001, 0.4330127018922193, -0.49999999999999994}}}, - {"0:180", Point{r3.Vector{-1, 6.123233995736757e-17, 0}}}, - {"0:-180", Point{r3.Vector{-1, -6.123233995736757e-17, 0}}}, - {"90:-180", Point{r3.Vector{-6.123233995736757e-17, -0, 1}}}, - {"1e-20:1e-30", Point{r3.Vector{1, 0, 0}}}, + {"0:0", Point{r3.Vector{X: 1, Y: 0, Z: 0}}}, + {"90:0", Point{r3.Vector{X: 6.123233995736757e-17, Y: 0, Z: 1}}}, + {"-45:0", Point{r3.Vector{X: 0.7071067811865476, Y: 0, Z: -0.7071067811865475}}}, + {"0:0.01", Point{r3.Vector{X: 0.9999999847691292, Y: 0.00017453292431333684, Z: 0}}}, + {"0:30", Point{r3.Vector{X: 0.8660254037844387, Y: 0.49999999999999994, Z: 0}}}, + {"0:45", Point{r3.Vector{X: 0.7071067811865476, Y: 0.7071067811865475, Z: 0}}}, + {"0:90", Point{r3.Vector{X: 6.123233995736757e-17, Y: 1, Z: 0}}}, + {"30:30", Point{r3.Vector{X: 0.7500000000000001, Y: 0.4330127018922193, Z: 0.49999999999999994}}}, + {"-30:30", Point{r3.Vector{X: 0.7500000000000001, Y: 0.4330127018922193, Z: -0.49999999999999994}}}, + {"0:180", Point{r3.Vector{X: -1, Y: 6.123233995736757e-17, Z: 0}}}, + {"0:-180", Point{r3.Vector{X: -1, Y: -6.123233995736757e-17, Z: 0}}}, + {"90:-180", Point{r3.Vector{X: -6.123233995736757e-17, Y: -0, Z: 1}}}, + {"1e-20:1e-30", Point{r3.Vector{X: 1, Y: 0, Z: 0}}}, } for _, test := range tests { @@ -145,12 +145,12 @@ func TestTextFormatParsePointRoundtripEdgecases(t *testing.T) { // just past pole, lng should shift by 180 { have: "91:0", - wantPt: Point{r3.Vector{-0.017452406437283473, 0, 0.9998476951563913}}, + wantPt: Point{r3.Vector{X: -0.017452406437283473, Y: 0, Z: 0.9998476951563913}}, wantStr: "89:-180", }, { have: "-91:0", - wantPt: Point{r3.Vector{-0.017452406437283473, -0, -0.9998476951563913}}, + wantPt: Point{r3.Vector{X: -0.017452406437283473, Y: -0, Z: -0.9998476951563913}}, wantStr: "-89:-180", }, @@ -162,7 +162,7 @@ func TestTextFormatParsePointRoundtripEdgecases(t *testing.T) { // other side of the earth. { have: "179.99:0", - wantPt: Point{r3.Vector{-0.9999999847691292, -0, 0.00017453292431344843}}, + wantPt: Point{r3.Vector{X: -0.9999999847691292, Y: -0, Z: 0.00017453292431344843}}, wantStr: "0.0100000000000064:-180", }, /* @@ -175,7 +175,7 @@ func TestTextFormatParsePointRoundtripEdgecases(t *testing.T) { */ { have: "181.0:0", - wantPt: Point{r3.Vector{-0.9998476951563913, -0, -0.017452406437283637}}, + wantPt: Point{r3.Vector{X: -0.9998476951563913, Y: -0, Z: -0.017452406437283637}}, wantStr: "-1.00000000000001:-180", }, /* @@ -191,7 +191,7 @@ func TestTextFormatParsePointRoundtripEdgecases(t *testing.T) { // string contains more than one value, only first is used in making a point. { have: "37.4210:-122.0866, 37.4231:-122.0819", - wantPt: Point{r3.Vector{-0.4218751185559026, -0.6728760966593905, 0.6076669670863027}}, + wantPt: Point{r3.Vector{X: -0.4218751185559026, Y: -0.6728760966593905, Z: 0.6076669670863027}}, wantStr: "37.421:-122.0866", }, } @@ -215,19 +215,19 @@ func TestTextFormatParsePointsLatLngs(t *testing.T) { }{ { have: "0:0", - wantPts: []Point{{r3.Vector{1, 0, 0}}}, + wantPts: []Point{{r3.Vector{X: 1, Y: 0, Z: 0}}}, wantLLs: []LatLng{{Lat: 0, Lng: 0}}, }, { have: " 0:0, ", - wantPts: []Point{{r3.Vector{1, 0, 0}}}, + wantPts: []Point{{r3.Vector{X: 1, Y: 0, Z: 0}}}, wantLLs: []LatLng{{Lat: 0, Lng: 0}}, }, { have: "90:0,-90:0", wantPts: []Point{ - {r3.Vector{6.123233995736757e-17, 0, 1}}, - {r3.Vector{6.123233995736757e-17, 0, -1}}, + {r3.Vector{X: 6.123233995736757e-17, Y: 0, Z: 1}}, + {r3.Vector{X: 6.123233995736757e-17, Y: 0, Z: -1}}, }, wantLLs: []LatLng{ {Lat: 90 * s1.Degree, Lng: 0}, @@ -237,10 +237,10 @@ func TestTextFormatParsePointsLatLngs(t *testing.T) { { have: "90:0, 0:90, -90:0, 0:-90", wantPts: []Point{ - {r3.Vector{6.123233995736757e-17, 0, 1}}, - {r3.Vector{6.123233995736757e-17, 1, 0}}, - {r3.Vector{6.123233995736757e-17, 0, -1}}, - {r3.Vector{6.123233995736757e-17, -1, 0}}, + {r3.Vector{X: 6.123233995736757e-17, Y: 0, Z: 1}}, + {r3.Vector{X: 6.123233995736757e-17, Y: 1, Z: 0}}, + {r3.Vector{X: 6.123233995736757e-17, Y: 0, Z: -1}}, + {r3.Vector{X: 6.123233995736757e-17, Y: -1, Z: 0}}, }, wantLLs: []LatLng{ {Lat: 90 * s1.Degree, Lng: 0}, @@ -252,8 +252,8 @@ func TestTextFormatParsePointsLatLngs(t *testing.T) { { have: "37.4210:-122.0866, 37.4231:-122.0819", wantPts: []Point{ - {r3.Vector{-0.421875118555903, -0.672876096659391, 0.607666967086303}}, - {r3.Vector{-0.421808091075447, -0.672891829588934, 0.607696075333505}}, + {r3.Vector{X: -0.421875118555903, Y: -0.672876096659391, Z: 0.607666967086303}}, + {r3.Vector{X: -0.421808091075447, Y: -0.672891829588934, Z: 0.607696075333505}}, }, wantLLs: []LatLng{ {s1.Degree * 37.4210, s1.Degree * -122.0866}, @@ -272,7 +272,7 @@ func TestTextFormatParsePointsLatLngs(t *testing.T) { // Oversized values should come through as expected. have: "9000:1234.56", wantPts: []Point{ - {r3.Vector{-0.903035619536086, 0.429565675827430, 9.82193362e-16}}, + {r3.Vector{X: -0.903035619536086, Y: 0.429565675827430, Z: 9.82193362e-16}}, }, wantLLs: []LatLng{ @@ -309,50 +309,50 @@ func TestTextFormatParseRect(t *testing.T) { { "1:1", Rect{ - r1.Interval{float64(s1.Degree), float64(s1.Degree)}, - s1.Interval{float64(s1.Degree), float64(s1.Degree)}, + r1.Interval{Lo: float64(s1.Degree), Hi: float64(s1.Degree)}, + s1.Interval{Lo: float64(s1.Degree), Hi: float64(s1.Degree)}, }, }, { "1:1, 2:2, 3:3", Rect{ - r1.Interval{float64(s1.Degree), 3 * float64(s1.Degree)}, - s1.Interval{float64(s1.Degree), 3 * float64(s1.Degree)}, + r1.Interval{Lo: float64(s1.Degree), Hi: 3 * float64(s1.Degree)}, + s1.Interval{Lo: float64(s1.Degree), Hi: 3 * float64(s1.Degree)}, }, }, { "-90:-180, 90:180", Rect{ - r1.Interval{-90 * float64(s1.Degree), 90 * float64(s1.Degree)}, - s1.Interval{180 * float64(s1.Degree), -180 * float64(s1.Degree)}, + r1.Interval{Lo: -90 * float64(s1.Degree), Hi: 90 * float64(s1.Degree)}, + s1.Interval{Lo: 180 * float64(s1.Degree), Hi: -180 * float64(s1.Degree)}, }, }, { "-89.99:0, 89.99:179.99", Rect{ - r1.Interval{-89.99 * float64(s1.Degree), 89.99 * float64(s1.Degree)}, - s1.Interval{0, 179.99 * float64(s1.Degree)}, + r1.Interval{Lo: -89.99 * float64(s1.Degree), Hi: 89.99 * float64(s1.Degree)}, + s1.Interval{Lo: 0, Hi: 179.99 * float64(s1.Degree)}, }, }, { "-89.99:-179.99, 89.99:179.99", Rect{ - r1.Interval{-89.99 * float64(s1.Degree), 89.99 * float64(s1.Degree)}, - s1.Interval{179.99 * float64(s1.Degree), -179.99 * float64(s1.Degree)}, + r1.Interval{Lo: -89.99 * float64(s1.Degree), Hi: 89.99 * float64(s1.Degree)}, + s1.Interval{Lo: 179.99 * float64(s1.Degree), Hi: -179.99 * float64(s1.Degree)}, }, }, { "37.4210:-122.0866, 37.4231:-122.0819", Rect{ - r1.Interval{float64(s1.Degree * 37.4210), float64(s1.Degree * 37.4231)}, - s1.Interval{float64(s1.Degree * -122.0866), float64(s1.Degree * -122.0819)}, + r1.Interval{Lo: float64(s1.Degree * 37.4210), Hi: float64(s1.Degree * 37.4231)}, + s1.Interval{Lo: float64(s1.Degree * -122.0866), Hi: float64(s1.Degree * -122.0819)}, }, }, { "-876.54:-654.43, 963.84:2468.35", Rect{ - r1.Interval{-876.54 * float64(s1.Degree), -876.54 * float64(s1.Degree)}, - s1.Interval{-654.43 * float64(s1.Degree), -654.43 * float64(s1.Degree)}, + r1.Interval{Lo: -876.54 * float64(s1.Degree), Hi: -876.54 * float64(s1.Degree)}, + s1.Interval{Lo: -654.43 * float64(s1.Degree), Hi: -654.43 * float64(s1.Degree)}, }, }, } diff --git a/s2/wedge_relations_test.go b/s2/wedge_relations_test.go index 7d827892..46bf72f7 100644 --- a/s2/wedge_relations_test.go +++ b/s2/wedge_relations_test.go @@ -24,7 +24,7 @@ func TestWedgeRelations(t *testing.T) { // For simplicity, all of these tests use an origin of (0, 0, 1). // This shouldn't matter as long as the lower-level primitives are // implemented correctly. - ab1 := Point{r3.Vector{0, 0, 1}.Normalize()} + ab1 := Point{r3.Vector{X: 0, Y: 0, Z: 1}.Normalize()} tests := []struct { desc string @@ -35,100 +35,100 @@ func TestWedgeRelations(t *testing.T) { }{ { desc: "Intersection in one wedge", - a0: Point{r3.Vector{-1, 0, 10}}, - a1: Point{r3.Vector{1, 2, 10}}, - b0: Point{r3.Vector{0, 1, 10}}, - b1: Point{r3.Vector{1, -2, 10}}, + a0: Point{r3.Vector{X: -1, Y: 0, Z: 10}}, + a1: Point{r3.Vector{X: 1, Y: 2, Z: 10}}, + b0: Point{r3.Vector{X: 0, Y: 1, Z: 10}}, + b1: Point{r3.Vector{X: 1, Y: -2, Z: 10}}, contains: false, intersects: true, relation: WedgeProperlyOverlaps, }, { desc: "Intersection in two wedges", - a0: Point{r3.Vector{-1, -1, 10}}, - a1: Point{r3.Vector{1, -1, 10}}, - b0: Point{r3.Vector{1, 0, 10}}, - b1: Point{r3.Vector{-1, 1, 10}}, + a0: Point{r3.Vector{X: -1, Y: -1, Z: 10}}, + a1: Point{r3.Vector{X: 1, Y: -1, Z: 10}}, + b0: Point{r3.Vector{X: 1, Y: 0, Z: 10}}, + b1: Point{r3.Vector{X: -1, Y: 1, Z: 10}}, contains: false, intersects: true, relation: WedgeProperlyOverlaps, }, { desc: "Normal containment", - a0: Point{r3.Vector{-1, -1, 10}}, - a1: Point{r3.Vector{1, -1, 10}}, - b0: Point{r3.Vector{-1, 0, 10}}, - b1: Point{r3.Vector{1, 0, 10}}, + a0: Point{r3.Vector{X: -1, Y: -1, Z: 10}}, + a1: Point{r3.Vector{X: 1, Y: -1, Z: 10}}, + b0: Point{r3.Vector{X: -1, Y: 0, Z: 10}}, + b1: Point{r3.Vector{X: 1, Y: 0, Z: 10}}, contains: true, intersects: true, relation: WedgeProperlyContains, }, { desc: "Containment with equality on one side", - a0: Point{r3.Vector{2, 1, 10}}, - a1: Point{r3.Vector{-1, -1, 10}}, - b0: Point{r3.Vector{2, 1, 10}}, - b1: Point{r3.Vector{1, -5, 10}}, + a0: Point{r3.Vector{X: 2, Y: 1, Z: 10}}, + a1: Point{r3.Vector{X: -1, Y: -1, Z: 10}}, + b0: Point{r3.Vector{X: 2, Y: 1, Z: 10}}, + b1: Point{r3.Vector{X: 1, Y: -5, Z: 10}}, contains: true, intersects: true, relation: WedgeProperlyContains, }, { desc: "Containment with equality on the other side", - a0: Point{r3.Vector{2, 1, 10}}, - a1: Point{r3.Vector{-1, -1, 10}}, - b0: Point{r3.Vector{1, -2, 10}}, - b1: Point{r3.Vector{-1, -1, 10}}, + a0: Point{r3.Vector{X: 2, Y: 1, Z: 10}}, + a1: Point{r3.Vector{X: -1, Y: -1, Z: 10}}, + b0: Point{r3.Vector{X: 1, Y: -2, Z: 10}}, + b1: Point{r3.Vector{X: -1, Y: -1, Z: 10}}, contains: true, intersects: true, relation: WedgeProperlyContains, }, { desc: "Containment with equality on both sides", - a0: Point{r3.Vector{-2, 3, 10}}, - a1: Point{r3.Vector{4, -5, 10}}, - b0: Point{r3.Vector{-2, 3, 10}}, - b1: Point{r3.Vector{4, -5, 10}}, + a0: Point{r3.Vector{X: -2, Y: 3, Z: 10}}, + a1: Point{r3.Vector{X: 4, Y: -5, Z: 10}}, + b0: Point{r3.Vector{X: -2, Y: 3, Z: 10}}, + b1: Point{r3.Vector{X: 4, Y: -5, Z: 10}}, contains: true, intersects: true, relation: WedgeEquals, }, { desc: "Disjoint with equality on one side", - a0: Point{r3.Vector{-2, 3, 10}}, - a1: Point{r3.Vector{4, -5, 10}}, - b0: Point{r3.Vector{4, -5, 10}}, - b1: Point{r3.Vector{-2, -3, 10}}, + a0: Point{r3.Vector{X: -2, Y: 3, Z: 10}}, + a1: Point{r3.Vector{X: 4, Y: -5, Z: 10}}, + b0: Point{r3.Vector{X: 4, Y: -5, Z: 10}}, + b1: Point{r3.Vector{X: -2, Y: -3, Z: 10}}, contains: false, intersects: false, relation: WedgeIsDisjoint, }, { desc: "Disjoint with equality on the other side", - a0: Point{r3.Vector{-2, 3, 10}}, - a1: Point{r3.Vector{0, 5, 10}}, - b0: Point{r3.Vector{4, -5, 10}}, - b1: Point{r3.Vector{-2, 3, 10}}, + a0: Point{r3.Vector{X: -2, Y: 3, Z: 10}}, + a1: Point{r3.Vector{X: 0, Y: 5, Z: 10}}, + b0: Point{r3.Vector{X: 4, Y: -5, Z: 10}}, + b1: Point{r3.Vector{X: -2, Y: 3, Z: 10}}, contains: false, intersects: false, relation: WedgeIsDisjoint, }, { desc: "Disjoint with equality on both sides", - a0: Point{r3.Vector{-2, 3, 10}}, - a1: Point{r3.Vector{4, -5, 10}}, - b0: Point{r3.Vector{4, -5, 10}}, - b1: Point{r3.Vector{-2, 3, 10}}, + a0: Point{r3.Vector{X: -2, Y: 3, Z: 10}}, + a1: Point{r3.Vector{X: 4, Y: -5, Z: 10}}, + b0: Point{r3.Vector{X: 4, Y: -5, Z: 10}}, + b1: Point{r3.Vector{X: -2, Y: 3, Z: 10}}, contains: false, intersects: false, relation: WedgeIsDisjoint, }, { desc: "B contains A with equality on one side", - a0: Point{r3.Vector{2, 1, 10}}, - a1: Point{r3.Vector{1, -5, 10}}, - b0: Point{r3.Vector{2, 1, 10}}, - b1: Point{r3.Vector{-1, -1, 10}}, + a0: Point{r3.Vector{X: 2, Y: 1, Z: 10}}, + a1: Point{r3.Vector{X: 1, Y: -5, Z: 10}}, + b0: Point{r3.Vector{X: 2, Y: 1, Z: 10}}, + b1: Point{r3.Vector{X: -1, Y: -1, Z: 10}}, contains: false, intersects: true, relation: WedgeIsProperlyContained, @@ -136,10 +136,10 @@ func TestWedgeRelations(t *testing.T) { { desc: "B contains A with equality on the other side", - a0: Point{r3.Vector{2, 1, 10}}, - a1: Point{r3.Vector{1, -5, 10}}, - b0: Point{r3.Vector{-2, 1, 10}}, - b1: Point{r3.Vector{1, -5, 10}}, + a0: Point{r3.Vector{X: 2, Y: 1, Z: 10}}, + a1: Point{r3.Vector{X: 1, Y: -5, Z: 10}}, + b0: Point{r3.Vector{X: -2, Y: 1, Z: 10}}, + b1: Point{r3.Vector{X: 1, Y: -5, Z: 10}}, contains: false, intersects: true, relation: WedgeIsProperlyContained,