/src/s2geometry/src/s2/s2pointutil.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS-IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | |
16 | | // Author: ericv@google.com (Eric Veach) |
17 | | |
18 | | #include "s2/s2pointutil.h" |
19 | | |
20 | | #include <cfloat> |
21 | | #include <cmath> |
22 | | |
23 | | #include "absl/log/absl_check.h" |
24 | | #include "s2/s1angle.h" |
25 | | #include "s2/s2point.h" |
26 | | #include "s2/util/math/matrix3x3.h" |
27 | | |
28 | | using std::fabs; |
29 | | |
30 | | namespace S2 { |
31 | | |
32 | 0 | bool IsUnitLength(const S2Point& p) { |
33 | | // Normalize() is guaranteed to return a vector whose L2-norm differs from 1 |
34 | | // by less than 2 * DBL_EPSILON. Thus the squared L2-norm differs by less |
35 | | // than 4 * DBL_EPSILON. The actual calculated Norm2() can have up to 1.5 * |
36 | | // DBL_EPSILON of additional error. The total error of 5.5 * DBL_EPSILON |
37 | | // can then be rounded down since the result must be a representable |
38 | | // double-precision value. |
39 | 0 | return fabs(p.Norm2() - 1) <= 5 * DBL_EPSILON; // About 1.11e-15 |
40 | 0 | } |
41 | | |
42 | 0 | bool ApproxEquals(const S2Point& a, const S2Point& b, S1Angle max_error) { |
43 | 0 | ABSL_DCHECK_NE(a, S2Point()); |
44 | 0 | ABSL_DCHECK_NE(b, S2Point()); |
45 | 0 | return S1Angle(a, b) <= max_error; |
46 | 0 | } |
47 | | |
48 | 0 | S2Point Ortho(const S2Point& a) { |
49 | | #ifdef S2_TEST_DEGENERACIES |
50 | | // Vector3::Ortho() always returns a point on the X-Y, Y-Z, or X-Z planes. |
51 | | // This leads to many more degenerate cases in polygon operations. |
52 | | return a.Ortho(); |
53 | | #else |
54 | 0 | int k = a.LargestAbsComponent() - 1; |
55 | 0 | if (k < 0) k = 2; |
56 | 0 | S2Point temp(0.012, 0.0053, 0.00457); |
57 | 0 | temp[k] = 1; |
58 | 0 | return a.CrossProd(temp).Normalize(); |
59 | 0 | #endif |
60 | 0 | } |
61 | | |
62 | 0 | S2Point Rotate(const S2Point& p, const S2Point& axis, const S1Angle angle) { |
63 | 0 | ABSL_DCHECK(IsUnitLength(p)); |
64 | 0 | ABSL_DCHECK(IsUnitLength(axis)); |
65 | | // Let M be the plane through P that is perpendicular to "axis", and let |
66 | | // "center" be the point where M intersects "axis". We construct a |
67 | | // right-handed orthogonal frame (dx, dy, center) such that "dx" is the |
68 | | // vector from "center" to P, and "dy" has the same length as "dx". The |
69 | | // result can then be expressed as (cos(angle)*dx + sin(angle)*dy + center). |
70 | 0 | S2Point center = p.DotProd(axis) * axis; |
71 | 0 | S2Point dx = p - center; |
72 | 0 | S2Point dy = axis.CrossProd(p); |
73 | | // Mathematically the result is unit length, but normalization is necessary |
74 | | // to ensure that numerical errors don't accumulate. |
75 | 0 | const S1Angle::SinCosPair a = angle.SinCos(); |
76 | 0 | return (a.cos * dx + a.sin * dy + center).Normalize(); |
77 | 0 | } |
78 | | |
79 | 0 | Matrix3x3_d GetFrame(const S2Point& z) { |
80 | 0 | Matrix3x3_d m; |
81 | 0 | GetFrame(z, &m); |
82 | 0 | return m; |
83 | 0 | } |
84 | | |
85 | 0 | void GetFrame(const S2Point& z, Matrix3x3_d* m) { |
86 | 0 | ABSL_DCHECK(IsUnitLength(z)); |
87 | 0 | m->SetCol(2, z); |
88 | 0 | m->SetCol(1, Ortho(z)); |
89 | 0 | m->SetCol(0, m->Col(1).CrossProd(z)); // Already unit-length. |
90 | 0 | } |
91 | | |
92 | 0 | S2Point ToFrame(const Matrix3x3_d& m, const S2Point& p) { |
93 | | // The inverse of an orthonormal matrix is its transpose. |
94 | 0 | return m.Transpose() * p; |
95 | 0 | } |
96 | | |
97 | 0 | S2Point FromFrame(const Matrix3x3_d& m, const S2Point& q) { |
98 | 0 | return m * q; |
99 | 0 | } |
100 | | |
101 | | } // namespace S2 |