# Numbas Eukleides extension

This extension is a port of the Eukleides geometrical drawing language into Numbas’ JME system. In order to be compatible with JME, this version occasionally works differently to the original Eukleides language. The basic flow of constructing points and then drawing them has been retained, but some of the syntax is different.

## Basic concepts

The function `eukleides` creates a diagram which you can include anywhere in a Numbas question.

A diagram consists of a list of objects, drawn into a frame which is shown on screen. The boundaries of the frame are automatically determined, or you can give explicit values.

The basic objects in a diagram are:

• point
• point set (rendered as a line segment or a polygon, depending on the number of points)
• line
• circle
• conic (parabola, hyperbola or ellipse)
• text label
• angle label

Drawing modifiers change how an object is drawn, for example changing the colour or size. Modifiers can be applied to single objects, lists of objects, or even chained together to create reusable styles.

## Coordinates

All coordinates in Eukleides diagrams are specified in terms of the frame and then transformed onto the browser’s coordinates. The bottom-left of the diagram has coordinates `(min_x,min_y)` and the top-right of the diagram has coordinates `(max_x,max_y)`. The positive horizontal direction is right, and the positive vertical direction is up.

Angles are measured anti-clockwise. The bearing 0 points right. Angles can be given in radians, e.g. `rad(pi/4)`, or degrees, e.g. `degrees(45)`.

## Accessibility

It’s important that diagrams are accessible to as many people as possible. The Eukleides extension provides a variety of ways of doing this. It tries to do as much as it can automatically to improve accessibility, but you should bear accessibility in mind when designing diagrams.

### Screenreaders

Users who can’t see the diagram might access it through a screenreader.

The first argument to the `eukleides` function is a title for the diagram, which a screenreader will read out. This title should briefly identify the diagram and describe its contents, for example, “A circle inscribed in a square”, or “Bar chart showing number of customers against month”.

The Web Accessibility Initiative has a good tutorial on describing complex images.

The user can then navigate inside the diagram to have individual objects described.

Eukleides automatically adds a text description to each object in the diagram. At minimum, this is just the name of the object, for example ‘line’ or ‘circle’. If the object is defined in terms of points which have been labelled, those will be used: “triangle through A, B, C” for example.

The object’s colour and drawing style will also be described, for example “gray dotted line segment through A, B”.

The text descriptions are designed not to reveal any information which is not visually obvious. If you add the `verbose` modifier to an object, information such as coordinates and angles will be used to provide a more precise description of the object.

While these descriptions can give a rough idea of the contents of a diagram, information such as relative positions or implicit meanings of objects will be missing. You can manually set the description for an object with the `description` function. For example, a circle inscribed in a square will just be described as “circle”; “circle inscribed in square A B C D” would be a more helpful description.

### Colours

Eukleides provides a variety of colour schemes which have been designed to maximise accessibility, considering colour vision deficiency and other vision impairments. Most of these colour schemes are drawn from ColorBrewer.

The variables `color1` to `color6` are assigned to a set of colours which should be easily distinguishable by almost all sighted people, including those with colour vision deficiency.

The functions `qualitative_color_scheme`, `sequential_color_scheme` and `divergent_color_scheme` return lists of colours designed for different uses:

• A qualitative colour scheme is suitable for objects belonging to different categories.
• A sequential colour scheme is suitable for objects which can be mapped onto some linear scale.
• A divergent colour scheme is suitable for objects which can be mapped onto a scale with a “medium” and two different end points.

You can select other colours with the `color()` modifier, which accepts any colour specification accepted by CSS, such as hexadecimal format, RGB or HSL. You should not use other colours without considering contrast and CVD. The WebAIM link constrast checker is a good first port of call to check whether a pair of colours can be easily distinguished against each other and the background.

It’s a good idea to use aspects other than colour, such as the `dotted` and `dashed` modifiers, to distinguish objects.

## Animation and interactivity

Eukleides diagrams can be made dynamic in several ways.

The variable `time` represents the number of seconds since the diagram was created. Diagrams which contain references to `time` are continually redrawn with updated values for `time`.

The variables `mousex` and `mousey` represent the position of the mouse cursor, or the position of the last touch on touchscreen devices, in diagram coordinates. When the mouse moves, the diagram is redrawn with update values of these variables.

A point on the diagram can be made draggable by applying the modifier `draggable()` to it when drawing it. Any other free variables in the diagram are interpreted as free parameters, and given the initial value of `0`. You can explicitly give initial values for free variables in a dictionary as the last argument to the `eukleides` function.

When the user moves a draggable point, the system tries to position it as close as possible to the mouse by changing the values of the free variables. It does this by repeatedly picking values for the variables, redrawing the diagram, and measuring the distance between the drawn point and the cursor. A gradient descent algorithm homes in on the best solution within a few iterations.

The great advantage of this system is that you don’t need to explicitly provide a mapping between target coordinates and the free variables in your diagram. The algorithm will find a solution, even if the position of the dragged point is calculated indirectly.

Note: The solver algorithm assumes that draggable points move continuously, so will fail if the point’s position can only take discrete values. A workaround is to have a draggable point which can move continuously, and a second non-interactive point which takes the position you really want.

By default, moving a draggable point can affect any of the free variables in a diagram. You can give the `draggable` function an optional list of variable names that it’s allowed to affect.

## How to construct a diagram

The basic template for a Eukleides diagram is the following:

``````eukleides("A diagram",[
point(1,0)
, point(1,1) .. point(4,0)
])
``````

The first argument of the `eukleides` function is a title, and the second argument is a list of objects to draw.

The great power of Eukleides lies in its ability to construct geometrical objects from other objects. In order to achieve this, use the `let` function to temporarily assign names to objects so you can refer back to them:

``````eukleides("A triangle",
let(
a, point(1,0)
, b, point(3,1)
, c, point(2,3)
, [
a..b..c filled color1
, a..b..c
]
)
)
``````

The example above constructs three points, draws a filled triangle with those vertices, and then draws its outline.

There are several functions which construct common polygons, given a mixture of points and side lengths or angles.

``````eukleides("A right-angled triangle",
let(
[a,b,c], right(2,3)
, [
a..b..c
, a,b,c
]
)
)
``````

The example above constructs a right-angled triangle with side lengths 2 and 3. The function `right` returns a set of points, which are assigned the names `a`, `b` and `c`. We then draw the outline of the triangle, and dots at each of the points.

Note that constructing an object doesn’t mean it’s automatically drawn. The second argument of `eukleides` evaluates to a list of objects to be drawn - you can draw objects more than once, in different styles, or not at all.

You can use vectors to translate any object in a diagram.

``````eukleides("A diagram",
let(
u, vector(1,0)
, v, vector(1,2)
, a, point(0,0)
, [
a, a+u, a+v, (a+u..a..a+v) open
]
)
)
``````

The example above translates the point `a` by two different vectors.

When you repeat a construction, you can often make your code easier to read by using the `map` function:

``````eukleides("A diagram",
let(
u, vector(1,0)
, v, vector(1,2)
, a, point(0,0)
, b, point(4,2)
, c, point(-1,3)
, map(
[x, x+u, x+v, (x+u..x..x+v) open]
, x
, [a,b,c]
)
)
)
``````

Drawing modifiers change aspects of how objects are drawn, such as colour or shading style. When drawing an object, just write the modifier immediately afterwards to apply it. A modified object becomes a `drawing` data type, which collects up the object(s) being drawn with the modifiers, so you can’t use the result in further constructions. To minimise the inconvenience, we try to apply modifiers last: for example, `(origin red) .. point(2,0)` doesn’t work, but `origin .. point(2,0) red` does - the line segment is constructed before the `red` modifier is applied.

## Use in Numbas

To include a Eukleides diagram in a Numbas question, first enable the Eukleides extension. Then, create a variable whose definition is the code for your diagram, i.e. `eukleides(title,objects)`. In the following, suppose the variable is called `diagram`.

To show the diagram to the student, type `{diagram}` in a content area, such as the question statement, a part prompt, or the advice. The diagram will be inserted into the content at this point.

The definition of your diagram can refer to other question variables, but any values set interactively by the diagram (all free variable names in the diagram’s definition) can’t be used by other question variables - the values of question variables are only evaluated once, when the question is created.

## Reference

### Data Types

angle
An angle. The positive direction is anti-clockwise, and 0 points right.
point
A single point.
line
An infinite line.
point set
An ordered list of points, interpreted as a line segment, an outline, or a polygon, depending on context.
circle
A circle, defined by its centre point and radius.
conic
A conic curve: an ellipse, hyperbola or parabola.
drawing
A collection of drawing modifiers, applied to a list of objects.
angle label
A curve showing the angle defined by three points.

### Drawing modifiers

Colours: black, color1, color2, color3, color4, color5, color6, darkgray, gray, lightgray, white

arrow
Draw an arrow on line segments and angle labels, in the direction specified by `forth` or `back`.
arrows
Draw arrows on both ends of line segments and angle labels.
back
When `half` is applied, draw lines and curves in the backward direction. Arrows on line segments are drawn on the first point. Arrows on angle labels are drawn pointing clockwise.
bold
Text is drawn in boldface.
box
Points are drawn as solid squares.
closed
Point sets are drawn as closed polygons - the last point is joined to the first.
cross
Points are drawn as x shapes.
dashed
Lines are drawn with a dashed pattern, and filled shapes are drawn with stripes.
disc
Points are drawn as hollow discs.
dot
Points are drawn as solid dots.
dotted
Lines and filled shapes are drawn with a dotted pattern.
double
Segments and angle labels are marked with a double dash. If `dotted` is also applied, angle labels will instead be labelled with two dots.
entire
Draw lines and conics as far as possible in both directions.
filled
Point sets are drawn as filled polygons.
forth
When `half` is applied, draw lines and curves in the forward direction. Arrows on line segments are drawn on the last point. Arrows on angle labels are drawn pointing anti-clockwise.
full
Lines are drawn as continuous lines. This is the default.
half
Only draw lines and curves in the direction specified. The default is forwards.
italic
Text is drawn in italic style.
noarrow
Do not draw an arrow on segments or angle labels. This is the default.
nospoilers
Accessible descriptions will not give any information not explicitly given in the visual rendering.
open
Point sets are drawn as open paths.
origin
The point at coordinates (0,0).
plus
Points are drawn as + shapes.
right
Draw angle labels as right angles.
simple
Segments and angle labels are marked with a single dash.
transparent
Set the opacity to 0.5.
triple
Segments and angle labels are marked with a triple dash. If `dotted` is also applied, angle labels will instead be labelled with three dots.
verbose
Accessible descriptions give information not explicitly given in the visual rendering, such as coordinates and bearings.

### Functions

*
+
• Translate an object or list of objects by the given vector.

• (`a`: `angle`) `+` (`b`: `angle`)`angle`

Add two angles.

-
• Translate an object or list of objects by the opposite of the given vector.

• (`a`: `angle`) `-` (`b`: `angle`)`angle`

Subtract two angles.

• (`a`: `point`) `-` (`b`: `point`)`vector`

Vector from the second point's position to the first's.

• - `n`: `angle``angle`

Flip the direction of the given angle.

..
/
altitude
angle
angle_between
arc
area
argument
• `argument` (`v`: `vector`)`angle`

Direction of the given vector.

• `argument` (`line`: `line`)`angle`

Direction angle of the given line.

• `argument` (`conic`: `conic`)`angle`

The direction of the given conic.

• `argument` (`conic`: `conic`, `p`: `point`)`angle`

Polar angle of the given point with respect to the center of the given conic.

barycenter
bisector
cardinality
• `cardinality` (`set`: `point set`)`number`

Number of vertices in the given polygon.

center
• `center` (`set`: `point set`)`point`

The isobarycenter (centre of gravity) of the given polygon.

• `center` (`circle`: `circle`)`point`

The center of the given circle.

• `center` (`conic`: `conic`)`point`

The center of the given conic.

circle
color
• `color` (`color`: `string`)`drawing`

Set the fill or stroke colour.

conic
deg
• `deg` (`degrees`: `number`)`angle`

Construct an angle in degrees.

degrees
• `degrees` (`v`: `angle`)`number`

Convert an angle to a number of degrees.

description
• `description` (`description`: `string`)`drawing`

Set the accessible description for the object being drawn.

distance
divergent_color_scheme
• `divergent_color_scheme` (`n`: `integer`)`list`

Get a list of colours for a divergent data set.

divergent_color_schemes
• `divergent_color_schemes` (`n`: `integer`)`list`

Get a list of colour schemesfor a divergent data set.

draggable
eccentricity
• `eccentricity` (`conic`: `conic`)`number`

The eccentricity of the given conic.

ellipse
equilateral
• `equilateral` (`p1`: `point`, `p2`: `point`)`list`

`equilateral` ([`p1`: `point`], `l1`: `number`, [`orientation`: `angle`])`list`

Create an equilateral triangle from the given points. Can give up two two vertices; if fewer than two vertices are given must give the length of the first side and optionally the orientation of the first side.

eukleides
• Draw a Eukleides diagram.

foci
• `foci` (`conic`: `conic`)`list`

The foci of the given conic.

font
• `font` (`font`: `string`)`drawing`

Set the font.

group
homothetic
hsl
hsla
hyperbola
incircle
intersection
isobarycenter
• `isobarycenter` (`set`: `point set`)`point`

The isobarycenter (centre of gravity) of the given polygon.

isosceles
label
line
list
• `list` (`ps`: `point set`)`list`

Convert a set of points to a list of points.

major
• `major` (`conic`: `conic`)`number`

The major axis of the given conic.

median
midpoint
• `midpoint` (`set`: `point set`)`point`

The midpoint of the given segment.

minor
• `minor` (`conic`: `conic`)`number`

The minor axis of the given conic.

opacity
• `opacity` (`opacity`: `number`)`drawing`

Set the opacity. 0 is invisible and 1 is solid.

orthocenter
parabola
parallel
parallelogram
perimeter
• `perimeter` (`set`: `point set`)`number`

Total length of the given polygon's edges.

perpendicular
• `perpendicular` (`line`: `line`, `p`: `point`)`line`

A line perpendicular to the given line and containing the given point.

• `perpendicular` (`set`: `point set`, `p`: `point`)`line`

A line perpendicular to the given segment and containing the given point.

perpendicular_bisector
• `perpendicular_bisector` (`set`: `point set`)`line`

The perpendicular bisector of the given segment.

point
point_with_abscissa
• `point_with_abscissa` (`line`: `line`, `x`: `number`)`point`

A point on the given line with the given abscissa, with respect to the implicit coordinate system.

point_with_ordinate
• `point_with_ordinate` (`line`: `line`, `y`: `number`)`point`

A point on the given line with the given ordinate, with respect to the implicit coordinate system.

polygon
• `polygon` (`points`: `list` of multiple `point`)`point set`

Construct a polygon from the given list of points.

• `polygon` (`n`: `number`, `origin`: `point`, `r`: `number`, `a`: `angle`)`point set`

A regular polygon with the given number of sides and circumradius, with center at the given point and rotated by the given angle.

projection
qualitative_color_scheme
• `qualitative_color_scheme` (`n`: `integer`)`list`

Get a list of colours for a qualitative data set.

qualitative_color_schemes
• `qualitative_color_schemes` (`n`: `integer`)`list`

Get a list of colour schemes for a qualitative data set.

rad
• `rad` (`radians`: `number`)`angle`

Construct an angle in radians.

rectangle
reflect
rgb
rgba
right
rotate
segment
sequential_color_scheme
• `sequential_color_scheme` (`n`: `integer`)`list`

Get a list of colours for a sequential data set.

sequential_color_schemes
• `sequential_color_schemes` (`n`: `integer`)`list`

Get a list of colour schemes for a sequential data set.

size
• `size` (`size`: `number`)`drawing`

Set the size and stroke width.

square
• `square` (`p1`: `point`, `p2`: `point`)`list`

`square` ([`p1`: `point`], [`l`: `number`, [`orientation`: `angle`]])`list`

Create a square from the given points. Can give up to two vertices. If fewer than two vertices given, must give the length of the first side and can optionally give the orientation of the first side.

symmetric
tangent
text
• `text` (`text`: `string`)`drawing`

Draw text at a point.

triangle
vector
• `vector` (`set`: `point set`)`vector`

Vector from the first point of the polygon to the second.

• `vector` (`line`: `line`)`vector`

Unit vector in the direction of the given line.

x
• `x` (`p`: `point`)`number`

x coordinate of a point.

y
• `y` (`p`: `point`)`number`

y coordinate of a point.