3.4 Points

A point is a zero-dimensional location in 2D or 3D space. The Point2 and Point3 classes in pbrt represent points in the obvious way: using x , y , z (in 3D) coordinates with respect to a coordinate system. Although the same representation is used for vectors, the fact that a point represents a position whereas a vector represents a direction leads to a number of important differences in how they are treated. Points are denoted in text by normal p Subscript .

In this section, we will continue the approach of only including implementations of the 3D point methods for the Point3 class here.

<<Point3 Definition>>= 
template <typename T> class Point3 : public Tuple3<Point3, T> { public: <<Point3 Public Methods>> 
using Tuple3<Point3, T>::x; using Tuple3<Point3, T>::y; using Tuple3<Point3, T>::z; using Tuple3<Point3, T>::HasNaN; using Tuple3<Point3, T>::operator+; using Tuple3<Point3, T>::operator+=; using Tuple3<Point3, T>::operator*; using Tuple3<Point3, T>::operator*=; Point3() = default; PBRT_CPU_GPU Point3(T x, T y, T z) : Tuple3<pbrt::Point3, T>(x, y, z) {} // We can't do using operator- above, since we don't want to pull in // the Point-Point -> Point one so that we can return a vector // instead... PBRT_CPU_GPU Point3<T> operator-() const { return {-x, -y, -z}; } template <typename U> explicit Point3(Point3<U> p) : Tuple3<pbrt::Point3, T>(T(p.x), T(p.y), T(p.z)) {} template <typename U> explicit Point3(Vector3<U> v) : Tuple3<pbrt::Point3, T>(T(v.x), T(v.y), T(v.z)) {} template <typename U> auto operator+(Vector3<U> v) const -> Point3<decltype(T{} + U{})> { return {x + v.x, y + v.y, z + v.z}; } template <typename U> Point3<T> &operator+=(Vector3<U> v) { x += v.x; y += v.y; z += v.z; return *this; } template <typename U> auto operator-(Vector3<U> v) const -> Point3<decltype(T{} - U{})> { return {x - v.x, y - v.y, z - v.z}; } template <typename U> Point3<T> &operator-=(Vector3<U> v) { x -= v.x; y -= v.y; z -= v.z; return *this; } template <typename U> auto operator-(Point3<U> p) const -> Vector3<decltype(T{} - U{})> { return {x - p.x, y - p.y, z - p.z}; }
};

As with vectors, it is helpful to have shorter type names for commonly used point types.

<<Point3* Definitions>>= 
using Point3f = Point3<Float>; using Point3i = Point3<int>;

It is also useful to be able to convert a point with one element type (e.g., a Point3f) to a point of another one (e.g., Point3i) as well as to be able to convert a point to a vector with a different underlying element type. The following constructor and conversion operator provide these conversions. Both also require an explicit cast, to make it clear in source code when they are being used.

<<Point3 Public Methods>>= 
template <typename U> explicit Point3(Point3<U> p) : Tuple3<pbrt::Point3, T>(T(p.x), T(p.y), T(p.z)) {} template <typename U> explicit Point3(Vector3<U> v) : Tuple3<pbrt::Point3, T>(T(v.x), T(v.y), T(v.z)) {}

There are certain Point3 methods that either return or take a Vector3. For instance, one can add a vector to a point, offsetting it in the given direction to obtain a new point. Analogous methods, not included in the text, also allow subtracting a vector from a point.

<<Point3 Public Methods>>+=  
template <typename U> auto operator+(Vector3<U> v) const -> Point3<decltype(T{} + U{})> { return {x + v.x, y + v.y, z + v.z}; } template <typename U> Point3<T> &operator+=(Vector3<U> v) { x += v.x; y += v.y; z += v.z; return *this; }

Alternately, one can subtract one point from another, obtaining the vector between them, as shown in Figure 3.7.

Figure 3.7: Obtaining the Vector between Two Points. The vector bold v equals normal p prime minus normal p Subscript is given by the component-wise subtraction of the points normal p prime and normal p Subscript .

<<Point3 Public Methods>>+= 
template <typename U> auto operator-(Point3<U> p) const -> Vector3<decltype(T{} - U{})> { return {x - p.x, y - p.y, z - p.z}; }

The distance between two points can be computed by subtracting them to compute the vector between them and then finding the length of that vector. Note that we can just use auto for the return type and let it be set according to the return type of Length(); there is no need to use the TupleLength type trait to find that type.

<<Point3 Inline Functions>>= 
template <typename T> auto Distance(Point3<T> p1, Point3<T> p2) { return Length(p1 - p2); }

The squared distance between two points can be similarly computed using LengthSquared().

<<Point3 Inline Functions>>+= 
template <typename T> auto DistanceSquared(Point3<T> p1, Point3<T> p2) { return LengthSquared(p1 - p2); }