Commute Length Analysis: user input with help from Google maps, a pretty version

It has been a long time since I made this, but it was an interesting exploration at the time – and it has languished on a back page of this site for too long.

Userform connecting google maps to a survey

This was made as an abortive attempt to improve my work on a ‘commute survey’ – which used a list of employee addresses to assess the change in commute times due to a move of office. This version shows the route google maps has calculated between the office at the time, the time expected, and allows you to press submit to put your response into a google sheet for further analysis.

In the end, I wasn’t fast enough to get this working well before I needed to start gathering results, and wasn’t able to overcome the barriers to doing many, many requests to google maps for journey details (about 50 responders, with a couple of commute modes each [people were assumed to walk or cycle if it were close enough – in reality this could have been scrapped], return trips, and multiple potential new offices). This lack of ability to collect lots of points also scuppered the idea of making a ‘commute time heat map’ of many locations through London.

You can have a look here:

Laban Dance Icosahedron: a prototype

Rudolf Laban was a dancer, choreographer and movement theorist ( One of Laban’s most enduring contributions to dance is his notation – this notation acts as a way of recording movement and communicating dance, much like a musical score communicates between a composer and a musician.

One part of this notation indicates how the dancer should move in space – is your body extended up and back and right, or low and forward and left? Other parts of the notation include the part of the body that is moving, how long the movement goes on for and the dynamic qualities of the movement (

Much as cellist might practice their scales to help learn the position of their hands, a dancer needs to increase their ability to sense where their body is in space – they must hone their proprioception. Sportspeople do this all the time – when I trampolined we talked about the angle of kickout in terms of time (“a twelve o’clock kickout” means someone exits a shape directly towards the ceiling) and we would hone this by aiming for some position, then feeding back via our coach or a video to do better next time.

Improving your proprioception is made much easier when you have immediate feedback. Fortunately, the positions considered in Laban dance, the points you aim for, which are the corners of three planes that pass through you as you stand, coincide with the vertices of an icosahedron. If you stand in the center of an icosahedron and point to its vertices, you are pointing towards the positions shown in Laban notation, and will be better able to use the notation, and other aspects of the theory, to improve your dancing.

Laban dance teachers and students have been dancing inside icosahedrons as a training tool since the creation of the theory, but their complex nature has meant these icosahedrons tend to be permanent, expensive fixtures – not a lightweight training tools that can be taken to beginners classes, which is where they are likely to have the greatest value. So there is a need for laban dance teachers to be able to carry icosahedrons to lessons, erect the icosahedron, use it during their lesson, deconstruct it and carry them away again.

The icosahedron seems like quite a complex shape to produce – but why? It is completely repetitive and platonic, once you have one rod design, one node design and a way to fit them together, the problem is solved. All the thought must go into the creation of the joints if a ‘rod and node’ solution is pursued. It is also possible to move the complexity around the model – using a tensegrity form to absorb the nodes into the rods and flexible tension members, using a series of face pieces that join at the edges. These alternative approaches were explored – with really interesting and unconservative results. Sadly, perhaps, none were good enough to displace an improved ‘node and rod’ approach, which shares much with what has gone before.

The complexity of the nodes can be largely eliminated by using a magnetic connection – it provides many benefits in this application: it snaps into positon so can be attached without need for precision or force, it cannot transmit enough force to allow damage to the rest of the structure, it can be connected and disconnected without wear or damage and allows extreme geometric simplicity – easing manufacture. The drawbacks of a magnetic connection: low strength, especially little moment capacity, and absolutely no ductility. All of these forthcomings can be designed around by choosing strong magnets and making sure the nodes are built accurately to avoid moments at the connections. A design of embedded magnets in wooden spheres, with embedded magnets in wooden rods was chosen. The extra magnet in each sphere is for holding extra training ribbons in position.

A full set of drawing and manufacturing instructions to follow.

Prototype node with 4 of 5 rods attached, addtional central magnet for ribbon attachment

Node used in icosahedron, with magnet for ribbon in center. Image: Peter Clarkson of Thomas Matthews.

Constructed prototype icosahedron, note that is rests on one edge so two extra feet help to keep it balanced. Image: Peter Clarkson of Thomas Matthews

Deconstructing the icosahedron by removing a node. Image: Charlie Cornish of Expedition

First experiments with virtual Harmonograph

The first experiments are working well, although they are certainly a bit untidy looking – different projections and more consistent behaviours of pendulums are needed.

Individual harmonograph

Image with individual pendulum routes and the harmonograph beneath.

Script taking the csv files of several pendulums into one harmonograph plot, using theory from previous post:

 import numpy
 import matplotlib
 import pandas
 import matplotlib.pyplot as plt
 from mpl_toolkits.mplot3d import Axes3D</pre>
course1 = pandas.read_csv('C:\Users\david\Desktop\spherical_pendulum_0.98m.csv')
course2 = pandas.read_csv('C:\Users\david\Desktop\spherical_pendulum_0.99m.csv')
course3 = pandas.read_csv('C:\Users\david\Desktop\spherical_pendulum_1.00m.csv')

#check each of course1 course2 and course3 have the same number of timesteps
if (course1.shape[0]==course2.shape[0]) and (course2.shape[0]==course3.shape[0]):
print("all the same shape, good news!")
if (course1.shape[1]==course2.shape[1]) and (course2.shape[1]==course3.shape[1]):
print("same number of columns, good news!")
if list(course1.columns.values) == list(course2.columns.values) and list(course2.columns.values) == list(course3.columns.values):
print("same column titles, good news!")

numberOfTimeSteps = course1.shape[0]
timeSteps = numpy.arange(numberOfTimeSteps)
columnTitles = ['t', 'x1', 'y1', 'z1', 'x2', 'y2', 'z2', 'x3', 'y3', 'z3', 'x', 'y', 'z']
constants = {'lambda1':0.8, 'lambda2':0.8, 'lambda3':0.8, 'r1':0.8, 'r2':0.8, 'r3':0.8, 'xsupport1':0.0,'ysupport1':0.0,'zsupport1':0.0,'xsupport2':1.0,'ysupport2':0.0,'zsupport2':0.0,'xsupport3':0.5,'ysupport3':0.86,'zsupport3':0.0,}
harmonographCourse = pandas.DataFrame(numpy.zeros([numberOfTimeSteps,13],dtype=long), index = timeSteps, columns = columnTitles)

harmonographCourse['t'] = course1['t']
harmonographCourse['x1'] = constants['lambda1']*course1['x']+constants['xsupport1']
harmonographCourse['y1'] = constants['lambda1']*course1['y']+constants['ysupport1']
harmonographCourse['z1'] = constants['lambda1']*course1['z']+constants['zsupport1']
harmonographCourse['x2'] = constants['lambda2']*course2['x']+constants['xsupport2']
harmonographCourse['y2'] = constants['lambda2']*course2['y']+constants['ysupport2']
harmonographCourse['z2'] = constants['lambda2']*course2['z']+constants['zsupport2']
harmonographCourse['x3'] = constants['lambda3']*course3['x']+constants['xsupport3']
harmonographCourse['y3'] = constants['lambda3']*course3['y']+constants['ysupport3']
harmonographCourse['z3'] = constants['lambda3']*course3['z']+constants['zsupport3']

xsupport1 = numpy.array([constants['xsupport1'],constants['ysupport1'],constants['zsupport1']])

for timeStep in timeSteps:
x1 = numpy.array([harmonographCourse.loc[timeStep,'x1'],harmonographCourse.loc[timeStep,'y1'],harmonographCourse.loc[timeStep,'z1']])
x2 = numpy.array([harmonographCourse.loc[timeStep,'x2'],harmonographCourse.loc[timeStep,'y2'],harmonographCourse.loc[timeStep,'z2']])
x3 = numpy.array([harmonographCourse.loc[timeStep,'x3'],harmonographCourse.loc[timeStep,'y3'],harmonographCourse.loc[timeStep,'z3']])
vector_a = x2 - x1
vector_c = numpy.cross((x2-x1),(x3-x1))
vector_b = numpy.cross((x2-x1),vector_c)
norm_vector_a = vector_a / numpy.sqrt(numpy.sum(numpy.square(vector_a)))
norm_vector_b = vector_b / numpy.sqrt(numpy.sum(numpy.square(vector_b)))
norm_vector_c = vector_c / numpy.sqrt(numpy.sum(numpy.square(vector_c)))
d =,norm_vector_a)
i =,norm_vector_a)
j =,norm_vector_b)
a = (numpy.square(constants['r1']) - numpy.square(constants['r2']) + numpy.square(d)) / (2*d)
b = (numpy.square(constants['r1']) - numpy.square(constants['r3']) + numpy.square(i) + numpy.square(j))/(2*j) - i/j*a
c = -1*numpy.sqrt(numpy.square(constants['r1'])-numpy.square(a)-numpy.square(b))
x = xsupport1 + x1 + a*norm_vector_a + b*norm_vector_b + c*norm_vector_c
harmonographCourse.loc[timeStep,'x'] = x[0]
harmonographCourse.loc[timeStep,'y'] = x[1]
harmonographCourse.loc[timeStep,'z'] = x[2]
print harmonographCourse

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(harmonographCourse['x'], harmonographCourse['y'], harmonographCourse['z'], label = 'harmonograph')
ax.plot(harmonographCourse['x1'], harmonographCourse['y1'], harmonographCourse['z1'], label = '0.98m pendulum')
ax.plot(harmonographCourse['x2'], harmonographCourse['y2'], harmonographCourse['z2'], label = '0.99m pendulum')
ax.plot(harmonographCourse['x3'], harmonographCourse['y3'], harmonographCourse['z3'], label = '1.00m pendulum')
ax.set_xlabel('x value')
ax.set_ylabel('y value')
ax.set_zlabel('z value')

Harmonograph from spherical pendulums

Spherical pendulums produce some attractive forms on their own, but they have been applied together for a long time now (it is quite a Victorian thing apparently) to create compound shapes. The machines that make these shapes are called harmonographs, so called due to their use in helping to visualise musical harmonies. As far as I know, Harmonographs have only ever been curiosities, without any real practical application beyond the production of attractive postcards.

Harmonographs use pendulums in a variety of configurations to produce different shapes, dragging a pen over paper to produce a shape. Some use simple pendulums in combination with spherical pendulums. In every case, the complexity and beauty of the form produced is much greater than the crude contraption it has come from.

A few harmonographs have been produced using light and long exposure and produce very beautiful images:

One artist (artist collective) has already done some of this before, though without interaction between the physical and the digital. I hear they are a big deal, so very happy to follow in their footsteps.

Someone online has made a 3D harmonograph using python (as I hope to do very soon!) but has just used sinusoidal patterns rather than any proper decay functions to try to model a spherical pendulum – I am not even sure they have used a model of a spherical pendulum rather than a series of simple pendulums. I wonder how mine might be different.

Solution for a simple harmonograph’s motion is here:

Download (PDF, 516KB)

Spherical Pendulums

Finding the governing equations, and forming a strategy for creating a really basic solver given some initial conditions:

Download (PDF, 122KB)

Then using this code to draw some pendulums and their movements through time:

For a simple pendulum, plotting its x and y coordinated with time, without any air resistance:


Then including some air resistance, see pdf for detail, shows a roughly exponential decay of the amplitude of the oscillations over time, as would be expected:


The same approach is then taken with the more complicated spherical pendulum, which, with no air resistance considered, has a path that looks like this:


Adding in a small air resistance of alpha=0.01 (see pdf for expanation), produces a slightly different path, as would be expected. The ‘no air resistance path’ is in blue, the ‘small air resistance path’ is in green:


Following the green path for a longer period of time, we see the following pattern (now plotted in blue):


Setting alpha=0.05 leads to the following difference from the no air resistance path (no air resistance in blue, with air resistance in green):


Following this green path for a longer period of time we see the following pattern (now plotted in blue rather than green):


Perhaps most nicely, the later, gentle, spiraling behaviour is clear here.


The code used to generate these plots was as follows, for detail on how it was derived see the pdf at the top of the post:

The simple pendulum:

import numpy
import matplotlib
import pandas
import matplotlib.pyplot as plt
import time
from mpl_toolkits.mplot3d import Axes3D

def inputInitialConditions():
 print("installising arrays and inputting initial conditions")
 t_initial = 0
 theta_initial = numpy.pi/5
 thetadot_initial = 0
 psi_initial = 0
 psidot_initial = 4
 numberOfTimeSteps = 20000
 lengthOfTimeStep = 0.001
 m = 1
 l = 1
 g = 9.81
 alpha = 0.04
 timeSteps = numpy.arange(numberOfTimeSteps)
 columnTitles = ['t', 'theta', 'thetadot', 'thetadotdot', 'psi', 'psidot', 'psidotdot', 'x', 'y', 'z']
 constants = {'m':m, 'l':l, 'g':g, 'lengthOfTimeStep':lengthOfTimeStep, 'numberOfTimeSteps':numberOfTimeSteps, 't_initial':t_initial, 'alpha':alpha}
 course = pandas.DataFrame(numpy.zeros([numberOfTimeSteps,10],dtype=long), index = timeSteps, columns = columnTitles)
 course.loc[0] = [t_initial, theta_initial,thetadot_initial,0,psi_initial,psidot_initial,0,0,0,0]
 return [course, constants, timeSteps]

def completeInitialTimeStep(course, constants, timeSteps):
 g = constants['g']
 l = constants['l']
 m = constants['m']
 alpha = constants['alpha']
 t_initial = constants['t_initial']
 theta = course.loc[0,'theta']
 psi = course.loc[0,'psi']
 if numpy.absolute(theta) < 0.000001:
 theta = 0.000001
 print 'Important Warning: Very small theta on timestep 0 generating errors, use simple pendulum program'
 if numpy.absolute(theta) > numpy.pi/2:
 theta = numpy.pi/2 
 print 'Important Warning: Very large theta, potential errors or unphysical behaviour'
 sintheta = numpy.sin(theta)
 costheta = numpy.cos(theta)
 tantheta = sintheta / costheta
 sinpsi = numpy.sin(psi)
 cospsi = numpy.cos(psi)
 psidot = course.loc[0, 'psidot']
 thetadot = course.loc[0,'thetadot']

 course.loc[0,'thetadotdot'] = ((psidot**2)*costheta-g/l)*sintheta-alpha*l/m*sintheta*numpy.absolute(thetadot)*thetadot
 course.loc[0,'psidotdot'] = -2*psidot*thetadot/tantheta-alpha*l/m*numpy.absolute(psidot)*psidot
 course.loc[0,'t'] = t_initial
 course.loc[0,'x'] = l*sintheta*cospsi
 course.loc[0,'y'] = l*sintheta*sinpsi
 course.loc[0,'z'] = l*costheta
 return course

def calculatePendulumCourse(course, constants, timeSteps):
 g = constants['g']
 l = constants['l']
 m = constants['m']
 alpha = constants['alpha']
 lengthOfTimeStep = constants['lengthOfTimeStep']
 previoustheta = course.loc[0,'theta']
 previousthetadot = course.loc[0, 'thetadot']
 previousthetadotdot = course.loc[0, 'thetadotdot']
 previouspsi = course.loc[0,'psi']
 previouspsidot = course.loc[0,'psidot']
 previouspsidotdot = course.loc[0,'psidotdot']
 for timeStep in timeSteps[1:]:
 theta = previoustheta + (previousthetadot * lengthOfTimeStep) + ((previousthetadotdot * lengthOfTimeStep**2)/2)
 course.loc[timeStep, 'theta'] = theta
 sintheta = numpy.sin(theta)
 costheta = numpy.cos(theta)
 tantheta = numpy.tan(theta)
 if numpy.absolute(theta) < 0.000001:
 sintheta = 0.000001
 tantheta = sintheta
 print 'Important Warning: Very small theta on timestep' + str(timeStep)
 psi = course.loc[timeStep, 'psi'] = previouspsi + (previouspsidot * lengthOfTimeStep) + ((previouspsidotdot * lengthOfTimeStep**2)/2)
 course.loc[timeStep, 'psi'] = psi
 sinpsi = numpy.sin(psi)
 cospsi = numpy.cos(psi)
 if numpy.absolute(psi) < 0.000001:
 sinpsi = 0.000001
 print 'Important Warning: Very small psi on timestep' + str(timeStep)
 tanpsi = sinpsi / cospsi 
 thetadot = previousthetadot + previousthetadotdot * lengthOfTimeStep
 course.loc[timeStep, 'thetadot'] = thetadot
 psidot = previouspsidot + previouspsidotdot * lengthOfTimeStep
 course.loc[timeStep, 'psidot'] = psidot 
 thetadotdot = ((psidot**2)*costheta-g/l)*sintheta-alpha*l/m*numpy.absolute(thetadot)*thetadot
 course.loc[timeStep,'thetadotdot'] = thetadotdot
 psidotdot = -2*psidot*thetadot/tantheta-alpha*l/m*numpy.absolute(psidot)*psidot*sintheta
 course.loc[timeStep,'psidotdot'] = psidotdot
 x = l*sintheta*cospsi
 y = l*sintheta*sinpsi
 z = l*costheta
 course.loc[timeStep,'x'] = x
 course.loc[timeStep,'y'] = y
 course.loc[timeStep,'z'] = z
 previoustheta = theta
 previousthetadot = thetadot
 previousthetadotdot = thetadotdot
 previouspsi = psi
 previouspsidot = psidot
 previouspsidotdot = psidotdot
 return course
def plotPendulumCourse(course):
 xs = course['x']
 ys = course['y']
 zs = course['z']
 fig = plt.figure()
 ax = fig.gca(projection='3d')
 ax.plot(xs, ys, zs)

def main():
 print("Starting spherical pendulum")
 t0 = time.time()
 [course,constants,timeSteps] = inputInitialConditions()
 course = completeInitialTimeStep(course, constants, timeSteps)
 course = calculatePendulumCourse(course, constants, timeSteps)
 print (time.time()-t0)
 print("Completed spherical pendulum")


The comparison plot:

import numpy
import matplotlib
import pandas
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

course0 = pandas.read_csv('C:\Users\david\Desktop\spherical_pendulum_no_air_resistance.csv')
course1 = pandas.read_csv('C:\Users\david\Desktop\spherical_pendulum_0.01_air_resistance.csv')
course5 = pandas.read_csv('C:\Users\david\Desktop\spherical_pendulum_0.05_air_resistance.csv')
course10 = pandas.read_csv('C:\Users\david\Desktop\spherical_pendulum_0.1_air_resistance.csv')

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(course0['x'], course0['y'], course0['z'], label = 'alpha = 0')
ax.plot(course1['x'], course1['y'], course1['z'], label = 'alpha = 0')
ax.plot(course5['x'], course5['y'], course5['z'], label = 'alpha = 0')
ax.plot(course10['x'], course10['y'], course10['z'], label = 'alpha = 0')
ax.set_xlabel('x value')
ax.set_ylabel('y value')
ax.set_zlabel('z value')

The world is inside out


Another day, another door on the tube. But, Donald J. Trump is now president elect of the United States, so I can’t be more odd than the median(ish) American.

The inside out

Door on the tube

Today I carried an ebay-ed door across London. The second door can wait, my forearms hurt.

But, so many people engaged with it – mostly with jokes, knocking on it, or making up stories as to why it was there.

There was something about this door, ripped from its doorway, that was strange and intruiging – the mundanity heightening the strangeness.

I agree, it is an unsettling thing to find. The inside has been taken out: literally – something pinned down has escaped, as a small insight into personal taste that is usually left unshown, and as something that brings forward doors other people have known.

Everyone liked doorways, not everyone liked the door, or doors.

Getting started with Grasshopper, working with set data

Sets are a subset of lists in grasshopper, with some useful restrictions, though on the whole their usefulness is quite limited.

Sets are limited to more primitive data types, such as numbers, strings and vectors, where there is an easy test for equality, it does not allow more complex objects like curves and breps. A set does not allow the same element to appear more than once, though note that items that look similar might be identical, for example an integer and float, with the same value. However, they are not the same.

There are many functions in the sets tab in grasshopper that seem better suited to lists – for example components that assume there might be identical elements in a set.

An introduction to the different containers for data available in grasshopper is here:

Download (PDF, 621KB)

Getting started with Grasshopper: Working neatly, working with list data

First, good sources of information:



AAD_Algorithms-Aided Design by Fulvio Wirz


I am starting to use Grasshopper in anger now – and am managing to create things more quickly, and explore ideas that usually very hard, compared modelling by hand. I am taking a different approach to others who have been learning the software – I am looking at how it manipulates data and then thinking about how this could be applied, rather than approaching problems and trying to solve them directly. This is probably a reflection of my background as a more theoretically driven engineer, but I feel it has some real benefits in knowing how the program works, and is supposed to work, rather than developing bad habits and workarounds. I will need to move onto creating real items eventually though – though hopefully when I do I will be creating efficiently and working with the program, rather than against it.


There are several data primitives in grasshopper, which closely align to the geometric primitives found in Rhino3D – points, vectors, curves of various types, rectangular surfaces and their breps, fields. There are other primitives not seen in Rhino to control the flow of data: booleans, numbers, strings, colours, domains, matrices, file paths. Often, these are the properties of rhino primitive – the length of a curve expressed as a float for example.


There seem to be significant differences between working in Rhino and Grasshopper about ‘Modelling with Precision’ – in Grasshopper precision is guaranteed by the environment (or at least by the catastrophic results of making a mistake, errors usually become very apparent – usually…). In comparison, when modelling in Rhino discipline is required to keep a model working well and with good associative relationships, for example via the use of compound points and using the appropriate object snaps.


See pdf for examples of items listed below:

Download (PDF, 914KB)


Working neatly in grasshopper:

Clustering: the most powerful way of working neatly, combines many components into one, this cluster can then be reused and saved as a cluster and used elsewhere.

Grouping – put a box round things

Aligning – make boxes line up nicely, not associative, which might be a mercy


Working with list data:

Lists from panels, type in data with a new line between each item, turn off ‘multiline data’ in the options (right click on the panel object).

Whilst lists of primitives are common (e.g. a range of numbers), the most common use of lists are lists of geometric primitives – for example, ‘set multiple lines’ in a line primitive will create a list of lines, this list of objects can then be manipulated as a list of normal primitives.

Many different ways to create, interrogate, manipulate lists. Some much more useful than others. See pdf for examples.


Next up, working with tree data structures.

Thoughts on: The Selection of Design, Gorgon L. Glegg

The Selection of Design is short – really short, it maybe takes an hour to read through. This is understandable, looking at the timeline of books written by Glegg this is the second, written four years after The Design of Design, which I enjoyed greatly. Unfortunately it suffers the fate of many second outputs, it fails to live up to the first as it only contains a few years of wisdom, whereas the first contained the best ideas of most of a career.

Many of the ideas are interesting and some are thought provoking, though there are some that do not feel are fully thought through.

  • There is little simple engineering left – or at least there shouldn’t be… disagree with this – changes in opportunity and materials allow simple solutions where previously a workaround was required
  • Try to focus your thought when starting to solve a problem at the ‘interfaces’ to make these, often hard to analyse, parts simple – in the case of a manufacturing run this is often at the interface where, up to the interface, value is measured in weight (to help account for variation in density) and afterwards it is measured in volume. For other systems the interfaces can often be seen at points where the types of energy change radically. There is usually more than one interface in each system. When designing, start from each of these interfaces and work outwards. Agree with this.
  • As a strategy when faced with difficult and highly constrained problems, try solving the problem several times, each time with one of the constraints removed – what is common between these solutions? Try to reimpose the final condition by adjusting one of the partial designs. Agree with this.
  • Think about the context of the thing you are designing in its entirety and think about ways it might vary from your common experience – an example given is moisture in the air condensing on cool objects, making them wet, another that vibrations make nuts fall off bolts, changing the conditions of the machine.
  • When choosing between designs of seemingly equal merit, give benefit to the one that is statically determinate (or easy to analyse accurately), this reduces the risk by allowing a more informed design. If both are determinate and easy enough to analyse accurately, choose the one that is “complicated*” and “could not have been done 5 years ago”. I disagree with the latter – the assumption that all neat design solutions have already been found is certainly not true in structural engineering.
    • * Complicated is justified later – something with unneeded complications is bad, something with appropriate complexity tends to be good. Glegg is still advocating the approach of ‘divide and tidy up’ from The Design of Design, but is now pushing towards a paradigm of a fairly direct mapping of function to components, this is advocated over a many functions to few components approach largely to increase the effectiveness of any one component – I agree with this. However, in the context of another constraint the combining of functions might well be well worthwhile despite impacts on individual component’s efficiency, for example, reducing the weight of a racing car by using the block of the engine as part of the structure of the car.
  • Differentiating between possible impossibilities and intrinsic impossibilities – use basic principles, not only from physics and engineering, but also from accounting, psychology etc.
  • When faced with an impossibility do not try to negotiate a compromise – the right solution will not lie there, instead, try to make some of the impossibility dissolve through a clever solution, or one that moves a part of the impossibility elsewhere where it can be easily managed.
  • Value simplicity only for its more direct virtues, such as reliability and cheapness. There is no intrinsic value in simplicity itself. Furthermore, an oversimplified design can be vulnerable to small variations between the model and the real world which a more complicated design is able to accommodate.
  • Work with the material and its effects wherever you can – use expansion to create beneficial internal stresses, change the material (e.g. heating or cooling it) so it works for you rather than fighting it


Now with complementary bookmark – good choice Keith Blacks. Who knew the Spice Girls were still touring together in 2008?