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.

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.

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)`

.

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.

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.

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.

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.

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.

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.

- 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.

- 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.

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

- *
(

`a`

:`number`

)`*`

(`b`

:`angle`

) →`angle`

Multiply an angle by the given scale factor.

(

`a`

:`angle`

)`*`

(`b`

:`number`

) →`angle`

Multiply an angle by the given scale factor.

(

`d1`

:`drawing`

)`*`

(`d2`

:`drawing`

) →`drawing`

Combine two drawings.

(

`set`

:`point set`

)`*`

(`drawing`

:`drawing`

) →`drawing`

Add a drawing modifier to a set of points.

(

`list`

:`list`

)`*`

(`drawing`

:`drawing`

) →`drawing`

Add a drawing modifier to a list of objects.

(anything)

`*`

(`drawing`

) →`drawing`

Add a drawing modifier to an object.

- +
- -
(

`point`

|`line`

|`point set`

|`circle`

|`conic`

|`drawing`

|`angle label`

|`list`

)`-`

(`vector`

) →`?`

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.

- ..
(

`a`

:`point`

)`..`

(`b`

:`point`

) →`point set`

A segment between two points.

(

`set`

:`point set`

)`..`

(`p`

:`point`

) →`point set`

Add a point to the end of a polygon.

(

`p`

:`point`

)`..`

(`set`

:`point set`

) →`point set`

Add a point to the start of a polygon.

(

`a`

:`point set`

)`..`

(`b`

:`point set`

) →`point set`

Concatenate two polygons.

(

`p1`

:`point`

)`..`

(`p2`

: drawing of`point`

) →`drawing`

A segment between two points.

(

`set`

:`point set`

)`..`

(`p`

: drawing of`point`

) →`drawing`

Add a point to the end of a polygon.

(

`p`

:`point`

)`..`

(`set`

: drawing of`point set`

) →`drawing`

Add a point to the start of a polygon.

- /
- altitude
- angle
`angle`

(`a`

:`point`

,`b`

:`point`

,`c`

:`point`

) →`angle label`

Draw an angle label.

- angle_between
- arc
- area
- argument
- barycenter
- bisector
- cardinality
- center
- circle
- color
- conic
- deg
- degrees
- description
- distance
- divergent_color_scheme
- divergent_color_schemes
- draggable
- eccentricity
- 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
- foci
- font
- group
- homothetic
`homothetic`

(`p`

:`point`

,`origin`

:`point`

,`k`

:`number`

) →`point`

Homothecy (reduction or dilation) of the first point with respect to the second, and the given scale.

`homothetic`

(`line`

:`line`

,`origin`

:`point`

,`k`

:`number`

) →`line`

Homothecy (reduction or dilation) of a line with respect to the given point and scale factor.

`homothetic`

(`conic`

:`conic`

,`origin`

:`point`

,`k`

:`number`

) →`conic`

Homothecy (reduction or dilation) of a conic with respect to the given point and scaling factor.

- hsl
- hsla
- hyperbola
- incircle
- intersection
`intersection`

(`l1`

:`line`

,`l2`

:`line`

) →`point`

The intersection point of two lines.

`intersection`

(`l`

:`line`

,`set`

:`point set`

) →`point set`

All points at which the line intersects the perimeter of the given point set.

`intersection`

(`l`

:`line`

,`c`

:`circle`

) →`point set`

All points at which the line intersects the given circle.

`intersection`

(`l`

:`line`

,`c`

:`conic`

) →`point set`

All points at which the tline intersects the given conic.

`intersection`

(`s1`

:`point set`

,`s2`

:`point set`

) →`point set`

All points at which the perimeters of the two point sets intersect.

`intersection`

(`c1`

:`circle`

,`c2`

:`circle`

) →`point set`

The points of intersection of the two circles.

`intersection`

(`s`

:`point set`

,`c`

:`circle`

) →`point set`

All points of intersection of the perimeter of the point set with the given circle.

- isobarycenter
- isosceles
`isosceles`

(`p1`

:`point`

,`p1`

:`point`

,`l2`

:`number`

|`a1`

:`angle`

) →`list`

`isosceles`

([`p1`

:`point`

], [`p2`

:`point`

], [`l1`

:`number`

,`l2`

:`number`

|`a1`

:`angle`

, [`orientation`

:`angle`

]]) →`list`

Create an isosceles triangle from the given points. Can give up to two vertices; one other length or angle; and the orientation of the first side if fewer than two vertices given.

- label
- line
- list
- major
- median
- midpoint
- minor
- opacity
- orthocenter
- parabola
- parallel
- parallelogram
`parallelogram`

(`p1`

:`point`

,`p2`

:`point`

,`p3`

:`point`

) →`list`

`parallelogram`

(`p1`

:`point`

,`p2`

:`point`

, [`l2`

:`number`

,`a1`

:`angle`

]) →`list`

`parallelogram`

([`p1`

:`point`

], [`l1`

:`number`

,`l2`

:`number`

,`a1`

:`angle`

, [`orientation`

:`angle`

]]) →`list`

Create a parallelogram from the given points. Can give up to three vertices. If fewer than two vertices given, must give the length of the first side, one more side and an angle, and optionally the orientation of the first side.

- perimeter
- perpendicular
- perpendicular_bisector
- point
`point`

(`x`

:`number`

,`y`

:`number`

) →`point`

A point at the given coordinates.

`point`

(`r`

:`number`

,`a`

:`angle`

) →`point`

A point at the given polar coordinates.

`point`

(`set`

:`point set`

,`t`

:`number`

) →`point`

A point along the first edge of the given polygon.

`point`

(`line`

:`line`

,`t`

:`number`

) →`point`

A point on the given line, the given distance away from its origin.

`point`

(`circle`

:`circle`

,`a`

:`angle`

) →`point`

A point on the given circle at the given angle.

`point`

(`conic`

:`conic`

,`t`

:`number`

) →`point`

A point with the given argument on the given conic.

- point_with_abscissa
- point_with_ordinate
- polygon
- projection
- qualitative_color_scheme
- qualitative_color_schemes
- rad
- rectangle
`rectangle`

(`p1`

:`point`

,`p2`

:`point`

, [`l2`

:`number`

]) →`list`

`rectangle`

([`p1`

:`point`

], [`l1`

:`number`

,`l2`

:`number`

, [`orientation`

:`angle`

]]) →`list`

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

- reflect
- rgb
- rgba
- right
`right`

(`p1`

:`point`

,`p2`

:`point`

, [`l2`

:`number`

|`a1`

:`angle`

], [`orientation`

:`angle`

]) →`list`

`right`

([`p1`

:`point`

], [`p2`

:`point`

], [`l1`

:`number`

, [`l2`

:`number`

|`a1`

:`angle`

], [`orientation`

:`angle`

]]) →`list`

Create a right-angled triangle from the given parameters. Can give up to two vertices; one other length or angle; and the orientation of the first side if fewer than two vertices given.

- rotate
`rotate`

(`p`

:`point`

,`origin`

:`point`

,`angle`

:`angle`

) →`point`

Rotate the first point the given angle around the second.

`rotate`

(`v`

:`vector`

,`a`

:`angle`

) →`vector`

Rotate a vector by the given angle.

`rotate`

(`line`

:`line`

,`origin`

:`point`

,`angle`

:`angle`

) →`line`

Rotate a line by the given angle around the given point.

`rotate`

(`set`

:`point set`

,`origin`

:`point`

,`a`

:`angle`

) →`point set`

Rotation of a polygon by the given angle around the given point.

`rotate`

(`conic`

:`conic`

,`origin`

:`point`

,`a`

:`angle`

) →`conic`

Rotate a conic by the given angle around the given point.

- segment
- sequential_color_scheme
- sequential_color_schemes
- size
- square
- symmetric
`symmetric`

(`p`

:`point`

,`origin`

:`point`

) →`point`

180° rotation of the first point around the second.

`symmetric`

(`line`

:`line`

,`p`

:`point`

) →`line`

180° degree rotation of a line around the given point.

`symmetric`

(`set`

:`point set`

,`p`

:`point`

) →`point set`

180° degree rotation of the given polygon around the given point.

`symmetric`

(`conic`

:`conic`

,`p`

:`point`

) →`conic`

180° rotation of the given conic around the given point.

- tangent
- text
- triangle
`triangle`

(`p1`

:`point`

,`p2`

:`point`

, [`l2`

:`number`

|`a2`

:`angle`

]) →`list`

`triangle`

(`p1`

:`point`

, [`l1`

:`number`

, [[`l2`

:`number`

|`a2`

:`angle`

]]], [`orientation`

:`angle`

]) →`list`

`triangle`

([`l1`

:`number`

, [[`l2`

:`number`

|`a2`

:`angle`

], [`l3`

:`number`

|`a3`

:`angle`

]]], [`orientation`

:`angle`

]) →`list`

Create a triangle from the given parameters. Can give up to two vertices; any remaining lengths or angles; and the orientation of the first side if fewer than two vertices given.

- vector
- x
- y