Loading [MathJax]/extensions/tex2jax.js
LSST Applications g04a91732dc+cc8870d3f5,g07dc498a13+5aa0b8792f,g0fba68d861+488cddfaa9,g1409bbee79+5aa0b8792f,g1a7e361dbc+5aa0b8792f,g1fd858c14a+f64bc332a9,g35bb328faa+fcb1d3bbc8,g4d2262a081+b1c1982739,g4d39ba7253+9633a327c1,g4e0f332c67+5d362be553,g53246c7159+fcb1d3bbc8,g60b5630c4e+9633a327c1,g668ecb457e+25d63fd678,g78460c75b0+2f9a1b4bcd,g786e29fd12+cf7ec2a62a,g7b71ed6315+fcb1d3bbc8,g8852436030+8b64ca622a,g89139ef638+5aa0b8792f,g89e1512fd8+37f975783e,g8d6b6b353c+9633a327c1,g9125e01d80+fcb1d3bbc8,g989de1cb63+5aa0b8792f,g9f33ca652e+b196626af7,ga9baa6287d+9633a327c1,gaaedd4e678+5aa0b8792f,gabe3b4be73+1e0a283bba,gb1101e3267+71e32094df,gb58c049af0+f03b321e39,gb90eeb9370+2807b1ad02,gc741bbaa4f+1ae86710ed,gcf25f946ba+8b64ca622a,gd315a588df+a39986a76f,gd6cbbdb0b4+c8606af20c,gd9a9a58781+fcb1d3bbc8,gde0f65d7ad+94dfc458f4,ge278dab8ac+932305ba37,ge82c20c137+76d20ab76d,gfe73954cf8+a1301e4c20,w.2025.11
LSST Data Management Base Package
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Box.cc
Go to the documentation of this file.
1/*
2 * This file is part of sphgeom.
3 *
4 * Developed for the LSST Data Management System.
5 * This product includes software developed by the LSST Project
6 * (http://www.lsst.org).
7 * See the COPYRIGHT file at the top-level directory of this distribution
8 * for details of code ownership.
9 *
10 * This software is dual licensed under the GNU General Public License and also
11 * under a 3-clause BSD license. Recipients may choose which of these licenses
12 * to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
13 * respectively. If you choose the GPL option then the following text applies
14 * (but note that there is still no warranty even if you opt for BSD instead):
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 */
29
32
33#include "lsst/sphgeom/Box.h"
34
35#include <cmath>
36#include <ostream>
37#include <stdexcept>
38
39#include "lsst/sphgeom/Box3d.h"
40#include "lsst/sphgeom/Circle.h"
43#include "lsst/sphgeom/codec.h"
44#include "lsst/sphgeom/utils.h"
45
46
47namespace lsst {
48namespace sphgeom {
49
51 if (r <= Angle(0.0)) {
52 return NormalizedAngle(0.0);
53 }
54 // If a circle centered at the given latitude contains a pole, then
55 // its bounding box contains all possible longitudes.
56 if (abs(lat) + r >= Angle(0.5 * PI)) {
57 return NormalizedAngle(PI);
58 }
59 // Now, consider the circle with opening angle r > 0 centered at (0,δ)
60 // with r < π/2 and |δ| ≠ π/2. The circle center vector in ℝ³ is
61 // c = (cos δ, 0, sin δ). Its bounding box spans longitudes [-α,α], where
62 // α is the desired half-width. The plane corresponding to longitude α has
63 // normal vector (-sin α, cos α, 0) and is tangent to the circle at point
64 // p. The great circle segment between the center of the circle and the
65 // plane normal passes through p and has arc length π/2 + r, so that
66 //
67 // (cos δ, 0, sin δ) · (-sin α, cos α, 0) = cos (π/2 + r)
68 //
69 // Solving for α gives
70 //
71 // α = arcsin (sin r / cos δ)
72 //
73 // In the actual computation, there is an absolute value and an explicit
74 // arcsin domain check to cope with rounding errors. An alternate way to
75 // compute this is:
76 //
77 // α = arctan (sin r / √(cos(δ - r) cos(δ + r)))
78 double s = std::fabs(sin(r) / cos(lat));
79 if (s >= 1.0) {
80 return NormalizedAngle(0.5 * PI);
81 }
82 return NormalizedAngle(std::asin(s));
83}
84
86 // The basic idea is to compute the union of the bounding boxes for all
87 // circles of opening angle r with centers inside this box.
88 //
89 // The bounding box for a circle of opening angle r with center latitude
90 // |δ| ≤ π/2 - r has height 2r.
91 //
92 // Given fixed r, the width of the bounding box for the circle centered at
93 // latitude δ grows monotonically with |δ| - for justification, see the
94 // derivation in halfWidthForCircle(). The maximum width is therefore
95 // attained when the circle is centered at one of the latitude angle
96 // boundaries of this box. If max(|δ|) ≥ π/2 - r, it is 2π.
97 //
98 // Dilating the longitude interval of this box by the maximum width and
99 // the latitude interval by r gives the desired result.
100 if (isEmpty() || isFull() || r <= Angle(0.0)) {
101 return *this;
102 }
103 Angle maxAbsLatitude = std::max(abs(_lat.getA()), abs(_lat.getB()));
104 NormalizedAngle w = halfWidthForCircle(r, maxAbsLatitude);
105 return dilateBy(w, r);
106}
107
109 if (isEmpty() || isFull()) {
110 return *this;
111 }
112 _lon.dilateBy(w);
113 if (!h.isNan()) {
114 Angle a = (_lat.getA() > Angle(-0.5 * PI)) ? _lat.getA() - h : _lat.getA();
115 Angle b = (_lat.getB() < Angle(0.5 * PI)) ? _lat.getB() + h : _lat.getB();
116 _lat = AngleInterval(a, b);
117 }
118 _enforceInvariants();
119 return *this;
120}
121
122double Box::getArea() const {
123 if (isEmpty()) {
124 return 0.0;
125 }
126 // Given a, b ∈ [-π/2, π/2] and a std::sin implementation that is not
127 // correctly rounded, b > a does not imply that std::sin(b) > std::sin(a).
128 // To avoid potentially returning a negative area, defensively take an
129 // absolute value.
130 double dz = sin(_lat.getB()) - sin(_lat.getA());
131 return std::fabs(_lon.getSize().asRadians() * dz);
132}
133
135 if (isEmpty()) {
136 return Box3d();
137 }
138 if (isFull()) {
140 }
141 double slata = sin(_lat.getA()), clata = cos(_lat.getA());
142 double slatb = sin(_lat.getB()), clatb = cos(_lat.getB());
143 double slona = sin(_lon.getA()), clona = cos(_lon.getA());
144 double slonb = sin(_lon.getB()), clonb = cos(_lon.getB());
145 // Compute the minimum/maximum x/y values of the box vertices.
146 double xmin = std::min(std::min(clona * clata, clonb * clata),
147 std::min(clona * clatb, clonb * clatb)) - 2.5 * EPSILON;
148 double xmax = std::max(std::max(clona * clata, clonb * clata),
149 std::max(clona * clatb, clonb * clatb)) + 2.5 * EPSILON;
150 double ymin = std::min(std::min(slona * clata, slonb * clata),
151 std::min(slona * clatb, slonb * clatb)) - 2.5 * EPSILON;
152 double ymax = std::max(std::max(slona * clata, slonb * clata),
153 std::max(slona * clatb, slonb * clatb)) + 2.5 * EPSILON;
154 // Compute the maximum latitude cosine of points in the box.
155 double mlc;
156 if (_lat.contains(Angle(0.0))) {
157 mlc = 1.0;
158 // The box intersects the equator - the x or y extrema of the box may be
159 // at the intersection of the box edge meridians with the equator.
160 xmin = std::min(xmin, std::min(clona, clonb) - EPSILON);
161 xmax = std::max(xmax, std::max(clona, clonb) + EPSILON);
162 ymin = std::min(ymin, std::min(slona, slonb) - EPSILON);
163 ymax = std::max(ymax, std::max(slona, slonb) + EPSILON);
164 } else {
165 // Note that clata and clatb are positive.
166 mlc = std::max(clata, clatb) + EPSILON;
167 }
168 // Check for extrema on the box edges parallel to the equator.
169 if (_lon.contains(NormalizedAngle(0.0))) {
170 xmax = std::max(xmax, mlc);
171 }
172 if (_lon.contains(NormalizedAngle(0.5 * PI))) {
173 ymax = std::max(ymax, mlc);
174 }
175 if (_lon.contains(NormalizedAngle(PI))) {
176 xmin = std::min(xmin, -mlc);
177 }
178 if (_lon.contains(NormalizedAngle(1.5 * PI))) {
179 ymin = std::min(ymin, -mlc);
180 }
181 // Clamp x/y extrema to [-1, 1]
182 xmin = std::max(-1.0, xmin);
183 xmax = std::min(1.0, xmax);
184 ymin = std::max(-1.0, ymin);
185 ymax = std::min(1.0, ymax);
186 // Compute z extrema.
187 double zmin = std::max(-1.0, slata - EPSILON);
188 double zmax = std::min(1.0, slatb + EPSILON);
189 return Box3d(Interval1d(xmin, xmax),
190 Interval1d(ymin, ymax),
191 Interval1d(zmin, zmax));
192}
193
195 if (isEmpty()) {
196 return Circle::empty();
197 }
198 if (isFull()) {
199 return Circle::full();
200 }
202 // The minimal bounding circle center p lies on the meridian bisecting
203 // this box. Let δ₁ and δ₂ be the minimum and maximum box latitudes.
204 if (w.asRadians() <= PI) {
205 UnitVector3d p;
206 UnitVector3d boxVerts[4] = {
207 UnitVector3d(_lon.getA(), _lat.getA()),
208 UnitVector3d(_lon.getA(), _lat.getB()),
209 UnitVector3d(_lon.getB(), _lat.getA()),
210 UnitVector3d(_lon.getB(), _lat.getB())
211 };
212 // We take advantage of rotational symmetry to fix the bisecting
213 // meridian at a longitude of zero. The box vertices then have
214 // coordinates (±w/2, δ₁), (±w/2, δ₂), and p = (0, ϕ). Converting
215 // to Cartesian coordinates gives p = (cos ϕ, 0, sin ϕ), and box
216 // vertices at (cos w/2 cos δ₁, ±sin w/2 cos δ₁, sin δ₁) and
217 // (cos w/2 cos δ₂, ±sin w/2 cos δ₂, sin δ₂).
218 //
219 // The point p₁ on the meridian that has minimum angular separation
220 // to the vertices with latitude δ₁ lies on the plane they define.
221 // The sum of the two vertex vectors is on that plane and on the plane
222 // containing the meridian. Normalizing to obtain p₁, we have
223 //
224 // (cos ϕ₁, 0, sin ϕ₁) =
225 // λ ((cos w/2 cos δ₁, sin w/2 cos δ₁, sin δ₁) +
226 // (cos w/2 cos δ₁, -sin w/2 cos δ₁, sin δ₁))
227 //
228 // for some scaling factor λ. Simplifying, we get:
229 //
230 // cos ϕ₁ = λ cos w/2 cos δ₁
231 // sin ϕ₁ = λ sin δ₁
232 //
233 // so that
234 //
235 // tan ϕ₁ = sec w/2 tan δ₁
236 //
237 // Similarly, the point p₂ on the meridian that has minimum angular
238 // separation to the vertices with latitude δ₂ satisfies:
239 //
240 // tan ϕ₂ = sec w/2 tan δ₂
241 //
242 // where ϕ₁ ≤ ϕ₂ (since δ₁ ≤ δ₂). Finally, consider the point p₃
243 // separated from each box vertex by the same angle. The dot
244 // products of p₃ with the box vertices are all identical, so
245 //
246 // cos ϕ₃ cos w/2 cos δ₁ + sin ϕ₃ sin δ₁ =
247 // cos ϕ₃ cos w/2 cos δ₂ + sin ϕ₃ sin δ₂
248 //
249 // Rearranging gives:
250 //
251 // tan ϕ₃ = - cos w/2 (cos δ₁ - cos δ₂)/(sin δ₁ - sin δ₂)
252 //
253 // which can be simplified further using a tangent half-angle identity,
254 // yielding:
255 //
256 // tan ϕ₃ = cos w/2 tan (δ₁ + δ₂)/2
257 //
258 // Consider now the function f₁(ϕ) that gives the angular separation
259 // between p with latitude ϕ and the vertices at latitude δ₁. It has
260 // a line of symmetry at ϕ = ϕ₁, and increases monotonically with
261 // |ϕ - ϕ₁|. Similarly, f₂(ϕ) has a minimum at ϕ₂ and increases
262 // monotonically with |ϕ - ϕ₂|. The two functions cross at ϕ₃. The
263 // opening angle of the bounding circle centered at latitude ϕ is
264 // given by g = max(f₁, f₂), which we seek to minimize.
265 //
266 // If ϕ₁ ≤ ϕ₃ ≤ ϕ₂, then g is minimized at ϕ = ϕ₃. Otherwise, it
267 // is minimized at either ϕ₁ or ϕ₂.
268 double phi1, phi2, phi3;
269 double c = cos(0.5 * w);
270 if (c == 0.0) {
271 // This code should never execute. If it does, the implementation
272 // of std::cos is broken.
273 phi1 = ::copysign(0.5 * PI, _lat.getA().asRadians());
274 phi2 = ::copysign(0.5 * PI, _lat.getB().asRadians());
275 phi3 = 0.0;
276 } else {
277 phi1 = std::atan(tan(_lat.getA()) / c);
278 phi2 = std::atan(tan(_lat.getB()) / c);
279 phi3 = std::atan(c * tan(_lat.getCenter()));
280 }
281 if (phi1 <= phi3 && phi3 <= phi2) {
282 p = UnitVector3d(_lon.getCenter(), Angle(phi3));
283 } else {
284 UnitVector3d p1 = UnitVector3d(_lon.getCenter(), Angle(phi1));
285 UnitVector3d p2 = UnitVector3d(_lon.getCenter(), Angle(phi2));
286 if (p1.dot(boxVerts[0]) > p2.dot(boxVerts[1])) {
287 p = p2;
288 } else {
289 p = p1;
290 }
291 }
292 // Compute the maximum squared chord length between p and the box
293 // vertices, so that each one is guaranteed to lie in the bounding
294 // circle, regardless of numerical error in the above.
295 double cl2 = (p - boxVerts[0]).getSquaredNorm();
296 for (int i = 1; i < 4; ++i) {
297 cl2 = std::max(cl2, (p - boxVerts[i]).getSquaredNorm());
298 }
299 // Add double the maximum squared-chord-length error, so that the
300 // bounding circle we return also reliably CONTAINS this box.
301 return Circle(p, cl2 + 2.0 * MAX_SQUARED_CHORD_LENGTH_ERROR);
302 }
303 // The box spans more than π radians in longitude. First, pick the smaller
304 // of the bounding circles centered at the north and south pole.
305 Angle r;
306 UnitVector3d v;
307 if (abs(_lat.getA()) <= abs(_lat.getB())) {
308 v = UnitVector3d::Z();
309 r = Angle(0.5 * PI) - _lat.getA();
310 } else {
311 v = -UnitVector3d::Z();
312 r = _lat.getB() + Angle(0.5 * PI);
313 }
314 // If the box does not span all longitude angles, we also consider the
315 // equatorial bounding circle with center longitude equal to the longitude
316 // of the box center. The smaller of the polar and equatorial bounding
317 // circles is returned.
318 if (!_lon.isFull() && 0.5 * w < r) {
319 r = 0.5 * w;
320 v = UnitVector3d(_lon.getCenter(), Angle(0.0));
321 }
322 return Circle(v, r + 4.0 * Angle(MAX_ASIN_ERROR));
323}
324
326 if (isEmpty()) {
327 if (c.isEmpty()) {
328 return CONTAINS | DISJOINT | WITHIN;
329 }
330 return DISJOINT | WITHIN;
331 } else if (c.isEmpty()) {
332 return CONTAINS | DISJOINT;
333 }
334 if (isFull()) {
335 if (c.isFull()) {
336 return CONTAINS | WITHIN;
337 }
338 return CONTAINS;
339 } else if (c.isFull()) {
340 return WITHIN;
341 }
342 // Neither region is empty or full. We now determine whether or not the
343 // circle and box boundaries intersect.
344 //
345 // If the box vertices are not all inside or all outside of c, then the
346 // boundaries cross.
347 LonLat vertLonLat[4] = {
348 LonLat(_lon.getA(), _lat.getA()),
349 LonLat(_lon.getA(), _lat.getB()),
350 LonLat(_lon.getB(), _lat.getA()),
351 LonLat(_lon.getB(), _lat.getB())
352 };
353 UnitVector3d verts[4];
354 bool inside = false;
355 for (int i = 0; i < 4; ++i) {
356 verts[i] = UnitVector3d(vertLonLat[i]);
357 double d = (verts[i] - c.getCenter()).getSquaredNorm();
358 if (std::fabs(d - c.getSquaredChordLength()) <
360 // A box vertex is close to the circle boundary.
361 return INTERSECTS;
362 }
363 bool b = d < c.getSquaredChordLength();
364 if (i == 0) {
365 inside = b;
366 } else if (inside != b) {
367 // There are box vertices both inside and outside of c.
368 return INTERSECTS;
369 }
370 }
371 UnitVector3d norms[2] = {
372 UnitVector3d::orthogonalTo(_lon.getA()),
373 UnitVector3d::orthogonalTo(_lon.getB())
374 };
375 if (inside) {
376 // All box vertices are inside c. Look for points in the box edge
377 // interiors that are outside c.
378 for (int i = 0; i < 2; ++i) {
379 double d = getMaxSquaredChordLength(
380 c.getCenter(), verts[2 * i + 1], verts[2 * i], norms[i]);
381 if (d > c.getSquaredChordLength() -
383 return INTERSECTS;
384 }
385 }
386 LonLat cc(-c.getCenter());
387 if (_lon.contains(cc.getLon())) {
388 // The points furthest from the center of c on the small circles
389 // defined by the box edges with constant latitude are in the box
390 // edge interiors. Find the largest squared chord length to either.
391 Angle a = std::min(getMinAngleToCircle(cc.getLat(), _lat.getA()),
392 getMinAngleToCircle(cc.getLat(), _lat.getB()));
393 double d = Circle::squaredChordLengthFor(Angle(PI) - a);
394 if (d > c.getSquaredChordLength() -
396 return INTERSECTS;
397 }
398 }
399 // The box boundary is completely inside c. However, the box is not
400 // necessarily within c: consider a circle with opening angle equal to
401 // π - ε. If a box contains the complement of such a circle, then
402 // intersecting it with that circle will punch a hole in the box. In
403 // this case each region contains the boundary of the other, but
404 // neither region contains the other.
405 //
406 // To handle this case, check that the box does not contain the
407 // complement of c - since the boundaries do not intersect, this is the
408 // case iff the box contains the center of the complement of c.
409 if (contains(cc)) {
410 return INTERSECTS;
411 }
412 return WITHIN;
413 }
414 // All box vertices are outside c. Look for points in the box edge
415 // interiors that are inside c.
416 for (int i = 0; i < 2; ++i) {
417 double d = getMinSquaredChordLength(
418 c.getCenter(), verts[2 * i + 1], verts[2 * i], norms[i]);
420 return INTERSECTS;
421 }
422 }
423 LonLat cc(c.getCenter());
424 if (_lon.contains(cc.getLon())) {
425 // The points closest to the center of c on the small circles
426 // defined by the box edges with constant latitude are in the box
427 // edge interiors. Find the smallest squared chord length to either.
428 Angle a = std::min(getMinAngleToCircle(cc.getLat(), _lat.getA()),
429 getMinAngleToCircle(cc.getLat(), _lat.getB()));
430 double d = Circle::squaredChordLengthFor(a);
432 return INTERSECTS;
433 }
434 }
435 // The box boundary is completely outside of c. If the box contains the
436 // circle center, then the box contains c. Otherwise, the box and circle
437 // are disjoint.
438 if (contains(cc)) {
439 return CONTAINS;
440 }
441 return DISJOINT;
442}
443
445 // ConvexPolygon-Box relations are implemented by ConvexPolygon.
446 return invert(p.relate(*this));
447}
448
450 // Ellipse-Box relations are implemented by Ellipse.
451 return invert(e.relate(*this));
452}
453
454TriState Box::overlaps(Box const &b) const {
455 // `intersects` returns exact value.
456 return TriState(intersects(b));
457}
458
460 // `relate` with Circle returns exact value.
461 return TriState(not (relate(c) & DISJOINT).any());
462}
463
465 // ConvexPolygon-Box relations are implemented by ConvexPolygon.
466 return p.overlaps(*this);
467}
468
470 // Ellipse-Box relations are implemented by Ellipse.
471 return e.overlaps(*this);
472}
473
477 buffer.reserve(ENCODED_SIZE);
478 buffer.push_back(tc);
479 encodeDouble(_lon.getA().asRadians(), buffer);
480 encodeDouble(_lon.getB().asRadians(), buffer);
481 encodeDouble(_lat.getA().asRadians(), buffer);
482 encodeDouble(_lat.getB().asRadians(), buffer);
483 return buffer;
484}
485
487 if (buffer == nullptr || n != ENCODED_SIZE || *buffer != TYPE_CODE) {
488 throw std::runtime_error("Byte-string is not an encoded Box");
489 }
490 std::unique_ptr<Box> box(new Box);
491 ++buffer;
492 double a = decodeDouble(buffer); buffer += 8;
493 double b = decodeDouble(buffer); buffer += 8;
494 box->_lon = NormalizedAngleInterval::fromRadians(a, b);
495 a = decodeDouble(buffer); buffer += 8;
496 b = decodeDouble(buffer); buffer += 8;
497 box->_lat = AngleInterval::fromRadians(a, b);
498 box->_enforceInvariants();
499 return box;
500}
501
503 return os << "{\"Box\": [" << b.getLon() << ", " << b.getLat() << "]}";
504}
505
506}} // namespace lsst::sphgeom
This file declares a class for representing axis-aligned bounding boxes in ℝ³.
This file declares a class for representing circular regions on the unit sphere.
This file declares a class for representing convex polygons with great circle edges on the unit spher...
T asin(T... args)
T atan(T... args)
Angle represents an angle in radians.
Definition Angle.h:50
bool isNan() const
isNan returns true if the angle value is NaN.
Definition Angle.h:98
AngleInterval represents closed intervals of arbitrary angles.
static AngleInterval fromRadians(double x, double y)
Box3d represents a box in ℝ³.
Definition Box3d.h:49
static Box3d aroundUnitSphere()
aroundUnitSphere returns a minimal Box3d containing the unit sphere.
Definition Box3d.h:63
Box represents a rectangle in spherical coordinate space that contains its boundary.
Definition Box.h:62
static NormalizedAngle halfWidthForCircle(Angle r, Angle lat)
halfWidthForCircle computes the half-width of bounding boxes for circles with radius r and centers at...
Definition Box.cc:50
Box()
This constructor creates an empty box.
Definition Box.h:100
NormalizedAngle getWidth() const
getWidth returns the width in longitude angle of this box.
Definition Box.h:173
double getArea() const
getArea returns the area of this box in steradians.
Definition Box.cc:122
Box3d getBoundingBox3d() const override
getBoundingBox3d returns a 3-dimensional bounding-box for this region.
Definition Box.cc:134
Relationship relate(LonLat const &p) const
Definition Box.h:305
static std::unique_ptr< Box > decode(std::vector< std::uint8_t > const &s)
Definition Box.h:356
static constexpr std::uint8_t TYPE_CODE
Definition Box.h:64
bool isFull() const
isFull returns true if this box contains all points on the unit sphere.
Definition Box.h:163
std::vector< std::uint8_t > encode() const override
encode serializes this region into an opaque byte string.
Definition Box.cc:474
bool isEmpty() const override
isEmpty returns true if this box does not contain any points.
Definition Box.h:159
Box & dilateBy(Angle r)
dilateBy minimally expands this Box to include all points within angular separation r of its boundary...
Definition Box.cc:85
TriState overlaps(Region const &other) const override
Definition Box.h:344
bool contains(LonLat const &x) const
Definition Box.h:182
bool intersects(LonLat const &x) const
Definition Box.h:202
Circle getBoundingCircle() const override
getBoundingCircle returns a bounding-circle for this region.
Definition Box.cc:194
Circle is a circular region on the unit sphere that contains its boundary.
Definition Circle.h:54
static Circle empty()
Definition Circle.h:58
static Circle full()
Definition Circle.h:60
bool isFull() const
Definition Circle.h:122
double getSquaredChordLength() const
getSquaredChordLength returns the squared length of chords between the circle center and points on th...
Definition Circle.h:131
UnitVector3d const & getCenter() const
getCenter returns the center of this circle as a unit vector.
Definition Circle.h:126
static double squaredChordLengthFor(Angle openingAngle)
squaredChordLengthFor computes and returns the squared chord length between points in S² that are sep...
Definition Circle.cc:48
bool isEmpty() const override
isEmpty returns true when a region does not contain any points.
Definition Circle.h:117
ConvexPolygon is a closed convex polygon on the unit sphere.
TriState overlaps(Region const &other) const override
Relationship relate(Region const &r) const override
Ellipse is an elliptical region on the sphere.
Definition Ellipse.h:177
Relationship relate(Region const &r) const override
Definition Ellipse.h:296
TriState overlaps(Region const &other) const override
Definition Ellipse.h:306
Interval1d represents closed intervals of ℝ.
Definition Interval1d.h:47
LonLat represents a spherical coordinate (longitude/latitude angle) pair.
Definition LonLat.h:55
Angle getLat() const
Definition LonLat.h:97
NormalizedAngle getLon() const
Definition LonLat.h:95
NormalizedAngle is an angle that lies in the range [0, 2π), with one exception - a NormalizedAngle ca...
double asRadians() const
asRadians returns the value of this angle in units of radians.
static NormalizedAngleInterval fromRadians(double a, double b)
TriState represents a boolean value with additional unknown state.
Definition TriState.h:46
UnitVector3d is a unit vector in ℝ³ with components stored in double precision.
static UnitVector3d Z()
double dot(Vector3d const &v) const
dot returns the inner product of this unit vector and v.
static UnitVector3d orthogonalTo(Vector3d const &v)
orthogonalTo returns an arbitrary unit vector that is orthogonal to v.
This file contains simple helper functions for encoding and decoding primitive types to/from byte str...
T fabs(T... args)
T max(T... args)
T min(T... args)
double decodeDouble(std::uint8_t const *buffer)
decodeDouble extracts an IEEE double from the 8 byte little-endian byte sequence in buffer.
Definition codec.h:77
void encodeDouble(double item, std::vector< std::uint8_t > &buffer)
encodeDouble appends an IEEE double in little-endian byte order to the end of buffer.
Definition codec.h:57
Angle getMinAngleToCircle(Angle x, Angle c)
getMinAngleToCircle returns the minimum angular separation between a point at latitude x and the poin...
Definition utils.h:69
constexpr double MAX_ASIN_ERROR
Definition constants.h:52
Angle abs(Angle const &a)
Definition Angle.h:113
std::ostream & operator<<(std::ostream &, Angle const &)
Definition Angle.cc:41
double getMaxSquaredChordLength(Vector3d const &v, Vector3d const &a, Vector3d const &b, Vector3d const &n)
Let p be the unit vector furthest from v that lies on the plane with normal n in the direction of the...
Definition utils.cc:65
double getMinSquaredChordLength(Vector3d const &v, Vector3d const &a, Vector3d const &b, Vector3d const &n)
Let p be the unit vector closest to v that lies on the plane with normal n in the direction of the cr...
Definition utils.cc:43
double sin(Angle const &a)
Definition Angle.h:109
constexpr double MAX_SQUARED_CHORD_LENGTH_ERROR
Definition constants.h:57
double tan(Angle const &a)
Definition Angle.h:111
constexpr double EPSILON
Definition constants.h:61
double cos(Angle const &a)
Definition Angle.h:110
constexpr double PI
Definition constants.h:43
Relationship invert(Relationship r)
Given the relationship between two sets A and B (i.e.
std::bitset< 3 > Relationship
Relationship describes how two sets are related.
T push_back(T... args)
T reserve(T... args)
This file declares a class for representing longitude/latitude angle boxes on the unit sphere.
This file declares a class for representing elliptical regions on the unit sphere.
This file declares miscellaneous utility functions.