| tags |
|
|---|
In this article we will consider basic operations on points in Euclidean space which maintains the foundation of the whole analytical geometry.
We will consider for each point
Both 2D and 3D points maintain linear space, which means that for them sum of points and multiplication of point by some number are defined. Here are those basic implementations for 2D:
struct point2d {
ftype x, y;
point2d() {}
point2d(ftype x, ftype y): x(x), y(y) {}
point2d& operator+=(const point2d &t) {
x += t.x;
y += t.y;
return *this;
}
point2d& operator-=(const point2d &t) {
x -= t.x;
y -= t.y;
return *this;
}
point2d& operator*=(ftype t) {
x *= t;
y *= t;
return *this;
}
point2d& operator/=(ftype t) {
x /= t;
y /= t;
return *this;
}
point2d operator+(const point2d &t) const {
return point2d(*this) += t;
}
point2d operator-(const point2d &t) const {
return point2d(*this) -= t;
}
point2d operator*(ftype t) const {
return point2d(*this) *= t;
}
point2d operator/(ftype t) const {
return point2d(*this) /= t;
}
};
point2d operator*(ftype a, point2d b) {
return b * a;
}And 3D points:
struct point3d {
ftype x, y, z;
point3d() {}
point3d(ftype x, ftype y, ftype z): x(x), y(y), z(z) {}
point3d& operator+=(const point3d &t) {
x += t.x;
y += t.y;
z += t.z;
return *this;
}
point3d& operator-=(const point3d &t) {
x -= t.x;
y -= t.y;
z -= t.z;
return *this;
}
point3d& operator*=(ftype t) {
x *= t;
y *= t;
z *= t;
return *this;
}
point3d& operator/=(ftype t) {
x /= t;
y /= t;
z /= t;
return *this;
}
point3d operator+(const point3d &t) const {
return point3d(*this) += t;
}
point3d operator-(const point3d &t) const {
return point3d(*this) -= t;
}
point3d operator*(ftype t) const {
return point3d(*this) *= t;
}
point3d operator/(ftype t) const {
return point3d(*this) /= t;
}
};
point3d operator*(ftype a, point3d b) {
return b * a;
}Here ftype is some type used for coordinates, usually int, double or long long.
The dot (or scalar) product
The dot product holds some notable properties:
$\mathbf a \cdot \mathbf b = \mathbf b \cdot \mathbf a$ $(\alpha \cdot \mathbf a)\cdot \mathbf b = \alpha \cdot (\mathbf a \cdot \mathbf b)$ $(\mathbf a + \mathbf b)\cdot \mathbf c = \mathbf a \cdot \mathbf c + \mathbf b \cdot \mathbf c$
I.e. it is a commutative function which is linear with respect to both arguments. Let's denote the unit vectors as
With this notation we can write the vector
we can see that in terms of coordinates for
That is also the algebraic definition of the dot product. From this we can write functions which calculate it.
ftype dot(point2d a, point2d b) {
return a.x * b.x + a.y * b.y;
}
ftype dot(point3d a, point3d b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}When solving problems one should use algebraic definition to calculate dot products, but keep in mind geometric definition and properties to use it.
We can define many geometrical properties via the dot product. For example
- Norm of
$\mathbf a$ (squared length):$|\mathbf a|^2 = \mathbf a\cdot \mathbf a$ - Length of
$\mathbf a$ :$|\mathbf a| = \sqrt{\mathbf a\cdot \mathbf a}$ - Projection of
$\mathbf a$ onto$\mathbf b$ :$\dfrac{\mathbf a\cdot\mathbf b}{|\mathbf b|}$ - Angle between vectors:
$\arccos \left(\dfrac{\mathbf a\cdot \mathbf b}{|\mathbf a| \cdot |\mathbf b|}\right)$ - From the previous point we may see that the dot product is positive if the angle between them is acute, negative if it is obtuse and it equals zero if they are orthogonal, i.e. they form a right angle.
Note that all these functions do not depend on the number of dimensions, hence they will be the same for the 2D and 3D case:
ftype norm(point2d a) {
return dot(a, a);
}
double abs(point2d a) {
return sqrt(norm(a));
}
double proj(point2d a, point2d b) {
return dot(a, b) / abs(b);
}
double angle(point2d a, point2d b) {
return acos(dot(a, b) / abs(a) / abs(b));
}To see the next important property we should take a look at the set of points
In 2D these vectors will form a line, in 3D they will form a plane.
Note that this result allows us to define a line in 2D as
Assume you have three vectors
How would you calculate its volume?
From school we know that we should multiply the area of the base with the height, which is projection of
This defines the cross (or vector) product
Some notable properties of cross and triple products:
-
$\mathbf a\times \mathbf b = -\mathbf b\times \mathbf a$ -
$(\alpha \cdot \mathbf a)\times \mathbf b = \alpha \cdot (\mathbf a\times \mathbf b)$ -
For any
$\mathbf b$ and$\mathbf c$ there is exactly one vector$\mathbf r$ such that$\mathbf a\cdot (\mathbf b\times \mathbf c) = \mathbf a\cdot\mathbf r$ for any vector$\mathbf a$ .
Indeed if there are two such vectors$\mathbf r_1$ and$\mathbf r_2$ then$\mathbf a\cdot (\mathbf r_1 - \mathbf r_2)=0$ for all vectors$\mathbf a$ which is possible only when$\mathbf r_1 = \mathbf r_2$ . -
$\mathbf a\cdot (\mathbf b\times \mathbf c) = \mathbf b\cdot (\mathbf c\times \mathbf a) = -\mathbf a\cdot( \mathbf c\times \mathbf b)$ -
$(\mathbf a + \mathbf b)\times \mathbf c = \mathbf a\times \mathbf c + \mathbf b\times \mathbf c$ . Indeed for all vectors$\mathbf r$ the chain of equations holds:[\mathbf r\cdot( (\mathbf a + \mathbf b)\times \mathbf c) = (\mathbf a + \mathbf b) \cdot (\mathbf c\times \mathbf r) = \mathbf a \cdot(\mathbf c\times \mathbf r) + \mathbf b\cdot(\mathbf c\times \mathbf r) = \mathbf r\cdot (\mathbf a\times \mathbf c) + \mathbf r\cdot(\mathbf b\times \mathbf c) = \mathbf r\cdot(\mathbf a\times \mathbf c + \mathbf b\times \mathbf c)]
Which proves
$(\mathbf a + \mathbf b)\times \mathbf c = \mathbf a\times \mathbf c + \mathbf b\times \mathbf c$ due to point 3. -
$|\mathbf a\times \mathbf b|=|\mathbf a| \cdot |\mathbf b| \sin \theta$ where$\theta$ is angle between$\mathbf a$ and$\mathbf b$ , since$|\mathbf a\times \mathbf b|$ equals to the area of the parallelogram formed by$\mathbf a$ and$\mathbf b$ .
Given all this and that the following equation holds for the unit vectors
we can calculate the cross product of
Which also can be written in the more elegant form:
Here
Some kind of cross product (namely the pseudo-scalar product) can also be implemented in the 2D case.
If we would like to calculate the area of parallelogram formed by vectors
If we will take the sign into consideration then the area will be positive if the rotation from
Let's implement all this stuff!
point3d cross(point3d a, point3d b) {
return point3d(a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x);
}
ftype triple(point3d a, point3d b, point3d c) {
return dot(a, cross(b, c));
}
ftype cross(point2d a, point2d b) {
return a.x * b.y - a.y * b.x;
}As for the cross product, it equals to the zero vector iff the vectors
From this we can obtain universal equations defining lines and planes.
A line can be defined via its direction vector
In 2D the pseudo-scalar product also may be used to check the orientation between two vectors because it is positive if the rotation from the first to the second vector is clockwise and negative otherwise. And, of course, it can be used to calculate areas of polygons, which is described in a different article. A triple product can be used for the same purpose in 3D space.
There are many possible ways to define a line in 2D and you shouldn't hesitate to combine them.
For example we have two lines and we want to find their intersection points.
We can say that all points from first line can be parameterized as
Let's implement function to intersect two lines.
point2d intersect(point2d a1, point2d d1, point2d a2, point2d d2) {
return a1 + cross(a2 - a1, d2) / cross(d1, d2) * d1;
}However sometimes it might be hard to use some geometric insights.
For example, you're given three planes defined by initial points
Instead of thinking on geometric approach, you can work out an algebraic one which can be obtained immediately. For example, given that you already implemented a point class, it will be easy for you to solve this system using Cramer's rule because the triple product is simply the determinant of the matrix obtained from the vectors being its columns:
point3d intersect(point3d a1, point3d n1, point3d a2, point3d n2, point3d a3, point3d n3) {
point3d x(n1.x, n2.x, n3.x);
point3d y(n1.y, n2.y, n3.y);
point3d z(n1.z, n2.z, n3.z);
point3d d(dot(a1, n1), dot(a2, n2), dot(a3, n3));
return point3d(triple(d, y, z),
triple(x, d, z),
triple(x, y, d)) / triple(n1, n2, n3);
}Now you may try to find out approaches for common geometric operations yourself to get used to all this stuff.
