7.3 Algebra of Shapes
In the previous section we saw the need for the concept of empty shape, which becomes more evident when we compare the operations for combining shapes with basic algebraic operations, such as sum and product. To begin, let us consider a function that adds numbers in an array:
sum(numbers) =
if numbers == []
0
else
numbers[1]+sum(numbers[2:end])
end
As we can see in the previous function, the sum of an empty array of numbers is zero. This makes sense because, when there are no numbers to add, the total is necessarily zero. Moreover, during recursion, there are pending sums and, when it reaches the base case, the function needs to return a value that does not affect those pending sums, which in this case would have to be zero, since it is the neutral element of the sum.
Likewise, if we think of a function that calculates the union of regions in an array, we should write:
unions(regions) =
if regions == []
empty_shape()
else
union(regions[1], unions(regions[2:end]))
end
where the empty_shape \(\varnothing\) is the neutral element of the union operation.
Let us now consider a function that multiplies numbers in an array:
product(numbers) =
if numbers == []
???
else
numbers[1]*product(numbers[2:end])
end
What value should the function return in the base case? In other words, what is the product of an empty array of numbers? Though we might be tempted to use zero as the base case value, that would be incorrect because zero is the absorbing element of the product and, therefore, in the case of a non-empty array of numbers, it would be propagated throughout the sequence of pending products, producing a final result of zero. Thus, it becomes clear that the correct value for the basic scenario has to be 1, i.e., the neutral element of the product:
product(numbers) =
if numbers == []
1
else
numbers[1]*product(numbers[2:end])
end
This analysis is crucial for the correct definition of a function that computes the intersection of regions in an array. Although it is straightforward to write a first draft:
intersections(regions) =
if regions == []
???
else
intersection(regions[1], intersections(regions[2:end]))
end
it is not entirely clear what to return in the base case. We know that this value has to be the neutral element of the combination operation, which, in this case, is the intersection. This neutral element will have to be, necessarily, the universal shape \(U\), i.e., the shape that includes all the points of space. In Khepri, this imaginary shape is produced by the function universal_shape, allowing us to complete the definition:
intersections(regions) =
if regions == []
universal_shape()
else
intersection(regions[1], intersections(regions[2:end]))
end
It is important that we understand that the need for the empty_shape and the universal_shape functions results from us having to assure the correct mathematical behavior of the union, intersection and subtraction operations of regions. That mathematical behavior is dictated by the following functions of the algebra of regions:
\[R \cup \varnothing = \varnothing \cup R = R\] \[R \cup U = U \cup R = U\] \[R \cup R = R\] \[R \cap \varnothing = \varnothing \cap R = \varnothing\] \[R \cap U = U \cap R = R\] \[R \cap R = R\] \[R \setminus \varnothing = R\] \[\varnothing \setminus R = \varnothing\] \[R \setminus R = \varnothing\]
7.3.1 Exercises 34
7.3.1.1 Question 121
The algebra of regions we elaborated is incomplete because it does not include the complement operation of a region. The complement \(R^C\) of a region \(R\) is defined as the subtraction between the universal region \(U\) and the region \(R\):
\[R^C=U\setminus R\]
The complement operation allows the representation of the concept of hole. A hole with the shape of the region \(R\) is obtained simply through \(R^C\). A hole has no obvious geometric representation, as it is difficult to imagine a hole without knowing in which region the hole is located. However, from the mathematical point of view, the concept makes sense as long as the algebraic operations on the regions know how to interpret it. For example, given the hole \(R_1^C\), we can apply it to a region \(R_0\) through the intersection of the two regions \(R_0\cap R_1^C\). As CAD tools do not know how to handle the complement of regions, the operation will have to be translated in terms of other operations already known. In this case, the subtraction is an obvious choice, as \(R_0\cap R_1^C=R_0\setminus R_1\).
To complete the algebra of holes, it is necessary that we define the result of the union, intersection and subtraction operations when applied to holes. Define mathematically those operations, as well as the combination between regions and holes.
7.3.1.2 Question 122
Since Khepri does not implement the concept of complement, define a constructor for the complement of regions. The constructor should receive the region from which the complement is intended and should return an object that symbolically represents the complement of the region. Do not forget that the complement of a region’s complement is the region itself.
Also define a recognizer of complements that receives any type of object and only returns true for those that represent complements of regions.
7.3.1.3 Question 123
Define the union, intersection, and subtraction operations of regions so as to deal with the complement of regions.
7.3.1.4 Question 124
Consider the construction of a region composed by a recursive union of regular polygons successively smaller and centered at the vertices of the polygon immediately bigger, as seen in the three examples presented in the following figure:
As it happened with the regular_polygon and vertices_polygon_regular functions defined in section \ref{sec:2DGeometricModeling}, each of these polygons is characterized for having a certain number of sides \(n\), for being inscribed in a circumference centered at a point \(P\) and with a radius \(r\), and for having a vertex that makes an angle \(\phi\) with the \(X\) axis.
Furthermore, the construction of regular polygons is done so that each vertex is the center of a new identical polygon, but inscribed in a circle whose radius is a fraction (given by \(\alpha_r\)) of the radius \(r\), with this process being repeated for a certain number of levels. For example, in the previous figure, the left image was created with \(p=(0,0)\), \(r=1\), \(\phi=0\), \(\alpha_r=0.3\), \(n=4\), and with a number of levels equal to \(2\). In fact, the images were produced by the evaluation of the following expressions:
recursive_polygons(xy(0, 0), 1, 0, 0.3, 4, 2)
recursive_polygons(xy(3, 0), 1, pi/3, 0.3, 3, 3)
recursive_polygons(xy(6, 0), 1, 0, 0.3, 5, 4)
7.3.1.5 Question 125
The Petronas twin towers were designed by the Argentine architect César Pelli and were considered the tallest buildings in the world from 1998 to 2004. This figure shows a perspective of one of the towers.
Petronas Towers, located at Kuala Lumpur, in Malaysia. Photograph by Mel Starrs.
The towers’ section, strongly inspired by Islamic motifs, is composed by two intersecting squares, one rotated 45 degrees, to which circles were added at the intersection points, as it can be seen in the scheme below.
Note that the circles are tangent to the imaginary edges that connect the vertices.
Define a Julia function named petronas_section that receives the center of the section and the length \(l\), and produces the section of the Petronas towers. Suggestion: use the surface_regular_polygon, surface_circle, and union functions to generate the relevant regions.
7.3.1.6 Question 126
Define the function petronas_tower that, from the base center, builds a succession of sections of the Petronas tower in order to reproduce the real geometry of building, as illustrated in the following perspective where the function was invoked twice to generate towers in different positions. Note that the sections’ length decrease at a given point of the towers’ height.
7.3.1.7 Question 127
Consider the construction of a sphere made of cones like the one presented in the following image:
Notice that all the cones have their vertex in the same point and are oriented so that the center of the base lies on a virtual sphere. Also note that all the meridians and parallels have the same number of cones, and that the radius of the base of the cones diminishes as we come closer to the poles, so that the cones do not interfere with each other.
Write a Julia program capable of building the sphere of cones. The function should receive the center and radius of the sphere, and the number and radius of the cones on the equator.
7.3.1.8 Question 128
Consider a variation on the sphere of cones from the previous exercise in which, instead of diminishing the radius of the cones’ base as we get closer to the poles, we diminish the number of cones, as presented in the following image:
Write a Julia program able to build this sphere of cones. The function should receive the center and radius of the sphere, and the number and radius of the cones on the equator.
7.3.1.9 Question 129
Define a Julia function to create perforated spherical shells, as the ones presented below:
The function should have as arguments the center, radius, and thickness of the spherical shell, and the radius and number of perforations to perform along the equator. This number should diminish as we come closer to the poles.
7.3.1.10 Question 130
Consider the following construction built from a random arrangement of perforated spheres:
To model the previous image, define a function that receives two points, which define the limits of an imaginary volume (parallel to the coordinated axes) inside which are located the centers of the spheres, the minimum and maximum radius of each sphere, the thickness of the shell, the number of spheres to create, and, finally, the necessary parameters to do the same type of perforations on each sphere.
Note that the interior of the construction should be unobstructed, as illustrated in the following section view:
7.3.1.11 Question 131
An impossible cube (also known as irrational cube) is a famous optical illusion in which a cube seems to have some edges in front of others in a seemingly impossible configuration. The following image shows an impossible cube.
Define an impossible_cube function that creates impossible cubes.
7.3.1.12 Question 132
Consider a cube built from an arrangement of smaller cubes, as presented in the following image:
Each smaller cube has a third of the side of the built cube. Define a function that, from the coordinates of one vertex and the length of the side of the cube, creates a cube with the arrangement of smaller cubes as shown in the previous image.
7.3.1.13 Question 133
The Menger sponge is a well-known fractal invented by the mathematician Karl Menger. The following image illustrates several construction stages of a Menger sponge.
Like the previous exercise, building a Menger sponge can be done through the composition of smaller cubes, with the nuance of replacing the smaller cubes by (sub-)sponges of Menger. Naturally, in the case a computer implementation, an infinite recursion is impracticable and thus we need to establish a stopping condition to guarantee that, at a certain point, no more (sub-)sponges of Menger are created.
Define the menger_sponge function that receives the coordinate of one vertex of the sponge, the sponge dimension and the desired level of depth for the recursion.
7.3.1.14 Question 134
Consider the following barrel vaults, composed by semi-cylindrical arches:
Define a function called barrel_vault that, given the center of the vault, the radius of the circle that circumscribes the vault, the thickness of the vault, and the number of arches to place, produces vaults as the ones presented above. Make sure your function is able to generate the following vault with only three arches: