Sculpture and Architecture with Geometrica

Bruno Autin and Elena Wildner

bautin@club-internet.fr
Elena.Wildner@cern.ch

Introduction

The extension of Geometrica to 3D has been triggered by modern architecture. A project of building, coined Cubolyhedron™ was indeed developed at the Ecole Polytechnique Federale of Lausanne (Switzerland) and a set of geometrical functions has been worked out to represent it. The approach to the general design is similar to the one followed in sculpture. One starts from a raw block of matter and carves it to produce a more complex polyhedron. The building is made of two solids stacked atop one another. The lower part is a hexahedron derived from the primary cube by cutting facets. The interior contains floors intersecting a central cylindrical well. The upper part keeps the general cubic shape but small cubes are detached at each vertex and inside it a sphere shelters a theater. >From that brief description, it appears that each element of the building can be described by Euclidean geometry and thus relevant to Geometrica.
The new version is a generalization of Geometrica97 and proceeds from the same design. For instance, the same function applies to a point with two or three coordinates. The cartesian description has been kept for the line and the plane. However the program has been re-organized to give the user more flexibility in the choice of cartesian, parametric or euclidean representation of an object. Almost all the functions but Draw and Draw3D remain listable and this feature will be used intensively to keep concise the description of the various constructs. The illustration of the new functions in the design of an advanced architecture building should give the flavour of the increased potential of Geometrica in pure and applied geometry. The commercially available Geometrica02 can be used for almost all of the functions described in this paper, however the code would have to be modified  to find the edges of a polyhedron attached to a vertex, an operation achieved more simply with Geometrica2004.

<< Geometrica`Geometrica2004`

Introducing Geometrica with the cube

The block of matter given by the function Cube is a cube centered at the origin and whose vertical edges of unit length intersect the x and y axes.  The length of the edge of the cube is the scaling factor of the whole project, it is called (Subscript[norm, 1]) and its value is fixed to 1 in that study. This original orientation of the cube is not however the one desired because one diagonal has to be vertical.

A rotation of   Arctan(Sqrt[2]) about the axis Ox is to be performed. The axis Ox is defined by two points. The function Rotate[obj, axis, angle] rotates any 3D object about an axis by a certain angle. The drawing necessitates a new function Draw3D because the simultaneous representation of 2D and 3D objects is not possible. By default a polyhedron is represented by its edges.

norm1 = 1;
cu = Cube[norm1];
ox = 
        ELine[CPoint[0, 0, 0], CPoint[1, 0, 0]];
cu = Rotate[cu, ox, ArcTan[Sqrt[2]]];
Draw3D[cu, Legend["abcdefgh", cu]];

It can be noted that the name of a straight line such as Ox is no longer given by Ruler but by ELine although Ruler would be accepted because the compatibility between versions has ben preserved. The reason for the change is the classification of the representations. A function beginning with the capital letter E, C or P is a euclidean, cartesian or parametric definition. ELine and CLine are thus the euclidean and cartesian definition of a line. A specific function for the parametric representation of a line does not exist because it is replaced by the more general function Pointer which defines a point on a line or a surface.
An acute problem in dealing with 3D figures is to assign names to the various points of a figure. The technique followed here consists of labeling the cube or any polyhedron or segment with the function Legend using the syntax already applied to 2D polygonal lines. Legend attaches a single letter to the vertices of a polyhedron. One can thus read the name of the vertices on the figure and see that the vertical diagonal is ab.

Hexahedron

Cutting the cube can now start. The sections by horizontal planes can be triangles or hexagons. The ones which pass through the vertices deg of height 1/2(Sqrt[3]) and cfh of height -1/2(Sqrt[3]) are remarkable because they are equilateral triangles. The sides of the triangles are indeed diagonals of the faces of the cube. A second transformation is then applied: the cube is lowered so that  deg lies in the xy plane. The function Translate[obj, m] means that the object obj is translated parallel to the vector Om.

cu = 
        Translate[cu, 
          CPoint[0, 0, -norm1/(2 Sqrt[3])]];

The pyramid  of vertex b and base deg is extracted from the cube and re-labeled. The base is painted in green.

{a, b, c, d, e, f, g, h} = 
        Simplify /@ Vertices[cu];
base = Segment[d, e, g, d];
py = Pyramid[b, base];
Draw3D[Red, py, Paint[base, Green], 
        Legend["abcd", py]];

The final hexahedron is delimited by two planes. The first one passes through the middle e of bd and is parallel to abc. Two euclidean definitions are used for the plane and the function Plane is polymorphic. In the first instance, the plane passes through the three points a, b, c. In the second one, it passes through the mid-point m of bd and is parallel to abc. 
The syntax of the function Pointer is the same as in 2D but can be applied to 3D objects. The functions POLYGON and LINE have been replaced by the single function Segment. If the end points of Segment are different, the object is a broken line; if they are the same, the object is a polygon. A broken line is transformed into a polygon by composing the function Close with Segment. 
The function Intersections (⋂) has been extended to the intersections of a plane with another plane, a line, a segment or a polyhedron. In the latter case, the result is a polygon.

{a, b, c, d} = Vertices[py];
e = Pointer[Segment[b, d], 1/2];
p1 = Plane[a, b, c];
p2 = Plane[e, p1];
tr1 = Part[p2 ⋂ py, 1]

The second plane  is parallel to acd and passes through the point j of cb located at the fractional distance t of cb starting from c. The choice of j is a matter of aesthetics. Several trials can easily be made by letting the point j be a function of the parameter t. Then, the triangle ijh can be visualized for any value of t. In the present application, t is taken equal to 3/5.

t =. 
jt[t_] = Pointer[Segment[c, b], t];
j = jt[3/5]; 
p1 = Plane[a, c, d]; 
p2 = Plane[j, p1]; 
tr2 = Part[p2 ⋂ py, 1]

Up to now, the internal form of a polyhedron had not to be known because it was automatically generated by functions such as Cube or Pyramid. In the general case, when no dedicated function is available, a polyhedron is defined by the function Solid whose arguments are the faces (of head Segment) of the polyhedron. The hexahedron H is thus defined by its six faces: the two triangles and four new faces constructed with the vertices. It is colored so that its interior could be seen. The front faces acgf and afehi were left transparent for this purpose.

{{e, f, g}, {h, i, j}} = 
        Flatten /@ Vertices[{tr1, tr2}];
{f3, f4} = 
        Close /@ Segment[a, c, {j, g}, {i, f}];
{f5, f6} = 
        Close /@ Segment[{a, c}, {f, g}, e, 
            h, {i, j}];
hex = Solid[f3, f4, f5, f6, tr1, tr2];
\(\(Draw3D[hex, Blue, 
        Legend[{"a", "c", "e", "f", "g", "h", "i", "j"}, {a, c, e, f, g, h, i, j}], Red, py];\)\)

Staggered floors

The floors of the building are sections of H by two families of horizontal planes corresponding to odd and even floors. The even and odd floors are limited by the vertical planes (Subscript[V, 1]) and (Subscript[V, 2]) parallel the plane V passing through a and perpendicular to ci. The translation vectors are: c(Subscript[m, 1]) = ci/20 and c(Subscript[m, 2])  = - ci /20 respectively. A third euclidean definition of the plane, passing through a point and perpendicular to a line,  is applied still using the function Plane.

d = ELine[c, j];
pv = NormalPlane[a, d];
{m1, m2} = Pointer[Segment[c, j], {1, -1}/20];
{pv1, pv2} = Translate[pv, c, {m1, m2}];
{ff1, ff2, fpv} = 
        Flatten@Intersections[
            hex, {pv1, pv2, pv}];
Draw3D[Legend["agicfejh", hex], 
        Paint[{f3, f6, tr1, tr2}, {Green, Green, Yellow, 
            Yellow}], 
White, hex, ff1, ff2, fpv, 
        Legend[{"klmn", "opqr"}, {ff1, ff2}]];

Then two new polyhedra (Subscript[H, 1]) and (Subscript[H, 2]) are defined by partitioning H with the planes (Subscript[V, 1]) and (Subscript[V, 2]). Here, the listability of Segment for the construction of the various polygonal faces is not invoked. The faces are first represented by ordered lists of their vertices then the symbol Segment is applied to the sub-lists of the list of faces via the operator @@@.

{{k, l, m, n}, {o, p, q, r}} = Vertices[{ff1, ff2}];
fa = {{a, c, g, f, a}, {a, c, n, m, a}, {f, g, k, l, f}, {a, f, l, m, 
            a}, {c, g, k, n, c}};
fa = Segment @@@ fa;
hex1 = Solid @@ Append[fa, ff1];
fa = {{i, j, h, i}, {i, j, r, q, a, i}, {j, r, o, e, h, j}, {a, f, p, 
            q, a}, {e, o, p, f, e}, {e, h, i, a, f, e}};
fa = Segment @@@ fa;
hex2 = Solid @@ Append[fa, ff2];
Draw3D[Blue, hex1, Red, hex2];

The first floor lies at some height h above the ground level. The choice of h can be determined by testing various values using a function. The height of the pyramid is 1/(Sqrt[3]) for a norm equal to 1 as checked by looking at the third coordinate of the vertex a. Fixing the number of left-hand floors to 3, the height can be expressed by the function

he[t_] = t/(3 (Sqrt[ 3]));

The variable t is positive and smaller than 1. There are five floors spaced by h/2. Three floors (Subscript[P, h1]) belong to (Subscript[H, 1])and two others (Subscript[P, h2]) interspersed between (Subscript[P, h1]) belong to (Subscript[H, 2]).The symbol ⋂ does not accept a list as a first argument and the complete statement Intersections is to be used. The value 1/3 of t is tested here.

ph1 = CPlane[0, 0, 1, -he[1/3] {1, 2, 3}];
ph2 = CPlane[0, 0, 1, -he[1/3] {3, 5}/2];
{fl1, fl2} = 
        Flatten /@ 
          Intersections[{hex1, hex2}, {ph1, 
              ph2}];
Draw3D[Blue, fl1, Red, fl2];

Central well

The central well is a cylinder whose axis is the altitude of H issued from a. Its radius r is twice the height of the first floor. The function Cylinder[m, c] defines a cylinder of directrix c and of generators parallel to Om. The directrix can be a polygonal line, a parametric curve or a 3D-conic. The directrix is a special conic: a circle, and the generators are vertical. A 3D-conic c defined by CConic[k, p] lies in a plane p and is deduced from the 2D-conic k by rotation of k about the intersection of p with the horizontal plane. If p is horizontal, the rotation is replaced by a translation. This definition of a 3D conic takes full advantage of all the functions related to the 2D conics and to the circle. The present application is particularly simple. The euclidean circle (ECircle) is centered at the origin and of radius r and its plane is h of equation z = 0.

r = 2 he[1/3];
ci = ECircle[CPoint[0, 0], r];
ci3D = CConic[ci, CPlane[0, 0, 1, 0]];

Now the problem becomes less easy because two cylindrical shells have to be defined, one for each family of floors. It is often the case that part of a 3D problem resorts to 2D geometry and when this happens, such a simplification must be thoroughly exploited. Here, instead of dealing with cylindrical shells, it is sufficient to manipulate circular sectors. The two sectors are limited by the lines (Subscript[d, 1])and (Subscript[d, 2])intersections of (Subscript[V, 1])and (Subscript[V, 2])with h. Their cartesian form is obtained by dropping the third component of the cartesian representation of the planes.

{d1, d2} = CLine @@@ (Drop[#, {3}] & /@ {pv1, pv2})

A circular sector is an arc limited by points of azimuths (Subscript[u, 1]) and (Subscript[u, 2]). These azimuths are the parameters of the intersections of  (Subscript[d, 1])and (Subscript[d, 2]) with the circle, they are provided by the function PointParameter.

{m1, m2} = ci ⋂ {d1, d2};
{{u11, u12}, {u21, u22}} = PointParameter[ci, {m1, m2}]

The 2D treatment ceases here. A point on a cylinder or, more generally on a surface, depends on two parameters. In the case of the cylinder, the point is located on a generator whose position is determined by its intersection m with the directrix. The point m describes the directrix and is characterized by the parameter u which varies here between (Subscript[u, 11]) and (Subscript[u, 12]) for the first shell and between (Subscript[u, 21]) and (Subscript[u, 22]) for the second shell. The second parameter v locates the point of the cylinder on the generator of parameter u; it belongs to the interval (0, 1). The intervals of variation of the two parameters are the right hand side of the option PRange. The computing time for the search of an intersection in 3D is rather long because it takes the surfaces in parametric form.

cy1 = 
        Cylinder[a, ci3D, 
          PRange -> {{u11, u12 + 2  Pi}, {0, 1}}];
cy2 = 
        Cylinder[a, ci3D, PRange -> {{u21, u22}, {0, 1}}];
ch1 = Flatten@Intersections[cy1, ph1];
ch2 = Flatten@Intersections[cy2, ph2];
Draw3D[Blue, ch1, Red, ch2];

In order to make the construction fully satisfactory, the diameter of the circles has to be suppressed. This is achieved by concatenating the arcs with the segments of the polygons transformed into broken lines by deleting one end point with Drop. The arcs are transformed into polygonal lines with ToSegment. Then the function Inner applies the operators Join and List to the lists of segments and completes the polygonal line. The order of the vertices is not known a priori and operations such as Reverse, RotateLeft and RotateRight have to be applied to re-distribute the vertices.

rfl1 = Drop[#, -1] & /@ fl1;
nfl1 = 
        Close /@ Inner[Join, ch1, rfl1, List];
rfl2 = {Reverse@RotateRight@Drop[fl2[[1]], -1], 
          RotateLeft@Drop[fl2[[2]], 1]};
nfl2 = Close /@ Inner[Join, Reverse /@ ch2, rfl2, List]; 
    g2 = Draw3D[hex, 
        Paint[{f3, f6, tr1, tr2}, {Green, Green, Yellow, Yellow}], Red, nfl1, 
        Blue, nfl2];

Indented cube

The upper part of the building is derived from a new cube whose proportions relative to the lower part can be adjusted with the norm (Subscript[norm, 2]) chosen equal to (Subscript[norm, 1])/(Sqrt[2]). Its diagonal must be vertical and it is translated upwards by (Subscript[norm, 1])/(Sqrt[3]) + (Subscript[norm, 2])(Sqrt[3])/4. This way the lower part of the upper indented cube fits exactly the top of the lower hexahedron.

norm2 = norm1/(Sqrt[2]);
ucu = Cube[norm2];
ucu = Rotate[ucu, ox, ArcTan[Sqrt[2]]];
ccu = 
        CPoint[0, 0, norm1/(Sqrt[3]) + norm2 (Sqrt[ 3])/4];
ucu = Translate[ucu, ccu];

Now cubes of edge length one quarter of the cube edge have to be cut at each vertex. The new solid is not entirely defined by its faces as previously but in part by its edges and in part by its faces. This is sufficient for a drawing but would not be adequate for geometric operations such as transformations or intersections. The remaining parts of the edges are segments which join the points located at 1/4 and 3/4 from each vertex of the cube. The power of the Listable attribute of Segment can be appreciated in that example.

e1 = Edges[ucu];
l1 = Pointer[#, 1/4] & /@ e1;
l2 = Pointer[#, 3/4] & /@ e1;
s = Segment[l1, l2];

The small cubes to be built at each vertex use the function Parallelepiped[a, b, c, d] that creates a parallelepiped using the point a as a vertex and the three points b, c, d as vertices adjacent to a. The three faces which share the vertex a are the first faces of the parallelepiped. The function Edge is polymorphic. When its arguments are a polyhedron and a vertex, it returns the edges issued from the vertex. The vertices are the points of type a. The points distant by 1/4 an edge length from the vertices are the points of type b, c, d. They are obtained with the function Pointer mapped to the triplets of edges (Subscript[e, 2]). The lists are arranged so that they fit the required syntax of Parallelepiped. The outer faces of the small cubes are removed by dropping the first three faces of each small cube.

v = Vertices[ucu];
e2 = Edges[ucu, v];
m = Transpose[Pointer[#, 1/4] & /@ e2];
p = Parallelepiped @@ Join[{v}, m];
p = Drop[#, 3] & /@ p;

The last figure is a sphere which touches the inner vertices of the corners.

\(\(\(\ \)\(\(r = norm2\ \@3/4;\)

    \(sp = Sphere[ccu, r];\)\)\)\)

The complete structure is represented in the figure below.

g3 = 
        Draw3D[hex, s, p, Red, nfl1, Blue, nfl2, 
          sp, 
Paint[{f3, f6, tr1, tr2}, {Green, Green, 
              Yellow, Yellow}]];

Exporting Geometrica objects

The Graphics3D files generated with Geometrica can be exported to other programs such as AutoCAD by converting them to the dxf format. Mathematica has indeed the package Utilities`DXF` to perform that conversion using the command WriteDXF[" file.dxf", input file]. The first argument is the name of the output file onto which the dxf file is written. The second argument is the input Graphics3D file.

Conclusion

It has been shown how Geometrica can be applied to the elaboration of a real architectural project. All the constructions have the rigor of mathematics and the coordinates of the points are strictly exact. Not only representation but design is possible. The relative sizes of the objects are determined by scaling factors and whether the building is 10 or 300 meters high, the construction remains the same. Moreover, simple functions help to figure out elements of the whole complex. Functional drawing is certainly the ultimate strength of Geometrica. Geometrica is a pure geometry package and does not have all the features of a professional architecture package but its graphical files can be used in the dxf format for instance and thus serve as an input to other programs. The study presented here was mainly focused on polyhedra but other shapes such as quadrics or more general surfaces can be treated and may give rise to new architectural styles.