Programming for Architecture
1 Preface
2 Introduction
2.1 Programming Languages
2.1.1 Exercises 1
2.1.1.1 Question 1
2.1.1.2 Question 2
2.1.1.3 Question 3
2.2 The Racket Language
2.2.1 Syntax, Semantics and Pragmatics
2.2.2 Syntax and Semantics of Racket
2.2.3 The Evaluator
2.3 Language Elements
2.3.1 Numbers
2.4 Combinations
2.4.1 Indentation
2.4.2 Exercises 2
2.4.2.1 Question 4
2.4.2.2 Question 5
2.4.2.3 Question 6
2.4.2.4 Question 7
2.4.2.5 Question 8
2.4.2.6 Question 9
2.4.3 Evaluating Combinations
2.4.3.1 Question 10
2.4.4 Strings
2.5 Defining Functions
2.5.1 Exercises 3
2.5.1.1 Question 11
2.6 Names
2.6.1 Exercises 4
2.6.1.1 Question 12
2.6.1.2 Question 13
2.6.1.3 Question 14
2.6.1.4 Question 15
2.6.1.5 Question 16
2.6.1.6 Question 17
2.6.1.7 Question 18
2.7 Predefined Functions
2.7.1 Exercises 5
2.7.1.1 Question 19
2.7.1.2 Question 20
2.7.1.3 Question 21
2.7.1.4 Question 22
2.7.1.5 Question 23
2.8 Arithmetic in Racket
2.8.1 Exercises 6
2.8.1.1 Question 24
2.8.1.2 Question 25
2.8.1.3 Question 26
2.9 Name Evaluation
2.10 Conditional Expressions
2.10.1 Logical Expressions
2.10.2 Logical Values
2.11 Predicates
2.11.1 Arithmetic Predicates
2.12 Logical Operators
2.12.1 Exercises 7
2.12.1.1 Question 27
2.13 Predicates with a Variable Number of Arguments
2.14 Recognizers
2.14.1 Exercises 8
2.14.1.1 Question 28
2.14.1.2 Question 29
2.14.1.3 Question 30
2.14.1.4 Question 31
2.14.1.5 Question 32
2.14.1.6 Question 33
2.14.1.7 Question 34
2.15 Selection
2.16 Multiple Selection
2.16.1 Exercises 9
2.16.1.1 Question 35
2.16.1.2 Question 36
2.16.1.3 Question 37
2.17 Local Variables
2.18 Global Variables
2.19 Modules
2.19.1 Exercises 10
2.19.1.1 Question 38
2.19.1.2 Question 39
2.19.1.3 Question 40
3 Modelling
3.1 Coordinates
3.2 Operations with Coordinates
3.2.1 Exercises 11
3.2.1.1 Question 41
3.2.1.2 Question 42
3.2.2 Bi-dimensional Coordinates
3.2.3 Exercises 12
3.2.3.1 Question 43
3.2.3.2 Question 44
3.2.4 Polar Coordinates
3.2.5 Exercises 13
3.2.5.1 Question 45
3.3 Bi-dimensional Geometric Modelling
3.3.1 Exercises 14
3.3.1.1 Question 46
3.3.1.2 Question 47
3.3.1.3 Question 48
3.3.1.4 Question 49
3.4 Side Effects
3.5 Sequencing
3.5.1 Exercises 15
3.5.1.1 Question 50
3.5.1.2 Question 51
3.6 Doric Order
3.7 Parametrization of Geometric Figures
3.8 Documentation
3.8.1 Exercises 16
3.8.1.1 Question 52
3.8.1.2 Question 53
3.8.1.3 Question 54
3.8.1.4 Question 55
3.9 Debugging
3.9.1 Syntactic Errors
3.9.2 Semantic Errors
3.10 Three-dimensional Modelling
3.10.1 Predefined Solids
3.10.2 Exercises 17
3.10.2.1 Question 56
3.10.2.2 Question 57
3.10.3 Exercises 18
3.10.3.1 Question 58
3.10.3.2 Question 59
3.10.3.3 Question 60
3.10.3.4 Question 61
3.10.3.5 Question 62
3.11 Cylindrical Coordinates
3.11.1 Exercises 19
3.11.1.1 Question 63
3.11.1.2 Question 64
3.12 Spherical Coordinates
3.12.1 Exercises 20
3.12.1.1 Question 65
3.12.1.2 Question 66
3.13 Modelling Doric Columns
3.13.1 Exercises 21
3.13.1.1 Question 67
3.14 Vitruvian Proportions
3.14.1 Exercises 22
3.14.1.1 Question 68
4 Recursion
4.1 Introduction
4.1.1 Exercises 23
4.1.1.1 Question 69
4.1.1.2 Question 70
4.2 Recursion in Architecture
4.2.1 Exercises 24
4.2.1.1 Question 71
4.2.1.2 Question 72
4.2.1.3 Question 73
4.2.1.4 Question 74
4.2.1.5 Question 75
4.3 Debugging Recursive Programs
4.3.1 Exercises 25
4.3.1.1 Question 76
4.3.1.2 Question 77
4.3.1.3 Question 78
4.3.1.4 Question 79
4.3.1.5 Question 80
4.3.1.6 Question 81
4.4 Doric Temples
4.4.1 Exercises 26
4.4.1.1 Question 82
4.4.1.2 Question 83
4.4.1.3 Question 84
4.4.1.4 Question 85
4.4.1.5 Question 86
4.4.1.6 Question 87
4.4.1.7 Question 88
4.4.1.8 Question 89
4.5 Ionic Order
4.5.1 Exercises 27
4.5.1.1 Question 90
4.5.1.2 Question 91
4.5.1.3 Question 92
4.6 Recursion in Nature
5 State
5.1 Introduction
5.2 Randomness
5.3 Random Numbers
5.4 State
5.5 Random Choices
5.5.1 Random Fractional Numbers
5.5.2 Random Numbers within a Range
5.5.3 Exercises 28
5.5.3.1 Question 93
5.5.3.2 Question 94
5.5.3.3 Question 95
5.5.3.4 Question 96
5.5.3.5 Question 97
5.5.3.6 Question 98
5.6 Urban Planning
5.6.1 Exercises 29
5.6.1.1 Question 99
5.6.1.2 Question 100
5.6.1.3 Question 101
5.6.1.4 Question 102
5.6.1.5 Question 103
5.6.1.6 Question 104
6 Structures
6.1 Introduction
6.2 Lists
6.2.1 Pairs
6.2.2 Graphic Representation of Pairs
6.3 Recursive Types
6.4 Recursion in Lists
6.4.1 Exercises 30
6.4.1.1 Question 105
6.4.1.2 Question 106
6.4.1.3 Question 107
6.4.1.4 Question 108
6.4.1.5 Question 109
6.4.1.6 Question 110
6.4.1.7 Question 111
6.4.1.8 Question 112
6.5 Predicates on Lists
6.5.1 Exercises 31
6.5.1.1 Question 113
6.5.1.2 Question 114
6.5.1.3 Question 115
6.5.1.4 Question 116
6.5.1.5 Question 117
6.6 Enumerations
6.6.1 Exercises 32
6.6.1.1 Question 118
6.6.1.2 Question 119
6.6.1.3 Question 120
6.6.1.4 Question 121
6.6.1.5 Question 122
6.6.1.6 Question 123
6.6.1.7 Question 124
6.6.1.8 Question 125
6.6.1.9 Question 126
6.6.1.10 Question 127
6.7 Polygon
6.7.1 Regular Stars
6.7.2 Regular Polygons
6.7.3 Exercises 33
6.7.3.1 Question 128
6.7.3.2 Question 129
6.7.3.3 Question 130
6.7.3.4 Question 131
6.8 Polygonal Lines and Splines
6.8.1 Exercises 34
6.8.1.1 Question 132
6.8.1.2 Question 133
6.9 Trusses
6.9.1 Drawing of Trusses
6.9.1.1 Question 134
6.9.1.2 Question 135
6.9.1.3 Question 136
6.9.1.4 Question 137
6.9.2 Creating Positions
6.9.2.1 Question 140
6.9.2.2 Question 138
6.9.2.3 Question 139
6.9.3 Spatial Trusses
6.9.3.1 Question 141
6.9.4 Exercises 35
6.9.4.1 Question 142
6.9.4.2 Question 143
6.9.4.3 Question 144
7 Constructive Solid Geometry
7.1 Introduction
7.2 Constructive Geometry
7.2.1 Exercises 36
7.2.1.1 Question 145
7.2.1.2 Question 146
7.3 Surfaces
7.3.1 Trefoils, Quatrefoils and Other Foils
7.4 Algebra of Shapes
7.4.1 Exercises 37
7.4.1.1 Question 147
7.4.1.2 Question 148
7.4.1.3 Question 149
7.4.1.4 Question 150
7.4.1.5 Question 151
7.4.1.6 Question 152
7.4.1.7 Question 153
7.4.1.8 Question 154
7.4.1.9 Question 155
7.4.1.10 Question 156
7.4.1.11 Question 157
7.4.1.12 Question 158
7.4.1.13 Question 159
7.4.1.14 Question 160
7.4.1.15 Question 161
7.4.1.16 Question 162
7.4.1.17 Question 163
7.5 Slice of Regions
7.5.1 Exercises 38
7.5.1.1 Question 164
7.5.1.2 Question 165
7.5.1.3 Question 166
7.6 Extrusions
7.6.1 Simple Extrusion
7.6.1.1 Question 167
7.6.1.2 Question 168
7.6.1.3 Question 169
7.6.1.4 Question 170
7.6.1.5 Question 171
7.6.1.6 Question 172
7.6.1.7 Question 173
7.6.1.8 Question 174
7.6.1.9 Question 175
7.6.1.10 Question 176
7.6.1.11 Question 177
7.6.2 Extrusion Along a Path
7.6.2.1 Question 178
7.6.2.2 Question 179
7.6.3 Extrusion with Transformation
7.7 Gaudí’s Columns
7.8 Revolutions
7.8.1 Surfaces of Revolution
7.8.1.1 Question 180
7.8.1.2 Question 181
7.8.2 Solids of Revolution
7.8.2.1 Question 182
7.8.2.2 Question 183
7.8.2.3 Question 184
7.8.2.4 Question 185
7.9 Sections Interpolation
7.9.1 Interpolation by Sections
7.9.2 Interpolation with Guiding
7.9.2.1 Question 186
8 Transformations
8.1 Introduction
8.2 Translation
8.3 Scale
8.4 Rotation
8.5 Reflection
8.6 The Sydney Opera House
8.6.1 Exercises 39
8.6.1.1 Question 187
8.6.1.2 Question 188
8.6.1.3 Question 189
9 Higher-Order Functions
9.1 Introduction
9.2 Curvy Facades
9.3 Higher-Order Functions
9.4 Anonymous Functions
9.4.1 Exercises 40
9.4.1.1 Question 190
9.4.1.2 Question 191
9.4.1.3 Question 192
9.4.1.4 Question 193
9.5 Identity Function
9.5.1 Exercises 41
9.5.1.1 Question 194
9.5.1.2 Question 195
9.5.1.3 Question 196
9.5.1.4 Question 197
9.6 The Function Restriction
9.6.1 Exercises 42
9.6.1.1 Question 198
9.6.1.2 Question 199
9.6.2 Exercises 43
9.6.2.1 Question 200
9.7 The Composition Function
9.7.1 Exercises 44
9.7.1.1 Question 201
9.7.1.2 Question 202
9.7.1.3 Question 203
9.8 Higher Order Functions on Lists
9.8.1 Mapping
9.8.2 Filtering
9.8.3 Reduction
9.8.4 Exercises 45
9.8.4.1 Question 204
9.9 Generation of Three-Dimensional Models
9.9.1 Exercises 46
9.9.1.1 Question 205
9.9.1.2 Question 206
9.9.2 Exercises 47
9.9.2.1 Question 207
10 Parametric Representation
10.1 Introduction
10.2 Computation of Parametric Functions
10.3 Rounding errors
10.4 Mapping and Enumerations
10.4.1 Exercises 48
10.4.1.1 Question 208
10.4.1.2 Question 209
10.4.1.3 Question 210
10.4.2 Fermat’s Spiral
10.4.3 Cissoid of Diocles
10.4.4 Lemniscate of Bernoulli
10.4.5 Exercises 49
10.4.5.1 Question 211
10.4.6 Lamé Curve
10.4.7 Exercises 50
10.4.7.1 Question 212
10.4.7.2 Question 213
10.4.7.3 Question 214
10.4.7.4 Question 215
10.4.7.5 Question 216
10.4.7.6 Question 217
10.5 Precision
10.5.1 Adaptive Sampling
10.5.2 Exercises 51
10.5.2.1 Question 218
10.5.2.2 Question 219
10.6 Parametric Surfaces
10.6.1 The Möbius Strip
10.7 Surfaces
10.7.1 Exercises 52
10.7.1.1 Question 220
10.7.1.2 Question 221
10.7.2 Helicoid
10.7.3 Spring
10.7.4 Exercises 53
10.7.4.1 Question 222
10.7.4.2 Question 223
10.7.5 Shells
10.7.6 Cylinders, Cones, and Spheres
10.7.7 Exercises 54
10.7.7.1 Question 224
10.8 Bodegas Ysios
10.8.1 Exercises 55
10.8.1.1 Question 225
10.8.1.2 Question 226
10.8.1.3 Question 227
10.8.1.4 Question 228
10.8.1.5 Question 229
10.8.1.6 Question 230
10.8.1.7 Question 231
10.8.1.8 Question 232
10.9 Surface Normals
10.10 Surface Processing
10.10.1 Exercises 56
10.10.1.1 Question 233
10.10.1.2 Question 234
10.10.1.3 Question 235
10.10.2 Exercises 57
10.10.2.1 Question 236
10.10.2.2 Question 237
11 Epilogue
12 Operations
12.1 Types
Real
Integer
Loc
Vec
Cs
Shape
12.2 Coordinate Space
world-cs
current-cs
with-cs
12.3 Locations
xyz
cx
cy
cz
x
y
z
xy
xz
yz
+  xyz
+  x
+  y
+  z
+  xy
+  xz
+  yz
pol
pol-rho
pol-phi
+  pol
cyl
+  cyl
sph
+  sph
12.4 Vectors
vxyz
cx
cy
cz
vx
vy
vz
vxy
vxz
vyz
-vx
-vy
-vz
+  vxyz
+  vx
+  vy
+  vz
+  vxy
+  vxz
+  vyz
vpol
pol-rho
pol-phi
+  vpol
vcyl
+  vcyl
vsph
+  vsph
u-vxyz
unitize
12.5 Operations with Locations
distance
12.6 Algebraic Operations with Locations and Vectors
p-p
p+  v
v+  v
v*r
v/  r
u0
12.7 1D Modeling
point
12.8 2D Modeling
circle
surface-circle
arc
surface-arc
ellipse
line
closed-line
polygon
surface-polygon
spline
closed-spline
surface-polygon
rectangle
rectangle
surface-rectangle
surface-rectangle
regular-polygon
regular-polygon
text
text-centered
12.9 3D Modeling
box
box
cone
cone
cone-frustum
cone-frustum
cylinder
cylinder
cuboid
irregular-pyramid
regular-pyramid
regular-pyramid
regular-pyramid-frustum
regular-pyramid-frustum
regular-prism
regular-prism
right-cuboid
right-cuboid
sphere
pi
-pi
2pi
-2pi
3pi
-3pi
4pi
-4pi
pi/  2
-pi/  2
pi/  3
-pi/  3
pi/  4
-pi/  4
pi/  5
-pi/  5
pi/  6
-pi/  6
3pi/  2
-3pi/  2
12.10 Randomness
random
random-range
Index
6.3

Programming for Architecture

António Menezes Leitão

    1 Preface

    2 Introduction

      2.1 Programming Languages

        2.1.1 Exercises 1

          2.1.1.1 Question 1

          2.1.1.2 Question 2

          2.1.1.3 Question 3

      2.2 The Racket Language

        2.2.1 Syntax, Semantics and Pragmatics

        2.2.2 Syntax and Semantics of Racket

        2.2.3 The Evaluator

      2.3 Language Elements

        2.3.1 Numbers

      2.4 Combinations

        2.4.1 Indentation

        2.4.2 Exercises 2

          2.4.2.1 Question 4

          2.4.2.2 Question 5

          2.4.2.3 Question 6

          2.4.2.4 Question 7

          2.4.2.5 Question 8

          2.4.2.6 Question 9

        2.4.3 Evaluating Combinations

          2.4.3.1 Question 10

        2.4.4 Strings

      2.5 Defining Functions

        2.5.1 Exercises 3

          2.5.1.1 Question 11

      2.6 Names

        2.6.1 Exercises 4

          2.6.1.1 Question 12

          2.6.1.2 Question 13

          2.6.1.3 Question 14

          2.6.1.4 Question 15

          2.6.1.5 Question 16

          2.6.1.6 Question 17

          2.6.1.7 Question 18

      2.7 Predefined Functions

        2.7.1 Exercises 5

          2.7.1.1 Question 19

          2.7.1.2 Question 20

          2.7.1.3 Question 21

          2.7.1.4 Question 22

          2.7.1.5 Question 23

      2.8 Arithmetic in Racket

        2.8.1 Exercises 6

          2.8.1.1 Question 24

          2.8.1.2 Question 25

          2.8.1.3 Question 26

      2.9 Name Evaluation

      2.10 Conditional Expressions

        2.10.1 Logical Expressions

        2.10.2 Logical Values

      2.11 Predicates

        2.11.1 Arithmetic Predicates

      2.12 Logical Operators

        2.12.1 Exercises 7

          2.12.1.1 Question 27

      2.13 Predicates with a Variable Number of Arguments

      2.14 Recognizers

        2.14.1 Exercises 8

          2.14.1.1 Question 28

          2.14.1.2 Question 29

          2.14.1.3 Question 30

          2.14.1.4 Question 31

          2.14.1.5 Question 32

          2.14.1.6 Question 33

          2.14.1.7 Question 34

      2.15 Selection

      2.16 Multiple Selection

        2.16.1 Exercises 9

          2.16.1.1 Question 35

          2.16.1.2 Question 36

          2.16.1.3 Question 37

      2.17 Local Variables

      2.18 Global Variables

      2.19 Modules

        2.19.1 Exercises 10

          2.19.1.1 Question 38

          2.19.1.2 Question 39

          2.19.1.3 Question 40

    3 Modelling

      3.1 Coordinates

      3.2 Operations with Coordinates

        3.2.1 Exercises 11

          3.2.1.1 Question 41

          3.2.1.2 Question 42

        3.2.2 Bi-dimensional Coordinates

        3.2.3 Exercises 12

          3.2.3.1 Question 43

          3.2.3.2 Question 44

        3.2.4 Polar Coordinates

        3.2.5 Exercises 13

          3.2.5.1 Question 45

      3.3 Bi-dimensional Geometric Modelling

        3.3.1 Exercises 14

          3.3.1.1 Question 46

          3.3.1.2 Question 47

          3.3.1.3 Question 48

          3.3.1.4 Question 49

      3.4 Side Effects

      3.5 Sequencing

        3.5.1 Exercises 15

          3.5.1.1 Question 50

          3.5.1.2 Question 51

      3.6 Doric Order

      3.7 Parametrization of Geometric Figures

      3.8 Documentation

        3.8.1 Exercises 16

          3.8.1.1 Question 52

          3.8.1.2 Question 53

          3.8.1.3 Question 54

          3.8.1.4 Question 55

      3.9 Debugging

        3.9.1 Syntactic Errors

        3.9.2 Semantic Errors

      3.10 Three-dimensional Modelling

        3.10.1 Predefined Solids

        3.10.2 Exercises 17

          3.10.2.1 Question 56

          3.10.2.2 Question 57

        3.10.3 Exercises 18

          3.10.3.1 Question 58

          3.10.3.2 Question 59

          3.10.3.3 Question 60

          3.10.3.4 Question 61

          3.10.3.5 Question 62

      3.11 Cylindrical Coordinates

        3.11.1 Exercises 19

          3.11.1.1 Question 63

          3.11.1.2 Question 64

      3.12 Spherical Coordinates

        3.12.1 Exercises 20

          3.12.1.1 Question 65

          3.12.1.2 Question 66

      3.13 Modelling Doric Columns

        3.13.1 Exercises 21

          3.13.1.1 Question 67

      3.14 Vitruvian Proportions

        3.14.1 Exercises 22

          3.14.1.1 Question 68

    4 Recursion

      4.1 Introduction

        4.1.1 Exercises 23

          4.1.1.1 Question 69

          4.1.1.2 Question 70

      4.2 Recursion in Architecture

        4.2.1 Exercises 24

          4.2.1.1 Question 71

          4.2.1.2 Question 72

          4.2.1.3 Question 73

          4.2.1.4 Question 74

          4.2.1.5 Question 75

      4.3 Debugging Recursive Programs

        4.3.1 Exercises 25

          4.3.1.1 Question 76

          4.3.1.2 Question 77

          4.3.1.3 Question 78

          4.3.1.4 Question 79

          4.3.1.5 Question 80

          4.3.1.6 Question 81

      4.4 Doric Temples

        4.4.1 Exercises 26

          4.4.1.1 Question 82

          4.4.1.2 Question 83

          4.4.1.3 Question 84

          4.4.1.4 Question 85

          4.4.1.5 Question 86

          4.4.1.6 Question 87

          4.4.1.7 Question 88

          4.4.1.8 Question 89

      4.5 Ionic Order

        4.5.1 Exercises 27

          4.5.1.1 Question 90

          4.5.1.2 Question 91

          4.5.1.3 Question 92

      4.6 Recursion in Nature

    5 State

      5.1 Introduction

      5.2 Randomness

      5.3 Random Numbers

      5.4 State

      5.5 Random Choices

        5.5.1 Random Fractional Numbers

        5.5.2 Random Numbers within a Range

        5.5.3 Exercises 28

          5.5.3.1 Question 93

          5.5.3.2 Question 94

          5.5.3.3 Question 95

          5.5.3.4 Question 96

          5.5.3.5 Question 97

          5.5.3.6 Question 98

      5.6 Urban Planning

        5.6.1 Exercises 29

          5.6.1.1 Question 99

          5.6.1.2 Question 100

          5.6.1.3 Question 101

          5.6.1.4 Question 102

          5.6.1.5 Question 103

          5.6.1.6 Question 104

    6 Structures

      6.1 Introduction

      6.2 Lists

        6.2.1 Pairs

        6.2.2 Graphic Representation of Pairs

      6.3 Recursive Types

      6.4 Recursion in Lists

        6.4.1 Exercises 30

          6.4.1.1 Question 105

          6.4.1.2 Question 106

          6.4.1.3 Question 107

          6.4.1.4 Question 108

          6.4.1.5 Question 109

          6.4.1.6 Question 110

          6.4.1.7 Question 111

          6.4.1.8 Question 112

      6.5 Predicates on Lists

        6.5.1 Exercises 31

          6.5.1.1 Question 113

          6.5.1.2 Question 114

          6.5.1.3 Question 115

          6.5.1.4 Question 116

          6.5.1.5 Question 117

      6.6 Enumerations

        6.6.1 Exercises 32

          6.6.1.1 Question 118

          6.6.1.2 Question 119

          6.6.1.3 Question 120

          6.6.1.4 Question 121

          6.6.1.5 Question 122

          6.6.1.6 Question 123

          6.6.1.7 Question 124

          6.6.1.8 Question 125

          6.6.1.9 Question 126

          6.6.1.10 Question 127

      6.7 Polygon

        6.7.1 Regular Stars

        6.7.2 Regular Polygons

        6.7.3 Exercises 33

          6.7.3.1 Question 128

          6.7.3.2 Question 129

          6.7.3.3 Question 130

          6.7.3.4 Question 131

      6.8 Polygonal Lines and Splines

        6.8.1 Exercises 34

          6.8.1.1 Question 132

          6.8.1.2 Question 133

      6.9 Trusses

        6.9.1 Drawing of Trusses

          6.9.1.1 Question 134

          6.9.1.2 Question 135

          6.9.1.3 Question 136

          6.9.1.4 Question 137

        6.9.2 Creating Positions

          6.9.2.1 Question 140

          6.9.2.2 Question 138

          6.9.2.3 Question 139

        6.9.3 Spatial Trusses

          6.9.3.1 Question 141

        6.9.4 Exercises 35

          6.9.4.1 Question 142

          6.9.4.2 Question 143

          6.9.4.3 Question 144

    7 Constructive Solid Geometry

      7.1 Introduction

      7.2 Constructive Geometry

        7.2.1 Exercises 36

          7.2.1.1 Question 145

          7.2.1.2 Question 146

      7.3 Surfaces

        7.3.1 Trefoils, Quatrefoils and Other Foils

      7.4 Algebra of Shapes

        7.4.1 Exercises 37

          7.4.1.1 Question 147

          7.4.1.2 Question 148

          7.4.1.3 Question 149

          7.4.1.4 Question 150

          7.4.1.5 Question 151

          7.4.1.6 Question 152

          7.4.1.7 Question 153

          7.4.1.8 Question 154

          7.4.1.9 Question 155

          7.4.1.10 Question 156

          7.4.1.11 Question 157

          7.4.1.12 Question 158

          7.4.1.13 Question 159

          7.4.1.14 Question 160

          7.4.1.15 Question 161

          7.4.1.16 Question 162

          7.4.1.17 Question 163

      7.5 Slice of Regions

        7.5.1 Exercises 38

          7.5.1.1 Question 164

          7.5.1.2 Question 165

          7.5.1.3 Question 166

      7.6 Extrusions

        7.6.1 Simple Extrusion

          7.6.1.1 Question 167

          7.6.1.2 Question 168

          7.6.1.3 Question 169

          7.6.1.4 Question 170

          7.6.1.5 Question 171

          7.6.1.6 Question 172

          7.6.1.7 Question 173

          7.6.1.8 Question 174

          7.6.1.9 Question 175

          7.6.1.10 Question 176

          7.6.1.11 Question 177

        7.6.2 Extrusion Along a Path

          7.6.2.1 Question 178

          7.6.2.2 Question 179

        7.6.3 Extrusion with Transformation

      7.7 Gaudí’s Columns

      7.8 Revolutions

        7.8.1 Surfaces of Revolution

          7.8.1.1 Question 180

          7.8.1.2 Question 181

        7.8.2 Solids of Revolution

          7.8.2.1 Question 182

          7.8.2.2 Question 183

          7.8.2.3 Question 184

          7.8.2.4 Question 185

      7.9 Sections Interpolation

        7.9.1 Interpolation by Sections

        7.9.2 Interpolation with Guiding

          7.9.2.1 Question 186

    8 Transformations

      8.1 Introduction

      8.2 Translation

      8.3 Scale

      8.4 Rotation

      8.5 Reflection

      8.6 The Sydney Opera House

        8.6.1 Exercises 39

          8.6.1.1 Question 187

          8.6.1.2 Question 188

          8.6.1.3 Question 189

    9 Higher-Order Functions

      9.1 Introduction

      9.2 Curvy Facades

      9.3 Higher-Order Functions

      9.4 Anonymous Functions

        9.4.1 Exercises 40

          9.4.1.1 Question 190

          9.4.1.2 Question 191

          9.4.1.3 Question 192

          9.4.1.4 Question 193

      9.5 Identity Function

        9.5.1 Exercises 41

          9.5.1.1 Question 194

          9.5.1.2 Question 195

          9.5.1.3 Question 196

          9.5.1.4 Question 197

      9.6 The Function Restriction

        9.6.1 Exercises 42

          9.6.1.1 Question 198

          9.6.1.2 Question 199

        9.6.2 Exercises 43

          9.6.2.1 Question 200

      9.7 The Composition Function

        9.7.1 Exercises 44

          9.7.1.1 Question 201

          9.7.1.2 Question 202

          9.7.1.3 Question 203

      9.8 Higher Order Functions on Lists

        9.8.1 Mapping

        9.8.2 Filtering

        9.8.3 Reduction

        9.8.4 Exercises 45

          9.8.4.1 Question 204

      9.9 Generation of Three-Dimensional Models

        9.9.1 Exercises 46

          9.9.1.1 Question 205

          9.9.1.2 Question 206

        9.9.2 Exercises 47

          9.9.2.1 Question 207

    10 Parametric Representation

      10.1 Introduction

      10.2 Computation of Parametric Functions

      10.3 Rounding errors

      10.4 Mapping and Enumerations

        10.4.1 Exercises 48

          10.4.1.1 Question 208

          10.4.1.2 Question 209

          10.4.1.3 Question 210

        10.4.2 Fermat’s Spiral

        10.4.3 Cissoid of Diocles

        10.4.4 Lemniscate of Bernoulli

        10.4.5 Exercises 49

          10.4.5.1 Question 211

        10.4.6 Lamé Curve

        10.4.7 Exercises 50

          10.4.7.1 Question 212

          10.4.7.2 Question 213

          10.4.7.3 Question 214

          10.4.7.4 Question 215

          10.4.7.5 Question 216

          10.4.7.6 Question 217

      10.5 Precision

        10.5.1 Adaptive Sampling

        10.5.2 Exercises 51

          10.5.2.1 Question 218

          10.5.2.2 Question 219

      10.6 Parametric Surfaces

        10.6.1 The Möbius Strip

      10.7 Surfaces

        10.7.1 Exercises 52

          10.7.1.1 Question 220

          10.7.1.2 Question 221

        10.7.2 Helicoid

        10.7.3 Spring

        10.7.4 Exercises 53

          10.7.4.1 Question 222

          10.7.4.2 Question 223

        10.7.5 Shells

        10.7.6 Cylinders, Cones, and Spheres

        10.7.7 Exercises 54

          10.7.7.1 Question 224

      10.8 Bodegas Ysios

        10.8.1 Exercises 55

          10.8.1.1 Question 225

          10.8.1.2 Question 226

          10.8.1.3 Question 227

          10.8.1.4 Question 228

          10.8.1.5 Question 229

          10.8.1.6 Question 230

          10.8.1.7 Question 231

          10.8.1.8 Question 232

      10.9 Surface Normals

      10.10 Surface Processing

        10.10.1 Exercises 56

          10.10.1.1 Question 233

          10.10.1.2 Question 234

          10.10.1.3 Question 235

        10.10.2 Exercises 57

          10.10.2.1 Question 236

          10.10.2.2 Question 237

    11 Epilogue

    12 Operations

      12.1 Types

      12.2 Coordinate Space

      12.3 Locations

      12.4 Vectors

      12.5 Operations with Locations

      12.6 Algebraic Operations with Locations and Vectors

      12.7 1D Modeling

      12.8 2D Modeling

      12.9 3D Modeling

      12.10 Randomness

    Index

1 Preface

This book was born in 2007, after an invitation to teach an introductory programming course to the students of Architecture at Instituto Superior Técnico (IST). The original motivation for the introduction of this course was the same as for several other courses: similar to Mathematics and Physics, Programming is now one of the fundamental courses that constitute the basic education of any IST student.

With this premise, it did not seem to be a subject that would entice the student’s interest, particularly since it was not very clear the contribution it could have to the course. To contradict that first impression, I decided to include in the course’s syllabus some applications of Programming in Architecture. In that sense, I had a conversation with several architectural students and teachers and asked them to explain to me what they did and how they did it. What I heard and saw was revealing.

Despite the enormous progresses that Computer-Aided-Design (CAD) brought to the profession, the truth is that its use continuous to be manual, laborious, repetitive and boring. The creation of a digital model in a CAD tool requires extreme attention to detail, distracting from what is fundamental: the idea. Frequently, the obstacles found end up forcing the Architect to simplify the original idea. Unfortunately, those obstacles do not end with the creation of the model. On the contrary, they become aggravated when the inevitable changes need to be made to the model.

In general, CAD tools are conceived to make the most common tasks easier, in detriment of other less common or sophisticated tasks. In fact, to an Architect interested in modelling more complex shapes, the CAD tool used can raise several limitations. However, those limitations are only deceptions since they can be overcome with the aid of programming. Programming allows a CAD tool to be amplified with new capabilities, thus eliminating the obstacles that restrict the work of the Architect.

The programming practice is intellectually very stimulating but it is also a challenge. It implies the need to master a new language, it implies a new way of thinking. Frequently, that effort makes several people give up but to the ones that prevail in overcoming the initial difficulties, they acquire the skill to go further in the creation of innovative architectural solutions.

This books aims to meet those Architects.

2 Introduction

Knowledge transmission is one of the issues that has worried mankind throughout the ages. As man is able to accumulate knowledge throughout his life, it would be unfortunate if all that knowledge disappeared with his death.

To avoid this loss, mankind invented a series of mechanisms to preserve knowledge. Firstly, oral transmission, consisting in the transmission of knowledge from one person to a small group of people, in a way transferring the problem of knowledge preservation to the next generation. Secondly, written transmission, consisting in documenting knowledge. On one hand, this approach has the great advantage of reaching out to a much larger group of people. On the other hand, it significantly reduces the loss of knowledge due to transmission problems. In fact, the written word allows to preserve knowledge for long periods of time and without the inevitable changes that occur on a long chain of oral transmissions.

It is thanks to the written word that mankind can understand and accumulate vast amounts of knowledge, some of it dating back to thousands of years. Unfortunately, the written word has not always been able to accurately transmit what the author had in mind: the natural language is ambiguous and it evolves with time, making the interpretation of written texts a subjective task. Whether when we write a text or when we read, or interpret one, there are omissions, imprecisions, errors, and ambiguities which can turn the knowledge transmission fallible. If the transmitted knowledge is simple, the receptor will most likely have enough culture and imagination to understand it. For the transmission of more complex knowledge, however,that might be much more difficult to do.

When rigour in the transmission of knowledge is needed, relying on the receptor’s abilities to understand it can have disastrous outcomes and, in fact, throughout history we can find many catastrophic events caused solely by insufficient or incorrect transmission of knowledge.

To avoid these problems, more accurate languages were developed. Mathematics, in particular, has for the past millenia obsessively sought to construct a language that shines for its absolute rigour. This allows knowledge transmission to be much more accurate than in other areas, reducing to the bare minimum the need for imagination in order to understand that knowledge.

To better understand this problem, let us consider one concrete example of knowledge transmission: the calculus of the factorial of a number. If we assume that the person, to whom we want to transmit that knowledge, knows beforehand about numbers and arithmetic operations, we could tell him that, to calculate the factorial of any number, one must multiply every number from one until that number. Unfortunately, that description is too long, and worse yet, inaccurate, because it does not state that only integer numbers are to be multiplied. To avoid these imprecisions and simultaneously make the information more compact, Mathematics developed a set of symbols and concepts that should be understood by everyone. For example, to define the integer sequence of numbers between \(1\) and \(9\), mathematics allows us to write \(1,2,3,\ldots,9\). In the same manner, instead of referring to "any number" mathematics invented the concept of "variable": a name that refers to some "thing" that can be used in several parts of a mathematical statement, always representing the same "thing". That way, Mathematics allows us to more accurately express the factorial computation as follows:

\[n! = 1\times 2\times 3\times \cdots{} \times n\]

But is this definition rigorous enough? Is it possible to interpret it without requiring imagination to figure the author’s intention? Apparently, it is but there is a detail in this definition that requires imagination: the ellipses. The ellipses indicate that the the reader must imagine what should be in its place. Although most readers will correctly understand that the author meant the multiplication of the sequential numbers, some might think to replace the ellipsis with something else.

Even if we exclude this last group of people from our target audience, there are still other problems with the previous definition. Let us imagine, for example, the factorial of \(2\). What is its value? If we use \[n = 2\] in the formula, we get:

\[2! = 1\times 2\times 3\times \cdots{} \times 2\]

In this case, the computation makes no sense, which shows that, in fact, imagination is need for more than just on how to fill in the ellipsis: the number of terms to consider depends on the number to which we want to calculate the factorial.

Assuming that our reader has enough imagination to figure out this particular detail, he would easily calculate that \(2!=1\times 2=2\). But even then, there will be cases where it is not that clear. For example, what is the factorial of zero? The answer does not appear to be obvious. What about the factorial of \(-1\)? Again, it is not clear. And the factorial of \(4.5\)?. Once again the formula says nothing regarding these situations and our imagination can not guess the correct procedure.

Would it be possible to find a way of transmitting the knowledge required to compute the factorial function that minimizes imprecisions, gaps, and ambiguities? Let us try the following variation of the definition of the factorial function:

\[n!= \begin{cases} 1, & \text{if $n=0$}\\ n \cdot (n-1)!, & \text{if $n\in \mathbb{N}$.} \end{cases}\]

Have we reached the necessary rigour that requires no imagination on the reader’s part? One way to find out is with the previous cases that gave us problems. Fist of all, there are no ellipsis, which is positive. Secondly, for the factorial of the number \(2\) we will have that:

\[2!=2\times 1!=2\times (1\times 0!)=2\times (1\times 1)=2\times 1=2\]

which means that there is no ambiguity. Finally, we can see that it makes no sense trying to determine the factorial value of \(-1\) or \(4.5\) because this function can only be applied to \(\mathbb{N}_0\) members}.

This example shows that, even in mathematics, there are different levels of rigour in the different ways that is possible to transmit knowledge. Some require more imagination than others but in general they have been enough for Mankind to preserve knowledge throughout history.

It so happens that nowadays Mankind has a partner that has been giving a huge contribution to its progress: the computer. This machine has the extraordinary capability of instructed on how to execute a complex set of tasks. Programming is essentially all about transmitting to a computer the knowledge needed to solve a specific problem. This knowledge is called a program. Because they are programable, computers have been used for the most diversified ends, and in the last decades they have radically changed the way we work. Unfortunately, the computer’s extraordinary ability to learn comes with an equal extraordinary lack of imagination. A computer does assume or imagine, it just rigorously interprets the knowledge transmitted in the form of a program.

Since it has no imagination the computer depends critically on the way we present it the knowledge that we wish to transmit: that knowledge must be described in such a way that no ambiguity, gaps or imprecision. A language with these characteristics is generally called a programming language.

2.1 Programming Languages

For a computer to be able to solve a problem it is necessary to describe the process of solving a problem in a language that it understands. Unfortunately, the language that a computer "innately" understands is extremely poor, making the description of how to solve a non-trivial problem a very exhausting, tedious and complex one. The countless programming languages that have been invented aim at lighting the programmer’s burden, by introducing linguistic elements capable of simplifying those descriptions. For example the concept of function, sum, matrix or rational number do not exist natively in computers but many programming languages allow their usage in order to simplify the description of scientific calculus. Naturally, there must be a process that is able to transform the programmer’s descriptions into instructions that computers can understand. Although this process is relatively complex what matters is that it allows us to have programming languages that operate closer to human thinking process rather than the computer’s.

This last fact is of extreme importance because it allows us to use programming languages not only to instruct a computer on how to solve a problem, but also to explain that process accurately to another human being. This way, programming languages become a way of transmitting knowledge as mathematics has been for the last thousands of years.

There is a huge amount of programming languages, some better equipped than others to solve specific problems. The choice of a programming language should therefore depend heavily on the type of the problems we wish to solve but it should not be a total commitment. For a programmer it is much more important to understand the fundamentals and techniques of programming than to master this or that language. However, to better understand these fundamentals, it’s convenient to exemplify them in a concrete programming language.

As the focus of this document will be on programming for Architecture, we will use a programming language that is geared towards solving geometrical problems. There are many languages that serve this purpose, most commonly associated with computed aided design tools - Computer Aided Design (CAD). ArchiCAD, for instance, offers a programming language called GDL, an acronym for Geometric Description Language that enables users to program multiple geometric forms. In the case of AutoCAD that language used is called AutoLisp, a dialect of a famous programming language called Lisp. A third option will be the RhinoScript language, available for Rhinoceros. Despite these languages seeming very different from each other, the concepts behind them are very similar. It is on these concepts that we will be leaning on, although for pedagogical reasons, it is convenient to particularize them in a single language.

Unfortunately GDL, AutoLisp, and RhinoScript were developed a long time ago and they have not been updated, possessing many archaic characteristics that makes them harder to learn and use. In order to make the learning process easier and, simultaneously allowing our programs to run in different CAD environments, we are going to use a new language called Racket, that has was purposely adapted for programming in Architecture. In this text we will explain the fundamentals of programming using Racket, not just because its easier to learn, but also for it’s practical applicability. However, once learned, the reader should be able to apply these fundamentals to any other programming language.

In order to facilitate the programmer’s task, Racket is equipped with a programming environment called DrRacket, that offers a text editor adapted to edit Racket’s programs, as well as a set of additional tools for error detection and debugging. This programming environment is shared with a freeware license and it is available at:

2.1.1 Exercises 1
2.1.1.1 Question 1

Exponentiation \(b^n\)is an operation between two numbers \(b\) and \(n\). When \(n\) is a positive integer, exponentiation is defined as:

\[b^n = \underbrace{b \times b \times \cdots \times b}_n\]

To a reader not familiarized with exponentiation, the previous definition raises several questions that may not be evident: how many multiplications should actually be done?,\(n\)?, \(n-1\)? What if \(b=1\)? or \(b=0\)? Propose a definition for the exponentiation function in order to clear any doubts.

2.1.1.2 Question 2

What is a program and what purpose does it serve?

2.1.1.3 Question 3

What is a programming language and what purpose does it serve?

2.2 The Racket Language

In this section we will learn about Racket programming language, which we will use throughout this text. But first, we are going to examine some aspects that are common to other languages.

2.2.1 Syntax, Semantics and Pragmatics

Every language has syntax, semantics, and pragmatics.

In simple terms, syntax is a set of rules that dictate the kind of sentence that can be written in that language. Without it, any concatenation of words could be a sentence. For example, given the words “John”, “cake”, “ate”, “the” the syntax rules of the English language tell us that - “John ate the cake” is a correct sentence, and that - “ate the Jonh cake” is not. Note that according to the English syntax, "The cake ate John" is also syntactically correct.

Syntax dictates how a sentence is constructed but says nothing in regards to its meaning. Semantics are what attributes meaning to a sentence, thus telling us that “The cake ate John” makes no sense.

Finally, pragmatics sets the way sentences are commonly expressed. In a language, pragmatic changes depending on the context: the way two close friends talk with each other is different from the way two strangers talk.

These three aspects of a language are also present when we discuss programming languages. Unlike the natural languages we use to communicate between us, programming languages are characterized as being formal, obeying a set of simple and restrictive rules that can be mechanically processed.

In this document we will describe Racket’s syntax and semantics and, although there are mathematical formalisms to describe rigorously those two aspects, they require a mathematical sophistication that, given the nature of this work, is inappropriate. So we will only use informal descriptions. Afterwards, as we introduce language elements, we will discuss language pragmatics’.

2.2.2 Syntax and Semantics of Racket

When compared to other programming languages, Racket’s syntax is extraordinary simple and is based on the concept of expressions.

An expression in Racket can be formed using primitive elements such as numbers; or by the combination of those elements such as the sum of two numbers. This simple definition allows us to build expressions of arbitrary complexity. However, it is important to remember that syntax restricts what can be written: the fact that we can combine expressions to create more complex ones, that does not mean we can write any combination of sub-expressions. These combinations are restricted by syntactic rules that we will describe throughout this text.

Much like the syntax, Racket’s semantics is also very simple when compared to other programming languages. As we will see, semantics is determined by the operators that are used in our expressions. For instance, the sum operator, is used to add two numbers. An expression that combines this operator with, for example, the numbers \(3\) and \(4\) will have as its meaning the sum between \(3\) and \(4\), i.e., \(7\). In a programming language, the semantics’ of an expression is given by the computer that will evaluate the expression.

2.2.3 The Evaluator

Every expression in Racket has a value. This concept is so important that Racket provides an evaluator, i.e., a program designed to interact with the user in order to evaluate expressions defined by the user.

In Racket, the evaluator is shown as soon as we start working the DrRacket environment, and it is possible to easily change between the editor and the evaluator at any time. Once DrRacket is running, the user is presented with the character > (called prompt), meaning that Racket is waiting for the user to input an expression.

The character ">" is Racket’s "prompt", in front of which the user’s expressions will be shown. Racket interacts with the user by executing a cycle that reads an expressions, determines its value and writes the result. This cycle is traditionally called read-eval-print-loop (abbreviated to REPL).

During the read phase, Racket reads an expression and creates an internal object that represents it. In the evaluation phase, that object is analysed in order to produce a value. This analysis uses rules that dictate, for each case, the object’s value. Finally, the result is given back in text form to the user in the print phase.

Given the existence of the read-eval-print-loop process, in Racket it is not necessary to instruct that computer to explicitly print the result of an expression, meaning that testing and debugging is significantly easy. The advantage of Racket being an interactive language is that it allows programs to be quickly developed by writing, testing and correcting small fragments at a time.

2.3 Language Elements

In every programming language we have to deal with two sets of objects: data and procedures. Data comprise all the entities that we wish to manipulate. Procedures designate the rules on how to manipulate that data.

In Mathematics, we can look at numbers as the data and algebraic operations as the procedures. These operations allows us to combine numbers. For example, \(2\times 2\) is a combination. Another combination involving more data is \(2\times 2\times 2\), and using even more data \(2\times 2\times 2\times 2\). However, unless we want to spend time solving problems of elementary arithmetic, we should consider more elaborate operations that represent calculation patterns. In the previous sequence of combinations shown, it is clear that the pattern that is emerging is the definition of exponentiation, which has been defined in Mathematics a long time ago. Exponentiation is therefore an abstraction of a succession of multiplications.

As in Mathematics, a programming language should contain primitive data and procedures, it should be capable of combining data and procedures to create more complex data and procedures and it should be able to abstract calculation patterns and allow them to be used as simple operations, defining new operations that represent those patterns.

Further ahead we are going to see how it is possible to define these abstractions in Racket. But for now, let us take a closer look at the primitive elements of the language, i.e., the most simple entities that the language deals with.

2.3.1 Numbers

As said previously, Racket executes a read-eval-print cycle. This implies that everything we write in Racket must be evaluated, i.e., everything must have a value that Racket displays on the screen.

That way, if we give the evaluator a number it will return the value of that number. How much is the value of a number? At best we can say it has its own value. For example, the value of 1 is 1.

> 1

1

> 12345

12345

> 1/2

1/2

> 1+2i

1+2i

> 4.5

4.5

In Racket, numbers can be exact or inexact. Exact numbers include integers, fractions and complex numbers with integer parts. Inexact numbers are all others, being typically written in decimal or scientific notation).

2.4 Combinations

A combination is an expression that describes the application of an operator to its operands. In Mathematics, numbers can be combined using operations like the sum or multiplication; e.g. \(1 + 2\) and \(1 + 2 \times 3\). The sum and multiplication of numbers are but two of the extremely primitive procedures provided by Racket.

In Racket, a combination can be created by writing a sequence of expressions inside a pair of parentheses. An expression is a primitive element or another combination. The expression (+ 1 2) is a combination of two primitive elements 1 and 2 through the primitive procedure +. In the case of (+ 1 (* 2 3)) the combination is between \(1\) and (* 2 3) (this last expression is also a combination). Note that each expression must be separated from the rest using at least one space. Despite the combination (* 2 3) having three expressions - *, 2 and 3, the combination (*2 3) only has two - *2 and 3, in which the first expression has no predefined meaning.

For now, the only useful combinations are those in which expressions have meaning as operators and operands. Conventionally, Racket considers the first element of the combination the operator and the rest its operands.

The notation Racket uses to build expressions (the operator first and then the operands) is called prefix notation. This form of notation can cause some perplexity to new users of this language since most of them expect a notation closer to that taught in arithmetic and which is usually used in other programming languages. The expression (+ 1 (* 2 3)) is normally written 1 + 2 * 3 (designated infix notation, operator between operands), and usually this is easier for a human being to read. However, the prefix notation used by Racket has advantages over the infix notation:

Besides the infix and prefix notations, there is also the postfix notation in which the operator comes after the operands. This notation has the same properties as the prefix notation but it is, in general, more difficult to read since it is necessary to read every operand before we are able to understand what should be done with them.

2.4.1 Indentation

The disadvantage of the prefix notation is the writing of complex combinations. The expression 1+2*3-4/5*6 is easy to read but when written using Racket’s syntax, (- (+ 1 (* 2 3)) (* (/ 4 5) 6)), it has a form that for those not yet accustomed to this syntax can be harder to read due to the large number of parentheses.

To make the expression easier to read, we can (and we should) use indentation. This technique is based on using different alignments in the textual disposition of programs in order to make them easier to read. This way, instead of writing our expressions in a single line or with an arbitrary line arrangement, we write them throughout several lines and with an alignment between lines that shows how the sub-expressions are related to the expression that contains them.

The rule for indentation in Racket is extremely simple: in one line we have the operator and the first operand, the remaining operands are placed immediately below the first on, with enough blank spaces on the left so they are correctly aligned. If the case of a short expression, we can write it in a single line, with the operands immediately after the operator, using a single blank space to separate them. Using these two rules, we can rewrite the previous expression in the following manner:

(- (+ 1
      (* 2 3))
   (* (/ 4 5)
      6))

Note that arranging a combination in several lines does not affect the way Racket reads it. The correct delimitation of elements in a combination is done only by the visual separation and the correct usage of stacked parenthesis.

When the indentation rule is not enough to produce an aesthetically pleasing disposition of text lines, some minor variations may be used, such as placing the operator in a line and the operands underneath it, like in the following example:

(an-operator-with-a-very-very-very-big-name
  1 2 3 4)

Generally, we might need to apply several rules simultaneously:

(an-operator (an-operator-with-a-very-very-very-big-name
               1 2 3 4)
             (another-operator 5
                               6
                               (and-another 7
                                            8))
             (and-the-last-one 9 10))

Some operators have a proper indentation rule but this will be explained as we introduce them.

Indentation is crucial in Racket because it makes it easier to write and read complex code. Most editors that recognize Racket’s language automatically format the programs as we write them, also showing the correct matching between parenthesis. Eventually with practice, it becomes every easy to write and read programs, regardless how complex their structure is.

2.4.2 Exercises 2
2.4.2.1 Question 4

Define REPL?

2.4.2.2 Question 5

What is the difference between prefix an infix notation?

2.4.2.3 Question 6

In Mathematics it is usual to use simultaneously the prefix, infix and postfix notations. Write some mathematical examples of expressions that make use of those different notations.

2.4.2.4 Question 7

Convert the following arithmetic infix expressions to Racket’s prefix notation:
  1. \(1 + 2 - 3\)

  2. \(1 - 2 \times 3\)

  3. \(1 \times 2 - 3\)

  4. \(1 \times 2 \times 3\)

  5. \((1 - 2) \times 3\)

  6. \((1 - 2) + 3\)

  7. \(1 - (2 + 3)\)

  8. \(2 \times 2 + 3 \times 3 \times 3\)

2.4.2.5 Question 8

Convert the following Racket prefix notation expressions into arithmetic infix ones:
  1. (* (/ 1 2) 3)

  2. (* 1 (- 2 3))

  3. (/ (+ 1 2) 3)

  4. (/ (/ 1 2) 3)

  5. (/ 1 (/ 2 3))

  6. (- (- 1 2) 3)

  7. (- 1 2 3)

2.4.2.6 Question 9

Use indentation to rewrite the following expression, so that there is only a single operand per line.

(* (+ (/ 3 2) (- (* (/ 5 2) 3) 1) (- 3 2)) 2)

2.4.3 Evaluating Combinations

As we have seen, Racket considers the first element of a combination its operator and the rest the operands.

The evaluator determines the combination’s value by applying the procedure specified by the user to the value of the operands. The value of an operand is designated as the argument of the procedure. The value of the combination (+ 1 (* 2 3)) is the result of adding the value of 1 to (* 2 3). As we have already seen, the value of 1 is \(1\) and (* 2 3) is a combination whose value is the result of multiplying 2 by 3, which is \(6\). Finally, by summing \(1\) with \(6\) we get \(7\).

> (* 2 3)

6

> (+ 1 (* 2 3))

7

2.4.3.1 Question 10

Calculate the value of the following Racket expressions:

  1. (* (/ 1 2) 3)

  2. (* 1 (- 2 3))

  3. (/ (+ 1 2) 3)

  4. (- (- 1 2) 3)

  5. (- 1 2 3)

  6. (- 1)

2.4.4 Strings

Chains of characters (also called Strings) are another type of primitive data. A character is a letter, a digit or any kind of graphic symbols, including non-visible graphic symbols like blank spaces, tabs and others. A string is specified by a character sequence between quotations marks. Just like with numbers, the value of a string is the string itself:

> "Hi"

"Hi"

> "I am my own value"

"I am my own value"

Since a string is delimited by quotation marks, one could ask how can we create a string that contains quotation marks. For this and other special characters, there is a special character that Racket interprets differently: when in a strings the character \ appears it tells Racket that the next characters must be evaluated in a special way. For example, to create the following string:

John said "Good morning!" to Peter.

We must write:

"John said \"Good morning!\" to Peter."

Some valid escape characters in Racket.

Sequence

 

Result

\\

 

the character \ (backslash)

\"

 

the character " (quotation marks)

\e

 

the character escape

\n

 

new line character (newline)

\r

 

new line character (carriage return)

\t

 

tab character (tab)

The character \ is called an escape character and allows the inclusion of characters in strings that would otherwise be difficult to input. this table) shows examples of other escape characters.

As it happens with numbers, there are countless operators to manipulate strings. For example, to concatenate multiple strings there is the string-append operator. The concatenation of several strings produces a single string with all characters of those strings, in the same order:

> (string-append "1" "2")

"12"

> (string-append "one" "two" "three" "four")

"onetwothreefour"

> (string-append "I" " " "am" " " "a" " " "string")

"I am a string"

> (string-append "And I" " am " "another")

"And I am another"

To know how many characters there are in a string we have the string-length operator:

> (string-length "I am string")

11

> (string-length "")

0

Note that quotation marks define strings’ boundaries and are not consider characters. Besides strings and numbers, Racket has other kinds of primitive elements that will be addressed later.

2.5 Defining Functions

In addition to basic arithmetic operations, Mathematics offers a large set of operations that are defined based on those basic ones. For example, the square of a number is an operation (also designated as a function) that, given a number, calculates the multiplication of that number by itself. This function has the following mathematical definition \(x^2 = x \cdot x\).

Like in Mathematics, it is possible to define the square function in a programming language. In Racket, to obtain the square of a number, for example 5, we write the combination (* 5 5). In general, given a number x, we know to obtain the square value by writing (* x x) combination. All that remains now is to associate a name indicating that, given a number x, we obtain its square by evaluating (* x x). Racket allows us to do that by using the define operation:

(define (square x) (* x x))

As you can see from the square function definition, in order to define a function in Racket, we need to combine three elements. The first element is the word define, that informs the evaluator that we are defining a function. The second element is a combination with the function’s name and its parameters. The third element is the expression that will compute the function value for those parameters. In generic terms we could say that the definition of functions is done in the following manner:

(define (name parameter1 ... parametern)
  body)

The function’s parameters are called formal parameters and they are used in the body of an expression to refer to the correspondent arguments. When we write in the evaluator (square 5), the number 5 is the formal parameter. During the calculation this argument is associated with the number x. The arguments of a function are also called actual parameters.

The definition of the square function declares that in order to determine the square of a number x, we should multiply that number by itself (* x x). This definition associates the word square with a procedure, i.e., a description on how to obtain the desired result. Note that this procedure has parameters allowing it to use different arguments. For example, let’s evaluate the following expressions:

> (square 5)

25

> (square 6)

36

The rule to evaluate combinations stated above is also valid for functions defined by the user. The evaluation of the expression (square (+ 1 2)) first evaluates (+ 1 2) operand. This value of this operand, \(3\), is used by the function in place of x. The function’s body is then evaluated and all occurrences of x will be replaced by the value 3, i.e., the final value will b e the combination (* 3 3).

Formally, in order to invoke a function, is necessary to construct a combination in which the first element is an expression that evaluates for the function itself, and the remaining elements are expressions that evaluate for the arguments that the function is supposed to use. The result of the combination’s evaluation is the value calculated by the function for those arguments.

The process of evaluating a combination is done by the following steps:

  1. All elements in a combination are evaluated, with the value of the first one being necessarily a function.

  2. The formal parameters are associated with the function’s arguments, i.e., the value of the remaining elements of that combination. Each parameter is associated to an argument, according to the order of parameters and arguments. An error occurs when the number of parameters and arguments is different.

  3. The function’s body is evaluated keeping in mind these associations between parameters and arguments.

To better understand this process, it is useful to decompose it in its most elementary steps. The following example shows the process of evaluating the expression \(((1+2)^2)^2\) step by step:

(square (square (+ 1 2)))
\(\downarrow\)
(square (square 3))
\(\downarrow\)
(square (* 3 3))
\(\downarrow\)
(square 9)
\(\downarrow\)
(* 9 9)
\(\downarrow\)
81

Every function created by the user is evaluated by Racket in equal terms as other predefined function. This allows them to be used to create new functions. For example, after defining the square function, we can define the function that calculates the area of a circle with radius \(r\), using the formula \(\pi * r^2\):

(define (circle-area radius)
  (* pi (square radius)))

Naturally, during the evaluation of the expression used to compute the area of a circle, the square function will be invoked. This is visible in the following evaluation sequence:

(circle-area 2)
\(\downarrow\)
(* pi (square 2))
\(\downarrow\)
(* 3.14159 (square 2))
\(\downarrow\)
(* 3.14159 (* 2 2))
\(\downarrow\)
(* 3.14159 4)
\(\downarrow\)
12.5664

Since defining functions allows for associations to be established between a procedure and a name, that means Racket needs to have memory in which to store those associations. This memory is called environment.

Note that this environment exists only while we are working. When the program is shut down, that environment is lost. In order to avoid losing those definitions, they should be saved as in a file. This is the reason why the process of working in Racket is based on writing the definitions in files although still needing to test them using the evaluator to ensure the proper behaviour of the created definitions.

2.5.1 Exercises 3
2.5.1.1 Question 11

Define the function double, that calculates the double of a given number.

2.6 Names

The definition of functions in Racket involves assigning names: names for functions and names for its parameters.

Racket presents almost no limit towards names that you can give. A name like square is as valid as x+y+z because what separates a name from the other elements of a combination are parentheses and blank spaces.

The blank space concept includes tabs and changing line.

In Racket the only characters that cannot be used in names are the parentheses (, apostrophe , quotation marks " and semicolons ;. All other characters can be used in names, but, in practice, the creation of names should take some rules in consideration:

The choice of names will have a significant impact on the program’s legibility. Let us consider for example the area \(A\) of a triangle with a base \(b\) and a height \(c\) which can be defined mathematically by:

\[A(b,c) = \frac{b \cdot c}{2}\]

In Racket’s language we will have:

(define (A b c) (/ (* b c) 2))

Note that the Racket definition is identical to the corresponding mathematical expression, apart from the prefix notation and the \(=\) symbol being define. However, if we did not know beforehand what the function does, we will hardly understand it. Therefore, and contrary to Mathematics, the names that we assign in Racket should have a clear meaning. Instead of writing "A" it is preferable that we write "triangle-area" and instead of writing "b" and "c" we should write "base" and "height" respectively. Taking these aspects in consideration we can present a more meaningful definition:

(define (triangle-area base height)
  (/ (* base height) 2))

As the number of definitions grow, names become particularly important for the reader to quickly understand the written program, so it is crucial that names are carefully chosen.

2.6.1 Exercises 4
2.6.1.1 Question 12

Suggest an appropriate name for the following functions:
  • Function that calculates the volume of a sphere;

  • Function that tests if a number is a prime-number;

  • Function that converts a measurement in centimetres into inches.

2.6.1.2 Question 13

Define the function radians<-degrees that receives an angle in degrees and computes the corresponding value in radians. Note that \(180\) degrees are \(pi\) radians.

2.6.1.3 Question 14

Define the function degrees<-radians that receives an angle in radians and computes the corresponding value in degrees.

2.6.1.4 Question 15

Define a function that calculates the perimeter of a circle given the radius \(r\).

2.6.1.5 Question 16

Define a function that calculates the volume of a parallelepiped from its length, width and height.

2.6.1.6 Question 17

Define a function that calculates the volume of a cylinder a length and radius. The volume corresponds to multiplying the base radius with the cylinder’s length.

2.6.1.7 Question 18

Define a function average that calculates the average value between two numbers. For example: (average 2 3) \(\rightarrow\) 2.5.

2.7 Predefined Functions

The possibility of defining new functions is fundamental for increasing the language’s flexibility and its ability to adapt to the problems we want to solve. The new functions, however, must be defined in terms of others that were either defined by the user or, at most, were already pre-defined in the language.

As we will see, Racket has a reasonable set of predefined functions that in most cases they are enough for what we want to do, but we should not try to avoid defining new functions whenever we deem it necessary.

In this table we see a set of mathematical functions predefined in Racket. Note that, due to syntax limitations (that are also present in other languages), it is common that some Racket functions have a notation that is different when compared to the mathematical definition. For example, the square root function, \(\sqrt{x}\) is written as (sqrt x). The name sqrt is a contraction of the words square root and similar contractions are used for several other functions. The absolute value function is written as \(|x|\) and the exponentiation function \(x^y\) as (expt x y). This table shows some equivalents between the invocations of Rackets functions and the correspondent Mathematics invocations.

Some math predefined functions in Racket.

Function

 

Arguments

 

Result

+

 

Multiple Numbers

 

The sum of all arguments. With no arguments, zero.

-

 

Multiple Numbers

 

With only one argument, the symmetric value. For more than one argument, the subtraction of the first argument by all the remaining arguments. With no arguments, zero.

*

 

Multiple Numbers

 

The multiplication of all arguments. With no arguments, zero.

/

 

Multiple Numbers

 

The dividision of the first argument by all the remaining arguments. With no arguments, zero.

add1

 

One number

 

The sum of the argument with 1.

sub1

 

One number

 

The subtraction of the argument with 1.

abs

 

One number

 

The absolute value of the argument.

sin

 

One number

 

The sine of the argument (in radians).

cos

 

One number

 

The cosine of the argument (in radians).

atan

 

One or two numbers

 

With only one argument, the inverse tangent of the argument (in radians). With two arguments,the arc tangent of the division between the first and the second. The argument’s sign is used to determine the quadrant.

sqr

 

One number

 

The square of the argument.

sqrt

 

One number

 

The square root of the argument.

exp

 

One number

 

The exponential value with \(e\) base of the argument.

expt

 

Two numbers

 

The first argument raised to the second one.

log

 

One number

 

The logarithmic value of the argument.

max

 

Multiple Numbers

 

The highest argument.

min

 

Multiple Numbers

 

the lowest argument.

remainder

 

Two numbers

 

With two arguments, the remainder of the division between the first and the second argument.

floor

 

One number

 

The argument without the fractional part.

Racket’s predefined math functions.

Racket

 

Mathematics

(+ x0 x1 ... xn)

 

\(x_0 + x_1 + \ldots + x_n\)

(+ x)

 

\(x\)

(+)

 

\(0\)

(- x0 x1 ... xn)

 

\(x_0 - x_1 - \ldots - x_n\)

(- x)

 

\(-x\)

(-)

 

Error

(* x0 x1 ... xn)

 

\(x_0 \times x_1 \times \ldots \times x_n\)

(* x)

 

\(x\)

(*)

 

\(1\)

(/ x0 x1 ... xn)

 

\(x_0 / x_1 / \ldots / x_n\)

(/ x)

 

\(x\)

(/)

 

Error

(add1 x)

 

\(x+1\)

(sub1 x)

 

\(x-1\)

(abs x)

 

\(|x|\)

(sin x)

 

\(\sin x\)

(cos x)

 

\(\cos x\)

(atan x)

 

\(\arctan x\)

(atan y x)

 

\(\arctan \frac{y}{x}\)

(sqr x)

 

\(x^2\)

(sqrt x)

 

\(\sqrt{x}\)

(exp x)

 

\(e^x\)

(expt x y)

 

\(x^y\)

(log x)

 

\(\log x\)

(floor x)

 

\(\lfloor x\rfloor\)

2.7.1 Exercises 5
2.7.1.1 Question 19

Translate the following mathematical expressions into Racket’s notation:
  1. \(\sqrt{\frac{1}{\log 2^{\left|(3-9\log 25)\right|}}}\)

  2. \(\frac{\cos^4 \frac{2}{\sqrt 5}}{\arctan 3}\)

  3. \(\frac{1}{2} + \sqrt 3 + \sin^{\frac{5}{2}} 2\)

2.7.1.2 Question 20

Translate the following Racket expressions into mathematical notation:
  1. (log (sin (+ (expt 2 4) (/ (floor (atan pi)) (sqrt 5)))))

  2. (expt (cos (cos (cos 0.5))) 5)

  3. (sin (/ (cos (/ (sin (/ pi 3)) 3)) 3))

2.7.1.3 Question 21

Define the function odd? that, for a given number evaluates if it is odd, i.e., if the remainder of that number when divided by two is one. In order to do so, you can use the predefined function remainder

2.7.1.4 Question 22

The area \(A\) of a pentagon inscribed in a circle of radius \(r\) is given by the following expression: \[A = \frac{5}{8}r^2\sqrt{10 + 2\sqrt{5}}\] Define a function to calculate that same area.

2.7.1.5 Question 23

Define a function to calculate the volume of an ellipsoid with semi-axis \(a\), \(b\) and \(c\). That volume can be calculated using the formula: \(V=\frac{4}{3}\pi a b c\)

2.8 Arithmetic in Racket

We saw previously that Racket is capable of dealing with several types of numbers, from integers to complex numbers and also fractions. Some of those numbers like \(\sqrt 2\) or \(pi\), do not have a rigorous representation based in numerals and for that reason, Racket classifies them as inexact numbers, in order to emphasize that they are dealing with an approximated value. When an inexact number is used in an arithmetic operation, the result will also be inexact, so the inexactness is said to be contagious.

Finitude is another feature of the inexact numbers. Unlike exact numbers that theoretically have no limits, inexact numbers cannot surpass a certain limit, above which every number is represented by infinity, as you can see by the following example:

> (expt 10.0 10)

10000000000.0

> (expt 10.0 100)

1e+100

> (expt 10.0 1000)

+inf.0

Note that |+inf.0| (or |-inf.0|) is Racket’s way of saying that a number exceeds the inexact numbers representation capacity. The number is not infinite, as one might think, but merely a value excessively big for Racket’s capacity.

There is also another problem regarding inexact numbers: round-off errors. As an example, let us consider the obvious equality \((4/3-1)*3-1=0\) and let us compare the results that we get by using exact or inexact numbers in Racket:

> (- (* (- (/ 4 3) 1) 3) 1)

0

> (- (* (- (/ 4.0 3.0) 1.0) 3.0) 1.0)

-2.220446049250313e-16

As we can see, by using inexact numbers we cannot obtain a correct result and the problem is caused by the use of round-off errors: 3/4 can’t be represented with a finite number of digits. This round-off error is then propagated to the remaining operations which will produce a value that, even though not zero, is relatively close enough.

2.8.1 Exercises 6
2.8.1.1 Question 24

Translate the following definition into Racket: \[f(x)=x-0.1\cdot{}(10\cdot{}x-10)\]

2.8.1.2 Question 25

In Mathematical terms, whatever the argument used in the previous function, the result should always be \(1\) because \[f(x)=x-0.1\cdot{}(10\cdot{}x-10)=x-(x-1)=1\] Using the created function calculate the result of the following expressions and explain them:

(f 5.1)
(f 51367.7)
(f 176498634.7)
(f 1209983553611.9)
(f 19843566622234756.0)
(f 5.5377455871102e+20)
2.8.1.3 Question 26

We wish to create a flight of stairs with \(n\) treads, capable of covering a height \(a\) in meters. Considering that each step as a tread height \(h\) and a width \(d\) that obey to the following proportion: \[2h+d=0.64\]

define a function that, from a given height to cover and the number of treads, computes the length of the flight of stairs.

2.9 Name Evaluation

The primitive elements presented so far, such as numbers and strings, evaluate to themselves, i.e., the value of an expression composed only by a primitive element is the primitive element itself. With names this is no longer true.

Names have a special meaning in Racket. Note that when we define a function, it has a name. And its formal parameters have names as well. When a combination is written, the evaluator uses the function definition associated with the name that is the first element of the combination. This means that the value of the first element in a combination is the associated function. If we had defined the function square, as suggested previously in section Defining Functions, we could test this behaviour in the following expressions:

> (square 3)

9

> square

#<procedure:square>

As we can see, the value of the name square is an entity that Racket describes using a special notation. This entity is, as shown, a function. The same behaviour happens to any other predefined function:

> +

#<procedure:+>

> *

#<procedure:*>

As we have seen, the sum + and multiplication * signs are some of the predefined names of the language. For example, the symbol pi is also predefined and associated with an approximated value of \(pi\):

> pi

3.141592653589793

However, when the body of the expression is evaluated, the value of a name assigned to a parameter in a function is the corresponding argument during the function call. For example, in the combination (square 3), after the evaluator knows that the square value is a function by us defined and that 3 has the value \(3\), it evaluates the body of the function but associating the name x, whenever is necessary, to the same \(3\) that was previously associated with x.

2.10 Conditional Expressions

There are many operations in which the result depends on a test. For example, the mathematical function \(|x|\), that estimates the absolute value of \(x\) is equivalent to the inverse of a number if it is negative or the number itself otherwise. Using the mathematical notation we have that:

\[|x|= \begin{cases} -x, & \text{if $x<0$}\\ x, & \text{otherwise.} \end{cases}\]

This function needs to test if the argument is negative and choose one of two alternatives: it either evaluates for the number itself or for its symmetrical value.

These kind of expressions that depend on making one or more tests, are called conditional expressions.

2.10.1 Logical Expressions

A conditional expression follows the structure ”if expression then ..., otherwise ...”. The expression that determines whether to use the branch ”if” or the branch ”otherwise”, is called the logical expression and is characterized for having its value interpreted as either true or false. For example, the logical expression (< x 0) tests if the value of x is less than zero. If it is, the expression’s evaluation will return true, otherwise it will return false.

2.10.2 Logical Values

Some programming languages consider true and false as part of a special data type called logical or boolean data.

After George Boole, the English mathematician that invented the algebra of logic.

Other languages, like Racket, do not consider that these values should be treated as special data, just that the conditional expression considers some of the values as true and the remaining ones as false.

In Racket, conditional expressions consider only one of its values as false, represented as #f. Any other value that is different than #f is considered to be true. From the conditional expression point of view, the expression \(123\) is considered to be true. However, it makes little sense to a human user that a number is considered as true or false so a constant that represents true was introduced the language. This constant is represented by #t. If #f is the only value that represents falsehood and if #t is different than #f then #t necessarily represents truth.

2.11 Predicates

In the most usual case, a logical expression is a function applied to some arguments. In this case, the function used as the test case is known as a predicate. The test value is interpreted as true or false. So the predicate is a function that produces only true or false.

Despite the use of #t and #f it is important to know that not every predicate returns #t and #f exclusively. There are predicates produce different values from #t and #f.

2.11.1 Arithmetic Predicates

The mathematical relational operators \(<\),\(>\),\(=\),\(\leq\) and \(\geq\) are some of the most simple predicates. These operators compare numbers between each other. Their use in Racket follows the prefix notation and are written respectively <,>,=, <= and >=. Some examples are:

> (> 4 3)

#t

> (< 4 3)

#f

> (<= (+ 2 3) (- 6 1))

#t

2.12 Logical Operators

In order to combine logical expressions together we have the and, or and not operators. The and and the or operators accept any number of arguments. The not only accepts one. The value of such combinations is determined according to the following rules:

Note that although the meaning of false is clear, it necessarily corresponds to the value of #f, the meaning of true is not so clear because everything different than #f is considered to be true.

2.12.1 Exercises 7
2.12.1.1 Question 27

What is the value of the following expressions?
  1. (and (or (> 2 3) (not (= 2 3))) (< 2 3))

  2. (not (or (= 1 2) (= 2 3)))

  3. (or (< 1 2) (= 1 2) (> 1 2))

  4. (and 1 2 3)

  5. (or 1 2 3)

  6. (and #f 2 3)

  7. (or #f #f 3)

2.13 Predicates with a Variable Number of Arguments

An important property of the arithmetic predicates <,>,=, <= and >= is they accept any number of arguments. Whenever there is more than one argument, the predicate is applied sequentially to pairs of argument. That way,

(< e1 e2 e3 ... en-1 en)

is equivalent to
(and (< e1 e2)
(< e2 e3)
...
(< en-1 en))
. This property can be seen in the following examples:

> (< 1 2 3)

#t

> (< 1 2 2)

#f

2.14 Recognizers

Apart from relational operators, there are many other predicates in Racket, like zero?, that tests if the number is zero:

> (zero? 1)

#f

> (zero? 0)

#t

Note that zero? ends with an question mark because when a predicate is called, a question is being asked. For historical reasons, not all predicates in Racket follow this convention. However, when we define new predicates we should be mindful to use them.

Note that the operator zero? is used to recognize a particular element (zero) in a data type (numbers). These type of predicates are known as recognizers.

Another important set of predicates are the universal recognizers. These do not recognize one but all elements of a particular type of data. An universal recognizer accepts any kind of data as an argument and returns true if that elements belongs to the that same kind.

For example, to determine if a certain element is a number, we can use the number? predicate:

> (number? 1)

#t

> (number? "Two")

#f

And the string? predicate determines if entities are strings:

> (string? "Two")

#t

> (string? 3)

#f

Finally, there are predicates that recognize certain sub types of data, like the predicate integer? that recognizes integer values:

> (integer? 1)

#t

> (integer? 1.0)

#t

> (integer? 1.1)

#f

> (integer? 2/3)

#f

> (integer? "four")

#f

Note that similar to the number 1, the number 1.0 is also an integer. The first is an exact number and the second one is an inexact number which implies that operations involving 1.0 will produce inexact results. To distinguish between both types of numbers we have the predicates exact? and the inexact?:

> (exact? 1)

#t

> (exact? 1.0)

#f

> (inexact? 1)

#f

> (exact? 2/3)

#t

2.14.1 Exercises 8
2.14.1.1 Question 28

What is a conditional expression? What is a logical expression?

2.14.1.2 Question 29

What is a logical value? Which logic values does Racket incorporate?

2.14.1.3 Question 30

What is a predicate? Give examples of predicates used in Racket.

2.14.1.4 Question 31

What is a relational operator? Give examples of relational operators used in Racket.

2.14.1.5 Question 32

What is a logical operator? Give examples of logical operators used in Racket.

2.14.1.6 Question 33

What is a recognizer? What is an universal recognizer? Give examples in Racket.

2.14.1.7 Question 34

Translate the following mathematical expressions into Racket’s notation:
  1. \(x<y\)

  2. \(x\leq y\)

  3. \(x<y\wedge y<z\)

  4. \(x<y\wedge x<z\)

  5. \(x\leq y \leq z\)

  6. \(x\leq y < z\)

  7. \(x< y \leq z\)

2.15 Selection

If we look at the mathematical definition of absolute value:

\[|x|= \begin{cases} -x, & \text{if $x<0$}\\ x, & \text{otherwise} \end{cases}\]

we notice that it uses a conditional expression in the form of

\[\begin{cases} \text{consequent expression}, & \text{if logical expression}\\ \text{alternative expression}, & \text{otherwise} \end{cases}\]

that translates to common language as “if logical expression then consequent expression, otherwise alternative expression”.

The evaluation of a conditional expression is made through the evaluation of the logical expression and if it is true, the consequent expression is applied, if it is false then the alternative expression is applied.

The use of conditional expressions in Racket is even easier than in mathematics because it is based on a simple operator, the if operator, called a selection operator since it allows to choice between two alternatives. The syntax of the if operator is as follows:

(if logical-expression consequent-expression alternative-expression)

The value of a conditional expression that uses the operator if is computed in the following way:

  1. The logical-expression is evaluated;

  2. If the previous evaluation is true, then the combination value is the consequent-expression;

  3. Otherwise, if the logical expression turns out to be false, the combination value is the alternative-expression.

Such behaviour, identical to what we would have in Mathematics, can be verified by the following examples:

> (if (> 3 2)
       1
       2)

1

> (if (> 3 4)
       1
       2)

2

Using the if operator, we can now define the absolute value function by doing a simple translation from the mathematical definition to Racket:

(define (abs x)
  (if (< x 0)
    (- x)
    x))

The purpose of using the if operator is to define functions whose behaviour depends on one or more conditions. For example, if we consider the max function that receives two numbers as arguments and returns the highest. To define such function we only need to test if the first number is higher than the second one. If it is, the function returns the first argument, otherwise it returns the second one. Based on this logic we can write:

(define (max x y)
  (if (> x y)
    x
    y))

Another far more interesting example is the mathematical function sign \(\operatorname{sgn}\), also known as signum (latim for "sign"). This function could be interpreted as the dual function of the absolute value function because we will have that \(x=\operatorname{sgn}(x) |x|\). The sign function is defined as:

\[\operatorname{sgn} x = \begin{cases} -1 & \text{if $x<0$} \\ 0 & \text{if $x = 0$} \\ 1 & \text{otherwise}\end{cases}\]

In common language, we would say that if \(x\) is negative, the \(\operatorname{sgn} x\) value is \(-1\), otherwise, if \(x\) is \(0\), the value is \(0\), otherwise the value is \(1\). That shows that the above expression uses two conditional expressions stacked in the following way:

\[\operatorname{sgn} x = \begin{cases} -1 & \text{se $x<0$} \\ \begin{cases} 0 & \text{se $x = 0$} \\ 1 & \text{otherwise}\end{cases} & \text{otherwise}\end{cases}\]

To define this function in Racket, two ifs must be used:

(define (signum x)
  (if (< x 0)
    -1
    (if (= x 0)
      0
      1)))

2.16 Multiple Selection

When a conditional expression requires more than one if, it is possible that the code becomes increasingly harder to read. In this case there is an alternative called cond which makes the function’s definition easier to read. The syntax of cond is as follows:

(cond (expr0,0 expr0,1 ... expr0,n)
      (expr1,0 expr1,1 ... expr1,m)
      ...
      (exprk,0 exprk,1 ... exprk,p))

A cond receives any number of arguments. Each argument is called a clause and is made up of a list of expressions. The semantics of a cond is based on evaluating sequentially the first expression in each clause until one of them turns out to be true. In that case the consequent expressions are evaluated and the value of the last one is returned. If none of the clauses has a first expression that is true, the cond returns |#<void>| meaning there is no relevant result to be returned. If the clause, in which the first expression is true, has no other expressions then cond returns the value of that first expression.

It is important to note that the parenthesis around the clauses do not mean the clauses are combinations: they are simply part of the cond syntax and are necessary to separate clauses from each other.

The usual pragmatic used in a cond (especially when the clause only has two expressions) consists in aligning the expressions one under the other.

Using cond the sign function can be much easily defined:

(define (signum x)
  (cond ((< x 0)
         -1)
        ((= x 0)
         0)
        (#t
         1)))

Note that in the previous example the last cond clause has, as logical expression, the #t symbol. As we have seen, this last symbol represents true so its presence ensures that it will be evaluated in case none of the previous ones are. This way, a clause in the form of (#t ...) represents a "for everything else....". To make the reading task easier, Racket accepts a special form for this last situation: else. Using that syntax, the example can now be written as:

(define (signum x)
  (cond ((< x 0)
         -1)
        ((= x 0)
         0)
        (else
          1)))
2.16.1 Exercises 9
2.16.1.1 Question 35

Define the function sum-highest that given 3 numbers as arguments calculates the sum of the 2 with the highest value.

2.16.1.2 Question 36

Define the function max3 that given 3 numbers as arguments returns the highest value.

2.16.1.3 Question 37

Define the function second-highest that given 3 numbers as arguments and returns the second highest number: the number between the maximum and minimum value.

2.17 Local Variables

Let us consider the following triangle:

and try to define a function in Racket to calculate the triangle’s area from the parameters \(a\), \(b\) and \(c\).

One way of calculating the area of a triangle is to use the famous Heron’s formula:

Heron of Alexandria was an important Greek mathematician and engineer of the 1st century A.D. to whom numerous discoveries and inventions were credited to, including the steam engine and the syringe.

\[A=\sqrt{s\left(s-a\right)\left(s-b\right)\left(s-c\right)}\]

in which \(s\) is the triangle’s semi-perimeter:

\[s=\frac{a+b+c}{2}\]

When trying to use the Heron’s formula to write the equivalent in Racket we come across a small problem: the formula is (also) written in terms of the semi-perimeter \(s\), but \(s\) is not a parameter but rather a value that is derived from other parameters of the triangle.

One way of solving this problem is to replace \(s\) with its meaning:

\[A=\sqrt{\frac{a+b+c}{2}\left(\frac{a+b+c}{2}-a\right)\left(\frac{a+b+c}{2}-b\right)\left(\frac{a+b+c}{2}-c\right)}\]

From this formula it is now possible to define the function in Racket:

(define (area-triangulo a b c)
  (sqrt (* (/ (+ a b c) 2)
           (- (/ (+ a b c) 2) a)
           (- (/ (+ a b c) 2) b)
           (- (/ (+ a b c) 2) c))))

Unfortunately, this definition has two problems. The first one is the loss of correspondence between the original formula and the function definition, making it harder to recognize as the Heron’s formula. The second one is that the function is repeatedly using (/ (+ a b c) 2) which is a waste of human effort, because we had to write it four times, and a waste of computational effort, because the expression needs to be calculated four times, even though we know it always has the same value.

In order to solve this problem, Racket allows the use of local variables. A local variable only has meaning in the context of a function and is used to calculate intermediate values such as the semi-perimeter s. Using a local variable we can rewrite the triangle-area function:

(define (triangle-area a b c)
  (define s (/ (+ a b c) 2))
  (sqrt (* s (- s a) (- s b) (- s c))))

The semantics used when definition local variables is the same as the definition of regular ones, with the added subtlety that its context, i.e. the part of the program in which the defined name can be used, is confined to the function that it contains.

When calling the function triangle-area, giving it the arguments for the corresponding parameters a, b and c, it starts by introducing an additional name - s - associated to the value that comes from the expression (/ (+ a b c) 2) and, in the context of than new name, evaluates the remaining expressions in the function’s body. In practice it is as if the function was stating: "Knowing that \(s=\frac{a+b+c}{2}\), let us calculate \(\sqrt{s\left(s-a\right)\left(s-b\right)\left(s-c\right)}\)."

There is another way of defining local variables that, although semantically similar to the previous one, has the advantage of being usable in any part where an expression is expected. We can do that by using the let form. The redefinition of the previous function using the let form is as follows:

(define (triangle-area a b c)
  (let ((s (/ (+ a b c) 2)))
    (sqrt (* s (- s a) (- s b) (- s c)))))

Let uses the following syntax:

(let ((name0 expr0)
      (name1 expr1)
      ...
      (namen exprn))
  exprn+1
  exprn+2
  ...
  exprn+m)

The semantic of the let form consists of associating each name (#,(lispemphi name "i") to the corresponding expression expri and, in the context established by that association, evaluate the let’s body, i.e., evaluate the expressions from exprn+1 to exprn+m and return the value of the last one.

One important characteristic of the let form is the fact that the association between expressions and names does not depend on other associated names. This implies that the context for evaluating the body of let is established just once, and not incrementally. This can be explained in the following example:

> (let ((pi 3)
        (prev-pi pi))
    (+ pi prev-pi))

6.141592653589793

However, if we want the context to be established incrementally, thus allowing expressions to associate names that can depend on previous established associations, Racket provides the form let*: form:

> (let* ((pi 3)
         (prev-pi pi))
    (+ pi prev-pi))

6

The Let* form is formally equivalent to a cascade of let forms, as can be seen in the following example:

> (let ((pi 3))
    (let ((prev-pi pi))
      (+ pi prev-pi)))

6

2.18 Global Variables

Contrary to local names that have a limited context, a global name, is a name that can be seen in any context of our programs. Its context is therefore the entire program. The name pi represents the constant \(\pi=3.14159...\) and can be used in any part of our program. For that reason, pi is a global name.

The definition of global names is the same to that of local names, with the difference of being defined outside a function. Therefore, if we wish to introduce a new global name, for example, for the golden ratio:

Also known as gold proportion and divine proportion among other names, and abbreviated to \(\phi\) in honour of Fineas, a Greek sculptor responsible for building the Parthenon where, supposedly, this golden proportion was used. The golden ration was first introduced by Euclid when solving the problem of dividing a line segment into two parts such that the ratio between the line segment and the longest part was equal to the ratio between the longest part and the shortest part. If \(a\) is the length of the longest part and \(b\) the shortest part, the Euclid’s problem is equivalent to \(\frac{a+b}{a}=\frac{a}{b}\). As a result, \(a^2-ab-b^2=0\) or \(a=\frac{b\pm\sqrt{b^2+4b^2}}{2}=b\frac{1\pm\sqrt{5}}{2}\). What makes sense then is: \(a=b\frac{1+\sqrt{5}}{2}\). The expression for calculating the golden ratio is thus: \(\phi=\frac{a}{b}=\frac{1+\sqrt{5}}{2}.\)

\[\phi=\frac{1+\sqrt{5}}{2}\approx 1.6180339887\]

We simply need to write:

(define golden-ratio (/ (+ 1 (sqrt 5)) 2))

From this moment on, the golden-ration can be referenced in any part of our program.

It should be warned that global names should be limited, when possible, to defining just constants, like 2pi. Other useful examples may be pi/2, 4pi and pi/4, as well their symmetric values, that are defined in terms of:

(define 2pi (* 2 pi))
(define pi/2 (/ pi 2))
(define 4pi (* 4 pi))
(define pi/4 (/ pi 4))
(define -pi (- pi))
(define -2pi (- 2pi))
(define -pi/2 (- pi/2))
(define -4pi (- 4pi))
(define -pi/4 (- pi/4))

2.19 Modules

Every functionality of Racket is stored and organized modules. Every module is a unit containing a set of definitions. The Racket language is nothing more than an aggregation of modules that provide often required functionalities. There are many other functionalities in modules that we can only have access to if we specifically ask for it.

Take for example the following program:

#lang racket

(define (square x)

  (* x x))

 

(define (circle-area r)

  (* pi (square r)))

The first line indicates the language in which the program is written, in this case, Racket. The following lines are the definitions of our program that, naturally, make use of Racket’s functionalities. For this program that includes the define function, the arithmetic operation * and the pi value.

If it was necessary to have additional functionalities we would have to require it, using the form require. For example, if we want to visualize the \(\sin\) function graph, we could use the plot module, like so:

#lang racket

(require plot)

 

(plot (function sin (- pi) pi))

The plot module used above provides the means to visualize graphs, namely the functions plot and function, with the remaining names being provided by Racket’s module.

The require form can also be used in other ways, the most useful being to access Racket’s central modules repository, called planet (http://planet.racket-lang.org/). For example, for accessing the rosetta module, whose author is aml we should write:

#lang racket

(require (planet aml/rosetta))

2.19.1 Exercises 10
2.19.1.1 Question 38

Define a module called hyperbolic with the three following functions: hyperbolic sin (sinh), hyperbolic cosin (cosh) and hyperbolic tangent (tanh), based on the mathematical definitions: \[\sinh x = \frac{e^x-e^{-x}}{2}\] \[\cosh x = \frac{e^x+e^{-x}}{2}\] \[\tanh x = \frac{e^x-e^{-x}}{e^x+e^{-x}}\]

2.19.1.2 Question 39

In the same module, define the inverse hyperbolic functions: asinh, acosh, and atanh, whose mathematical definitions are:

\[\sinh^{-1} x=\ln(x+\sqrt{x^2+1})\] \[\cosh^{-1} x=\pm\ln(x+\sqrt{x^2-1})\] \[\tanh^{-1} x=\begin{cases} \frac{1}{2}\ln(\frac{1+x}{1-x}), & \text{se $|x|<1$}\\ \frac{1}{2}\ln(\frac{x+1}{x-1}), & \text{se $|x|>1$} \end{cases}\]

2.19.1.3 Question 40

Set the defined names, from the previous exercises, as available for other modules. Hint: See Racket’s documentation on provide.

3 Modelling

 (require rosetta/tikz) package: rosetta

We saw in previous sections some types of pre-defined data in Racket. In many cases these are enough to build our programs. But in other cases it will become necessary to introduce new types of data. In this section we will study a new type of data that will become particularly useful to model geometric entities: coordinates.

3.1 Coordinates

Architecture relies on positioning elements in space. That position is expressed in terms of of what we designate as Coordinates: each coordinate is a number and a sequence of coordinate identifies a point in space. this figure demonstrates one possible sequence of coordinates \((x,y,z)\) that identify a point \(p\) in a three-dimensional space. Different types of coordinate systems are possible and, in the case of this figure, we are using a system called \(rectangular\), also known as \(Cartesian\) in honour of its inventor: René Descartes.

Descartes was a 19th Century French philosopher, author of the famous quote: "Cogito ergo sum", (I think, therefore I am) and of countless contributions in the fields of Mathematics and Physics.

Cartesian coordinates of a point in space.

There are other types of useful operations that we can make using coordinates. For example, we can calculate the distance between two positions in space \(P_0=(x_0,y_0,z_0)\) and \(P_1=(x_1,y_1,z_1)\). That distance can be expressed using the formula:

\[d = \sqrt{(x_1-x_0)^2+(y_1-y_0)^2+(z_1-z_0)^2}\]

and a first draft of this definition in Racket would be:

(define (dist x0 y0 z0 x1 y1 z1)
  (sqrt (+ (sqr (- x1 x0))
           (sqr (- y1 y0))
           (sqr (- z1 z0)))))

The distance between \((2,1,3)\) and \((5,6,4)\) would then be:

> (dist 2 1 3 5 6 4)

5.916079783099616

Unfortunately, by treating coordinates as a set of three independent numbers the use of functions becomes unclear. This can already be seen in the previous example, where the function dist calls upon six parameters forcing the reader to know where the coordinates of one point start and where they end. This problem becomes even worse when a function must return, not a number as it so happens with the function dist, but rather a position in space, as it happens, for example, with the function that computes the mid position \(P_m\) between \(P_0=(x_0,y_0,z_0)\) and \(P_1=(x_1,y_1,z_1)\). That position can be calculated using the formula:

\[P_m=(\frac{x_0+x_1}{2},\frac{y_0+y_1}{2},\frac{z_0+z_1}{2})\]

But it is difficult to conceive a function that implements this because, apparently, it would have to calculate three different result simultaneously, one for each of the coordinates \(X\), \(Y\) and \(Z\).

To deal with this kind of problems, mathematicians came up with the concept of \(tuple\): a tuple is nothing more than group of values but, in certain cases, this grouping has a specific name. For example, a rational number is tuple since it groups a number and a denominator, the same way that a position in space is also a tuple since it groups three coordinates.

All programming languages have mechanisms to create and manipulate tuples. In Racket, in addition to the predefined tuples, like rational and complex numbers, various other tuples have already been defined in the module rosetta which will be very useful to us when modelling geometry.

To use them, we must first require the module rosetta

#lang racket

(require (planet aml/rosetta))

To set the coordinates \((x,y,z)\), Rosetta provides the function xyz:

> (xyz 1 2 3)

#<xyz:1 2 3>

> (xyz (* 2 3) (+ 4 1) (- 6 2))

#<xyz:6 5 4>

Note that the result from evaluating the expression (xyz 1 2 3) is a value that represents a position in the three-dimensional Cartesian space. That value is expressed as #<xyz:x y z> in which x, y, and z are the coordinate values.

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 points \(P_0=(x_0,y_0,z_0)\) and \(P_1=(x_1,y_1,z_1)\), which, as we saw, can be calculated using the formula:

\[\sqrt{(x_1-x_0)^2+(y_1-y_0)^2+(z_1-z_0)^2}\]

A first draft of this definition translated into Racket would be:

(define (dist p0 p1)
  (sqrt (+ (sqr (- ? ?))
           (sqr (- ? ?))
           (sqr (- ? ?)))))

In order to complete the function we need to know how to get the \(x\), \(y\), and \(z\) coordinates of a certain position \(P\). For that purpose, Rosetta provides the functions cx, cy and cz, abreviations for ccoordinate x, ccoordinate y and ccoordinate z respectively.

Using these functions we can now write:

(define (dist p0 p1)
  (sqrt (+ (sqr (- (cx p1) (cx p0)))
           (sqr (- (cy p1) (cy p0)))
           (sqr (- (cz p1) (cz p0))))))

We can test is using a specific case:

The dist is pre-defined in Rosetta under the name distance.

> (dist (xyz 2 1 3) (xyz 5 6 4))

5.916079783099616

Let us look at another example. Suppose we wanted to define a function that 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. For \(P=(x,y,z)\) we will have \(P'=(x+\Delta_x,y+\Delta_y,z+\Delta_z)\). To make the use of this function easier we shall call it +xyz. Naturally, it needs as inputs a starting point \(P\) and the increments \(\Delta_x\), \(\Delta_y\) and \(\Delta_z\) that we will call dx, dy, and dz, respectively.

The point \(P'\) as a result of the translation of point \(P=(x,y,z)\) of \(\Delta_x\) in the \(X\) axis, of the \(\Delta_y\) in \(Y\) axis and \(\Delta_z\) in the \(Z\) axis.

The definition of this function is as follows:

(define (+xyz p dx dy dz)
  (xyz (+ (cx p) dx)
       (+ (cy p) dy)
       (+ (cz p) dz)))

Naturally we ca now use +xyz to define new functions, as for example, the horizontal and vertical translation:

(define (+x p dx)
  (+xyz p dx 0 0))
 
(define (+y p dy)
  (+xyz p 0 dy 0))
 
(define (+z p dz)
  (+xyz p 0 0 dz))

Equally useful would be the functions that compute the diagonal translations through the orthogonal planes XY, XZ and YZ:

(define (+xy p dx dy)
  (+xyz p dx dy 0))
 
(define (+xz p dx dz)
  (+xyz p dx 0 dz))
 
(define (+yz p dy dz)
  (+xyz p 0 dy dz))

The effect of this function can be seen in this figure.

Translations made by +x, +y, +z, +xy, +xz, +yz and +xyz from an arbitrary \(P\) point and the by \(\Delta_x\), \(\Delta_y\) and \(\Delta_z\).

Note that every function defined in this section is based on the xyz, cx, cy and cz operations, which we can consider to be the fundamental operations on coordinates. The first one allows us to construct a position given three numbers and the others to know which numbers determine a position. For this reason, the first operation is said to be a constructor of coordinates and the others selectors of coordinates.

Although we are unaware on 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

3.2.1 Exercises 11
3.2.1.1 Question 41

Define the function midpoint that calculates the three-dimensional coordinates of the midpoint between two points \(P_0\) and \(P_1\), given their three-dimensional coordinates.

3.2.1.2 Question 42

Define the function =c that compares two points coordinates and returns true if they are the 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 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 modelling program we must inevitably think where that plane is located. If omitted, CAD applications will by default consider the bi-dimensional plane to be the \(XY\) plane with the height \(Z\) being zero. So let us consider the bi-dimensional coordinate \((x,y)\) as a simplified notation for the three-dimensional coordinate \((x,y,0)\).

Based on this simplification, we can define a bi-dimensional coordinates constructor in terms of the three-dimensional coordinates constructor:

(define (xy x y)
  (xyz x y 0))

One of the advantages of defining bi-dimensional coordinates as a particular case of three-dimensional coordinates is that the selectors cx, cy and cz are automatically applicable to bi-dimensional as well, as are the other functions we created, such as distance and the translations - +x, +y, +z, +xy, +xz, +yz and +xyz.

3.2.3 Exercises 12
3.2.3.1 Question 43

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 44

Knowing that the maximum step height allowed for each step is \(0.18\)m define a function that calculates the minimum number of steps needed for a flight of stairs, shown in the following diagram, to connect \(P_1\) to \(P_2\).

3.2.4 Polar Coordinates

Although the Cartesian coordinate system is largely used, there are other coordinate systems that can be more useful in certain situations. As an example, suppose we wanted to set \(n\) elements, equally spaced between them and with distance \(d\) from the origin point, as is partially represented in this figure. Logically, the elements will eventually form a circle and it is easy to see that the angle between them would have to be \(\frac{2\pi}{n}\).

Positions along a circle.

Taking the \(X\) axis as reference, we can say that the first element will be positioned at \(d\) distance 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 have the same distance but in a different axis, making an angle of \(\frac{2\pi}{n}\) wit 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 x-axis and y-axis, while in polar coordinates it is expressed by \(\rho\) and \(\phi\) - respectively the radius vector (also called module) 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.\]

or from rectangular coordinates to 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") that will construct coordinates from its polar representation, by simply converting them into the equivalent rectangular ones:

(define (pol ro fi)
  (xy (* ro (cos fi))
      (* ro (sin fi))))

That being said, polar coordinate will be implemented based on the rectangular system. For that reason, the polar coordinates selectors - the function (pol-rho that allows us to obtain the \(\rho\) value and the function pol-phi that allows us to obtain the \(\phi\) value) - must use the rectangular coordinates selectors, i.e., cx and cy.

These functions are already predefined in Rosetta.

(define (pol-rho c)
  (sqrt (+ (sqr (cx c)) (sqr (cy c)))))
 
(define (pol-phi  c)
  (atan (cy c) (cx c)))

Here are some examples of these functions:

Note that in some cases the coordinates numbers are not zero or one as we would expect, but values very close to them. This is due to rounding errors. And also note that since we are using bi-dimensional coordinates the \(z\) coordinate is always zero.

> (pol 1 0)

#<xyz:1 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>

Another very useful operation is the one that, given a point \(P=(x,y)\) and a ""vector"" with its origin in \(P\) and specified in polar coordinates by a distance \(\rho\) and an angle \(\phi\), returns the the point located at the end of the vector, as shown in this figure. Using trigonometry it is easy to calculate that this position given by \(P'=(x+\rho\cos\phi, y+\rho\sin\phi)\).

A point displacement in polar coordinates

This translated into Racket becomes:

(define (+pol p ro fi)
  (+xy p
       (* ro (cos fi))
       (* ro (sin fi))))

Some examples of its use:

> (+pol (xy 1 2) (sqrt 2) (/ pi 4))

#<xyz:2.0 3.0 0>

> (+pol (xy 1 2) 1 0)

#<xyz:2 2 0>

> (+pol (xy 1 2) 1 (/ pi 2))

#<xyz:1.0 3.0 0>

3.2.5 Exercises 13
3.2.5.1 Question 45

The function =c defined in Question 42 compares the coordinates of two points, returning true if they are coincidental. 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 Racket will not consider them equal, which can be seen in the example below:

> (=c (xy -1 0) (pol 1 pi))

#f

> (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 =c based on the concept of distance between coordinates.

3.3 Bi-dimensional Geometric Modelling

In this section we will be introducing some bi-dimensional geometric modelling operations.

In order to visualize the shapes we create we need to have a CAD application, like AutoCAD or Rhino. The choice of which CAD application we wish to use is made using the backend function together with the argument (autocad or rhino). Therefore, a program that uses Rosetta usually starts with:

#lang racket

(require (planet aml/rosetta))

(backend autocad)

or with:

#lang racket

(require (planet aml/rosetta))

(backend rhino)

depending on the user’s preference for AutoCAD or Rhino, respectively.

Let us start by considering the creation of three circles. For that we can use the function circle which receives the centre point and the radius as arguments. In this figure you can see the result of the following program in AutoCAD:

From here onwards, we will omit the header that requires Rosetta and chooses the CAD application and, instead, we shall focus our attention on the operations for geometric modelling.

#lang racket

(require (planet aml/rosetta))

(backend autocad)

 

(circle (pol 0 0) 4)

(circle (pol 4 (/ pi 4)) 2)

(circle (pol 6 (/ pi 4)) 1)

A series of circles.

Another much used operation is the one that creates line segments: line. In its most simple form it takes the two positions of its extremities. However, it is possible to invoke this function with any number of positions, case in which it will successively connect each position with the next, forming a polygonal line. this figure shows the example of a swastika

The swastika is a mythical symbol, used by many cultures since the neolithic period

produced by the following code:

(line (xy -1 -1) (xy -1 0) (xy 1 0) (xy 1 1))
(line (xy -1 1) (xy 0 1) (xy 0 -1) (xy 1 -1))

A set of line segments.

In case we wish to draw closed polygonal lines it is preferable that we use the polygon function, very similar to the function line but with the difference that it creates an additional segment connecting the last position with the first. This figure shows the result of the following code:

(polygon (pol 1 (* 2 pi 0))
         (pol 1 (* 2 pi 1/5))
         (pol 1 (* 2 pi 2/5))
         (pol 1 (* 2 pi 3/5))
         (pol 1 (* 2 pi 4/5)))

A polygon.

And for drawing regular polygons, i.e., polygons that have equal edges and angles, as shown in this figure, it is preferable to use the function regular-polygon. This function receives as arguments the number of sides, its centre point, a radius, a rotation angle and a boolean to indicate if the radius refers to an inscribed circle (i.e. the radius is the distance from the edges to the centre) or a circumscribed circle (i.e. the radius is the distance from the vertexes to the centre). If omitted, the centre point will be considered the origin, the radius will have one unit of measurement, the angle will be considered zero and the circle will be circumscribed.

Using regular-polygon, this figure can be obtained by:

(regular-polygon 5)

More interesting examples can be obtained by changing the rotation angle. For example, the following expressions will produce the image shown in this figure:

(regular-polygon 3 (xy 0 0) 1 0 #t)
(regular-polygon 3 (xy 0 0) 1 (/ pi 3) #t)
(regular-polygon 4 (xy 3 0) 1 0 #t)
(regular-polygon 4 (xy 3 0) 1 (/ pi 4) #t)
(regular-polygon 5 (xy 6 0) 1 0 #t)
(regular-polygon 5 (xy 6 0) 1 (/ pi 5) #t)

Overlapping triangles, squares and pentagons with different rotation angles.

For four sided polygons aligned with the \(X\) and \(Y\) axis there is a very simple function: rectangle. This function can either be used with the position of its bottom left corner and upper right corner or the with the position of its bottom left corner and the two rectangle dimensions, as exemplified below and represented in this figure:

(rectangle (xy 0 1) (xy 3 2))
(rectangle (xy 3 2) 1 2)

A set of rectangles

In the following sections we will introduce the remaining functions available in Rosetta.

3.3.1 Exercises 14
3.3.1.1 Question 46

Recreate the drawing presented in this figure but this time using rectangular coordinates.

3.3.1.2 Question 47

We wish to place two circles with unit radius and around an origin so that the circles are tangent to each other as shown in the following drawing:

Write a sequence of expressions that when evaluated produce the above image.

3.3.1.3 Question 48

We wish to place four circles with unit radius and around an origin so that the circles are tangent to each other as shown in the following drawing:

Write a sequence of expressions that when evaluated produce the above image.

3.3.1.4 Question 49

We wish to place three circles with unit radius and around an origin so that the circles are tangent to each other as shown in the following drawing:

Write a sequence of expressions that when evaluated produce the above image.

3.4 Side Effects

In Racket, as we have previously seen, every expression has a value. We can see that by evaluating an arithmetic expression but also when evaluating a geometric expression:

> (+ 1 2)

3

> (circle (xy 1 2) 3)

#<circle 0>

In the last example, the result of evaluating the second expression is a geometric entity. When Racket writes a result that is a geometric entity it uses a notation based on the name of that entity and an integer to distinguish between them. Most of the times we are not only interested in seeing a geometric entity as a piece of text but we are also interested in visualizing that entities in space. For that purpose the evaluation of geometric expressions also has a side effect: all created geometrical forms are automatically added to the chosen CAD application using the backend function.

That way, evaluating the following program:

#lang racket

(require (planet aml/rosetta))

(backend autocad)

 

(circle (xy 1 2) 3)

produces as a result an abstract value that represents a circle with a radius of \(3\) units, centred at the point \(1,2\) and, as a side effect, that circle becomes visible in AutoCAD.

This behaviour of geometric functions like circle, line, rectangle, etc., is fundamentally different from the ones we have seen so far because previously these functions were used to compute something, i.e., to produce a value, and now it is not that value that interests us the most but rather its side effect (also called collateral effect) that allows us to visualize the geometrical shape in the CAD application.

One important aspect of using side effects is the possibility of their composition. The composition of side effects is accomplished through sequencing, i.e., the sequential computation of the different effects. In the next section we will discuss sequencing of side effects.

3.5 Sequencing

So far, we have combined mathematical expressions using mathematical operators. For example, from the expressions (sin x) and (cos x) we can calculate their division by (/ (sin x) (cos x)). This is possible because the evaluation of the sub-expressions (sin x) and (cos x) will produce two values that can then be used in the division.

With geometrical functions these kinds of combinations must be done differently since, as we saw, their evaluation also produces side effects. Seeing as these side effects are precisely what we want, Racket provides a way of producing them sequentially, i.e., one after the other. That feature is called begin and is used for sequencing side effects. For example, consider a function that draws a circle with a radius \(r\), centred on \(P\) with an inscribed or circumscribed square, depending on the user’s specification, as we show in this figure.

A circle with a square inscribed (left) and a square circumscribed (right).

The function’s definition could start as something like:

(define (circle-square p r inscribed?)
  ...)

The drawing produced by the function will naturally depend on the logic value of inscribed?, that is, this function’s definition could be something like:

(define (circle-square p r inscribed?)
  (if inscribed?
    "create a circle and a square inscribed in that circle"
    "create a circle and a square circumscribed in that circle"))

The problem now is that, for each case of if, the function must generate two side effects, namely create a circle and create a square. But the if only admits one expression, making us wonder how we would be able to combine two side effects in a single expression. For this purpose Racket provides the form Sbegin. This operator will take any number of expressions and will sequentially evaluate them, i.e., one after the other, returning the value of the last. Logically, if only the value of the last expression is used, then all other values from the other expressions are discarded and these are only relevant for the side effect they may have produced.

Using the begin operator we can further detail our function:

(define (circle-square p r inscribed?)
  (if inscribed?
    (begin
      "create a circle"
      "create a square inscribed in the circle")
    (begin
      "create a circle"
      "create a square circumscribed in the circle")))

All we need to do now is translate each expressions into the corresponding functions. In the case of the inscribed square we will use polar coordinates because we know its vertices will be set in a circle, one with \(\frac{\pi}{4}\) and another at \(\pi+\frac{\pi}{4}\).

(define (circle-square p r inscribed?)
  (if inscribed?
    (begin
      (circle p r)
      (rectangle (+pol p r (* 5/4 pi)) (+pol p r (* 1/4 pi))))
    (begin
      (circle p r)
      (rectangle (+xy p (- r) (- r)) (+xy p r r)))))

Note that for the if operator, both the consequence and the alternative are one single expression even though each of those expressions is the result of two other more elemental expressions. The begin operator can therefore be seen as a mechanism for grouping expressions.

Even though sequencing expressions requires the use of the operator begin, it is usually possible to minimize its use in these expressions. An attentive look at the previous function circle-square shows that a circle is always created independently of the square being inscribed or circumscribed. That way we can redefine the function so that the circle is created outside the if:

(define (circle-square p r inscribed?)
  (begin
    (circle p r)
    (if inscribed?
      (begin
        (rectangle (+pol p r (* 5/4 pi)) (+pol p r (* 1/4 pi))))
      (begin
        (rectangle (+xy p (- r) (- r)) (+xy p r r))))))

It is now clear that the two begins of the if form only have one expression each so its use is unnecessary. We can therefore simplify the expression to:

(define (circle-square p r inscribed?)
  (begin
    (circle p r)
    (if inscribed?
      (rectangle (+pol p r (* 5/4 pi)) (+pol p r (* 1/4 pi)))
      (rectangle (+xy p (- r) (- r)) (+xy p r r)))))

Even tough the operator begin is necessary every time we wish to evaluate more than one expression, there are some situations where Racket uses an implicit begin, such as in a function’s body. In fact, when a function is invoked every expression in the function’s body is evaluated sequentially and the function’s value is only determined by the last expression. This fact allows us to simplify the circle-square function even more:

(define (circle-square p r inscribed?)
  (circle p r)
  (if inscribed?
    (rectangle (+pol p r (* 5/4 pi)) (+pol p r (* 1/4 pi)))
    (rectangle (+xy p (- r) (- r)) (+xy p r r))))
3.5.1 Exercises 15
3.5.1.1 Question 50

Define a function called circle-and-radius that given the coordinates of its centre point and the radius creates the specified circle and, as shown in this figure, places the text describing the radius on the circle’s right side. The text should be proportional to the circle’s size.

3.5.1.2 Question 51

Using the previously defined function circle-and-radius, recreate this figure.

3.6 Doric Order

The Doric Order exemplified in the Greek Temple of Segesta. This temple was never ended Photography by Enzo De Martino.

image

In This figure we see an image of the Segesta Greek temple. This temple, which was never finished, was built during the 5th century D.C, and represents a fine example of the Doric order, the oldest of the three orders of Greek architecture. In this order a column is composed of a shaft, an Echinus and an abacus. The abacus is shaped like a squared plaque that stands on top the Echinus, the Echinus is similar to an inverted cone frustum which stands on top the shaft, and the shaft is similar to a cone frustum with twenty flutes around it. These flutes are semi-circular shaped and carved along the shaft.

These columns also present an intentional deformation called entasis. The entasis is a small curvature give to columns and is believed to be a way a creating a optical illusion in order to misguide the eye to see the column curved instead of straight.

When the Romans adopted the Doric order they introduced some modifications, in particular to the flutes which, in many cases, were simply removed.

Even though we are particularly interested in three.dimensional modelling, for pedagogic reasons, we are going to start by sketching a Doric column (without flutes) in two dimensions. In the following sections we will extend this process to create a three-dimensional model.

The same way a Doric columns can be decomposed into its basic components - shaft, Echinus and abacus - the drawing of one can too be decomposed in components. Therefore, we will create functions to draw the shaft, Echinus and abacus. this figure shows a reference model. Let us start by defining a function for the shaft.

The Doric column for reference

(define (shaft)
  (line (xy -0.8 10)
        (xy -1 0)
        (xy 1 0)
        (xy 0.8 10)
        (xy -0.8 10)))

In this example, we used the line function that, given a sequence of positions, will create a line with vertices on those positions. Another possibility, probably more appropriate, would be to create a closed polygonal line, something we can do with the polygon function, omitting the repeated position, i.e.:

(define (shaft)
  (polygon (xy -0.8 10)
           (xy -1 0)
           (xy 1 0)
           (xy 0.8 10)))

To complete the figure we also need a function for the Echinus and another for the abacus. The reasoning for the Echinus is similar:

(define (echinus)
  (polygon (xy -0.8 10)
           (xy -1 10.5)
           (xy 1 10.5)
           (xy 0.8 10)))

For the abacus we could use a similar strategy or explore a function in Rosetta that creates rectangles. This function requires two points to define a rectangle:

(define (abacus)
  (rectangle (xy -1 10.5)
             (xy 1 11)))

Finally, the expression that creates a Doric column:

(define (doric-column)
  (shaft)
  (echinus)
  (abacus))

Note that the doric-column function sequentially calls the functions shaft, Echinus and finally abacus.

This figure shows the result of invoking the doric-column function.

A Doric column.

3.7 Parametrization of Geometric Figures

Unfortunately, the Doric column we created has fixed position and size, making it difficult to use this function in different contexts. Naturally, this function would be much more useful if its creating was parametrized, i.e., if its creation depended on the parameters that describe a column, as for example, the column’s base coordinates, the height of the Echinus, shaft and abacus, the base and top Echinus radius, etc.

In order to better understand this parametrization of these functions, let us start by considering the shaft represented in this figure.

Sketch of a column’s shaft.

The first step in parametrizing a geometrical drawing is to correctly identify the relevant parameters. In the case of the shaft one of the obvious parameters would be its spatial location, i.e., the coordinates of a reference point in relation to which the shaft will be drawn. Let us then consider that the shaft will be placed with its base’s centre point at an imaginary point \(P\) of arbitrary coordinates \((x,y)\). In addition to this parameter we also need know the height of the shaft \(a\) and both base \(r_b\) and top radius \(r_t\).

To make the drawing process easier it is convenient to consider additional reference points in our sketch. For the shaft, since it’s shaped essentially like a trapeze, we can look at its shape as the succession of line segments along a sequence of points \(P_1\), \(P_2\), \(P_3\) and \(P_4\), points which we can easily calculate from \(P\).

We now have all we need to define a function that draws the column’s shaft. To make the program clearer we will use the names a-shaft for the height \(a\), the base radius r-base and top radius r-top respectively. The definition will now be:

(define (shaft p a-shaft r-base r-top)
  (polygon (+xy p (- r-top) a-shaft)
           (+xy p (- r-base) 0)
           (+xy p (+ r-base) 0)
           (+xy p (+ r-top) a-shaft)))

Next we need to draw out the Echinus. It is convenient to consider once more a geometrical sketch, as shown in this figure.

Sketch of an Echinus.

As similar to the shaft, from the bases’ centre point \(P\) we can compute the coordinates that define the extremities of the lines that draw an Echinus. Using those points, the function will be:

(define (echinus p a-echinus r-base r-top)
  (polygon (+xy p (- r-base) 0)
           (+xy p (- r-top) a-echinus)
           (+xy p (+ r-top) a-echinus)
           (+xy p (+ r-base) 0)))

Having done the shaft and Echinus all that is left now is to draw the Abacus. For that we can consider yet another geometric sketch, shown in this figure.

Sketch of an Abacus.

Once more we will consider \(P\) as the starting point in the Abacus’s base. From this point we can easily calculate the points \(P_1\) and \(P_2\), that are the two opposite corners of the rectangle that defines the Abacus. That way, we have:

(define (abacus p a-abacus l-abacus)
  (rectangle (+xy p (/ l-abacus -2) 0)
             (+xy p (/ l-abacus 2) a-abacus)))

Finally, to create the entire column we must combine the functions that draw the shaft, the Echinus and the Abacus. We need only to take into account that, as this figure shows, the shaft’s top radius is coincidental with the Echinus’ base radius and the Echinus top radius is half the width of the Abacus. The figure also shows that the coordinates of the Abacus’ base is the result of adding the shaft’s height to the the coordinates of the the shaft’s base and that the Abacus’s base coordinates are the result of adding the combined heights of the shaft and Echinus to the shaft’s base coordinates.

Composition of the shaft, Echinus and Abacus.

As we did before, let us give more appropriate names to the parameters in this figure. Using the names p, a-shaft, r-base-shaft, a-Echinus, r-base-Echinus, a-abacus and l-abacus instead of the corresponding, \(P\), \(a_f\), \(r_{bf}\), \(a_c\), \(r_{bc}\), \(a_a\) and \(l_a\), we obtain:

(define (column p
                a-shaft r-base-shaft
                a-echinus r-base-echinus
                a-abacus l-abacus)
  (shaft p a-shaft r-base-shaft r-base-echinus)
  (Echinus (+xy p 0 a-shaft) a-echinus r-base-echinus (/ l-abacus 2))
  (abacus (+xy p 0 (+ a-shaft a-echinus)) a-abacus l-abacus))

Using this function we can easily explore different variations of columns. The following examples reproduce what is shown in this figure.

(column (xy  0 0) 9 0.5 0.4 0.3 0.3 1.0)
(column (xy  3 0) 7 0.5 0.4 0.6 0.6 1.6)
(column (xy  6 0) 9 0.7 0.5 0.3 0.2 1.2)
(column (xy  9 0) 8 0.4 0.3 0.2 0.3 1.0)
(column (xy 12 0) 5 0.5 0.4 0.3 0.1 1.0)
(column (xy 15 0) 6 0.8 0.3 0.2 0.4 1.4)

Multiple Doric columns.

As we can see, not all columns obey the proportion’s canon of the Doric order. Further ahead we are going to see which modifications are needed to avoid this problem.

3.8 Documentation

In the column function, a-shaft is the shaft’s height, r-base-shaft is the shaft’s base radius, r-top-shaft is the shaft’s top radius, a-echinus is the Echinus’ height and, finally, r-abacus is the Abacus’ radius. Because the function already employs many parameters and its meaning may not be clear to someone that reads the function’s definition for the first time, it is convenient to document the function. For that, Racket provides a special syntax: each time a semicolon ; is used Racket will ignore everything that is in front of it until the end of that line. That allows text to be written between the code without Racket trying to interpret its meaning.

Using documentation, the full program for creating Doric columns will look something like what is shown below. Note that this example tries to show the different ways documentation can be used in Racket and not a specific example of a documented program.

The program is so simple in fact that it should not require so much documentation.

;;;;Drawing Doric Columns

 

;;;The drawing of a Doric column is divided into three parts:

;;;shaft, Echinus and abacus. Each of those parts has an

;;;independent function.

 

;Draws the shaft of a Doric column.

;p: column's centre base coordinate,

;a-shaft: shaft's height,

;r-base: shaft's base radius,

;r-top: shaft's top radius.

(define (shaft p a-shaft r-base r-top)

  (polygon (+xy p (- r-top) a-shaft)

           (+xy p (- r-base) 0)

           (+xy p (+ r-base) 0)

           (+xy p (+ r-top) a-shaft)))

 

;Draws the Echinus of a Doric column.

;p: Echinus centre base coordinate,

;a-echinus: Echinus height,

;r-base: Echinus base radius,

;r-top: Echinus top radius.

(define (Echinus p a-Echinus r-base r-top)

  (polygon (+xy p (- r-base) 0)

           (+xy p (- r-top) a-echinus)

           (+xy p (+ r-top) a-echinus)

           (+xy p (+ r-base) 0)))

 

;Draws the Abacus of a Doric column.

;p: column's centre base coordinate,

;a-abacus: abacus height,

;l-abacus: abacus width.

(define (abacus p a-abacus l-abacus)

  (rectangle (+xy p (/ l-abacus -2) 0)

             (+xy p (/ l-abacus +2) a-abacus)))

 

;Draws a Doric column composed of a shaft, an Echinus and an Abacus.

;p: column's centre base coordinate,

;a-shaft: shaft's height,

;r-base-shaft: shaft's base radius,

;r-base-echinus: Echinus base radius = shaft's top radius,

;a-echinus: Echinus height,

;a-abacus: abacus height,

;l-abacus: abacus width = 2*Echinus top radius.

(define (column p

                a-shaft r-base-shaft

                a-echinus r-base-echinus

                a-abacus l-abacus)

  ;;We draw the shaft at the base point p

  (shaft p a-shaft r-base-shaft r-base-echinus)

  ;;We place the Echinus on top of the shaft

  (Echinus (+xy p 0 a-shaft) a-echinus r-base-echinus (/ l-abacus 2))

  ;;and the Abacus on top of the Echinus

  (abacus (+xy p 0 (+ a-shaft a-echinus)) a-abacus l-abacus))

When a program is documented, is easier to understand what the program ~does, without having to study the functions’ body. As we can see in the following example, it is common pragmatic in Racket to use a different number of semicolons to indicate the importance of the comment:

It is important that we get used to documenting our programs but it is important to note that excessive documentation can also have disadvantages:

For these reasons, we should try to write the code as clear as possible and at the same time provide short and useful documentation: the documentation should not say what is already obvious from reading the program.

3.8.1 Exercises 16
3.8.1.1 Question 52

Consider an arrow with an origin in \(P\), a length of \(\rho\), an inclination \(\alpha\) , an opening angle \(\beta\) and a tip \(\sigma\), as shown in the following figure:

Define a function arrow that, given the parameters \(P\), \(\rho\), \(\alpha\), \(\beta\) and \(\sigma\) creates the corresponding arrow.

3.8.1.2 Question 53

Based on the previous exercise define a function that given the point \(P\), the length \(\rho\) and the angle \(\alpha\) draws "the North" as shown in the following figure:

This drawing should also obey the following constraints:
  • The opening angle \(\beta\) must be \(45\,^{\circ}.\)

  • The arrow’s tip length \(\sigma\) must be \(\frac{\rho}{2}\).

  • The "N" should be distanced \(\frac{\rho}{10}\) from the arrow’s tip in the arrow’s direction

  • The size of "N" should be half the length \(\rho\).

3.8.1.3 Question 54

Using the function arrow function, define a new function called arrow-from-to that given two points, creates an arrow that goes from the first point to the second. coordinate. The tips should have one unit as measurement and the angle should be \(\frac{\pi}{8}\).

3.8.1.4 Question 55

Consider a house with only rectangular rooms. Define the function rectangular-divisions that receives as parameters the bottom left corner of a room, the length and width of the room and a text describing that room’s type of use. With those values, that function should build a rectangle with two text lines, one with the rooms type of use and the other with the room’s floor area. For example, the following code lines:

(rectangular-division (xy 0 0) 4 3 "kitchen")
(rectangular-division (xy 4 0) 2 3 "pantry")
(rectangular-division (xy 6 0) 5 3 "room")
(rectangular-division (xy 0 5) 5 4 "living-room")
(rectangular-division (xy 5 5) 3 4 "toilet")
(rectangular-division (xy 8 3) 3 6 "room")

They produce as a result the following drawing:

3.9 Debugging

As we all know Errare humanum est. Making mistakes is part of our day-to-day life and we mostly learn how to deal with them. The same does not apply to programming languages. Any mistake made in a computer program will result in it having a different behaviour than that which was to be expected.

Seeing how easy it is to make errors, it should also be easy to detect and correct them. The process of detecting and correcting errors is called debugging. Different programming languages provide different mechanisms to do that. As we will see Racket is well covered for these mechanisms.

Generally, errors in programs can be classified as syntactic errors or semantic errors.

3.9.1 Syntactic Errors

Syntactic errors occur each time we write a line of code which does not follow the language’s grammar rules. As an example let us suppose we wish to create a function to create a single Doric column, which we will refer as standard, and that always has the same dimensions, dispensing the need for any other parameters. One possible definition is:

(define (standard-column
  (column (xy 0 0) 9 0.5 0.4 0.3 0.3 0.5)))

However, if we test this definition, Racket will produce an error, telling us that something is wrong:

define: not an identifier,identifier with default,or keyword for
procedure argument in: (column (xy 0 0) 9 0.5 0.4 0.3 0.3 0.5)

The error Racket is warning us about is that the form define does not follow the required syntax, and in fact a careful look at it shows we have not followed the correct syntax that, as we saw in section Defining Functions, should obey the following structure:

(define (name parameter1 ... parametern)
  body)

Our mistake is now obvious, we forgot to close the parentheses in the list of parameters. That makes Racket use the following expression as part of the parameters list and, being unable to do so, Racket reports a syntactic error, i.e., a "sentence" which does not obey the language syntax.

There are several other types of errors that Racket is capable of detecting and these will be discussed as we go along. The important thing is not that what kind of syntactic errors Racket is capable of detecting but rather that Racket is capable of checking the expressions we write and detect syntactic errors in them before evaluating them.

3.9.2 Semantic Errors

Semantic errors are very different from syntactic ones. A semantic error is not the misspelling of a "sentence" but rather a mistake in its meaning. In other terms, a semantic error occurs when we write a sentence which we think has a certain meaning but in reality it has a different one.

Generally semantic errors can only be detected during the evaluation of the functions that contain them. Part of the semantic errors are detectable by Racket’s evaluator but countless others can only be detected by the programmer.

As an example of a semantic error consider a meaningless operation such as the sum of a number with a string:

> (+ 1 "two")

+: contract violation

  expected: number?

  given: "two"

  argument position: 2nd

  other arguments...:

   1

As we can see the mistake is explained in the given message, which says that the second argument should be a number. In this example the mistake is obvious enough for us to detect it immediately. However, with more complex programs the process of finding mistakes can often be slow and frustrating. It is also a fact that the more experienced we get at detecting errors the faster we will be at doing it..

3.10 Three-dimensional Modelling

As you have seen in the previous section, Rosetta provides multiple drawing tools (lines, rectangles, circles, etc.) that allows us to easily draw bi-dimensional representations of objects such as floor sections, side sections, etc.

Although to this moment we have only used Rosetta’s bi-dimensional drawing capacities it is possible to go further and start exploring three-dimensional modelling. This type of modelling represents lines, surfaces and volumes in the three-dimensional space.

In this section we will study Rosetta’s functions the allow the creating of such three-dimensional objects.

3.10.1 Predefined Solids

Rosetta provides a set of predefined functions that create solids from their three-dimensional coordinates. Although these predefined functions only allow the creation of a limited number of solids they are enough to create sophisticated models.

The predefined operations can create boxes (function box), cylinders (function cylinder), cones (function cone), spheres (function sphere), toruses (function torus) and pyramids (function regular-pyramid). Each of these functions accepts various optional arguments for creating solids in these solids in different ways. this figure shows a set of solids built from the following expressions:

(box (xyz 2 1 1) (xyz 3 4 5))
(cone (xyz 6 0 0) 1 (xyz 8 1 5))
(cone-frustum (xyz 11 1 0) 2 (xyz 10 0 5) 1)
(sphere (xyz 8 4 5) 2)
(cylinder (xyz 8 7 0) 1 (xyz 6 8 7))
(regular-pyramid 5 (xyz -2 1 0) 1 0 (xyz 2 7 7))
(torus (xyz 14 6 5) 2 1)

Primitive solids in Rosetta.

Great Pyramid of Giza. Photography by Nina Aldin Thune.

image

It is interesting to notice that some of the most important works in architectural history could be modelled directly using these operations. One example is the Great Pyramid of Giza, this figure, built over forty five centuries ago and an almost perfect example of a square pyramid. In its original form, the Great Pyramid had a square base, with sides measuring 230 meters, and a height of 147 meters which made it the tallest man-made structure up until the construction of the Eiffel Tower. Many other Egyptian pyramids have similar proportions which makes them easy to model with the following function:

(define (egyptian-pyramid p side height)
  (regular-pyramid 4 p (/ side 2) 0 height #f))

The case of the Great Pyramid of Giza would be:

(egyptian-pyramid (xyz 0 0 0) 230 147)

Contrary to the Great Pyramid of Giza, there are not many examples that can be modelled with a single geometric primitive. It is however possible to create more complex structures by combining these primitives.

Take for example the cross in this figure, built using six identical truncated cones, with their base positioned at the same point and the top vertices positioned on orthogonal axis.

Cross, overlapping truncated cones.

To model this solid we will parametrize the base point \(p\) and the other cone’s dimensions : the base radius \(r_b\), top radius \(r_t\) and length \(c\):

(define (cross p rb rt c)
  (cone-frustum p rb (+x p c) rt)
  (cone-frustum p rb (+y p c) rt)
  (cone-frustum p rb (+z p c) rt)
  (cone-frustum p rb (+x p (- c)) rt)
  (cone-frustum p rb (+y p (- c)) rt)
  (cone-frustum p rb (+z p (- c)) rt))
3.10.2 Exercises 17
3.10.2.1 Question 56

Using the function cross determine approximate values for the parameters as to create the following models:

3.10.2.2 Question 57

Using the function cone-frustum define the function hourglass function that given the base centre point, the base radius, the neck radius and the height, creates the model of a hourglass similar to the following example:

Similar to the truncated cone, but with a polygonal base, we have the truncated pyramid. A truncated pyramid can be created using the function regular-pyramid-frustum. For that we must specify the number of sides, the base centre point, the radius of the circle that circumscribes the base, the base rotation angle, the top centre point and the radius of the circle that circumscribes the top.

this figure you can see the rotation’s angle effect given by the following expressions:

Three truncated pyramids with different rotation angles. From left to right the angles are: \(0\), \(\frac{\pi}{4}\) e \(\frac{\pi}{2}\).

(regular-pyramid-frustum 3 (xyz 0 0 0) 2 0 (xyz 0 0 1) 1)
(regular-pyramid-frustum 3 (xyz 8 0 0) 2 pi/4 (xyz 8 0 1) 1)
(regular-pyramid-frustum 3 (xyz 16 0 0) 2 pi/2 (xyz 16 0 1) 1)

The Dahshur pyramid. Photography by Ivrienen.

image

For a more architectural example let us consider the Dahshur rhomboidal pyramid, illustrated in this figure, characterized for having sloped edges that abruptly change from \(43^{\circ}\) to \(55^{\circ}\), presumably to avoid its collapse due to the original slope. This pyramid is \(188.6\) meters wide and \(101.1\) meters tall and it can be decomposed into two geometrical forms, an initial truncated pyramid onto of which stands a quadrangular pyramid.

In order to generalise the modeling of this type of pyramid we can consider the schematic model in This figure where a section of this pyramid is shown. From there it is easy to see that \(h_0 + h_1 = h\) and that \(l_0+l_1=l\). Moreover we have the trigonometric functions

\[\tan\alpha_0=\frac{h_0}{l_0}\qquad\qquad \tan\alpha_1=\frac{h_1}{l_1}\]

As a result, we have

\[l_0=\frac{h-l\tan\alpha_1}{\tan\alpha_0-\tan\alpha_1}\]

Section of a rhomboidal pyramid.

Transcribing these functions into Racket we have:

(define (rhomboidal-pyramid p l h a0 a1)
  (define l0 (/ (- h (* l (tan a1))) (- (tan a0) (tan a1))))
  (define l1 (- l l0))
  (define h0 (* l0 (tan a0)))
  (define h1 (- h h0))
  (regular-pyramid-frustum 4 p l 0 h0 l1)
  (regular-pyramid 4 (+z p h0) l1 0 h1))

The rightmost model in This figure shows a Dahshur pyramid created by the following expression:

(rhomboidal-pyramid (xyz 0 0 0) (/ 186.6 2) 101.1
                   (radians<-degrees 55) (radians<-degrees 43))

In the same image, to the left, two other pyramids were created with the following expressions:

(rhomboidal-pyramid (xyz 300 0 0) (/ 186.6 2) 101.1
                   (radians<-degrees 75) (radians<-degrees 40))
(rhomboidal-pyramid (xyz 600 0 0) (/ 186.6 2) 101.1
                   (radians<-degrees 95) (radians<-degrees 37))

Three different rhomboidal pyramids.

Washington Monument. Photography by David Iliff.

image

3.10.3 Exercises 18
3.10.3.1 Question 58

An obelisk is a monument shaped like a rhomboidal pyramid. The Washington Monument, this figure, is a modern example of an obelisk of enormous size, which can be defined, (relative to this figure) with a truncated pyramid \(2l=16.8\) meters wide on the bottom and \(2l_1=10.5\) meters wide on top, a total height of \(169.3\) meters and an upper pyramid top height of \(h_1=16.9\) meters.

Define the obelisk function that given the base centre point, base width, base height, top width and total height, creates an obelisk.

3.10.3.2 Question 59

A perfect obelisk follows a set of proportions in which its height is equal to the pyramid’s base width, which in turn is one-tenth of the total height. The top width has to be two thirds of the base width. With these proportions in mind, define the perfect-obelisk function, that given a base centre point and the total height, creates a perfect obelisk.

3.10.3.3 Question 60

Using the regular-pyramid-frustum function, define a function called prism that creates a regular prismatic solid. The function should receive as parameters the number of sides, the three-dimensional coordinates of the base’s centre point, the distance between that centre point to each vertices, the base rotation angle and the three-dimensional coordinates of the top’s centre point. As examples consider the following expressions:

(prism 3 (xyz  0  0 0) 0.4 0 (xyz  0  0 5))
(prism 5 (xyz -2  0 0) 0.4 0 (xyz -1  1 5))
(prism 4 (xyz  0  2 0) 0.4 0 (xyz  1  1 5))
(prism 6 (xyz  2  0 0) 0.4 0 (xyz  1 -1 5))
(prism 7 (xyz  0 -2 0) 0.4 0 (xyz -1 -1 5))
which produce the following image:

3.10.3.4 Question 61

The Sears Tower shown in This figure (today called Willis Tower was for many years the tallest building in the world. This tower consists of nine square prisms, with different heights \(h_{i,j}\) connected to each other.

The Sears Tower, em Chicago.

image

From a top view these nine blocks define a square with a side \(l\), as shown in the following sketch:

Using the function prism defined in the previous exercise, define a function called sears-tower capable of creating buildings similar to the Sears Tower. The function should have as parameters the three-dimensional coordinates of the base corner \(P\), the base width \(l\) and nine more parameters relative to each height value \(h_{0,0}, h_{0,1},\ldots,h_{2,2}\).

The real Sears Tower has the following parameters: \(l=68.7 m\), \(h_{0,1}=h_{1,1}=442 m\), \(h_{1,0}=h_{2,1}=h_{1,2}=368 m\), \(h_{0,0}=h_{2,2}=270 m\) and \(h_{0,2}=h_{2,0}=205 m\) as shown in the following image:

Besides the already presented geometrical primitives there is another that allows the creation of cuboid solids, i.e., solids with six faces but with a shape that is not necessarily cubic. A cuboid is defined by its eight vertices divided into two sets of four, respectively the base and top vertices (in counter-clockwise order. The following expressions produce the three cuboids presented in this figure:

Three cuboid solids with different vertexes

(cuboid (xyz 0 0 0) (xyz 2 0 0) (xyz 2 2 0) (xyz 0 2 0)
        (xyz 0 0 2) (xyz 2 0 2) (xyz 2 2 2) (xyz 0 2 2))
 
(cuboid (xyz 4 0 0) (xyz 5 0 0) (xyz 5 2 0) (xyz 4 2 0)
        (xyz 3 1 2) (xyz 5 1 2) (xyz 5 2 2) (xyz 3 2 2))
 
(cuboid (xyz 7 2 0) (xyz 8 0 0) (xyz 8 3 0) (xyz 6 3 0)
        (xyz 7 2 2) (xyz 8 0 2) (xyz 8 3 2) (xyz 6 3 2))

The John Hancock Center, in Chicaco. %Fotografia de User:Cacophony

image

The John Hancock Center, in this figure, is a good example of a building with a geometry that can be modelled with a cuboid. In fact this building has a truncated shape with regular base and top. To model it we can can start by defining the regular-cuboid-geometry function parametrized by the base centre point \(P\), the base length \(c_b\) and width \(l_b\), the top base length \(c_t\) and width \(l_t\) and finally by the height \(h\). For creating the solid the cuboid function becomes particularly useful, leaving us only with determining the position each vertex relative to the base point \(P\).

(define (regular-cuboid-geometry p cb lb ct lt h)
  (cuboid (+xyz p (/ cb -2) (/ lb -2) 0)
          (+xyz p (/ cb 2) (/ lb -2) 0)
          (+xyz p (/ cb 2) (/ lb 2) 0)
          (+xyz p (/ cb -2) (/ lb 2) 0)
          (+xyz p (/ ct -2) (/ lt -2) h)
          (+xyz p (/ ct 2) (/ lt -2) h)
          (+xyz p (/ ct 2) (/ lt 2) h)
          (+xyz p (/ ct -2) (/ lt 2) h)))

Using this function, it becomes trivial to create buildings inspired by the shape of the John Hancock Center, as presented in this figure.

Buildings inspired by John Hancock Center’s cuboid geometry.

Pylons of the Karnak Temple. Illustration by Albert Henry Payne.

image

3.10.3.5 Question 62

A pylon is a distinctive Egyptian architectural element, illustrated in this figure. It is a monumental gateway enclosed by two identical tapering towers on both sides. Each tower is cuboid shaped, with a rectangular base and top and the remaining sides as trapeziums. Define a conveniently parametrized function capable of creating a simplified version of a pylon, similar to the one shown in the following image:

3.11 Cylindrical Coordinates

We have seen in previous sections some examples of the use of rectangular and polar coordinate systems. It also became clear that a rightful choice of coordinate system can simplify a geometric problem greatly.

For three-dimensional modelling, besides the rectangular and polar, it is also common to use two other coordinate systems: cylindrical coordinates and spherical coordinates.

As we can see in figure this figure, a point in cylindrical coordinates is defined by a radius \(\rho\) radius on the \(z=0\) plan, an angle \(\phi\) with the \(x\) axis and a height \(z\). It is easy to see that the radius and the angle match the polar coordinates of a point’s projection on the \(z\) plan.

Cylindrical coordinates.

From this figure we can easily see that given a point \((\rho, \phi, z)\) in cylindrical coordinates, that same point in rectangular coordinates would be \[(\rho \cos \phi, \rho \sin \phi, z)\].

Likewise, a point in rectangular coordinates \((x,y,z)\) would be represented in in cylindrical coordinates as \[(\sqrt{x^2+y^2},\arctan\frac{y}{x}, z)\]

These equivalences are assured by the constructor of cylindrical coordinates cyl. Although this function is pre-defined in Rosetta it is not difficult it is defined as

(define (cyl ro fi z)
  (xyz (* ro (cos fi))
       (* ro (sin fi))
       z))

If we simply want to add to a point a translation in cylindrical coordinates, we can use the +cyl function, which makes use of the +xyz function:

(define (+cyl p ro fi z)
  (+xyz p
        (* ro (cos fi))
        (* ro (sin fi))
        z))
3.11.1 Exercises 19
3.11.1.1 Question 63

Define the selectors cyl-rho, cyl-phi and cyl-z which return, respectively, the components \(\rho\), \(\phi\) and \(z\) of a point built with the constructor cyl.

3.11.1.2 Question 64

Define a function stairs capable of building a helix staircase. The following image shows three different examples of helix staircases:

It can be seen that a staircase is formed by a central cylinder onto which \(10\) cylindrical steps are connected. For easier testing consider the central cylinder as a radius of \(r\). Each step is equal to the central cylinder, they measure \(10\) times the centre pole radius and are placed at incremental heights. Each is distanced \(h\) from the previous one and, seen from a top view, makes with it an angle \(\alpha\).

The function stairs should have as parameters the coordinates of the central cylinder’s base, the radius \(r\), the height \(h\) and the the angle \(\alpha\). As an example, consider that the stairs in the previous figure were created with the following expressions:

(stairs (xyz 0 0 0) 1.0 3 (/ pi 6))
(stairs (xyz 0 40 0) 1.5 5 (/ pi 9))
(stairs (xyz 0 80 0) 0.5 6 (/ pi 8))

3.12 Spherical Coordinates

As we can see in this figure, a point in spherical coordinates (also called polar) is characterized by the measurement of the radius \(\rho\), an angle \(\phi\) (called longitude or azimuth) whose projection onto the \(z=0\) plane makes with the \(x\) axis an angle \(\psi\) (also called colatitude, zenith or emph{polar angle}) with the \(z\) axis.

Colatitude is the complementary angle to the latitude, i.e., the the difference between the pole (\(\frac{\pi}{2}\)) and the latitude.

Spherical Coordinates

Given a point \((\rho, \phi, \psi)\), that same point in spherical coordinates is \[(\rho \sin \psi \cos \phi, \rho \sin \psi \sin \phi, \rho \cos \psi)\]

Likewise a point \((x,y,z)\) in Cartesian coordinates, that same point in spherical coordinates is \[(\sqrt{x^2+y^2+z^2},\arctan\frac{y}{x}, \arctan\frac{\sqrt{x^2+y^2}}{z})\]

As it happens with cylindrical coordinates, the constructors of spherical coordinates sph and +sph are already pre-defined but it is not difficult to deduce their definitions:

(define (sph ro fi psi)
  (xyz (* ro (sin psi) (cos fi))
       (* ro (sin psi) (sin fi))
       (* ro (cos psi))))
 
(define (+sph p ro fi psi)
  (+xyz p
        (* ro (sin psi) (cos fi))
        (* ro (sin psi) (sin fi))
        (* ro (cos psi))))
3.12.1 Exercises 20
3.12.1.1 Question 65

Define the selectors sph-rho, sph-phi and sph-psi which return, respectively, the components \(\rho\), \(\phi\) and \(\psi\) of a point built with the constructor sph.

3.12.1.2 Question 66

The Mohawk hairstyle was widely used during the punk period. It is defined by styling the hair in the shape of a crest, as shown below:

Define the function mohawk, with parameters \(P\), \(r\), \(c\), \(\phi\) and \(\Delta_\psi\), which creates 9 cones of length \(c\) and base radius \(r\), all centred at point \(P\), leaning with an angle \(\Delta_\psi\) between them and placed along a plane with an angle \(\phi\) with the \(XZ\) plane.

An example is presented below as a result of the following expressions:

(mohawk (xyz 0  0 0) 1.0 10 (/ pi 2) (/ pi 6))
(mohawk (xyz 0 15 0) 0.5 15 (/ pi 3) (/ pi 9))
(mohawk (xyz 0 30 0) 1.5 6 (/ pi 4) (/ pi 8))

3.13 Modelling Doric Columns

The three-dimensional modelling has the virtue of allowing us to create geometrical entities that are more realistic than mere agglomerates of lines representing views of that entity. As an example, reconsider the Doric column we introduced back in Doric Order. In that section we developed a series of functions capable of creating a front view of each of that column’s components. Even though those views are useful it is even more useful to model a column directly as a three-dimensional entity.

In this section we are going to employ some of the most relevant operations for three-dimensional modelling of columns, in particular truncated cones for shaping the shaft and the Echinus and rectangular box to shape the Abacus.

Before, our "columns" were laid out in the \(XY\) axis with them "growing" along the \(Y\) axis. Now, only the column’s base will be set on the \(XY\) plane: the column’s body will grow along the \(Z\) axis. Although it would be trivial to employ a different arrangement of axes, this is the one closest to reality.

Similarly to many other functions in Rosetta, each of the operations to model solids has different ways of being called upon. For the case of modelling truncated cones - cone-frustum - the method to us more convenient is that one that receives the base centre coordinates, the base radius, height and finally the top radius.

With this in mind we can redefine the operation for creating the column’s shaft:

(define (shaft p h-shaft r-base r-top)
  (cone-frustum p r-base h-shaft r-top))

Likewise, the operation for creating the Echinus will become:

(define (echinus p h-echinus r-base r-top)
  (cone-frustum p r-base a-echinus r-top))

Finally, to build the Abacus - the rectangular box at the column’s top - we have many ways of specifying it. One way is to specify the two corners of this box. The other is to specify one of these corners followed by the box’s dimensions. For this example we will employ the second alternative.

(define (abacus p h-abacus l-abacus)
  (box (+xyz p (/ l-abacus -2) (/ l-abacus -2) 0)
       l-abacus
       l-abacus
       h-abacus))
3.13.1 Exercises 21
3.13.1.1 Question 67

Implement the abacus function but using the other option for creating a rectangular box whit the two corners.

Finally all there is left is to implement the column function that, similar to what happened in the bi-dimensional case, successively invokes the functions shaft, Echinus and abacus but now progressively increasing the \(Z\) coordinate:

(define (column p
                h-shaft r-base-shaft
                h-echinus r-base-echinus
                h-abacus l-abacus)
  (shaft p h-shaft r-base-shaft r-base-echinus)
  (echinus (+z p h-shaft) a-echinus r-base-echinus (/ l-abacus 2))
  (abacus (+z p (+ h-shaft h-echinus)) h-abacus l-abacus))

With these redefinitions we can now repeat the columns drawn in section Doric Order, and shown in this figure, but now creating a three-dimensional image as presented in this figure:

(column (xyz  0 0 0) 9 0.5 0.4 0.3 0.3 1.0)
(column (xyz  3 0 0) 7 0.5 0.4 0.6 0.6 1.6)
(column (xyz  6 0 0) 9 0.7 0.5 0.3 0.2 1.2)
(column (xyz  9 0 0) 8 0.4 0.3 0.2 0.3 1.0)
(column (xyz 12 0 0) 5 0.5 0.4 0.3 0.1 1.0)
(column (xyz 15 0 0) 6 0.8 0.3 0.2 0.4 1.4)

Multiple three-dimensional columns.

3.14 Vitruvian Proportions

The method for modelling Doric columns that we developed in the previous section allows us to easily build columns, for which we need only indicate the values for the relevant parameters, such as the shaft’s height and base radius, the Echinus’ height and base radius and the Abacus’ height and width. Each of these parameters represents a degree of freedom that we can freely vary.

Even though it is logic to think that the more degrees of freedom we have the more flexible the modelling is, the truth is an excessive number of parameters will often lead to unrealistic models. That phenomenon can be seen in this figure where we show a a set of columns with randomly chosen parameters.

Three-dimensional columns with randomly chosen parameters. Only one of these columns obeys the canon of the Doric order.

In fact, according to the canons of the Doric Order, the different parameters that regulate the shape of a column should relate to each other following a set of well defined proportions. Vitruvius, in his famous architectural treatise, considers that these proportions derive directly from the proportions of the human body.

Vitruvius was a Roman writer, architect and engineer during the 1st century b.C., and the author of the only architectural treatise that has survived from Ancient times.

Because they wanted to raise a temple with columns but did not know the adequate proportions, [...], they measured a man’s foot and saw that is was one sixth of his height, so they gave the column a similar proportion, i.e., they made its height, including the capital, six times the column’s width, measured from the base. Thus the Doric order obtained its proportion and its beauty from the male human figure.

Vitruvius characterizes the Doric order in terms of modules:

These considerations lead us to determine the values of some of the parameters to draw a column, in terms of the shaft’s base radius. In terms of implementing this, that means that the function’s parameters will now be local variables whose value is attributed by applying the proportions established by Vitruvius to the the parameter r-base-shaft. The function is thus defined:

(define (doric-column p r-base-shaft r-base-echinus)
  (define h-shaft (* 13 r-base-shaft))
  (define h-echinus (* 2/3 r-base-shaft))
  (define h-abacus (* 1/3 r-base-shaft))
  (define l-abacus (* 13/6 r-base-shaft))
  (shaft p h-shaft r-base-shaft r-base-echinus)
  (echinus (+z p h-shaft) h-echinus r-base-echinus (/ l-abacus 2))
  (abacus (+z p (+ h-shaft h-echinus)) h-abacus l-abacus))

or, alternatively:

(define (doric-column p r-base-shaft r-base-echinus)
  (let ((h-shaft (* 13 r-base-shaft))
        (h-echinus (* 2/3 r-base-shaft))
        (h-abacus (* 1/3 r-base-shaft))
        (l-abacus (* 13/6 r-base-shaft)))
    (shaft p h-shaft r-base-shaft r-base-echinus)
    (echinus (+z p h-shaft) h-echinus r-base-echinus (/ l-abacus 2))
    (abacus (+z p (+ h-shaft a-echinus)) h-abacus l-abacus)))

Using this function it is now possible to create columns closer to the Doric proportions (as set by Vitruvius). this figure shows the result of evaluating the following expressions:

(doric-column (xyz  0 0 0) 0.3 0.2)
(doric-column (xyz  3 0 0) 0.5 0.3)
(doric-column (xyz  6 0 0) 0.4 0.2)
(doric-column (xyz  9 0 0) 0.5 0.4)
(doric-column (xyz 12 0 0) 0.5 0.5)
(doric-column (xyz 15 0 0) 0.4 0.7)

Variations of Doric columns according to Vitruvius’ proportions.

Vitruvius’ proportions allowed us to reduce the number of independent parameters for a Doric column to only two: the shaft’s base radius and Echinus’ base radius. However, it does not seem right for these parameters to be completely independent since that allows bizarre columns to be constructed, where the shaft’s top is larger than the base, as it happens in the rightmost column in this figure.

In truth, the characterization of the Doric Order that we presented is incomplete since, for the column’s proportions, Vitruvius also added:

The reduction at the top of a column seems to be regulated according to the following principles: if a column is less than fifteen feet, let the base width be divided into six parts and use five of those and let five of those parts be used to form the top’s width. If the column has between fifteen and twenty feet, let base width be divided into six and a half parts, and let five and a half of those parts be used for the upper width of the column. If a column has between twenty to thirty feet let the base width be divided into seven parts and let the reduced top measure six of them. A column of thirty to forty feet should be divided at the base into seven and a half parts, and, at the beginning of the reduction, it should have six and a half of these parts at the top. Columns of forty to fifty feet should be divided into eight parts, and reduced to seven of those at the top of the column under the capital. In the case of higher columns, let the reduction be determined proportionally, on the same principles. (In Vitruvius, The Ten Books on Architecture, III book, Chapter 3.1)

These considerations by Vitruvius allow us to determine the ratio between the top and bottom of a column in terms of its height in feet.

A Foot was the fundamental unit of measurement during for several centuries but its value has changed along the years. The measurement of the international foot is \(304.8\) millimetres and was established in 1958. Before that, many other measurements were used, as the Doric foot of \(324\), the Roman and Ionic feet of \(296\) millimetres, the Athenian foot of \(315\) millimetres, the Egyptian and Phoenician feet of \(300\) millimetres, etc.

Let us then consider a function, which we will call shaft-top-radius, that receives as parameters the column’s base width and the column’s height and returns as the result the width for the column’s top width.

A literal translation of Vitruvius’ considerations allows us to write:

(define (shaft-top-radius base-radius height)
  (cond ((< height 15) (* (/ 5.0 6.0) base-radius))
        ...))

The previous fragment obviously corresponds to the statement: "if a column is less than fifteen feet, let the base width be into six parts and use five of those and let five of those parts be used to form the top’s width." In case the column has less than fifteen feet we skip to the next statement: "If the column has between fifteen and twenty feet, let base width be divided into six and a half parts, and let five and a half of those parts be used for the upper width of the column". Translating this last statement we have:

(define (shaft-top-radius base-radius height)
  (cond ((< height 15)
         (* (/ 5.0 6.0) base-radius))
        ((and (>= height 15) (< height 20))
         (* (/ 5.5 6.5) base-radius))
        ...))

A careful analysis of the two previous statements shows that, in reality, we are making excessive tests on the second clause. In fact, if we can get to the second clause that means the first one is false, i.e., a height is not less than 15 and, therefore, it is higher or equal to 15. In that case it is useless to test if the height is higher of equal to 15 again. That way we can simplify the function and write instead:

(define (shaft-top-radius base-radius height)
  (cond ((< height 15) (* (/ 5.0 6.0) base-radius))
        ((< height 20) (* (/ 5.5 6.5) base-radius))
        ...))

Moving on with the translation, leads us to:

(define (shaft-top-radius base-radius height)
  (cond ((< height 15) (* (/ 5.0 6.0) base-radius))
        ((< height 20) (* (/ 5.5 6.5) base-radius))
        ((< height 30) (* (/ 6.0 7.0) base-radius))
        ((< height 40) (* (/ 6.5 7.5) base-radius))
        ((< height 50) (* (/ 7.0 8.0) base-radius))
        ...))

The problem now is that Vitruvius as let the door open to arbitrarily high columns, simply saying: "In the case of higher columns, let the reduction be determined proportionally, on the same principles". To clearly understand the principles we speak of let us consider the evolution of the relation between the top and base of the columns which is visible on the side image.

The ration between the column’s top radius and the base radius is as shown in the side image (something which was also already clear in the shaft-top-radius function), a sequence like

\[\frac{5}{6},\, \frac{5\frac{1}{2}}{6\frac{1}{2}},\, \frac{6}{7},\, \frac{6\frac{1}{2}}{7\frac{1}{2}},\, \frac{7}{8},\, \cdots{}\]

It now becomes obvious that, for higher columns, "the same principles" Vitruvius speaks of come down to, for each \(10\) additional feet, adding \(\frac{1}{2}\) to both the numerator and the denominator. However, it is important to notice that this principle should only be applied if the height exceeds \(15\) feet, since the first interval is bigger than the other ones. Thus, we have to handle columns up to \(15\) feet differently and, from there onward, simply subtract \(20\) feet from the height and determine integer division by \(10\) in order to know how many times we need to add \(\frac{1}{2}\) to both the numerator and the denominator of \(\frac{6}{7}\).

It is the "handle differently" for one case and the other which suggests the need to come up with a selection mechanism: it is necessary to distinguish between two cases and react to each accordingly. For Vitruvius’ column, if the column has a height \(a\) up to \(15\) feet, the ration between the top and the base is \(r=\frac{5}{6}\); if the height \(a\) is not less than \(15\) feet, the ration between the top and the base shall be:

\[r=\frac{6 + \lfloor\frac{a-20}{10}\rfloor\cdot\frac{1}{2}}{7 + \lfloor\frac{a-20}{10}\rfloor\cdot\frac{1}{2}}\]

As an example, let us consider a column with \(43\) feet. The integer division of \(43-20\) by \(10\) is \(2\) so we must add \(2\cdot{}\frac{1}{2}=1\) to the numerator and \(\frac{6}{7}\) to the denominator, and we will get \(\frac{7}{8}=0.875\).

As as for a second example let us consider the proposal made by Adolf Loos for the headquarters of the Chicago Tribune journal, a \(122\) meter-tall building with the shape of a doric column on top of a large base. The column alone would be \(85\) meters hight. Taking into account that a foot, in the Doric Order, measured \(324\) millimetres, the column would have \(85/0.324\approx 262\) feet. The integer division of \(262-20\) by \(10\) is \(24\). So the ratio between the top and the base of this hypothetical would then be \(\frac{6+24/2}{7+24/2}=\frac{18}{19}=0.95\). Because the value is close to the unit it shows that the column would be practically cylindrical.

Based on these considerations we can now define a function that, given an integer representing the column’s height in feet, computes the ration between the top and the base. Beforehand, however, it is convenient to simplify the formula for columns with heights not inferior to \(15\) feet. So:

\[r=\frac{6 + \lfloor\frac{a-20}{10}\rfloor\cdot\frac{1}{2}}{7 + \lfloor\frac{a-20}{10}\rfloor\cdot\frac{1}{2}}= \frac{12 + \lfloor\frac{a-20}{10}\rfloor}{14 + \lfloor\frac{a-20}{10}\rfloor}= \frac{12 + \lfloor\frac{a}{10}\rfloor - 2}{14 + \lfloor\frac{a}{10}\rfloor - 2}= \frac{10 + \lfloor\frac{a}{10}\rfloor}{12 + \lfloor\frac{a}{10}\rfloor}\]

The function’s definition would then be:

(define (shaft-top-radius base-radius height)
  (if (< height 15)
      (* 5/6 base-radius)
      (let ((divisions (quotient height 10)))
        (* (/ (+ 10 divisions)
              (+ 12 divisions))
           base-radius))))

This was the last expression that was missing in order to completely specify the drawing of a Doric column according to Vitruvius in his architectural treatise. Let us consider that we will supply the coordinates for the column’s base centre point and its height. All remaining parameters will be calculated in terms of these ones. The definition will be:

(define (doric-column p height)
  (define r-base-shaft (/ height 14))
  (define r-base-echinus (shaft-top-radius r-base-shaft height))
  (define a-shaft (* 13 r-base-shaft))
  (define a-echinus (* 2/3 r-base-shaft))
  (define a-abacus (* 1/3 r-base-shaft))
  (define l-abacus (* 13/6 r-base-shaft))
  (shaft p a-shaft r-base-shaft r-base-echinus)
  (echinus (+z p a-shaft) a-echinus r-base-echinus (/ l-abacus 2))
  (abacus (+z p (+ a-shaft a-echinus)) a-abacus l-abacus))

The following expressions produce the result shown in this figure:

Note that the column’s height should be given specified in feet.

(doric-column (xy 0 0) 10)
(doric-column (xy 10 0) 15)
(doric-column (xy 20 0) 20)
(doric-column (xy 30 0) 25)
(doric-column (xy 40 0) 30)
(doric-column (xy 50 0) 35)

Column variations according to Vitruvius proportions.

Finally it is worth mentioning that the functions column and doric-column represent two extreme cases: the first one models a column with many degrees of freedom, from the position to the measurements of the shaft, echinus and abacus, whereas the second only allows the position and height to be given. The function doric-column is in fact a particular case of function column so it can be defined in terms of it:

(define (doric-column p height)
  (define r-base-shaft (/ height 14))
  (define r-base-echinus (shaft-top-radius r-base-shaft height))
  (define a-shaft (* 13 r-base-shaft))
  (define a-echinus (* 2/3 r-base-shaft))
  (define a-abacus (* 1/3 r-base-shaft))
  (define l-abacus (* 13/6 r-base-shaft))
  (column p
          a-shaft r-base-shaft
          a-echinus r-base-echinus
          a-abacus l-abacus))

The functions column and doric-column are also a good example of a modelling strategy. Whenever possible, we should begin by defining the most general and unconstrained case, contemplating the highest number of degrees of freedom that are reasonable, and only then should we consider the particular cases, modelled with specific functions but which can naturally resort to the definition of the general case.

3.14.1 Exercises 22
3.14.1.1 Question 68

A careful look at the shaft-top-radius function shows there is a repeated fragment of code, namely the multiplication by the base-radius parameter. This suggests that it should be possible to come up with an even more compact version of this function. Define it.

4 Recursion

4.1 Introduction

We have seen previously that our functions, in order to do something useful, must call other functions. For example, if we already have the function that computes the square of a number and if we want to define the function that computes the cube of a number, we can easily do it by using the square and an additional multiplication, i.e.:

(define (cube x)
  (* (square x) x))

Similarly, we can define the function fourth-power in terms of the cube function and an additional multiplication:

(define fourth-power (x)
  (* (cube x) x))

Obviously, we can continue to define new functions to compute larger powers but this is a lengthy process and, moreover, it will always be limited. It would be much more useful if we were able to generalize this process and simply define the exponentiation function which, from two numbers (base and exponent) computes the first one raised to the power of the second one.

However, what we did for the fourth-power, the cube and the square gives us an important clue: if we have a function that computes the exponentiation with the immediately lower exponent, then we only need one additional multiplication to compute the exponentiation with the next exponent.

In other words, we have:

(define (power x n)
  (* (inferior-power x n) x))

Although we were able to simplify our power calculation problem, there is still one unanswered question: how can we calculate the power immediately below? The answer may not be obvious but once understood, it is trivial: the exponentiation immediately lower to the exponentiation of exponent n is the exponentiation to the power of \(n-1\). That implies that (inferior-power x n) is exactly the same as (power x (- n 1)). Based on this idea, we can rewrite the previous definition:

(define (power x n)
  (* (power x (- n 1)) x))

In spite of our ingenious solution this definition has a problem: regardless of the exponentiation we try to compute, we will never be able to get the a final result. In order to understand this problem it is simpler to consider a real case: let us try to calculate the third power of the number \(4\), i.e., (power 4 3).

For this, according to the power function definition, we will need to evaluate the following expression:

(* (power 4 2) 4)
\(\downarrow\)
(* (* (power 4 1) 4) 4)
\(\downarrow\)
(* (* (* (power 4 0) 4) 4) 4)
\(\downarrow\)
(* (* (* (* (power 4 -1) 4) 4) 4) 4)
\(\downarrow\)
(* (* (* (* (* (power 4 -2) 4) 4) 4) 4) 4)
\(\downarrow\)
(* (* (* (* (* (* (power 4 -3) 4) 4) 4) 4) 4) 4)

It is obvious that this process will never finish. The problem is due to the fact that we reduced the power calculation of a number raised to an exponent to the power calculation of this number raised to an exponent immediately below it, but we have not said in which situation we already have a simple enough exponent to which the solution is immediate. Which is the situation where this happens? We have seen that when the exponent is \(2\) the square function returns the correct answer so the case \(n = 2\) is sufficiently simple. However, it is possible to have an even simpler case: when the exponent is \(1\), the result is simply the base value. Finally, the simplest case of all: when the exponent is \(0\), the result is \(1\), regardless of the base value. This last case is easy to understand when we see that the evaluation of (power 4 2) (i.e., the forth power of four) is reduced to (* (* (power 4 0) 4) 4). For this expression to be similar to (* 4 4) it is necessary that the evalauation of (power 4 0) produces 1.

We are now capable of defining the power function correctly:

(define (power x n)
  (if (zero? n)
    1
    (* (power x (- n 1)) x)))

The previous example is an example of a recursive function, i.e., it is a function which is defined in terms of itself. In other words, a recursive function is a function that calls itself inside its own definition. This use is obvious when we "unwrap" the evaluation process for the (power 4 3):

(power 4 3)
\(\downarrow\)
(* (power 4 2) 4)
\(\downarrow\)
(* (* (power 4 1) 4) 4)
\(\downarrow\)
(* (* (* (power 4 0) 4) 4) 4)
\(\downarrow\)
(* (* (* 1 4) 4) 4)
\(\downarrow\)
(* (* 4 4) 4)
\(\downarrow\)
(* 16 4)
\(\downarrow\)
64

The recursion is the mechanism that allows a function to call upon itself during its own evaluation process. Recursion is one of the most important programming tools, so it is important we understand it well. Many apparently complex problems usually have surprisingly simple recursive solutions.

There are countless examples of recursive functions. One of the simplest is the factorial function that is defined mathematically as:

\[n!= \begin{cases} 1, & \text{if $n=0$}\\ n \cdot (n-1)!, & \text{otherwise} \end{cases}\]

The translation of this formula into Racket is straightforward:

(define (factorial n)
  (if (zero? n)
     1
     (* n (factorial (- n 1)))))

It is important to notice that for all recursive functions there is:

If we analyse the factorial function, the stopping criterion is the equality test to zero (zero? n), the immediate result is 1, and the recursive case is obviously (* n (factorial (- n 1))).

Usually, a recursive function is only correct if it has a conditional statement which identifies the basic case but this needs not be mandatory. Invoking a recursive function consists of successively solving simpler sub-problems until the simplest case of all is reached, for which the result is immediate. This way, the most common pattern to write a recursive function is:

Given this pattern, the most common errors associated with recursive functions are:

Note that a recursive function that works perfectly for the cases for which it was created can be completely wrong for other cases. The factorial function is an example: when the argument is negative, the problem’s complexity increases and becomes further away from the basic case:

(factorial -1)
\(\downarrow\)
(-1 * (factorial -2))
\(\downarrow\)
(-1 * (-2 * (factorial -3)))
\(\downarrow\)
(-1 * (-2 * (* -3 (factorial -4))))
\(\downarrow\)
(-1 * (-2 * (-3 * (* -4 (factorial -5)))))
\(\downarrow\)
(-1 * (-2 * (-3 * (* -4 (* -5 (factorial -6))))))
\(\downarrow\)

The most frequent error in a recursive function is when it never stops, either because the basic case in not correctly detected or, because the recursion does not decrease the problem’s complexity. In this case, the number of recursive calls grows indefinitely until the computer’s memory is exhausted. At this point, the program generates an error message. In Racket’s case this error is not entirely obvious because the evaluator only interrupts the evaluation, showing no results. Here is an example:

> (factorial 3)
6
> (factorial -1)
ERROR

It is very important to correctly understand the concept of recursion. Although, at first, it may be difficult to embrace fully its implications, recursion allows solving with great simplicity, apparently very complex problems.

4.1.1 Exercises 23
4.1.1.1 Question 69

The Ackermann function is set to non-negative numbers as follows: \[A(m, n) = \begin{cases} n+1 & \text{if $m = 0$} \\ A(m-1, 1) & \text{if $m > 0$ and $n = 0$} \\ A(m-1, A(m, n-1)) & \text{if $m > 0$ and $n > 0$}\end{cases}\] Define the Ackermann function in Racket.

4.1.1.2 Question 70

What is the value of:
  • (ackermann 0 8)

  • (ackermann 1 8)

  • (ackermann 2 8)

  • (ackermann 3 8)

  • (ackermann 4 8)

4.2 Recursion in Architecture

As we will see, in architecture recursion is also a fundamental concept. As an example, let us consider a ladder profile, as outlined in this figure and let us imagine that we intend to define a function called ladder that, given the point \(P\), the length \(c\) of the thread and the \(e\) height of each riser, and finally the number of steps \(n\), creates the stairs with the first riser starting at \(P\). Given these parameters, the definition of the function should start as:

(define (ladder p c e n)
  ...)

Profile of a ladder with \(n\) steps, with the fist step starting at the point \(P\), each step containing a thread \(c\) and a riser \(e\).

To implement this function we have to be able to decompose the problem in less complex sub problems and this is where recursion provides a great help: it allows us to decompose the drawing of a ladder with \(n\) steps into the drawing of a step followed by the drawing of a ladder with \(n-1\) steps, as presented in the diagram of this figure.

Decomposition of the design of a ladder of \(n\) steps into the design of a ladder of \(n-1\) steps. steps.

This means the function will be something like:

(define (ladder p c e n)
  ...
  (step p c e)
  (ladder (+xy p c e) c e (- n 1)))

To draw a step we can define the following function that creates the segments for the thread and riser:

(define (step p c e)
  (line p (+y p e) (+xy p c e)))

The problem now is that the ladder function needs to stop creating steps at some point. It is easy that when successively reducing the number of steps, that moment comes when we reach a point where that number is zero. Thus, when asked to draw a ladder with zero steps, the ladder function no longer needs to do anything. This means that the function should have the following form:

(define (ladder p c e n)
  (if (= n 0)
    ...
    (begin
      (step c e)
      (ladder (+xy p c e) c e (- n 1)))))

What is left to decide is what does the function produces as output when it reaches the stopping condition. As, in this case, what interests us is the side effect resulting from invoking the function, it is less relevant what it produces as a result so we will stipulate that it will produce #t to indicate all worked out well:

(define (ladder p c e n)
  (if (= n 0)
    #t
    (begin
      (step p c e)
      (ladder (+xy p c e) c e (- n 1)))))

To see a more interesting example of recursion in Architecture let us consider the Saqqara Pyramid, illustrated in this figure, built by the architect Imhotep in XXVII century b.C.. This step pyramid is considered to be the first pyramid in Egypt and the oldest monumental stone construction in the world, being composed of six progressively smaller mastabas, stacked on top of each other. Another way of looking at this step pyramid is a mastaba on top of which stands another smaller step pyramid.

The Saqqara steps Pyramid. Photography by Charles J. Sharp.

image

Formally, we can define a pyramid of \(n\) steps as a mastaba on top of which stands a pyramid of \(n-1\) steps. To complete this definition it must be said that when the last mastababa is created, the pyramid of \(0\) steps at the top is, actually, non-existent.

Thus, considering the illustration in this figure, if we consider that the centre of the base of the pyramid is the \(p\) position and the mastabas are several pyramid frustums, we can write:

Schematic step pyramid.

(define (step-pyramid p b t h d n)
  (if (= n 0)
    #t
    (begin
      (regular-pyramid-frustum 4 p b 0 h t)
      (step-pyramid (+z p h) (- b d) (- t d) h d (- n 1)))))

An approximate example of the pyramid of Saqqara would then be:

(step-pyramid (xyz 0 0 0) 120 115 20 15 6)

4.2.1 Exercises 24
4.2.1.1 Question 71

The above definition does not accurately reflect the geometry of the step pyramid of Saqqara because it has sloped surfaces between each mastaba, as can be seen in the following diagram where we compare the sections of the pyramid we defined (left) and to the actual pyramid of Saqqara (right):

Define a more rigorous version of the step-pyramid function which receives, in addition to the above parameters, the height of each slope. Experiment with different parameters for you to produce a model similar to the following one:

4.2.1.2 Question 72

The false arch is the oldest form of arch, formed by parallelepipeds arranged horizontally like steps, forming an opening that narrows towards the top, ending with a horizontal beam, as shown in the following diagram:

Assuming that the parallelepipeds have a square section measuring \(l\), the opening reduction is \(\Delta_e\), equal in every step, and that the point \(p\) is the arc’s centre point, define the false-arc function that, with the parameters \(p\), \(c\), \(e\), \(\Delta_e\) and \(l\), creates a false arc.

4.2.1.3 Question 73

Define the balanced-circles function that allows you to create any of the following illustrations:

(balanced-circles (xy 0 0) 1.2 0.3)
(balanced-circles (xy 3 0) 1.2 0.5)
(balanced-circles (xy 6 0) 0.9 0.6)
(balanced-circles (xy 9 0) 0.5 0.8)

Note that the circles have radius that are in a geometrical progression ratio of \(f\), with \(0 <f < 1\). That way, each circle (except the first one) has a radius that is the product of \(f\) by the radius of the largest circle in which it stands. The smallest circle has a radius that is greater or equal to \(1\). The function should have as parameters the centre point and the radius of the larger circle, and also the reduction factor \(f\).

4.2.1.4 Question 74

Consider the drawing of circles as shown in the following image:

Define a radial-circles function that given the coordinates the rotation centre \(p\), the number of circles \(n\), the \(r_0\) translation radius, the circle radius \(r_1\), the initial angle \(\phi\) and the angle increment \(\Delta\phi\), draws the circles as shown in the previous figure.

Test your function with the following expressions:

(radial-circles (xy 0 0) 10 1.5 0.3 0 (/ pi  5))
(radial-circles (xy 4 0) 20 1.5 0.3 0 (/ pi 10))
(radial-circles (xy 8 0) 40 1.5 0.3 0 (/ pi 20))

whose evaluation should generate the following image:

4.2.1.5 Question 75

Consider the design of symbolic flowers composed of an inner circle around which radial circles are arranged corresponding to the petals. These circles should be tangent to each other and to the inner circle, as shown in the following image:

(flower (xy 0 0) 1 10)

Define a flower function that receives only the flower’s centre point, the radius of the inner circle and the number of petals.

Test your function with the following expressions:

(flower (x 0.0) 1.0 10)
(flower (x 3.6) 0.4 10)
(flower (x 8.0) 2.0 20)

Their evaluation should generate the following image:

4.3 Debugging Recursive Programs

We saw in the Debugging section that errors in a program can be classified as syntactic or semantic errors. Syntactical errors occur whenever we write invalid phrases in that language, i.e., phrases that do not obey the grammar rules. Semantic errors are more complex than the syntactic in that they generally can only be detected during the program’s execution.

There are some semantic errors that can be detected before the program’s execution, but this detection depends strongly on the quality of the language implementation and its ability to anticipate the program’s consequences.

For example, if we try to calculate the factorial of a string we will have a semantic error, as shown in the following example:

> (factorial 5)
120
> (factorial "five")
zero?: contract violation
  expected: number?
  given: "five"

Obviously this last error has nothing to do with Racket’s grammar rules: the "sentence" on how to call the factorial function is correct. The problem is that it does not make sense to calculate the factorial of a string, because calculating factorials involves arithmetic operations and these do not apply to strings. Therefore, the error is related to the meaning of the written "sentence", i.e., with the semantics. It is then, a semantic error.

An infinite recursion is another example of a semantic error. We saw that if the factorial function is called with a negative argument, infinite recursion occurs. Consequently, if we use a negative argument, we will be making a semantic error.

Racket provides several mechanisms for detecting errors. One of the simplest ones is the trace form (provided by the racket/trace module) that allows the visualization of a function’s invocations. The trace receives the name of the functions to be analysed and changes these functions so as to write the successive calls with the respective arguments, as well as the result of the its invocation. The information given as the trace result is generally extremely useful for debugging functions.

For example, to visualize the call of the factorial function, consider the following definition:

#lang racket

(require racket/trace)

 

(define (factorial n)

  (if (zero? n)

     1

     (* n (factorial (- n 1)))))

 

(trace factorial)

and the following call:

> (factorial 5)

>(factorial 5)

> (factorial 4)

> >(factorial 3)

> > (factorial 2)

> > >(factorial 1)

> > > (factorial 0)

< < < 1

< < <1

< < 2

< <6

< 24

<120

120

Note that, in the previous example as a consequence of trace, the call of the factorial function appears aligned to the left side. Each recursive call appears slightly to the right, allowing the display of the recursion’s "depth", i.e., the number of recursive calls. The result returned by each call appears aligned in the same column of that call.

4.3.1 Exercises 25
4.3.1.1 Question 76

Trace the power function. What is the resulting trace of the (power 2 10) evaluation?

4.3.1.2 Question 77

Define a circles function capable of creating the illustration presented below:

Note that, the circles have radius that are in geometrical progression ration of \(\frac{1}{2}\). In other words, the smaller circles have half the radius of the adjacent larger circle. The smallest circles of all have a radius greater or equal to \(0.1\). The function should only have as parameters the centre and radius of the larger circle.

4.3.1.3 Question 78

Define the saw function that, given a point \(P\), a number of teeth, the length \(c\) of each tooth and the height \(a\) of each tooth, draws a saw, with the first tooth starting at \(P\) as presented in the following image:

4.3.1.4 Question 79

Define the lozenges function capable of creating the illustration presented below:

(lozenges (xy 0 0) 1.6 0.1)

Note that the dimensions of the lozenges have a geometrical progression ration of \(\frac{1}{2}\). In other words, the smaller lozenges have half the size of the largest lozenges at the tips of which they are centred. The smallest lozenges have a width greater or equal to \(1\). This function should only have as parameters the centre and width of the largest lozenge.

4.3.1.5 Question 80

Consider the stair outlined in the figure below, designed to overcome an slope \(\alpha\).

Define the stair-slope function that receives the point \(p\), the angle \(\alpha\), the length \(c\) and the number of steps \(n\) and builds the ladder described in the previous schema.

4.3.1.6 Question 81

Consider the ladder outlined in the figure below, designed to overcome a slope \(\alpha\).

Note that the steps’ dimensions have a geometric progression ration of \(f\), i.e., given a step with a length of \(c\), the step immediately above has a length of \(f \cdot c\). Define the geometric-progression-ladder function that receives the point \(P\), the angle \(\alpha\), the length \(c\), the number of steps \(n\) and the ration \(f\) and creates the ladder described in the previous schema.

4.4 Doric Temples

With Vitruvius we have seen that the Greeks created an elaborate proportion system for columns. These columns were used to form porticos, wherein a succession of columns crowned with a roof served as the entrance for buildings and, in particular, for temples. When this arrangement of columns was projected from the building it was called prostyle, and it was classified according to the number of columns in its composition as Diastyle, Tristyle, Tetrastyle, Pentastyle, Hexastyle, etc. When the prostyle was extended to the whole building, placing columns all around it, it was called peristyle.

In addition to describing the proportions of columns, Vitruvius also explained in his famous treaty the rules that the construction of temples had to follow, in particular, regarding their orientation, which should be from east to west. and regarding the spacing between columns, distinguishing several cases of temples from those with a very reduced spacing (pycnostyle) to temples with excessively large columns spacing (araeostilo), including the style which he considered to have the best proportion (eustilo) in which the spacing between columns is variable, being larger in the central columns.

To simplify our implementation we will ignore these details and,instead of distinguishing each style, we will simply consider consider the placement of columns distributed linearly in a particular direction, as sketched in this figure.

Temple’s floor plan with an arbitrary orientation

To this moment, we have considered coordinates as mere positions in space. Now, in order to model this temple, it will be useful to adopt a vectorial perspective of the concept of coordinates. In this perspective, coordinates are seen as the tips of vectors positioned at the origin. This can be seen in this figure where we have marked the position of two columns with the vectors \(P\) and \(Q\).

With all vectors being positioned at the origin it becomes irrelevant to mention it, which allows us to characterize vectors as having only a magnitude and a direction. It is easy to see that this magnitude and direction are precisely the polar coordinates of the vector’s end, i.e., the distance from the origin to the tip of the vector and the angle that the vector makes with the \(X\) axis.

The great advantage of adopting the vectorial perspective is that it enables us to conceive an algebra for operating with vectors. For example, the sum of vector is a vector whose components are the sum of corresponding components, i.e., \[P + Q = (P_x + Q_x, P_y + Q_y, P_z + Q_z)\]

Similarly, we can define the subtraction of vectors as \[P - Q = (P_x - Q_x, P_y - Q_y, P_z - Q_z)\] and the multiplication of a vector with a scalar \(\alpha\): \[P\cdot\alpha=(P_x\cdot\alpha,P_y\cdot\alpha,P_z\cdot \alpha)\]

Finally, the division of a vector by a scalar can be defined in terms of the multiplication by the scalar’s inverse value, i.e., \[\frac{P}{\alpha} = P\frac{1}{\alpha}\]

These operations are presented in this figure for the bi-dimensional case.

Algebraic operations using vectors.

Translating these definitions for Racket is straightforward. Since we are creating algebraic operations for coordinates, we shall name them by combining the names of the arithmetic operators with the letter "c" (of "coordinates").

These operations are pre-defined in Racket.

(define (+c p0 p1)
  (xyz (+ (cx p0) (cx p1))
       (+ (cy p0) (cy p1))
       (+ (cz p0) (cz p1))))
 
(define (-c p0 p1)
  (xyz (- (cx p0) (cx p1))
       (- (cy p0) (cy p1))
       (- (cz p0) (cz p1))))
 
(define (*c p a)
  (xyz (* (cx p) a)
       (* (cy p) a)
       (* (cz p) a)))
 
(define (/c p a)
  (*c p (/ 1 a)))
4.4.1 Exercises 26
4.4.1.1 Question 82

A unit vector is a vector of unitary magnitude. Define the unit-vector operation that given any vector calculates the unit vector with the same direction as the given one.

4.4.1.2 Question 83

The symmetric vector of a \(\vec{v}\) vector is the vector \(\vec{v}^\prime\), such that \(\vec{v}+\vec{v}^\prime=0\). In other words, is the vector with equal magnitude but opposite direction. Define the symmetric-vector operation that given any vector calculates the symmetric vector.

Returning to the problem of positioning columns in the temple, illustrated in this figure. Given the orientation and separation vector \(\vec{v}\) of columns, from the position of any column \(P\), we determine the position of the next column through \(P+\vec{v}\). This reasoning allows us to first define a function to create a row of columns. This function will have as parameters the coordinates \(P\) of the base of the first column, the height \(h\) of the column, the vector \(\vec{v}\) separating the axes of the columns and also the number \(n\) of columns that we wish to create. The reasoning behind the definition of this function is, once more, recursive:

The translation of this process to Racket we have:

(define (doric-columns p h v n)
  (if (= n 0)
    #t
    (begin
      (doric-column p h)
      (doric-columns (+c p v)
                     h
                     v
                     (- n 1)))))

We can test the creating of columns using, for example:

(doric-columns (xy 0 0) 10 (xy 5 0) 8)

of which result is presented in this figure.

A perspective of a set of eight Doric columns with \(10\) units of height and \(5\) spacing units between columns along the \(x\) axis.

4.4.1.3 Question 84

Although the use of separation vectors between columns is relatively simple, it is possible to simplify that process even further by calculating the vector value based on the start and end points of the row of columns. Using the doric-columns function, define a function called doric-columns-between that given centre points \(P\) and \(Q\) of the first and final columns, the height \(h\) of the columns and finally the number of columns, creates a row of columns between those two points.

As an example, the following image shows the result of evaluating the following expressions:

(doric-columns-between (pol 10 0.0) (pol 50 0.0) 8 6)
(doric-columns-between (pol 10 0.4) (pol 50 0.4) 8 6)
(doric-columns-between (pol 10 0.8) (pol 50 0.8) 8 6)
(doric-columns-between (pol 10 1.2) (pol 50 1.2) 8 6)
(doric-columns-between (pol 10 1.6) (pol 50 1.6) 8 6)

From the moment we know how to create rows of columns, it becomes easy to create the four necessary rows for building peristyle temples. Normally, the description of these temples is done in terms of the number of columns at the front and at the side, assuming that the columns oat the corners count for both rows. This means that, for example, a temple with \(6 \times 12\) columns there are actually only \(4 \times 2 + 10 \times 2 + 4 = 32\) columns. For creating the peristyle, besides the number of columns at the front and side, we need to know the position of the columns at the extremities of the temple and obviously the column’s height.

In terms of the algorithm, we start by creating one of the corners of peristyle:

(define (doric-peristyle-corner p height v0 n0 v1 n1)
  (doric-columns p height v0 n0)
  (doric-columns (+c p v1) height v1 (- n1 1)))

Note that, in order to avoid repeating columns, the second row must start at the second column and consequentially one less column must be placed.

To build the complete peristyle we only have to create one corner and then build another corner with one less column on each side, progressing in opposite directions.

(define (doric-peristyle p height v0 n0 v1 n1)
  (doric-peristyle-corner p height v0 n0 v1 n1)
  (doric-peristyle-corner
    (+c p (+c (*c v0 (- n0 1)) (*c v1 (- n1 1))))
    height
    (*c v0 -1) (- n0 1) (*c v1 -1) (- n1 1)))

A realistic example is the temple of Segesta, represented in this figure. This temple is of the peristyle type, composed of \(6\) columns (i.e., Hexastyle) at each front and \(14\) columns at the side, a total of \(36\) \(9\) meters high columns. The distance between the columns axes is approximately \(4.8\) meters at the front and \(4.6\) meters at the sides. The expression that creates the peristyle of this temple is then:

(doric-peristyle (xy 0 0) 9 (xy 4.8 0) 6 (xy 0 4.6) 14)

The result of evaluating the above expression is shown in this figure.

An overview of the peristyle of the temple of Segesta. The columns were generated by the peristyle-doric function using as parameters, \(6\) columns on the front and \(14\) on the side, with a column distance of \(4.8\) meters on the front and \(4.6\) meters on the sides, with columns \(9\) meters high.

Although the vast majority of Greek temples were rectangular, circular temples were also built, called Tholos. The Sanctuary of Athena Pronaia at Delphi has a good example of one such buildings. Although little remains of this temple is not difficult to imagine its original shape based on what is still remains, shown in this figure.

The Temple of Pronaia in Delphi, built in IV century b.C.. Photography by Michelle Kelley.

image

To simplify the construction of the Tholos temple, we will divide it into two parts. In one of them we will create the base and on the second one we will position the columns.

For designing the base we can consider a set of flattened cylinders, stacked to form the circular steps, as shown in this figure. Thus, the total base height \(a_b\) will be divided in steps of \(\Delta a_b\) and the base radius will also be divided in \(\Delta r_b\) steps.

A Tholos base section. The base is composed by a sequence of stacked cylinders whose base radius \(R_B\) shrinks \(\Delta r_b\) each step and whose height grows in increments of \(\Delta a_b\) in every step.

For each cylinder we have to consider its radius and the d-height of each step. To draw the next cylinder we have also to consider the radius increment \(d-radius\) due to the step’s length. These steps will be built using a recursive process:

This process is implemented by the following function:

(define (base-tholos p n-steps radius d-height d-radius)
  (if (= n-steps 0)
    #t
    (begin
      (cylinder p radius d-height)
      (base-tholos (+xyz p 0 0</