# Layout

## Concept

Positioning pictures relative to other pictures is important for many compositions, and the Layout algebra provides a flexible system for handling this.

### Above, Beside, and On

The most basic layout methods are `above`, `beside`, and `on`. They do what their names suggest, putting a picture above, beside, or on top of another picture. Below is an example.

``````import doodle.core.*
import doodle.java2d.*
import doodle.syntax.all.*

val basicLayout =
Picture
.circle(100)
.strokeColor(Color.blue)
.beside(Picture.square(100).strokeColor(Color.darkBlue))
.above(Picture.triangle(100, 100).strokeColor(Color.crimson))
.strokeWidth(5.0)``````

Here's the output this creates.

As a convenience, there are also methods `below` and `under`, which are the opposite of `above` and `on` respectively. That is, `a.above(b) == b.below(a)` and `a.on(b) == b.under(a)`

### Bounding Box and Origin

To really understand how layout works we have to understand how layout works with the bounding box and origin. Every picture has a bounding box and origin. The bounding box defines the outer extent of the picture, and the origin is an arbitrary point within the bounding box. By convention, the built-in shapes and paths have their origin in the center of the bounding box. You can position the origin anywhere you want, either by creating your own paths or using the `at` and `originAt` methods described below. If necessary, the bounding box will expand to include the origin.

We can see the bounding box and origin using the `debug` method. In the example below I'm displaying the bounding box and origin of the circle and pentagon separately, above the bounding box and origin of the circle beside the pentagon.

``````val debugLayout =
Picture
.circle(100)
.debug
.beside(Picture.regularPolygon(5, 30).debug)
.above(
Picture.circle(100).beside(Picture.regularPolygon(5, 30)).debug
)``````

This gives us some insight into how the basic layout works. Using `beside` horizontally aligns the origins of the two pictures, the creates a new bounding box enclosing the two existing boxes with the new origin in the middle of the line joining the two origins. `Above` works similarly, except the alignment is vertical, while `on` simply places the origins at the same location.

### Repositioning the Origin

The origin defines a local coordinate system for each picture, and the origin is always the point (0, 0). Changing the location of the origin is the key to creative layouts. There are two methods that do this:

• `at`, which changes the location of the picture relative to the origin; and
• `originAt`, which changes the location of the origin relative to the picture.

As you can see from the description, the two methods are opposites of one another. Let's see an example of use.

``````val atAndOriginAt =
Picture
.circle(100)
.at(25, 25)
.debug
.beside(Picture.circle(100).originAt(25, 25).debug)``````

When you want to position pictures at arbitrary locations, a common pattern is to use `at` and `on`. For example, here we position five shapes at the points of a pentagon. This also demonstrates we can use polar coordinates with `at`.

``````val pentagon =
Picture
.circle(10)
.at(50, 0.degrees)
.on(Picture.circle(10).at(50, 72.degrees))
.on(Picture.circle(10).at(50, 144.degrees))
.on(Picture.circle(10).at(50, 216.degrees))
.on(Picture.circle(10).at(50, 288.degrees))``````

### Positioning using Landmarks

Landmark provides more flexible layout, by allowing you to specify points relative to the bounding box or origin instead of in absolute terms relative to the origin. For example, we can specify the top left of the bounding box by simply using `Landmark.topLeft` instead of working out the coordinates of this location. Both `at` and `originAt` support landmarks.

Ultimately, all landmarks are specified relative to the origin, but you can use a percentage Coordinate instead of an absolute value. Zero percent is the origin, 100% is the top or right edge of the bounding box, and -100% is the bottom or left edge of the bounding box.

In the example below we use landmarks to specify points that are halfway between the origin and the edge of the bounding box. In this simple example we could easily work out the absolute coordinate directly, but landmarks come into their own in more complex examples.

``````val overlappingCircles =
Picture
.circle(100)
.originAt(Landmark(Coordinate.percent(50), Coordinate.percent(-50)))
.on(
Picture
.circle(100)
.originAt(Landmark(Coordinate.percent(-50), Coordinate.percent(-50)))
)
.on(
Picture
.circle(100)
.originAt(Landmark(Coordinate.percent(-50), Coordinate.percent(50)))
)
.on(
Picture
.circle(100)
.originAt(Landmark(Coordinate.percent(50), Coordinate.percent(50)))
)``````

The `size` and `margin` methods allow direct manipulation of the bounding box. We will show examples below to generate this image:

We can directly adjust the size of the bounding box using `size`, which sets the width and height of the bounding box to the given values. These values must be non-negative, and the resulting bounding box distributes the width and height equally between the left and right, and top and bottom, respectively. Here's an example where we set the width and height to different values, and use `debug` to draw the resulting bounding boxes.

``````val rollingCirclesSize =
circle
.size(100, 25)
.debug
.beside(circle.size(80, 20).debug)
.beside(circle.size(50, 15).debug)
.beside(circle.size(20, 10).debug)
.beside(circle.size(0, 0).debug)``````

To adjust the existing bounding box we can use `margin`. This allows us to add extra space around a picture or, with a negative margin, to have a picture that overflows its bounding box. Here's an example that uses the form of `margin` that adjusts both the width and height of the bounding box. There are other variants that allow us to adjust the width and the height separately, or adjust all four edges independently.

``````val circle = Picture.circle(50)
val rollingCirclesMargin =
circle
.margin(25)
.debug
.beside(circle.margin(15).debug)
.beside(circle.debug)
.beside(circle.margin(-15).debug)
.beside(circle.margin(-25).debug)``````

## Implementation

The `Layout` algebra supports all the features described above, as does `Image`.

Style→