0% found this document useful (0 votes)
20 views63 pages

Asymptote: The Vector Graphics Language

The document provides an overview of Asymptote, a vector graphics language developed for creating high-quality graphics, including 2D and 3D visualizations. It details the history, statistics, and key features of Asymptote, including its programming syntax, graphical capabilities, and various modules for specialized applications. Additionally, it discusses algorithms for generating Bézier curves and paths, along with examples of different types of graphs and visual representations.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views63 pages

Asymptote: The Vector Graphics Language

The document provides an overview of Asymptote, a vector graphics language developed for creating high-quality graphics, including 2D and 3D visualizations. It details the history, statistics, and key features of Asymptote, including its programming syntax, graphical capabilities, and various modules for specialized applications. Additionally, it discusses algorithms for generating Bézier curves and paths, along with examples of different types of graphs and visual representations.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 63

Asymptote: The Vector Graphics

Language
John Bowman and Andy Hammerlindl
Department of Mathematical and Statistical Sciences
University of Alberta
Collaborators: Orest Shardt, Michail Vidiassov

June 30, 2010

https://asymptote.sourceforge.io/intro.pdf 1
History
• 1979: TEX and METAFONT (Knuth)

• 1986: 2D Bézier control point selection (Hobby)

• 1989: MetaPost (Hobby)


• 2004: Asymptote
– 2004: initial public release (Hammerlindl, Bowman, & Prince)
– 2005: 3D Bézier control point selection (Bowman)
– 2008: 3D interactive TEX within PDF files (Shardt & Bowman)
– 2009: 3D billboard labels that always face camera (Bowman)
– 2010: 3D PDF enhancements (Vidiassov & Bowman)

2
Statistics (as of June, 2010)
• Runs under Linux/UNIX, Mac OS X, Microsoft Windows.

• 4000 downloads/month from primary


asymptote.sourceforge.io site alone.
• 80 000 lines of low-level C++ code.
• 36 000 lines of high-level Asymptote code.

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));

• units are PostScript big points (1 bp = 1/72 inch)


• -- means join the points with a linear segment to create a path
• cyclic path:
draw((0,0)--(100,0)--(100,100)--(0,100)--cycle);

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);

• One can also specify the size in cm:


size(3cm,3cm);
draw(unitsquare);

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

(1 − t)3z0 + 3t(1 − t)2c0 + 3t2(1 − t)c1 + t3z1, t ∈ [0, 1].

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));

• First, linear equations involving the curvature are solved to find


the direction through each knot. Then, control points along those
directions are chosen:

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;

// Assignment: Assign x the value 1.


x=1.0;

// Conditional: Test if x equals 1 or not.


if(x == 1.0) {
write("x equals 1.0");
} else {
write("x is not equal to 1.0");
}

// Loop: iterate 10 times


for(int i=0; i < 10; ++i) {
write(i);
}

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);

real f(real x) {return exp(x);} y


pair F(real x) {return (x,f(x));}

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);

real Sin(real t) {return sin(2pi*t);}


real Cos(real t) {return cos(2pi*t);}

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

y 0.0 LABEL sin(2πx)


cos(2πx)
−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);

real f(real t) {return 1/t;}

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

• The resulting shape may be adjusted by modifying optional tension


parameters and curl boundary conditions.
29
Hobby’s 2D Control Point Algorithm
• Having prescribed outgoing and incoming path directions eiθ at
node z0 and eiϕ at node z1 relative to the vector z1 − z0, the control
points are determined as:

u= z0 + eiθ (z1 − z0)f (θ, −ϕ),


v= z1 − eiϕ(z1 − z0)f (−ϕ, θ),
where the relative distance function f (θ, ϕ) is given by Hobby [1986].

φ
ω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

• The resulting curve is also a Bézier curve:


3
x′i(t) =
X
Bk (t)Aij (Pk )j + Ci
k=0
3
Bk (t)Pk′ ,
X
=
k=0 3
X
where Pk′ is the transformed k th control point, noting Bk (t) = 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 (θ, −ϕ),

v = z1 − ω1 |z1 − z0| f (−ϕ, θ),

φ
ω1
z1

ω0 θ

z0

interpreting θ and ϕ as the angle between the corresponding path


direction vector and z1 − z0.
• Here there is an unambiguous reference vector for determining the
relative sign of the angles ϕ and θ. 33
Interactive 3D Saddle
• A unit circle in the X–Yplane may be constructed with:
(1,0,0)..(0,1,0)..(-1,0,0)..(0,-1,0)..cycle:

and then distorted into the saddle


(1,0,0)..(0,1,1)..(-1,0,0)..(0,-1,1)..cycle:

34
Lifting TeX to 3D
• Glyphs are first split into simply connected regions and then
decomposed into planar Bézier surface patches [?, ?]:

merge, bezulate

partition 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);

• Arguments can be given by name:


drawEllipse(xsize=2, ysize=1);
drawEllipse(ysize=2, xsize=3, green);

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

int subtract(int start ... int[] subs) {


return start - sum(... subs);
}

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

typedef real func(real);


func f(int n) {
real fn(real x) {
return n*sin(x/n);
}
return fn;
}

func f1=f(1);
real y=f1(pi);

for(int i=1; i<=5; ++i)


draw(graph(f(i),-10,10),red);

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;

real f(real x)=poly.eval;


real y=f(2);
draw(graph(poly.eval, -5, 5));
56
Specialization
• Can create specialized objects just by redefining methods:
struct Shape {
void draw();
real area();
}

Shape rectangle(real w, real h) {


Shape s=new Shape;
s.draw = new void () {
fill((0,0)--(w,0)--(w,h)--(0,h)--cycle); };
s.area = new real () { return w*h; };
return s;
}

Shape circle(real radius) {


Shape s=new Shape;
s.draw = new void () { fill(scale(radius)*unitcircle); };
s.area = new real () { return pi*radiusˆ2; }
return s;
} 57
Overloading
• Consider the code:
int x1=2;
int x2() {
return 7;
}
int x3(int y) {
return 2y;
}

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.

// Don’t try this at home.


int operator +(int x, int y) {
return add(2x,y);
}
write(2+3); // Writes 7.
• This allows operators to be defined for new types.

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

You might also like