3.2 Operations with Coordinates
Now that we know how to create coordinates, we can rethink the functions that manipulate them. Let us begin with the function that calculates the distance between two positions \(P=(p_x,p_y,p_z)\) and \(Q=(q_x,q_y,q_z)\), which, as we saw, can be calculated using the formula:
\[\sqrt{(q_x-p_x)^2+(q_y-p_y)^2+(q_z-p_z)^2}\]
A first draft of this definition translated into Julia would be:
dist(p, q) =
sqrt((qx?-px?)^2+(qy?-py?)^2+(qz?-pz?)^2)
In order to complete the function, we need to know how to get the \(x\), \(y\), and \(z\) coordinates of a given position \(P\). For that purpose, Khepri provides the functions cx, cy and cz, abbreviations for coordinate x, coordinate y, and coordinate z, respectively.
The functions xyz, cx, cy, and cz can be considered the fundamental operations on coordinates. The first one allows us to construct a position given three numbers, and the others allow us to know which numbers determine a given position. For this reason, the first operation is said to be a constructor of coordinates, whereas the others are selectors of coordinates.
Although we are unaware of how these functions operate internally, we know they are consistent with each other, ensured by the following expressions:
cx(xyz(x, y, z)) \(=\) x
cy(xyz(x, y, z)) \(=\) y
cz(xyz(x, y, z)) \(=\) z
Using these functions we can now write:
dist(p, q) = sqrt((cx(q)-cx(p))^2+(cy(q)-cy(p))^2+(cz(q)-cz(p))^2)
The function dist can be tested using a specific case:The dist function is predefined in Khepri under the name distance.
> dist(xyz(2, 1, 3), xyz(5, 6, 4))
5.916079783099616
To simplify the use of the functions cx, cy and cz, Khepri allows an additional syntax that is closer to mathematics. Using this syntax, the expressions cx(p), cy(p), and cz(p) can be written, respectively, as p.x, p.y, and p.z. This allows us to simplify the previous function definition:
dist(p, q) = sqrt((q.x-p.x)^2+(q.y-p.y)^2+(q.z-p.z)^2)
Let us look at another example. Suppose we want to define a function, named add_xyz, which calculates the position of a point after a translation, expressed in terms of its orthogonal components \(\Delta_x\), \(\Delta_y\) and \(\Delta_z\), as can be seen in this figure, on the left. For \(P=(x,y,z)\) we will have \(P'=(x+\Delta_x,y+\Delta_y,z+\Delta_z)\). Naturally, the function needs as inputs a starting point \(P\) and the increments \(\Delta_x\), \(\Delta_y\) and \(\Delta_z\), which we will name as dx, dy, and dz, respectively.
The definition of this function is as follows:
add_xyz(p, dx, dy, dz) = xyz(p.x+dx, p.y+dy, p.z+dz)
However, just like it happened previously, it is not very practical to separately specify each of the components of the translation. Fortunately, we can avoid this problem by using a vector. A vector is a mathematical entity that includes a direction and a magnitude, and thus can easily represent a translation. Note that a vector has neither an origin nor a destination.
In this figure, on the right, the vector \(\vec{v}=(\Delta_x, \Delta_y, \Delta_z)\) represents the displacement that we want to apply to the position \(P\) to reach the position \(P'\). If we define the addition \(P+\vec{v}\) of the position \(P=(x,y,z)\) with the vector \(\vec{v}=(\Delta_x, \Delta_y, \Delta_z)\) as \((x+\Delta_x,y+\Delta_y,z+\Delta_z)\), it becomes evident that \(P'=P+\vec{v}\). In the same way, it is possible to define the vector \(\vec{v}\) as the difference between the two positions, i.e., \(\vec{v}=P'-P\). Many other operations are meaningful in the context of vectors, including addition and subtraction of vectors, as well as product of vectors by scalars or by other vectors. This vector algebra, known since the 17th century, allows the simplification of computations involving positions and displacements.
The point \(P'\) as a result of the translation of the point \(P=(x,y,z)\) by adding \(\Delta_x\) in the \(X\) axis, \(\Delta_y\) in the \(Y\) axis and \(\Delta_z\) in the \(Z\) axis.
Given the usefulness of vectors, these are also provided by Khepri under the form of an operation called vxyz, which, from three independent displacements along the coordinate axes \(X\), \(Y\), and \(Z\), produces the corresponding vector. Similarly to positions, vectors can be used with the operations cx, cy, and cz, and with the alternative syntax .x, .y, and .z.
The following interaction demonstrates the use of positions and vectors:
> xyz(1,2,3) + vxyz(3,2,1)
xyz(4.0,4.0,4.0)
> xyz(4,5,6) - xyz(3,2,1)
vxyz(1.0,3.0,5.0)
> vxyz(4,5,6) - vxyz(3,2,1)
vxyz(1.0,3.0,5.0)
> xyz(1,2,3) + (xyz(4,5,6) - xyz(3,2,1))
xyz(2.0,5.0,8.0)
> xyz(1,2,3) + xyz(4,5,6) - xyz(3,2,1)
ERROR: MethodError: no method matching +(::XYZ, ::XYZ)
> xyz(1,2,3) - xyz(3,2,1) + xyz(4,5,6)
xyz(2.0,5.0,8.0)
> vxyz(1,2,3) + vxyz(4,5,6) - xyz(3,2,1)
ERROR: MethodError: no method matching -(::VXYZ, ::XYZ)
Note that not all operations are possible. In particular, the addition of positions does not make sense.
3.2.1 Exercises 11
3.2.1.1 Question 35
Define the function midpoint that calculates the location of the midpoint between two points \(P_0\) and \(P_1\).
3.2.1.2 Question 36
Define the function equal_c that takes two points and returns true if they are coincident. Note that two points are coincident when their \(x\), \(y\), and \(z\) coordinates are equal.
3.2.2 Bi-dimensional Coordinates
Just as three-dimensional coordinates locate points in space, bi-dimensional coordinates locate points in a plane. The question to be asked is: which plane? From a mathematical point of view, this question is not relevant since it is perfectly possible to think about geometry in a plane without needing to visualize the plane itself. But when we try to visualize that geometry in a 3D modeling program, we must inevitably think where that plane is located. If omitted, CAD applications will consider, by default, the bi-dimensional plane as the \(XY\) plane, being the height \(z\) equal to zero. So let us consider the bi-dimensional coordinates \((x,y)\) as a simplified notation for the three-dimensional coordinates \((x,y,0)\).
Based on this simplification, we can define a bi-dimensional coordinates’ constructor in terms of the three-dimensional coordinates’ constructor:
xy(x, y) = xyz(x, y, 0)
In the same way, we can define constructors for bi-dimensional coordinates along the other coordinate planes, i.e., \(XZ\) and \(YZ\):
xz(x, z) = xyz(x, 0, z)
yz(y, z) = xyz(0, y, z)
Similarly, we can define bi-dimensional vectors using the same approach:
vxy(dx, dy) = vxyz(dx, dy, 0)
vxz(dx, dz) = vxyz(dx, 0, dz)
vyz(dy, dz) = vxyz(0, dy, dz)
One advantage of the definition of bi-dimensional positions and vectors on top of three-dimensional ones is the fact that the coordinate selectors become immediately applicable to bi-dimensional coordinates and, therefore, all other operations defined using the selectors are also applicable to the bi-dimensional case.
3.2.3 Exercises 12
3.2.3.1 Question 37
Given the point \(P_0=(x_0,y_0)\) and a line defined by two points \(P_1=(x_1,y_1)\) and \(P_2=(x_2,y_2)\), the minimum distance \(d\) between \(P_0\) and the line is given by:
\[d=\frac{\left\vert(x_2-x_1)(y_1-y_0)-(x_1-x_0)(y_2-y_1)\right\vert}{\sqrt{(x_2-x_1)^2+(y_2-y_1)^2}}\]
Define a function point_line_distance that, given the coordinates of \(P_0\), \(P_1\) and \(P_2\), returns the minimum distance between \(P_0\) and the line defined by \(P_1\) and \(P_2\).
3.2.3.2 Question 38
3.2.4 Polar Coordinates
Although the Cartesian coordinate system is widely used, there are other coordinate systems that can be more useful in certain situations. As an example, suppose we wanted to place \(n\) elements equally spaced between them and with the distance \(d\) from the origin point, as is represented in this figure. Logically, the elements will form a circle and the angle between them is \(\frac{2\pi}{n}\).
Positions along a circle.
Taking the \(X\) axis as a reference, we can say that the first element will be positioned at a distance \(d\) from the origin point, the second element will have the same distance but on a different axis that makes a \(\frac{2\pi}{n}\) angle with the \(X\) axis, the third element will also have the same distance but is positioned in an axis that makes an angle of \(\frac{4\pi}{n}\) with the \(X\) axis, and so on. However, when trying to define those positions using Cartesian coordinates, we would find that the regularity expressed with the “and so on” is immediately lost. This should make us consider a different system of coordinates, namely, the polar coordinate system.
As represented in this figure, a position in a bi-dimensional plane is expressed, in rectangular coordinates, by the numbers \(x\) and \(y\) - respectively the abscissa (x coordinate) and ordinate (y coordinate), while in polar coordinates it is expressed by \(\rho\) and \(\phi\) - respectively the radius vector (also called modulus) and the polar angle (also called argument). With the help of trigonometry and the Pythagorean theorem it is easy to convert polar coordinates into rectangular coordinates:
\[\left\{\begin{aligned} x&=\rho \cos \phi\\ y&=\rho \sin \phi \end{aligned}\right.\]
Likewise, it is also straightforward to convert rectangular coordinates into polar coordinates:
\[\left\{\begin{aligned} \rho&=\sqrt{x^2 + y^2}\\ \phi&=\arctan \frac{y}{x} \end{aligned}\right.\]
Rectangular and polar coordinates.
Based on the above equations, we can define the constructor of polar coordinates pol (abbreviation of polar) by simply converting them into the equivalent rectangular representation:
pol(rho, phi) = xy(rho*cos(phi), rho*sin(phi))
That being said, polar coordinates will be implemented based on the rectangular system. For that reason, the polar coordinates selectors - the function pol_rho to obtain the \(\rho\) value, and the function pol_phi to obtain the \(\phi\) value - must use the rectangular coordinates selectors, i.e., cx and cy. The functions pol_phi and pol_rho are already predefined in Khepri.
pol_rho(c) = sqrt(c.x^2+c.y^2)
pol_phi(c) = atan(c.y, c.x)
Here are some examples of these functions usage: Note that in some cases the coordinates are not zero or one as we would expect, but values very close to them. This is due to rounding errors. Also note that, due to the use of bi-dimensional coordinates, the \(z\) coordinate is always zero.
> pol(1, 0)
xyz(1.0,0.0,0)
> pol(sqrt(2), pi/4)
xyz(1.0000000000000002,1.0,0)
> pol(1, pi/2)
xyz(6.123233995736766e-17,1.0,0)
> pol(1, pi)
xyz(-1.0,1.2246467991473532e-16,0)
In case we want to specify vectors in polar coordinates, as illustrated in this figure, we can use a similar approach, by defining the constructor vpol:
vpol(rho, phi) = vxy(rho*cos(phi), rho*sin(phi))
A point displacement in polar coordinates.
Consider the following examples of usage:
> xy(1, 2)+vpol(sqrt(2), pi/4)
xyz(2.0,3.0,0.0)
> xy(1, 2)+vpol(1, 0)
xyz(2.0,2.0,0.0)
> xy(1, 2)+vpol(1, pi/2)
xyz(1.0,3.0,0.0)
3.2.5 Exercises 13
3.2.5.1 Question 39
The function equal_c defined in Question 36 compares the coordinates of two points, returning true if they are coincident. However, taking into account that numeric operations can produce rounding errors, it is possible that two coordinates, which in theory should be the same, in practice are not considered as such. For example, the point \((-1,0)\) in rectangular coordinates can be expressed in polar coordinates as \(\rho=1, \phi=\pi\) but Julia will not consider them equal, as can be seen in the example below:
> equal_c(xy(-1, 0), pol(1, pi))
false
> xy(-1, 0)
xyz(-1,0,0)
> pol(1, pi)
xyz(-1.0,1.2246467991473532e-16,0)
As you can see, although the coordinates are not the same, they are very close, i.e., the distance between them is very close to zero. Propose a new definition for the function equal_c based on the concept of distance between coordinates.