Search⌘ K
AI Features

Circle and Curves

Explore how to draw arcs and complete circles with Pycairo's arc function, using radians for angle measurements. Learn to create versatile Bezier curves with control and anchor points, and combine curves and lines to form complex shapes.

We'll cover the following...

Arcs

An arc is a part of the circumference of a circle. The arc function is called like this: ctx.arc(cx,cy,r,a1,a2)

The following image shows how these parameters are used to draw an arc:

The arc is part of a circle, with radius r and centered at the point (cx, cy). It starts at angle a1 and ends at angle a2. Angles are measured from the x-axis and, by default, increase as we move clockwise. Here is an example of the code used to draw an arc:

Python 3.8
import cairo
import math
# Set up pycairo
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 600, 400)
ctx = cairo.Context(surface)
ctx.set_source_rgb(0.8, 0.8, 0.8)
ctx.paint()
# Draw an arc
ctx.arc(300, 200, 150, 0, math.pi/2)
ctx.set_source_rgb(1, 0, 0)
ctx.set_line_width(10)
ctx.stroke()

Angles in Python, as in most computer languages, are measured in radians rather than degrees. The pi radians are exactly 180 degrees. That makes 1 radian equal to approximately 57.3 degrees.

The code given above draws an arc of a circle, with its center located at (300, 200): The middle of the image. The circle radius is 150, and the arc goes from angle 0 to angle pi/2 radians, which is a quarter of a turn. Run the code to see how the image looks.

Circles

There is no function for drawing a circle. Instead, we use the arc function again. An arc from 0 to 2pi2*pi radians (which is equivalent to 360 degrees) forms a complete circle.

Here is how to draw a circle, with center (cx, cy) and radius r:

ctx.arc(cx,cy,r,0,2*math.pi)

Python 3.8
import cairo
import math
# Set up pycairo
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 600, 400)
ctx = cairo.Context(surface)
ctx.set_source_rgb(0.8, 0.8, 0.8)
ctx.paint()
# Small Circle
ctx.arc(300, 200, 50, 0, 2*math.pi)
ctx.set_source_rgb(0, 0, 0)
ctx.set_line_width(10)
ctx.stroke()
# Medium Circle
ctx.arc(300, 200, 100, 0, 2*math.pi)
ctx.set_source_rgb(1, 0, 1)
ctx.set_line_width(10)
ctx.stroke()
# Large Circle
ctx.arc(300, 200, 150, 0, 2*math.pi)
ctx.set_source_rgb(1, 1, 1)
ctx.set_line_width(10)
ctx.stroke()

Bezier curves

A Bezier curve is a versatile curve, which is used to create many different shapes. It is based on four points. The anchors, A and D, are the endpoints of the curve. The control points, B and C, control the route the curve takes between the anchors. Here is an example of a Bezier curve:

We will cover the properties of this curve in an upcoming chapter. For now, we will just observe how it works.

Here is the code used to draw a single Bezier curve:

Python 3.8
import cairo
# Set up pycairo
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 600, 400)
ctx = cairo.Context(surface)
ctx.set_source_rgb(0.8, 0.8, 0.8)
ctx.paint()
# Bezier curve
ctx.move_to(100, 200)
ctx.curve_to(200, 100, 400, 300, 500, 200)
ctx.set_source_rgb(1, 0, 0)
ctx.set_line_width(10)
ctx.stroke()

Let’s look at the code given above, in detail.

  • In the code, the move_to function sets the current point. The curve_to(xB, yB, xC, yC, xD, yD) function accepts six parameters. It treats the current point as the first anchor A. The six parameters represent the x, y values of the points B, C, and D.
  • After calling the curve_to function, the current point is set to the location of D, which is the end of the curve.

We can also join curves and lines together to form poly curves. Here, we join a curve, a line, another curve, and then close the path (creating another line) to form a shape:

Python 3.8
import cairo
# Set up pycairo
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 600, 400)
ctx = cairo.Context(surface)
ctx.set_source_rgb(0.8, 0.8, 0.8)
ctx.paint()
# Bezier curve
ctx.move_to(100, 100)
ctx.curve_to(200, 0, 400, 200, 500, 100)
ctx.line_to(500, 300)
ctx.curve_to(400, 400, 200, 200, 100, 300)
ctx.close_path()
ctx.set_source_rgb(1, 0, 0)
ctx.set_line_width(10)
ctx.stroke()