A New Type of Collage for the Blind

a grid of variable height display pins made of discarded paper

Greg Sepesi
24 min readOct 27, 2023

1. Introduction

According to Wikipedia,

Collage (/kəˈlɑːʒ/, from the French: coller, “to glue” or “to stick together”) is a technique of art creation, primarily used in the visual arts, but in music too, by which art results from an assemblage of different forms, thus creating a new whole.”

In contrast, in the context of printing for the blind, collage is one of the four production methods for transcribing printed graphics into tactile graphics. According to the Braille Authority of North America’s Guidelines and Standards for Tactile Graphics, the four production methods are

  • embossed braille image
    “An image is computer-generated using software programs for braille and graphics and then embossed on computer paper with a graphics embosser. Embossed braille, tooling, and collage may be combined to form a hard copy tactile graphic master. Production and duplication equipment required: computer, braille and graphics software programs, specific braille fonts, braille paper, graphics embosser.”
  • microcapsule image
    “An image is computer-generated using software programs for braille and graphics, transferred to microcapsule paper using a photocopier or printer, and then developed by a fuser. Production and duplication equipment required: computer, braille and graphics software programs, specific braille fonts, photocopier or printer, microcapsule paper, fuser.”
  • collage image
    “Textured materials are glued onto a paper foundation (base layer) to form a raised image. Common household items (i.e., drywall tape, corrugated paper, crochet cotton, string, punched-out dots) can be used to create a tactile graphic master. Collage, tooling, and embossed braille may be combined to form a tactile graphic master. Production and duplication equipment required: braille paper, household items, plastic sheets, vacuum-form machine.”
  • customized image
    “Designed for one-time use by a reader.”

Choosing a particular production method for tactile graphics has been more of an art than a science. And that graphics production isn’t cheap. Again according to the Braille Authority of North America’s Guidelines and Standards for Tactile Graphics,

“The transcription of a text is not considered complete until the required graphics have been included. […] Cost and time must not be the primary considerations when determining the method of production. Choose the most effective production medium for each graphic.”

This essay describes a tactile display that is a different type of collage: instead of gluing different pieces of paper together, the proposed tactile display rolls and glues pieces of paper into display pins, each including a ratchet mechanism. Arranging thousands of those display pins into a grid, they can be individually pushed up to different heights to form many different shapes (e.g., the shape of a friend’s face).

2. Why

High unemployment among the blind has been a social problem for many generations. Dr. James S. Nyman (1930–2019) was blinded by a dynamiting accident when he was 11 years old and he eventually became the director of Nebraska Services for the Blind. In 2008, speaking at the annual White Cane Banquet of the Omaha Chapter of the National Federation of the Blind, the title of his talk was Unemployment Rates and Reasons — Dissing the Blind. He structured his talk around six reasons for the long term high unemployment among the blind, each reason starting with the prefix “dis”:

  1. discrimination — “As blind people we are fortunate if we get from one end of a day to the other without experiencing some form of discrimination. It is a pervasive phenomenon with many manifestations. Any time we confront some form of differential treatment, even if it is intended to benefit us, it reflects an underlying attitude that places us in a class outside ordinary membership in the human community. No single approach can effectively cope with the many forms that discrimination takes.”
  2. disincentives — “When Supplemental Security Income (SSI) was implemented in 1974, an even more restrictive earnings limitation was applied. Until 1996 the earnings limitation for blind SSDI recipients was linked to those for Social Security recipients between the ages of sixty-five and seventy. In that year that coupling was eliminated, and, while the earnings limits increased at an accelerated rate for older people, it lagged significantly for the blind. In 2008 this disparity is between $18,840 for the blind and $36,120 for older people: a total of $17,280, or $1,440 a month. On May 15 [2008] the House of Representatives passed the Blind Persons Earnings Fairness Act, which would gradually re-couple earnings limitations for blind and senior recipients. If this is finally adopted by both House and Senate, one of the significant disincentives to seeking employment will have been greatly reduced.”
  3. distance — “Many aspects of ordinary life are impaired by the limited options that confront a blind person. Social, economic, recreational, entertainment, religious, educational, and family participation can involve the necessity of devising alternatives for simply getting there. At best public transportation is a poor option, except in the largest metropolitan areas. The private automobile has come to dominate social existence, including work, to the point that in some settings blindness can virtually immobilize an individual. The lack of imagination and resources among those who operate public transportation systems makes it clear that no solution to the problem of simply getting there, wherever there might be, is likely to come from that quarter.”
  4. discouragement — “Anyone who has experienced repeated failures to obtain employment may feel discouraged and drop out of the labor force. The likelihood of experiencing repeated failure if one is blind is many times greater than it is for members of the general public. I know of no way to quantify the fraction of unemployed blind people who are simply discouraged and have withdrawn from the job search. Workshops by consultants, books and articles by experts, job fairs, and individual counseling can lay out many brilliant strategies for job seeking, but the realities of discrimination and indifference more often than not reduce these to exercises in futility. Meanwhile, discouragement and withdrawal from the job search continue to swell the ranks of unemployed blind people and account for a significant fraction of the unemployment rate. Repeated assertions of the 70 percent unemployment rate can hardly be encouraging to these individuals.”
  5. disinclination — “Some people in this world would prefer not to work. Some of them are blind. If people are blind in this society, there is a pretty good chance they can qualify for a variety of public supports: SSDI, Medicare, SSI, public housing, food stamps, and other benefits. If an individual settles into a comfort zone in this framework, a disinclination to work can be sustained. […] No matter how much we may deplore this rejection of the work ethic, most of us know someone who prefers this lifestyle.”
  6. disability — “In the familiar formulation of Kenneth Jernigan: “If a blind person has proper training and opportunity, blindness can be reduced to a physical nuisance.” The critical qualification, of course, is, “with proper training in the alternative techniques of blindness.” When positive attitudes drive and sustain the motivation to employ the alternative techniques, then blindness is significantly reduced as a factor. It is not an accident that individuals who complete a training program in the orientation center in Lincoln have an employment rate of around 90 percent. Further evidence for the value of training in the alternative techniques is provided by Dr. Ruby Ryles of Louisiana Tech and Dr. Fred Schroeder, who have documented that 90 percent of employed blind people are proficient Braille readers. In the modern economy Braille literacy and computer literacy combined are indispensable skills. Without such training it is difficult to see how individuals could, in the strict requirements of Labor Department statistics, be said to be available for employment.”

3. Where to focus

When a problem (e.g., unemployment among the blind) has so many contributing factors (e.g., discrimination, disincentives, distance, discouragement, disinclination, disability), it is difficult to know where to start. In other words, it is difficult to identify the crux of the problem. However, taking a step back, jobs require functioning markets and, according to the Wikipedia article about markets, functioning markets require

  • cooperation,
  • trust,
  • mutual understanding, and
  • legal enforcement of contracts.

Those functioning market requirements seem to follow the precedence hierarchy shown in figure 3.1 (generated by the Julia code in appendix C): mutual understanding enables trust, trust enables cooperation, and cooperation enables legal enforcement of contracts.

Relationship diagram of functioning market requirements with relationship arrows in line starting at the bottom with “mutual understanding” up to “trust” up to “cooperation” and finally up to “legal enforcement of contracts”.
Figure 3.1 — precedence of requirements of functioning market

Merging that functioning market requirement hierarchy diagram with Dr. James S. Nyman’s list of six major factors contributing to unemployment among the blind results in the following diagram (generated by the Julia code in appendix C). Note that all the “enables” arrow labels are removed to reduce diagram clutter.

Figure 3.2 — hierarchy of factors contributing to a job market that reduces unemployment among the blind

Therefore, the crux of the problem (i.e., the primary roadblock) is at the very bottom: overcoming disability. Accordingly, overcoming disability is the place to focus in order to increase employment rates among the blind. In other words, although programs to provide transportation, laws against discrimination, laws to reduce disincentives, and programs that offer emotional support are all based upon good intentions, they are all distractions away from where help is needed most. The next section proposes how to overcome disability.

4. How

In order for a new tactile display to significantly contribute to overcoming disability, the tactile display must vastly increase the information displayed while vastly decreasing the cost, which depends upon

  1. the cost of the display’s materials and
  2. the cost of preparing the displayed information. (Recall that “The transcription of a text is not considered complete until the required graphics have been included. […] Cost and time must not be the primary considerations when determining the method of production.”)

Concerning the cost of materials, the proposed tactile display is

  • upcycled — the display pins are made from discarded copier and printer paper,
  • reusable — the display pins can be automatically pushed up to different heights to display another shape, and
  • variable height — each display pin can be pushed up to much more than the two heights available to braille display pins.

The proposed tactile display is NOT

  • sized like braille — as shown in figure 4.1 (generated by the Julia code in appendix A), the display pins of the proposed tactile display are much larger than refreshable braille display pins and therefore do not simultaneously fit upon a fingertip for fast braille reading,
  • spaced like braille — as shown in figures 4.2 and 4.3 (generated by the Julia code in appendix B), the proposed tactile display has uniformly spaced display pins (without any extra gaps to separate adjacent braille cells),
  • built like refreshable braille — the proposed tactile display is mostly a bunch of flimsy paper (in contrast, some of the refreshable braille displays currently on the market survive MIL-STD-810G drop tests), and
  • priced like refreshable braille — as shown in figure 4.4 (generated by the Julia code in appendix C), the proposed tactile display is much cheaper than refreshable braille devices.
A top view of the cross section of display pins, showing that the proposed tactile display pins are much larger refreshable braille pins and therefore will not fit on the finger tip for fast reading.
Figure 4.1 — comparison of dot sizes

As defined in section 3.4.2 of the Guidelines and Standards for Tactile Graphics, the standard braille page layout is quite large: 11.5 x 11 inches with 40 columns and 25 rows of 6-dot braille cells, including the separation space between the braille cells as shown in the following diagram.

Layout of standard braille page that is 11.5 inches wide and 11 inches tall with 40 columns and 25 rows of 6-dot braille cells.
Figure 4.2 — standard embossed braille page layout with 40 columns and 25 rows of 6 dot braille cells.

In contrast, as shown in the following diagram, the page layout of dots in the proposed paper tactile display is even larger and with a uniformly spaced grid (i.e., no spacing added to separate 6-dot braille cells). The aspect ratio of the proposed paper tactile display page layout is 16:9 which is the most common aspect ratio of videos and smartphone displays.

The proposed tactile display page layout is a 128 x 72 (=9216) grid of dots in a 16:9 aspect ratio.
Figure 4.3 — proposed tactile display’s spacing of display pins

An important difference between figures 4.2 and 4.3 is that the proposed tactile display shown in figure 4.3 has a lot more display pins. The display pin count in the proposed paper tactile display is 128 x 72 (= 9,216). To allow a price low, the proposed display pin material is discarded printer/copier paper, which is virtually free. That paper will be laser cut and then rolled into the shape of a display pin, including its ratchet mechanism.

The American Foundation for the Blind’s list of refreshable braille displays currently on the market covers a wide range of prices. In the following diagram (generated by the Julia code in appendix C), the prices of the refreshable braille displays are plotted as black dots and the linear least squared error fit through that data is plotted as a dotted line with a slope of about 14.37. In other words, the market price for each additional display pin in a refreshable braille device is about $14.37.

A scatter plot of refreshable braille display prices (y axis) versus the number of display pins in the display (x axis). A dotted line with a slope of $14.37 per display pin is a least squared error fit through the scatter plot points.
Figure 4.4 — comparison of the cost of display pins in current refreshable braille devices and the proposed tactile display.

In contrast to refreshable braille devices with prices that increase with each additional display pin, the price of the proposed tactile display does not depend much on the number of display pins because the display pins are made of discarded paper, a virtually free material. Instead, the expected price range of the proposed tactile display is due to the expected price of the robotics that move the display pins. And robotics, in general, are getting cheaper.

In addition to price, there are many other differences between the proposed tactile display and refreshable braille devices. In fact, the use cases are expected to be completely different, which is why the proposed tactile display is not even considered to be a type of braille device. Although it can display large braille dot patterns, the proposed tactile display does not meet any of the braille dot size standards.

5. Use cases

(TODO)

  • display faces of family and friends
  • display maps
  • graph math functions
  • display music scores
  • edit computer source code
  • automate the transcription of printed images

However, with affordable robotics to move display pins and affordable smartphones to transfer and process information, the proposed type of tactile display is now possible and it might finally solve that high unemployment problem indirectly (by boosting marketable skills) and directly (by being manufactured and serviced by blind people).

6. Conclusion

In the book Range: Why Generalists Triumph in a Specialized World, David Epstein describes the following origin story.

“Gunpei Yokoi was was a Japanese man who didn’t score well on his electronics exams in university so he had to settle for a low tier job as a machine maintenance worker at a playing card company. This playing card company, founded in the 19th century, is called Nintendo. And one day, the president of the company saw Yokoi essentially playing around with company equipment because he didn’t have anything to do and he made an extendable arm called the Ultra Hand. It was just a device where you could grab distant objects with suction cups. And the desperate president says, “turn that into a toy, we’re going to market,” and it’s sort of a success. And so the president says, “all right, you’re going to start a game and toy operation.”

Yokoi realizes that he’s not equipped to work on the cutting edge, but there’s so much information widely available that he can take information from different domains and merge it, and he did that for his magnum opus, the Game Boy. He developed this philosophy he called lateral thinking with withered technology. And what he meant by that, withered technology, he meant technology that’s already well understood easily available and often cheap, and lateral thinking meant taking it from an area where everyone’s already used to it and merging it with something else. Because the technology was so withered and so well understood, programmers inside and outside of Nintendo pumped out games for it way faster than their competitors and the Game Boy became the best selling console of the 20th century and Nintendo still uses that lateral thinking with withered technology philosophy today.”

Similarly, the proposed tactile display design can be thought of as lateral thinking (e.g., display pins that have variable heights) with withered technology (e.g., scherenschnitte to make the display pins and cheap robotics to move them). Aside from the low cost, perhaps the main advantage of the proposed design is its modular architecture for faster development and testing of the three modules:

  • the display mechanism (e.g., the display pin ratchets and pawls),
  • the robotics (e.g., to automate the moving of the display pins), and
  • the smartphone camera application (e.g., to transmit and process information).

Does working on this project to significantly reduce unemployment among the blind interest you?

Appendix A

The following Julia code generates figure 4.1.

# sizedot.jl: plot of braille dot dimensions
using GLMakie
using Printf

function sizedot()
# initialize figure data
ls = 0.8 # arrow lengthscale
wTick = 0.5 # width of label tick
lblOffset = 1.1 # label offset
lblLine = 0.8 # label line length (arrow length)
stkWidth = 1 # stroke width
C = [ # marker colors
:red,
:blue,
:green]
MS = [ # marker sizes
72,
75,
150]
IXY = reduce(hcat,vec(
Iterators.product(0:1,0:2) .|> collect))
fig = Figure(size = (800, 800))
ax = Axis(fig[1,1],
limits = (-5,16, -1.5,19.5),
title = "dimensions of braille dots and tactile display dots",
xlabel = "x (unit: mm)",
ylabel = "y (unit: mm)",
aspect = 1)
hidedecorations!(ax)
hidespines!(ax)

# plot legend directly below title
X = [0, lblLine] .+ 2
Y = [19.25, 19.25]
lines!(X,Y, color = C[1])
text!(X[2],Y[2], # red for reading embossed paper
text = " braille dots embossed in paper",
align = (:left, :center),
color = C[1])
Y .-= 0.6
lines!(X,Y, color = C[2])
text!(X[2],Y[2], # blue for building signage
text = " braille dots in building signage",
align = (:left, :center),
color = C[2])
Y .-= 0.6
lines!(X,Y, color = C[3])
text!(X[2],Y[2], # green for upcycled paper tactile display
text = " upcycled paper tactile display dots",
align = (:left, :center),
color = C[3])


## braille embossed in paper
iBraille = 1

# set dimensions
delDot = 2.337
delCell = 6.223
delLine = 10.2
diameter = 1.45
height = 0.48
XY = IXY .* delDot

# plot dots
scatter!(XY,
marker = :circle,
markersize = MS[iBraille],
strokewidth = stkWidth,
strokecolor = C[iBraille],
color = :white)
scatter!(XY[1,:] .+ delCell, XY[2,:],
marker = :circle,
markersize = MS[iBraille],
strokewidth = stkWidth,
strokecolor = C[iBraille],
color = :white)
scatter!(XY[1,:], XY[2,:] .+ delLine,
marker = :circle,
markersize = MS[iBraille],
strokewidth = stkWidth,
strokecolor = C[iBraille],
color = :white)

# label dot dimensions
lines!( # label dot diameter
[XY[1,1],XY[1,1]] .- diameter/2,
[XY[2,1]-wTick/2,XY[2,1]+wTick/2] .- lblOffset,
color = C[iBraille])
lines!( # label dot diameter
[XY[1,1],XY[1,1]] .+ diameter/2,
[XY[2,1]-wTick/2,XY[2,1]+wTick/2] .- lblOffset,
color = C[iBraille])
X =[XY[1,1]-diameter/2-lblLine,
XY[1,1]+diameter/2+lblLine]
Y =[XY[2,1], XY[2,1]] .- lblOffset
U =[lblLine, -lblLine]
V =[0.0, 0.0]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm", diameter)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
color = C[iBraille])

lines!( # label dot delta
[XY[1,1],XY[1,1]],
[XY[2,3]-wTick/2,XY[2,3]+wTick/2] .- lblOffset,
color = C[iBraille])
lines!( # label dot delta
[XY[1,2],XY[1,2]],
[XY[2,3]-wTick/2,XY[2,3]+wTick/2] .- lblOffset,
color = C[iBraille])
X =[XY[1,1]-lblLine,
XY[1,2]+lblLine]
Y =[XY[2,3], XY[2,3]] .- lblOffset
U =[lblLine, -lblLine]
V =[0.0, 0.0]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm", delDot)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
color = C[iBraille])

lines!( # label cell delta
[XY[1,1],XY[1,1]],
[XY[2,5]-wTick/2,XY[2,5]+wTick/2] .- lblOffset,
color = C[iBraille])
lines!( # label cell delta
[XY[1,1],XY[1,1]] .+ delCell,
[XY[2,5]-wTick/2,XY[2,5]+wTick/2] .- lblOffset,
color = C[iBraille])
X =[XY[1,1]-lblLine,
XY[1,1]+delCell+lblLine]
Y =[XY[2,5], XY[2,5]] .- lblOffset
U =[lblLine, -lblLine]
V =[0.0, 0.0]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm", delCell)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
color = C[iBraille])

lines!( # label line delta
[XY[1,1]-wTick/2,XY[1,1]+wTick/2] .- lblOffset,
[XY[2,3],XY[2,3]],
color = C[iBraille])
lines!( # label line delta
[XY[1,1]-wTick/2,XY[1,1]+wTick/2] .- lblOffset,
[XY[2,3],XY[2,3]] .+ delLine,
color = C[iBraille])
X =[XY[1,1], XY[1,1]] .- lblOffset
Y =[XY[2,3]-lblLine, XY[2,3]+lblLine+delLine]
U =[0.0, 0.0]
V =[lblLine, -lblLine]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm", delLine)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
rotation = pi/2,
color = C[iBraille])

x0 = XY[1,1] + delCell + diameter/2
y0 = XY[2,1] + delLine
lines!( # side view of dot
[x0-diameter, x0],
[y0, y0],
linewidth = stkWidth,
color = C[iBraille])
rDome = (4*height^2 + diameter^2) / (8*height)
theta0 = atan(rDome-height, diameter/2)
xDome = x0 - diameter/2
yDome = y0 + height - rDome
nDome = 20
THETA = LinRange(theta0,pi-theta0,nDome)
XDome = rDome .* cos.(THETA) .+ xDome
YDome = rDome .* sin.(THETA) .+ yDome
lines!( # side view of dot dome
XDome, YDome,
linewidth = stkWidth,
color = C[iBraille])
lines!([
x0-diameter/2+lblOffset-wTick/2,
x0-diameter/2+lblOffset+wTick/2],
[y0, y0],
color = C[iBraille])
lines!([
x0-diameter/2+lblOffset-wTick/2,
x0-diameter/2+lblOffset+wTick/2],
[y0+height, y0+height],
color = C[iBraille])
X =[x0-diameter/2, x0-diameter/2] .+ lblOffset
Y =[y0-lblLine, y0+height+lblLine]
U =[0.0, 0.0]
V =[lblLine, -lblLine]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" dot height = %.2f mm", height)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
rotation = pi/2,
color = C[iBraille])


## braille signage in buildings
iBraille = 2

# set dimensions
delDot = 2.415
delCell = 6.87
delLine = 10.1
diameter = 1.55
height = 0.79
XY = IXY .* delDot

ddelDot = 0.025
ddelCell = 0.75
ddelLine = 0.1
ddiameter = 0.05
dheight = 0.15

# plot dots
scatter!(XY,
marker = :circle,
markersize = MS[iBraille],
strokewidth = stkWidth,
strokecolor = C[iBraille],
color = RGBAf(1,1,1,0.5))
scatter!(XY[1,:] .+ delCell, XY[2,:],
marker = :circle,
markersize = MS[iBraille],
strokewidth = stkWidth,
strokecolor = C[iBraille],
color = RGBAf(1,1,1,0.5))
scatter!(XY[1,:], XY[2,:] .+ delLine,
marker = :circle,
markersize = MS[iBraille],
strokewidth = stkWidth,
strokecolor = C[iBraille],
color = RGBAf(1,1,1,0.5))

# label dot dimensions
lines!( # label dot diameter
[XY[1,1],XY[1,1]] .+ (delCell - diameter/2),
[XY[2,1]-wTick/2,XY[2,1]+wTick/2] .- lblOffset,
color = C[iBraille])
lines!( # label dot diameter
[ddiameter,ddiameter,-ddiameter,-ddiameter,ddiameter] .+
(XY[1,1] + diameter/2 + delCell),
[-wTick,wTick,wTick,-wTick,-wTick]./2 .+
(XY[2,1] - lblOffset),
color = C[iBraille])
X =[XY[1,1]+delCell-diameter/2-lblLine,
XY[1,1]+delCell+diameter/2+lblLine]
Y =[XY[2,1], XY[2,1]] .- lblOffset
U =[lblLine, -lblLine]
V =[0.0, 0.0]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm +/- %.2f mm",
diameter, ddiameter)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
color = C[iBraille])

lines!( # label dot delta
[XY[1,1],XY[1,1]] .+ delCell,
[XY[2,3]-wTick/2,XY[2,3]+wTick/2] .- lblOffset,
color = C[iBraille])
lines!( # label dot delta
[ddelDot,ddelDot,-ddelDot,-ddelDot,ddelDot] .+
(XY[1,2] + delCell),
[-wTick,wTick,wTick,-wTick,-wTick]./2 .+
(XY[2,3] - lblOffset),
color = C[iBraille])
X =[XY[1,1]+delCell-lblLine,
XY[1,2]+delCell+lblLine]
Y =[XY[2,3], XY[2,3]] .- lblOffset
U =[lblLine, -lblLine]
V =[0.0, 0.0]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm +/- %.2f mm",
delDot, ddelDot)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
color = C[iBraille])

lines!( # label cell delta
[XY[1,1],XY[1,1]],
[XY[2,5]-wTick/2,XY[2,5]+wTick/2] .+ lblOffset,
color = C[iBraille])
lines!( # label cell delta
[ddelCell,ddelCell,-ddelCell,-ddelCell,ddelCell] .+
(XY[1,1] + delCell),
[-wTick,wTick,wTick,-wTick,-wTick]./2 .+
(XY[2,5] + lblOffset),
color = C[iBraille])
X =[XY[1,1]-lblLine,
XY[1,1]+delCell+lblLine]
Y =[XY[2,5], XY[2,5]] .+ lblOffset
U =[lblLine, -lblLine]
V =[0.0, 0.0]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm +/- %.2f mm",
delCell, ddelCell)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
color = C[iBraille])

lines!( # label line delta
[XY[1,2]-wTick/2,XY[1,2]+wTick/2] .+ lblOffset,
[XY[2,3],XY[2,3]],
color = C[iBraille])
lines!( # label line delta
[-wTick,wTick,wTick,-wTick,-wTick] ./ 2 .+
(XY[1,2] + lblOffset),
[-ddelLine,-ddelLine,ddelLine,ddelLine,-ddelLine] .+
(XY[2,3] + delLine),
color = C[iBraille])
X =[XY[1,2], XY[1,2]] .+ lblOffset
Y =[XY[2,3]-lblLine, XY[2,3]+lblLine+delLine]
U =[0.0, 0.0]
V =[lblLine, -lblLine]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm +/- %.2f mm",
delLine, ddelLine)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
rotation = pi/2,
color = C[iBraille])

x0 = XY[1,2] + delCell + diameter/2
lines!( # side view of dot
[x0-diameter, x0],
[y0, y0],
linewidth = stkWidth,
color = C[iBraille])
rDome = (4*height^2 + diameter^2) / (8*height)
nDome = 20
xDome = x0 - diameter/2
yDome = y0 + height - rDome
if rDome < height
THETA = LinRange(0,pi,nDome)
else
theta0 = atan(rDome-height, diameter/2)
THETA = LinRange(theta0,pi-theta0,nDome)
end
XDome = rDome .* cos.(THETA) .+ xDome
YDome = rDome .* sin.(THETA) .+ yDome
lines!( # side view of dot dome
XDome, YDome,
linewidth = stkWidth,
color = C[iBraille])
lines!([
x0-diameter/2+lblOffset-wTick/2,
x0-diameter/2+lblOffset+wTick/2],
[y0, y0],
color = C[iBraille])
lines!(
[wTick,wTick,-wTick,-wTick,wTick] ./ 2 .+
(x0 - diameter/2 + lblOffset),
[-dheight,dheight,dheight,-dheight,-dheight] .+
(y0 + height),
color = C[iBraille])
X =[x0-diameter/2, x0-diameter/2] .+ lblOffset
Y =[y0-lblLine, y0+height+lblLine]
U =[0.0, 0.0]
V =[lblLine, -lblLine]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" dot height = %.2f mm +/- %.2f mm",
height, dheight)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
rotation = pi/2,
color = C[iBraille])


## upcycled paper tactile display
iBraille = 3

# set dimensions
deltaPin = 11 * 25.4 / 72
r2Pin = 0.8 * deltaPin / 2
x0 = XY[1,2] + delCell + deltaPin + lblLine
IXY = reduce(hcat,vec(
Iterators.product(0:3,0:2) .|> collect))
XY = IXY .* deltaPin

# plot dots
scatter!(XY,
marker = :circle,
markersize = MS[iBraille],
strokewidth = stkWidth,
strokecolor = C[iBraille],
color = RGBAf(1,1,1,0.5))
nDot = size(XY,2)
for iDot = 1:nDot
lines!( # dome split
[XY[1,iDot]-r2Pin; XY[1,iDot]+r2Pin],
[XY[2,iDot]; XY[2,iDot]],
linewidth = stkWidth,
color = C[iBraille])
end

diameter = r2Pin * 2
height = 2.0
rDome = 0.5
lines!( # side view of dot
[x0-diameter, x0-diameter/2, x0-diameter/2, x0-rDome],
[y0, y0, y0+height, y0+height],
linewidth = stkWidth,
color = C[iBraille])
lines!(
[x0, x0],
[y0+height-rDome, y0],
linewidth = stkWidth,
color = C[iBraille])
nDome = 10
xDome = x0 - rDome
yDome = y0 + height - rDome
THETA = LinRange(0,pi/2,nDome)
XDome = rDome .* cos.(THETA) .+ xDome
YDome = rDome .* sin.(THETA) .+ yDome
lines!( # side view of dot dome
XDome, YDome,
linewidth = stkWidth,
color = C[iBraille])
x0 += (lblOffset-diameter/4.3) # label position
X = [x0, x0]
Y = [y0-lblLine, y0+height+lblLine]
U = [0.0, 0.0]
V = [lblLine, -lblLine]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
lines!(
[x0-wTick/2,x0+wTick/2],
[y0, y0],
color = C[iBraille])
lines!(
[x0-wTick/2,x0+wTick/2],
[y0+height, y0+height],
color = C[iBraille])
str = @sprintf(" dot height = %.2f mm",
height)
text!(X[2],Y[2],
text = str,
align = (:left, :center),
rotation = pi/2,
color = C[iBraille])
x0 = XY[1,1] - diameter/2 - wTick
X = [x0, x0]
Y = [XY[2,1]-lblLine, XY[2,5]+lblLine]
U = [0.0, 0.0]
V = [lblLine, -lblLine]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
str = @sprintf(" %.2f mm",
XY[2,5] - XY[2,1])
text!(X[2],Y[2],
text = str,
align = (:left, :center),
rotation = pi/2,
color = C[iBraille])
lines!( # label line delta
[x0-wTick/2,x0+wTick/2],
[XY[2,1],XY[2,1]],
color = C[iBraille])
lines!( # label line delta
[x0-wTick/2,x0+wTick/2],
[XY[2,5],XY[2,5]],
color = C[iBraille])
x0 = XY[1,10] + diameter/2
y0 = XY[2,10] + diameter/2 + wTick/2
X = [x0-diameter-lblLine,x0+lblLine]
Y = [y0, y0]
U = [lblLine, -lblLine]
V = [0.0, 0.0]
arrows!(X,Y,U,V,
lengthscale = ls,
color = C[iBraille])
lines!( # label line delta
[x0, x0] .- diameter,
[y0-wTick/2,y0+wTick/2],
color = C[iBraille])
lines!( # label line delta
[x0, x0],
[y0-wTick/2,y0+wTick/2],
color = C[iBraille])
str = @sprintf(" %.2f mm", diameter)
text!(x0+lblLine,y0,
text = str,
align = (:left, :center),
color = C[iBraille])


save("sizedot.png", fig)
fig
end # sizedot()

Appendix B

The following Julia code generates figures 4.2 and 4.3.

# sizepage.jl: page layout of braille & tactile display
using GLMakie

function sizepage(iBrailleMod::Int64=0)

# interpret argument
fn = "sizepage.png"
strTitle = ""
figWidth = 0
figHeight = 0
ar = 1
if iBrailleMod == 0
fn = "sizepage.braille.png"
strTitle = "page layout of standard 11.5\" x 11\" braille page"
pageWidth = 11.5
pageHeight = 11
figWidth = 800
figHeight = 800
ar = 1
elseif iBrailleMod == 1
fn = "sizepage.tactile_display.png"
strTitle = "page layout of tactile display with 16:9 aspect ratio"
pageWidth = 20.55
pageHeight = 12
figWidth = 1422
figHeight = 800
ar = 1.77777
else
println("unknown argument: $iBraillMod")
return
end

# initialize figure data
stkWidth = 1 # stroke width
fig = Figure(size = (figWidth, figHeight))
ax = Axis(fig[1,1],
limits = (0,pageWidth, 0,pageHeight),
title = strTitle,
xlabel = "page width (unit: inch)",
ylabel = "page height (unit: inch)",
aspect = ar)

# initialize data
nTHETA = 32
THETA = LinRange(0, 2*pi, nTHETA+1)

if iBrailleMod == 0 # standard braille
delDot = 0.092
delCell = 0.245
delLine = 0.4
diameter = 0.057
XCIRC = diameter/2 .* cos.(THETA)
YCIRC = diameter/2 .* sin.(THETA)
IXY = reduce(hcat,vec(
Iterators.product(0:1,0:2) .|> collect))
XY = IXY .* delDot
xOffset = 0.9
yOffset = 0.6

# for each cell row
for iRow = 1:25

# for each cell column
for iCol = 1:40

# for each dot row
for iRowDot = 1:3

# for each dot column
for iColDot = 1:2
X = (xOffset +
(iCol-1) * delCell +
(iColDot-1) * delDot) .+
XCIRC
Y = (yOffset +
(iRow-1) * delLine +
(iRowDot-1) * delDot) .+
YCIRC
lines!(X,Y,
linewidth = 0.5,
color = "black")
end # for each dot column
end # for each dot row
end # for each column
end # for each row

else # tactile display
delPin = 11.0 / 72
r1Pin = 0.5 * delPin / 2
r2Pin = 0.8 * delPin / 2
X1 = r1Pin .* cos.(THETA)
Y1 = r1Pin .* sin.(THETA)
X2 = r2Pin .* cos.(THETA)
Y2 = r2Pin .* sin.(THETA)
xOffset = 0.5 + delPin / 2
yOffset = 0.5 + delPin / 2

# for each dot row
for iRow = 1:72
yOff = (iRow-1)*delPin

# for each dot column
for iCol = 1:128
xOff = (iCol-1)*delPin
lines!( # inner radius
(xOff+xOffset) .+ X1,
(yOff+yOffset) .+ Y1,
linewidth = 1,
color = :red)
lines!( # outer radius
(xOff+xOffset) .+ X2,
(yOff+yOffset) .+ Y2,
linewidth = 1,
color = :red)
end # for each column
end # for each row
end

# save figure
save(fn, fig)
fig
end # sizepage()

Appendix C

The following Julia code generates figures 3.1, 3.2, and 4.4.

# market.jl: directed graph of market requirements
using GLMakie
using Printf

function market()
# initialize data
ls = 0.74 # arrow lengthscale
vfs = 34 # vertex font size

# initialize diagram data
XY::Matrix{Float32} = [ # locations of vertices
0 1;
0 2;
0 3;
0 4]
TOI::Vector{Vector{Int64}} = [ # arrow directions
[2],
[3],
[4],
[]]
VT = [ # vertex text
"mutual understanding",
"trust",
"cooperation",
"legal enforcement of contracts"]
XYUVMT = [ # mid arrow text
"enables",
"enables",
"enables",
""]

# generate arrows from vertices
XYUV = Matrix{Float32}(undef, 0, 4)
row = zeros(Float32, 1, 4)
nXY = size(XY,1)
for iXY = 1:nXY
nHead = length(TOI[iXY])
for iHead = 1:nHead
row[1:2] = XY[iXY,:]
row[3:4] = XY[TOI[iXY][iHead],:]
XYUV = vcat(XYUV, row)
end
end

# convert arrow columns from absolute to relative
XYUV[:,3:4] = XYUV[:,3:4] - XYUV[:,1:2]
XYUVM = XYUV[:,1:2] + 0.5.*XYUV[:,3:4]

# initialize figure
fig = Figure(size = (600, 800))
ax = Axis(fig[1,1],
limits = (-2,2, 0.85,4.25),
title = "functioning market\nrequirements",
titlesize = 40)
hidedecorations!(ax)
hidespines!(ax)

# plot figure
arrows!( # gray arrows
XYUV[:,1],
XYUV[:,2],
XYUV[:,3],
XYUV[:,4],
arrowsize = 25,
lengthscale = ls,
color = :gray)
text!(XY[:,1], XY[:,2],
text = VT,
align = (:center, :center),
fontsize = vfs)
text!(XYUVM[:,1], XYUVM[:,2],
text = XYUVMT,
align = (:center, :center),
color = :gray,
fontsize = vfs/2)

save("market.png", fig)
fig
end # market()

function market2()
# initialize data
ls = 0.74 # arrow lengthscale
vfs = 34 # vertex font size

# initialize diagram data
XY::Matrix{Float32} = [ # locations of vertices
0 0; # 1
-7 0.6;
7 0.6; # 3
0 1;
0 2; # 5
-7 2.6;
7 2.6; # 7
0 4;
0 4.5; # 9
0 5]
TOI::Vector{Vector{Int64}} = [ # arrow directions
[2,3,4],# 1
[5],
[5], # 3
[5],
[6,7,8],# 5
[8],
[8], # 7
[9],
[10], # 9
[]]
VT = [ # vertex text
"overcoming disability", # 1
"overcoming discouragement",
"overcoming disinclination",# 3
"mutual understanding",
"trust", # 5
"overcoming disincentives",
"overcoming distance", # 7
"cooperation",
"legal enforcement of contracts",
"overcoming discrimination"]

# generate arrows from vertices
XYUV = Matrix{Float32}(undef, 0, 4)
row = zeros(Float32, 1, 4)
nXY = size(XY,1)
for iXY = 1:nXY
nHead = length(TOI[iXY])
for iHead = 1:nHead
row[1:2] = XY[iXY,:]
row[3:4] = XY[TOI[iXY][iHead],:]
XYUV = vcat(XYUV, row)
end
end

# convert arrow columns from absolute to relative
XYUV[:,3:4] = XYUV[:,3:4] - XYUV[:,1:2]

# initialize figure
fig = Figure(size = (1200, 800))
ax = Axis(fig[1,1],
limits = (-15,15, -0.25,5.25),
title = "functioning job market " *
"for the blind",
titlesize = 45)
hidedecorations!(ax)
hidespines!(ax)

# plot figure
IGRAY = [6,9,12]
arrows!( # gray arrows
XYUV[IGRAY,1],
XYUV[IGRAY,2],
XYUV[IGRAY,3],
XYUV[IGRAY,4],
arrowsize = 25,
lengthscale = ls,
color = :gray)
IORANGE = setdiff(1:13,IGRAY)
arrows!( # green arrows
XYUV[IORANGE,1],
XYUV[IORANGE,2],
XYUV[IORANGE,3],
XYUV[IORANGE,4],
arrowsize = 25,
lengthscale = ls,
linewidth = 5,
color = :orange)
text!(XY[:,1], XY[:,2],
text = VT,
align = (:center, :center),
fontsize = vfs)

save("market2.png", fig)
fig
end # market2()

function market3()
# initialize data
DC = [ # col 1: Display pin count (thousands); col 2: Cost of display (thousands)
0.128 2.795; # Actilino 3.0; see https://irie-at.com/product/actilino-3-0/
0.320 6.495; # Active Braille; see https://www.northstateat.com/Active-Braille_p_263.html
0.160 2.295; # Basic Braille 20 cells; see https://www.northstateat.com/Basic-Braille-BT-by-Help-Tech_p_261.html
0.320 3.295; # Basic Braille 40 cells; see https://www.northstateat.com/Basic-Braille-BT-by-Help-Tech_p_261.html
0.384 4.695; # Basic Braille 48 cells; see https://www.northstateat.com/Basic-Braille-BT-by-Help-Tech_p_261.html
0.512 6.995; # Basic Braille 64 cells; see https://www.northstateat.com/Basic-Braille-BT-by-Help-Tech_p_261.html
0.640 8.995; # Basic Braille 80 cells; see https://www.northstateat.com/Basic-Braille-BT-by-Help-Tech_p_261.html
0.160 2.407; # Brailliant BI 20X; see https://store.humanware.com/heu/braille-devices/braille-displays
0.256 2.595; # Brailliant BI 32; see https://www.bapingroup.com/brailliant-bi-32.html
0.320 3.931; # Mantis Q40; see https://store.humanware.com/heu/braille-devices/braille-displays
0.640 9.646; # Brailliant B 80; see https://store.humanware.com/heu/brailliant-80.html
0.112 1.545; # Focus 14 Blue; see https://store.freedomscientific.com/products/focus-14-blue-5th-generation
0.320 3.570; # Focus 40 Blue; see https://store.freedomscientific.com/products/focus-40-blue-5th-generation
0.640 9.520; # Focus 80 Blue; see https://store.freedomscientific.com/collections/all/products/focus-80-blue-5th-generation
0.320 2.795; # Braille Edge 40; see https://braillerdepot.com/products_page.html
0.112 1.395; # Smart Beetle; see https://braillerdepot.com/products_page.html
0.320 2.695; # ALVA USB 640; see https://braillerdepot.com/products_page.html
0.640 7.995; # ALVA BC680; see https://braillerdepot.com/products_page.html
0.320 2.595; # Braille 40 v5; see https://braillerdepot.com/products_page.html
0.320 2.395; # Braille 40 v3; see https://braillerdepot.com/products_page.html
0.640 3.995; # Braille 80 (formerly Seika); see https://braillerdepot.com/products_page.html
0.128 1.549; # Perkins Mini; see https://braillerdepot.com/products_page.html
0.096 1.595; # EasyLink 12; see https://braillerdepot.com/products_page.html
0.320 5.450; # Vario 340; see https://www.specialneedscomputers.ca/index.php?l=product_detail&p=6169
0.160 4.340; # Vario Ultra 20; see https://www.specialneedscomputers.ca/index.php?l=product_detail&p=6168
0.320 8.106; # Vario Ultra 40; see https://www.specialneedscomputers.ca/index.php?l=product_detail&p=6168
0.640 16.450;# VarioPro; see https://www.specialneedscomputers.ca/index.php?l=product_detail&p=6170
9.216 0.200; # expected low end cost of tactile display
9.216 0.500] # expected high end cost of tactile display
m = size(DC,1) - 2 # row count of market data

# initialize figure
fig = Figure(size = (1200, 800))
ax = Axis(fig[1,1],
title = "prices of refreshable braille displays " *
"currently on the market\n" *
"(the slope of the least squared error line " *
"fit is \$14.37 per display pin)",
titlesize = 25,
limits = (0,9.5, 0,18),
xlabel = "number of display pins (unit: 1000 display pins)",
xlabelsize = 24.0,
ylabel = "price (unit: 1000 US dollars)",
ylabelsize = 24.0)

# plot price data of refreshable displays on market
scatter!(DC[1:m,:],
color = :black)

# calculate and plot linear L.S.E. fit
A = [ones(m) DC[1:m,1]]
b = DC[1:m,2]
x = A \ b # x[1] is intercept; x[2] is slope
maxPrice = maximum(DC[1:m,2])
lines!(
[0, (maxPrice-x[1])/x[2]],
[x[1], maxPrice],
color = :gray,
linestyle = :dot)
println("intercept,slope: $x")

# plot expected price range of proposed tactile display
scatterlines!(
DC[m+1:end,1],
DC[m+1:end,2],
color = :green)

save("market3.png", fig)
fig
end # market3()

--

--

Greg Sepesi

software engineer pondering basic stuff like how to read