Asymptote: The Vector Graphics Language
Asymptote: The Vector Graphics Language
Language
John Bowman and Andy Hammerlindl
Department of Mathematical and Statistical Sciences
University of Alberta
Collaborators: Orest Shardt, Michail Vidiassov
https://asymptote.sourceforge.io/intro.pdf 1
History
• 1979: TEX and METAFONT (Knuth)
2
Statistics (as of June, 2010)
• Runs under Linux/UNIX, Mac OS X, Microsoft Windows.
3
Vector Graphics
• Raster graphics assign colors to a grid of pixels.
• Vector graphics are graphics which still maintain their look when
inspected at arbitrarily small scales.
4
Cartesian Coordinates
• Asymptote’s graphical capabilities are based on four primitive
commands: draw, label, fill, clip [?]
draw((0,0)--(100,100));
5
Scaling to a Given Size
• PostScript units are often inconvenient.
• Instead, scale user coordinates to a specified final size:
size(3cm);
draw((0,0)--(1,0)--(1,1)--(0,1)--cycle);
6
Labels
• Adding and aligning LATEX labels is easy:
size(6cm);
draw(unitsquare);
label("$A$",(0,0),SW);
label("$B$",(1,0),SE);
label("$C$",(1,1),NE);
label("$D$",(0,1),NW);
D C
A B
7
2D Bézier Splines
• Using .. instead of -- specifies a Bézier cubic spline:
draw(z0 .. controls c0 and c1 .. z1,blue);
c0 c1
z0 z1
8
Smooth Paths
• Asymptote can choose control points for you, using the algorithms of
Hobby and Knuth [?, ?]:
pair[] z={(0,0), (0,1), (2,1), (2,0), (1,0)};
draw(z[0]..z[1]..z[2]..z[3]..z[4]..cycle,
grey+linewidth(5));
dot(z,linewidth(7));
9
Filling
• The fill primitive to fill the inside of a path:
path star;
for(int i=0; i < 5; ++i)
star=star--dir(90+144i);
star=star--cycle;
fill(star,orange+zerowinding);
draw(star,linewidth(3));
fill(shift(2,0)*star,blue+evenodd);
draw(shift(2,0)*star,linewidth(3));
10
Filling
• Use a list of paths to fill a region with holes:
path[] p={scale(2)*unitcircle, reverse(unitcircle)};
fill(p,green+zerowinding);
11
Clipping
• Pictures can be clipped to a path:
fill(star,orange+zerowinding);
clip(scale(0.7)*unitcircle);
draw(scale(0.7)*unitcircle);
12
Affine Transforms
• Affine transformations: shifts, rotations, reflections, and scalings can
be applied to pairs, paths, pens, strings, and even whole pictures:
fill(P,blue);
fill(shift(2,0)*reflect((0,0),(0,1))*P, red);
fill(shift(4,0)*rotate(30)*P, yellow);
fill(shift(6,0)*yscale(0.7)*xscale(2)*P, green);
13
C++/Java-like Programming Syntax
// Declaration: Declare x to be real:
real x;
14
Modules
• There are modules for Feynman diagrams,
e− µ+
k p′
q
k′ p
e+ µ−
data structures,
2 3
4 0 6 7
15
algebraic knot theory:
5 0 1
4 3 2
ΦΦ(x1, x2, x3, x4, x5) =ρ4b(x1 + x4, x2, x3, x5) + ρ4b(x1, x2, x3, x4)
+ρ4a(x1, x2 + x3, x4, x5) − ρ4b(x1, x2, x3, x4 + x5)
−ρ4a(x1 + x2, x3, x4, x5) − ρ4a(x1, x2, x4, x5).
16
Textbook Graph
import graph;
size(150,0);
draw(graph(f,-4,2,operator ..),red);
xaxis("$x$");
yaxis("$y$",0);
ex
labely(1,E);
label("$eˆx$",F(1),SE); 1
17
Scientific Graph
import graph;
size(250,200,IgnoreAspect);
draw(graph(Sin,0,1),red,"$\sin(2\pi x)$");
draw(graph(Cos,0,1),blue,"$\cos(2\pi x)$");
xaxis("$x$",BottomTop,LeftTicks);
yaxis("$y$",LeftRight,RightTicks(trailingzero));
label("LABEL",point(0),UnFill(1mm));
attach(legend(),truepoint(E),20E,UnFill);
18
1.0
0.5
−1.0
0 0.2 0.4 0.6 0.8 1
x
19
Data Graph
import graph;
size(200,150,IgnoreAspect);
real[] x={0,1,2,3};
real[] y=xˆ2;
draw(graph(x,y),red);
xaxis("$x$",BottomTop,LeftTicks);
yaxis("$y$",LeftRight,
RightTicks(Label(fontsize(8pt)),new real[]{0,4,9}));
20
9
y
4
0
0 1 2 3
x
21
Imported Data Graph
import graph;
size(200,150,IgnoreAspect);
file in=input("filegraph.dat").line();
real[][] a=in;
a=transpose(a);
real[] x=a[0];
real[] y=a[1];
draw(graph(x,y),red);
xaxis("$x$",BottomTop,LeftTicks);
yaxis("$y$",LeftRight,RightTicks);
22
2
y 1
0
50 70 90 110
x
23
Logarithmic Graph
import graph;
size(200,200,IgnoreAspect);
scale(Log,Log);
draw(graph(f,0.1,10));
//limits((1,0.1),(10,0.5),Crop);
dot(Label("(3,5)",align=S),Scale((3,5)));
xaxis("$x$",BottomTop,LeftTicks);
yaxis("$y$",LeftRight,RightTicks);
24
101
(3,5)
y 100
10−1 −1
10 100 101
x
25
Secondary Axis
Proportion of crows
0.9 100
0.7
0.5 10−1
0.3
0.1 10−2
10 11 12 13 14 15
Time (τ )
26
Images and Contours
+1.0
6
+0.8
5 +0.6
+0.4
4
+0.2
f (x, y)
y 0.0
3
−0.2
2 −0.4
−0.6
1
−0.8
0 −1.0
0 1 2 3 4 5 6
x 27
sediment depth (cm)
400
300
200
100
0
A
25
ch
na
nt
50
he
s
m
A in
25
no ut
m is
si
oe m
a
50
on
ei K
s ue
A
vi tz
25
tr in
st
er
ea g
i on (G
el ru
la no
fo w
Ta )
be rm R
%
os os
lla a s
50 20 40
ri
a H
flo as
cc sa
ll
25
Fr
ag ul
os
ila
ri a
a (R
cf ot
h)
A
C .t
ha ene K
et ra ue
oc tz
er in
os g
A m
ul ue
ac lle
os
eir
ri
5
Multiple Graphs
Fr /e
a lm
ag
ila s pp or
.
4
Fr ri ei
ag a cy
50 20 40 20 40 10 8
ila a c st
ri p s
a uci
1763
1888
1950
1961
1965
1970
1972
1978
1980
1988
2000
1726 cr na
ot
B
on var
1915 1910
1920
1940 1942
1984 1982
1986
1992 1990
1996 1994
1998
en . v
si
s auc
K he
it
to ria
n e
(K
ue
tz
in
g)
C
28
Hobby’s 2D Direction Algorithm
• A tridiagonal system of linear equations is solved to determine any
unspecified directions ϕk and θk through each knot zk :
θk−1 − 2ϕk ϕk+1 − 2θk
= .
ℓk ℓk+1
φk
zk
θk
ℓk+1
zk+1
ℓk
zk−1
φ
ω1
z1
ω0 θ
z0
30
Bézier Curves in 3D
• Apply an affine transformation
x′i = Aij xj + Ci
to a Bézier curve:
3
X
x(t) = Bk (t)Pk , t ∈ [0, 1].
k=0
31
3D Generalization of Direction Algorithm
• Must reduce to 2D algorithm in planar case.
• Determine directions by applying Hobby’s algorithm in the plane
containing zk−1, zk , zk+1.
• The only ambiguity that can arise is the overall sign of the angles,
which relates to viewing each 2D plane from opposing normal
directions.
• A reference vector based on the mean unit normal of successive
segments can be used to resolve such ambiguities [?, ?]
32
3D Control Point Algorithm
• Express Hobby’s algorithm in terms of the absolute directions ω0
and ω1:
u = z0 + ω0 |z1 − z0| f (θ, −ϕ),
φ
ω1
z1
ω0 θ
z0
34
Lifting TeX to 3D
• Glyphs are first split into simply connected regions and then
decomposed into planar Bézier surface patches [?, ?]:
merge, bezulate
bezulate
35
Label Manipulation
• They can then be extruded and/or arbitrarily transformed:
36
Billboard Labels
37
Smooth 3D surfaces
38
Curved 3D Arrows
39
Slide Presentations
• Asymptote has a module for preparing slides.
title("Slide Presentations");
item("Asymptote has a module for preparing slides.");
40
Automatic Sizing
• Figures can be specified in user coordinates, then automatically scaled
to the desired final size.
y
y
(a, 0) (2a, 0) (a, 0) (2a, 0) (a, 0) (2a, 0)
x x x
size(0,50);
size(0,100);
size(0,200);
41
Deferred Drawing
• We can’t draw a graphical object until we know the scaling factors for
the user coordinates.
• Instead, store a function that, given the scaling information, draws
the scaled object.
void draw(picture pic=currentpicture, path g, pen p=currentpen) {
pic.add(new void(frame f, transform t) {
draw(f,t*g,p);
});
pic.addPoint(min(g),min(p));
pic.addPoint(max(g),max(p));
}
42
Coordinates
• Store bounding box information as the sum of user and true-size
coordinates:
pic.addPoint(min(g),min(p));
pic.addPoint(max(g),max(p));
• Filling ignores the pen width:
pic.addPoint(min(g),(0,0));
pic.addPoint(max(g),(0,0));
• Communicate with LATEX via a pipe to determine label sizes:
E = mc2
43
Sizing
• When scaling the final figure to a given size S, we first need to
determine a scaling factor a > 0 and a shift b so that all of the
coordinates when transformed will lie in the interval [0, S].
• That is, if u and t are the user and truesize components:
0 ≤ au + t + b ≤ S.
• Maximize the variable a subject to a number of inequalities.
• Use the simplex method to solve the resulting linear programming
problem.
44
Sizing
• Every addition of a coordinate (t, u) adds two restrictions
au + t + b ≥ 0,
au + t + b ≤ S,
and each drawing component adds two coordinates.
• A figure could easily produce thousands of restrictions, making the
simplex method impractical.
• Most of these restrictions are redundant, however. For instance, with
concentric circles, only the largest circle needs to be accounted for.
45
Redundant Restrictions
• In general, if u ≤ u′ and t ≤ t′ then
au + t + b ≤ au′ + t′ + b
for all choices of a > 0 and b, so
0 ≤ au + t + b ≤ au′ + t′ + b ≤ S.
• This defines a partial ordering on coordinates. When sizing a
picture, the program first computes which coordinates are maximal (or
minimal) and only sends effective constraints to the simplex algorithm.
• In practice, the linear programming problem will have less than a
dozen restraints.
• All picture sizing is implemented in Asymptote code.
46
Infinite Lines
• Deferred drawing allows us to draw infinite lines.
drawline(P, Q);
47
Helpful Math Notation
• Integer division returns a real. Use quotient for an integer result:
3/4 == 0.75 quotient(3,4) == 0
• Caret for real and integer exponentiation:
2ˆ3 2.7ˆ3 2.7ˆ3.2
• Many expressions can be implicitly scaled by a numeric constant:
2pi 10cm 2xˆ2 3sin(x) 2(a+b)
• Pairs are complex numbers:
(0,1)*(0,1) == (-1,0)
48
Function Calls
• Functions can take default arguments in any position. Arguments are
matched to the first possible location:
void drawEllipse(real xsize=1, real ysize=xsize, pen p=blue) {
draw(xscale(xsize)*yscale(ysize)*unitcircle, p);
}
drawEllipse(2);
drawEllipse(red);
49
Rest Arguments
• Rest arguments allow one to write a function that takes an arbitrary
number of arguments:
int sum(... int[] nums) {
int total=0;
for(int i=0; i < nums.length; ++i)
total += nums[i];
return total;
}
sum(1,2,3,4); // returns 10
sum(); // returns 0
sum(1,2,3 ... new int[] {4,5,6}); // returns 21
50
High-Order Functions
• Functions are first-class values. They can be passed to other functions:
import graph;
real f(real x) {
return x*sin(10x);
}
draw(graph(f,-3,3,300),red);
51
Higher-Order Functions
• Functions can return functions:
x
fn(x) = n sin .
n
func f1=f(1);
real y=f1(pi);
52
Anonymous Functions
• Create new functions with new:
path p=graph(new real (real x) { return x*sin(10x); },-3,3,red);
func f(int n) {
return new real (real x) { return n*sin(x/n); };
}
• Function definitions are just syntactic sugar for assigning function
objects to variables.
real square(real x) {
return xˆ2;
}
is equivalent to
real square(real x);
square=new real (real x) {
return xˆ2;
};
53
Structures
• As in other languages, structures group together data.
struct Person {
string firstname, lastname;
int age;
}
Person bob=new Person;
bob.firstname="Bob";
bob.lastname="Chesterton";
bob.age=24;
• Any code in the structure body will be executed every time a new
structure is allocated...
struct Person {
write("Making a person.");
string firstname, lastname;
int age=18;
}
Person eve=new Person; // Writes "Making a person."
write(eve.age); // Writes 18.
54
Modules
• Function and structure definitions can be grouped into modules:
// powers.asy
real square(real x) { return xˆ2; }
real cube(real x) { return xˆ3; }
and imported:
import powers;
real eight=cube(2.0);
draw(graph(powers.square, -1, 1));
55
Object-Oriented Programming
• Functions are defined for each instance of a structure.
struct Quadratic {
real a,b,c;
real discriminant() {
return bˆ2-4*a*c;
}
real eval(real x) {
return a*xˆ2 + b*x + c;
}
}
• This allows us to construct “methods” which are just normal functions
declared in the environment of a particular object:
Quadratic poly=new Quadratic;
poly.a=-1; poly.b=1; poly.c=2;
write(x1+x2()); // Writes 9.
write(x3(x1)+x2()); // Writes 11.
58
Overloading
• x1, x2, and x3 are never used in the same context, so they can all be
renamed x without ambiguity:
int x=2;
int x() {
return 7;
}
int x(int y) {
return 2y;
}
write(x+x()); // Writes 9.
write(x(x)+x()); // Writes 11.
• Function definitions are just variable definitions, but variables are
distinguished by their signatures to allow overloading.
59
Operators
• Operators are just syntactic sugar for functions, and can be addressed
or defined as functions with the operator keyword.
int add(int x, int y)=operator +;
write(add(2,3)); // Writes 5.
60
Operators
• Operators for constructing paths are also functions:
a.. controls b and c .. d--e
is equivalent to
operator --(operator ..(a, operator controls(b,c), d), e)
• This allowed us to redefine all of the path operators for 3D paths.
61
Summary
• Asymptote:
– uses IEEE floating point numerics;
– uses C++/Java-like syntax;
– supports deferred drawing for automatic picture sizing;
– supports Grayscale, RGB, CMYK, and HSV colour spaces;
– supports PostScript shading, pattern fills, and function shading;
– can fill nonsimply connected regions;
– generalizes MetaPost path construction algorithms to 3D;
– lifts TEX to 3D;
– supports 3D billboard labels and PDF grouping.
62
Asymptote: 2D & 3D Vector Graphics Language
https://asymptote.sourceforge.io
(freely available under the LGPL license)
63