# What does the `align` argument do in this Asymptote code?

The following code produces the output

``````picture pic1;
size(pic1,10);
fill(pic1,(0,0)--(5,10)--(10,0)--cycle,red+opacity(0.5)); // triangle

picture pic2;
size(pic2,10);
fill(pic2,unitcircle,green+opacity(0.5)); // circle

picture pic;

`````` However, if I change the line `add(pic,pic1.fit(),position = (0,0));` to `add(pic,pic1.fit(),position = (0,0),align=N);` I get the output I expected the red-triangle to have shifted slightly north from its position in the first picture. Where am I going wrong in understanding the functions behavior?

• This is AFAIK the alignment anchor, whereby unfortunately the meaning is sort of opposite to what it is in TikZ. In the first picture, the triangle's left corner is at (0,0) because of the way you draw it, i.e. in the pic (0,0) is the left corner. In the second pic the southern anchor is at at (0,0), so roughly speaking TikZ's `anchor=south` corresponds to `align=N` (and to PStricks' `\rput[b]{...}`). – marmot Apr 14 at 15:51
• I am not sure I follow. Can you please explain it a little more? By anchor do you mean the edges of the bounding box of the figure? – smilingbuddha Apr 14 at 17:45

Hy

In fact I started to write some test examples for `align` a few months ago (due to your question What does the .fit() method of a picture do?). There was also a discussion on Asymptote forum help due to some behavior. Please find some explanations, codes, pictures. I hope it will help Asymptote users.

Tests 1 : simple `pic.fit()` no `align` argument

From left to right and top to bottom. A picture `pic1` is created (with `keepAspect=false`) and is added with various `pic.fit(x.size, y.size,keepAspect)`.

case 1 : `pic1` is added at (1.2,.5) coordinates point. No extra argument

case 2 : `pic1.fit(2*xs,ys,keepAspect=true)`. Due to `keepAspect=true` `pic1` is not scaled (the minimum is chosen)

case 3 : `pic1` is enlarged by 2 `pic1.fit(2*xs,ys)`. Since `keepAspect=false` (precised for pic1) the `y` coordinate is not scaled

case 3 : `pic1.fit(2*xs,3*ys,keepAspect=true)` `pic1` is scaled (`x` and `y by 2=min(2,3))

In cases 3 and 4 it is worth noting that the fixed size object (label, linewidth) are not scaled. Please also notice that the `(0,0)` coordinate of `pic1` is the left bottom.

``````size(10cm);

picture pic1;
size(pic1,2cm,keepAspect=false);
label(pic1,"T",(.5,.5));
label(pic1,"O",(1,1),SW);
draw(pic1,unitsquare);
draw(pic1,(.5,.5)--(1,1));

frame f1=pic1.fit();
dot((.5,1.2),blue);

real xs=pic1.xsize;
real ys=pic1.ysize;

frame f2=pic1.fit(2*xs,ys,keepAspect=true);
dot((1.5,1.2),blue);

frame f3=pic1.fit(2*xs,ys);
dot((.5,.5),blue);

frame f4=pic1.fit(2*xs,3*ys,keepAspect=true);
dot((1.5,.5),blue);
`````` Tests 2 : `pic.fit()` and `align` arguments

With respect to the first tests, the `(0,0)` coordinate of `pic1` is not the left-bottom (the rectangle is shift). As mentionned in the Asymptote documentation `pic1` will be aligned so that the origin is at position (here `(.5,1)`) of the current picture. (see the cases 1 and 2)

Case 1: no option is given. The origin of `pic1` is at position `(.5,1)` of the current picture.

Case 2: `pair align` option is given : `(0,0)`. Then `pic1` is aligned so that the center of `pic1` is at position `(.9,1)` of the current picture.

Case 3: From the documentation, the constant `Align` can be used to align the bottom-left corner of the label at position. `Align` is a `pair`, so that using `+/-Align.x`, `+/-Align.y` we can align `pic1` at {Left/Mid/Right}/{Top/Mid/Bottom} point. Here `pair align=(Align.x,0)` and `position=(.5,.7)`. It means that `pic1` will be aligned in the direction of `(Align.x,0)` (which is equivalent to `(1,0)`) and displaced from `position=(.5,.7)` by the PostScript offset `(Align.x,0)*labelmargin(p)`.

Case 4: another illustration of case 3, align to a point of the border of `pic2`. `add(f4,(1,.9),(-2*Align.x,-5*Align.y))`. The green line is added to `pic1` to obtain `pic2`, `pair l=truepoint(pic2,(2,5))` allows one to place the point on the border. Following the documentation `truepoint(picture pic=currentpicture, pair dir, bool user=true)` is a convenient way of determining the point on the bounding box of pic in the direction dir relative to its center (and here including the fixed-size objects).

Case 5: `Align.x` value is 1.05367121277235e-08. What happens with larger value ? Here we choose `add(f5,(.5,.7),(10,15))`. Following the documentation it will be aligned in the direction of `(10,15)` and displaced from `(.5,.7)` (the currend picture) by the PostScript offset `(10,15)*labelmargin(p)`. To illustrate the obtained boundary point of `pic2`, a line is added with `draw((.5,.7),(0,0)--(10,15),linecap(0)+red)` : allows one to draw a fixed-sized object (in PostScript coordinates, the (0,0)--(10,15) line) about the user coordinate origin `(.5,.7)`. It is worth noting that the red and blue lines have a common end.

Case 6: similar to case 5 with a position in cm. You can verify that the distance from the dot to the left-bottom corner is equal to 2cm.

``````size(9cm);

picture pic1;
size(pic1,3cm);
label(pic1,"T",(.5,.5));
label(pic1,"O",(1,1),SW);
draw(pic1,shift(0,.2)*scale(2,1)*unitsquare);
draw(pic1,(.5,.5)--(1,1));

frame f1=pic1.fit();

dot((.5,1));

dot((.9,1.05));

dot((.5,.9));

picture pic2;
size(pic2,3cm);
pair l=truepoint(pic2,(2,5));
draw(pic2,l--(l.x,.5),green+linecap(0));
frame f4=pic2.fit();
dot((1,.95));

pair l=truepoint(pic1,(-10,-15));
draw(pic1,l--(l.x,.5),blue+linecap(0));
frame f5=pic1.fit();
dot((.5,.7));
write(labelmargin(currentpen));
draw((.5,.7),(0,0)--(10,15),linecap(0)+red);

dot((.75,.7));
draw((.75,.7),(0,0)--1cm*unit((1,1)),linecap(0)+red);
`````` Tests 3: `add(pic1)` vs `add(pic1.fit())`, scaling

Case 1: no option no position. `add(pic1)` is equivalent to the apply the draw command of `pic1` to the current picture

Case 2: no option is given, only the position `(4,.5)`. Surprise ! The adding picture is tiny ! In fact as mentioned in the documentation, `add(pic1,(4,.5))` will add `pic1` specified in Postcript coordinates to the currentpicture.

Case 3: the standard `pic1.fit` at position `(0,2)`.

Case 4: by scaling `pic1` into `pic2` with an appropriate value, we have an equivalent of `pic1.fit`, at position `(3,-2)`. It is worth noting that fixed scaled object (Labels) are not scaled.

Case 5: scaling by a factor 3 in the x direction with respect to the y direction the picture `pic1`. Fixed scaled object (Labels) are not scaled.

Case 6: scaling by a factor 3 in the x direction `pic1.fit()`. Fixed scaled object (Labels, linewidth) are `x`-scaled. */

``````size(8cm);

//label("Picture test",(1,1));
draw(shift(3,-2)*scale(8)*shift((-.5,-.5))*unitsquare);

/*
Last test: the difference between scaling/adding picture to picture and frame to picture.
*/

picture pic1;
size(pic1,2cm);
label(pic1,"T",(.5,.5));
label(pic1,"O",(1,1),SW);
draw(pic1,scale(2,1)*unitsquare);
draw(pic1,(.5,.5)--(1,1));

/* is equivalent to
label("T",(.5,.5));
label("O",(1,1),SW);
draw(scale(2,1)*unitsquare);
draw((.5,.5)--(1,1));
*/
dot((0,0),blue); // is at the origin of `add(pic1)`

frame f1=pic1.fit();

picture pic2;
pic2=(scale(size(pic1).x/size(pic1,user=true).x)*pic1); 