Clipping regions in generativepy


Martin McBride, 2020-10-04
Tags generativepy tutorial path
Categories generativepy generativepy tutorial

This tutorial covers the basics of using clipping regions in generativepy.

A clipping region defines the area of the page that you can draw on. If you draw a shape that is inside the clipping region, it will be visible, if you draw a shape that is outside the clipping region it will not be visible. If a shape is partly inside the clipping region, it will be clipped so that only the part that is inside the region is visible. This can create interesting effects, especially with a complex clipping region.

Clipping example code

Here is a sample Python program that creates two different clipping regions. The code is explained later in this article:

from generativepy.drawing import make_image, setup
from generativepy.color import Color
from generativepy.geometry import Circle, Square, Text
import math

def draw(ctx, width, height, frame_no, frame_count):
    setup(ctx, width, height, width=5, background=Color(0.8))

    # Create a circular clip region and draw some squares in it
    ctx.save()
    Circle(ctx).of_center_radius((1.9, 1.9), 1).clip()
    Square(ctx).of_corner_size((1, 1), .8).fill(Color('red'))
    Square(ctx).of_corner_size((1, 2), .8).fill(Color('green'))
    Square(ctx).of_corner_size((2, 1), .8).fill(Color('blue'))
    Square(ctx).of_corner_size((2, 2), .8).fill(Color('black'))
    ctx.restore()

    # Create a text clip region and fill it with circles
    ctx.save()
    Text(ctx).of("ABC", (1.5, 3.5))\
             .font("Times")\
             .size(1.5)\
             .align_left()\
             .align_top()\
             .clip()
    circles = [(2, 3.8, 'orange'), (2, 4.5, 'cyan'), (3, 3.8, 'green'),
               (3, 4.5, 'purple'), (4, 3.8, 'yellow'), (4, 4.5, 'blue')]
    for x, y, color in circles:
        Circle(ctx).of_center_radius((x, y), 0.7).fill(Color(color))
    ctx.restore()


make_image("clip-method.png", draw, 500, 500)

Here is the resulting image:

Circular clipping path

The first part of the code creates a circular clip region, and draws some squares inside it:

    ctx.save()
    Circle(ctx).of_center_radius((1.9, 1.9), 1).clip()
    Square(ctx).of_corner_size((1, 1), .8).fill(Color('red'))
    Square(ctx).of_corner_size((1, 2), .8).fill(Color('green'))
    Square(ctx).of_corner_size((2, 1), .8).fill(Color('blue'))
    Square(ctx).of_corner_size((2, 2), .8).fill(Color('black'))
    ctx.restore()

In this case, we have created a Circle in the usual way, but instead of filling or stroking the shape, we call clip. This sets the circle as the clip path. Only the parts of the image inside the circle can be marked.

We then draw 4 squares that are partly inside and partly outside the clip region. As you can see from the final image above each square is clipped to the shape of the circle.

Notice that we use ctx.save at the start of the code block. This stores the current state of the drawing context. This state includes the clip path, which initially includes the entire image.

After drawing the squares, we call ctx.restore, which restores the original drawing state. This has the effect of removing the clip path, so the whole page can be drawn on again. See useful context methods for more information about this.

Text clipping path

The second part of the code creates a complex clip region that takes teh shape of the text string "ABC" drawn in a lrge font. The code then draw some overlapping coloured circles. These are clipped to the text shape:

    ctx.save()
    Text(ctx).of("ABC", (1.5, 3.5))\
             .font("Times")\
             .size(1.5)\
             .align_left()\
             .align_top()\
             .clip()
    circles = [(2, 3.8, 'orange'), (2, 4.5, 'cyan'), (3, 3.8, 'green'),
               (3, 4.5, 'purple'), (4, 3.8, 'yellow'), (4, 4.5, 'blue')]
    for x, y, color in circles:
        Circle(ctx).of_center_radius((x, y), 0.7).fill(Color(color))
    ctx.restore()

Copyright (c) Axlesoft Ltd 2020