AngleMarker

By Martin McBride, 2022-01-18
Tags: geometry angle
Categories: generativepy generative art


The AngleMarker class is a special Shape that draws an angle marker. Angle markers look like this:

An AngleMarker can have 1, 2 or 3 arcs. The 2 and 3 arc forms are often used to indicate that two angles are equal. You can also draw a right angle marker, as shown.

The AngleMarker only draws the arcs, it doesn't draw the lines that make up the angle. These would normally be draw using a Line object, Polygon object, or similar.

AngleMarker class

AngleMarker is derived from the Shape class. It adds several methods:

  • of_points
  • with_radius
  • with_count
  • with_gap
  • as_right_angle

of_points

Creates a marker based on a 3 points.

of_points(a, b, c)
Parameter Type Description
a (number, number) Tuple (x, y) for point a
b (number, number) Tuple (x, y) for point b
c (number, number) Tuple (x, y) for point c

This will draw an angle marker for the angle formed by abc. The angle will be start at the line ab and be drawn in a clockwise direction to the line cb, with point b as the centre of the angle.

with_radius

Sets the radius of the arc.

with_radius(radius)
Parameter Type Description
radius number Radius of arc in user units.

The default is 8.

with_count

Sets the number of arcs in the marker.

with_count(count)
Parameter Type Description
count int Number of arcs

This can be used to draw a single, double, or triple arc. Permitted values are 1, 2, or 3. Default is 1.

with_gap

Sets the gap between the arcs if count > 1.

with_gap(gap)
Parameter Type Description
gap number Gap between arcs in user units.

Sets the spacing of the arcs. This is only relevant if there is more than one arc (ie if count > 1), otherwise it is ignored.The default is 2.

For double of triple arcs, the set of arcs is centred on the requested radius. So for example if radius is 8 and gap is 2, and 3 arcs are specified, the arcs will have radii of 6, 8, and 10.

as_right_angle

Marks the angle as a right angle.

as_right_angle(right_angle=True)
Parameter Type Description
right_angle Bool Draws the angle as a right angle.

The controls whether the angle should be drawn as a normal arc, or as a right angle symbol.

AngleMarker defaults to normal angle, so:

  • AngleMarker with no call to as_right_angle() will draw a normal angle.
  • AngleMarker with a call to as_right_angle() with no parameters will draw a right angle.
  • AngleMarker with a call to as_right_angle(value) will be controlled by value.

Note that is a right angle is selected, the marker will attempt to draw a right angle symbol even if the angle isn't actually 90 degrees. This will create a strange effect. Only choose the right angle option if the angle is actually close to 90 degrees.

angle_marker function

This older angle_marker function is deprecated as of GenerativePy 3.1.

angle_marker(ctx, a, b, c, count=1, radius=8, gap=2, right_angle=False)
Parameter Type Description
ctx Context The Pycairo Context to draw to
a (number, number) Tuple (x, y) for point a
b (number, number) Tuple (x, y) for point b
c (number, number) Tuple (x, y) for point c
count int Number of arcs on angle, 1, 2 or 3.
with_radius number Radius of arc in user units.
gap number Gap between arcs in user units.
right_angle boolean True for a right angle.

Draws an angle arc for the angle abc. The arc is centred on point b, and shows the angle between lines ab and cb in the clockwise direction.

If you are using a flipped coordinate system (see the setup function in the drawing module), the angle is drawn in the counterclockwise direction.

count allows you to draw double or triple arcs to indicate different pairs of equal angles. If count is not 1, gap sets the distance between the arcs - typically a value that is about twice the line thickness usually looks best.

right_angle can be set to true to draw a right angle marker rather than an arc. In that case, count is ignored.

Note that it is up to your code do ensure that the angle actually is a right angle before setting this. If you set this flag when the angle isn't a right angle (or very close), you will get strange looking result. If you don't set this flag when the angle is a right angle, a normal angle arc will be drawn. This is to avoid spurious effects in animations if a changing angle happens to be exactly 90 degrees in one frame/

Example

Here is an example that shows the angle_marker, tick and paratick functions in use:

from generativepy.drawing import make_image, setup
from generativepy.color import Color
from generativepy.geometry import line, polygon, angle_marker, tick, paratick

'''
Create rectangles using the geometry module.
'''

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

    ctx.set_source_rgba(*Color(0, 0, 0.5))
    ctx.set_line_width(3)

    ## Draw lines with ticks and paraticks
    a = (50, 50)
    b = (50, 150)
    line(ctx, a, b)
    ctx.stroke()
    tick(ctx, a, b, length=12, gap=6)
    ctx.stroke()

    a = (100, 50)
    b = (150, 150)
    line(ctx, a, b)
    ctx.stroke()
    tick(ctx, a, b, 2, length=12, gap=6)
    ctx.stroke()

    a = (250, 50)
    b = (200, 150)
    line(ctx, a, b)
    ctx.stroke()
    tick(ctx, a, b, 3, length=12, gap=6)
    ctx.stroke()

    a = (350, 50)
    b = (350, 150)
    line(ctx, a, b)
    ctx.stroke()
    paratick(ctx, a, b, length=12, gap=6)
    ctx.stroke()

    a = (400, 50)
    b = (450, 150)
    line(ctx, a, b)
    ctx.stroke()
    paratick(ctx, a, b, 2, length=12, gap=6)
    ctx.stroke()

    a = (550, 150)
    b = (500, 50)
    line(ctx, a, b)
    ctx.stroke()
    paratick(ctx, a, b, 3, length=12, gap=6)
    ctx.stroke()

    ## Draw lines with angles
    a = (50, 250)
    b = (50, 450)
    c = (150, 450)
    polygon(ctx, (a, b, c), closed=False)
    ctx.stroke()
    angle_marker(ctx, a, b, c, radius=24, gap=6, right_angle=True)
    ctx.stroke()

    a = (250, 250)
    b = (200, 450)
    c = (300, 450)
    polygon(ctx, (a, b, c), closed=False)
    ctx.stroke()
    angle_marker(ctx, a, b, c, 3, radius=24, gap=6)
    ctx.stroke()

    a = (300, 250)
    b = (400, 300)
    c = (500, 300)
    polygon(ctx, (a, b, c), closed=False)
    ctx.stroke()
    angle_marker(ctx, c, b, a, radius=24, gap=6)
    ctx.stroke()

    a = (300, 350)
    b = (400, 400)
    c = (500, 400)
    polygon(ctx, (a, b, c), closed=False)
    ctx.stroke()
    angle_marker(ctx, a, b, c, 2, radius=24, gap=6)
    ctx.stroke()

make_image("/tmp/geometry-markers.png", draw, 600, 500)

See also

If you found this article useful, you might be interested in the book NumPy Recipes or other books by the same author.

Join the PythonInformer Newsletter

Sign up using this form to receive an email when new content is added:

Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop formula function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function latex len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart pil pillow polygon pong positional parameter print product programming paradigms programming techniques pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template tex text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip zip_longest