generativepy has moved to the pythoninformer.com website, and this page might not be up to date. Please visit the new location.
This tutorial covers the basics of using Path objects in generativepy.
Here is a sample Python program for creating various filled and outlined rectangles. The code is explained later in this article:
from generativepy.drawing import make_image, setup from generativepy.color import Color from generativepy.geometry import Path, Polygon, Text import math def draw(ctx, width, height, frame_no, frame_count): setup(ctx, width, height, width=5, background=Color(0.8)) # Get a polygon path object path1 = Polygon(ctx).of_points([(0, 0), (1, 1), (0.5, 2), (0.5, 1)])\ .path() # Get a text path object path2 = Text(ctx).of("Path text", (0, 0))\ .font("Times")\ .size(0.2)\ .align_left()\ .align_top()\ .path() # Apply the polygon in various places ctx.save() ctx.translate(0.5, 1) Path(ctx).of(path1).stroke(Color('darkgreen'), 0.1) ctx.restore() ctx.save() ctx.translate(1, 2.5) Path(ctx).of(path1).fill(Color('blue')) ctx.restore() ctx.save() ctx.translate(2.5, 0.5) ctx.scale(2, 2) Path(ctx).of(path1).fill(Color('orange')).stroke(Color('black'), 0.05) ctx.restore() # Apply the text in various places ctx.save() ctx.translate(0, 0) Path(ctx).of(path2).fill(Color('black')) ctx.restore() ctx.save() ctx.translate(2, 3) Path(ctx).of(path2).stroke(Color('red'), 0.01) ctx.restore() ctx.save() ctx.translate(2, 4) ctx.scale(2, 2) Path(ctx).of(path2).fill(Color('yellow')).stroke(Color('black'), 0.01) ctx.restore() make_image("path-method.png", draw, 600, 600)
Here is the resulting image:
The first part of the code creates a couple of paths. Here is the first:
path1 = Polygon(ctx).of_points([(0, 0), (1, 1), (0.5, 2), (0.5, 1)])\ .path()
In this case, we have created a Polygon
in the usual way, but instead of filling or stroking the shape, we call path
. This returns a Pycario path object. You can think of the path object as being like a set of instructions for drawing the shape.
This code doesn't actually draw anything, it just saves the drawing instructions in path1
.
Here is the second path:
path2 = Text(ctx).of("Path text", (0, 0))\ .font("Times")\ .size(0.2)\ .align_left()\ .align_top()\ .path()
This time we have created a complex path - some text. But the result is the same, we don't draw anything but the instructions for drawing the text are store in path2
.
Here is the code that actually draws path1
ctx.save() ctx.translate(0.5, 1) Path(ctx).of(path1).stroke(Color('darkgreen'), 0.1) ctx.restore() ctx.save() ctx.translate(1, 2.5) Path(ctx).of(path1).fill(Color('blue')) ctx.restore() ctx.save() ctx.translate(2.5, 0.5) ctx.scale(2, 2) Path(ctx).of(path1).fill(Color('orange')).stroke(Color('black'), 0.05) ctx.restore()
In the first section, we save the current context and then call translate
. This moves user space by (0.5, 1)
. See useful context methods for more information about this.
We then use a Path
object. This takes the drawing instructions in path1
, and adds them to the context ready to be drawn. We then stroke the shape in dark green. If you look at the definition of the polygon that is used to define path1
, you will see that the top left corner of the polygon is at (0, 0)
, but because we have tranlsted user space, the polygon actually gets drawn at (0.5, 1)
.
Finally we call restore
. This sets the context back to the state it was in when save
was called, so it effectively undoes the translate.
The second block draws the same shape again, this time at (1, 2.5)
, and it fills it rather than outlining it.
The third block draws the shape yet again, this time at (2.5, 0.5)
. In this case we also scale user space by (2, 2)
, which scales user space in the x and y directions. We fill and outline the shape, and because of the scaling the shape appears twice as big.
As we said before, restore
takes us back to the previous save
, so in this case it undoes the translate and the scale.
Here is the code that draws path2
ctx.save() ctx.translate(0, 0) Path(ctx).of(path2).fill(Color('black')) ctx.restore() ctx.save() ctx.translate(2, 3) Path(ctx).of(path2).stroke(Color('red'), 0.01) ctx.restore() ctx.save() ctx.translate(2, 4) ctx.scale(2, 2) Path(ctx).of(path2).fill(Color('yellow')).stroke(Color('black'), 0.01) ctx.restore()
This illustrates the use of complex paths. We draw the same text path filled, stroked, and also scaled, filled and stroked.
Copyright (c) Axlesoft Ltd 2020