#### Composing pictures

To build the traffic light picture we presented at the beginning of this section, the different Picture values for the lights will have to be combined together. The Picture type provides three basic composition operators:

• Overlays take the sum of two pictures, combining two Picture values by aligning their origins and drawing one on top of the other: @tindex{PicOverlay}

data Picture =
...
| PicOverlay Picture Picture
...


i.e., Overlay picA picB is a picture formed by putting picA on top of picB, so that their origins match up: \hbox{ \hspace{0.5in} \begin{minipage}[b]{2in} \begin{verbatim} picture = Overlay (ellipse (40,20)) (ellipse (20,40)) \end{verbatim} \end{minipage} \vbox{\vspace*{0.3in} \psfig{figure=overlay.eps}}}
picture =
PicOverlay
(ellipse (40,20))
(ellipse (20,40))

The bounding box of the combined picture is the bounding box of the union of the bounding boxes for the two pictures.
• Clipping combines two pictures by aligning their origins like PicOverlay, but interprets one picture as defining the clip mask to be used when drawing the second: @tindex{PicClip}

...
| PicClip Picture Picture
..


Clip clip clipped is a new picture that clips the second picture by the clip mask defined by the first: \hbox{ \hspace{0.5in} \begin{minipage}[b]{2.3in} \begin{verbatim} picture = PicClip (Pen largeFont (text "Clip")) (lines 500) lines l = foldl1 (Overlay) [ rline (l*cos a,l*sin a) | a <- [0,(pi/72)..2*pi] \end{verbatim} \end{minipage} \vbox{\psfig{figure=clip.eps} \vspace*{0.1in}}} \vspace{0.2in}
picture =
PicClip
(Pen largeFont (text "Clip"))
(lines 500)
lines l =
foldl1 (Overlay)
[ rline (l*cos a,l*sin a)
| a <- [0,(pi/72)..2*pi]


The bounding box of the constructed picture is equal to the bounding box of the picture describing the clip mask.
• Constrained overlay. The picture union operator, PicOverlay, allows you to combine two Picture values, but the composition does not impose any constraints between the sizes of the two Pictures combined. Having an overlay operator that imposes such constraints between the two pictures turns out to be quite useful in a number of cases, e.g.,

inBox :: Picture -> Picture


is a picture combinator that puts a bounding rectangle around an arbitrary picture. This combinator could of course be expressed if we had a function for computing the bounding box of a picture, but in the same way as in See section Structured translation, we introduce a higher-level mechanism for expressing size constraints between two pictures being combined: @tindex{ConstrainOverlay} @tindex{RelSize}

...
| ConstrainOverlay RelSize RelSize
Picture Picture

data RelSize
= None
| Fixed Which Int
| Prop  Which Double

data Which = First | Second


ConstrainOverlay None (Prop Second 2.0) picA picB is a picture that when rendered, will align the origins of picA and picB, drawing picA on top of picB. The operator will also scale picB in the Y direction such that the size of its bounding box will double that of picA along this axis (the Which value indicates which of the two pictures is constrained). The RelSize data type contains the different types of size constraints we can place between the two dimensions, None indicates that no size constraints should be imposed, Fixed that the lengths should differ by a fixed amount. The ConstrainOverlay constructor provides a superset of the functionality of Overlay,

PicOverlay = ConstrainOverlay None None


but we choose to provide the PicOverlay constructor separately, due to its frequent occurrence in pictures.

Combining the PicOverlay operator with the structured translation operator in Section See section Structured translation, picture combinators that tile two pictures together can be expressed:


beside :: Picture -> Picture -> Picture
beside picA picB =
Overlay
(Move (OffDir East) picA)
(Move (OffDir West) picB)

above :: Picture -> Picture -> Picture
above picA picB =
Overlay
(Move (OffDir South) picA)
(Move (OffDir North) picB)



The beside combinator overlays two pictures, but translates their local origins such that picA will be shifted to the left of the vertical axis and picB wholly to the right. The combinator above uses the same trick, but this time the translation is with respect to the horizontal axis.

As an example of these various composition operators, we can finally present the construction of the traffic light example presented at the beginning of this section, starting with a combinator for placing an arbitrary text string within a coloured oval:


light :: Colour -> String -> Picture
light col lab =
ConstrainOverlay
(Fixed Second 20)
(Fixed Second 20)
(withColour black $centre$ Text lab)
(filledCircle col 2)



The light combinator centres the text string lab within an ellipse that has horizontal and vertical extent 20 units bigger than that of the extent of the picture representing the string. Using this combinator we can construct the pictures for the individual lights:


redTLight    = light red    "R"
orangeTLight = light orange "O"
greenTLight  = light green  "G"



To align the lights horizontally, we want to use the horizontal tiling operator beside, but want to add some air' between the lights first:


besideSpace :: Unit -> Picture -> Picture -> Picture
besideSpace spc picA picB =
beside
picA
(Transform (xlt (spc,0)) \$
moveWest picB)



besideSpace uses a Transform constructor to enlarge the bounding box of picB before invoking beside. The three traffic lights then become just:

\vspace{0.15in} \hbox{ \hspace{0.5in} \begin{minipage}[b]{2in} \begin{verbatim} lights = foldr1 (besideSpace 10) [redTLight, orangeTLight, greenTLight] \end{verbatim} \end{minipage} \vbox{\vspace*{0.3in} \psfig{figure=lights.eps}}}

lights =
foldr1
(besideSpace 10)
[redTLight, orangeTLight,
greenTLight]


The final step is then adding a black background for the casing of the traffic lights:

\vspace{0.15in} \hbox{ \hspace{0.5in} \begin{minipage}[b]{2in} \begin{verbatim} trafficLight = ConstrainOverlay (Fixed Second 20) (Fixed Second 20) (Move (OffDir Centre) lights) (Move (OffDir Centre) (Rectangle (2,2))) \end{verbatim} \end{minipage} \vbox{\psfig{figure=tlight.eps} \vspace*{0.3in}}}

trafficLight =
ConstrainOverlay
(Fixed Second 20)
(Fixed Second 20)
(Move (OffDir Centre)
lights)
(Move (OffDir Centre)
(Rectangle (2,2)))
`

This example, while small, demonstrates the compositional programming style that follows naturally, where complete Pictures are formed by repeatedly applying picture combinators to existing Pictures.