Coverage Report

Created: 2025-08-02 06:33

/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