It is sometimes desirable to have elements of a fixed absolute size,
independent of the picture scaling from user to
PostScript
coordinates.
For example, normally one would want the size of a dot created with
dot
, the size of the arrowheads created with arrow
(see arrows), and labels to be drawn independent of the scaling.
However, because of Asymptote
’s automatic scaling feature (see Figure size),
the translation between user coordinate and PostScript
coordinate
is not determined until shipout time:
size(1cm); dot((0,0)); dot((1,1)); shipout("x"); // at this point, 1 unit coordinate = 1cm dot((2,2)); shipout("y"); // at this point, 1 unit coordinate = 0.5cm
It is therefore necessary to defer the drawing of these elements until shipout time.
For example, a frame can be added at a specified user coordinate of a
picture with the deferred drawing routine
add(picture dest=currentpicture, frame src, pair position)
:
frame f; fill(f,circle((0,0),1.5pt)); add(f,position=(1,1),align=(0,0));
A deferred drawing routine is an object of type drawer
,
which is a function with signature void(frame f, transform t)
.
For example, if the drawing routine
void d(frame f, transform t){ fill(f,shift(3cm,0)*circle(t*(1,1),2pt)); }
is added to currentpicture
with
currentpicture.add(d);
a filled circle of radius 2pt will be drawn on currentpicture centered
3cm to the right of user coordinate (1,1)
. The parameter t
is the
affine transformation from user coordinates to PostScript
coordinates.
Even though the actual drawing is deferred, you still need to specify to the
Asymptote
scaling routines that ultimately a fixed-size circle
of radius 2pt will be drawn 3cm to the right of user-coordinate (1,1),
by adding a frame about (1,1) that extends beyond (1,1) from
(3cm-2pt,-2pt)+min(currentpen)
to
(3cm+2pt,2pt)+max(currentpen)
, where we have even
accounted for the pen linewidth. The following example will then
produce a PDF file 10 cm wide:
settings.outformat="pdf"; size(10cm); dot((0,0)); dot((1,1),red); add(new void(frame f, transform t) { fill(f,shift(3cm,0)*circle(t*(1,1),2pt)); }); pair trueMin=(3cm-2pt,-2pt)+min(currentpen); pair trueMax=(3cm+2pt,2pt)+max(currentpen); currentpicture.addPoint((1,1),trueMin); currentpicture.addPoint((1,1),trueMax);
Here we specified the minimum and maximum user and truesize (fixed)
coordinates of the drawer with the picture
routine
void addPoint(pair user, pair truesize);
Alternatively, one can use
void addBox(pair userMin, pair userMax, pair trueMin=0, pair trueMax=0) {
to specify a bounding box
with bottom-left corner t*(1,1)+trueMin
and top-right corner t*(1,1)+trueMax
,
where t
is the transformation that transforms
from user coordinates to PostScript
coordinates.
For more details about deferred drawing, see “Asymptote: A vector graphics language,” John C. Bowman and Andy Hammerlindl, TUGBOAT: The Communications of the TeX Users Group, 29:2, 288-294 (2008),
https://www.math.ualberta.ca/~bowman/publications/asyTUG.pdf.