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 , , (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 .
In this section, we’ll continue the approach of only including
implementations of the 3D point methods in the Point3 class here.
Also like vectors, a Point3 constructor takes parameters
to set the x, y, and z coordinate values.
<<Point3 Public Methods>>=
Point3() { x = y = z = 0; }
Point3(T x, T y, T z) : x(x), y(y), z(z) {
Assert(!HasNaNs());
}
It can be useful to convert a Point3 to a Point2 by dropping
the coordinate. The constructor that does this conversion has the
explicit qualifier so that this conversion can’t happen without an
explicit cast, lest it happen unintentionally.
It’s 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.
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.
<<Point3 Public Methods>>+=
Point3<T> operator+(const Vector3<T> &v) const {
return Point3<T>(x + v.x, y + v.y, z + v.z);
}
Point3<T> &operator+=(const Vector3<T> &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 2.6.
Figure 2.6: Obtaining the Vector between Two Points. The vector
is given by the component-wise subtraction of the points
and .
<<Point3 Public Methods>>+=
Vector3<T> operator-(const Point3<T> &p) const {
return Vector3<T>(x - p.x, y - p.y, z - p.z);
}
Subtracting a vector from a point gives a new point.
<<Point3 Public Methods>>+=
Point3<T> operator-(const Vector3<T> &v) const {
return Point3<T>(x - v.x, y - v.y, z - v.z);
}
Point3<T> &operator-=(const Vector3<T> &v) {
x -= v.x; y -= v.y; z -= v.z;
return *this;
}
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:
Although in general it doesn’t make sense mathematically to weight points
by a scalar or add two points together, the point classes still allow
these operations in order to be able to compute weighted sums of points,
which is mathematically meaningful as long as the weights used all sum to
one. The code for scalar multiplication and addition with points is
identical to the corresponding code for vectors, so it is not shown here.
On a related note, it’s useful to be able to linearly interpolate between
two points. Lerp() returns p0 at t==0, p1 at
t==1, and linearly interpolates between them at other values of
t. For t<0 or t>1, Lerp()
extrapolates.