zeno · 2019. 2. 5. · contents prologue 1 introduction 2 lists - programming style; primitive...

133
ZENO a thinking tool for mathematics Fred McBride June 2012

Upload: others

Post on 02-Aug-2021

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

ZENO

a thinking tool for mathematics

Fred McBride

June 2012

Page 2: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Contents

Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing in 2-d and 3-d space; a delay

function (simple animation) - with some demonstrations 4 Simultaneous Equations - matrix operations; use of \ (under); find the centre and

radius of the circumcircle for 3 given points 5 Graphs - a simple graphing function with examples 6 Circles - draw circles using chords (ie Logo polygons); using ‘graphing’

technique with cartesian and parametric coordinates; and draw the circumcircle for 3 given points

7 Conic Sections - draw ellipses, parabolas and hyperbolas with cartesian and

parametric coordinates 8 Linear Transforms - 5 built-in transforms with examples of use; serial

composition; the ‘maths’; and building your own transforms 9 Complex Plane - non-linear transforms; draw circles, spirals and other shapes 10 Vectors - vector operations; draw circles using chords (but with centre and radius) 11 Loci - re-draw conic sections as loci 12 3-2-d Space - draw wireframe and solid shapes in 3-d and project to 2-d space 13 2-3-2-d Space - map 2-d grids to 3-d then project back to 2-d space 14 Trees - 2- and 3-branch trees in 2-d space; 2- and 4- branch trees in 3-2-d space 15 Fractals - line curves in 2-d space; triangles and quadrilaterals in 2-d space; and

pyramids and cuboids in 3-d space Other possible topics include – Dependent Actions, Waves, Random Walks, Tessellations and Graphical

Projection

Page 3: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1 .zno (text) files for sections above

lists.zno utils.zno simeqs.zno graphs.zno circles.zno conics.zno linear.zno complex.zno vectors.zno loci.zno 3-2-dspace.zno 2-3-2-d1.zno views and surfaces 2-3-2-d2.zno sphere .. Klein bottle trees.zno frac1.zno line curves frac2.zno 2-d and 3-d shapes

In development

- depact.zno chases and collisions - waves.zno harmonic (sine and cosine) waves, composition - rwalks.zno in 2-d and 3-d - tess.zno tiling - gproj.zno parallel and perspective

Page 4: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Prologue For a long time, the extent to which language mediates or structures thinking has been an important question for philosophers, psychologists, linguists and anthropologists, and now (even) computer scientists are also thinking about it. Views vary widely from no effect – Chomsky posits that there are universal concepts existing independently of language, which echoes Plato’s contention that thought and language have meaning stemming from abstract concepts called ‘forms’ – to the view that language determines thought and that linguistic categories limit and determine cognitive categories, which is the strongest form of the Sapir-Whorf Hypothesis of Linguistic Relativity – with others broadly supporting Vygotsky’s intermediate position that the structure of the language we habitually use influences the way we perceive our environment. Creators of computer programming languages are now engaged – Iverson (APL) considered notation as a tool of thought and concluded that more powerful notations aid thinking about computer algorithms, and Matsumoto (Ruby) acknowledged that the Sapir-Whorf Hypothesis influenced his design. My own experience of 49 years of writing and observing others writing computer programs across a wide variety of languages supports the Vygotsky position. Almost without exception, the design of a programming solution is strongly influenced by the language its writer expects to use in its implementation. But, from theoretical Computer Science, we learn that programming and reasoning are isomorphic. Learning to program is learning to reason. Is it that our language imposes a conceptual framework on our thinking without our noticing it? If so, what if the language to be used is prescribed? – say, mathematics? So far, the question has been posed as how does language affect thinking, but what if the question is inverted to ask how do concepts affect language? While this enquiry may not seem relevant to disciplines engaged with the study of the external, sounds and symbols of natural language to gain some insight to the internal, mental activities of thinking, it arguably should be of interest to designers of computer programming languages that seek to be considered as tools for thinking about particular concepts – say, conceptual programming languages? While general purpose programming languages, built mainly on the foundation of machine architectures, are clearly not designed for this purpose it could be argued that domain specific languages already exist to address these requirements. But, such language systems mainly deliver already packaged features to assist work in their domains rather than to enable the investigation of their underlying concepts. So, the target area is the gap between general purpose and domain specific, and the objective is to assist conceptual understanding by building the functionality for a particular data domain using certain definitional formalisms and a base set of pre-defined (aka built-in) functions – cf Peano’s axioms (see # ??) using 2 formalisms with a base set of 2 functions to build all possible functions for the domain of natural numbers, or McCarthy’s (pure) Lisp starting from 2 formalisms and 5 functions to build all functions for his domain of S-expressions. Vygo is a conceptual programming language designed (by my son Conor) to be a thinking tool for mathematics. We believe that it is possible to achieve transfer of mathematical skills and understanding of mathematical concepts from computer programming, but only by using a language capable of representing the processes involved in mathematically meaningful ways. Vygo starts from Logo, whose simplicity of linear movements relative to the current position and direction of its turtle enables easy first access to Euclidean Geometry. But, its

Page 5: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

lack of any coordinate system and its limited language constructs make it incapable of representing any higher order mathematical process except in the most obscure and opaque fashion, thus making transfer at best improbable. So, we have provided a multi-dimensional coordinate system, additional base and structured number types – although Vygo is an untyped language like Logo – and restored some of the elements of functional programming which were removed from Lisp when Logo was created in the first place. Vygo can pass functions as arguments and compute them as results; Vygo can apply functions to figures; Vygo uses functional scope to implement multiple turtles; Vygo can compose functions in sequence and in parallel; Vygo functions can accept their arguments one at a time. Vygo is as accessible as Logo in that it contains Logo, without compromising its existing syntax or features. However, as Logo reaches the limits of its expressive capability, and hence the limits of the transferable mathematical skills its students can acquire, Vygo is only getting started.

Fred McBride

June 2012 PS It is probably obvious that the name Vygo is derived from Vygotsky, but I only just managed to restrain myself from using the name Vygot if only to facilitate the slogan -

Have Vygot maths for you!

Page 6: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Introduction

1 Introduction A detailed description of Zeno is given in the books – The Zeno Programming Language and The Zeno System Guide – but, here we will present briefly two aspects that enable Zeno to offer greater scope for representing higher order mathematical processes. The first aspect concerns data types. Zeno has two base data types, viz words and numbers, and two structured data types, viz lists and matrices. Vectors are treated as special types of matrices, and complex numbers are represented as 2-element column vectors. The list is the only general purpose data type in Zeno, and a small but comprehensive set of functions for list manipulation is provided. Similarly, functions are provided for complex numbers, vectors and matrices, including the introduction of a new infix operator, \, called ‘under’. The second aspect and the most important new feature introduced by Zeno is the concept of context functions. It enables the creation and manipulation of multiple turtles, and the linear and non-linear transformations of all turtle-related movements to be described in an easily understood and accessible manner. It supports the (sequential and parallel) composition of functions enabling complex contexts to be built from their simpler components. The ability of Zeno functions to accept their arguments one at a time combined with the prompt facility enables interactive investigations to be undertaken within layered scopes. The ensuing sections will demonstrate some examples of the use of these Zeno features to explore well-known mathematical applications. The treatment is not intended as a mathematical teaching text and is certainly not comprehensive but is merely illustrative of Zeno’s expressive capability when addressing these mathematical concepts.

Page 7: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Lists

2 Lists The list is the only general purpose data type in Zeno, and a small but comprehensive set of functions for list manipulation is provided. These functions are defined and explored in The ZENO Programming Language. In this section, their use will be illustrated in the development of some set operations as a series of recursive functions. But, first we introduce this style of programming in another domain, viz the natural numbers. A function is said to be recursive if it calls itself as part of its definition. This leads to a particular form of definition where the terminating conditions are described first, followed by the production statements, which must modify one or more of the arguments in a way that will eventually cause a terminating condition to be satisfied. A good example of this style of programming is a variant of the primitive recursive functions (aka Peano’s Axioms). In this exercise, the domain is the natural numbers, ie 0, 1, 2, 3, … and we have only 2 base functions, a successor function (succ) and a predicate test for equality (eq)

where succ x => x+1 and eq x y => true if x=y else false and our task is to build all other possible functions in this domain starting only with these base functions and using only (serial) composition, simple conditionals (ie if .. then statements but without else) and recursion. In Zeno, we define eq and succ as follows.

> to eq :x :y : :x=:y : end eq > to succ :x : :x+1 : end succ > eq 2 2 true > eq 1 2 false > succ 0 1 > succ 3

4 Now, we will define functions for predecessor, sum, difference, product, less than and quotient.

> to pred :x : to p1 :n :x define an auxiliary function p1 local to pred : if eq (succ :n) :x [val :n] if counter n is 1 less than x then n is the pred of x : p1 (succ :n) :x else increment counter n and try again

Page 8: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Lists

: end : if eq :x 0 [val 0] pred of 0 is 0 because naturals have no negatives : p1 0 :x else invoke p1 with counter n initialised to 0 : end pred ie set n=0, then keep adding 1 to n until n+1=x > pred 5 4 > to sum :x :y : if eq :x 0 [val :y] 0 + y = y else sum is (x-1) + (y+1) : sum (pred :x) (succ :y) ie reduce x by 1 each time until it becomes 0 : end while adding 1 to y sum > sum 3 4 7 > to diff :x :y : if eq :y 0 [val :x] x – 0 = x : if eq :x 0 [val 0] 0 – y = 0 because natural numbers have no negatives : diff (pred :x) (pred :y) else (x-1) – (y-1) : end diff > diff 7 2 5 > to mult :x :y called mult rather than prod to avoid confusion with pred : if eq :x 0 [val 0] x*0 = 0 : sum :y (mult (pred :x) :y) x*y = y + (x-1)*y : end mult > mult 3 4 12 > to lessthan :x :y need lessthan not only for itself but to be used in quot : if eq :y 0 [val :false] NB the order of tests for 0 is important : if eq :x 0 [val :true] : lessthan (pred :x) (pred :y) subtract 1 from x and y until one is 0 : end lessthan > lessthan 2 3 true > lessthan 3 3 false > lessthan 3 2 false > to quot :x :y : if lessthan :x :y [val 0] x/y = 0 for x<y : succ (quot (diff :x :y) :y) x/y = (x-y)/y + 1 for x≥y : end quot > quot 12 3

Page 9: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Lists

4 > quot 11 3 3 > quot 2 3 0

You may wish to continue with (say) remainder, factorial, highest common factor etc and predicates for greater than, even, odd, prime etc. While this programming exercise might be described as ‘academic’, please note that it cannot be achieved without a thorough understanding of the mathematical concepts being addressed. Now, consider some common operations in handling sets, viz testing for membership of a set, and forming the unions and intersections of sets. We use lists to represent sets. Consider a function, mem, that tests if some element i appears in the list x.

> to mem :i :x : if null :x [value :false] if list x is empty, i cannot be in it, so value is false : if :i=:x#1 [value :true] if i appears as the first element of x then value : mem :i :x#-1 is true else try mem again with i and x#-1 : end ie list x with its first element removed mem > mem 'c [a b c] so, c is a member of [a b c] true > mem 'd [a b c] and d is not a member of [a b c] false > mem [b c] [a [b c] d] but [b c] is recognised as a member of [a [b c] d] true as the = test can be used with non-atomic data

This recursive function definition has two stopping conditions and a re-entry line to scan the list x from left to right. The latter is a common feature in list manipulations and is sometimes referred to as ‘tail’ recursion. Now, using mem, the functions union and inter may be defined.

> to union :x :y : if null :x [value :y] : if mem :x#1 :y [value union :x#-1 :y] : list [:x#1],union :x#-1 :y comma , is an infix concatentation operator : end union > union [a b c d] [a c e] [b d a c e] > to inter :x :y : if null :x [value []] : if mem :x#1 :y [value (list [:x#1],inter :x#-1 :y)] : inter :x#-1 :y : end inter

Page 10: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Lists

> inter [a b c d] [a c e] [a c]

In both of these functions, tail recursion is used to step through the first argument x until it becomes empty. Each element is tested for membership of the second argument y, and action taken to form the union or intersection as appropriate. Now, you may wish to define the difference of 2 sets, and some comparisons, say, equal, notequal and subset. There are many examples of the use of this style of programming with recursive functions in the ensuing sections of this document. This style encourages the use of (normally short) functions each capturing a single concept in a clear fashion by using concepts already established, and, in turn, each being used to build up a more comprehensive set of concepts for their domain of application. It is the recognition that this style of programming aligns exactly with conventional mathematical reasoning that makes this approach our chosen basis of a conceptual programming language for a thinking tool for mathematics.

Page 11: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Utilities

3 Utilities Before starting on our mathematical journey, we introduce a graphics font and some utility functions designed to aid the presentations to follow. The definitions are available in the file utils.zno, listed in Appendix 1. NB See The Zeno System Guide for explanations of the use of the Start button (or Ctrl/R) for ‘loading’ function definitions and the Step button (or Ctrl/Enter) for line-by-line execution of a ‘program’.

delay :n // used to slow step-wise execution to enable simple animation line :p1 :p2 :col // draw line between 2 points in 1-d, 2-d, 3-d .. join :plist :col // join points from list [p..p] where points may be 1-d, 2-d, 3-d .. filltri :a :b :c :col // draw triangle defined by points a, b, c filled with col(our) fillquad :a :b :c :d :col // draw quadrilateral defined by a, b, c, d filled with col(our) axes :x1 :x2 :y1 :y2 :col // draw 2-d axes (x1..x2) x (y1..y2) markaxes :x1 :x2 :sx :y1 :y2 :sy :col

// mark 2-d axes in steps of sx and sy grid :blh :w :sx :h :sy :col

// draw 2-d grid of w(idth) x h(eight) at blh (bottom left hand corner) with step sizes sx and sy

box :blh :w :h :col // draw box w x h at blh gpaper :s // 2-d draw graph paper (-s..s) x (-s..s), 1 x 1 in grey, 5 x 5 in blue, axes in red gwrite :strlis :p :s :col // starting at point p, write ‘string’ in strlis, scaled by s, and in colour col gfont - is local to gwrite but note that font could be made a parameter of gwrite and so

enable other fonts to be defined (globally) and then select one for gwrite-ing // font for writing to graphics window // list of character definitions [[char, width, list(s) of points] .. ] oblique :a :s // oblique projection from 3-d to 2-d, z-lines at angle a, scaled by s grid3 :blh :w :sx :h :sy :d :sz :col // draw 3-d grid w x h x d at blh in steps of sx, sy and sz box3 :blh :w :h :d :col draw 3-d box w x h x d at blh cube :blh :s :col draw cube with side s at blh axes3 :x1 :x2 :y1 :y2 :z1 :z2 :col // 3-d axes (x1..x2) x (y1..y2) x (z1..z2)

Demos of selected utilities follow – starting with the programmer’s traditional global greeting, then displays of the graphics font, graph paper and a 3-d grid.

Page 12: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Utilities

> cs clear screen and then write Hello World in black at (-110|-150) and scaled by *5 > gwrite [H e l l o $ W o r l d] (-110|-150) 5 :black

repeat in red still at (-110|-150), > rl (0|0) 90 then rotate left through 90o about (0|0) : gwrite [H e l l o $ W o r l d] (-110|-150) 5 :red > rl (0|0) 180 again but in blue with a left rotation of 180o : gwrite [H e l l o $ W o r l d] (-110|-150) 5 :blue > rr (0|0) 90 and again in green with a right rotation of 90o : gwrite [H e l l o $ W o r l d] (-110|-150) 5 :green // screen 1 > cs clear screen and display characters of gfont in black and *4 > gwrite [A B C D E F G H I J K L M N O P Q R S T U V W X Y Z] : (-250|20) 4 :black upper case alphabetic > gwrite [a b c d e f g h i j k l m n o p q r s t u v w x y z] : (-250|70) 4 :black lower case alphabetic > gwrite [0 1 2 3 4 5 6 7 8 9] (-200|120) 4 :black digits 0..9 > gwrite [lpr rpr lbk rbk lbc rbc lam ang $ : ovr und mi pl eq neq gt gte ls lse] : (-200|170) 4 :black brackets, infix operators and others // screen 2

NB The brackets etc must be assigned ‘labels’ as identifiers, eg lpr for left parenthesis, because either their usual symbols have reserved and fixed meanings in Zeno or are required to enable parsing of user input. But, it is quite simple to add new characters as required, eg Greek characters such as θ (theta) or φ (phi).

> cs ht clear screen and hide turtle > 15 * gpaper 20 20x20 graph paper scaled by *15 // screen 3 > cs clear screen – turtle still hidden > xl (-280|-250) xl .. is context for the block of commands in ( ) : ( oblique 30 1/2 oblique .. is context for an inner nested block also in ( ) which : ( grid3 (0|0|0) 400 100 400 100 400 100 :darkgrey draws a 3d grid : axes3 0 450 0 450 0 450 :lightblue ) and 3d axes : gwrite [x] (460|0) 4 :black back in the outer block to label the axes x, y and z

Page 13: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Utilities

: gwrite [y] (0|460) 4 :black NB start point for z label is oblique .. (0|0|460) : gwrite [z] oblique 30 1/2 (0|0|460) 4 :black ) // screen 4

In the gwrites above, we only used oblique with the 3d point for the z label. oblique s a changes any 3d point (x | y | z) to the 2d point (x+s*z*cos a | y+s*z*cos a). But z = o for the x and y labels and any (x | y | 0) simply becomes (x | y). Further, when x = 0 and y = 0, oblique s a (0 | 0 | z) becomes (s*z*cos a | s*z*sin a). So, given s = ½ and a = 30, we might have written the z label start point as (230*cos 30 | 230*sin 30). It might seem attractive to write all the label start points as 3d and bring the gwrites within the scope of the outer oblique, but this is not possible as the first argument of gwrite is a list of 2-d points defining the shape of the characters to be displayed.

Page 14: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Simultaneous Equations

4 Simultaneous Equations Here we explore the solution of simultaneous equations not only for its own mathematical interest but also as a context to introduce some of Zeno’s vector and matrix operations, including a new infix operator, \, named ‘under’ - ie ‘a\b’ is ‘a under b’ - while ‘a/b’ is ‘a over b’. A system of n equations in n unknowns can be written as

A x = v where A is the (n x n) matrix of coefficients, x is the column vector of unknowns, and v is the column vector of values. Pre-multiplying both sides by A-1 yields

A-1 A x = A-1 v I x = A-1 v x = A-1 v Consider a simple example of two equations in two unknowns

2x + y = 5 x - 2y = 0

Appropriate Zeno sessions might be

> ‘A<-(2,1|1,-2) an assignment statement; both sides are evaluated A and outcome is value of the lhs (left-hand side) > ‘v<-(5|0) v > ‘x<-(inv :A)*:v compute A-1 using system supplied function x inverse or its abbreviation inv > :x inspect x to see its current value (2|1) which is (2|1)

or > ‘IA<-:A^-1 assign the inverse of A (computed using ^-1) to IA IA > :IA inspect IA to see the inverse of A (0.4,0.2|0.2,-0.4) > :IA*:v and multiply IA and v to get x (2|1)

or simply > (2,1|1,-2)\(5|0) use Zeno’s \ (under) operator directly (2|1)

Page 15: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Simultaneous Equations

and see that all of these methods deliver (x|y) = (2|1). Note the use of \ (under) in the last method above. When used with matrices, \ inverts its first argument and then multiplies with its second argument, ie

x = A \ v is equivalent to x = A-1 v

While it may be obvious that the column vector (2|1) decomposes to yield x = 2 and y = 1 as the solution to the given simultaneous equations, the components of any column vector may be selected using the appropriate vector scalar products, eg

> (1|0).(2|1) 2 > (0|1).(2|1) 1

Now consider a marginally more difficult problem with three unknowns

x + 4y - 5z = 8 2x + 3y + z = -1 3x - y + 2z = 3

> (1,4,-5|2,3,1|3,-1,2)\(8|-1|3) (2|-1|-2)

so x = 2, y = -1 and z = -2. Another example this time with four unknowns

3a + b - 2c - d = 6 2a - b + c + 2d = 5.5 a -3b + 4c + 3d = -1 2a + b + 2d = 11.5

> (3, 1,-2,-1 matrix input over 4 lines to improve legibility : |2,-1, 1, 2 : |1,-3, 4, 3 : |2, 1, 0, 2)\(6|5.5|-1|11.5) (1.5|2.5|-1|3)

so a = 1.5, b = 2.5, c = -1 and d = 3. As a final example, consider the problem of finding the centre and radius of the (unique) circumcircle for any three given 2-d points. The general equation for a circle is x2 + y2 + fx + gy + h = 0

rewrite as xf + yg + h = -(x2 + y2) substitute (x|y) values from the 3 given points to generate simultaneous equations in f, g and h; solve to find f, g and h; then centre = (-f/2|-g/2) and radius = ½√(f2 + g2 - 4 h).

Page 16: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Simultaneous Equations

> to circum :p1 :p2 :p3 : to x :p (1|0).:p end define local functions to enable selection of coeffs of : to y :p (0|1).:p end matrix A and to compute the elements of vector v : to v :p (-((x :p)*(x :p)+(y :p)*(y :p))) end : local 'fgh (x :p1, y :p1, 1 solve the simultaneous equations for f, g and h : |x :p2, y :p2, 1 and assign solution vector to local variable fgh : |x :p3, y :p3, 1)\(v :p1|v :p2|v :p3) : local 'f (1|0|0).:fgh select values of f, g and h from fgh : local 'g (0|1|0).:fgh again using the vector scalar product operator : local 'h (0|0|1).:fgh : local 'c (-:f/2|-:g/2) compute centre c and radius r : local 'r 2\sqrt :f*:f + :g*:g - 4*:h note use of \ : pr 'centre sp 1 prln :c and print to allow inspection : pr 'radius sp 1 prln :r : end circum > circum (-15|-10) (-5|-10) (-10|-5) centre (-10|-10) radius 5

To draw the circumcircle, complete the function by using one of the several methods described (later) in Circles for drawing a circle given its centre and radius, but first we consider graph drawing.

Page 17: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Graphs

5 Graphs We wish to draw graphs to represent y = f(x) for a given range of x. To make our graphs meaningful, we will show them against a background of x- and y-axes and grids to represent ‘graph paper’. So, load the needed functions from utils.zno:

line :p1 :p2 :col coloured line from p1 to p2 axes :x1 :x2 :y1 :y2 :col coloured axes x1..x2, and y1..y2 grid :x1 :x2 :sx :y1 :y2 :sy :col grid of coloured lines x1..x2 (sx) and y1..y2 (sy) gpaper :s graph paper: grey 1x1, blue 5x5, and red axes gwrite :strlis :p :s :col write strlis to graphics window starting

at point p, scaled by s and in col(our)

Now, we need the graph drawing function. > to graph :f :x1 :x2 :col : turtle :x1 1 :true :col 0 a 1-d turtle starts at x1 and moves to x2 along : ([:x]->'(:x|f :x)) the x-axis, mapping each x to a point (x, f(x)) : move :x2 ie draw the graph for y = f(x) for x = x1..x2 : end graph

Notice that the function, f, to be graphed is passed as an argument. Time to draw some graphs.

> cs > ht > 'y<-:([:x]->'((:x+7)*(:x+2)*(:x-6)/10)) y = f(x) = (x+7)(x+2)(x-6)/10 y > 15* prompt prompt context of 15* ie all subsequent drawings enlarged by 15 about (0|0) :> gpaper 20 40 x 40 graph paper :> graph :y -9 9 :green now draw graph for y from -9..9 in green :> graph :([:x]->'(:x^3-3*:x^2-:x+3)) -3 5 :black :> and x3 – 3x2 – x + 3 from -3..5 in black then

blank line forces exit from (1 level of) prompt-ing >

Note that the function in the second graph is un-named, or, in Zeno-speak, anonymous.

Page 18: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Graphs

> 'trig <- assign a block of commands to trig : '( cs to draw sin, cos and tan graphs : grid (-180|-200) 360 45 400 50 :lightgrey : axes -230 230 -250 250 :darkgrey within a grid with labelled axes : gwrite [X] (240|-8) 3 :black : gwrite [Y] (-6|260) 3 :black : gwrite [mi 1 8 0] (-200|-15) 2 :black : gwrite [mi 9 0] (-105|-15) 2 :black : gwrite [0] (5|-15) 2 :black : gwrite [9 0] (83|-15) 2 :black : gwrite [1 8 0] (170|-15) 2 :black : graph :([:x]->'(200*sin :x)) -180 180 :blue blue sine graph : graph :([:x]->'(200*cos :x)) -180 180 :green green cosine : graph :([:x]->'(200*tan :x)) -180 180 :red ) and red tan trig > trig draw without scaling > 1/2 * trig scale to ½ size

Page 19: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Graphs

> 1/10 * trig scale to 1/10 size > 1/100 * trig and finally to 1/100 size

Firstly, note that we assigned a block of commands to a ‘variable’ called trig – and then invoked trig with different scaling from none to 1/100. We could equally well have defined a function trig of no arguments, but the body of such a function would be the same block of commands. But, why re-display the graphs with different scalings? – answer – to observe the behaviour of the tan function at ±900 and Zeno’s treatment of these singularities. tan x = sin x / cos x, at ±900 cos x = 0, so tan x = ∞ As x moves from -180 to 180, it goes through -90 and later 90, and at both points cos x = 0. So, Zeno must encounter an instruction to divide by zero – but, no error is generated and the graph continues past these singularities. In drawing contexts and only in such contexts, Zeno will trap these ‘errors’ and work past them.

> 10/0 Error: ARITH-div-zero

This elegant definition not only clearly captures the (mathematical) essence of a graph but also suggests a possible approach to drawing other figures – and, we will start with circles.

Page 20: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Circles

6 Circles Here, we begin to explore the circle in terms of its fundamental properties, viz centre and radius, and its common mathematical representations, viz cartesian and parametric coordinates. To create a calibrated drawing background, we again use gpaper (needs axes, grid and line), which may be loaded from utils.zno. The circle is the best known conic section – it is also the only one which most Logo users attempt to draw. But what is a circle? It may be defined as a planar figure whose boundary (circumference) comprises all points at equal distance (radius) from a fixed point (centre). So, fundamental to the (mathematical) understanding of a circle are the concepts of centre and radius. But, the common Logo representation of a circle is as an n-sided polygon with each side of length l.

> to circle :l :n :col : spc :col set pen colour to given col : repeat :n [fd :l rt 360/:n] n sides of length l, so turn must be 360/n : end circle > 15 * prompt 15* prompt context for succeeding drawings :> gpaper 20 40x40 graph paper – zeno at (0|0) with dir (0|1) :> circle 3 20 :red 20-sided polygon with side of length 3 :> circle 2 30 :cyan 30 ……………………………….. 2 :> circle 1 60 :green 60 ……………………………….. 1 > blank line to return to outer (normal) scope

What are the radii of these ‘circles’? And, where are their centres? Clearly, this approach gives no control over placement of the centre and specification of the radius. (NB We will return to this ‘chord drawing’ approach to circles when we look at Vectors to see that it is possible to draw a circle in this way for a given centre and radius.) A useful method for many drawing situations is: create a unit-sized object at (0|0); enlarge by given scaling factor; and then move to final destination. So, to draw any circle - draw a unit circle (ie one with radius = 1) with centre at (0|0); next enlarge by radius r; and then translate the origin to centre c. See Linear Transforms for more details of enlarge and translate functions. The equation for a unit circle at the origin is x2 + y2 = 1

rewrite as y = ±√(1 – x2) and because of the need to deal with both +ve and –ve square roots, move from -1 to 1 with one root and then back from 1 to -1 with the other root. NB The order is not critical as it only changes the direction of the drawing, ie clockwise or anti-clockwise.

Page 21: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Circles

> to circle :c :r :col : translate :c : turtle -1 1 :true :col 0 : ( :r * ([:x]->'(:x| sqrt 1-:x^2)) move 1 : :r * ([:x]->'(:x|-sqrt 1-:x^2)) move -1 ) : end circle > 15*circle (10|-10) 5 :green draw green-coloured circle, centre (10|-10) and radius 5

in a ‘15*’ context – only need prompt when more than 1 following command

Now, consider a parametric coordinates approach to drawing a circle.

> to cpt :t function to map t (for theta) to the point (cos t | sin t) : (cos :t|sin :t) parametrics for a circle are r*(cos t | sin t) : end substitute into x2 + y2 = r2 * (cos2t + sin2t) = r2 cpt > to circle :c :r :col : translate :c : turtle 0 1 :true :col 0 1-d turtle starts at 0 and in the context of : :r * cpt the radius r * cpt ie a map to point r*(cos t | sin t) : fd 360 goes forward 360 (degrees) : end ie the points r*(cos t | sin t) for t = 0..360 form a circle of circle radius r around (0 | 0), and then the origin is moved to c > 15*circle (10|10) 5 :cyan > to circle :c :r :col circle as above but with internal anonymous map function : xl :c xl is abbreviation for translate : turtle 0 1 :true :col 0 : :r*([:t]->'(cos :t|sin :t)) : fd 360 : end circle > 15*circle (-10|10) 5 :magenta magenta circle again in 15* context

Finally, returning to the problem of drawing the circumcircle given 3 points (introduced in Simultaneous Equations), we can now complete the required function using the parametric method.

Page 22: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Circles

> to circle :p1 :p2 :p3 :col : to x :p (1|0).:p end : to y :p (0|1).:p end : to v :p (-((x :p)*(x :p)+(y :p)*(y :p))) end : local 'fgh (x :p1, y :p1, 1 : |x :p2, y :p2, 1 : |x :p3, y :p3, 1)\(v :p1|v :p2|v :p3) : local 'f (1|0|0).:fgh : local 'g (0|1|0).:fgh : local 'h (0|0|1).:fgh : local 'c (-:f/2|-:g/2) : local 'r 2\sqrt :f*:f + :g*:g - 4*:h : xl :c : turtle 0 1 :true :col 0 : :r*([:t]->'(cos :t|sin :t)) : fd 360 : end circle > 15*circle (-15|-10) (-5|-10) (-10|-5) :red

So, a circle can be drawn with functions clearly based on its fundamental properties, viz centre and radius, and using the common representations of circles, viz cartesian and parametric coordinates – thus exposing and reinforcing our mathematical understanding of circles. In Conic Sections we will investigate if these approaches can be extended to ellipses, parabolas, hyperbolas etc.

Page 23: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Conic Sections

7 Conic Sections Having explored circles, we now wish to investigate the drawing of the other conic sections – ellipses, parabolas and hyperbolas – in terms of their fundamental properties and by using their common mathematical representations, viz parametric and cartesian coordinates. We will continue to use gpaper (and axes, grid and line) loaded from utils.zno as in the preceding sections on Circles and Graphs. This time, we will start with parametric coordinates.

> cs ht clear screen, home and hide turtle > 15*gpaper 20 draw 40x40 graph paper, scaled by *15 > to ellipse :c :a :b :col definition for a col ellipse with centre c, : xl :c semi-major axis a and semi-minor axis b : turtle 0 1 :true :col 0 : ([:t]->'(:a*cos :t|:b*sin :t)) parametrics for an ellipse are (a cos t | b sin t) : fd 360 substitute into x2/a2 + y2/b2 = 1 to get : end a2 cos2t / a2 + b2 sin2t / b2 = cos2t + sin2t = 1 ellipse > 15*ellipse (-10|-10) 8 5 :red again use context 15* to draw a red ellipse > to parabola :a :t1 :t2 :col : turtle :t1 1 :true :col 0 : ([:t]->'(:a*:t^2|2*:a*:t)) parametrics for a parabola are (at2 | 2at) : move :t2 substitute into y2 = 4ax to get 4a2t2 = 4a2t2 : end parabola > 15*parabola 4 -2 2 :blue and again use 15* context to draw a blue parabola > to hyperbola :a :b :col : turtle 0 1 :true :col 0 : ([:t]->'(:a/cos :t|:b*tan :t)) parametrics for a hyperbola are (a / cos t | b tan t) : fd 360 substitute into x2/a2 – y2/b2 = 1 to get : end a2 / a2 cos2t – b2 sin2t / b2 cos2t hyperbola = 1 / cos2t – sin2t / cos2t = (1 – sin2t) / cos2t = cos2t / cos2t = 1 > 15*hyperbola 3 4 :black and use 15* context to draw a black hyperbola

Page 24: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Conic Sections

The annotations above related the parametric coordinate representations of the conic sections to their equivalent cartesian representations. Now, repeat the drawings this time using the cartesian coordinates representations directly. The special case of the rectangular hyperbola has been included.

> to ellipse :c :a :b :col : xl :c : turtle -:a 1 :true :col 0 : ( ([:x]->'(:x| sqrt :b^2*(1-:x^2/:a^2))) move :a : ([:x]->'(:x|-sqrt :b^2*(1-:x^2/:a^2))) move -:a ) : end ellipse > to parabola :a :x2 :col : turtle 0 1 :true :col 0 : ( ([:x]->'(:x| sqrt 4*:a*:x)) move :x2 : ([:x]->'(:x|-sqrt 4*:a*:x)) move 0 ) : end parabola > to hyperbola :a :b :x2 :col : turtle -:x2 1 :true :col 0 : ( ([:x]->'(:x|:b/:a * sqrt :x^2-:a^2)) move -:a : ([:x]->'(:x|:b/:a * -sqrt :x^2-:a^2)) move -:x2 ) : turtle :a 1 :true :col 0 : ( ([:x]->'(:x|:b/:a * sqrt :x^2-:a^2)) move :x2 : ([:x]->'(:x|:b/:a * -sqrt :x^2-:a^2)) move :a ) : end hyperbola

Page 25: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Conic Sections

> to recthyperbola :c :x2 :col : turtle -:x2 1 :true :col 0 : ([:x]->'(:x|:c/:x)) move :x2 ie x y = c : end rect_hyperbola > cs ht > 15* prompt :> gpaper 20 :> ellipse (-10|-10) 8 5 :red :> parabola 4 20 :blue :> hyperbola 3 4 20 :black :> recthyperbola 25 20 :magenta :> recthyperbola -25 20 :green >

As with circles, these definitions embody the relevant mathematical concepts. It might appear that the use of cartesian coordinates imposes a higher burden of awareness because of the need to deal with both +ve and –ve square roots. But, this ‘burden’ is not caused by any opacity of the programming language - the underpinning mathematical reasoning is clearly reflected in the definitions. We will return to conic sections again when we consider their mathematics as Loci.

Page 26: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Conic Sections

The rectangular hyperbola drawings expose other interesting issues about how computing should deal with singularities – see also the introductory discussion in Graphs for trig functions. As x moves from -20 .. 20 it must pass through 0 – so, Zeno must encounter the computations 25/0 and -25/0, which ‘normally’ would (and should) generate error messages. But, Zeno’s ‘bendy line’ routine traps arithmetic exceptions and advances the controlling parameter of the curve past singularities. This issue of how errors are handled ‘locally’is another aspect of ‘generalised context’. In drawing contexts, the relevant floating-point error signals are trapped while the rest are propagated. There is another facet in play here too. Zeno is aware that it has only a finite drawing area – so, when point values outside this area are generated, drawing is effectively suspended, but computation continues until a point within the drawing area is computed or the end of range is reached. See sections on Complex Plane and Vectors for more examples and insights.

Page 27: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Linear Transforms

8 Linear Transforms Linear transformations always preserve shape. They may change size, location or orientation but they do not change shape. (NB We have already used linear transforms in our earlier investigations, in particular, we used enlargements and translations when defining and drawing Circles and the other Conic Sections. Also, arguably we have already seen some non-linear transformations where straight line movements, albeit in 1-d space, were transformed into Graphs, Circles and other Conic Sections in 2-d space.) Zeno provides five ‘ready-to-use’ linear transforms, viz:

enlarge (enl) point scale_factor reflect (rf) point bearing rotateleft (rl) point angle rotateright (rr) point angle translate (xl) point

where the names in ( ) are abbreviations. First, we will explore the use of these built-in functions to see their effects. But, we need something distinctive to transform and some background to help us to follow the applied transformations. From utils.zno, load functions line, axes and markaxes to provide the background and joinpts to draw the F shape defned below.

> to F :col draws coloured F at (0|0) in ‘box’ of 5 high x 3 wide : joinpts [(0|0)(0|5)(3|5)(3|4)(1|4)(1|3) : (2|3)(2|2)(1|2)(1|0)(0|0)] :col : end F > to setup setup for new drawings : cs : axes -20 20 -20 20 :lightgrey : markaxes -20 20 1 -20 20 1 :lightgrey : markaxes -20 20 5 -20 20 5 :lightblue : end setup > 15* prompt prompt in context of 15* :> setup setup for new drawings :> F :black black F at (0|0) :> enl (0|0) 2 (F :red) red F at (0|0) enlarged by 2 from (0|0) so all (x|y) * 2 but no translation from (0|0) :> enl (-5|0) 2 (F :blue) blue F at (0|0) enlarged by 2 from (-5|0) so all (x|y) * 2 and (0|0) is translated to (5|0) :> line (-5|0) (5|10) :blue construction line for top left hand corner of F :> enl (-10|0) 1/2 (F :black) black F at (0|0) enlarged by ½ from (-10|0) so all (x|y) * ½ and (0|0) is translated to (-5|0) :> line (-10|0) (0|5) :black construction line for top left hand corner of F :> enl (-15|0) 2 (F :green) green F at (0|0) enlarged by 2 from (-15|0) so all (x|y) * 2 and (0|0) is translated to (15|0)

Page 28: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Linear Transforms

:> line (-15|0) (15|10) :green construction line for top left hand corner of F :> enl (0|0) -1 (F :black) black F at (0|0) enlarged by -1 from (0|0) so all (x|y) * -1 but no translation from (0|0) :> enl (0|0) -2 (F :red) red F at (0|0) enlarged by -2 from (0|0) so all (x|y) * -2 but no translation from (0|0) :> enl (-5|0) -2 (F :blue) blue F at (0|0) enlarged by -2 from (-5|0) so all (x|y) * -2 and (0|0) is translated to (-15|0) :> line (-5|0) (-15|-10) :blue construction line for top left hand corner of F :> enl (-10|0) -1/2 (F :black) black F at (0|0) enlarged by -½ from (-10|0) so all (x|y) * -½ and (0|0) is translated to (-15|0) :> line (-10|0) (-15|-2.5) :black construction line for top left hand corner of F :> blank line to leave prompt context of 15*

From the preceding examples, you may have noticed that – n * drawing <=> enl (0|0) n drawing but, repeating some of the lines above with ‘swaps’ should reinforce this observation.

> enl (0|0) 15 prompt substitute enl (0|0) 15 for 15* as context for prompt :> setup setup for new drawings :> F :black black F at (0|0) - no change :> 2*F :red 2*F :red = enl (0|0) 2 (F :red) NB ( ) needed for parsing :> -1*F :black likewise for -1*F :black

Page 29: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Linear Transforms

:> -2*F :red and for -2*F :red :>

Also, in the examples above, we have been composing transformations serially, ie the enl (0|0) 15 as the prompt context is composed in turn with another enl transformation. The next sequence of four drawings illustrates both parallel (&) and serial (juxtaposition) composition to build more complex contexts from their simpler components.

> 15* prompt :> setup setup for first drawings (left hand below) :> (1* & 2*) F :black F at (0|0) => two Fs at (0|0)

one as original, ie 1*, and the second 2* :> setup setup for second drawings (right hand below) :> (1* & xl (0|10)) F :red F at (0|0) => two Fs, 1* at (0|0) and xl (0|10) at (0|10) :> xl (10|0) (1* & 2*) F :green F at (0|0) => two F s at (0|0), a 1* and a 2*,

=> both translated to (10|0)

Page 30: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Linear Transforms

:> setup setup for third drawings (left hand below) :> ( 1* F at (0|0) => two Fs, at (0|0) and (0|10) :: & rr (0|0) 90 => eight Fs, 1* still at (0|0) and (0|10), and the others :: & rr (0|0) 180 along axes via rr about (0|0) by 90o, 180o, and 270o :: & rr (0|0) 270) (1* & xl (0|10)) F :blue :> setup setup for fourth drawings (right hand below) F at (0|0) => two Fs, at (0|0) and (0|10) :> (1* & rf (0|0) 135) (1* & rr (0|0) 90) (1* & xl (0|10)) F :cyan => four Fs, two via 1* still at (0|0) and (0|10), and :> line (-15|15) (15|-15) :lightgrey two via rr about (0|0) by 90o => eight Fs, four via 1* as before and their > reflection in line through (0|0) at 135o

Notice that the order of interpretation is right to left – ie start with drawing F at (0|0) as defined by the F function, then apply the transform or block of transforms immediately to its left, then next on the left again, and again until completed.

Now that we have seen Zeno’s built-in linear transforms in action, and not just idividually but also composed serially and in parallel, it is time to explore the underlying maths. The five built-in transforms introduced above are merely special cases of another built-in function called linear. Inspect some examples to see their linear forms –

> :( enl (1|2) 15 ) {linear (-14|-28) (15,0|0,15)} > :( rf (10|10) 30 ) {linear (6.33975|-3.66025) (-0.5,0.866025|0.866025,0.5)} > :( rr (5|10) 60 )

Page 31: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Linear Transforms

{linear (-6.16025|9.33013) (0.5,0.866025|-0.866025,0.5)} > :( rl (10|5) 45 ) {linear (6.46447|-5.6066) (0.707107,- 0.707107|0.707107, 0.707107)} > :( xl (15|5) ) {linear (15|5) (1,0|0,1)}

which are derived via their definitions –

enl p f = {linear (x*(1-f) | y*(1-f)) (f,0 | 0,f)} rf p b = {linear (x*(1-c2)-y*s2 | y*(1+c2)-x*s2) (c2,s2 | s2,-c2)} rl p a = {linear (x*(1-c)+y*s | y*(1-c)-x*s) (c,-s | s,c)} rr p a = {linear (x*(1-c)-y*s | y*(1-c)+x*s) (c,s | -s,c)} xl p = {linear (x | y) (1,0 | 0,1)} where p is a point (x | y)

f is a scale factor b is a bearing angle – and c2 = cos 2*b, s2 = sin 2*b a is a rotation angle – and c = cos a, s = sin a All linear functions have the form {linear t m}, where t is a point, representing a displacement, and m is a rotation matrix. When applied to a single argument, say p, linear returns the value t + m*p. Note that p may be a single point or all of the points of any shape. When linears are juxtaposed (ie serial composition) in a context, they are combined according to the following rule.

{linear tn mn} …. {linear t2 m2} {linear t1 m1} => {linear tn mn} …. {linear t3 m3} {linear t2+m2*t1 m2*m1} => {linear tn mn} …. {linear t4 m4} {linear t3+m3* (t2+m2*t1) m3*m2*m1} => …..

Note the right to left association as described in the commentaries of application above. So, now we can see that functionally enl .. xl are not essential as we can always use their equivalent linear forms. But, they are undoubtedly useful because they facilitate descriptions of mathematical operations in more accessible and meaningful language. But, why do we even need a built-in linear? Why not create our own, ie user-defined function, say lin, to do the same thing?

> to lin :t :m :p : :t + :m*:p : end lin > 15*setup > 15 * lin (-10|5) (1,0|0,1) F :black > 15 * : ( lin (-10|5) (1,0|0,1) : lin (0|0) (cos 45,sin 45|-sin 45,cos 45)

Page 32: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Linear Transforms

: lin (0|0) (3,0|0,3) ) : F :red >

That was simple – and it works. Now, why not define our own enl .. xl using lin and the generic forms given earlier? There is no conceptual language reason for not doing so – and it will work if the generic forms are encoded correctly. These functions are built-in simply to assist program execution. When dealing with linear transformations, Zeno can use the assumption that shape will not change to optimise execution. This assumption can never be made for transformations invoked by user-defined functions, so Zeno must use its ‘bendy line’ routine which is much more compute-intensive and so slower.

Page 33: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Complex Plane

9 Complex Plane A complex number, like x + iy, is represented by the 2-element column vector (x | y). Note that the same form is also used to represent both points and direction vectors in 2-d cartesian coordinates, but having these different (but related) meanings for the one form does not normally lead to any confusion in their use. We start with a short illustration of the multiplication and divison of complex numbers.

> (1|3)*(4|2) multipy two complex numbers (-2|14) product is also a complex number > (-2|14)/(4|2) divide the product by one of the original operands (1|3) to deliver the other operand > 1/(1|1) inverse of a complex number (0.5|-0.5) is a complex number > (1|1)*(0.5|-0.5) multiply a complex number by its inverse (1|0) result is a complex number but with zero imaginary part > (1|1)\1 demonstrate that \ (under) works with complex numbers (0.5|-0.5)

Many of Zeno’s arithmetic functions may be used with complex numbers and these functions are described in detail in The Zeno Programming Language, but now we will focus on how this functionality enables non-linear transformations.

> cs home clear screen; ensure (turtle) zeno is at home, ie at (0|0) and with direction (0|1) > spc :black set pen (ink) colour to black > fd 100 draw a black line from (0|0) to (0|100) > home return zeno to (0|0) > 100*exp fd 2*:pi ‘draw a line’ from (0|0) to (0|2π) but in the context of 100*exp, and a circle, centre (0|0) and radius 100 > :zeno is drawn, but an inspection of zeno reveals its {turtle (0|6.28319) (0|1) true 0 0} current position to be (0|2π) > jump (0.25|0) repeat this process, but starting at (0.25|0) with > spc :blue blue ink, to draw a concentric circle with a radius > 100*exp fd 2*:pi greater than 100 > jump (-0.25|0) and repeat again, this time from (-0.25|0) with > spc :red red ink, to draw another concentric circle but with > 100*exp fd 2*:pi a radius smaller than 100

Clearly, we have non-linear transformations – straight lines have been transformed to circles, so shape has not been preserved. But why is it happening? In general terms, each of these circles results from the evaluation of the expression

Page 34: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Complex Plane

100 * ex+iy = 100 * ex * eiy = 100 * ex * (cos y | sin y) where x remains constant, and y varies from 0 to 2π. The points (cos y | sin y) for y = 0 .. 2π give a circle with centre (0 | 0) and radius 1, and this unit circle is then enlarged by the factor 100 * ex. For x = 0, ex = 1; for x = 0.25, ex =1.284; and for x = -0.25, ex =0.779; and so the enlargement factors applied to the unit circle, and thus the radii of the generated circles, are 100, 128.4 and 77.9 respectively. These examples suggest another simple way of drawing a circle for a given centre, radius and colour. (NB See Circles for other circle drawing methods.)

> to circle :c :r :col create a homed turtle with given pen colour, col, : xl :c and use it to draw a circle of the given radius, r, : turtle (0|0) (0|1) :true :col 0 but centred on the origin (0|0), and then move : :r * exp fd 2*:pi the origin to given centre, c. : end circle > circle (150|150) 100 :green draw a green circle, centre (150|150), and radius 100

Note that circles are generated in these cases because x remains constant. Again, start from the homed position but pointing to the right or left to draw spirals.

> cs home > rt 1.5 from (0|0) but pointing (slightly) to the right > spc :blue and with blue ink > 5*exp fd 50*:pi draw an outward, anti-clockwise, blue spiral > cs home > lt 1.5 from (0|0) but pointing (slightly) to the left > spc :red and with red ink > 250*exp fd 50*:pi draw an inward, anti-clockwise, red spiral

Now, re-introduce functions line and grid from utils.zno, and apply some transforms to some grids to see the effects

> cs home > grid 0 20 0 20 1 :green small (solid) green square at origin – no transform > 20*grid 0 10 0 10 1 :blue transform 10x10 blue grid with 20* - but still linear

Page 35: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Complex Plane

> _*exp(0|:pi/6) grid 0 200 0 200 20 :magenta use placeholder _ to enable post-multiplication of a magenta grid by eiπ/6 > cs => could be non-linear? but looks like a rotate left by 300 to me? is it? > _^2 grid (-10|-10) 20 1 20 1 :blue blue grid squared – non-linear – but why only 2 leaves from 4 quadrants? > cs > _^3 grid (-5|-5) 10 0.5 10 0.5 :red red grid cubed – non-linear – and 4 leaves –

ie one for each quadrant?

> cs square root of a green grid > xl (-150|0) : 100 * _^(1/2) grid (-9|-9) 18 1 18 1 :green > cs cube-root of a blue grid > xl (-150|0) : 100 * _^(1/3) grid (-27|-27) 54 3 54 3 :blue > cs inverse of a red grid > 30 / grid (-1|-1) 2 0.1 2 0.1 :red >

To investigate the mathematics of these effects: perhaps start with the transform in question applied to a unit square at the origin? and then develop to a suitable grid?

Page 36: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Vectors

10 Vectors A vector is a quantity that is determined by its magnitude and direction. (A scalar has magnitude only.) A unit vector has a magnitude of 1. A position vector starts at the origin (0|0) and finishes at the (cartesian) point given by the vector’s (rectilinear) components. Zeno represents 2-d points and vectors (and complex numbers) as (x|y). First, we will explore some properties of vectors and develop some associated functions. Then, we will return to the topic of conic sections and develop yet another way to represent them – including a ‘chord’ drawing approach which does retain their fundamental concepts. And, finally, we will introduce the idea of dependent actions. We will use delay, line, axes, grid, gpaper and gwrite from utils.zno.

> cs > 'p<-(3|1) position vector p = (3|1) p > 'q<-(2|3) position vector q = (2|3) q > 25* prompt 25* prompt context :> gpaper 10 20x20 graph paper :> line (0|0) :p :black draw position vector p :> gwrite [P] :p+(0.25|0) 2/25 :black label the point P :> gwrite [p] (1.5|0) 2/25 :black and the vector p :> line (0|0) :q :black draw position vector q :> gwrite [Q] :q+(0.25|0) 2/25 :black label the point Q :> gwrite [q] (1|2) 2/25 :black and the vector q :> line (0|0) :p+:q :black draw position vector p+q :> gwrite [p pl q] (4|2.5) 2/25 :black and label it p+q :> line :p :p+:q :lightgrey draw the construction lines from points P and Q to see the :> line :q :p+:q :lightgrey parallelogram and the 2 paths ie p+q = q+p :> line (0|0) :p-:q :blue draw the (blue) position vector p-q (NB direction is “to p from q”) :> gwrite [p mi q] (-0.5|-1.5) 2/25 :black and label it :> line (0|0) :q-:p :red draw the (red) position vector q-p (NB direction is “to q from p”) :> gwrite [q mi p] (-2|1) 2/25 :black and label it NB q-p = -(p-q) :> line :p :q :red draw the (red) line between P and Q

Page 37: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Vectors

:>

The line function only draws between 2 points – so how can we extend this line in either or both directions? How can we test if a given point/position vector is on this extended line? To address the latter, it is helpful first to consider the angle between 2 vectors. Finally, we will look at the special case to test if 2 vectors are at right angles to each other. Consider the position vector r of any point R which lies on the line through P and Q: we see that the vectors q - r and q - p must have the same (or opposite) direction, and so only vary in their respective magnitudes; so we may write

q – r = λ(q – p) => r = λ p + (1 – λ)q and see that when λ = 1 then r = p, and when λ = 0 then r = q. The function below captures this relationship to extend the line defined by (position vectors) u and v to end points given by λ1 and λ2.

> to extend :u :v :lam1 :lam2 :col : line (:lam1*:u + (1-:lam1)*:v) (:lam2*:u + (1-:lam2)*:v) :col : end extend > 25* prompt return to the 25* prompt context :> extend :p :q 1 4 :green extend the line beyond P, ie where λ>1 :> gwrite [lam gt 1] (4.5|-1) 2/25 :black and label it :> extend :p :q -3 0 :blue extend the line beyond Q, ie where λ<0

Page 38: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Vectors

:> gwrite [lam ls 0] (1|6) 2/25 :black and label it :> extend :p :q 1 0 :black overdraw the red line between P and Q :> leave prompt context > 'r<-(5|-3) position vector r = (5|-3) r > 25* prompt re-enter 25* prompt context :> line (0|0) :r :black draw position vector r :> gwrite [R] :r+(0.25|0) 2/25 :black label the point R :> gwrite [r] (2.5|-2) 2/25 :black and the vector r :> and leave prompt context again

> to angle :u :v define angle between 2 vectors – cos rule : acos (:u.:v)/((mod :u)*(mod :v)) dot product / product of moduli : end angle > angle (-1|0) (1|0) 1800 between +ve and –ve x-axes 180 > angle (1|0) (0|1) 900 between +ve x- and y-axes 90

Page 39: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Vectors

> angle (1|0) (1|1) 450 between +ve x-axis and (1|1) 45 > angle :p :q 37.8750 between position vectors p and q 37.875 > to online :p :u :v does vector p define a point on the line : local 'up :p-:u through the points given by vectors u and v : local 'vp :p-:v yes: if (dot product)2 = (product of mods)2 : (:up.:vp)*(:up.:vp) = (:up.:up)*(:vp.:vp) see definition of angle : end if online then angle = 0 or 180, so cos = ±1 online so squares of numerator and denominator of

the angle formula must be equal > online :r :p :q is R on the line through P and Q? true yes > online (6|-4) :p :q is (6|-4)? false no > online (1|5) :p :q but (1|5) is online true > to perp :u :v test if 2 vectors are perpendicular : :u.:v = 0 yes: if their dot product is 0 : end perp > perp (1|0) (0|1) as might be expected, the x- and y- axes are true > perp (0|1) (0|1) but the x-axis is not perp to itself false > perp :q :r but are q and r? - no false

Time to draw circles (again). The approach is to draw a circle with radius r and centre at (0|0) and then translate the origin to c. But, this time we will draw the circumference in 2πr chord-steps. The first attempt will use the tangent at the beginning of the chord.

> to circle :c :r :col : local 'p 0 : xl :c when circle is drawn, move centre to c : turtle (:r|0) (0|1) :true :col 0 1st point is (r|0) and direction is (0|1) : repeat 2*:pi*:r : [ fd 1 fd 1 step along the tangent : 'p <- pos/:r take new position and make a unit vector p : sdir (-(0|1).:p|(1|0).:p) ] set dir perpendicular to p : end (and to go anticlockwise) circle > cs > circle (50|50) 50 :red small error – always drawing outside the circumference? > to circle :c :r :col : local 'p 0 : xl :c

Page 40: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Vectors

: turtle (:r|0) (0|1) :true :col 0 : repeat 2*:pi*:r 2nd attempt : [ 'p <- (pos + dir)/:r reset dir using end of chord-step position : sdir (-(0|1).:p|(1|0).:p) : fd 1 ] before moving fd 1 : end circle > circle (50|50) 150 :blue still small error – always drawing inside the circumference? > to circle :c :r :col : local 'p 0 : xl :c : turtle (:r|0) (0|1) :true :col 0 : repeat 2*:pi*:r 3rd attempt : [ 'p <- (pos + 0.5*dir)/:r reset dir using mid-chord-step position : sdir (-(0|1).:p|(1|0).:p) : fd 1 ] before moving fd 1 : end circle > circle (50|50) 100 :black seems OK? the method is now drawing chords, but taking into account that the perpendicular bisector of a chord passes through the centre of a circle?

> to ellipse :c :a :b :col use a similar method to draw an ellipse : local 'F1 (sqrt :a^2 - :b^2|0) ie based on chord drawing round the : local 'F2 (-:F1) circumference, where the dir is derived : local 'P (0|0) from the property that any line from one : local 'pf2 0 focus of an ellipse will be refected at the : local 'pf1 0 circumference to pass through the other

Page 41: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Vectors

: local 'd 0 focus – so the dir required is perpendicular : xl :c to the bisector of the angle between the 2 : turtle (0|:b) (1|0) :true :col 0 lines from the foci to the point on the : repeat 2*:pi*sqrt :a^2 + :b^2 circumference : [ 'P <- pos + 0.5*dir : 'pf2 <- :P - :F2 'pf2 <- :pf2/mod :pf2 : 'pf1 <- :P - :F1 'pf1 <- :pf1/mod :pf1 : 'd <- (:pf2 + :pf1)/2 : sdir (-(0|1).:d|(1|0).:d) : fd 1 : delay 10 ] use delay to see action more clearly : end ellipse > to parabola :a :x2 :col similar method again, but this time any line : local 'A 0 from the focus to the parabola is reflected : local 't1 :(turtle (0|0) (0|1) :true :col 0) parallel to the x-axis, ie // to (1|0) : local 't2 :(turtle (0|0) (0|-1) :true :col 0) : repeat :x2 uses 2 turtles to draw the : [ 'A <- angle (1|0) (:a|0) - t1 (pos+0.5*dir) symmetric curve : t1 ( sdir (sin :A/2|cos :A/2) fd 1 ) : t2 ( sdir (sin :A/2|-cos :A/2) fd 1 ) : delay 10 ] use delay to see : end simultaneous action parabola > to hyperbola :a :b :n :col similar method again, but here any line : local 'F1 (sqrt :a^2 + :b^2|0) from one focus to its branch of the : local 'F2 (-:F1) hypberbola is reflected along a line which : local 'P (0|0) extended backwards passes through the : local 'A 0 other focus : local 't1 :(turtle (:a|0) (0|1) :true :col 0) use 4 turtles and delay : local 't2 :(turtle (:a|0) (0|-1) :true :col 0) to observe the pseudo- : local 't3 :(turtle (-:a|0) (0|1) :true :col 0) synchronised action : local 't4 :(turtle (-:a|0) (0|-1) :true :col 0) : repeat :n : [ 'P <- t1 (pos + 0.5*dir) : 'A <- (angle :P-:F2 (1|0)) + 90-2\angle :P-:F2 :F1-:P : t1 ( sdir (cos :A|sin :A) fd 1 ) : t2 ( sdir (cos :A|-sin :A) fd 1 ) : t3 ( sdir (-cos :A|sin :A) fd 1 ) : t4 ( sdir (-cos :A|-sin :A) fd 1 ) : delay 10 ] : end hyperbola > cs > 15* prompt draw a circle, ellipse, parabola and hyperbola as in the sessions in Conic Sections for parametric :> gpaper 20 and cartesian coordinates :> circle (10|10) 5 :cyan :> ellipse (-10|-10) 8 5 :red :> parabola 4 20 :blue :> hyperbola 3 4 20 :black

Page 42: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Vectors

:> > to circle :c :r :col yet another circle definition : local 't1 :(turtle (0|0) (0|1) 0 0 0) only interested in t1’s pos and dir : local 't2 :(turtle (t1 dir) 0 :true :col 0) and t2’s pos, pen state and colour : xl :c : :r * : repeat 360 use 2 related (dependent?) turtles : [ t1 rt 1 as t1 rotates 3600 at the origin, its unit vector dir will : t2 move (t1 dir) ] describe a unit circle for t2 to draw – then enlarge : end by r and translate centre to c circle > 15 * circle (-10|10) 5 :green draw a 15* circle to join the rest on the graph paper

The last (?) definition for circle introduced an interesting idea, viz one turtle’s position could depend on another turtle’s direction. We could equally well make one turtle’s direction depend on the position of another turtle, eg turn to ‘face’ that position. On reflection, there seems no reason why we cannot make any property of one turtle depend on the properties of one or more other turtles. These ideas will be explored a little more in the section on Dependent Actions.

Page 43: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Loci

11 Loci

A locus is the point, line (straight or curved) or surface comprising all of the points satisfying a given rule or condition. For example, a circle may be thought of as the locus of all points on the same plane at a fixed distance (aka radius) from a fixed point (aka centre). A similar definition of a sphere could be given but in 3-d. Here we will develop locus-based definitions for parabolas, ellipses and hyperbolas, but first we must introduce some associated terms, viz focus, directrix and eccentricity. Given a focus point F and a straight line directrix L then any point P on a conic section will satisfy the condition: PF = e * PL ie the distance from P to F is equal to the product of the ecentricity e and the distance from P perpendicular to the line L. A short table for all of the conic sections may help to clarify:

interval curve e directrix

e = 0 circle 0 x = ∞

0 < e < 1 ellipse √(1 – b2/a2) x = a2/c

e = 1 parabola 1 x = -a

e > 1 hyperbola √(1 + b2/a2) x = a2/c where F is at (c | 0), and c = a * e, and a and b are semi-major and semi-minor axes. (NB Ellipses and hyperbolas each have two foci, the second one at (-c | 0).) Now, we can define our functions, which all follow a similar pattern.

> to parabola :a :y2 :col parabola with Focus at (a | 0) and max y = y2 : local 'P (0|0) initial P at (0 | 0) : local 't :(turtle :P 0 :true :col 0) : local 'd 0 : repeat :y2 for y = 0 .. y2 : [ 'P <- :P + (0|1) increment P’s y value by 1 : L1:'d <- :P - (:a|0) d set to vector PF : if (:P.(1|0) + :a)^2 >= :d.:d [go 'L2] if PL2 ≥ PF2 then go L2 : 'P <- :P + (1|0) else add 1 to P’s x value and : go 'L1 try again until condition is met : L2:(t & t clone rf (0|0) 90) move :P t and t clone reflected in x-axis draw to P : delay 10 delay to see action => simple animation : ] : end parabola > to ellipse :cen :a :b :col ellipse with axes a and b, and centre cen : local 'P (:a|0) initial P at (a | 0), ie +ve end of semi-major axis : local 't :(turtle :P 0 :true :col 0) : local 'd 0 : local 'c sqrt :a^2-:b^2 set c to F’s x value : local 'e2 1-(:b/:a)^2 and e2 to value of e2 : local 'dx :a^2/:c directrix L is x = dx : xl :cen when ellipse has been drawn, xl origin to cen : repeat :b for y = 0 .. b

Page 44: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Loci

: [ 'P <- :P + (0|1) : L1: 'd <- :P - (:c|0) : if :e2*(:dx-:P.(1|0))^2 >= :d.:d [go 'L2] if e2*PL2 ≥ PF2 then go L2 : 'P <- :P - (1|0) : if :P.(1|0) = 0 [go 'L2] if P’s x value has reached 0 then time to stop : go 'L1 : L2: (t t and 3 clones with suitable reflections draw to P : & t clone rf (0|0) 270 NB the 2nd argument in the reflection is a bearing : & t clone rf (0|0) 0 in range 0..360, clockwise from 0 = North, ie : & t clone rf (0|0) 0 rf (0|0) 90 ) 0 = N (+ve y-axis); 90 = E (+ve x-axis); : move :P 180 = S (-ve y-axis); 270 = W (-ve x-axis) : delay 10 delay to see action => simple animation : if :P.(1|0) = 0 [exit] : ] : end ellipse > to hyperbola :a :b :y2 :col hyperbola similar to ellipse, with y2 = max y : local 'P (:a|0) : local 't :(turtle :P 0 :true :col 0) : local 'd 0 : local 'c sqrt :a^2+:b^2 : local 'e2 1+(:b/:a)^2 : local 'dx :a^2/:c : repeat :y2 : [ 'P <- :P + (0|1) : L1: 'd <- :P - (:c|0) : if :e2*(:dx-:P.(1|0))^2 >= :d.:d [go 'L2] : 'P <- :P + (1|0) : go 'L1 : L2: (t : & t clone rf (0|0) 270 : & t clone rf (0|0) 0 : & t clone rf (0|0) 0 rf (0|0) 90 ) : move :P : delay 10 : ] : end hyperbola > cs > axes -200 200 -200 200 :lightgrey > parabola 40 200 :blue draw blue parabola > ellipse (50|50) 100 50 :red a red ellipse > hyperbola 40 50 200 :magenta and a magenta hyperbola

Page 45: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Loci

The common technique used here has a number of interesting features. Each function merely ‘computes’ the part of its curve lying in the first quadrant (ie +ve xy space), and then uses clone turtles with appropriate reflections to exploit the curve’s symmetries to draw it in the other quadrants. The chosen starting point is on the x-axis (ie y = 0) and moves in the smallest y-steps possible (ie 1 pixel as we are using 1:1 mapping) towards a pre-defined stopping point. Here the stopping y-value is always known, and so is the stopping x-value for the ellipse. At each step, we increment (for parabola and hyperbola) or decrement (for ellipse) the current x-value, again by the smallest amount possible (ie 1 pixel) until our condition is satisfied. There are two noteworthy features of this test for satisfaction. Firstly, it has been squared – as we are dealing with only +ve values, this does not incur any risk wrt sign; and the base quantities require square roots to be computed, so it is more accurate and more efficient to ‘stay’ with the squared quantities. Secondly, we use a ≥ test rather than an = test: here, we are dealing with the comparison of real numbers and at the limits of our screen resolution, ie the probability of the two real numbers being exactly equal is small, but our test does tell us that e2*PL2 was < PF2 and then 1 pixel later e2*PL2 was ≥ PF2. There is still a possible argument about which of the two pixels is the ‘better’ approximation, but intrinsically we are acknowledging that we can only measure within the limitations of our measuring instrument. Also, we are exposing the type of ‘creeping’ approaches to drawing curves that Zeno and drawing packages in general are making all the time – indeed, all of our other methods for drawing conic sections were making decisions like this, but unseen by us.

Page 46: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

3-2-d Space

12 3-2-d Space We face an immediate problem when considering the visualisation of 3-d objects – how to map 3-d space on to a 2-d computer screen? There are several possible graphical projections to achieve this and we will use perhaps the simplest one, which is called the oblique projection – a fuller description of this projection is given along with some others in section #16 Graphical Projections. There is an oblique function in utils.zno, but its definition is repeated here to allow us to consider it more closely. Also from utils.zno, load functions line, join, gwrite, grid3 and axes3 to assist the demonstrations.

to oblique :a :s oblique projection with z-angle a and z-scale factor s linear (0|0) (1,0,:s*cos :a|0,1,:s*sin :a) end

oblique is a linear transform with no displacement and a (2 x 3) rotation matrix. When applied to any 3-d point, it will generate a 2-d point as (2 x 3) * (3 x 1) => (2 x 1), ie (1, 0, s*cos a | 0, 1, s*sin a) * (x | y | z) = (x + z*s*cos a | y + z*s*sin a) = (x | y) + (z*s*cos a | z*s*sin a) Notice that only z-values are affected, ie oblique applied to (x | y | 0) => (x | y) – referred to as ‘keeping the xy-plane true’ – and the z-values define a 2-d point (z*s*cos a | z*s*sin a) relative to (x | y), ie at distance z*s from (x | y) and at an angle a relative to the direction of the x-axis. The selected values for s and a are arbitrary, but certain values are widely used, viz s = 1, a = 30o (is called the cavalier projection); and s = ½, a = 30o (is called the cabinet projection). We will mostly use the latter but with occasional exceptions when different values may give a better view. We will start with some wireframe drawings.

> to oblique :a :s : linear (0|0) (1,0,:s*cos :a|0,1,:s*sin :a) : end oblique > to cube :blh :s :col define a function to draw a cube of side s : grid3 :blh :s :s :s :s :s :s :col at blh and in col(our), where at blh means : end its bottom left hand corner is at blh cube > to t :p define t as an ‘abbreviation’ for the composition : xl (-150|-150) of two transforms to be used several times below : oblique 30 1/2 : :p : end t > cs ht > t 40* prompt prompt for instructions in context of t 40* :> grid3 (0|0|0) 6 3 6 3 6 3 :lightgrey draw a 3-d grid (6 x 6 x 6) with steps of 3 :> cube (0|0|0) 6 :lightblue draw the outline cube in lightblue

Page 47: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

3-2-d Space

:> axes3 0 7 0 7 0 7 :red and slightly longer axes in red :> blank line to exit prompt context > gwrite [X] t (290|0|0) 3 :black and label the axes X, Y and Z > gwrite [Y] t (0|290|0) 3 :black note use of t to convert 3-d points > gwrite [Z] t (0|0|290) 3 :black // screen 1 > cs > t cube (0|0|0) 240 :lightblue // screen 2 draw similar cube but without 40* > to pyr :s :h :col define a square-based pyramid of side s and height h : join [(0|0|0) (:s|0|0) (:s|0|:s) (0|0|:s) (0|0|0) use join to connect the points : (:s/2|:h|:s/2) (:s|0|0) (:s/2|:h|:s/2) of the pyramid – starts at (0|0|0) : (:s|0|:s) (:s/2|:h|:s/2) (0|0|:s)] :col : end pyr > cs > t ( axes3 0 350 0 350 0 350 :lightgrey t is context for a block of instructions to : pyr 300 300 :red ) draw lightgrey axes and a red pyramid > gwrite [X] t (360|0|0) 3 :black label the axes using t again to set positions > gwrite [Y] t (0|360|0) 3 :black > gwrite [Z] t (0|0|360) 3 :black // screen 3

Now, we turn our attention to the drawing of 3-d solids – so, we need some functions to ‘fill’ an area with solid colour – and triangles would be a good start as all areas with boundaries made of straight-line segments may be broken down into triangles.

to filltri :a :b :c :fcol :bcol triangle defined by points a, b, c is filled with to f1 :x :y :z fcol and the boundary is redrawn in bcol if mod (:y-:z)<1 [exit] local 'm (:y+:z)/2 fill by repeatedly drawing lines from the line :x :m :fcol apices to the mid-point of the opposite side f1 :x :y :m until the length of this side is < 1 f1 :x :m :z end f1 :a :b :c f1 :b :c :a

Page 48: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

3-2-d Space

f1 :c :a :b join list [:a :b :c :a] :bcol draw boundary in bcol using join end may help to ‘sharpen’ image cs filltri (-200|-200) (0|200) (200|-200) :blue :blue // screen 4 to fillquad :a :b :c :d :fcol :bcol define fillquad using filltri and join filltri :a :b :c :fcol :fcol filltri :c :d :a :fcol :fcol join list [:a :b :c :d :a] :bcol end cs fillquad (0|0) (-30|200) (200|170) (200|-40) :blue :black // screen 5

Our interest here is drawings in 3-d, but the drawings above of filled triangle and quadrilateral are in 2-d space. But, note that the two fill functions and join all use the utility function line, which works in any dimension. Look at its definition below to understand why.

to line :p1 :p2 :col turtle :p1 0 :true :col 0 move :p2 end

This is a very simple function – it draws a line from point p1 to point p2 in a given colour – but its utility is much deeper. To draw the desired line, it creates a local turtle with position p1, direction is 0, pen is down (ie true) and pen colour is the supplied col. (NB The final argument is also 0 for body colour – but turtles local to a function are always invisible.) The direction is 0 because we are not going to use it – in fact it could be set to anything at all. The effect of the move command is to change the turtle’s position to move’s given argument, ie p2, and because its pen is down, a line will be drawn. But, nothing in this definition specifies the dimensions of p1 and p2 – the only practical constraint is that they should have same dimenson. So, line can draw in 1-d, 2-d, 3-d, … and functions that draw only using line – like join, filltri and fillquad – will also work in any dimension, eg we have examples above of join drawing a 3-d wireframe pyramid, a 2-d triangle and a 2-d quadrilateral. Now that we have chosen our graphical projection and we have two ‘fill’ functions, we must address two other related issues when drawing 3-d solids, viz which faces of the desired figure will be visible and what order should its components be drawn to achieve the desired effect. The next two drawings may help to illustrate these issues.

Page 49: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

3-2-d Space

> cs > xl (0|-100) : oblique 30 1/2 : ( fillquad (0|0|0) (0|200|0) (0|200|200) (0|0|200) :blue :black : fillquad (0|0|0) (0|200|0) (-200|200|0) (-200|0|0) :red :black : fillquad (0|0|0) (0|200|0) (0|200|-200) (0|0|-200) :lightblue :black : fillquad (0|0|0) (0|200|0) (200|200|0) (200|0|0) :lightred :black ) // scr 6 > cs > xl (0|-100) : oblique 30 1/2 : ( fillquad (-200|0|200) (-200|200|200) (200|200|200) (200|0|200) :red :black : fillquad (-200|0|-200) (-200|200|-200) (-200|200|200) (-200|0|200) :blue :black : fillquad (-200|0|-200) (-200|200|-200) (200|200|-200) (200|0|-200) :lightred :black : fillquad (200|0|-200) (200|200|-200) (200|200|200) (200|0|200) :lightblue :black ) // sc 7

In both cases, we observe that the order may be summarised as: back and left must be drawn before front and right but the order within the two pairs does not matter – and where back and front are determined by their z-values, and left and right by their x-values. Now, consider the drawing of a solid pyramid. From our earlier wireframe pyramid, we can see that only the front and right faces would be visible if all faces were filled.

> to pyr :blh :s :h :frontcol :rightcol pyramid with front and right face : local 'apex (:s/2|:h|:s/2) : filltri :blh+(:s|0|0) :blh+:apex :blh+(:s|0|:s) :rightcol :black : filltri :blh+(0|0|0) :blh+:apex :blh+(:s|0|0) :frontcol :black : end pyr > cs try different combinations of colours > xl(-200|0) oblique 30 1/2 : pyr (0|0|0) 100 100 :darkgrey :lightgrey > xl(-50|0) oblique 30 1/2 : pyr (0|0|0) 100 100 :lightgrey :darkgrey > xl(100|0) oblique 30 1/2 : pyr (0|0|0) 100 100 :blue :lightblue // screen 8 > cs ‘hand’ build a pyramid of pyrs > xl (-100|-100) : oblique 30 1/2 : (pyr (0|0|100) 100 100 :darkgrey :lightgrey

Page 50: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

3-2-d Space

: pyr (100|0|100) 100 100 :darkgrey :lightgrey : pyr (0|0|0) 100 100 :darkgrey :lightgrey : pyr (100|0|0) 100 100 :darkgrey :lightgrey : pyr (50|100|50) 100 100 :darkgrey :lightgrey) // screen 9

Finally, we define a function to draw a pyramid with n layers of pyramids of side s and height h, on a square base of n x n pyramids with bottom left hand corner at (0|0|0).

> to pyramid :n :s :h :frontcol :rightcol draw pyramid with n layers at (0|0|0) : : to pyr :blh : filltri :blh+(:s|0|0) :blh+:apex :blh+(:s|0|:s) :rightcol :black : filltri :blh+(0|0|0) :blh+:apex :blh+(:s|0|0) :frontcol :black : end : : to lineofpyr :n :b draw a line of n pyrs starting at b : rep :n [ pyr :b 'b<-:b+(:s|0|0) ] : end : : to layerofpyr :n :b draw a layer = n lines of pyrs starting at b : local 'c 1 : rep :n [ lineofpyr :n :b+(:n-:c)*(0|0|:s) 'c<-:c+1 ] : end : : local 'c n draw n layers of pyrs starting at (0|0|0) : local 'a (0|0|0) : local 'apex (:s/2|:h|:s/2) apex is computed once and is then available : rep :n [ layerofpyr :c :a 'a<-:a + :apex 'c<-:c-1 ] to local functions by ‘scope’ : end pyramid > cs > xl (-280|-250) : oblique 30 1/2 : pyramid 5 80 100 :lightgrey :darkgrey // 5 layers of 5 X 5 //screen 10

Page 51: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

3-2-d Space

Page 52: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space

13 2-3-2-d Space We will explore how to draw surfaces in 3-d by mapping 2-d grids on to 3-d space and then projecting them back to 2-d for an oblique view. From utils.zno, load line, join, grid, gwrite, oblique, grid3, box3 and axes3 to assist our presentations. Our basic foundation for all of the surface drawings to follow is the simple 2-d grid – like the 300x300 with mesh size 15 drawn below with labelled axes and title.

> cs ht > xl (-150|-150) xl to centre grid on (0|0) : ( axes 0 320 0 320 :darkgrey axes in darkgrey : gwrite [x] (325|0) 4 :black label x axis : gwrite [y] (0|325) 4 :black and y axis : gwrite [2 mi d $4 g r i d] (100|-50) 4 :black title 2-d grid : grid (0|0) 300 15 300 15 :darkgrey ) // screen 1

Define two ‘abbreviation’ functions, cab and labelaxes, which will be used several times below. > to cab :p cabinet oblique : oblique 30 1/2 :p : end cab > to labelaxes labelled 3-d axes : cab axes3 0 320 0 320 0 320 :darkgrey : gwrite [x] (325|0) 4 :black : gwrite [y] (0|325) 4 :black : gwrite [z] cab (0|0|325) 4 :black : end labelaxes

Many surfaces (but not all) may be defined by expressing one axis variable as a function of the other two, ie as y = f(x,z) or z = f(x,y) or x = f(y,z). Further, by ‘swapping’ these variables, we can obtain three different views of the ‘same’ surface. We start with some simple examples of these observations – firstly, y = f(x,z) = 0.

> to plane_xz :p ie y=0 plane : (:p.(1|0) | 0 | :p.(0|1)) ie 3-d point with (p’s x value | 0 | p’s y value) : end extract values using scalar products plane_xz cs xl (-150|-150) ( labelaxes cab plane_xz grid (0|0) 300 15 300 15 :darkgrey map 2-d grid to 3-d via plane_xz gwrite [y eq f lpr x cma z rpr eq 0] title y = f(x,z) = 0 (100|-50) 4 :black ) // screen 2 to plane_xy :p ie z=0 plane (:p.(1|0) | :p.(0|1) | 0) ie 3-d point with (p’s x value | p’s y value | 0) end cs xl (-150|-150) ( labelaxes cab plane_xy grid (0|0) 300 15 300 15 :darkgrey map same grid via plane_xy

Page 53: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space gwrite [z eq f lpr x cma y rpr eq 0] title z = f(x,y) = 0 (100|-50) 4 :black ) // screen 3 to plane_yz :p ie x=0 plane (0 | :p.(0|1) | :p.(1|0)) ie 3-d point with (0 | p’s y value | p’s x value) end cs xl (-150|-150) ( labelaxes cab plane_yz grid (0|0) 300 15 300 15 :darkgrey map same grid via plane_yz gwrite [x eq f lpr y cma z rpr eq 0] title x = f(y,z) = 0 (100|-50) 4 :black ) // screen 4

Now, time for some more interesting surfaces, starting with y = f(x,z) = sinr (x+z2) - where we need to define sinr in terms of (the system supplied) sin.

> to sinr :x sin of x radians : sin (:x*180)/:pi convert radians to degrees : end and use sin sinr > to sinrsurf :p y = f(x,z) = sinr (x+z2) : local 'x (1|0).:p x = p’s x value : local 'z (0|1).:p z = p’s y value : local 'y sinr (:x+:z^2) y = sinr (x+z2) : (:x|:y|:z) : end sinrsurf > to t :p 'abbreviation' function - compostion of oblique with 50*

Page 54: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space : oblique 60 2\sqrt 3 50*:p NB use of a=60o, s=2\√3 - better view? : end t > cs ht surface from cyan grid > t sinrsurf then boundary in red : ( grid (-3|-2) 6 0.1 4 0.05 :cyan : grid (-3|-2) 6 6 4 4 :red ) > t ( box3 (-3|-1|-2) 6 2 4 :darkgrey enclosing box with extended : line (-3.5|1|2) (-3|1|2) :darkgrey corners to enable labelling : line (-3.5|1|-2) (-3|1|-2) :darkgrey : line (-3.5|-1|-2) (-3|-1|-2) :darkgrey : line (-3|-1.5|-2) (-3|-1|-2) :darkgrey : line (3|-1.5|-2) (3|-1|-2) :darkgrey ) > gwrite [pl 2] t (-3.5|0.75|2) 2 :black label +2 > gwrite [Z] t (-3.5|0.8|0) 2 :black ....... Z > gwrite [mi 2] t (-3.4|1.1|-2) 2 :black ....... -2 > gwrite [pl 1] t (-3.4|0.75|-2) 2 :black ....... +1 > gwrite [Y] t (-3.3|0|-2) 2 :black …… Y > gwrite [mi 1] t (-3.4|-0.9|-2) 2 :black …… -1 > gwrite [mi 3] t (-2.9|-1.3|-2) 2 :black …… -3 > gwrite [X] t (0|-1.3|-2) 2 :black ........ X > gwrite [pl 3] t (2.7|-1.3|-2) 2 :black …… +3 // screen 5

Page 55: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space

> to dip :p y = f(x,z) = x2 + z2 : local 'x (1|0).:p : local 'z (0|1).:p : local 'y :x^2+:z^2 : (:x|:y|:z) : end dip > cs xl (0|-200) : oblique 60 (sqrt 3)/2 : 50*dip : ( grid (-2|-2) 4 0.1 4 0.05 :cyan : grid (-2|-2) 4 4 4 4 :red ) // screen 6 > to asinreal :p z = f(x,y) = real part of asin (x|y)3 : local 'x (1|0).:p : local 'y (0|1).:p : local 'z (1|0).asin :p^3 : (:x|:y|:z) : end asinreal > cs cab 100*asinreal : ( grid (-2|-2) 4 0.1 4 0.1 :cyan : grid (-2|-2) 4 4 4 4 :red ) // screen 7 > to asinim :p z = f(x,y) = imaginary part of asin (x|y)3 : local 'x (1|0).:p : local 'y (0|1).:p : local 'z (0|1).asin :p^3 : (:x|:y|:z) : end asinim > cs cab 80*asinim : ( grid (-2|-2) 4 0.1 4 0.1 :cyan : grid (-2|-2) 4 4 4 4 :red ) // screen 8

Now for something (completely?) different – we will explore spherical surfaces. Consider the drawing below.

> cs explore spherical surfaces > xl (-200|-200) : cab 100* prompt :> axes3 0 4 0 4 0 4 :blue :> join [(3.5|0|0)(3.5|0|3.5)(0|0|3.5)] :darkgrey ‘outline’ of y = 0 plane :> line (0|0|0) (1.5|2|2.5) :black position vector to point R :> line (1.5|0|2.5) (1.5|2|2.5) :darkgrey vertical to y = 0 plane at pont P

Page 56: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space :> line (1.5|0|2.5) (0|0|0) :darkgrey position vector to point P :> line (1.5|0|2.5) (0|0|2.5) :darkgrey line from P to z-axis // to x-axis > blank line to exit prompt and then gwrite labels > gwrite [X] (205|-205) 3 :black > gwrite [Y] (-205|205) 3 :black > gwrite [Z] (-25|-105) 3 :black > gwrite [R] (65|60) 3 :black > rl (-80|-70) 45 gwrite [r] (-80|-70) 3 :black > gwrite [O] (-215|-210) 3 :black > gwrite [P] (65|-140) 3 :black > gwrite [Q] (-105|-140) 3 :black > gwrite [l a t eq ang P O R] (-100|150) 3 :black > gwrite [l o n eq ang Q O P] (-100|120) 3 :black > rl (-100|-190) 13 gwrite [p eq r $1 c o s $2 l a t] (-100|-190) 2 :black p = r * cos lat > gwrite [x eq p $1 s i n $2 l o n] (-50|-130) 2 :black x = p * sin lon = r * cos lat * sin lon > gwrite [y eq r $1 s i n $2 l a t] (65|-50) 2 :black y = r * sin lat > rl (-185|-180) 30 gwrite [z eq p $1 c o s $2 l o n] (-185|-180) 2 :black // sc 9 z = p * cos lon = r * cos lat * cos lon > to sphere :r :p : local 'lon :p.(1|0) longitude = p’s x value : local 'lat :p.(0|1) latitude = p’s y value : ( :r*(cos :lat)*(sin :lon) : | :r*(sin :lat) : | :r*(cos :lat)*(cos :lon) ) : end sphere > cs cab sphere 200 : grid (0|0) 360 9 360 9 :lightgreen > to equator :col : clone ( spc :col jump (0|0) move (360|0) ) equator is lon = 0..360 at lat = 0 : end equator > to dateline :col : clone ( spc :col jump (180|-90) move (180|90) )dateline is lat = -90..90 at lon = 180 : end dateline > to arctic :col : clone ( spc :col jump (0|66.5) move (360|66.5) )arctic is lon = 0..360 at lat = 66.5 : end arctic > to cancer :col : clone ( spc :col jump (0|23.5) move (360|23.5) )cancer is lon = 0..360 at lat =23.5 : end cancer

Page 57: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space > to capricorn :col : clone (spc :col jump (0|-23.5) move (360|-23.5))capricorn is lon=0..360, lat= -23.5 : end capricorn > to antarctic :col : clone (spc :col jump (0|-66.5) move (360|-66.5))antarctic is lon=0..360, lat = -66.5 : end antarctic > cab sphere 200 prompt :> equator :red :> arctic :blue :> antarctic :blue :> cancer :darkgrey :> capricorn :darkgrey :> dateline :black // screen 10

Now we can develop surfaces for ellipsoids, cylinders, cones, paraboloids, hyperboloids, Mobius Strip and Klein Bottle

> to ellipsoid :a :b :p : local 'e :p.(1|0) : local 'n :p.(0|1) : ( :a*(cos :n)*(sin :e) : | :b*(sin :n) : | :a*(cos :n)*(cos :e) ) : end ellipsoid > cs cab ellipsoid 200 100 : grid (0|0) 360 9 360 9 :lightblue // screen 11 > to cylinder :r :p : local 'x :p.(1|0) : local 'y :p.(0|1) : ( :r*(cos :x) : | :r*(sin :x) : | :y ) : end cylinder > cs cab

Page 58: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space : ( cylinder 100 : grid (0|0) 360 9 360 9 :darkgrey : axes3 -200 200 -200 200 -300 200 :lightblue ) // screen 12

> to cone :r :h :p : local 'x :p.(1|0) : local 'y :p.(0|1) : local 'cr :r*(:h-:y)/:h : ( :cr*(cos :x) : | :cr*(sin :x) : | :y ) : end cone > cs cab : ( cone 150 400 : grid (0|0) 360 9 360 9 :darkgrey : axes3 -200 200 -200 200 -400 300 :lightblue ) // screen 13 > to icone :r :h :p : local 'x :p.(1|0) : local 'y :p.(0|1) : local 'cr :r*:y/:h : ( :cr*(cos :x) : | :y : | :cr*(sin :x) ) : end icone > cs cab : ( axes3 -200 200 -200 200 -200 200 :lightblue : icone 100 150 : grid (-360|-250) 720 10 500 10 :darkgrey ) // screen 14

Page 59: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space

> to paraboloid :a :h :p : local 'u :p.(1|0) : local 'v :p.(0|1) : local 's sqrt (:u/:h) : ( :a*:s*cos :v : | :u : | :a*:s*sin :v ) : end paraboloid > cs xl (0|-200) cab : ( axes3 -200 200 -100 400 -200 200 :lightblue : paraboloid 150 300 : grid (0|0) 400 10 360 9 :darkgrey ) // screen 15 > to hyperboloid :a :c :p : local 'u :p.(1|0) : local 'v :p.(0|1) : local 's sqrt (1+:u*:u) : ( :a*:s*cos :v : | :c*:u : | :a*:s*sin :v ) : end hyperboloid > cs cab : ( axes3 -200 200 -200 200 -200 200 :lightblue : hyperboloid 20 15 : grid (-12|0) 24 1 360 10 :darkgrey ) // screen 16

> to klein8 :r :t :p : local 'u :p.(1|0) : local 'v :p.(0|1) : local 'tv :t*:v : local 'ce 4 + 2*(cos :u)*(cos :tv) - (sin :u)*(sin :tv) : :r*( (sin :v)*:ce : | 2*(cos :u)*(sin :tv) + (sin 2*:u)*(cos :tv) : | (cos :v)*:ce ) : end klein8 > cs oblique 60 (sqrt 3)/2 : klein8 40 1 prompt :> grid (0|0) 180 6 360 6 :cyan :> grid (0|0) 180 180 360 360 :red Mobius Strip – red line shows join // screen 17

Page 60: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

2-3-2-d Space :> grid (180|0) 360 6 360 6 :blue continue to generate a Klein Bottle // screen 18 >

Page 61: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Trees

14 Trees

Mathematically speaking, a tree is a set of nodes that are connected by edges in such a way that there is only one path between any two nodes. If an individual node has been singled out then the tree is called a rooted tree. If the tree splits into two at each node, then it is called a binary tree. For example, to mathematicians, an evolutionary tree is a rooted binary tree, with a single ancestral node as the root. But trees may also be used to represent the mutations of a single gene or a virus like HIV or influenza, human migration patterns, and even the development of languages. (NB Mathematicians have studied trees as part of the wider field of graph theory since 1736, when Leonhard Euler published his first paper on the subject.) From utils.zno load functions, delay, line, join, filltri, fillquad, oblique, grid3 and cube – and widen the graphics window to facilitate the presentations. We will start with trees with two line branches in 2-d space – consider a function to draw a symmetric, rooted binary tree.

> to tree :n :x :a :fx :fa define a function to draw a symmetric, rooted binary tree, : if :n=0 [exit] of depth n, initial branch length x and splay angle a : local 't1 :(turtle pos dir :true pc 0) : ct lt :a drawing performed by the current turtle, ct, and a local : t1 rt :a copy, t1, where ct turns left and t1 turns right by same angle : (ct & t1) and branch shortens at rate fx and angle closes at rate fa : (fd :x tree :n-1 :fx*:x :fa*:a :fx :fa) : end tree

This short function repays a closer inspection. Notice that a block of expressions is evaluated in an & (parallel) context. This context comprises the current turtle and a local copy. But the block being evaluated contains a recursive re-entry to the function itself, and, in this & context, this will lead to the generation of 2n active turtles to effect the drawing of a tree to depth n.

> cs ht > turtle (0|-80) (0|1) :true :black 0 : ( fd 80 tree 6 80 30 4/5 4/5 ) fd 80 draws trunk of tree of depth 6 // screen 1

> 'tbrown <- :(turtle (0|0) (0|-1) :true :brown 0) tbrown > 'tgreen <- :(turtle (0|0) (0|1) :true :green 0) tgreen > 'tblue <- :(turtle (0|0) (1|0) :true :blue 0) tblue > 'tred <- :(turtle (0|0) (-1|0) :true :red 0) tred > cs > (tbrown & tblue & tred & tgreen) 4 turtles each drawing a tree of depth 8 : tree 8 70 30 4/5 4/5 => parallel action // screen 2

Page 62: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Trees

> cs > turtle (0|-100) (0|1) :true :green 0 draw a Pythagorus tree of depth 12 : ( fd 100 tree 12 100 45 2\sqrt 2 1 ) // screen 3 > cs > turtle (0|-20) (0|1) :true :blue 0 draw a ‘honeycomb’ tree – NB scale factors = 1 : tree 8 40 60 1 1 // screen 4

Extend our tree definition to have three line branches but still in 2-d space – ct goes straight ahead, while two local copies, t1 and t2, turn left and right by the splay angle – so symmetry is maintained – and scale factors are as before.

> to tree3b :n :x :a :fx :fa : if :n=0 [exit] : local 't1 :(turtle pos dir :true pc 0) : local 't2 :(turtle pos dir :true pc 0) : t1 lt :a : t2 rt :a : (ct & t1 & t2) : ( fd :x tree3b :n-1 :fx*:x :fa*:a :fx :fa) : end tree3b > cs > turtle (0|-150) (0|1) :true :blue 0 halve branch length while maintaining angle as 90o : ( fd 150 tree3b 8 150 90 1/2 1 ) // screen 5

Page 63: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Trees

> cs > turtle (0|-150) (0|1) :true :red 0 halve branch length while maintaining angle as 60o : ( fd 150 tree3b 9 150 60 1/2 1 ) // screen 6

Reverting to two branches in 2-d space, we repeat the drawings of the Pythagorus and ‘honeycomb’ trees, but instead of lines as branches we will draw filled squares.

> to treesq :n :x :a :fx :fa : to fillsq :x local function to fill square with ct’s pc : local 'p1 pos taking p1 = ct’s pos as its bottom left hand corner : fd :x and moving clockwise around the square : local 'p2 pos to find positions of the other apices p2, p3 and p4 : rt 90 fd :x and leaving ct’s pos and dir as on entry to fillsq : local 'p3 pos : rt 90 fd :x : local 'p4 pos : rt 90 fd :x rt 90 : fillquad :p1 :p2 :p3 :p4 pc pc use fillquad to fill square given by p1, p2, p3, p4 : end : if :n=0 [exit] : local 't1 :(turtle pos dir :true pc 0) : ct lt :a : t1 (rt 90 fd :x/:fx lt 180-:a fd :x rt 90) move t1 to become blh of right branch : (ct & t1) : (fillsq :x fd :x treesq :n-1 :fx*:x :fa*:a :fx :fa) : end treesq > cs ht > 's <- 80*sqrt 2 s = size of 'square trunk' s > xl (-:s/2|-:s/2) xl to ‘centre align’ square tree : ( fillquad (0|0)(0|-:s)(:s|-:s)(:s|0) :blue :blue draw trunk : turtle (0|0) (0|1) :true :blue 0 : treesq 10 80 45 2\sqrt 2 1 ) draw Pythagorus tree // screen 7 > cs > turtle (-20|0) (0|1) :true :blue 0 : treesq 6 40 60 1 1 draw ‘honeycomb’ tree // screen 8

Page 64: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Trees

Now, we explore drawing trees in 3-d space. From our earlier investigations of 3-d drawing in 3-2-d-Space, we recall that the order of drawing is critical to achieve the correct visual effect, viz back and left must be drawn before front and right but the order within the two pairs does not matter – and where back and front are determined by their z-values, and left and right by their x-values. To demonstrate these ‘rules’ again, we define ‘planar’ 3-d trees, ie one where we draw on the z = 0 plane and the other on the x = 0 plane.

> to tree3dxy :n :x :a :fx :fa z = 0 plane : if :n=0 [exit] : local 'c cos :a local variables for cos a and sin a to avoid : local 's sin :a re-calculation and improve legibility : local 't3 :(turtle pos (c,-s,0|s,c,0|0,0,1)*dir :true pc 0) 3-d left turn : local 't4 :(turtle pos (c,s,0|-s,c,0|0,0,1)*dir :true pc 0) 3-d right turn : (t3&t4) ( fd :x tree3dxy :n-1 :fx*:x :fa*:a :fx :fa) : end tree3dxy > to tree3dyz :n :x :a :fx :fa x = 0 plane : if :n=0 [exit] : local 'c cos :a : local 's sin :a : local 't1 :(turtle pos (1,0,0|0,c,-s|0,s,c)*dir :true pc 0) : local 't2 :(turtle pos (1,0,0|0,c,s|0,-s,c)*dir :true pc 0) : (t1&t2) ( fd :x tree3dyz :n-1 :fx*:x :fa*:a :fx :fa) : end tree3dyz > cs ht > xl (0|-150) delays only to slow execution : oblique 30 1/2 : ( turtle (0|70|00) (0|sin 30|cos 30) :true :lightblue 0 : tree3dyz 6 70 30 3/4 4/5 draw ‘back’ tree, ie +ve z : delay 500 : turtle (0|70|0) (-cos 30|sin 30|0) :true :red 0 : tree3dxy 6 70 30 3/4 4/5 draw ‘left’ tree, ie –ve x : delay 500 : turtle (0|70|0) (0|sin 30|-cos 30) :true :lightblue 0 : tree3dyz 6 70 30 3/4 4/5 draw ‘front’ tree, ie –ve z : delay 500 : turtle (0|70|0) (cos 30|sin 30|0) :true :red 0 : tree3dxy 6 70 30 3/4 4/5 draw ‘right’ tree, ie +ve x

Page 65: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Trees

: delay 500 : turtle (0|0|0) (0|1|0) :true :brown 0 : move (0|70|0) ) draw brown trunk > xl (0|-200) draw grey ‘plane’ boxes : oblique 30 1/2 : turtle (0|0|0) (0|1|0) :true :lightgrey 0 : ( move (250|0|0) move (250|350|0) move (-250|350|0) : move (-250|0|0) move (0|0|0) move (0|0|250) : move (0|350|250) move (0|350|-250) : move (0|0|-250) move (0|0|0) move (0|350|0) ) // screen 9

Combining these ‘planar’ trees, we can draw a 3-d tree with four branches at each node

> to tree3d :n :x :a :fx :fa : if :n=0 [exit] : local 'c cos :a : local 's sin :a : local 't1 :(turtle pos (1,0,0|0,c,-s|0,s,c)*dir :true pc 0) : local 't2 :(turtle pos (1,0,0|0,c,s|0,-s,c)*dir :true pc 0) : local 't3 :(turtle pos (c,-s,0|s,c,0|0,0,1)*dir :true pc 0) : local 't4 :(turtle pos (c,s,0|-s,c,0|0,0,1)*dir :true pc 0) : (t1&t2&t3&t4) ( fd :x tree3d :n-1 :fx*:x :fa*:a :fx :fa) : end tree3d > cs > xl (-280|-260) enclosing grey cube : oblique 30 1/2 : cube (0|0|0) 380 :lightgrey > xl (0|-150) : oblique 30 1/2 : ( turtle (0|80|00) (0|sin 30|cos 30) :true :yellow 0 back : tree3d 5 80 30 3/4 4/5 : delay 500 : turtle (0|80|0) (-cos 30|sin 30|0) :true :green 0 left : tree3d 5 80 30 3/4 4/5 : delay 500 : turtle (0|80|0) (0|sin 30|-cos 30) :true :cyan 0 front : tree3d 5 80 30 3/4 4/5 : delay 500 : turtle (0|80|0) (cos 30|sin 30|0) :true :lightgreen 0 right : tree3d 5 80 30 3/4 4/5 : delay 500 : turtle (0|-60|0) (0|1|0) :true :brown 0 brown trunk : move (0|80|0) ) // screen 10

Page 66: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Trees

Some trees have characteristics similar to fractals – in particular, those that maintain splay angle but reduce branch length – and it is to the topic of fractals that we turn next.

Page 67: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

15 Fractals A fractal is a fragmented geometric shape that can be split into parts, each of which is (at least approximately) a reduced-size copy of the whole – this is a property called self-similarity. The mathematical study of self-similarity goes back to the 17th century, however, the term fractal was coined by Mandelbrot in 1975 and was derived from the Latin fractus meaning “broken” or “fractured”. Because they appear similar at all levels of magnification, fractals are often considered to be infinitely complex (in informal terms) – but, fortunately for us, fractals have fairly simple recursive definitions. Natural objects that are approximated by fractals include clouds, mountain ranges, lightning bolts, coastlines, snow flakes, various vegetables (cauliflower and broccoli), and animal coloration patterns. There are several types of fractals – we will start with ‘line curves’, and perhaps the best known of these, the Koch curve (aka the ‘snowflake’). From utils.zno, load the functions line and join.

// Koch 'snowflake' curve generator function > to genK :plist plist is list of points => used by join to draw lines : if null :plist#-1 [value :plist] adds 3 new points between each pair of points : local 'a :plist#1 n' = n + 3(n-1) = 4n-3 : local 'b :plist#2 ie number of points grows at a rate of 4n-3 : local 'p1 (2*:a+:b)/3 p1 is 1/3 from a to b : local 'l mod :a-:b l = length of line segment : local 'v (:b-:a)/:l unit vector of line to b from a : local 't :(turtle :p1 :v :false 0 0) t is turtle at p1 with dir v (and pen up) : t (lt 60 fd :l/3) turn and move t to apex of tri, ie t’s pos is p2 : local 'p2 t pos p2 is pos of t : local 'p3 (:a+2*:b)/3 p3 is 2/3 from a to b : list [:a :p1 :p2 :p3], genK :plist#-1 insert points p1, p2, p3 between a and b : end and concatenate with genK of rest of list genK > cs ht > 'Koch <- [(0|0)(1|0)] start with Koch = list of two points, (0|0) and (1|0) Koch > xl (-150|-225) 300* join :Koch :blue draw 300* join of these points at (-150|-225) 1st call to genK => adds 3 new points to list of points > 'Koch <- genK :Koch viz p1 at 1/3 from a to b, p3 at 2/3 from a to b, Koch and p2 which is the apex of the equilateral triangle with p1 p3 as its base > xl (-150|-175) 300* join :Koch :blue draw Koch again to show 1st generation curve > 'Koch <- genK :Koch repeat (generate and draw) up to 5 generations Koch number of points grows at a rate of 4n - 3 > xl (-150|-100) 300* join :Koch :blue gen points 0 2 > 'Koch <- genK :Koch 1 5 Koch 2 17 3 65 > xl (-150|0) 300* join :Koch :blue 4 257 5 1025 > 'Koch <- genK :Koch Koch

Page 68: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> xl (-150|100) 300* join :Koch :blue > 'Koch <- genK :Koch Koch > xl (-150|200) 300* join :Koch :red // screen 1

// change screen mode to 'console on top' > cs draw 3 ‘flakes’ – based on the sides of a triangle, a square and a hexagon > xl(-450|50) 250* : ( join [(0|0)(cos 60|sin 60) : (1|0)(0|0)] :lightgrey draw a triangle : ( rl (0|0) 60 then draw the Koch curve : & rr (1|0) 60 along its 3 sides : & xl (1|0) rr (0|0) 180 ) : join :Koch :blue ) > xl(200|50) 200* : ( join [(0|0) (0|1)(1|1) : (1|0)(0|0)] :lightgrey draw a square : ( rl (0|0) 90 then draw the Koch curve : & xl (0|1) along its 4 sides : & xl (1|1) rr (0|0) 90 : & xl (1|0) rr (0|0) 180 ) : join :Koch :blue ) > xl(-175|-200) 200* : ( join [(0|0)(0|1)(cos 30|1+sin 30) : (2*cos 30|1)(2*cos 30|0) : (cos 30|-sin 30) (0|0)] :lightgrey draw a hexagon : ( rl (0|0) 90 then draw the Koch curve

Page 69: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

: & xl (0|1) rl (0|0) 30 along its 6 sides : & xl (cos 30|1+sin 30) rr (0|0) 30 : & xl (2*cos 30|1) rr (0|0) 90 : & xl (2*cos 30|0) rl (0|0) 210 : & xl (cos 30|-sin 30) rl (0|0) 150 ) : join :Koch :blue ) // screen 2 > xl(-450|50) 250* : join [(0|0)(cos 60|sin 60) : (1|0)(0|0)] :white delete the triangle, ie 'white' it out > xl(200|50) 200* : join [(0|0) (0|1)(1|1) : (1|0)(0|0)] :white 'white' out the drawn square > xl(-175|-200) 200* : join [(0|0)(0|1)(cos 30|1+sin 30) : (2*cos 30|1)(2*cos 30|0) : (cos 30|-sin 30) (0|0)] :white 'white' out the drawn hexagon

// screen 3 > 'Koch <- [] set Koch = [ ] to ‘release’ working space Koch

So, now we have the schema for creating fractal line curves – write the generator function to introduce new points for the desired pattern between each pair of points – draw the starting line – then generate and draw the next generation of the curve – until bored or the system runs out of working space. We will draw four more – Koch’s Quadratics 1 and 2, Levy’s C and Heighway’s Dragon.

// Koch Quadratic 1 // reset screen mode > to genKQ1 :plist adds 4 new points between each pair of points : if null :plist#-1 [value :plist] => rate of growth is 5n-4 : local 'a :plist#1 : local 'b :plist#2 see screen 4 for pattern – similar to Koch curve : local 'p1 (2*:a+:b)/3 ie based on 1/3 but with square instead of triangle : local 'l mod :a-:b : local 'v (:b-:a)/:l : local 't :(turtle :p1 :v :false 0 0) : t (lt 90 fd :l/3) : local 'p2 t pos : t (rt 90 fd :l/3) : local 'p3 t pos : local 'p4 (:a+2*:b)/3 : list [:a :p1 :p2 :p3 :p4], genKQ1 :plist#-1

Page 70: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

: end genKQ1 > cs ht > 'KQ1 <- [(0|0)(1|0)] again start with plist = [(0|0) (1|0)] KQ1 > xl (-100|-300) 200* join :KQ1 :blue > 'KQ1 <- genKQ1 :KQ1 KQ1 > xl (-100|-250) 200* join :KQ1 :blue > 'KQ1 <- genKQ1 :KQ1 KQ1 > xl (-100|-100) 200* join :KQ1 :blue > 'KQ1 <- genKQ1 :KQ1 KQ1 > xl (-100|50) 200* join :KQ1 :blue > 'KQ1 <- genKQ1 :KQ1 KQ1 > xl (-100|200) 200* join :KQ1 :red // screen 4 'KQ1 <- [] again return KQ1’s attached list to working space KQ1 // Koch Quadratic 2 > to genKQ2 :plist adds 6 new points between each pair of points : if null :plist#-1 [value :plist] => rate of growth is 7n-6 : local 'a :plist#1 this pattern is based on ¼ of each line : local 'b :plist#2 with one square above and one below the line : local 'p1 (3*:a+:b)/4 : local 'l mod :a-:b : local 'v (:b-:a)/:l : local 't :(turtle :p1 :v :false 0 0) : t (lt 90 fd :l/4) square : local 'p2 t pos : t (rt 90 fd :l/4) : local 'p3 t pos : local 'p4 (:a+:b)/2 : t (rt 90 fd :l/2) square : local 'p5 t pos : t (lt 90 fd :l/4) square : local 'p6 t pos : local 'p7 (:a+3*:b)/4 : list [:a :p1 :p2 :p3 :p4 :p5 :p6 :p7], genKQ2 :plist#-1 :end genKQ2 > cs ht > 'KQ2 <- [(0|0)(1|0)] KQ2 > xl (-100|-250) 200* join :KQ2 :blue

Page 71: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> 'KQ2 <- genKQ2 :KQ2 KQ2 > xl (-100|-100) 200* join :KQ2 :blue > 'KQ2 <- genKQ2 :KQ2 KQ2 > xl (-100|50) 200* join :KQ2 :blue > 'KQ2 <- genKQ2 :KQ2 KQ2 > xl (-100|200) 200* join :KQ2 :red // screen 5 > 'KQ2 <- [] KQ2

// change screen mode to 'console on top' // Levy C > to genLevy :plist adds 1 new point between each pair of points : if null :plist#-1 [value :plist] => rate of growth is 2n-1 : local 'a :plist#1 new point is apex of the right-angled isosceles : local 'b :plist#2 triangle with a b as its base : local 'l mod :a-:b : local 'v (:b-:a)/:l : local 't :(turtle :a :v :false 0 0) : t (lt 45 fd :l/sqrt 2) : local 'p1 t pos : list [:a :p1], genLevy :plist#-1 list : end genLevy > cs ht > 'Levy <- [(0|0)(0|1)] start with a vertical line this time, Levy ie from (0|0) to (0|1) > xl (450|-100) 200* join :Levy :blue and draw the generations from right to left to see the C shape emerge > 'Levy <- genLevy :Levy Levy > xl (400|-100) 200* join :Levy :blue

Page 72: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> 'Levy <- genLevy :Levy Levy > xl (250|-100) 200* join :Levy :blue > 'Levy <- genLevy :Levy Levy > xl (100|-100) 200* join :Levy :blue > 'Levy <- genLevy :Levy Levy > xl (-50|-100) 200* join :Levy :blue > 'Levy <- genLevy :Levy Levy > xl (-250|-100) 200* join :Levy :blue > 'Levy <- genLevy :Levy // screen 6 Levy > cs > xl (400|-100) 200* join :Levy :blue > 'Levy <- genLevy :Levy Levy > xl (100|-100) 200* join :Levy :blue > 'Levy <- genLevy :Levy Levy > xl (-200|-100) 200* join :Levy :red // screen 7 'Levy <- [] Levy

// Heighway's Dragon > to genHD :plist :d adds 1 new point between each pair of points : if null :plist#-1 [value :plist] NB d is direction switch set to 1 or -1 : local 'a :plist#1 where d = 1 for lt, and d = -1 for rt : local 'b :plist#2 otherwise similar to Levy C : local 'l mod :a-:b rate of growth is still 2n-1 : local 'v (:b-:a)/:l

Page 73: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

: local 't :(turtle :a :v :false 0 0) : t (lt :d*45 fd :l/sqrt 2) : local 'p1 t pos : list [:a :p1], genHD :plist#-1 (-:d) re-enter genHD with d switched : end genHD > cs ht > 'HD <- [(0|1)(0|0)] again start with a vertical line from (0|0) to (0|1) HD but this time drawings appear from left to right > xl (-400|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (-350|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (-200|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (-50|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (100|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (300|-100) 200* join :HD :blue // screen 8 > cs > 'HD <- genHD :HD 1 HD > xl (-400|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (-200|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (0|-100) 200* join :HD :blue > 'HD <- genHD :HD 1 HD > xl (200|-100) 200* join :HD :red // screen 9 > 'HD <- [] HD

Page 74: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

Time to stop playing with snowflakes and dragons, and to start thinking about fractals derived from triangles and quadrilaterals. First, we will consider two ways to draw Sierpinski’s triangle – using line drawing or ‘cutting holes’. Earlier we loaded line and join from utils.zno, now add filltri and fillquad. Line drawing – draw any triangle – then draw 3 triangles: one for each apex with the mid-points of its two component lines – and repeat until ‘granularity becomes too small’.

// Sierpinski triangle - line drawing > to tri :a :b :c :col :g works for any 3 points a, b, c : join [:a :b :c :a] :col draw tri ab, bc, ca using join : if mod :a-:b < :g [exit] stop when length (ab) < g (granularity) : tri :a (:a+:b)/2 (:a+:c)/2 :col :g else draw tri for a and mid-points of ab and ac : tri (:a+:b)/2 :b (:b+:c)/2 :col :g then …………...b .............................ab ….. bc : tri (:a+:c)/2 (:b+:c)/2 :c :col :g and ……............c …………………..ac …. bc : end tri > cs ht draw a green isosceles Sierpinski triangle and again in blue but inverted to ‘interlock’ with the green > tri (0|256) (-256|-256) (256|-256) :green 8 // screen 10 > tri (-256|256) (0|-256) (256|256) :blue 8 // screen 11

> cs mirror red and blue triangles > tri (0|256) (-256|-256) (0|-256) :red 8 > tri (0|256) (256|-256) (0|-256) :blue 8 // screen 12

Page 75: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> cs ‘quarters’ in green and blue > tri (-256|256) (0|0) (256|256) :blue 8 > tri (-256|-256) (0|0) (256|-256) :blue 8 > tri (-256|256) (0|0) (-256|-256) :green 8 > tri (256|256) (0|0) (256|-256) :green 8 // screen 13

Now, instead of repeatedly drawing the shape in smaller and smaller sizes to create our final picture, we fill the original full-size shape with colour and then ‘cut out holes’, ie fill the ‘holes’ in white, to achieve the desired picture. Re-draw the Sierpinski triangle this way.

// Sierpinski triangle - 'filled' shapes > to Siertri :a :b :c :col :g works for any triangle given by a, b, c : to t1 :x :y :z local function t1 – ‘whites’ out the ‘holes’ : if mod (:x-:y) < :g [exit] same termination condition as before : filltri (:x+:y)/2 (:y+:z)/2 (:z+:x)/2 :white :white : t1 :x (:x+:y)/2 (:z+:x)/2 : t1 (:x+:y)/2 :y (:y+:z)/2 : t1 (:x+:z)/2 (:y+:z)/2 :z : end : filltri :a :b :c :col :col fill original tri with col : t1 :a :b :c t1 'whites’ out the 'holes' : end Siertri > cs > Siertri (-300|-300) (0|300) (300|-300) :blue 8 // screen 14

The next four fractals are based on the repeated sub-division of quadrilaterals into nine similar quads by joining the 1/3 and 2/3 points of opposite sides. Selected sub-quads are 'cut out', ie filled with white, and the process is repeated with the others. The functions below assume the following order and labelling -

b +---+---+---+ c | 4 | 5 | 6 | +---+---+---+ B +---+ C | 3 | 1 | 7 | | 1 | +---+---+---+ A +---+ D | 2 | 9 | 8 | a +---+---+---+ d

Page 76: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

// Sierpinski quadrilateral - aka 'carpet' - white 1, re-enter 2..9 > to Sierquad :a :b :c :d :col :g // works for any 4 points : to f1 :x :y :z :w : if mod :x-:y < :g [exit] // g is granularity : local 'A (4*:x + 2*:y + :z + 2*:w)/9 : local 'B (2*:x + 4*:y + 2*:z + :w)/9 : local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 : local 'D (2*:x + :y + 2*:z + 4*:w)/9 : fillquad :A :B :C :D :white :white // 1 - white : f1 :x (2*:x+:y)/3 :A (2*:x+:w)/3 // 2 - re-enter : f1 (2*:x+:y)/3 (:x+2*:y)/3 :B :A // 3 - re-enter : f1 (:x+2*:y)/3 :y (2*:y+:z)/3 :B // 4 - re-enter : f1 :B (2*:y+:z)/3 (:y+2*:z)/3 :C // 5 - re-enter : f1 :C (:y+2*:z)/3 :z (2*:z+:w)/3 // 6 - re-enter : f1 :D :C (2*:z+:w)/3 (:z+2*:w)/3 // 7 - re-enter : f1 (:x+2*:w)/3 :D (:z+2*:w)/3 :w // 8 - re-enter : f1 (2*:x+:w)/3 :A :D (:x+2*:w)/3 // 9 - re-enter : end : fillquad :a :b :c :d :col :col : f1 :a :b :c :d : end Sierquad > cs > Sierquad (-300|-300) (-300|300) (300|300) (300|-300) :blue 10 // sc 15

// Vicsekplus - white 2, 4, 6, 8 – re-enter 1, 3, 5, 7, 9 > to Vicsekplus :a :b :c :d :col :g // works for any 4 points : to f1 :x :y :z :w : if mod :x-:y < :g [exit] // g is granularity : local 'A (4*:x + 2*:y + :z + 2*:w)/9 : local 'B (2*:x + 4*:y + 2*:z + :w)/9 : local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 : local 'D (2*:x + :y + 2*:z + 4*:w)/9 : f1 :A :B :C :D // #1 - re-enter : fillquad :x (2*:x+:y)/3 :A (2*:x+:w)/3 :white :white // #2 - white : f1 (2*:x+:y)/3 (:x+2*:y)/3 :B :A // #3 - re-enter : fillquad (:x+2*:y)/3 :y (2*:y+:z)/3 :B :white :white // #4 - white : f1 :B (2*:y+:z)/3 (:y+2*:z)/3 :C // #5 - re-enter : fillquad :C (:y+2*:z)/3 :z (2*:z+:w)/3 :white :white // #6 - white : f1 :D :C (2*:z+:w)/3 (:z+2*:w)/3 // #7 - re-enter : fillquad (:x+2*:w)/3 :D (:z+2*:w)/3 :w :white :white // #8 - white : f1 (2*:x+:w)/3 :A :D (:x+2*:w)/3 // #9 - re-enter : end : fillquad :a :b :c :d :col :col : f1 :a :b :c :d

Page 77: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

: end Vicsekplus > cs > Vicsekplus (-300|-300) (-300|300) (300|300) (300|-300) :blue 7 // sc 16 // VicsekX - white 3, 5, 7, 9 – re-enter 1, 2, 4, 6, 8 > to VicsekX :a :b :c :d :col :g // works for any 4 points : to f1 :x :y :z :w : if mod :x-:y < :g [exit] // g is granularity : local 'A (4*:x + 2*:y + :z + 2*:w)/9 : local 'B (2*:x + 4*:y + 2*:z + :w)/9 : local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 : local 'D (2*:x + :y + 2*:z + 4*:w)/9 : f1 :A :B :C :D // #1 - re-enter : f1 :x (2*:x+:y)/3 :A (2*:x+:w)/3 // #2 - re-enter : fillquad (2*:x+:y)/3 (:x+2*:y)/3 :B :A :white :white // #3 - white : f1 (:x+2*:y)/3 :y (2*:y+:z)/3 :B // #4 - re-enter : fillquad :B (2*:y+:z)/3 (:y+2*:z)/3 :C :white :white // #5 - white : f1 :C (:y+2*:z)/3 :z (2*:z+:w)/3 // #6 - re-enter : fillquad :D :C (2*:z+:w)/3 (:z+2*:w)/3 :white :white // #7 - white : f1 (:x+2*:w)/3 :D (:z+2*:w)/3 :w // #8 - re-enter : fillquad (2*:x+:w)/3 :A :D (:x+2*:w)/3 :white :white // #9 - white : end : fillquad :a :b :c :d :col :col : f1 :a :b :c :d : end VicsekX > cs > VicsekX (-300|-300) (-300|300) (300|300) (300|-300) :blue 7 // sc 17

// Cantor Dust - white 1, 3, 5, 7, 9 – re-enter 2, 4, 6, 8 > to Cantor :a :b :c :d :col :g // works for any 4 points : to f1 :x :y :z :w : if mod :x-:y < :g [exit] // g is granularity : local 'A (4*:x + 2*:y + :z + 2*:w)/9 : local 'B (2*:x + 4*:y + 2*:z + :w)/9 : local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 : local 'D (2*:x + :y + 2*:z + 4*:w)/9 : fillquad :A :B :C :D :white :white // #1 - white : f1 :x (2*:x+:y)/3 :A (2*:x+:w)/3 // #2 - re-enter : fillquad (2*:x+:y)/3 (:x+2*:y)/3 :B :A :white :white // #3 - white : f1 (:x+2*:y)/3 :y (2*:y+:z)/3 :B // #4 - re-enter : fillquad :B (2*:y+:z)/3 (:y+2*:z)/3 :C :white :white // #5 - white

Page 78: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

: f1 :C (:y+2*:z)/3 :z (2*:z+:w)/3 // #6 - re-enter : fillquad :D :C (2*:z+:w)/3 (:z+2*:w)/3 :white :white // #7 - white : f1 (:x+2*:w)/3 :D (:z+2*:w)/3 :w // #8 - re-enter : fillquad (2*:x+:w)/3 :A :D (:x+2*:w)/3 :white :white // #9 - white : end : fillquad :a :b :c :d :col :col : f1 :a :b :c :d : end Cantor > cs Cantor Dust for g = 50 and g = 10 > Cantor (-300|-300) (-300|300) (300|300) (300|-300) :red 50 // screen 18 > Cantor (-300|-300) (-300|300) (300|300) (300|-300) :red 10 // screen 19

Our final 2-d shape fractal – the T-Square fractal – does not ‘cut holes’ in an original shape but rather builds up its shape by adding smaller replicas of the original shape. Start with a square – add 4 new squares, one around each corner, with side = 1/2 previous size. Squares are defined as a 'centre', side length and colour – sqline draws a 'line' square and sqfill draws a filled square. Unlike Cantor which 'disappears' after infinite iterations – T-Square’s boundary is a square of twice the original side length.

> to sqline :c :s :col // line square with centre c and side s : local 'h :s/2 : join list [:c+(-:h|-:h) :c+(-:h|:h) :c+(:h|:h) :c+(:h|-:h) :c+(-:h|-:h)] :col : end sqline > to sqfill :c :s :col // square with centre c and side s filled with col : local 'h :s/2 : fillquad :c+(-:h|-:h) :c+(-:h|:h) :c+(:h|:h) :c+(:h|-:h) :col :col : end sqfill > to TSquare :c :s :col :g : to t1 :x :y : if :y < :g [exit] // g is granularity : sqfill :x :y :col : local 'h :y/2 : t1 :x+(-:h|-:h) :h : t1 :x+(-:h|:h) :h : t1 :x+(:h|:h) :h : t1 :x+(:h|-:h) :h : end : sqline :c 2*:s :col // draw boundary line square : t1 :c :s // t1 is the generator function

Page 79: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

: end TSquare // change screen to 'console on top' > cs ht draw original + 5 generations of TSquare (by using g as the control of granularity) > xl (-300|150) TSquare (0|0) 150 :black 150 > xl (0|150) TSquare (0|0) 150 :black 75 > xl (300|150) TSquare (0|0) 150 :black 37 > xl (-300|-150) TSquare (0|0) 150 :black 18 > xl (0|-150) TSquare (0|0) 150 :black 9 > xl (300|-150) TSquare (0|0) 150 :black 4 // screen 20

We turn our attention to 3-d shape fractals, starting with a Sierpinski square pyramid, then two cube-based fractals – Cantor Dust and Vicsek Plus. Can we use the 2-d methods for drawing Sierpinski triangles explored earlier – line drawing and hole cutting – to produce a ‘realistic’ 3-d pyramid?

// Sierpinski (square) pyramid // use tri and Siertri from above to assist investigation // load oblique,grid3 and cube from utils.zno > cs ht // draw 'hollow' pyramid of 4 tri's

Page 80: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> xl (-250|-200) : oblique 30 1/2 : ( tri (0|0|0) (200|400|200) (0|0|400) :lightgrey 20 : tri (0|0|400) (200|400|200) (400|0|400) :darkgrey 20 : tri (400|0|400) (200|400|200) (400|0|0) :blue 20 : tri (0|0|0) (200|400|200) (400|0|0) :lightblue 20 ) // screen 21 > cs // draw 'solid' pyramid of 2 Siertri's > xl (-250|-200) : oblique 30 1/2 : ( Siertri (400|0|400) (200|400|200) (400|0|0) :blue 20 : Siertri (0|0|0) (200|400|200) (400|0|0) :lightblue 20 ) // screen 22

While giving some impression of our desired Sierpinski pyramid, these results are not really satisfactory. We need to build up our pyramid from its base with the ‘smallest’ (as determined by granularity) solid pyramids. Noting that the number of ‘small’ pyramids along each side of our base must be a power of 2, we will set granularity as a parameter, p2, such that

when p2 = 0 => number of pyramids is 20 = 1, ie draw 1 pyr p2 = n for n ≠ 0 => draw 5 x (p2 = n-1) pyrs, ie 4 as the square base + 1 on top

> to Sierpyramid :p2 :blh :s :frontcol :sidecol : to pyr :blh : local 'apex (:s/2|:s|:s/2) : filltri :blh+(:s|0|0) :blh+:apex :blh+(:s|0|:s) :sidecol :black : filltri :blh+(0|0|0) :blh+:apex :blh+(:s|0|0) :frontcol :black : end : if :p2 = 0 [pyr :blh exit] : local 'd :s*2^(:p2-1) : Sierpyramid :p2-1 :blh + (0|0|:d) :s :frontcol :sidecol back left : Sierpyramid :p2-1 :blh + (:d|0|:d) :s :frontcol :sidecol back right : Sierpyramid :p2-1 :blh :s :frontcol :sidecol front left : Sierpyramid :p2-1 :blh + (:d|0|0) :s :frontcol :sidecol front right : Sierpyramid :p2-1 :blh + (:d/2|:d|:d/2) :s :frontcol :sidecol top : end Sierpyramid // draw 4 pyramids of same size but different granularities > cs ht > xl (-500|-200) : oblique 30 1/2 : Sierpyramid 2 (0|0|0) 80 :lightgrey :darkgrey fit 22 = 4 pyrs per side of base > xl (0|-200) : oblique 30 1/2

Page 81: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

: Sierpyramid 3 (0|0|0) 40 :lightgrey :darkgrey 23 = 8 pyrs per side // sc 23 > cs > xl (-500|-200) : oblique 30 1/2 : Sierpyramid 4 (0|0|0) 20 :lightgrey :darkgrey 24 = 16 pyrs per side > xl (0|-200) : oblique 30 1/2 : Sierpyramid 5 (0|0|0) 10 :lightgrey :darkgrey 25 = 32 pyrs per side // sc 24

Tip? To see in better detail set Zoom to 500%. Draw 3-d Cantor Dust and Vicsek Plus fractals by repeatedly sub-dividing a cube into 27 sub-cubes, ie 3 layers of 9 each, say back, middle and front. Number and label as follows –

+---+---+---+ | 7 | 8 | 9 | +---+---+---+ | 4 | 5 | 6 | +---+---+---+ | 1 | 2 | 3 | (b)lh +---+---+---+

Unlike in 2-d, when we 'whited-out' some quads and re-entered with the others to continue processing - here we are only concerned with those to process, ie 'whiting out' is replaced by simply not processing them further. Cantor Dust 3-d back and front - re-enter with 1,3,7,9

middle - all 'white' Vicsek Plus 3-d back and front - re-enter with 5 middle - re-enter with 2,4,5,6,8

> to fillcube :blh :s :frontcol :sidecol :topcol solid cube – 3 faces only : fillquad :blh+(0|:s|0) :blh+(0|:s|:s) : :blh+(:s|:s|:s) :blh+(:s|:s|0) :topcol :black top face : fillquad :blh+(:s|0|0) :blh+(:s|:s|0) : :blh+(:s|:s|:s) :blh+(:s|0|:s) :sidecol :black side face : fillquad :blh :blh+(0|:s|0) : :blh+(:s|:s|0) :blh+(:s|0|0) :frontcol :black front face : end NB boundary is always black to add sharpness fillcube

Page 82: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> to Cantor3d :blh :s :frontcol :sidecol :topcol :g : to bf :b :x // cubes 1,3,7,9 : local 'x2 2*:x : Cantor3d :b :x :frontcol :sidecol :topcol :g // 1 : Cantor3d :b+(:x2|0|0) :x :frontcol :sidecol :topcol :g // 3 : Cantor3d :b+(0|:x2|0) :x :frontcol :sidecol :topcol :g // 7 : Cantor3d :b+(:x2|:x2|0) :x :frontcol :sidecol :topcol :g // 9 : end : local 'x1 :s/3 : local 'x2 2*:x1 : if :x1/3 < :g // is next generation < granularity? : [ fillcube :blh+(0|0|:x2) :x1 :frontcol :sidecol :topcol // b1 : fillcube :blh+(:x2|0|:x2) :x1 :frontcol :sidecol :topcol // b3 : fillcube :blh+(0|:x2|:x2) :x1 :frontcol :sidecol :topcol // b7 : fillcube :blh+(:x2|:x2|:x2) :x1 :frontcol :sidecol :topcol // b9 : fillcube :blh :x1 :frontcol :sidecol :topcol // f1 : fillcube :blh+(:x2|0|0) :x1 :frontcol :sidecol :topcol // f3 : fillcube :blh+(0|:x2|0) :x1 :frontcol :sidecol :topcol // f7 : fillcube :blh+(:x2|:x2|0) :x1 :frontcol :sidecol :topcol // f9 : exit ] : bf :blh+(0|0|:x2) :x1 : bf :blh :x1 : end Cantor3d > cs ht draw 4 views of Cantor Dust with decreasing g, ie getting smaller, inside wireframe cube > xl (-500|-200) : oblique 30 1/2 : ( cube (0|0|0) 300 :lightgrey : Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 100 ) > xl (0|-200) : oblique 30 1/2 : ( cube (0|0|0) 300 :lightgrey : Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 20 ) // screen 25 > cs > xl (-500|-200) : oblique 30 1/2 : ( cube (0|0|0) 300 :lightgrey : Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 5 ) > xl (0|-200) : oblique 30 1/2 : ( cube (0|0|0) 300 :lightgrey : Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 2 ) // screen 26

Page 83: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> to VicsekPlus3d :blh :s :frontcol :sidecol :topcol :g : : to bf :b :x // cube 5 : VicsekPlus3d :b+(:x|:x|0) :x :frontcol :sidecol :topcol :g // 5 : end : : to mid :b :x // cubes 2,4,5,6,8 : local 'x2 2*:x : VicsekPlus3d :b+(:x|0|0) :x :frontcol :sidecol :topcol :g // 2 : VicsekPlus3d :b+(0|:x|0) :x :frontcol :sidecol :topcol :g // 4 : VicsekPlus3d :b+(:x|:x|0) :x :frontcol :sidecol :topcol :g // 5 : VicsekPlus3d :b+(:x2|:x|0):x :frontcol :sidecol :topcol :g // 6 : VicsekPlus3d :b+(:x|:x2|0):x :frontcol :sidecol :topcol :g // 8 : end : : local 'x1 :s/3 : local 'x2 2*:x1 : if :x1/3 < :g // is next generation < granularity? : [ fillcube :blh+(:x1|:x1|:x2) :x1 :frontcol :sidecol :topcol // b5 : fillcube :blh+(:x1|0|:x1) :x1 :frontcol :sidecol :topcol // m2 : fillcube :blh+(0|:x1|:x1) :x1 :frontcol :sidecol :topcol // m4 : fillcube :blh+(:x1|:x1|:x1) :x1 :frontcol :sidecol :topcol // m5 : fillcube :blh+(:x2|:x1|:x1) :x1 :frontcol :sidecol :topcol // m6 : fillcube :blh+(:x1|:x2|:x1) :x1 :frontcol :sidecol :topcol // m8 : fillcube :blh+(:x1|:x1|0) :x1 :frontcol :sidecol :topcol // f5 : exit ] : bf :blh+(0|0|:x2) :x1 : mid :blh+(0|0|:x1) :x1 : bf :blh :x1 : end VicsekPlus3d > to cubesPlus :blh :s :col draws line cubes for starting shape : local 's1 :s/3 : local 's2 2*:s1 : cube :blh+(:s1|:s1|:s2) :s1 :col //b5 : cube :blh+(:s1|0|:s1) :s1 :col // m2 : cube :blh+(0|:s1|:s1) :s1 :col // m4 : cube :blh+(:s1|:s1|:s1) :s1 :col // m5 : cube :blh+(:s2|:s1|:s1) :s1 :col // m6 : cube :blh+(:s1|:s2|:s1) :s1 :col // m8 : cube :blh+(:s1|:s1|0) :s1 :col // f5 : end cubesPlus > cs ht draw 4 views of 3-d Vicsek Plus with decreasing g inside wireframe cubes for 3-d + > xl (-500|-200) : oblique 60 2\sqrt 2 : VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 100 > xl (0|-200) : oblique 60 2\sqrt 2 : ( cubesPlus (0|0|0) 300 :lightgrey : VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 20 ) // sc 27 > cs > xl (-500|-200) : oblique 60 2\sqrt 2 : ( cubesPlus (0|0|0) 300 :lightgrey : VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 5 )

Page 84: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Fractals

> xl (0|-200) : oblique 60 2\sqrt 2 : ( cubesPlus (0|0|0) 300 :lightgrey : VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 2 ) // sc 28

Page 85: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

Appendix 1

/////////////////////////// /////////////////////////// // // // Lists - lists.zno // // // /////////////////////////// ///////////////////////////

/////////////////////////////////// // Primitive Recursive Functions // /////////////////////////////////// to eq :x :y :x=:y end to succ :x :x+1 end eq 2 2 eq 1 2 succ 0 succ 3 to pred :x to p1 :n :x if eq (succ :n) :x [val :n] p1 (succ :n) :x end if eq :x 0 [val 0] p1 0 :x end pred 5 to sum :x :y if eq :x 0 [val :y] sum (pred :x) (succ :y) end sum 3 4 to diff :x :y if eq :y 0 [val :x] if eq :x 0 [val 0] diff (pred :x) (pred :y) end diff 7 2 to mult :x :y if eq :x 0 [val 0] sum :y (mult (pred :x) :y) end mult 3 4

Page 86: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

to lessthan :x :y if eq :y 0 [val :false] if eq :x 0 [val :true] lessthan (pred :x) (pred :y) end lessthan 2 3 lessthan 3 3 lessthan 3 2 to quot :x :y if lessthan :x :y [val 0] succ (quot (diff :x :y) :y) end quot 12 3 quot 11 3 quot 2 3 ////////// // Sets // ////////// to mem :i :x if null :x [value :false] if :i=:x#1 [value :true] mem :i :x#-1 end mem 'c [a b c] mem 'd [a b c] mem [b c] [a [b c] d] to union :x :y if null :x [value :y] if mem :x#1 :y [value union :x#-1 :y] list [:x#1],union :x#-1 :y end union [a b c d] [a c e] to inter :x :y if null :x [value []] if mem :x#1 :y [value (list [:x#1],inter :x#-1 :y)] inter :x#-1 :y end inter [a b c d] [a c e]

Page 87: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

/////////////////////////////////// /////////////////////////////////// // // // Utilities - utils.zno // // // /////////////////////////////////// ///////////////////////////////////

to delay :n // used to slow execution - simple animation turtle 0 0 :true 0 0 // NB only pen state is needed repeat :n [ repeat 100 [ pu pd ] ] end ////////////////////////// // 2-d or 3-d drawing // ////////////////////////// to line :p1 :p2 :col // draw line between 2 pts in 1-, 2- or 3-d turtle :p1 0 :true :col 0 move :p2 // NB dir not used - use for functions below end to join :plist :col // join points from given list [p..p] if null :plist#-1 [exit] line :plist#1 :plist#2 :col join :plist#-1 :col end to filltri :a :b :c :fcol :bcol // fill triangle a,b,c to f1 :x :y :z // fcol is fill colour if mod (:y-:z)<1 [exit] // bcol is boundary colour local 'm (:y+:z)/2 line :x :m :fcol f1 :x :y :m f1 :x :m :z end f1 :a :b :c f1 :b :c :a f1 :c :a :b join list [:a :b :c :a] :bcol end to fillquad :a :b :c :d :fcol :bcol // fill quadrilateral a,b,c,d filltri :a :b :c :fcol :fcol // fcol is fill colour filltri :c :d :a :fcol :fcol // bcol is boundary colour join list [:a :b :c :d :a] :bcol end /////////////////// // 2-d drawing // /////////////////// to axes :x1 :x2 :y1 :y2 :col // draw 2-d axes (x1..x2) X (y1..y2) line (:x1|0) (:x2|0) :col line (0|:y1) (0|:y2) :col end to markaxes :x1 :x2 :sx :y1 :y2 :sy :col // mark 2-d axes in steps of sx and sy local 'x :x1 repeat (:x2-:x1)/:sx + 1 [ line (:x|-0.5) (:x|0.5) :col 'x<-:x+:sx ]

Page 88: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

local 'y :y1 repeat (:y2-:y1)/:sy + 1 [ line (-0.5|:y) (0.5|:y) :col 'y<-:y+:sy ] end to grid :blh :w :sx :h :sy :col // draw 2-d grid w X h at blh local 'b :blh // with step sizes sx and sy repeat :w/:sx + 1 [ line :b :b+(0|:h) :col 'b<-:b+(:sx|0) ] 'b<-:blh repeat :h/:sy + 1 [ line :b :b+(:w|0) :col 'b<-:b+(0|:sy) ] end to box :blh :w :h :col // box of w X h at blh grid :blh :w :w :h :h :col end to gpaper :s // 2-d draw graph paper grid (-:s|-:s) 2*:s 1 2*:s 1 :lightgrey // 1 X 1 in grey grid (-:s|-:s) 2*:s 5 2*:s 5 :lightblue // 5 X 5 in blue axes -:s :s (-:s) :s :red // axes in red end ////////////////////////////////////// // draw 'text' on graphics screen // ////////////////////////////////////// to gwrite :strlis :p :s :col // draw chars in strlis at p, scaled by s, in col to joinlists :plists // given [[p..p] [p..p]..[p..p]] -> join [p..p] .. to join :plist // join points from given list [p..p] if null :plist#-1 [exit] turtle :plist#1 0 :true :col 0 move :plist#2 join :plist#-1 end if null :plists [exit] // extract next [p..p] from [[p..p]..[p..p]] join :plis#1 // and use join to draw joinlists :plists#-1 end to find :ch :alist if null :alist [val []] if :ch=:alist#1#1 [val :alist#1#-1] find :ch :alist#-1 end to gw :plis if null :plis [exit] :s * joinlists :plis#1 gw :plis#-1 end if null :strlis [exit] local'gfont [ // Alphabet for writing to graphics window [A 5 [(0|0)(0|5)(1|6)(2|6)(3|5)(3|3)(0|3)(3|3)(3|0)]] [B 5 [(0|0)(0|6)(2|6)(3|5)(3|4)(2|3)(0|3)(2|3)(3|2)(3|1)(2|0)(0|0)]] [C 5 [(3|1)(2|0)(1|0)(0|1)(0|5)(1|6)(2|6)(3|5)]]

Page 89: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

[D 5 [(0|0)(0|6)(2|6)(3|5)(3|1)(2|0)(0|0)]] [E 5 [(3|0)(0|0)(0|3)(2|3)(0|3)(0|6)(3|6)]] [F 5 [(0|0)(0|3)(2|3)(0|3)(0|6)(3|6)]] [G 5 [(2|2)(3|2)(3|1)(2|0)(1|0)(0|1)(0|5)(1|6)(2|6)(3|5)]] [H 5 [(0|0)(0|6)(0|3)(3|3)(3|6)(3|0)]] [I 4 [(0|0)(2|0)(1|0)(1|6)(0|6)(2|6)]] [J 5 [(0|1)(1|0)(2|1)(2|6)(1|6)(3|6)]] [K 5 [(3|0)(0|3)(3|6)(0|3)(0|6)(0|0)]] [L 5 [(0|6)(0|0)(3|0)]] [M 6 [(0|0)(0|6)(2|3)(4|6)(4|0)]] [N 5 [(0|0)(0|6)(3|0)(3|6)]] [O 5 [(1|0)(0|1)(0|5)(1|6)(2|6)(3|5)(3|1)(2|0)(1|0)]] [P 5 [(0|0)(0|6)(2|6)(3|5)(3|4)(2|3)(0|3)]] [Q 5 [(1|0)(0|1)(0|5)(1|6)(2|6)(3|5)(3|1)(2.5|0.5)(2|1)(3|0)(2.5|0.5)(2|0)(1|0)]] [R 5 [(0|0)(0|6)(2|6)(3|5)(3|4)(2|3)(0|3)(3|0)]] [S 5 [(0|1)(1|0)(2|0)(3|1)(3|2)(2|3)(1|3)(0|4)(0|5)(1|6)(2|6)(3|5)]] [T 6 [(2|0)(2|6)(0|6)(4|6)]] [U 5 [(0|6)(0|1)(1|0)(2|0)(3|1)(3|6)]] [V 5 [(0|6)(1.5|0)(3|6)]] [W 6 [(0|6)(0|0)(2|3)(4|0)(4|6)]] [X 5 [(0|0)(3|6)][(0|6)(3|0)]] [Y 6 [(2|0)(2|3)(0|6)(2|3)(4|6)]] [Z 5 [(3|0)(0|0)(3|6)(0|6)]] [a 4 [(0|4)(1|4)(2|3)(2|0)(1|0)(0|1)(0|2)(1|3)(2|3)]] [b 4 [(0|6)(0|0)(1|0)(2|1)(2|3)(1|4)(0|4)]] [c 5 [(3|1)(2|0)(1|0)(0|1)(0|3)(1|4)(2|4)(3|3)]] [d 4 [(2|6)(2|0)(1|0)(0|1)(0|3)(1|4)(2|4)(2|0)]] [e 5 [(3|1)(2|0)(1|0)(0|1)(0|3)(1|4)(2|4)(3|3)(3|2)(0|2)(1|2)]] [f 3 [(0|0)(0|4)(1|4)(0|4)(0|5)(0.5|6)(1|5)]] [g 4 [(2|4)(1|4)(0|3)(0|1)(1|0)(2|0)(2|4)(2|-1)(1|-2)(0|-2)]] [h 4 [(0|0)(0|6)(0|3)(1|4)(2|3)(2|0)(2|1)]] [i 2 [(1|1)(0.5|0)(0|1)(0|4)]] [j 3 [(0|-1)(0.5|-2)(1|-1)(1|4)]] [k 4 [(0|0)(0|6)(0|2)(2|4)(0|2)(2|0)]] [l 3 [(1|1)(0.5|0)(0|1)(0|6)]] [m 5 [(0|0)(0|4)(0|3)(0.5|4)(1|3)(1|0)(1|3)(1.5|4)(2|3)(2|0)]] [n 4 [(0|0)(0|4)(0|3)(1|4)(2|3)(2|0)]] [o 5 [(1|0)(0|1)(0|3)(1|4)(2|4)(3|3)(3|1)(2|0)(1|0)]] [p 4 [(0|-2)(0|6)(0|4)(1|4)(2|3)(2|1)(1|0)(0|0)]] [q 4 [(2.5|-1.5)(2|-2)(2|4)(1|4)(0|3)(0|1)(1|0)(2|0)]] [r 4 [(0|0)(0|4)(0|3)(1|4)(2|3)]] [s 5 [(3|3)(2|4)(1|4)(0|3)(1|2)(2|2)(3|1)(2|0)(1|0)(0|1)]] [t 4 [(1|5)(1|4)(0|4)(2|4)(1|4)(1|1)(1.5|0)(2|1)]] [u 4 [(0|4)(0|1)(1|0)(2|1)(2|4)(2|0)]] [v 4 [(0|4)(1|0)(2|4)]] [w 4 [(0|4)(0|1)(0.5|0)(1|1)(1|2)(1|1)(1.5|0)(2|1)(2|4)]] [x 4 [(0|0)(2|4)][(2|0)(0|4)]] [y 4 [(0|0)(2|4)(0|0)][(0|4)(1|2)]] [z 4 [(2|0)(0|0)(2|4)(0|4)]] [0 4 [(1|0)(0|1)(0|5)(1|6)(2|5)(2|1)(1|0)]] [1 3 [(1|0)(1|6)(0|5)]] [2 5 [(0|5)(1|6)(2|6)(3|5)(3|4)(0|1)(0|0)(3|0)]] [3 5 [(0|5)(1|6)(2|6)(3|5)(3|4)(2|3)(1|3)(2|3)(3|2)(3|1)(2|0)(1|0)(0|1)]] [4 5 [(2|0)(2|6)(0|2)(3|2)]] [5 5 [(3|6)(0|6)(0|4)(2|4)(3|3)(3|1)(2|0)(1|0)(0|1)]] [6 5 [(0|3)(2|3)(3|2)(3|1)(2|0)(1|0)(0|1)(0|4)(2|6)]] [7 5 [(0|0)(3|6)(0|6)]] [8 5 [(1|0)(0|1)(0|2)(1|3)(2|3)(3|4)(3|5)(2|6)(1|6)(0|5)(0|4)(1|3)(2|3)(3|2)(3|1)(2|0)(1|0)(0|1)]] [9 5 [(3|3)(1|3)(0|4)(0|5)(1|6)(2|6)(3|5)(3|2)(1|0)]]

Page 90: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

[$ 5 []] // special chars - starting with $ for 5-point space [$4 4 []] // 4-point space [$3 3 []] // 3-point space [$2 2 []] // 2-point space [$1 1 []] // 1-point space [mi 4 [(0|3)(2|3)]] // - [pl 4 [(0|3)(2|3)(0|3)][(1|2)(1|4)]] // + [eq 4 [(0|2)(2|2)][(0|3)(2|3)]] // = [neq 4 [(0|2)(2|2)(1|2)][(0|3)(2|3)(1|3)][(2|4)(0|1)(2|4)]] // <> [gt 4 [(0|4)(2|2)(0|0)]] // > [ls 4 [(2|4)(0|2)(2|0)]] // < [gte 4 [(0|5)(2|3)(0|1)][(0|0)(2|2)(0|0)]] // >= [lse 4 [(2|5)(0|3)(2|1)][(0|2)(2|0)]] // <= [ovr 4 [(3|6)(0|0)]] // / [und 4 [(0|6)(3|0)]] // \ [lbk 3 [(1|6)(0|6)(0|0)(1|0)]] // [ [rbk 3 [(0|6)(1|6)(1|0)(0|0)]] // ] [lpr 3 [(1|6)(0|4)(0|2)(1|0)]] // ( [rpr 3 [(0|6)(1|4)(1|2)(0|0)]] // ) [lbc 3 [(1.5|6)(1|6)(0.5|5.5)(0.5|3.5)(0|3)(0.5|2.5)(0.5|0.5)(1|0)(1.5|0)]] // { [rbc 3 [(0|6)(0.5|6)(1|5.5)(1|3.5)(1.5|3)(1|2.5)(1|0.5)(0.5|0)(0|0)]] // } [lam 5 [(0|0)(1.5|3)(0|0)][(-0.5|5)(0|6)(3|0)]] // lamda [ang 5 [(3|6)(0|0)(3|0)]] // angle [cma 2 [(0.5|0)(0|-0.5)]] // comma ] local 'v find :strlis#1 :gfont // v = [width [pts][pts]..] xl :p gw :v#-1 gwrite :strlis#-1 :p+:v#1*(:s|0) :s :col end /////////////////// // 3-d drawing // /////////////////// to oblique :a :s // oblique projection from 3-d to 2-d linear (0|0) (1,0,:s*cos :a|0,1,:s*sin :a) // z-lines at angle a, and scaled by s end to grid3 :blh :w :sx :h :sy :d :sz :col // draw 3-d grid of w X h X d local 'bp :blh local 'b :bp // steps of sx, sy and sz repeat :d/:sz + 1 [ repeat :w/:sx + 1 [ line :b :b+(0|:h|0) :col 'b<-:b+(:sx|0|0) ] 'b<-:bp repeat :h/:sy + 1 [ line :b :b+(:w|0|0) :col 'b<-:b+(0|:sy|0) ] 'bp<-:bp+(0|0|:sz) 'b<-:bp ] 'bp<-:blh 'b<-:bp repeat :w/:sx + 1 [ repeat :h/:sy + 1 [ line :b :b+(0|0|:d) :col 'b<-:b+(0|:sy|0) ] 'b<-:bp repeat :d/:sz + 1 [ line :b :b+(0|:h|0) :col 'b<-:b+(0|0|:sz) ] 'bp<-:bp+(:sx|0|0)

Page 91: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

'b<-:bp ] end to box3 :blh :w :h :d :col // 3-d box of w*h*d at blh grid3 :blh :w :w :h :h :d :d :col end to cube :blh :s :col //3-d cube with side s at blh grid3 :blh :s :s :s :s :s :s :col end to axes3 :x1 :x2 :y1 :y2 :z1 :z2 :col // 3-d axes line (:x1|0|0) (:x2|0|0) :col line (0|:y1|0) (0|:y2|0) :col line (0|0|:z1) (0|0|:z2) :col end /////////////////////// // Demo of Utilities // /////////////////////// cs gwrite [H e l l o $ W o r l d] (-110|-150) 5 :black rl (0|0) 90 gwrite [H e l l o $ W o r l d] (-110|-150) 5 :red rl (0|0) 180 gwrite [H e l l o $ W o r l d] (-110|-150) 5 :blue rr (0|0) 90 gwrite [H e l l o $ W o r l d] (-110|-150) 5 :green // screen 1 cs gwrite [A B C D E F G H I J K L M N O P Q R S T U V W X Y Z] (-250|20) 4 :black gwrite [a b c d e f g h i j k l m n o p q r s t u v w x y z] (-250|70) 4 :black gwrite [0 1 2 3 4 5 6 7 8 9] (-200|120) 4 :black gwrite [lpr rpr lbk rbk lbc rbc lam ang $ ovr und mi pl eq neq gt gte ls lse cma] (-200|170) 4 :black // screen 2 // display screens 1 & 2 on same line cs ht 15 * gpaper 20 // screen 3 cs xl (-250|-250) ( oblique 30 1/2 ( grid3 (0|0|0) 400 100 400 100 400 100 :lightgrey axes3 0 450 0 450 0 450 :lightblue ) gwrite [x] (460|0) 4 :black gwrite [y] (0|460) 4 :black gwrite [z] oblique 30 1/2 (0|0|460) 4 :black ) // screen 4 // display screens 3 & 4 on same line cs box (-200|-100) 400 200 :green

Page 92: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

cs oblique 30 1/2 box3 (-200|-100|-80) 400 200 160 :brown cs oblique 30 1/2 cube (-200|-200|-200) 400 :blue

Page 93: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

///////////////////////////////////////////// ///////////////////////////////////////////// // // // Simultaneous Equations - simeqs.zno // // // ///////////////////////////////////////////// /////////////////////////////////////////////

// demo of vector and matrix operations // and intro to \ (under) // solve simultaneous equations including // find the centre and radius of the // circumcircle for any 3 given points 'A<-(2,1|1,-2) 'v<-(5|0) 'x<-(inv :A)*:v :x 'IA<-:A^-1 :IA :IA*:v (2,1|1,-2)\(5|0) ( 1|0).(2|1) (0|1).(2|1) (1,4,-5|2,3,1|3,-1,2)\(8|-1|3) (3, 1,-2,-1 |2,-1, 1, 2 |1,-3, 4, 3 |2, 1, 0, 2)\(6|5.5|-1|11.5) to circum :p1 :p2 :p3 to x :p (1|0).:p end to y :p (0|1).:p end to v :p (-((x :p)*(x :p)+(y :p)*(y :p))) end local 'fgh (x :p1, y :p1, 1 |x :p2, y :p2, 1 |x :p3, y :p3, 1)\(v :p1|v :p2|v :p3) local 'f (1|0|0).:fgh local 'g (0|1|0).:fgh local 'h (0|0|1).:fgh local 'c (-:f/2|-:g/2) local 'r 2\sqrt :f*:f + :g*:g - 4*:h pr 'centre sp 1 prln :c pr 'radius sp 1 prln :r end circum (-15|-10) (-5|-10) (-10|-5)

Page 94: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

///////////////////////////////// ///////////////////////////////// // // // Graphs - graphs.zno // // // ///////////////////////////////// /////////////////////////////////

// load line, axes, grid, gpaper and gwrite from utils.zno to graph :f :x1 :x2 :col turtle :x1 1 :true :col 0 ([:x]->'(:x|f :x)) move :x2 end cs ht 'y<-:([:x]->'((:x+7)*(:x+2)*(:x-6)/10)) 15* prompt gpaper 20 graph :y -9 9 :green graph :([:x]->'(:x^3-3*:x^2-:x+3)) -3 5 :black // screen 1 // display screen 1 'trig <- // assign block of commands to trig '( cs // to draw sin, cos and tan graphs grid (-180|-200) 360 45 400 50 :lightgrey axes -230 230 -250 250 :darkgrey gwrite [X] (240|-8) 3 :black gwrite [Y] (-6|260) 3 :black gwrite [mi 1 8 0] (-200|-15) 2 :black gwrite [mi 9 0] (-105|-15) 2 :black gwrite [0] (5|-15) 2 :black gwrite [9 0] (83|-15) 2 :black gwrite [1 8 0] (170|-15) 2 :black graph :([:x]->'(200*sin :x)) -180 180 :blue graph :([:x]->'(200*cos :x)) -180 180 :green graph :([:x]->'(200*tan :x)) -180 180 :red ) trig // screen 2 1/2 * trig // screen 3 // display screens 2 & 3 on same line 1/10 * trig // screen 4 1/100 * trig // screen 5 // display screens 4 & 5 on same line

Page 95: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

/////////////////////////////////// /////////////////////////////////// // // // Circles - circles.zno // // // /////////////////////////////////// ///////////////////////////////////

// load line, grid, axes and gpaper from utils.zno // use ideas introduced in Graphs to draw // circles using both parametric and // cartesian coordinates - also // following on from example in // Simultaneous Equations, draw the // circumcircle for any 3 given points to circle :l :n :col // typical Logo definition spc :col repeat :n [fd :l rt 360/:n] // ie polygon of chords end 15 * prompt // prompt in 15* context gpaper 20 // 20 X 20 graph paper circle 3 20 :red // 20 'chords' of length 3 circle 2 30 :cyan // 30 .................. 2 circle 1 60 :green // 60 .................. 1 // cartesian // to circle :c :r :col // circle - centre c and radius r local 'f :([:x]->'(sqrt 1-:x^2)) // use 'graphing' technique translate :c // with f(x) = sqrt(1-x^2) turtle -1 1 :true :col 0 // 1-d turtle at -1 ( :r * ([:x]->'(:x| f :x)) fd 2 // move to +1 :r * ([:x]->'(:x|-f :x)) bk 2 )// move back to -1 end 15*circle (10|-10) 5 :green // green circle, centre (10|-10) and // radius 5, in a 15* context // parametric // to cpt :t // map angle t(heta) (cos :t|sin :t) // to point (cos t|sin t) end to circle :c :r :col translate :c turtle 0 1 :true :col 0 // points (cos t|sin t) for t=0..360 :r * cpt // are a unit circle (ie r=1) centre (0|0) fd 360 // * by r and translate (0|0) to c end 15*circle (10|10) 5 :cyan // demo new circle function to circle :c :r :col // another definiton - with xl :c // cpt absorbed as an anonymous fn turtle 0 1 :true :col 0 // xl is an abbreviation for translate :r*([:t]->'(cos :t|sin :t)) fd 360 end

Page 96: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

15*circle (-10|10) 5 :magenta // and demo this version // 3-points // to circle :p1 :p2 :p3 :col // given 3 points - draw circumcircle to x :p (1|0).:p end to y :p (0|1).:p end to v :p (-((x :p)*(x :p)+(y :p)*(y :p))) end local 'fgh (x :p1, y :p1, 1 |x :p2, y :p2, 1 |x :p3, y :p3, 1)\(v :p1|v :p2|v :p3) local 'f (1|0|0).:fgh // see Simultaneous Equation (simeqs.zno) local 'g (0|1|0).:fgh // solve simultaneous equations local 'h (0|0|1).:fgh // to derive f, g and h local 'c (-:f/2|-:g/2) // and then use to compute c and r local 'r 2\sqrt :f*:f + :g*:g - 4*:h xl :c turtle 0 1 :true :col 0 // then draw circle as above :r*([:t]->'(cos :t|sin :t)) fd 360 end 15*circle (-15|-10) (-5|-10) (-10|-5) :red // screen 1 // display screen 1

Page 97: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

///////////////////////////////////////// ///////////////////////////////////////// // // // Conic Sections - conics.zno // // // ///////////////////////////////////////// /////////////////////////////////////////

// load line, grid and gpaper from utils.zno // extension of ideas introduced in Graphs // and developed in Circles to draw ellipses, // parabolas and hyperbolas using both // parametric and cartesian coordinates cs ht 15*gpaper 20 // parametrics // to ellipse :c :a :b :col xl :c turtle 0 1 :true :col 0 ([:t]->'(:a*cos :t|:b*sin :t)) fd 360 end 15*ellipse (-10|-10) 8 5 :red to parabola :a :t1 :t2 :col turtle :t1 1 :true :col 0 ([:t]->'(:a*:t^2|2*:a*:t)) move :t2 end 15*parabola 4 -2 2 :blue to hyperbola :a :b :col turtle 0 1 :true :col 0 ([:t]->'(:a/cos :t|:b*tan :t)) fd 360 end 15*hyperbola 3 4 :black // screen 1 // display screen 1 // cartesian // to ellipse :c :a :b :col local 'f :([:x]->'(sqrt :b^2*(1-:x^2/:a^2))) xl :c turtle -:a 1 :true :col 0 ( ([:x]->'(:x| f :x)) move :a ([:x]->'(:x|-f :x)) move -:a ) end to parabola :a :x2 :col local 'f :([:x]->'(sqrt 4*:a*:x)) turtle 0 1 :true :col 0 ( ([:x]->'(:x| f :x)) move :x2

Page 98: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

([:x]->'(:x|-f :x)) move 0 ) end to hyperbola :a :b :x2 :col local 'f :([:x]->'(:b/:a * sqrt :x^2-:a^2)) turtle -:x2 1 :true :col 0 ( ([:x]->'(:x| f :x)) move -:a ([:x]->'(:x|-f :x)) move -:x2 ) turtle :a 1 :true :col 0 ( ([:x]->'(:x| f :x)) move :x2 ([:x]->'(:x|-f :x)) move :a ) end to recthyperbola :c :x2 :col turtle -:x2 1 :true :col 0 ([:x]->'(:x|:c/:x)) move :x2 end cs ht 15* prompt gpaper 20 ellipse (-10|-10) 8 5 :red parabola 4 20 :blue hyperbola 3 4 20 :black recthyperbola 25 20 :magenta recthyperbola -25 20 :green // screen 2 // display screen 2

Page 99: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

//////////////////////////////////////////// //////////////////////////////////////////// // // // Linear Transforms - linear.zno // // // //////////////////////////////////////////// ////////////////////////////////////////////

// load line, axes, markaxes and join from utils.zno to F :col join [(0|0)(0|5)(3|5)(3|4)(1|4)(1|3) (2|3)(2|2)(1|2)(1|0)(0|0)] :col end to setup cs axes -20 20 -20 20 :lightgrey markaxes -20 20 1 -20 20 1 :lightgrey markaxes -20 20 5 -20 20 5 :lightblue end 15* prompt setup F :black enl (0|0) 2 (F :red) enl (-5|0) 2 (F :blue) line (-5|0) (5|10) :blue enl (-10|0) 1/2 (F :black) line (-10|0) (0|5) :black enl (-15|0) 2 (F :green) line (-15|0) (15|10) :green enl (0|0) -1 (F :black) enl (0|0) -2 (F :red) enl (-5|0) -2 (F :blue) line (-5|0) (-15|-10) :blue enl (-10|0) -1/2 (F :black) line (-10|0) (-15|-2.5) :black // screen 1 // display screen 1 enl (0|0) 15 prompt setup F :black 2*F :red -1*F :black -2*F :red // screen 2 // display screen 2 15* prompt setup (1* & 2*) F :black // screen 3 setup (1* & xl (0|10)) F :red xl (10|0) (1* & 2*) F :green // screen 4 // // display screens 3 4 on same line // setup ( 1*

Page 100: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

& rr (0|0) 90 & rr (0|0) 180 & rr (0|0) 270) (1* & xl (0|10)) F :blue // screen 5 // setup (1* & rf (0|0) 135) (1* & rr (0|0) 90) (1* & xl (0|10)) F :cyan line (-15|15) (15|-15) :lightgrey // screen 6 // // display screens 5 & 6 on same line // :( enl (1|2) 15 ) :( rf (10|10) 30 ) :( rr (5|10) 60) :( rl (10|5) 45 ) :( xl (15|5) ) to lin :t :m :p :t + :m*:p end 15*setup 15 * lin (-10|5) (1,0|0,1) F :black 15 * ( lin (-10|5) (1,0|0,1) lin (0|0) (cos 45,sin 45|-sin 45,cos 45) lin (0|0) (3,0|0,3) ) F :red // screen 7 // display screen 7

Page 101: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

///////////////////////////////////////// ///////////////////////////////////////// // // // Complex Plane - complex.zno // // // ///////////////////////////////////////// /////////////////////////////////////////

// load line and grid from utils.zno (1|3)*(4|2) (-2|14)/(4|2) 1/(1|1) (1|1)*(0.5|-0.5) (1|1)\1 cs home spc :black fd 100 home 100*exp fd 2*:pi :zeno jump (0.25|0) spc :blue 100*exp fd 2*:pi jump (-0.25|0) spc :red 100*exp fd 2*:pi to circle :c :r :col xl :c turtle (0|0) (0|1) :true :col 0 :r * exp fd 2*:pi end circle (150|150) 100 :green // screen 1 cs home rt 1.5 spc :blue 5*exp fd 50*:pi // screen 2 cs home lt 1.5 spc :red 250*exp fd 50*:pi // screen 3 // display screens 1 & 2 & 3 on same line // load line and grid from utils.zno cs home grid (0|0) 20 1 20 1 :green // (20 X 20) X 1 (filled) 20*grid (0|0) 10 1 10 1 :blue // 20* (10 X 10) X 1 _*exp(0|:pi/6) grid (0|0) 200 20 200 20 :magenta // e^(i*pi/6) screen 4 cs _^2 grid (-10|-10) 20 1 20 1 :blue // z^2 screen 5 cs _^3 grid (-5|-5) 10 0.5 10 0.5 :red // z^3 screen 6

Page 102: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

// display screens 4 & 5 & 6 on same line cs xl (-150|0) 100 * _^(1/2) grid (-9|-9) 18 1 18 1 :green // z^(1/2) screen 7 cs xl (-150|0) 100 * _^(1/3) grid (-27|-27) 54 3 54 3 :blue // z^(1/3) screen 8 cs 30 / grid (-1|-1) 2 0.1 2 0.1 :red // 1/z screen 9 // display screens 7 & 8 & 9 on same line

Page 103: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

/////////////////////////////////// /////////////////////////////////// // // // Vectors - vectors.zno // // // /////////////////////////////////// ///////////////////////////////////

// load from utils.zno // delay, line, join, axes, grid, gpaper and gwrite cs // expo of position vectors 'p<-(3|1) 'q<-(2|3) 25* prompt gpaper 10 line (0|0) :p :black gwrite [P] :p+(0.25|0) 2/25 :black gwrite [p] (1.5|0) 2/25 :black line (0|0) :q :black gwrite [Q] :q+(0.25|0) 2/25 :black gwrite [q] (1|2) 2/25 :black line (0|0) :p+:q :black gwrite [p pl q] (4|2.5) 2/25 :black line :p :p+:q :lightgrey line :q :p+:q :lightgrey line (0|0) :p-:q :blue gwrite [p mi q] (-0.5|-1.5) 2/25 :black line (0|0) :q-:p :red gwrite [q mi p] (-2|1) 2/25 :black line :p :q :red // screen 1 // display screen 1 to extend :u :v :lam1 :lam2 :col line (:lam1*:u + (1-:lam1)*:v) (:lam2*:u + (1-:lam2)*:v) :col end 25* prompt extend :p :q 1 4 :green gwrite [lam gt 1] (4.5|-1) 2/25 :black extend :p :q -3 0 :blue gwrite [lam ls 0] (1|6) 2/25 :black extend :p :q 1 0 :black 'r<-(5|-3) 25* prompt line (0|0) :r :black gwrite [R] :r+(0.25|0) 2/25 :black gwrite [r] (2.5|-2) 2/25 :black to angle :u :v acos (:u.:v)/((mod :u)*(mod :v)) end angle (-1|0) (1|0) angle (1|0) (0|1) angle (1|0) (1|1) angle :p :q to online :p :u :v

Page 104: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

local 'up :p-:u local 'vp :p-:v (:up.:vp)*(:up.:vp) = (:up.:up)*(:vp.:vp) end online :r :p :q online (6|-4) :p :q online (1|5) :p :q to perp :u :v :u.:v = 0 end perp (1|0) (0|1) perp (0|1) (0|1) perp :q :r // screen 2 // display screen 2 to circle :c :r :col local 'p 0 xl :c turtle (:r|0) (0|1) :true :col 0 repeat 2*:pi*:r [ fd 1 'p <- pos/:r sdir (-(0|1).:p|(1|0).:p) ] end cs circle (50|50) 50 :red to circle :c :r :col local 'p 0 xl :c turtle (:r|0) (0|1) :true :col 0 repeat 2*:pi*:r [ 'p <- (pos + dir)/:r sdir (-(0|1).:p|(1|0).:p) fd 1 ] end circle (50|50) 150 :blue to circle :c :r :col local 'p 0 xl :c turtle (:r|0) (0|1) :true :col 0 repeat 2*:pi*:r [ 'p <- (pos + 0.5*dir)/:r sdir (-(0|1).:p|(1|0).:p) fd 1 ] end circle (50|50) 100 :black // screen 3 // display screen 3 to ellipse :c :a :b :col local 'F1 (sqrt :a^2 - :b^2|0) local 'F2 (-:F1)

Page 105: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

local 'P (0|0) local 'pf2 0 local 'pf1 0 local 'd 0 xl :c turtle (0|:b) (1|0) :true :col 0 repeat 2*:pi*sqrt :a^2 + :b^2 [ 'P <- pos + 0.5*dir 'pf2 <- :P - :F2 'pf2 <- :pf2/mod :pf2 'pf1 <- :P - :F1 'pf1 <- :pf1/mod :pf1 'd <- (:pf2 + :pf1)/2 sdir (-(0|1).:d|(1|0).:d) fd 1 delay 10 ] end to parabola :a :x2 :col local 'A 0 local 't1 :(turtle (0|0) (0|1) :true :col 0) local 't2 :(turtle (0|0) (0|-1) :true :col 0) repeat :x2 [ 'A <- angle (1|0) (:a|0) - t1 (pos+0.5*dir) t1 ( sdir (sin :A/2|cos :A/2) fd 1 ) t2 ( sdir (sin :A/2|-cos :A/2) fd 1 ) delay 10 ] end to hyperbola :a :b :n :col local 'F1 (sqrt :a^2 + :b^2|0) local 'F2 (-:F1) local 'P (0|0) local 'A 0 local 't1 :(turtle (:a|0) (0|1) :true :col 0) local 't2 :(turtle (:a|0) (0|-1) :true :col 0) local 't3 :(turtle (-:a|0) (0|1) :true :col 0) local 't4 :(turtle (-:a|0) (0|-1) :true :col 0) repeat :n [ 'P <- t1 (pos + 0.5*dir) 'A <- (angle :P-:F2 (1|0)) + 90-2\angle :P-:F2 :F1-:P t1 ( sdir (cos :A|sin :A) fd 1 ) t2 ( sdir (cos :A|-sin :A) fd 1 ) t3 ( sdir (-cos :A|sin :A) fd 1 ) t4 ( sdir (-cos :A|-sin :A) fd 1 ) delay 10 ] end cs 15* prompt gpaper 20 circle (10|10) 5 :cyan ellipse (-10|-10) 8 5 :red parabola 4 20 :blue hyperbola 3 4 20 :black to circle :c :r :col local 't1 :(turtle (0|0) (0|1) 0 0 0) local 't2 :(turtle (t1 dir) 0 :true :col 0) xl :c :r * repeat 360 [ t1 rt 1

Page 106: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

t2 move (t1 dir) ] end 15 * circle (-10|10) 5 :green // screen 4 // display screen 4

Page 107: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

///////////////////////////// ///////////////////////////// // // // Loci - loci.zno // // // ///////////////////////////// /////////////////////////////

// load delay, line and axes from utils.zno // re-visit conic sections, but this time as loci to parabola :a :y2 :col local 'P (0|0) local 't :(turtle :P 0 :true :col 0) local 'd 0 repeat :y2 [ 'P <- :P + (0|1) L1:'d <- :P - (:a|0) if (:P.(1|0) + :a)^2 >= :d.:d [go 'L2] 'P <- :P + (1|0) go 'L1 L2:(t & t clone rf (0|0) 90) move :P delay 10 ] end to ellipse :cen :a :b :col local 'P (:a|0) local 't :(turtle :P 0 :true :col 0) local 'd 0 local 'c sqrt :a^2-:b^2 local 'e2 1-(:b/:a)^2 local 'dx :a^2/:c xl :cen repeat :b [ 'P <- :P + (0|1) L1: 'd <- :P - (:c|0) if :e2*(:dx-:P.(1|0))^2 >= :d.:d [go 'L2] 'P <- :P - (1|0) if :P.(1|0) = 0 [go 'L2] go 'L1 L2: (t & t clone rf (0|0) 270 & t clone rf (0|0) 0 & t clone rf (0|0) 0 rf (0|0) 90 ) move :P delay 10 if :P.(1|0) = 0 [exit] ] end to hyperbola :a :b :y2 :col local 'P (:a|0) local 't :(turtle :P 0 :true :col 0) local 'd 0 local 'c sqrt :a^2+:b^2 local 'e2 1+(:b/:a)^2 local 'dx :a^2/:c repeat :y2 [ 'P <- :P + (0|1)

Page 108: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

L1: 'd <- :P - (:c|0) if :e2*(:dx-:P.(1|0))^2 >= :d.:d [go 'L2] 'P <- :P + (1|0) go 'L1 L2: (t & t clone rf (0|0) 270 & t clone rf (0|0) 0 & t clone rf (0|0) 0 rf (0|0) 90 ) move :P delay 10 ] end cs ht axes -200 200 -200 200 :lightgrey parabola 40 200 :blue ellipse (50|50) 100 50 :red hyperbola 40 50 200 :magenta // screen 1 // display screen 1

Page 109: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

////////////////////////////////////////// ////////////////////////////////////////// // // // 3-2-d Space - 3-2-dspace.zno // // // ////////////////////////////////////////// //////////////////////////////////////////

// load from utils.zno // line,join, gwrite,grid3 and axes3 // draw wireframe and solid shapes in 3-d and // project to 2-d using oblique projection to oblique :a :s linear (0|0) (1,0,:s*cos :a|0,1,:s*sin :a) end ///////////////////////////// // 3-d wireframe drawing // ///////////////////////////// to cube :blh :s :col //3-d cube at blh grid3 :blh :s :s :s :s :s :s :col // with side s end to t :p xl (-150|-150) oblique 30 1/2 :p end cs ht t 40* prompt grid3 (0|0|0) 6 3 6 3 6 3 :lightgrey cube (0|0|0) 6 :lightblue axes3 0 7 0 7 0 7 :red // next line must be blank to exit prompt gwrite [X] t (290|0|0) 3 :black gwrite [Y] t (0|290|0) 3 :black gwrite [Z] t (0|0|290) 3 :black // screen 1 cs t cube (0|0|0) 240 :lightblue // screen 2 to pyr :s :h :col join [(0|0|0) (:s|0|0) (:s|0|:s) (0|0|:s) (0|0|0) (:s/2|:h|:s/2) (:s|0|0) (:s/2|:h|:s/2) (:s|0|:s) (:s/2|:h|:s/2) (0|0|:s)] :col end cs t ( axes3 0 350 0 350 0 350 :lightgrey pyr 300 300 :red ) gwrite [X] t (360|0|0) 3 :black gwrite [Y] t (0|360|0) 3 :black gwrite [Z] t (0|0|360) 3 :black // screen 3 // display screens 1, 2 & 3 on same line /////////////////////////

Page 110: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

// 3-d solid drawing // ///////////////////////// to filltri :a :b :c :fcol :bcol // fill triangle a,b,c to f1 :x :y :z // fcol is fill colour if mod (:y-:z)<1 [exit] // bcol is boundary colour local 'm (:y+:z)/2 line :x :m :fcol f1 :x :y :m f1 :x :m :z end f1 :a :b :c f1 :b :c :a f1 :c :a :b join list [:a :b :c :a] :bcol end cs filltri (-200|-200) (0|200) (200|-200) :blue :blue // screen 4 (NB 2-d) to fillquad :a :b :c :d :fcol :bcol // fill quadrilateral a,b,c,d filltri :a :b :c :fcol :fcol // fcol is fill colour filltri :c :d :a :fcol :fcol // bcol is boundary colour join list [:a :b :c :d :a] :bcol end cs fillquad (0|0) (-30|200) (200|170) (200|-40) :blue :black // screen 5 (NB 2-d) // display screens 4 & 5 on same line cs xl (0|-100) oblique 30 1/2 ( fillquad (0|0|0) (0|200|0) (0|200|200) (0|0|200) :blue :black fillquad (0|0|0) (0|200|0) (-200|200|0) (-200|0|0) :red :black fillquad (0|0|0) (0|200|0) (0|200|-200) (0|0|-200) :lightblue :black fillquad (0|0|0) (0|200|0) (200|200|0) (200|0|0) :lightred :black ) // screen 6 cs xl (0|-100) oblique 30 1/2 ( fillquad (-200|0|200) (-200|200|200) (200|200|200) (200|0|200) :red :black fillquad (-200|0|-200) (-200|200|-200) (-200|200|200) (-200|0|200) :blue :black fillquad (-200|0|-200) (-200|200|-200) (200|200|-200) (200|0|-200) :lightred :black fillquad (200|0|-200) (200|200|-200) (200|200|200) (200|0|200) :lightblue :black ) // screen 7 // display screens 6 & 7 on same line to pyr :blh :s :h :frontcol :rightcol // pyramid with front and right face local 'apex (:s/2|:h|:s/2) filltri :blh+(:s|0|0) :blh+:apex :blh+(:s|0|:s) :rightcol :black filltri :blh+(0|0|0) :blh+:apex :blh+(:s|0|0) :frontcol :black end cs xl(-200|0) oblique 30 1/2 pyr (0|0|0) 100 100 :darkgrey :lightgrey

Page 111: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

xl(-50|0) oblique 30 1/2 pyr (0|0|0) 100 100 :lightgrey :darkgrey xl(100|0) oblique 30 1/2 pyr (0|0|0) 100 100 :blue :lightblue // screen 8 cs // build a pyramid of pyrs xl (-100|-100) oblique 30 1/2 (pyr (0|0|100) 100 100 :darkgrey :lightgrey pyr (100|0|100) 100 100 :darkgrey :lightgrey pyr (0|0|0) 100 100 :darkgrey :lightgrey pyr (100|0|0) 100 100 :darkgrey :lightgrey pyr (50|100|50) 100 100 :darkgrey :lightgrey) // screen 9 // display screens 8 & 9 on same line to pyramid :n :s :h :frontcol :rightcol // draw at (0|0|0) to pyr :blh filltri :blh+(:s|0|0) :blh+:apex :blh+(:s|0|:s) :rightcol :black filltri :blh+(0|0|0) :blh+:apex :blh+(:s|0|0) :frontcol :black end to lineofpyr :n :b rep :n [ pyr :b 'b<-:b+(:s|0|0) ] end to layerofpyr :n :b local 'c 1 rep :n [ lineofpyr :n :b+(:n-:c)*(0|0|:s) 'c<-:c+1 ] end local 'c n local 'a (0|0|0) local 'apex (:s/2|:h|:s/2) rep :n [ layerofpyr :c :a 'a<-:a + :apex 'c<-:c-1 ] end cs xl (-280|-250) oblique 30 1/2 pyramid 5 80 100 :lightgrey :darkgrey // pyramid 5 layers of 5 X 5 //screen 10 // display screen 10

Page 112: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

////////////////////////////////////////// ////////////////////////////////////////// // // // 2-3-2-d Space - 2-3-2-d1.zno // // // ////////////////////////////////////////// //////////////////////////////////////////

// draw surfaces by mapping 2-d grids on to 3-d // space and then back to 2-d for oblique view // load from utils.zno // line, join, axes, grid, gwrite, // oblique, grid3, box3 and axes3 cs ht // labelled 2-d axes xl (-150|-150) // and 2-d grid ( axes 0 320 0 320 :lightgrey gwrite [x] (325|0) 4 :black gwrite [y] (0|325) 4 :black gwrite [2 mi d $4 g r i d] (100|-50) 4 :black grid (0|0) 300 15 300 15 :lightgrey ) // screen 1 to cab :p // cabinet oblique oblique 30 1/2 :p end to labelaxes // labelled 3-d axes cab axes3 0 320 0 320 0 320 :lightgrey gwrite [x] (325|0) 4 :black gwrite [y] (0|325) 4 :black gwrite [z] cab (0|0|325) 4 :black end to plane_xz :p // ie y=0 plane (:p.(1|0) | 0 | :p.(0|1)) end cs // map 2-d grid via plane_xz xl (-150|-150) // ie onto y=0 plane ( labelaxes // label y=f(x,z)=0 cab plane_xz grid (0|0) 300 15 300 15 :lightgrey gwrite [y eq f lpr x cma z rpr eq 0] (100|-50) 4 :black ) // screen 2 to plane_xy :p // ie z=0 plane (:p.(1|0) | :p.(0|1) | 0) end cs // map 2-d grid via plane_xy xl (-150|-150) // ie onto z=0 plane ( labelaxes // label z=f(x,y)=0 cab plane_xy grid (0|0) 300 15 300 15 :lightgrey gwrite [z eq f lpr x cma y rpr eq 0] (100|-50) 4 :black ) // screen 3 to plane_yz :p // ie x=0 plane (0 | :p.(0|1) | :p.(1|0)) end

Page 113: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

cs // map 2-d grid via plane_yz xl (-150|-150) // ie onto x=0 plane ( labelaxes // label x=f(y,z)=0 cab plane_yz grid (0|0) 300 15 300 15 :lightgrey gwrite [x eq f lpr y cma z rpr eq 0] (100|-50) 4 :black ) // screen 4 // display screens 1,2,3,4 on same line to sinr :x // sin of x radians sin (:x*180)/:pi // radians to degrees end // and use sin to sinrsurf :p // y = f(x,z) = sinr (x+z^2) local 'x (1|0).:p local 'z (0|1).:p local 'y sinr (:x+:z^2) (:x|:y|:z) end to t :p // 'abbreviation' function oblique 60 (sqrt 3)/2 50*:p // for compostion of end // oblique with 50* cs ht // surface from cyan grid t sinrsurf // then boundary in red ( grid (-3|-2) 6 0.1 4 0.05 :cyan grid (-3|-2) 6 6 4 4 :red ) t ( box3 (-3|-1|-2) 6 2 4 :lightgrey // enclosing line (-3.5|1|2) (-3|1|2) :lightgrey // box with line (-3.5|1|-2) (-3|1|-2) :lightgrey // extended line (-3.5|-1|-2) (-3|-1|-2) :lightgrey // corners to line (-3|-1.5|-2) (-3|-1|-2) :lightgrey // enable line (3|-1.5|-2) (3|-1|-2) :lightgrey ) // labelling gwrite [pl 2] t (-3.5|0.75|2) 2 :black // label +2 gwrite [Z] t (-3.5|0.8|0) 2 :black // ..... Z gwrite [mi 2] t (-3.4|1.1|-2) 2 :black // ..... -2 gwrite [pl 1] t (-3.4|0.75|-2) 2 :black // ..... +1 gwrite [Y] t (-3.3|0|-2) 2 :black // ..... Y gwrite [mi 1] t (-3.4|-0.9|-2) 2 :black // ..... -1 gwrite [mi 3] t (-2.9|-1.3|-2) 2 :black // ..... -3 gwrite [X] t (0|-1.3|-2) 2 :black // ..... X gwrite [pl 3] t (2.7|-1.3|-2) 2 :black // ..... +3 // screen 5 // display screen 5 to dip :p // y = f(x,z) = x^2 + z^2 local 'x (1|0).:p local 'z (0|1).:p local 'y :x^2+:z^2 (:x|:y|:z) end cs xl (0|-200) oblique 60 (sqrt 3)/2 50*dip ( grid (-2|-2) 4 0.1 4 0.05 :cyan

Page 114: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

grid (-2|-2) 4 4 4 4 :red ) // screen 6 to asinreal :p // z = f(x,y) = real part of asin (x|y)^3 local 'x (1|0).:p local 'y (0|1).:p local 'z (1|0).asin :p^3 (:x|:y|:z) end cs cab 100*asinreal ( grid (-2|-2) 4 0.1 4 0.1 :cyan grid (-2|-2) 4 4 4 4 :red ) // screen 7 to asinim :p // z = f(x,y) = imaginary part of asin (x|y)^3 local 'x (1|0).:p local 'y (0|1).:p local 'z (0|1).asin :p^3 (:x|:y|:z) end cs cab 80*asinim ( grid (-2|-2) 4 0.1 4 0.1 :cyan grid (-2|-2) 4 4 4 4 :red ) // screen 8 // display screens 6,7,8 on same line

////////////////////////////////////////// ////////////////////////////////////////// // // // 2-3-2-d Space - 2-3-2-d2.zno // // // ////////////////////////////////////////// //////////////////////////////////////////

cs ht // explore spherical surfaces xl (-200|-200) cab 100* prompt axes3 0 4 0 4 0 4 :blue join [(3.5|0|0)(3.5|0|3.5)(0|0|3.5)] :lightgrey line (0|0|0) (1.5|2|2.5) :black line (1.5|0|2.5) (1.5|2|2.5) :lightgrey line (1.5|0|2.5) (0|0|0) :lightgrey line (1.5|0|2.5) (0|0|2.5) :lightgrey gwrite [X] (205|-205) 3 :black gwrite [Y] (-205|205) 3 :black gwrite [Z] (-25|-105) 3 :black gwrite [R] (65|60) 3 :black rl (-80|-70) 45 gwrite [r] (-80|-70) 3 :black gwrite [O] (-215|-210) 3 :black gwrite [P] (65|-140) 3 :black gwrite [Q] (-105|-140) 3 :black gwrite [l a t eq ang P O R] (-100|150) 3 :black gwrite [l o n eq ang Q O P] (-100|120) 3 :black rl (-100|-190) 13 gwrite [p eq r $1 c o s $2 l a t] (-100|-190) 2 :black gwrite [x eq p $1 s i n $2 l o n] (-50|-130) 2 :black gwrite [y eq r $1 s i n $2 l a t] (65|-50) 2 :black rl (-185|-180) 30 gwrite [z eq p $1 c o s $2 l o n] (-185|-180) 2 :black // screen 9

Page 115: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

to sphere :r :p local 'lon :p.(1|0) // x is longitude local 'lat :p.(0|1) // y is latitude ( :r*(cos :lat)*(sin :lon) | :r*(sin :lat) | :r*(cos :lat)*(cos :lon) ) end cs cab sphere 200 grid (0|0) 360 6 360 6 :lightgreen to equator :col clone ( spc :col jump (0|0) move (360|0) ) end to dateline :col clone ( spc :col jump (180|-90) move (180|90) ) end to arctic :col clone ( spc :col jump (0|66.5) move (360|66.5) ) end to cancer :col clone ( spc :col jump (0|23.5) move (360|23.5) ) end to capricorn :col clone ( spc :col jump (0|-23.5) move (360|-23.5) ) end to antarctic :col clone ( spc :col jump (0|-66.5) move (360|-66.5) ) end cab sphere 200 prompt equator :red arctic :blue antarctic :blue cancer :darkgrey capricorn :darkgrey dateline :black // screen 10 // display screens 9 & 10 on same line to ellipsoid :a :b :p local 'e :p.(1|0) local 'n :p.(0|1) ( :a*(cos :n)*(sin :e) | :b*(sin :n) | :a*(cos :n)*(cos :e) ) end cs cab ellipsoid 200 100 grid (0|0) 360 9 360 9 :lightblue // screen 11 to cylinder :r :p local 'x :p.(1|0) local 'y :p.(0|1) ( :r*(cos :x)

Page 116: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

| :r*(sin :x) | :y ) end cs cab ( cylinder 100 grid (0|0) 360 9 360 9 :lightgrey axes3 -200 200 -200 200 -300 200 :lightblue ) // screen 12 // display screens 11 & 12 on same line to cone :r :h :p local 'x :p.(1|0) local 'y :p.(0|1) local 'cr :r*(:h-:y)/:h ( :cr*(cos :x) | :cr*(sin :x) | :y ) end cs cab ( cone 150 400 grid (0|0) 360 9 360 9 :lightgrey axes3 -200 200 -200 200 -400 300 :lightblue ) // screen 13 to icone :r :h :p local 'x :p.(1|0) local 'y :p.(0|1) local 'cr :r*:y/:h ( :cr*(cos :x) | :y | :cr*(sin :x) ) end cs cab ( axes3 -200 200 -200 200 -200 200 :lightblue icone 100 150 grid (-360|-250) 720 10 500 10 :lightgrey ) // screen 14 // display screens 13 & 14 on same line to paraboloid :a :h :p local 'u :p.(1|0) local 'v :p.(0|1) local 's sqrt (:u/:h) ( :a*:s*cos :v | :u | :a*:s*sin :v ) end cs xl (0|-200) cab ( axes3 -200 200 -100 400 -200 200 :lightblue paraboloid 150 300 grid (0|0) 400 10 360 9 :lightgrey ) // screen 15 to hyperboloid :a :c :p local 'u :p.(1|0) local 'v :p.(0|1) local 's sqrt (1+:u*:u) ( :a*:s*cos :v | :c*:u

Page 117: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

| :a*:s*sin :v ) end cs cab ( axes3 -200 200 -200 200 -200 200 :lightblue hyperboloid 20 15 grid (-12|0) 24 1 360 10 :lightgrey ) // screen 16 // display screens 15 & 16 on same line to klein8 :r :t :p local 'u :p.(1|0) local 'v :p.(0|1) local 'tv :t*:v local 'ce 4 + 2*(cos :u)*(cos :tv) - (sin :u)*(sin :tv) :r*( (sin :v)*:ce | 2*(cos :u)*(sin :tv) + (sin 2*:u)*(cos :tv) | (cos :v)*:ce ) end cs oblique 60 (sqrt 3)/2 klein8 40 1 prompt grid (0|0) 180 6 360 6 :cyan grid (0|0) 180 180 360 360 :red // Mobius Strip // screen 17 grid (180|0) 360 6 360 6 :blue // Klein Bottle // screen 18 // display screens 17 & 18 on same line

Page 118: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

/////////////////////////////// /////////////////////////////// // // // Trees - trees.zno // // // /////////////////////////////// ///////////////////////////////

// from utils.zno load // delay, line, join, filltri, fillquad, // oblique, grid3 and cube // widen graphics window ////////////////////////////// // 2 line branches in 2-d // ////////////////////////////// to tree :n :x :a :fx :fa if :n=0 [exit] local 't1 :(turtle pos dir :true pc 0) ct lt :a t1 rt :a (ct & t1) (fd :x tree :n-1 :fx*:x :fa*:a :fx :fa) end cs ht turtle (0|-80) (0|1) :true :black 0 ( fd 80 tree 6 80 30 4/5 4/5 ) // screen 1 'tbrown <- :(turtle (0|0) (0|-1) :true :brown 0) 'tgreen <- :(turtle (0|0) (0|1) :true :green 0) 'tblue <- :(turtle (0|0) (1|0) :true :blue 0) 'tred <- :(turtle (0|0) (-1|0) :true :red 0) cs (tbrown & tblue & tred & tgreen) tree 8 70 30 4/5 4/5 // screen 2 // display screens 1 & 2 on same line cs turtle (0|-100) (0|1) :true :green 0 // Pythagorus tree ( fd 100 tree 12 100 45 2\sqrt 2 1 ) // screen 3 cs turtle (0|-20) (0|1) :true :blue 0 tree 8 40 60 1 1 // screen 4 // display screens 3 & 4 on same line ////////////////////////////// // 3 line branches in 2-d // ////////////////////////////// to tree3b :n :x :a :fx :fa if :n=0 [exit] local 't1 :(turtle pos dir :true pc 0)

Page 119: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

local 't2 :(turtle pos dir :true pc 0) t1 lt :a t2 rt :a (ct & t1 & t2) ( fd :x tree3b :n-1 :fx*:x :fa*:a :fx :fa) end cs turtle (0|-150) (0|1) :true :blue 0 ( fd 150 tree3b 8 150 90 1/2 1 ) // screen 5 cs turtle (0|-150) (0|1) :true :red 0 ( fd 150 tree3b 9 150 60 1/2 1 ) // screen 6 // display screens 5 & 6 on same line //////////////////////////////// // 2 square branches in 2-d // //////////////////////////////// to treesq :n :x :a :fx :fa to fillsq :x // fill square with ct's pc local 'p1 pos // p1 is blh = ct's pos fd :x // clockwise to set up p2, p3 and p4 local 'p2 pos // leave ct as on entry rt 90 fd :x // use fillquad to fill with col local 'p3 pos rt 90 fd :x local 'p4 pos rt 90 fd :x rt 90 fillquad :p1 :p2 :p3 :p4 pc pc end if :n=0 [exit] local 't1 :(turtle pos dir :true pc 0) ct lt :a t1 (rt 90 fd :x/:fx lt 180-:a fd :x rt 90) // set t1's pos and dir (ct & t1) (fillsq :x fd :x treesq :n-1 :fx*:x :fa*:a :fx :fa) end cs ht 's <- 80*sqrt 2 // size of 'square trunk' xl (-:s/2|-:s/2) ( fillquad (0|0)(0|-:s)(:s|-:s)(:s|0) :blue :blue turtle (0|0) (0|1) :true :blue 0 treesq 10 80 45 2\sqrt 2 1 ) // Pythagorus tree // screen 7 cs turtle (-20|0) (0|1) :true :blue 0 // screen 8 treesq 6 40 60 1 1 // display screens 7 & 8 on same line /////////////////////////////////////////// // 2 line branches in 3-d single planes // /////////////////////////////////////////// to tree3dxy :n :x :a :fx :fa if :n=0 [exit]

Page 120: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

local 'c cos :a local 's sin :a local 't3 :(turtle pos (c,-s,0|s,c,0|0,0,1)*dir :true pc 0) local 't4 :(turtle pos (c,s,0|-s,c,0|0,0,1)*dir :true pc 0) (t3&t4) ( fd :x tree3dxy :n-1 :fx*:x :fa*:a :fx :fa) end to tree3dyz :n :x :a :fx :fa if :n=0 [exit] local 'c cos :a local 's sin :a local 't1 :(turtle pos (1,0,0|0,c,-s|0,s,c)*dir :true pc 0) local 't2 :(turtle pos (1,0,0|0,c,s|0,-s,c)*dir :true pc 0) (t1&t2) ( fd :x tree3dyz :n-1 :fx*:x :fa*:a :fx :fa) end cs ht xl (0|-150) oblique 30 1/2 ( turtle (0|70|00) (0|sin 30|cos 30) :true :lightblue 0 tree3dyz 6 70 30 3/4 4/5 delay 500 turtle (0|70|0) (-cos 30|sin 30|0) :true :red 0 tree3dxy 6 70 30 3/4 4/5 delay 500 turtle (0|70|0) (0|sin 30|-cos 30) :true :lightblue 0 tree3dyz 6 70 30 3/4 4/5 delay 500 turtle (0|70|0) (cos 30|sin 30|0) :true :red 0 tree3dxy 6 70 30 3/4 4/5 delay 500 turtle (0|0|0) (0|1|0) :true :brown 0 move (0|70|0) ) xl (0|-200) oblique 30 1/2 turtle (0|0|0) (0|1|0) :true :lightgrey 0 ( move (250|0|0) move (250|350|0) move (-250|350|0) move (-250|0|0) move (0|0|0) move (0|0|250) move (0|350|250) move (0|350|-250) move (0|0|-250) move (0|0|0) move (0|350|0) ) // screen 9 ///////////////////////// // 4 branches in 3-d // ///////////////////////// to tree3d :n :x :a :fx :fa if :n=0 [exit] local 'c cos :a local 's sin :a local 't1 :(turtle pos (1,0,0|0,c,-s|0,s,c)*dir :true pc 0) local 't2 :(turtle pos (1,0,0|0,c,s|0,-s,c)*dir :true pc 0) local 't3 :(turtle pos (c,-s,0|s,c,0|0,0,1)*dir :true pc 0) local 't4 :(turtle pos (c,s,0|-s,c,0|0,0,1)*dir :true pc 0) (t1&t2&t3&t4) ( fd :x tree3d :n-1 :fx*:x :fa*:a :fx :fa) end cs xl (-280|-260) oblique 30 1/2

Page 121: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

cube (0|0|0) 380 :lightgrey xl (0|-150) oblique 30 1/2 ( turtle (0|80|00) (0|sin 30|cos 30) :true :yellow 0 tree3d 5 80 30 3/4 4/5 delay 500 turtle (0|80|0) (-cos 30|sin 30|0) :true :green 0 tree3d 5 80 30 3/4 4/5 delay 500 turtle (0|80|0) (0|sin 30|-cos 30) :true :cyan 0 tree3d 5 80 30 3/4 4/5 delay 500 turtle (0|80|0) (cos 30|sin 30|0) :true :lightgreen 0 tree3d 5 80 30 3/4 4/5 delay 500 turtle (0|-60|0) (0|1|0) :true :brown 0 move (0|80|0) ) // screen 10 // display screens 9 & 10 on same line

Page 122: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

////////////////////////////////////////////////////// ////////////////////////////////////////////////////// ///// ///// ///// Fractals - line curves - frac1.zno ///// ///// ///// ////////////////////////////////////////////////////// //////////////////////////////////////////////////////

/////////////////// // Line Curves // /////////////////// // load line and join from utils.zno // Koch 'snowflake' curve to genK :plist // add 3 new points between each pair of points if null :plist#-1 [value :plist] // n' = n + 3(n-1) = 4n-3 local 'a :plist#1 // ie number of points grows at rate 4n-3 local 'b :plist#2 local 'p1 (2*:a+:b)/3 // p1 is 1/3 from a to b local 'l mod :a-:b // length of line segment local 'v (:b-:a)/:l // unit vector of line to b from a local 't :(turtle :p1 :v :false 0 0) // turtle at p1 with dir v (and pen up) t (lt 60 fd :l/3) // turn and move t to apex of tri, ie t pos is p2 local 'p2 t pos // p2 is pos of t local 'p3 (:a+2*:b)/3 // p3 is 2/3 from a to b list [:a :p1 :p2 :p3], genK :plist#-1 end // concatenate with gen of rest of list cs ht 'Koch <- [(0|0)(1|0)] xl (-150|-225) 300* join :Koch :blue 'Koch <- genK :Koch xl (-150|-175) 300* join :Koch :blue 'Koch <- genK :Koch xl (-150|-100) 300* join :Koch :blue 'Koch <- genK :Koch xl (-150|0) 300* join :Koch :blue 'Koch <- genK :Koch xl (-150|100) 300* join :Koch :blue 'Koch <- genK :Koch xl (-150|200) 300* join :Koch :red // screen 1 // display screen 1 // change screen mode to 'console on top' cs xl(-450|50) 250* ( join [(0|0)(cos 60|sin 60) (1|0)(0|0)] :lightgrey // draw a triangle ( rl (0|0) 60 // draw the Koch curve & rr (1|0) 60 // along its 3 sides & xl (1|0) rr (0|0) 180 ) join :Koch :blue ) xl(200|50) 200* ( join [(0|0) (0|1)(1|1) (1|0)(0|0)] :lightgrey // draw a square

Page 123: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

( rl (0|0) 90 // draw the Koch curve & xl (0|1) // along its 4 sides & xl (1|1) rr (0|0) 90 & xl (1|0) rr (0|0) 180 ) join :Koch :blue ) xl(-175|-200) 200* ( join [(0|0)(0|1)(cos 30|1+sin 30) (2*cos 30|1)(2*cos 30|0) (cos 30|-sin 30) (0|0)] :lightgrey // draw a hexagon ( rl (0|0) 90 // draw the Koch curve & xl (0|1) rl (0|0) 30 // along its 6 sides & xl (cos 30|1+sin 30) rr (0|0) 30 & xl (2*cos 30|1) rr (0|0) 90 & xl (2*cos 30|0) rl (0|0) 210 & xl (cos 30|-sin 30) rl (0|0) 150 ) join :Koch :blue ) // screen 2 xl(-450|50) 250* join [(0|0)(cos 60|sin 60) (1|0)(0|0)] :white // 'white' out the drawn triangle xl(200|50) 200* join [(0|0) (0|1)(1|1) (1|0)(0|0)] :white // 'white' out the drawn square xl(-175|-200) 200* join [(0|0)(0|1)(cos 30|1+sin 30) (2*cos 30|1)(2*cos 30|0) (cos 30|-sin 30) (0|0)] :white // 'white' out the drawn hexagon // screen 3 'Koch <- [] // display screens 2 & 3 on same line // Koch Quadratic 1 // reset screen mode to genKQ1 :plist // add 4 new points between each pair of points if null :plist#-1 [value :plist] // => rate of growth is 5n-4 local 'a :plist#1 local 'b :plist#2 local 'p1 (2*:a+:b)/3 // p1 is 1/3 from a to b local 'l mod :a-:b // length of line segment local 'v (:b-:a)/:l // unit vector of line to b from a local 't :(turtle :p1 :v :false 0 0) // turtle at p1 with dir v (and pen up) t (lt 90 fd :l/3) // turn and move t to next corner of square local 'p2 t pos // t's pos is p2 t (rt 90 fd :l/3) // turn and move t to next corner of square local 'p3 t pos // and t's pos is p3 local 'p4 (:a+2*:b)/3 // p4 is 2/3 from a to b list [:a :p1 :p2 :p3 :p4], genKQ1 :plist#-1 end // concatenate with gen of rest of list cs ht 'KQ1 <- [(0|0)(1|0)] xl (-100|-300) 200* join :KQ1 :blue 'KQ1 <- genKQ1 :KQ1 xl (-100|-250) 200* join :KQ1 :blue 'KQ1 <- genKQ1 :KQ1

Page 124: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

xl (-100|-100) 200* join :KQ1 :blue 'KQ1 <- genKQ1 :KQ1 xl (-100|50) 200* join :KQ1 :blue 'KQ1 <- genKQ1 :KQ1 xl (-100|200) 200* join :KQ1 :red // screen 4 'KQ1 <- [] // Koch Quadratic 2 to genKQ2 :plist // add 7 new points between each pair of points if null :plist#-1 [value :plist] // rate of growth is 8n-7 local 'a :plist#1 local 'b :plist#2 local 'p1 (3*:a+:b)/4 // p1 is 1/4 from a to b local 'l mod :a-:b // length of line segment local 'v (:b-:a)/:l // unit vector of line to b from a local 't :(turtle :p1 :v :false 0 0) // turtle at p1 with dir v (and pen up) t (lt 90 fd :l/4) // turn and move t to next corner of square local 'p2 t pos // t's pos is now p2 t (rt 90 fd :l/4) // turn and move t to next corner of square local 'p3 t pos // t is now at p3 local 'p4 (:a+:b)/2 // p4 is mid-point t (rt 90 fd :l/2) // turn and move t to next corner of square local 'p5 t pos // t is now at p5 t (lt 90 fd :l/4) // turn and move t to next corner of square local 'p6 t pos // t is now at p6 local 'p7 (:a+3*:b)/4 // p7 is 3/4 from a to b list [:a :p1 :p2 :p3 :p4 :p5 :p6 :p7], genKQ2 :plist#-1 end // concatenate with gen of rest of list cs ht 'KQ2 <- [(0|0)(1|0)] xl (-100|-250) 200* join :KQ2 :blue 'KQ2 <- genKQ2 :KQ2 xl (-100|-100) 200* join :KQ2 :blue 'KQ2 <- genKQ2 :KQ2 xl (-100|50) 200* join :KQ2 :blue 'KQ2 <- genKQ2 :KQ2 xl (-100|200) 200* join :KQ2 :red // screen 5 'KQ2 <- [] // display screens 4 & 5 on same line // change screen mode to 'console on top' // Levy C to genLevy :plist // add 1 new point between each pair of points if null :plist#-1 [value :plist] // rate of growth is 2n-1 local 'a :plist#1 local 'b :plist#2 local 'l mod :a-:b // length of line segment local 'v (:b-:a)/:l // unit vector of line to b from a local 't :(turtle :a :v :false 0 0) // turtle at a with dir v (and pen up) t (lt 45 fd :l/sqrt 2) // turn and move t to new point local 'p1 t pos list [:a :p1], genLevy :plist#-1 // concatenate with gen of rest of list end

Page 125: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

cs ht 'Levy <- [(0|0)(0|1)] xl (450|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy xl (400|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy xl (250|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy xl (100|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy xl (-50|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy xl (-250|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy // screen 6 cs xl (400|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy xl (100|-100) 200* join :Levy :blue 'Levy <- genLevy :Levy xl (-200|-100) 200* join :Levy :red // screen 7 'Levy <- [] // display screens 7 & 6 (in this order) on same line // Heighway's Dragon // reset screen mode to genHD :plist :d // add 1 new point between each pair of points if null :plist#-1 [value :plist] // NB d is direction switch set to 1 or -1 local 'a :plist#1 // d=1 for lt, d=-1 for rt local 'b :plist#2 // rate of growth is 2n-1 local 'l mod :a-:b // length of line segment local 'v (:b-:a)/:l // unit vector of line to b from a local 't :(turtle :a :v :false 0 0) // turtle at a with dir v (and pen up) t (lt :d*45 fd :l/sqrt 2) // turn and move t to new point local 'p1 t pos list [:a :p1], genHD :plist#-1 (-:d) // concatenate with gen of rest of list end cs ht 'HD <- [(0|1)(0|0)] xl (-400|-100) 200* join :HD :blue 'HD <- genHD :HD 1 xl (-350|-100) 200* join :HD :blue 'HD <- genHD :HD 1 xl (-200|-100) 200* join :HD :blue 'HD <- genHD :HD 1 xl (-50|-100) 200* join :HD :blue 'HD <- genHD :HD 1 xl (100|-100) 200* join :HD :blue 'HD <- genHD :HD 1 xl (300|-100) 200* join :HD :blue // screen 8 cs 'HD <- genHD :HD 1 xl (-400|-100) 200* join :HD :blue 'HD <- genHD :HD 1

Page 126: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

xl (-200|-100) 200* join :HD :blue 'HD <- genHD :HD 1 xl (0|-100) 200* join :HD :blue 'HD <- genHD :HD 1 xl (200|-100) 200* join :HD :red // screen 9 'HD <- [] // display screen 8 & 9 on same line

///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// ///// ///// ///// Fractals - 2-d and 3-d shapes - frac2.zno ///// ///// ///// ///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////

////////////////// // 2-d Shapes // ////////////////// // Sierpinski triangle - line drawing // load from utils.zno - line, join, filltri, fillquad to tri :a :b :c :col :g // works for any 3 points join list [:a :b :c :a] :col // tri for a, b and c if mod :a-:b < :g [exit] // g is granularity tri :a (:a+:b)/2 (:a+:c)/2 :col :g // tri for a and two mid-points tri (:a+:b)/2 :b (:b+:c)/2 :col :g // ....... b .................. tri (:a+:c)/2 (:b+:c)/2 :c :col :g // ....... c .................. end cs ht tri (0|256) (-256|-256) (256|-256) :green 8 // screen 10 tri (-256|256) (0|-256) (256|256) :blue 8 // screen 11 // display screens 10 & 11 on same line cs tri (0|256) (-256|-256) (0|-256) :red 8 tri (0|256) (256|-256) (0|-256) :blue 8 // screen 12 cs tri (-256|256) (0|0) (256|256) :blue 8 tri (-256|-256) (0|0) (256|-256) :blue 8 tri (-256|256) (0|0) (-256|-256) :green 8 tri (256|256) (0|0) (256|-256) :green 8 // screen 13 // display screens 12 & 13 on same line // Sierpinski triangle - 'filled' shapes to Siertri :a :b :c :col :g // works for any triangle to t1 :x :y :z // local function t1 if mod (:x-:y) < :g [exit] // 'whites' out the 'holes' filltri (:x+:y)/2 (:y+:z)/2 (:z+:x)/2 :white :white t1 :x (:x+:y)/2 (:z+:x)/2 t1 (:x+:y)/2 :y (:y+:z)/2 t1 (:x+:z)/2 (:y+:z)/2 :z

Page 127: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

end filltri :a :b :c :col :col // fill original tri with col t1 :a :b :c // t1 'whites' out the 'holes' end cs Siertri (-300|-300) (0|300) (300|-300) :blue 8 // screen 14 //////////////////////////////////////////////////////////// // // The next 4 fractals are based on the repeated sub-division // of quadrilaterals into 9 similar quads by joining the 1/3 // and 2/3 points of opposite sides. Selected sub-quads are 'cut // out', ie filled with white, and the process is repeated with // the others. // // The functions below assume the following order and labelling - // // b +---+---+---+ c // | 4 | 5 | 6 | // +---+---+---+ B +---+ C // | 3 | 1 | 7 | | 1 | // +---+---+---+ A +---+ D // | 2 | 9 | 8 | // a +---+---+---+ d // //////////////////////////////////////////////////////////// // Sierpinski quadrilateral - aka 'carpet' - white 1 to Sierquad :a :b :c :d :col :g // works for any 4 points to f1 :x :y :z :w if mod :x-:y < :g [exit] // g is granularity local 'A (4*:x + 2*:y + :z + 2*:w)/9 local 'B (2*:x + 4*:y + 2*:z + :w)/9 local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 local 'D (2*:x + :y + 2*:z + 4*:w)/9 fillquad :A :B :C :D :white :white // 1 - white f1 :x (2*:x+:y)/3 :A (2*:x+:w)/3 // 2 - re-enter f1 (2*:x+:y)/3 (:x+2*:y)/3 :B :A // 3 - re-enter f1 (:x+2*:y)/3 :y (2*:y+:z)/3 :B // 4 - re-enter f1 :B (2*:y+:z)/3 (:y+2*:z)/3 :C // 5 - re-enter f1 :C (:y+2*:z)/3 :z (2*:z+:w)/3 // 6 - re-enter f1 :D :C (2*:z+:w)/3 (:z+2*:w)/3 // 7 - re-enter f1 (:x+2*:w)/3 :D (:z+2*:w)/3 :w // 8 - re-enter f1 (2*:x+:w)/3 :A :D (:x+2*:w)/3 // 9 - re-enter end fillquad :a :b :c :d :col :col f1 :a :b :c :d end cs Sierquad (-300|-300) (-300|300) (300|300) (300|-300) :blue 10 // screen 15 // display screens 14 & 15 on same line // Vicsekplus - white 2, 4, 6 and 8 to Vicsekplus :a :b :c :d :col :g // works for any 4 points to f1 :x :y :z :w if mod :x-:y < :g [exit] // g is granularity

Page 128: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

local 'A (4*:x + 2*:y + :z + 2*:w)/9 local 'B (2*:x + 4*:y + 2*:z + :w)/9 local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 local 'D (2*:x + :y + 2*:z + 4*:w)/9 f1 :A :B :C :D // #1 - re-enter fillquad :x (2*:x+:y)/3 :A (2*:x+:w)/3 :white :white // #2 - white f1 (2*:x+:y)/3 (:x+2*:y)/3 :B :A // #3 - re-enter fillquad (:x+2*:y)/3 :y (2*:y+:z)/3 :B :white :white // #4 - white f1 :B (2*:y+:z)/3 (:y+2*:z)/3 :C // #5 - re-enter fillquad :C (:y+2*:z)/3 :z (2*:z+:w)/3 :white :white // #6 - white f1 :D :C (2*:z+:w)/3 (:z+2*:w)/3 // #7 - re-enter fillquad (:x+2*:w)/3 :D (:z+2*:w)/3 :w :white :white // #8 - white f1 (2*:x+:w)/3 :A :D (:x+2*:w)/3 // #9 - re-enter end fillquad :a :b :c :d :col :col f1 :a :b :c :d end cs Vicsekplus (-300|-300) (-300|300) (300|300) (300|-300) :blue 7 // screen 16 // VicsekX - white 3, 5, 7 and 9 to VicsekX :a :b :c :d :col :g // works for any 4 points to f1 :x :y :z :w if mod :x-:y < :g [exit] // g is granularity local 'A (4*:x + 2*:y + :z + 2*:w)/9 local 'B (2*:x + 4*:y + 2*:z + :w)/9 local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 local 'D (2*:x + :y + 2*:z + 4*:w)/9 f1 :A :B :C :D // #1 - re-enter f1 :x (2*:x+:y)/3 :A (2*:x+:w)/3 // #2 - re-enter fillquad (2*:x+:y)/3 (:x+2*:y)/3 :B :A :white :white // #3 - white f1 (:x+2*:y)/3 :y (2*:y+:z)/3 :B // #4 - re-enter fillquad :B (2*:y+:z)/3 (:y+2*:z)/3 :C :white :white // #5 - white f1 :C (:y+2*:z)/3 :z (2*:z+:w)/3 // #6 - re-enter fillquad :D :C (2*:z+:w)/3 (:z+2*:w)/3 :white :white // #7 - white f1 (:x+2*:w)/3 :D (:z+2*:w)/3 :w // #8 - re-enter fillquad (2*:x+:w)/3 :A :D (:x+2*:w)/3 :white :white // #9 - white end fillquad :a :b :c :d :col :col f1 :a :b :c :d end cs VicsekX (-300|-300) (-300|300) (300|300) (300|-300) :blue 7 // screen 17 // display screens 16 & 17 on same line // Cantor Dust - white 1, 3, 5, 7 and 9 to Cantor :a :b :c :d :col :g // works for any 4 points to f1 :x :y :z :w if mod :x-:y < :g [exit] // g is granularity local 'A (4*:x + 2*:y + :z + 2*:w)/9 local 'B (2*:x + 4*:y + 2*:z + :w)/9 local 'C ( :x + 2*:y + 4*:z + 2*:w)/9 local 'D (2*:x + :y + 2*:z + 4*:w)/9 fillquad :A :B :C :D :white :white // #1 - white f1 :x (2*:x+:y)/3 :A (2*:x+:w)/3 // #2 - re-enter fillquad (2*:x+:y)/3 (:x+2*:y)/3 :B :A :white :white // #3 - white

Page 129: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

f1 (:x+2*:y)/3 :y (2*:y+:z)/3 :B // #4 - re-enter fillquad :B (2*:y+:z)/3 (:y+2*:z)/3 :C :white :white // #5 - white f1 :C (:y+2*:z)/3 :z (2*:z+:w)/3 // #6 - re-enter fillquad :D :C (2*:z+:w)/3 (:z+2*:w)/3 :white :white // #7 - white f1 (:x+2*:w)/3 :D (:z+2*:w)/3 :w // #8 - re-enter fillquad (2*:x+:w)/3 :A :D (:x+2*:w)/3 :white :white // #9 - white end fillquad :a :b :c :d :col :col f1 :a :b :c :d end cs Cantor (-300|-300) (-300|300) (300|300) (300|-300) :red 50 // screen 18 Cantor (-300|-300) (-300|300) (300|300) (300|-300) :red 10 // screen 19 // display screens 18 & 19 on same line //////////////////////////////////////////////////////////////// // // T-square fractal does not 'cut' holes in an original shape // but rather builds up its shape by adding smaller replicas of // the origal shape. Start with a square - add 4 new squares, one // around each corner, with side = 1/2 previous size. // Squares are defined as a 'centre', side length and colour - sqline // draws a 'line' square and sqfill draws a filled square. // // Unlike Cantor which 'disappears' after infinite iterations - // T-square boundary is a square of 2* the original side length // //////////////////////////////////////////////////////////////// to sqline :c :s :col // line square with centre c and side s local 'h :s/2 join list [:c+(-:h|-:h) :c+(-:h|:h) :c+(:h|:h) :c+(:h|-:h) :c+(-:h|-:h)] :col end to sqfill :c :s :col // square with centre c and side s filled with col local 'h :s/2 fillquad :c+(-:h|-:h) :c+(-:h|:h) :c+(:h|:h) :c+(:h|-:h) :col :col end to TSquare :c :s :col :g to t1 :x :y if :y < :g [exit] // g is granularity sqfill :x :y :col local 'h :y/2 t1 :x+(-:h|-:h) :h t1 :x+(-:h|:h) :h t1 :x+(:h|:h) :h t1 :x+(:h|-:h) :h end sqline :c 2*:s :col t1 :c :s end // change screen to 'console on top' cs ht xl (-300|150) TSquare (0|0) 150 :black 150 xl (0|150) TSquare (0|0) 150 :black 75 xl (300|150) TSquare (0|0) 150 :black 37

Page 130: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

xl (-300|-150) TSquare (0|0) 150 :black 18 xl (0|-150) TSquare (0|0) 150 :black 9 xl (300|-150) TSquare (0|0) 150 :black 4 // screen 20 // display screen 20 ////////////////// // 3-d Shapes // ////////////////// // Sierpinski (square) pyramid // load tri and Siertri from above // load oblique, grid3 and cube from utils.zno cs ht // draw 'hollow' pyramid of 4 tri's xl (-250|-200) oblique 30 1/2 ( tri (0|0|0) (200|400|200) (0|0|400) :lightgrey 20 tri (0|0|400) (200|400|200) (400|0|400) :darkgrey 20 tri (400|0|400) (200|400|200) (400|0|0) :blue 20 tri (0|0|0) (200|400|200) (400|0|0) :lightblue 20 ) // screen 21 cs // draw 'solid' pyramid of 4 Siertri's xl (-250|-200) oblique 30 1/2 ( Siertri (400|0|400) (200|400|200) (400|0|0) :blue 20 Siertri (0|0|0) (200|400|200) (400|0|0) :lightblue 20 ) // screen 22 // display screens 21 & 22 on same line //////////////////////////////////////////////////////////////////////////// // // The function Sierpyramid is 'very' recursive. The parameter p2 represents // the granularity of the pyramid as a power of 2 - // // p2 = 0 ie 2^0 = 1 => draw 1 pyramid (using pyr) // p2 = n for n<>0 => draw 5 (p2=n-1 pyramids), 4 as square base + 1 on top // //////////////////////////////////////////////////////////////////////////// to Sierpyramid :p2 :blh :s :frontcol :sidecol to pyr:blh local 'apex (:s/2|:s|:s/2) filltri :blh+(:s|0|0) :blh+:apex :blh+(:s|0|:s) :sidecol :black filltri :blh+(0|0|0) :blh+:apex :blh+(:s|0|0) :frontcol :black end if :p2 = 0 [pyr :blh exit] local 'd :s*2^(:p2-1) Sierpyramid :p2-1 :blh + (0|0|:d) :s :frontcol :sidecol Sierpyramid :p2-1 :blh + (:d|0|:d) :s :frontcol :sidecol Sierpyramid :p2-1 :blh :s :frontcol :sidecol Sierpyramid :p2-1 :blh + (:d|0|0) :s :frontcol :sidecol Sierpyramid :p2-1 :blh + (:d/2|:d|:d/2) :s :frontcol :sidecol end // change to console on top // draw 4 pyramids of same size but different granularities

Page 131: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

cs ht xl (-500|-200) oblique 30 1/2 Sierpyramid 2 (0|0|0) 80 :lightgrey :darkgrey xl (0|-200) oblique 30 1/2 Sierpyramid 3 (0|0|0) 40 :lightgrey :darkgrey // screen 23 cs xl (-500|-200) oblique 30 1/2 Sierpyramid 4 (0|0|0) 20 :lightgrey :darkgrey xl (0|-200) oblique 30 1/2 Sierpyramid 5 (0|0|0) 10 :lightgrey :darkgrey // screen 24 // display screens 23 & 24 on same line //////////////////////////////////////////////////////////////// // // Draw 3-d Cantor Dust and Vicsek Plus fractals. // // Repeatedly sub-divide a cube into 27 sub-cubes, ie 3 layers // of 9 each, say back, middle and front. Number and label as // follows - // // +---+---+---+ // | 7 | 8 | 9 | // +---+---+---+ // | 4 | 5 | 6 | // +---+---+---+ // | 1 | 2 | 3 | // (b)lh +---+---+---+ // // Unlike in 2-d, when we 'whited-out' some quads and re-entered // with the others to continue processing - here we are only // concerned with those to process, ie 'whiting out' is replaced // by simply not processing them further. // // Cantor Dust 3-d back and front - re-enter with 1,3,7,9 // middle - all 'white' // // Vicsek Plus 3-d back and front - re-enter with 5 // middle - re-enter with 2,4,5,6,8 // ///////////////////////////////////////////////////////////////// to fillcube :blh :s :frontcol :sidecol :topcol fillquad :blh+(0|:s|0) :blh+(0|:s|:s) :blh+(:s|:s|:s) :blh+(:s|:s|0) :topcol :black fillquad :blh+(:s|0|0) :blh+(:s|:s|0) :blh+(:s|:s|:s) :blh+(:s|0|:s) :sidecol :black fillquad :blh :blh+(0|:s|0) :blh+(:s|:s|0) :blh+(:s|0|0) :frontcol :black end to Cantor3d :blh :s :frontcol :sidecol :topcol :g

Page 132: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

to bf :b :x // cubes 1,3,7,9 local 'x2 2*:x Cantor3d :b :x :frontcol :sidecol :topcol :g // 1 Cantor3d :b+(:x2|0|0) :x :frontcol :sidecol :topcol :g // 3 Cantor3d :b+(0|:x2|0) :x :frontcol :sidecol :topcol :g // 7 Cantor3d :b+(:x2|:x2|0) :x :frontcol :sidecol :topcol :g // 9 end local 'x1 :s/3 local 'x2 2*:x1 if :x1/3 < :g // is next generation < granularity? [ fillcube :blh+(0|0|:x2) :x1 :frontcol :sidecol :topcol // b1 fillcube :blh+(:x2|0|:x2) :x1 :frontcol :sidecol :topcol // b3 fillcube :blh+(0|:x2|:x2) :x1 :frontcol :sidecol :topcol // b7 fillcube :blh+(:x2|:x2|:x2) :x1 :frontcol :sidecol :topcol // b9 fillcube :blh :x1 :frontcol :sidecol :topcol // f1 fillcube :blh+(:x2|0|0) :x1 :frontcol :sidecol :topcol // f3 fillcube :blh+(0|:x2|0) :x1 :frontcol :sidecol :topcol // f7 fillcube :blh+(:x2|:x2|0) :x1 :frontcol :sidecol :topcol // f9 exit ] bf :blh+(0|0|:x2) :x1 bf :blh :x1 end cs ht xl (-500|-200) oblique 30 1/2 ( cube (0|0|0) 300 :lightgrey Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 100 ) xl (0|-200) oblique 30 1/2 ( cube (0|0|0) 300 :lightgrey Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 20 ) // screen 25 cs xl (-500|-200) oblique 30 1/2 ( cube (0|0|0) 300 :lightgrey Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 5 ) xl (0|-200) oblique 30 1/2 ( cube (0|0|0) 300 :lightgrey Cantor3d (0|0|0) 300 :lightgrey :black :darkgrey 2 ) // screen 26 // display screens 25 & 26 on same line to VicsekPlus3d :blh :s :frontcol :sidecol :topcol :g to bf :b :x // cube 5 VicsekPlus3d :b+(:x|:x|0) :x :frontcol :sidecol :topcol :g // 5 end to mid :b :x // cubes 2,4,5,6,8 local 'x2 2*:x VicsekPlus3d :b+(:x|0|0) :x :frontcol :sidecol :topcol :g // 2 VicsekPlus3d :b+(0|:x|0) :x :frontcol :sidecol :topcol :g // 4 VicsekPlus3d :b+(:x|:x|0) :x :frontcol :sidecol :topcol :g // 5 VicsekPlus3d :b+(:x2|:x|0):x :frontcol :sidecol :topcol :g // 6 VicsekPlus3d :b+(:x|:x2|0):x :frontcol :sidecol :topcol :g // 8

Page 133: ZENO · 2019. 2. 5. · Contents Prologue 1 Introduction 2 Lists - programming style; primitive recursive functions; and sets 3 Utilities - graphics font; useful functions for drawing

Appendix 1

end local 'x1 :s/3 local 'x2 2*:x1 if :x1/3 < :g // is next generation < granularity? [ fillcube :blh+(:x1|:x1|:x2) :x1 :frontcol :sidecol :topcol // b5 fillcube :blh+(:x1|0|:x1) :x1 :frontcol :sidecol :topcol // m2 fillcube :blh+(0|:x1|:x1) :x1 :frontcol :sidecol :topcol // m4 fillcube :blh+(:x1|:x1|:x1) :x1 :frontcol :sidecol :topcol // m5 fillcube :blh+(:x2|:x1|:x1) :x1 :frontcol :sidecol :topcol // m6 fillcube :blh+(:x1|:x2|:x1) :x1 :frontcol :sidecol :topcol // m8 fillcube :blh+(:x1|:x1|0) :x1 :frontcol :sidecol :topcol // f5 exit ] bf :blh+(0|0|:x2) :x1 mid :blh+(0|0|:x1) :x1 bf :blh :x1 end to cubesPlus :blh :s :col local 's1 :s/3 local 's2 2*:s1 cube :blh+(:s1|:s1|:s2) :s1 :col //b5 cube :blh+(:s1|0|:s1) :s1 :col // m2 cube :blh+(0|:s1|:s1) :s1 :col // m4 cube :blh+(:s1|:s1|:s1) :s1 :col // m5 cube :blh+(:s2|:s1|:s1) :s1 :col // m6 cube :blh+(:s1|:s2|:s1) :s1 :col // m8 cube :blh+(:s1|:s1|0) :s1 :col // f5 end cs ht xl (-500|-200) oblique 60 2\sqrt 2 VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 100 xl (0|-200) oblique 60 2\sqrt 2 ( cubesPlus (0|0|0) 300 :lightgrey VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 20 ) // screen 27 cs xl (-500|-200) oblique 60 2\sqrt 2 ( cubesPlus (0|0|0) 300 :lightgrey VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 5 ) xl (0|-200) oblique 60 2\sqrt 2 ( cubesPlus (0|0|0) 300 :lightgrey VicsekPlus3d (0|0|0) 300 :lightgrey :black :darkgrey 2 ) // screen 28 // display screens 27 & 28 on same line