# Symmetry Operations

How do you make two copies of a shape that are mirror images of each other, or three copies rotated 120° around a point? If the shapes are not random then it is straight forward. If the shapes are random then each copy will be different. Symmetry operations allow exact duplication of the design with various translation, rotation, and reflection symmetry operations applied.

## All or Nothing

The symmetry operations are applied to the whole design. Whatever is specified by your startshape will get the symmetry operations applied to it. But why not allow shape rules to specify symmetry operations for individual shape replacements? Because this would violate the context-free purity of Context Free/cfdg. There is no context-free grammar with separate parts that are random but identical. We get around this with symmetry operations by applying them to the entire design after the grammar is 'executed'. This is the same post-processing hack that is done with tiled rendering.

That said, there is still wiggle room if the design is explicitly impure (CF::Impure = 1). The clone statement allows designs to have localized symmetry.

# Two Dimensional Symmetry Operations

In two dimensions there are two symmetry operations: cyclic and dihedral. Cyclic symmetry is simply rotational symmetry, the design is rotated around a point. Dihedral symmetry adds mirror symmetry, so the design and its reflection are rotated around a point.

# One Dimensional Symmetry Operations

If your design has frieze symmetry then you can specify Frieze group symmetry: p11g, p11m, p1m1, p2, p2mg, and p2mm. Umm… just go click that Wikipedia link to find out what those mean.

# Specifying Symmetry Operations

Symmetry operations are enabled by adding a CF::Symmetry configuration declaration and assigning it a list of symmetry specifications:

``````CF::Symmetry = CF::Dihedral, 6   // snowflake symmetry
``````

A symmetry specification starts with the symmetry token (e.g., CF::Dihedral) followed by one or more configuration numbers, all separated by commas. There can be many symmetry specifications in the list, each separated by a comma. A shape adjustment can also be a symmetry specification.

#### Cyclic symmetry

Cyclic symmetry is specified with CF::Cyclic, followed the order and an optional center of rotation (one or three numbers). The order must be ≥1.

``````CF::Symmetry = CF::Cyclic, 4  // four-fold rotation symmetry
CF::Symmetry = CF::Cyclic, 4, 2, 1  // four-fold rotation symmetry around the point (2,1)
``````
##### Non-Integer Order

The order of cyclic symmetry need not be an integer. If the order is not an integer then it will be rounded down to determine how many copies of the design to draw. But the angle between them will be determined by the full value, not the rounded value. So if the order is 3.5 then 3 copies will be drawn at an angle of 360°/3.5=102.86°.

Be very careful with using an expression for symmetry order. If you intend to have four-fold symmetry but your order expression is 3.999999 then you will get 3 copies 89.99999° apart. If your symmetry order is supposed to be an integer but it is not an integer constant then it is a good idea to round it to the nearest integer using the floor() function.

#### Dihedral Symmetry

Dihedral symmetry is specified with CF::Dihedral, followed the order, an optional mirror angle and an optional center of rotation (one, two, three, or four numbers). The order must be ≥1 and also need not be an integer.

``````CF::Symmetry = CF::Dihedral, 4  // four-fold dihedral symmetry
CF::Symmetry = CF::Dihedral, 4, 2, 1  // four-fold dihedral symmetry around the point (2,1)
CF::Symmetry = CF::Dihedral, 4, 30  // four-fold dihedral symmetry, mirror angle at 30deg
CF::Symmetry = CF::Dihedral, 4, 2, 1, 30  // four-fold dihedral symmetry around the point (2,1), mirror angle at 30deg
``````

## Frieze Group Symmetry

#### CF::p11g, axis position — Step Symmetry

p11g symmetry is specified with CF::p11g, followed by the vertical or horizontal glide reflection axis position (one number). If the frieze symmetry is horizontal then the glide reflection axis is horizontal. Otherwise it is vertical. The axis position parameter is optional and defaults to 0.

``````CF::Symmetry = CF::p11g, 0  // step symmetry with the mirror across the line y=0
``````

p11g

#### CF::p11m, axis position — Jump Symmetry

p11m symmetry is specified with CF::p11m, followed by the vertical or horizontal mirror axis position (one number). If the frieze symmetry is horizontal then the mirror axis is horizontal. Otherwise it is vertical. The axis position parameter is optional and defaults to 0.

``````CF::Symmetry = CF::p11m, 0  // jump symmetry with the mirror across the line y=0
``````

p11m

#### CF::p1m1, axis position — Sidle Symmetry

p1m1 symmetry is specified with CF::p1m1, followed by the vertical or horizontal mirror axis position (one number). If the frieze symmetry is horizontal then the mirror axis is vertical. Otherwise it is horizontal. The axis position parameter is optional and defaults to 0.

``````CF::Symmetry = CF::p1m1, 0  // sidle symmetry with the mirror across the line x=0
``````

p1m1

#### CF::p2, centre_x, centre_y — Spinning Hop Symmetry

p2 symmetry is specified with CF::p2, followed by the center of 180° rotation (two numbers). The centre parameters are optional and default to (0,0).

``````CF::Symmetry = CF::p2, 0, 1  // spinning hop symmetry with the mirror around the point (0,1)
``````

p2

#### CF::p2mg, centre_x, centre_y — Spinning Sidle Symmetry

p2mg symmetry is specified with CF::p2mg, followed by the center of 180° rotation (two numbers). If the frieze symmetry is horizontal then the glide reflection axis is horizontal. Otherwise it is vertical. The centre parameters are optional and default to (0,0).

``````CF::Symmetry = CF::p2mg, 0, 1  // spinning sidle symmetry with the mirror around the point (0,1)
``````

p2mg

#### CF::p2mm, centre_x, centre_y — Spinning Jump Symmetry

p2mm symmetry is specified with CF::p2mm, followed by the center of 180° rotation (two numbers). The centre parameters are optional and default to (0,0).

``````CF::Symmetry = CF::p2mm, 0, 1  // spinning jump symmetry with the mirror around the point (0,1)
``````

p2mm

## Wallpaper Group Symmetry

Designs with symmetry generated by one of the 17 Wallpaper groups can set CF::Symmetry and CF::Tile appropriately. All wallpaper group symmetries require that tiling be enabled. Most wallpaper groups have specific requirements for the symmetry of the tiling lattice, except for p1 and p2 group symmetry.

### Groups with parallelogram tile: p1 and p2

Group p1 is implemented by setting the CF::Tile variable (skew is permitted), as the only elements of the symmetry group are translations.

Group p2, specified by setting the CF::Tile variable (as with p1) and setting CF::Symmetry to CF::p2. This gives the tiling a 180° rotation. Although it has the same symmetry name as the Frieze group p2 above, it differs from Frieze version in that the setting of the CF::Tile has definite width and height, and can be skewed.

#### CF::p2, centre_x, centre_y

The centre parameters in group p2 indicates the centre of the 2-fold rotation (the blue diamond). The centre parameters are optional and default to (0, 0).

``````CF::Tile=[[s 2 3 skew 0 10]] // tile is 2 wide, 3 high, skewed tiling
CF::Symmetry=CF::p2, 0.5, 0.75 // symmetry has 180 rotation centred on (0.5,0.75)
``````

p2

### Groups with arbitrary rectangular tile: pm, pg, pmm, pmg, pgg

Due to either having a reflection (mirror) or glide reflection (reflection plus translation parallel to the reflection axis) or a combination of two of these, the tile of these groups needs to be rectangular.

#### CF::pm, mirror axis, axis positionCF::pg, glide axis, axis positionCF::pmm, centre_x, centre_yCF::pgg, centre_x, centre_yCF::pmg, mirror axis, centre_x, centre_y

The axis specification in groups pm, pg, and pmg indicate which axis (x, y, x=y, or x=-y) is the mirror axis (or glide axis for pg). The axis position parameter in groups pm and pg indicate the position of the mirror or glide axis. The axis position parameter is optional and defaults to 0. The centre parameters in groups pmm, pgg, and pmg indicate the point that the mirror and/or glide axes intersect. The centre parameters are optional and default to (0, 0).

``````CF::Tile=[[s 2 3]]          // tile is 2 wide, 3 high
CF::Symmetry=CF::pm, 0, -0.5 // symmetry has horizontal mirror axis at y=-0.5
``````

pm and pm at 45°

``````CF::Tile=[[s 2 3]]          // tile is 2 wide, 3 high
CF::Symmetry=CF::pg, 1, 0.2 // symmetry has vertical glide axis at x=0.2
``````

pg and pg at 45°

``````CF::Tile=[[s 2 3]]              // tile is 2 wide, 3 high
CF::Symmetry=CF::pmm, 0.2, -0.5 // symmetry has two mirror axes, a vertical axis at x=0.2,
// and a horizontal axis at y=-0.5
``````

pmm and pmm at 45°

``````CF::Tile=[[s 2 3]]              // tile is 2 wide, 3 high
CF::Symmetry=CF::pgg, 0.2, -0.5 // symmetry has two glide axes, a vertical axis at x=0.2,
// and a horizontal axis at y=-0.5
``````

pgg and pgg at 45°

``````CF::Tile=[[s 2 3]]                 // tile is 2 wide, 3 high
CF::Symmetry=CF::pmg, 1, 0.2, -0.5 // symmetry has a vertical mirror axis at x=0.2,
// and a horizontal glide axis at y=-0.5
``````

pmg and pmg at 45°

#### 45° Rotated Square Tiles

A diamond tile (see below) with 90° angles is considered a square tile and is thus also a rectangular tile. This tiling is eligible for the pm, pg, pmm, pgg, and pmg wallpaper groups. The x=y (axis 2) or x=-y (axis 3) axis specifications are used instead of the x or y axis (axis 0 and axis 1).

### Groups with a diamond tile: cm, cmm

This figure illustrates a diamond tile, which is required for cm and cmm group symmetry:

The green rhombus indicates the unit cell of the diamond tile. However, Context Free only supports tiling lattices with at least one axis coincident with the x or y axis. So either the red or blue parallelogram must be used for the tiling lattice. The most straight-forward method for specifying this skewed tiling lattice is to use the six parameter form of the transform adjustment. For a diamond tile that is 3 units wide and 2 units high you would use one of these two:

``````CF::Tile=[trans 0 0 3 0 4.5 1]    // red parallelogram
``````
``````CF::Tile=[trans 0 0 1.5 1 1.5 3]  // blue parallelogram
``````

in general:

``````CF::Tile=[trans 0 0 width 0 (width * 1.5) (height * 0.5)]                       // red parallelogram
``````
``````CF::Tile=[trans 0 0 (width * 0.5) (height * 0.5) (width * 0.5) (height * 1.5)]  // blue parallelogram
``````

#### CF::cm, mirror axis, axis positionCF::cmm, centre_x, centre_y

The mirror axis specification in group cm indicates which axis (x, y, x=y, or x=-y) is the mirror axis. The axis position parameter in group cm indicates the position of mirror axis. The axis position parameter is optional and defaults to 0. The centre parameters in group cmm indicate the point that the mirror axes intersect. The centre parameters are optional and default to (0, 0).

``````CF::Tile=[trans 0 0 3 0 4.5 1]  // 3 wide and 2 high
CF::Symmetry=CF::cm, 1, 0.2     // symmetry has vertical mirror axis at x=0.2
``````

cm and cm at 45°

``````CF::Tile=[trans 0 0 3 0 4.5 1]  // 3 wide and 2 high
CF::Symmetry=CF::cmm, 0.2, -0.5 // symmetry has two mirror axes, a vertical axis at x=0.2,
// and a horizontal axis at y=-0.5
``````

cmm and cmm at 45°

#### 45° Rotated Diamond Tiles

A plain square tiling grid can be considered to be a diamond tile that is rotated 45°. In this case the available mirror axes for cm group symmetry is x=y (axis 2) or x=-y (axis 3), instead of x or y. Wallpaper group cmm will also work on a plain square tiling grid: the mirror axes will be x=y and x=-y, instead of x and y.

### Groups with a square tile: p4, p4m, p4g

As these groups have a 90° centre of rotation, they require the tiling grid to be square.

#### CF::p4, centre_x, centre_yCF::p4m, centre_x, centre_yCF::p4g, centre_x, centre_y

The centre parameters in groups p4, p4m, and p4g indicate the centre of the 4-fold rotation (the green squares). The centre parameters are optional and default to (0, 0).

``````CF::Tile=[s 20]         // tile with height and width 3
CF::Symmetry=CF::p4,2,2 // group p4 with centre of 4-fold rotation being the point (2,2)
``````

p4 and p4 at 45°

``````CF::Tile=[s 20]          // tile with height and width 3
CF::Symmetry=CF::p4m,2,2 // group p4m with centre of 4-fold rotation being the point (2,2)
``````

p4m and p4m at 45°

``````CF::Tile=[s 20]          // tile with height and width 3
CF::Symmetry=CF::p4g,2,2 // group p4g with centre of 4-fold rotation being the point (2,2)
``````

p4g and p4g at 45°

#### 45° Rotated Square Tiles

A diamond tile with 90° angles is considered a square tile and is eligible for the p4, p4m, and p4g wallpaper groups.

### Groups with a hexagonal tile: p3, p3m1, p31m, p6, p6m

These symmetry groups require a tile that fits on a hexagonal grid. There are two permissible hexagonal grids in Context Free: horizontal and vertical.

``````CF::Tile=[skew 15 15 s scale r -15]    // horizontal hexagonal grid
``````
``````CF::Tile=[skew 15 15 s scale r  15]    // vertical hexagonal grid
``````

#### CF::p3, centre_x, centre_yCF::p3m1, centre_x, centre_yCF::p31m, centre_x, centre_yCF::p6, centre_x, centre_yCF::p6m, centre_x, centre_y

The centre parameters in groups p3, p3m1, and p31m indicate the centre of the 3-fold rotation (the red triangles). The centre parameters in groups p6 and p6m indicate the centre of the 6-fold rotation. The centre parameters are optional and default to (0, 0).

``````CF::Tile=[skew 15 15 s 10 r -15]    // horizontal hexagonal grid
CF::Symmetry=CF::p3,1,1             // group p3 with default centre of rotation (1,1)
``````

p3 horizontal and p3 vertical

``````CF::Tile=[skew 15 15 s 10 r 15]    // vertical hexagonal grid
CF::Symmetry=CF::p3m1,1,1           // group p3m1 with default centre of rotation (1,1)
``````

p3m1 horizontal and p3m1 vertical

``````CF::Tile=[skew 15 15 s 10 r -15]    // horizontal hexagonal grid
CF::Symmetry=CF::p31m,1,1           // group p31m with default centre of rotation (1,1)
``````

p31m horizontal and p31m vertical

``````CF::Tile=[skew 15 15 s 10 r 15]    // vertical hexagonal grid
CF::Symmetry=CF::p6,1,1             // group p6 with default centre of rotation (1,1)
``````

p6 horizontal and p6 vertical

``````CF::Tile=[skew 15 15 s 10 r -15]    // horizontal hexagonal grid
CF::Symmetry=CF::p6m,1,1            // group p6m with default centre of rotation (1,1)
``````

p6m horizontal and p6m vertical

``````CF::Symmetry = [], [r 120], [r 240]    // equivalent to CF::Cyclic, 3
``````CF::Symmetry = [skew 30 0], [[skew 30 0 r 120]], [[skew 30 0 r 240]]  // skewed C3 symmetry