import fontsize;
usepackage("asycolors");
bool reverse=false; // Set to true to enable reverse video.
bool stepping=false; // Set to true to enable stepping.
bool itemstep=true; // Set to false to disable stepping on each item.
settings.toolbar=false; // Disable 3D toolbar by default.
if(settings.render < 0) settings.render=4;
bool allowstepping=false; // Allow stepping for current slide.
real pagemargin=0.5cm;
real pagewidth=-2pagemargin;
real pageheight=-2pagemargin;
bool landscape=orientation == Landscape || orientation == Seascape;
if(landscape) {
orientation=Portrait;
pagewidth += settings.paperheight;
pageheight += settings.paperwidth;
} else {
pagewidth += settings.paperwidth;
pageheight += settings.paperheight;
}
texpreamble("\paperwidth="+string(pagewidth)+"bp");
texpreamble("\paperheight"+string(pageheight)+"bp");
size(pagewidth,pageheight,IgnoreAspect);
picture background;
real minipagemargin=1inch;
real minipagewidth=pagewidth-2minipagemargin;
transform tinv=inverse(fixedscaling((-1,-1),(1,1),currentpen));
pen itempen=fontsize(24pt);
pen codepen=fontsize(20pt);
pen titlepagepen=fontsize(36pt);
pen authorpen=fontsize(24pt);
pen institutionpen=authorpen;
pen datepen=fontsize(18pt);
pen urlpen=datepen;
real itemskip=0.5;
real codeskip=0.25;
real aboveequationskip=-1.25;
pair dateskip=(0,0.1);
pair urlskip=(0,0.2);
pair titlealign=3S;
pen titlepen=fontsize(32pt);
real titleskip=0.5;
string oldbulletcolor;
string newbulletcolor="red";
string bullet="{\bulletcolor\textbullet}";
pair pagenumberposition=S+E;
pair pagenumberalign=4NW;
pen pagenumberpen=fontsize(12);
pen steppagenumberpen=colorless(pagenumberpen);
real figureborder=0.25cm;
pen figuremattpen;
pen backgroundcolor;
pen foregroundcolor;
pair titlepageposition=(-0.8,0.4);
pair startposition=(-0.8,0.9);
pair currentposition=startposition;
string bulletcolor(string color)
{
return "\def\bulletcolor{"+'\\'+"color{"+color+"}}%";
}
int[] firstnode=new int[] {currentpicture.nodes.length};
int[] lastnode;
bool firststep=true;
int page=0;
bool havepagenumber=true;
int preamblenodes=2;
bool empty()
{
return currentpicture.nodes.length <= preamblenodes;
}
void background()
{
if(!background.empty()) {
add(background);
layer();
preamblenodes += 2;
}
}
void color(string name, string color)
{
texpreamble("\def"+'\\'+name+"#1{{\color{"+color+"}#1}}%");
}
string texcolor(pen p)
{
real[] colors=colors(p);
string s;
if(colors.length > 0) {
s="{"+colorspace(p)+"}{";
for(int i=0; i < colors.length-1; ++i)
s += format("%.6f",colors[i],"C")+",";
s += format("%.6f",colors[colors.length-1],"C")+"}";
}
return s;
}
void setpens(pen red=red, pen blue=blue, pen steppen=red)
{
itempen=colorless(itempen);
codepen=colorless(codepen);
pagenumberpen=colorless(pagenumberpen);
steppagenumberpen=colorless(steppagenumberpen)+steppen;
titlepagepen=colorless(titlepagepen)+red;
authorpen=colorless(authorpen)+blue;
institutionpen=colorless(institutionpen)+blue;
datepen=colorless(datepen);
urlpen=colorless(urlpen);
}
void reversevideo()
{
backgroundcolor=black;
foregroundcolor=white;
fill(background,box((-1,-1),(1,1)),backgroundcolor);
setpens(mediumred,paleblue,mediumblue);
// Work around pdflatex bug, in which white is mapped to black!
figuremattpen=pdf() ? cmyk(0,0,0,1/255) : white;
color("Red","mediumred");
color("Green","green");
color("Blue","paleblue");
color("Foreground","white");
color("Background","black");
oldbulletcolor="white";
defaultpen(itempen+foregroundcolor);
}
void normalvideo() {
backgroundcolor=invisible;
foregroundcolor=black;
background=new picture;
size(background,currentpicture);
setpens();
figuremattpen=invisible;
color("Red","red");
color("Green","heavygreen");
color("Blue","blue");
color("Foreground","black");
color("Background","white");
oldbulletcolor="black";
defaultpen(itempen+foregroundcolor);
}
normalvideo();
texpreamble(bulletcolor(newbulletcolor));
texpreamble("\hyphenpenalty=10000\tolerance=1000");
texpreamble("\usepackage{amsmath}");
// Evaluate user command line option.
void usersetting()
{
plain.usersetting();
if(reverse) { // Black background
reversevideo();
} else { // White background
normalvideo();
}
}
void numberpage(pen p=pagenumberpen)
{
if(havepagenumber) {
label((string) page,pagenumberposition,pagenumberalign,p);
}
}
void nextpage(pen p=pagenumberpen)
{
if(!empty()) {
numberpage(p);
newpage();
}
background();
firststep=true;
}
void newslide(bool stepping=true)
{
allowstepping=stepping;
nextpage();
++page;
havepagenumber=true;
currentposition=startposition;
firstnode=new int[] {currentpicture.nodes.length};
lastnode.delete();
}
bool checkposition()
{
if(abs(currentposition.x) > 1 || abs(currentposition.y) > 1) {
newslide();
return false;
}
return true;
}
void erasestep(int erasenode) {
if(!stepping || !allowstepping) return;
if(!checkposition()) return;
lastnode.push(erasenode);
nextpage(steppagenumberpen);
for(int i=0; i < firstnode.length; ++i) {
for(int j=firstnode[i]; j <= lastnode[i]; ++j) {
tex(bulletcolor(oldbulletcolor));
currentpicture.add(currentpicture.nodes[j].d);
}
}
firstnode.push(currentpicture.nodes.length-1);
tex(bulletcolor(newbulletcolor));
}
void step()
{
// Step without erasing anything.
erasestep(currentpicture.nodes.length-1);
}
void incrementposition(pair z)
{
currentposition += z;
}
void title(string s, pair position=N, pair align=titlealign,
pen p=titlepen, bool newslide=true)
{
if(newslide) newslide();
checkposition();
frame f;
if(s != "") label(f,minipage("\center "+s,minipagewidth),(0,0),align,p);
add(f,position,labelmargin(p)*align);
currentposition=(currentposition.x,position.y+
(tinv*(min(f)-titleskip*I*lineskip(p)*pt)).y);
}
void outline(string s="Outline", pair position=N, pair align=titlealign,
pen p=titlepen)
{
newslide(stepping=false);
title(s,position,align,p,newslide=false);
}
void remark(bool center=false, string s, pair align=0, pen p=itempen,
real indent=0, bool minipage=true, real skip=itemskip,
filltype filltype=NoFill, bool step=false)
{
checkposition();
if(minipage) s=minipage(s,minipagewidth);
pair offset;
if(center) {
if(align == 0) align=S;
offset=(0,currentposition.y);
} else {
if(align == 0) align=SE;
offset=currentposition;
}
frame f;
label(f,s,(indent,0),align,p,filltype);
pair m=tinv*min(f);
pair M=tinv*min(f);
if(abs(offset.x+M.x) > 1)
warning("slidetoowide","slide too wide on page "+(string) page+':\n'+
(string) s);
if(abs(offset.y+M.y) > 1) {
void toohigh() {
warning("slidetoohigh","slide too high on page "+(string) page+':\n'+
(string) s);
}
if(M.y-m.y < 2) {
newslide(); offset=(offset.x,currentposition.y);
if(offset.y+M.y > 1 || offset.y+m.y < -1) toohigh();
} else toohigh();
}
if(step) {
if(!firststep) step();
firststep=false;
}
add(f,offset);
incrementposition((0,(tinv*(min(f)-skip*I*lineskip(p)*pt)).y));
}
void center(string s, pen p=itempen)
{
remark(center=true,"\center "+s,p);
}
void vbox(string s, pen p=itempen)
{
remark(center=true,"\vbox{"+s+"}",p,minipage=false,skip=0);
}
void skip(real n=1)
{
incrementposition((0,(tinv*(-n*itemskip*I*lineskip(itempen)*pt)).y));
}
void equation(string s, pen p=itempen)
{
skip(aboveequationskip);
vbox("\begin{gather*}"+s+"\end{gather*}",p);
}
void equations(string s, pen p=itempen)
{
skip(aboveequationskip);
if(find(s,"&") >= 0)
vbox("\begin{align*}"+s+"\end{align*}",p);
else
vbox("\begin{gather*}"+s+"\end{gather*}",p);
}
void display(frame[] f, real margin=0, pair align=S, pen p=itempen,
pen figuremattpen=figuremattpen, bool final=true)
{
if(f.length == 0) return;
real[] width=new real[f.length];
real sum;
for(int i=0; i < f.length; ++i) {
width[i]=size(f[i]).x;
sum += width[i];
}
if(sum > pagewidth)
warning("toowide","slide too wide on page "+(string) page);
else margin=(pagewidth-sum)/(f.length+1);
real pos;
frame F;
for(int i=0; i < f.length; ++i) {
real w=0.5*(margin+width[i]);
pos += w;
add(F,f[i],(pos,0),Fill(figureborder,figuremattpen));
pos += w;
}
add(F,(0,currentposition.y),align);
if (final) {
real a=0.5(unit(align).y-1);
incrementposition(
(0, (tinv*(a*(max(F)-min(F))-itemskip*I*lineskip(p)*pt)).y));
}
}
void display(frame f, real margin=0, pair align=S, pen p=itempen,
pen figuremattpen=figuremattpen, bool final=true)
{
display(new frame[] {f},margin,align,p,figuremattpen, final);
}
void display(string[] s, real margin=0, string[] captions=new string[],
string caption="", pair align=S, pen p=itempen,
pen figuremattpen=figuremattpen, bool final=true)
{
frame[] f=new frame[s.length];
frame F;
for(int i=0; i < s.length; ++i) {
f[i]=newframe;
label(f[i],s[i]);
add(F,f[i],(0,0));
}
real y=point(F,S).y;
int stop=min(s.length,captions.length);
for(int i=0; i < stop; ++i) {
if(captions[i] != "")
label(f[i],captions[i],point(f[i],S).x+I*y,S);
}
display(f,margin,align,p,figuremattpen, final);
if(caption != "") center(caption,p);
}
void display(string s, string caption="", pair align=S, pen p=itempen,
pen figuremattpen=figuremattpen, bool final=true)
{
display(new string[] {s},caption,align,p,figuremattpen, final);
}
void figure(string[] s, string options="", real margin=0,
string[] captions=new string[], string caption="",
string[] url=new string[],
pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
bool final=true)
{
string[] S;
for(int i=0; i < s.length; ++i) {
S[i]=graphic(s[i],options);
if(i < url.length && url[i] != "")
S[i]="\href{"+url[i]+"/"+s[i]+".html}{"+S[i]+"}";
}
display(S,margin,captions,caption,align,itempen,figuremattpen,final);
}
void figure(string s, string options="", string caption="",
string url="", pair align=S,
pen p=itempen, pen figuremattpen=figuremattpen, bool final=true)
{
figure(new string[] {s},options,caption,new string[] {url},align,p,
figuremattpen,final);
}
void multifigure(string[] slist, string options="", string caption="",
pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
bool step=itemstep)
{
if(step) {
int lastnode=currentpicture.nodes.length-1;
for (int i=0; i<slist.length-1; ++i) {
figure(slist[i],options,caption,align,p,figuremattpen,final=false);
erasestep(lastnode);
}
}
figure(slist[slist.length-1],options,caption,align,p,figuremattpen,final=true);
if(!firststep) step();
firststep=false;
}
void indexedfigure(string prefix, int first, int last,
string options="", string caption="",
pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
bool step=itemstep)
{
bool Stepping=stepping;
stepping=true;
string[] s;
for(int i=first; i <= last; ++i)
s.push(prefix+string(i));
multifigure(s,options,caption,align,p,figuremattpen,step=step);
stepping=Stepping;
}
string[] codefile;
void asyinclude(string s, real xsize=0, real ysize=xsize)
{
picture currentpictureSave=currentpicture;
currentpicture=new picture;
_eval("include \""+s+"\";",true);
s=stripdirectory(outprefix()+"_"+s);
codefile.push(s);
frame f=(xsize > 0 || ysize > 0) ?
currentpicture.fit(xsize,ysize) : currentpicture.fit();
currentpicture=currentpictureSave;
display(f);
}
string cropcode(string s)
{
while(substr(s,0,1) == '\n') s=substr(s,1,length(s));
while(substr(s,length(s)-1,1) == '\n') s=substr(s,0,length(s)-1);
return s;
}
void code(bool center=false, string s, pen p=codepen,
real indent=0, real skip=codeskip,
filltype filltype=NoFill)
{
remark(center,"{\tt "+verbatim(cropcode(s))+"}",p,indent,skip,filltype);
}
void filecode(bool center=false, string s, pen p=codepen, real indent=0,
real skip=codeskip, filltype filltype=NoFill)
{
code(center,file(s),p,indent,skip,filltype);
}
void asyfigure(string s, string options="", string caption="", pair align=S,
pen p=codepen, pen figuremattpen=figuremattpen,
filltype filltype=NoFill, bool newslide=false)
{
string a=s+".asy";
asy(nativeformat(),s);
s += "."+nativeformat();
if(newslide && !empty()) {
newslide();
currentposition=(currentposition.x,0);
align=0;
}
figure(s,options,caption,align,p,figuremattpen);
}
string asywrite(string s, string preamble="")
{
static int count=0;
string name=outprefix()+"_slide"+(string) count;
++count;
file temp=output(name+".asy");
write(temp,preamble);
write(temp,s);
close(temp);
codefile.push(name);
return name;
}
void asycode(bool center=false, string s, string options="",
string caption="", string preamble="",
pair align=S, pen p=codepen, pen figuremattpen=figuremattpen,
real indent=0, real skip=codeskip,
filltype filltype=NoFill, bool newslide=false)
{
code(center,s,p,indent,skip,filltype);
asyfigure(asywrite(s,preamble),options,caption,align,p,figuremattpen,filltype,
newslide);
}
void asyfilecode(bool center=false, string s, string options="",
string caption="",
pair align=S, pen p=codepen, pen figuremattpen=figuremattpen,
real indent=0, real skip=codeskip,
filltype filltype=NoFill, bool newslide=false)
{
filecode(center,s+".asy",p,indent,skip,filltype);
asyfigure(s,options,caption,align,p,figuremattpen,filltype,newslide);
}
void item(string s, pen p=itempen, bool step=itemstep)
{
frame b;
label(b,bullet,(0,0),p);
real bulletwidth=max(b).x-min(b).x;
remark(bullet+"\hangindent"+(string) (bulletwidth/pt)+"pt$\,$"+s,p,
-bulletwidth,step=step);
}
void subitem(string s, pen p=itempen)
{
remark("\quad -- "+s,p);
}
void titlepage(string title, string author, string institution="",
string date="", string url="", bool newslide=false)
{
newslide();
currentposition=titlepageposition;
center(title,titlepagepen);
center(author,authorpen);
if(institution != "") center(institution,institutionpen);
currentposition -= dateskip;
if(date != "") center(date,datepen);
currentposition -= urlskip;
if(url != "") center("{\tt "+url+"}",urlpen);
}
// Resolve optional bibtex citations:
void bibliographystyle(string name)
{
settings.twice=true;
settings.keepaux=true;
texpreamble("\bibliographystyle{"+name+"}");
}
void bibliography(string name)
{
numberpage();
havepagenumber=false;
string s=texcolor(backgroundcolor);
if(s != "") tex("\definecolor{Background}"+s+"\pagecolor{Background}%");
label("",itempen);
tex("\eject\def\refname{\fontsize{"+string(fontsize(titlepen))+"}{"+
string(lineskip(titlepen))+"}\selectfont References}%");
real hmargin,vmargin;
if(pdf()) {
hmargin=1;
vmargin=0.5;
} else {
hmargin=1.5;
vmargin=1;
}
string s;
if(landscape) {
s="{\centering\textheight="+string(pageheight-1inch)+"bp\textwidth="+
string(pagewidth-1.5inches)+"bp"+
"\vsize=\textheight\hsize=\textwidth\linewidth=\hsize"+
"\topmargin="+string(vmargin)+"in\oddsidemargin="+string(hmargin)+"in";
} else
s="{\centering\textheight="+string(pageheight-0.5inches)+"bp\textwidth="+
string(pagewidth-0.5inches)+
"bp\hsize=\textwidth\linewidth=\textwidth\vsize=\textheight"+
"\topmargin=0.5in\oddsidemargin=1in";
s += "\evensidemargin=\oddsidemargin\bibliography{"+name+"}\eject}";
tex(s);
}
exitfcn currentexitfunction=atexit();
void exitfunction()
{
numberpage();
if(currentexitfunction != null) currentexitfunction();
if(!settings.keep)
for(int i=0; i < codefile.length; ++i) {
string name=codefile[i];
delete(name+"."+nativeformat());
delete(name+"_.aux");
delete(name+".asy");
}
codefile=new string[];
}
atexit(exitfunction);