The SKIRT project
advanced radiative transfer for astrophysics
Quadrics Class Referencefinal

#include <Quadrics.hpp>

Static Public Member Functions

static double cube (double x)
static double cube (double x0, double x1)
static int distinctIntersectionsCone (Vec r0, Vec k, double cosTheta, double &x1, double &x2)
static int distinctIntersectionsCylinder (Vec r0, Vec k, double kq2, double radius, double &x1, double &x2)
static int distinctIntersectionsSphere (Vec r0, Vec k, double radius, double &x1, double &x2)
static int distinctSolutions (double a, double b, double c, double &x1, double &x2)
static int distinctSolutions (double b, double c, double &x1, double &x2)
static bool doSpheresOverlap (Vec center1, double radius1, Vec center2, double radius2)
static double firstIntersectionCone (Vec r0, Vec k, double cosTheta)
static double firstIntersectionCylinder (Vec r0, Vec k, double kq2, double radius)
static double firstIntersectionSphere (Vec r0, Vec k, double radius)
static double firstIntersectionSphere (Vec r0, Vec k, Vec center, double radius)
static double intersectionHorizontalPlane (Vec r0, Vec k, double zPlane)
static double intersectionMeridionalPlane (Vec r0, Vec k, double sinPhi, double cosPhi)
static bool isPositionInSphere (Vec p, Vec center, double radius)
static bool isSphereInShell (Vec center, double radius, double rmin, double rmax)
static bool isSphericalCellInSphere (double rmin, double rmax, double thetaMin, double thetaMax, double phiMin, double phiMax, Vec center, double radius)
static double smallestPositiveSolution (double a, double b, double c)
static double smallestPositiveSolution (double b, double c)
static bool sphereIntersectsPlane (double sphereRadius, double outOfPlaneCenterCoord, double &circleRadius)
static double sqrtDiffSquares (double a, double b)
static double square (double x)
static double volumeSphere (double radius)

Static Private Member Functions

static double minCosineOverInterval (double amp, double phase, double tlo, double thi)

Static Private Attributes

static constexpr double EPS

Detailed Description

This static class offers a collection of low-level geometric building blocks: raising a value to the second or third power, solving a quadratic equation, and a set of elementary sphere/plane tests and ray/quadric intersections centered on or relative to the origin.

All implementations are provided inline in the header.

Member Function Documentation

◆ cube() [1/2]

double Quadrics::cube ( double x)
inlinestatic

This function returns \(x^3\).

◆ cube() [2/2]

double Quadrics::cube ( double x0,
double x1 )
inlinestatic

This function returns \(x_1^3 - x_0^3 = (x_1-x_0)(x_1^2 + x_1 x_0 + x_0^2)\). The second form is used because it is more numerically stable.

◆ distinctIntersectionsCone()

int Quadrics::distinctIntersectionsCone ( Vec r0,
Vec k,
double cosTheta,
double & x1,
double & x2 )
inlinestatic

This function determines the solutions of the intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the double cone described in firstIntersectionCone(), i.e. the two-root counterpart of that function: it solves the same defining equation and quadratic, but through distinctSolutions() rather than smallestPositiveSolution(), so that both roots (or the single root of a linearly-degenerate case) are returned rather than only the smallest positive one. The degenerate cone with zero cosine (i.e. the xy-plane) is handled as a special case, with at most one solution, obtained only if the ray is not parallel to it. The return value has the same meaning as for distinctSolutions(): 2 for two distinct solutions (stored in x1 and x2), 1 for a single solution (stored in x1), or 0 for none.

◆ distinctIntersectionsCylinder()

int Quadrics::distinctIntersectionsCylinder ( Vec r0,
Vec k,
double kq2,
double radius,
double & x1,
double & x2 )
inlinestatic

This function determines the solutions of the intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the infinite cylinder described in firstIntersectionCylinder(), i.e. the two-root counterpart of that function: it solves the same defining equation and quadratic, but through distinctSolutions() rather than smallestPositiveSolution(), so that both roots are returned rather than only the smallest positive one; kq2 has the same meaning as there. The return value has the same meaning as for distinctSolutions(): 2 for two distinct solutions (stored in x1 and x2), or 0 if there are none, which includes the case where the ray is parallel to the z-axis (kq2 is zero).

◆ distinctIntersectionsSphere()

int Quadrics::distinctIntersectionsSphere ( Vec r0,
Vec k,
double radius,
double & x1,
double & x2 )
inlinestatic

This function determines the solutions of the intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the sphere described in firstIntersectionSphere(), i.e. the two-root counterpart of that function: it solves the same defining equation and quadratic, but through distinctSolutions() rather than smallestPositiveSolution(), so that both roots are returned rather than only the smallest positive one. The return value has the same meaning as for distinctSolutions(): 2 for two distinct solutions (stored in x1 and x2), or 0 if there are none.

◆ distinctSolutions() [1/2]

int Quadrics::distinctSolutions ( double a,
double b,
double c,
double & x1,
double & x2 )
inlinestatic

This function determines the solutions of \(ax^2 + 2bx + c = 0\). If there are two distinct real solutions, they are stored in the arguments x1 and x2, and the function returns 2. If the equation degenerates to a linear equation with a single finite solution, this solution is stored in the argument x1. In that case, x2 remains unchanged and the function returns 1. Otherwise, i.e. if there are no real solutions or the non-generate quadratic equation has two identical solutions, x1 and x2 remain unchanged, and the function returns 0.

◆ distinctSolutions() [2/2]

int Quadrics::distinctSolutions ( double b,
double c,
double & x1,
double & x2 )
inlinestatic

This function determines the solutions of \(x^2 + 2bx + c = 0\). If there are two distinct real solutions, they are stored in the arguments x1 and x2, and the function returns 2. Otherwise, i.e. if there are no real solutions or there is just one real solution, x1 and x2 remain unchanged, and the function returns 0.

Evaluating \(-b \pm \sqrt{b^2-c}\) directly for both roots would lose precision through catastrophic cancellation whenever the two terms nearly cancel for one of the roots. To avoid this, only the root for which \(-b\) and the square root have the same sign – so that they add rather than cancel – is evaluated directly: \(-b-\sqrt{b^2-c}\) if \(b>0\) (since \(-b\) is then negative), or \(-b+\sqrt{b^2-c}\) otherwise. The other root is then obtained from Vieta's formula \(x_1 x_2 = c\).

◆ doSpheresOverlap()

bool Quadrics::doSpheresOverlap ( Vec center1,
double radius1,
Vec center2,
double radius2 )
inlinestatic

This function returns true if the specified spheres overlap or touch, and false otherwise.

◆ firstIntersectionCone()

double Quadrics::firstIntersectionCone ( Vec r0,
Vec k,
double cosTheta )
inlinestatic

This function returns the distance to the first intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the double cone, centered on the origin and aligned with the z-axis, that has the given cosine of its opening angle, or zero if there is no intersection ahead along the ray. The degenerate cone with zero cosine (i.e. the xy-plane) is handled as a special case.

Substituting \({\bf{p}}(s) = {\bf{r}}_0 + s\hat{\bf{k}}\) into the cone's defining equation \(\cos^2\theta\,|{\bf{p}}|^2 = p_z^2\) gives the quadratic

\[ (\cos^2\theta - k_z^2)\,s^2 + 2s\,(\cos^2\theta\,({\bf{r}}_0\cdot\hat{\bf{k}}) - r_{0,z}\,k_z) + (\cos^2\theta\,r_0^2 - r_{0,z}^2) = 0, \]

whose smallest positive solution, if any, is the returned distance.

◆ firstIntersectionCylinder()

double Quadrics::firstIntersectionCylinder ( Vec r0,
Vec k,
double kq2,
double radius )
inlinestatic

This function returns the distance to the first intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the infinite cylinder of given radius, centered on and aligned with the z-axis, or zero if there is no intersection ahead along the ray (either no real intersection, both intersections lie behind the ray's origin, or the ray direction is parallel to the z-axis). The squared length \(k_x^2+k_y^2\) of the projection of \(\hat{\bf{k}}\) onto the xy-plane is passed in as kq2 rather than recomputed, because the caller typically needs the first intersection with several cylinders of different radii for the same ray, all sharing the same kq2.

Substituting \({\bf{p}}(s) = {\bf{r}}_0 + s\hat{\bf{k}}\) into the cylinder's defining equation \(p_x^2+p_y^2 = \text{radius}^2\) gives the quadratic

\[ (k_x^2+k_y^2)\,s^2 + 2s\,(r_{0,x}k_x + r_{0,y}k_y) + (r_{0,x}^2 + r_{0,y}^2 - \text{radius}^2) = 0, \]

whose smallest positive solution, if any, is the returned distance; kq2 is the leading coefficient \(k_x^2+k_y^2\).

◆ firstIntersectionSphere() [1/2]

double Quadrics::firstIntersectionSphere ( Vec r0,
Vec k,
double radius )
inlinestatic

This function returns the distance to the first intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the sphere of given radius centered at the origin, or zero if there is no intersection ahead along the ray (either no real intersection, or both intersections lie behind the ray's origin).

Substituting \({\bf{p}}(s) = {\bf{r}}_0 + s\hat{\bf{k}}\) into the sphere's defining equation \(|{\bf{p}}|^2 = \text{radius}^2\) gives the quadratic

\[ s^2 + 2s\, ({\bf{r}}_0\cdot\hat{\bf{k}}) + (r_0^2 - \text{radius}^2) = 0, \]

whose smallest positive solution, if any, is the returned distance.

◆ firstIntersectionSphere() [2/2]

double Quadrics::firstIntersectionSphere ( Vec r0,
Vec k,
Vec center,
double radius )
inlinestatic

This function returns the distance to the first intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the sphere of given center and radius, or zero if there is no intersection ahead along the ray. This is the arbitrary-center counterpart of the other firstIntersectionSphere() overload, obtained by translating the ray so that the sphere's center coincides with the origin – i.e. by substituting \({\bf{r}}_0 - \text{center}\) for \({\bf{r}}_0\) in that overload's defining equation.

◆ intersectionHorizontalPlane()

double Quadrics::intersectionHorizontalPlane ( Vec r0,
Vec k,
double zPlane )
inlinestatic

This function returns the distance to the intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the horizontal plane, perpendicular to the z-axis, at the given z coordinate, or zero if the ray direction is parallel to the plane.

Substituting \({\bf{p}}(s) = {\bf{r}}_0 + s\hat{\bf{k}}\) into the plane's defining equation \(p_z = z_\text{plane}\) and solving for \(s\) gives

\[ s = \frac{z_\text{plane} - r_{0,z}}{k_z}. \]

◆ intersectionMeridionalPlane()

double Quadrics::intersectionMeridionalPlane ( Vec r0,
Vec k,
double sinPhi,
double cosPhi )
inlinestatic

This function returns the distance to the intersection of the ray \(({\bf{r}}_0, \hat{\bf{k}})\) with the meridional half-plane, through the origin and the z-axis, at the azimuth with given sine and cosine, or zero if the ray direction is parallel to the plane.

Substituting \({\bf{p}}(s) = {\bf{r}}_0 + s\hat{\bf{k}}\) into the plane's defining equation \(p_x\sin\varphi - p_y\cos\varphi = 0\) and solving for \(s\) gives

\[ s = -\frac{r_{0,x}\sin\varphi - r_{0,y}\cos\varphi}{k_x\sin\varphi - k_y\cos\varphi}. \]

◆ isPositionInSphere()

bool Quadrics::isPositionInSphere ( Vec p,
Vec center,
double radius )
inlinestatic

This function returns true if the given position is inside the sphere with given center and radius, and false otherwise (a position exactly on the sphere's surface counts as inside).

◆ isSphereInShell()

bool Quadrics::isSphereInShell ( Vec center,
double radius,
double rmin,
double rmax )
inlinestatic

This function returns true if the sphere with given center and radius is fully inside the spherical shell, centered on the origin, with given inner and outer radii (no straggling nor touching allowed).

◆ isSphericalCellInSphere()

bool Quadrics::isSphericalCellInSphere ( double rmin,
double rmax,
double thetaMin,
double thetaMax,
double phiMin,
double phiMax,
Vec center,
double radius )
inlinestatic

This function returns true if the "spherical box" cell – the region with radius between rmin and rmax, polar angle (colatitude) between thetaMin and thetaMax, and azimuth between phiMin and phiMax, all measured around the origin – lies fully inside the sphere with the given center and radius (touching allowed).

The radial extent is handled exactly: for a fixed direction, the squared distance to a point at radius r is a convex function of r, so its maximum over [rmin,rmax] is always attained at one of the two endpoints, regardless of curvature. What remains is finding the direction within the cell's angular box that lies farthest, in projection, from the sphere's center. Because the azimuthal term of that projection is scaled by sin(theta), which is nonnegative throughout the box, the farthest azimuth can be found first, independently of theta, and the result then feeds a second, one-dimensional search over theta. Each of those two searches reduces to checking whether the antipodal direction falls within the relevant bound, and otherwise evaluating the two boundary values – never a full numerical optimization.

◆ smallestPositiveSolution() [1/2]

double Quadrics::smallestPositiveSolution ( double a,
double b,
double c )
inlinestatic

This function returns the smallest positive solution of \(ax^2 + 2bx + c = 0\), or zero if there is no positive solution. If the equation degenerates to a linear equation, this equation is solved instead.

◆ smallestPositiveSolution() [2/2]

double Quadrics::smallestPositiveSolution ( double b,
double c )
inlinestatic

This function returns the smallest positive solution of \(x^2 + 2bx + c = 0\), or zero if there is no positive solution.

As in distinctSolutions(), only the root for which \(-b\) and \(\sqrt{b^2-c}\) have the same sign is evaluated directly – \(-b-\sqrt{b^2-c}\) if \(b>0\), or \(-b+\sqrt{b^2-c}\) if \(b<0\) – avoiding the catastrophic cancellation that evaluating both roots directly would incur; the other root, when it is needed, is obtained from it through Vieta's formula \(x_1 x_2 = c\) rather than by evaluating the numerically unsafe combination directly.

◆ sphereIntersectsPlane()

bool Quadrics::sphereIntersectsPlane ( double sphereRadius,
double outOfPlaneCenterCoord,
double & circleRadius )
inlinestatic

This function determines the circle formed by intersecting a sphere (given its radius and its center's coordinate along the axis perpendicular to the plane) with a coordinate plane through the origin. It returns true and sets circleRadius if the sphere reaches the plane; it returns false (leaving circleRadius unchanged) if it doesn't. The circle's center in the plane is simply the sphere center's own two in-plane coordinates, so the caller already has those and doesn't need them returned here.

By the Pythagorean relation between the sphere's radius \(R\), its center's out-of-plane offset \(d\), and the radius \(\rho\) of the circle cut out of the plane,

\[ \rho = \sqrt{R^2 - d^2}, \]

which is real, and thus returned, only if \(|d|<R\).

◆ sqrtDiffSquares()

double Quadrics::sqrtDiffSquares ( double a,
double b )
inlinestatic

This function returns \(\sqrt{a^2-b^2}\) for \(|a|\ge|b|\), computed as \(\sqrt{(a-b)(a+b)}\) rather than directly from \(a^2-b^2\), to avoid the loss of precision that direct evaluation would incur through catastrophic cancellation when \(|a|\) and \(|b|\) are close. The argument to the square root is clamped to zero in case rounding error would otherwise make it (slightly) negative even though the exact value is nonnegative.

◆ square()

double Quadrics::square ( double x)
inlinestatic

This function returns \(x^2\).

◆ volumeSphere()

double Quadrics::volumeSphere ( double radius)
inlinestatic

This function returns the volume of a sphere with given radius, \(V = \frac{4}{3}\pi r^3\).


The documentation for this class was generated from the following file: