## Introduction

Braille is a tactile writing system used by people who are visually impaired.

A pattern of 2x3 dots is used to encode symbols, letters, words and language. The current(?) standard(?) for the English language is Unified English Braille, although Nemeth Braille seems to be a slightly different standard which still appears popular for encoding mathematical notion.

Disclaimer:

- I’m only looking at simple Grade 1 encoding (i.e. letter-by-letter transcription)
- I realise there are Braille symbols in unicode, but I’m thinking beyond screen/paper representations, so I want to render my own symbols.

## Braille subset - just the lowercase letters

## Defining a Braille symbol

- A Braille symbol is made up of 6 dots.
- Therefore, we need only 6 bits to encode it
- Let’s round it up to 8 bits, and store the definition for each symbol in a byte.
- Assign each of the dots a numerical value.
- The numerical representation of a symbol is the sum of its dots
- e.g.
- the letter
`g`

is represented by setting the upper 4 dots - sum of upper 4 dots = 1 + 2 + 4 + 8 = 15

- the letter

To turn a symbol back into a sequence of ON/OFF values, use `intToBits`

e.g.

```
dots <- intToBits(15)[1:6]
matrix(dots, ncol=2, byrow=TRUE)
```

```
[,1] [,2]
[1,] 01 01
[2,] 01 01
[3,] 00 00
```

## Exploiting redundancy

In the table of all the alphabet Braille symbols in the image above, you can see that the second set of 10 symbols is just a copy of the first set with the bottom left dot turned on.

Similarly the third set of 10 symbols is a copy of the first set but with *both*
bottom dots turned on.

So for my current purposes, it’s only necessary to carefully define the first row, and then just calculate all other rows from it.

## The alphabet

- Create the first 10 letters of the alphabet by summing the dots in each.
- Create subsequent rows by adding the extra dots that are set for that row.

```
set1 <- c(1, 5, 3, 11, 9, 7, 15, 13, 6, 14)
set2 <- set1 + 16
set3 <- set1 + 48
set4 <- set1 + 32
# Definition of the first 40 symbols
symbols <- c(set1, set2, set3, set4)
symbols
```

```
[1] 1 5 3 11 9 7 15 13 6 14 17 21 19 27 25 23 31 29 22 30 49 53 51 59 57
[26] 55 63 61 54 62 33 37 35 43 41 39 47 45 38 46
```

## Lookup table

For historical reasons, the letter `w`

is totally out of sequence, so the mapping
from letter to symbol is a bit weird.

```
letter_to_symbol_idx <- setNames(1:26,letters)
letter_to_symbol_idx['w'] <- 40
letter_to_symbol_idx['x'] <- 23
letter_to_symbol_idx['y'] <- 24
letter_to_symbol_idx['z'] <- 25
letter_to_symbol_idx
```

```
a b c d e f g h i j k l m n o p q r s t u v w x y z
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 40 23 24 25
```

## Simple Braille Renderer (Grade 1)

Split a word into characters and find all the symbols for these characters

```
this_word <- "braille"
chars <- strsplit(tolower(this_word),'')[[1]]
symbol_idx <- letter_to_symbol_idx[chars]
these_symbols <- symbols[symbol_idx]
these_symbols
```

`[1] 5 29 1 6 21 21 9`

Turn the symbols into ON/OFF dot definitions

```
dots <- these_symbols %>% map(~intToBits(.x)[1:6] > 0)
dots
```

```
[[1]]
[1] TRUE FALSE TRUE FALSE FALSE FALSE
[[2]]
[1] TRUE FALSE TRUE TRUE TRUE FALSE
[[3]]
[1] TRUE FALSE FALSE FALSE FALSE FALSE
[[4]]
[1] FALSE TRUE TRUE FALSE FALSE FALSE
[[5]]
[1] TRUE FALSE TRUE FALSE TRUE FALSE
[[6]]
[1] TRUE FALSE TRUE FALSE TRUE FALSE
[[7]]
[1] TRUE FALSE FALSE TRUE FALSE FALSE
```

## Create a data frame of dots positions

```
# Define x and y positions of each dot
x <- c(0, 1, 0, 1, 0, 1)
y <- c(2, 2, 1, 1, 0, 0)
# merge each dot with its (x, y) coordiante,
# and add some spacing to the x cordinate so that
# the characters appear one after the other
plot_df <- data.frame(
dot = unlist(dots),
x = x + rep(seq(dots), e=6) * 3,
y = y
)
knitr::kable(head(plot_df))
```

dot | x | y |
---|---|---|

TRUE | 3 | 2 |

FALSE | 4 | 2 |

TRUE | 3 | 1 |

FALSE | 4 | 1 |

FALSE | 3 | 0 |

FALSE | 4 | 0 |

`ggplot`

```
# Simple plot
ggplot(plot_df) +
geom_point(aes(x, y, size=dot)) +
coord_equal() +
theme_void() +
ggtitle(this_word) +
theme(legend.position = 'none') +
expand_limits(y=c(-0.5, 2.5))
```

## Tweetable Simple Braille Renderer (Grade 1)

```
#rstats
library(tidyverse)
d=c(1,5,3,11,9,7,15,13,6,14)
d=c(d,d+16,d+48,d+32)
L=setNames(c(1:22,40,23:25),letters)
D=map(d[L[strsplit('braille','')[[1]]]],~intToBits(.x)[1:6]>0)
P=data.frame(D=unlist(D),x=0:1+rep(seq(D),e=6)*3,y=rep(2:0,e=2))
ggplot(P)+geom_point(aes(x,y,size=D))
```

`Warning: Using size for a discrete variable is not advised.`

## Idea (free to a good home)

- Translation of R plotmath expressions to Nemeth Braille