How to Draw a Hyperboloid

Daniel Davis – 6 September 2014

Drawing a hyperboloid seems like a fairly straightforward task. In a world where architects are accustomed to creating complicated, non-uniform, free-form surfaces, the hyperboloid is a relatively regular shape. It seems trivial. Right now you’ve probably thought of three ways to draw a hyperboloid. I can tell you: they are all wrong.

For the past five years I’ve been drawing hyperboloids. Working as an assistant to Mark Burry on Antoni Gaudí’s Sagrada Família, I’ve drawn hyperboloids over and over. I’ve never quite managed to draw a totally accurate one in Rhino (often we have to use more sophisticated software like CATIA). My quest to draw the perfect hyperboloid has taken me progressively deeper into the geometry engine underlying NURBs based CAD programs like Rhino. Last month, I finally found a way to draw an accurate hyperboloid.

My hyperboloid drawing method derives from the underlying mathematics of NURBs surfaces. Despite the reliance on NURBs in contemporary architecture, I’ve never read anything about this fundamental geometric formula, much less about how to manipulate this formula to draw accurate shapes. In this post I’ll outline a number of methods for drawing hyperboloids. In the process I’ll expose the mechanisms of NURBs and show how you too can take advantage of these formulas to draw mathematically accurate shapes.

1. An intuitive hyperboloid

gif3

A hyperboloid can be made by twisting either end of a cylinder.

A hyperboloid can be generated intuitively by taking a cylinder and twisting one end. Twist tight enough and you’ll get two cones meeting at a point. Twist gently and you’ll get a shape somewhere between a cone and a cylinder: a hyperboloid. Depending on how you look at it, it is either a cylinder that flairs outwards or a cone that never quite comes to a point.

The hyperboloid is a doubly ruled surface. That is to say, for any point on the hyperboloid, two perfectly straight lines can be drawn on the surface passing through that point. This is the unique property of doubly ruled surfaces: although they are curved, you can always find a straight line on them.

Hyperboloids in Sagrada Família ceiling

The interior of the Sagrada Família looks complicated but if you study the geometry closely you’ll see that it is composed using a series of mathematical rules. In this case, the ceiling comprises of hyperboloids. The triangular cutouts follow the ruled geometry of the hyperboloids.

Much of Gaudí’s architecture is composed from doubly ruled surfaces (hyperboloids, hyperbolic paraboloids, helicoids, and planes). Gaudí rarely wrote about his design methods, so we can’t be certain as to why he favoured using doubly ruled surfaces. One possible reason is that the straight lines make the curves easy to specify. Unlike most other curved surfaces, the hyperboloid can be communicated intuitively and without any drawings. All a stone mason needs is the radius of the cylinder, the length, and the amount it has been twisted. To verify the surface is correct, you can just run a ruler along the surface. This type of construction logic always astounds me about Gaudí’s architecture. At first glance you see complicated curved surfaces, but if you look closely there is an elegant rational to his forms that make them possible to construct, even prior to the computer.

Most of my work for Mark Burry on Gaudí’s Sagrada Família involves hyperboloids in some way. Even projects I’ve worked on outside the Sagrada Família (although still with Mark), such as the Responsive Acoustic Surface and the Fab Pod, are a comprised of hyperboloids. I’ve milled hyperboloids from plywood, I’ve made them with spun metal, 3d printers, and plaster. On my 24th birthday, my girlfriend at the time made me a hyperboloid shaped cake. In this strange way, hyperboloids have become a regular part of what I do.

Hyperboloids in the Fab Pod

The Fab Pod is made from hyperboloids positioned to optimise their acoustic properties. Photograph by John Gollings.

While hyperboloids are easy to explain, they are difficult to draw in Rhino. The easiest way to draw a hyperboloid is to follow the explanation I’ve given above. Draw two offset circles (the two ends of the cylinder), twist one of the circles, draw a line between the circles, and create a revolved surface using that line. The code below shows how to do this. Unfortunately, you often end up with weird artefacts at the neck of the hyperboloid (shown below). This has to do with how the revolved line skews the UV curves of the hyperboloid surface. The construction logic of the hyperboloid doesn’t necessarily translate into the computer.

These striations in the neck of the hyperboloid come from the meshing algorithm. The twist makes everything somewhat inaccurate.

These striations in the neck of the hyperboloid come from the meshing algorithm. The twist makes everything somewhat inaccurate.

  1. #Rhino Python code to make a twisted hyperboloid
  2. import scriptcontext
  3. import Rhino
  4. import math
  5.  
  6. def get_hyperboloid(radius, twist, depth) :
  7.     """
  8.     Create revolved surface from line between circles.
  9.     """
  10.     top = Rhino.Geometry.Point3d(0,0,depth)
  11.     top = Rhino.Geometry.Plane(top, Rhino.Geometry.Vector3d.ZAxis)
  12.     top = Rhino.Geometry.Circle(top, radius)
  13.  
  14.     bottom = Rhino.Geometry.Point3d(0,0,-depth)
  15.     bottom = Rhino.Geometry.Plane(bottom, Rhino.Geometry.Vector3d.ZAxis)
  16.     bottom = Rhino.Geometry.Circle(bottom, radius)
  17.  
  18.     p_top = top.PointAt(0)
  19.     p_bottom = bottom.PointAt(twist)
  20.  
  21.     line = Rhino.Geometry.Line(p_top, p_bottom)
  22.     axis = Rhino.Geometry.Line(Rhino.Geometry.Point3d(0,0,0), Rhino.Geometry.Point3d(0,0,1))
  23.     hyperboloid = Rhino.Geometry.RevSurface.Create(line, axis)
  24.  
  25.     return hyperboloid
  26.  
  27. if __name__=="__main__":
  28.     """
  29.     Generate and bake hyperboloid.
  30.     """
  31.     hyperboloid = get_hyperboloid(2, 2, 1)
  32.     attributes = Rhino.DocObjects.ObjectAttributes()
  33.     scriptcontext.doc.Objects.AddSurface(hyperboloid, attributes)
  34.     scriptcontext.doc.Views.Redraw()

2. A mathematical hyperboloid

from_points_crop

These points were positioned using the hyperboloid formula. The surface was then interpolated through the points to generate the hyperboloid. While the points are accurate, the surface is still not entirely precise.

A hyperboloid can also be defined mathematically. The formula for a hyperboloid is:

f1

Parameterised, the formula becomes:

f2

Using this formula, we can generate any point on the hyperboloid. If we generate enough points, we can create a interpolated surface through the points.

  1. #Rhino Python code to make an interpolated hyperboloid
  2. import scriptcontext
  3. import Rhino
  4. import math
  5.  
  6. def get_hyperboloid(a, b, c, depth) :
  7.     """
  8.     Create revolved surface from hyperbola.
  9.     Scale to match proportions of hyperboloid.
  10.     """
  11.     detail_u = 10
  12.     detail_v = 10
  13.  
  14.     pts = list()
  15.  
  16.     for u in range(int(detail_u)):
  17.         for v in range(int(detail_v)):
  18.             u_normal = ((depth * 2 * u / (detail_u - 1)) - depth) / c
  19.             v_normal = 2 * math.pi * v / (detail_v)
  20.  
  21.             x = a * math.sqrt(1 + u_normal**2) * math.cos(v_normal)
  22.             y = b * math.sqrt(1 + u_normal**2) * math.sin(v_normal)
  23.             z = c * u_normal
  24.  
  25.             p = Rhino.Geometry.Point3d(x, y, z)
  26.  
  27.             pts.append(p)
  28.  
  29.     hyperboloid = Rhino.Geometry.NurbsSurface.CreateThroughPoints(pts, detail_u, detail_v, 3, 3, False, True)
  30.     return hyperboloid
  31.  
  32. if __name__=="__main__":
  33.     """
  34.     Generate and bake hyperboloid.
  35.     """
  36.     hyperbola = get_hyperboloid(1, 2, 1, 6)
  37.     attributes = Rhino.DocObjects.ObjectAttributes()
  38.     scriptcontext.doc.Objects.AddSurface(hyperbola, attributes)
  39.     scriptcontext.doc.Views.Redraw()

For a number of years this was the method I used to draw hyperboloids. From a distance it looks good, but if you examine the surface closely you’ll notice some slight inaccuracies. The points are in the right place, but the parts in-between – the parts that were interpolated – are sometimes too flat or too bent. This is because the interpolated curve is following the NURBs formula rather than the hyperboloid formula. The curve passes through all the points we defined but the curve is not following the mathematical formula we used.

diff

In a section through a hyperboloid you can see the difference between an interpolated hyperboloid (red) and an accurate one (blue). The difference is visually minor but fairly severe in a practical sense.

The inaccuracy can be reduced somewhat by increasing the number of points (which effectively reduces the distance of interpolation). Unfortunately, increasing the points also increases the computational complexity of the surface. At a certain density, the surfaces become unmanageable. This can be slightly mitigated by using fewer points in the flatter areas of the hyperboloid and more points in the curved section. Even then, the inaccuracy is only reduced and never eliminated. There will always be problems with the surface.

3. A BIM hyperboloid

Excel spreadsheet containing names and positions of hyperboloids. Some data has been obscured.

Excel spreadsheet containing names and positions of hyperboloids. Some data has been obscured.

I got around the interpolation problem by bypassing the Rhino geometry engine and creating my own specially for hyperboloids. Rather than drawing the hyperboloids in Rhino, I would store the shape of the hyperboloids in a spreadsheet. If I needed view the hyperboloids, I would draw them in Rhino, but if I needed to manipulate the hyperboloids, I would do it mathematically through code. For example, instead of relying on Rhino’s intersection function to find the junction between two hyperboloids, I would mathematically calculate where this intersection occurred based on the data from the spreadsheet. The results were perfect, the interface was clunky, and the mathematics was non-trivial. In my thesis I wrote about finding the intersections between hyperboloids on the Fab Pod, the equation looked like this:

formulas

4. A NURBs hyperboloid

Recently on the Sagrada Família we once again ran into the problem with the accuracy of the hyperboloids in Rhino. I began investigating how Rhino drew native elements like circles, which didn’t seem to suffer from any interpolation problems. They were always perfect. My initial assumption was that Rhino handled these native elements differently to other free-form NURBs curves. It seemed that Rhino was somehow using the formula for the circle instead of the NURBs formula. I was half-right. Rhino does use the formula for the circle but only via the NURBs formula. In other words, Rhino manipulates the inputs to the NURBs formula in such a way that it becomes the circle formula. On Wikipedia there is even an example of how to draw a perfect circle using NURBs.

Table showing location and weights of control points for a NURBs circle.

Location and weights of control points for a perfect NURBs circle. As explained in: http://en.wikipedia.org/wiki/Non-uniform_rational_B-spline

The table above gives the location for a set of control points that define a circle. The NURBs curve loosely traces path of these points, getting pulled towards the weightier points and passing more directly past the lighter points. These points don’t produce a free-form NURBs curve that approximates a circle, rather, when these precise values are entered into the NURBs formula, the NURBs formula becomes the formula for a circle. This is true of many analytic shapes. If you know the NURBs formula, you can manipulate the input variables to transform the NURBs formula into everything from the formula for a circle to the formula for a hyperboloid.

As an example, I’ll show you how to derive the points and weights needed to draw a hyperboloid using NURBs. First you need to see the NURBs formula, which looks a bit crazy:

f3

Where:

  • C is the point being calculated,
  • u is the location of the calculated point,
  • P is a control point,
  • w is the corresponding weight,
  • k is the number of control points,
  • N is the b-spline basis function,
  • And n is the degree of the curve.

The NURBs formula is a general version of the Bézier formula. If the points and weights of a Bézier curve are put into the NURBs formula, it will draw an identical shape. The only difference between NURBs curves and Bézier curves is that NURBs curves can have additional knots (essentially kinks) whereas Bézier curves can only draw continuous shapes. You’ll notice that the Bézier formula is therefore slightly more simple than the NURBs formula:

f4

Where B is the Bernstein polynomial.

Since the hyperboloid is a continuous shape, the Bézier formula can be used to derive the points and weights needed to draw a hyperboloid. Before drawing the 3d hyperboloid, we will first draw the 2d profile: a hyperbola. There is a hyperbola tool in Rhino but there isn’t any way to generate a hyperbola algorithmically. You could draw one using an interpolated curve, but as I’ve shown above, this will produce inaccurate results. The only way to draw a hyperbola accurately is to turn the formula for the Bézier curve into the formula for a hyperbola.

cut [Converted]-01

A hyperbola drawn on the XZ plan. To draw this hyperbola we need to calculate P0, P1, P2, and q.

The hyperbola formula looks like this (note that I’m drawing the hyperbola on the XZ plane just so the hyperbola lines up with the hyperboloid formula given above):

f5

To turn the Bézier formula into the hyperbola formula, we first need to know the degree of curve. Hyperbolas are quadratic since the the highest order is two (everything is to the power of two). Based on the Bézier formula above, the Bernstein polynomial for a quadratic curve is:

f6

These Bernstein polynomials can be inputed into the Bézier formula, which results in:

f7

All of a sudden there are only six unknowns in the Bézier formula: P0, P1, P2, & their corresponding weights. We just have to find these six values such that the formula equals the hyperbola formula (see diagram above to get a sense for how these points relate to the hyperbola).

One property of Bézier curves is that the curve always passes through the start and end points. This means the weights of these points doesn’t matter, so we can set w0 and w2 to 1. This also means that P0 and P2 must be a point on the hyperbola. Using the hyperbola formula, and setting P0 at an arbitrary height (h) on the z-axis, P0 becomes:

f8

Where h is the height of the hyperbola. For simplicity sake, we will make P2 the mirror image of P0:

f9

The only variables outstanding are P1 and w1. We know that P1 lies on the x-axis, so P1.z must equal zero. We also know that the ends of a Bézier curve are always tangental to the control points. In other words, the line between P1 and P0 is tangental to the hyperbola at P0.

The tangent of a hyperbola is:

f10

Where:

  • x, z is the point on the tangent (P1),
  • and x’, z’ is the point on the hyperbola we are calculating the tangent for (P0).

Since P0 is a point on the hyperbola that P1 is tangental to, we can use P0 for x’ & z’. And since P1 lies on the x-axis, P1.z must be zero. Therefore, all we need to solve for is x. Putting these variables into the formula above and rearranging gives the location of P1 relative to P0:

All that is left to calculate is w1. Since the hyperbola is symmetrical, we know the hyperbola will intersect with the x-axis at the apex of the curve (point q). Point q lies on the x-axis, so z=0 for point q. Putting z=0 into the hyperbola formula gives the location of point q as:

f12

Point q is the middle of the hyperbola. In the Bézier formula, this occurs when u=0.5. Putting u=0.5 into the Bézier formula results in:

f13

Simplifying and replacing the values we have calculated above (wo = 1, w1 = 2, P2 = P0 [which happens in the x dimension], and C(0.5) for q) gives:

f14

Multiplying the denominator and numerator by two:

f15

Rearranging:

f16

And with that, we have all the variables for defining a hyperbola (P0, P1, P2, w0, w1, w2). Putting this all into Rhino Python, you end up with the code below.

  1. #Rhino Python code to make an accurate hyperboloid
  2. import scriptcontext
  3. import Rhino
  4. import math
  5.  
  6. def get_hyperbola(a, c, h) :
  7.     """
  8.     Draws a hyperbola on the XZ plane, centred at 0,0,0.
  9.     """
  10.  
  11.     p0 = Rhino.Geometry.Point3d(0, 0, 0)
  12.     p1 = Rhino.Geometry.Point3d(0, 0, 0)
  13.     p2 = Rhino.Geometry.Point3d(0, 0, 0)
  14.     q = Rhino.Geometry.Point3d(0, 0, 0)
  15.  
  16.     p0.X = math.sqrt(a**2 * (1 + (h**2 / c**2)))
  17.     p0.Z = h
  18.  
  19.     p1.X = (-1 * p0.Z**2 * a**2) / (c**2 * p0.X) + p0.X
  20.     p1.Z = 0
  21.  
  22.     p2.X = p0.X
  23.     p2.Z = -h
  24.  
  25.     q.X = a
  26.     q.Z = 0
  27.  
  28.     w1 = (p0.X-q.X) / (q.X-p1.X)
  29.  
  30.     points = [p0, p1, p2]
  31.     hyperbola = Rhino.Geometry.NurbsCurve.Create(False, 2, points)
  32.     hyperbola.Points.SetPoint(1, Rhino.Geometry.Point4d(p1.X, p1.Y, p1.Z, w1))
  33.  
  34.     return hyperbola
  35.  
  36. def get_hyperboloid(a, b, c, depth) :
  37.     """
  38.     Create revolved surface from hyperbola.
  39.     Scale to match proportions of hyperboloid.
  40.     """
  41.     hyperbola = get_hyperbola(a, c, depth)
  42.     axis = Rhino.Geometry.Line(Rhino.Geometry.Point3d(0,0,0), Rhino.Geometry.Point3d(0,0,1))
  43.     hyperboloid = Rhino.Geometry.RevSurface.Create(hyperbola, axis)
  44.  
  45.     y_factor = float(b) / float(a)
  46.     scale = Rhino.Geometry.Transform.Scale(Rhino.Geometry.Plane.WorldXY, 1, y_factor, 1)
  47.     hyperboloid = hyperboloid.ToNurbsSurface()
  48.     hyperboloid.Transform(scale)
  49.  
  50.     return hyperboloid
  51.  
  52. if __name__=="__main__":
  53.     """
  54.     Generate and bake hyperboloid.
  55.     """
  56.     hyperboloid = get_hyperboloid(1, 2, 1, 6)
  57.     attributes = Rhino.DocObjects.ObjectAttributes()
  58.     scriptcontext.doc.Objects.AddSurface(hyperboloid, attributes)
  59.     scriptcontext.doc.Views.Redraw()

This code produces the hyperboloid below. It is a hyperboloid defined by only twenty-four control points, all weighted perfectly to give an absolutely precise hyperboloid. The geometry is lightweight, accurate, and splits cleanly with ruled lines. It has taken me a long time to get to this stage, but I finally feel like I understand – and can therefore control – the equations underlying software like Rhino. Hopefully this post has given you some insight into the underlying equations of CAD software and how they can be manipulated. And if not, hopefully you’ve at least learnt the many ways to draw a hyperboloid.

An accurate hyperboloid defined from just 24 control points.

An mathematically accurate hyperboloid defined from just 24 control points.

All code in this post licensed under Creative Commons attribution.

Share

Subscribe

Join the mailing list to receive an email whenever a new post comes out. Otherwise, you can follow me on Twitter, or add the RSS feed to your reader.

5 comments

  • Maher 18 September 2014 at 1:01 pm

    Loved the article! Well-explained and clearly written. Curious about what CATIA would generate. Did you run any tests?

    • Daniel 19 September 2014 at 2:41 am

      Hey Mahar, I haven’t done an explicit test but on occasion I have ended up in a situation where the Rhino model doesn’t quite match the CATIA model. This is to do with how I was modeling geometry in Rhino. CATIA has a lot of inbuilt checks and balances that ensures the integrity of the surfaces, so we haven’t experienced any accuracy problems in CATIA.

  • Nick Aplin 21 March 2015 at 4:23 pm

    I hope to make a planter in which to grow ‘enriched’ geraniums. what I imagine is one about 16 in. in diameter top and bottom and about 10 to 12 in. high with the minimum diameter being perhaps 14 in. (the shape to be a one sheeted hyperboloid)

    I hope to create a frame using small pieces of wood, around which to wrap fabric and then to use as a mould for possibly clay or plaster of paris …??

    Any suggestions will be appreciated …
    Thanks!

    • Daniel 22 March 2015 at 8:35 am

      Hey Nick, a while ago I cast some plaster hyperboloids. You can see the process here: http://www.danieldavis.com/responsive-acoustic-surfaces/ Basically, we cast the negative shape by spinning plaster and using a hyperbola template to shape it into a hyperboloid. We then cast the positive shape over the top of the negative to produce a hyperboloid shaped shell. Be warned however, it is a difficult shape to cast, we spent a few weeks learning how to do it!

  • ISHAN SHANKER VATS 24 October 2016 at 2:08 am

    We can draw the geometry of hyperbola in ANSYS APDL as well. All we need to have is the dimensions of the geometry, we know the equations. Generate the coordinates in excel,by feeding the equation and then import in ANSYS. Then from these plotted points we draw a spline. We copy this spline at distance equal to the desired thickness of the hyperboloid shell in order to make area and then we can extrude this area around a defined axis to create the hyperboloid geometry (volume).

Leave a comment