# Showcase of translations to Asymptote from TikZ/PSTricks

So you already know TikZ and/or PSTricks, but you would like to expand your knowledge by learning Asymptote as well? Here's your chance.

The task/question: Find an example of an impressive diagram drawn with TikZ or PSTricks (ideally but not necessarily one you created yourself), and redraw it using Asymptote. Your redrawn version should be at least as good as the original, except that 3d Asymptote pictures are allowed to be high-resolution rasterized images even if the original was a vector drawing. You should include, at a minimum, a link to the original; ideally, you should include (if allowed by copyright) the source code for the original and a picture of it. My hope is that ultimately, the answers to this question will become a useful resource for TikZ and PSTricks users seeking to learn Asymptote.

To sweeten the deal, I will be awarding a bounty of 500 reputation points to the most impressive answer. "Most impressive" will be determined by votes at the time the bounty ends, although I reserve the right to disqualify answers that I believe violate the letter or the spirit of original question.

Additional, semi-selfish motive: Please let me know if you find my Asymptote tutorial useful. Other potentially useful resources include the official documentation and this tutorial in French for 3d stuff.

If you would like to answer this question but would like more specific examples, try translating answers from this question on drawing an egg or this question on drawing a Christmas tree.

-
Note that I am planning to start the bounty, but the StackExchange software will not let me do so until the question has been around for two days. –  Charles Staats Dec 23 '13 at 17:27
While I understand that "showcases" are often good to look at, I doubt that this question fits into tex.sx, especially compared to other questions which are asked to be edited to fit this site. Wouldn't it be better to pose a question of sorts "how can this particular use-case be solved by means of asymptote"? The question could be based on one or two designated use-cases for which answers of tikz/pstricks are available. Maybe it would even be better to post a new answer to such a question... –  Christian Feuersänger Dec 23 '13 at 19:15
@ChristianFeuersänger: I agree that this question is borderline, and should probably be closed after the bounty is awarded so as not to encourage too many similar questions. However, I was looking for a question that would encourage TikZ and PSTricks users to try translating their own projects into Asymptote, and I don't see how to do that with a more conventional question. –  Charles Staats Dec 23 '13 at 21:52
I think your document is great, hats off :) Had been playing around with it for a while now. I think for straightforward TikZ syntax examples xparse can do the translations but far from trivial. –  percusse Dec 23 '13 at 23:46
asymptote.sourceforge.net/doc/Editing-modes.html. nice Emacs mode for editing asymptotes. –  Dror Dec 26 '13 at 6:27
show 1 more comment

For a baseline, here's an example I did when I was first learning Asymptote. The original TikZ picture (taken from Lecture 2 of these class notes) is on the left; the Asymptote translation is on the right.

The code is below. Note that the translation is a bit more thorough than necessary--for instance, I don't expect most answers to worry about changing the default line width from 0.5pt to 0.4pt. It's also less thorough than it conceivably could be: the arrow tips are not identical, nor are the heights of the labels.

\documentclass[margin=10pt]{standalone}
\usepackage{tikz}
\usepackage[squaren]{SIunits}
\usepackage[inline]{asymptote}

\begin{document}
\begin{asydef}
defaultpen(fontsize(10pt));
\end{asydef}
\begin{tikzpicture}[scale=4.0, axes/.style={thick,->}]
\draw[axes] (-1.2,0) -- (1.2,0) node[right] {$x$};
\draw[axes] (0,-1.2) -- (0,1.2) node[above] {$y$};

\draw[->] (0.2,0) node[above right]{$\scriptstyle t~\rad$} arc[start angle=0, end angle=30, radius=0.2];
\draw[->] (1.07,0) arc[start angle=0, end angle=30, radius=1.07] node[right]{$t$};
\draw (0,0) -- node[below]{$\Delta x = \cos t$} ({sqrt(3)/2},0)
-- node[right,fill=white]{$\Delta y = \sin t$} ({sqrt(3)/2},0.5)
-- cycle;
\path (0,0) -- node[above]{$1$} ({sqrt(3)/2},0.5);
\end{tikzpicture}

\begin{asy}
unitsize(4cm);
pen tikzthick = linewidth(0.8pt);
defaultpen(linewidth(0.4pt));       // This sets the default pen width to 0.4pt to match TikZ; in Asymptote, the default width is 0.5pt.

draw((-1.2,0)--(1.2,0), arrow=Arrow(TeXHead), L=Label("$x$",EndPoint), p=tikzthick);
draw((0,-1.2)--(0,1.2), arrow=Arrow(TeXHead), L=Label("$y$",EndPoint), p=tikzthick);

draw(circle(c=(0,0), r=1));

draw(arc(c=(0,0), r=0.2, angle1=0, angle2=30),
L=Label("$\scriptstyle t~\rad$",position=BeginPoint,align=NE) );
draw(arc(c=(0,0), r=1.07, angle1=0, angle2=30),
L=Label("$t$",position=EndPoint,align=E) );
path triangle = (0,0)--(sqrt(3)/2,0)--(sqrt(3)/2,1/2)--cycle;
draw(triangle);
label(subpath(triangle,0,1), L="$\Delta x = \cos t$", align=S);
label(subpath(triangle,1,2), L="$\Delta y = \sin t$", align=E, filltype=Fill(white));
label(subpath(triangle,2,3), L="$1$", align=N);
\end{asy}
\end{document}

-
In case anyone is wondering, I am of course ineligible for my own bounty and I do not expect to be offering any other answers to this question. –  Charles Staats Dec 24 '13 at 19:41

Stolen from the answers of this question 3D helix torus with hidden lines. It is about a helix wrapping around another helix which also wraps around a torus. Let me call it as the second order of helix wrapping around a torus, just for the sake of simplicity when referring to it.

## Herbert Voss' solution with the almighty PSTricks

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-solides3d}
\begin{document}
\begin{pspicture}[solidmemory](-6.5,-3.5)(6.5,3)
\psset{viewpoint=30 0 15 rtp2xyz,Decran=30,lightsrc=viewpoint}
\psSolid[object=tore,r1=5,r0=1,ngrid=36 36,tablez=0 0.05 1 {} for,
zcolor= 1 .5 .5 .5 .5 1,action=none,name=Torus]
\pstVerb{/R1 5 def /R0 1.2 def /k 20 def /RL 0.15 def /kRL 40 def}%
\defFunction[algebraic]{helix}(t)
{(R1+R0*cos(k*t))*sin(t)+RL*sin(kRL*k*t)}
{(R1+R0*cos(k*t))*cos(t)+RL*cos(kRL*k*t)}
{R0*sin(k*t)+RL*sin(kRL*k*t)}
\psSolid[object=courbe,
resolution=7800,
fillcolor=black,incolor=black,
r=0,
range=0 6.2831853,
function=helix,action=none,name=Helix]%
\psSolid[object=fusion,base=Torus Helix,grid]
\end{pspicture}
\end{document}


## Charles Staats' solution with the omnipotent Asymptote

settings.outformat = "png";
settings.render = 16;
settings.prc = false;
real unit = 2cm;
unitsize(unit);

import graph3;

void drawsafe(path3 longpath, pen p, int maxlength = 400) {
int length = length(longpath);
if (length <= maxlength) draw(longpath, p);
else {
int divider = floor(length/2);
drawsafe(subpath(longpath, 0, divider), p=p, maxlength=maxlength);
drawsafe(subpath(longpath, divider, length), p=p, maxlength=maxlength);
}
}

struct helix {
path3 center;
path3 helix;
int numloops;
int pointsperloop = 12;
/* t should range from 0 to 1*/
triple centerpoint(real t) {
return point(center, t*length(center));
}
triple helixpoint(real t) {
return point(helix, t*length(helix));
}
triple helixdirection(real t) {
return dir(helix, t*length(helix));
}
/* the vector from the center point to the point on the helix */
triple displacement(real t) {
return helixpoint(t) - centerpoint(t);
}
bool iscyclic() {
return cyclic(helix);
}
}

path3 operator cast(helix h) {
return h.helix;
}

helix helixcircle(triple c = O, real r = 1, triple normal = Z) {
helix toreturn;
toreturn.center = c;
toreturn.helix = Circle(c=O, r=r, normal=normal, n=toreturn.pointsperloop);
toreturn.numloops = 1;
}

helix toreturn;
toreturn.numloops = numloops;
from toreturn unravel pointsperloop;
toreturn.center = center.helix;
int n = numloops * pointsperloop;
triple[] newhelix;
for (int i = 0; i <= n; ++i) {
real theta = (i % pointsperloop) * 2pi / pointsperloop;
real t = i / n;
triple ihat = unit(center.displacement(t));
triple khat = center.helixdirection(t);
triple jhat = cross(khat, ihat);
triple newpoint = center.helixpoint(t) + radius*(cos(theta)*ihat + sin(theta)*jhat);
newhelix.push(newpoint);
}
toreturn.helix = graph(newhelix, operator ..);
}

int loopfactor = 20;
helix wrap(helix input, int order, int initialloops = 10, real initialradius = 0.6, int loopfactor=loopfactor) {
helix toreturn = input;
int loops = initialloops;
for (int i = 1; i <= order; ++i) {
loops *= loopfactor;
}
}

currentprojection = perspective(12,0,6);

helix circle = helixcircle(r=2, c=O, normal=Z);

/* The variable part of the code starts here. */
int order = 2;    // This line varies.
real safefactor = 1;
for (int i = 1; i < order; ++i)

helix todraw = wrap(circle, order=order, initialradius = helixradius, loopfactor=40);    // This line varies (optional loopfactor parameter).

surface torus = surface(Circle(c=2X, r=0.99*saferadius, normal=-Y, n=32), c=O, axis=Z, n=32);
material toruspen = material(diffusepen=gray, ambientpen=white);
draw(torus, toruspen);

drawsafe(todraw, p=0.5purple+linewidth(0.6pt));  // This line varies (linewidth only).


## About the Charles Staats' tutorial

The tutorial I regard as beautiful might also be regarded by other people as useful. (Donut E. Knot)

-
+1, but this is not really a translation. For instance, a "translation" of Herbert Voss's answer would use the same parametrization he did for the second-order helix, same viewpoint, and possibly the same color scheme (and would probably be a lot shorter than what I wrote, which was designed such that I would not have to compute the helix parametrization by hand). –  Charles Staats Dec 24 '13 at 15:50

# Disclaimer

This is the first picture I ever made using asymptote, so please comment.

I adapted a tikz answer I gave once here: Plot basic complex transformation in LaTeX

# TikZ Code

\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.markings}
\tikzset{
arrow inside/.style = {
postaction = {
decorate,
decoration={
markings,
mark=at position 0.5 with {\arrow{>}}
}
}
}
}
\begin{document}
\begin{tikzpicture}[>=latex,scale=1.5]
\begin{scope}
% Axes
\draw (0,0) node[below left] {$O$}
(-0.5,0) -- (4,0) node[below] {$x$}
(0,-0.5) -- (0,3) node[left] {$y$};
% Ticks
\draw (1,0) -- (1,-0.1) node[below] {$a$}
(3,0) -- (3,-0.1) node[below] {$b$}
(0,1) -- (-0.1,1) node[left] {$c$}
(0,2) -- (-0.1,2) node[left] {$d$};
% Square
\draw[thick] (1,1) node[below left] {$A$} --
(3,1) node[below right] {$B$} --
(3,2) node[above right] {$C$} --
(1,2) node[above left] {$D$} -- cycle;
\draw[arrow inside] (1.5,1) -- (1.5,2);
\end{scope}

\begin{scope}[xshift=6cm]
% Axes
\draw (0,0) node[below left] {$O$}
(-0.5,0) -- (4,0) node[below] {$u$}
(0,-0.5) -- (0,3) node[left] {$v$};
%Help Lines
\draw (0,0) -- (30:3) (0,0) -- (70:3);
% Angles
\draw[->] (0.6,0) arc[start angle=0, end angle=70, radius=0.6] node[above right] {\small $\phi = d$};
\draw[->] (0.8,0) node[above right] {\small$\phi = c$} arc[start angle=0, end angle=30, radius=0.8];
% Transformation
\draw[thick] (30:1.5) node[right] {$A'$} --
(30:3) node[below right] {$B'$} arc[start angle=30, end angle=70, radius=3]
(70:3) node[above right] {$C'$} --
(70:1.5) node[above left] {$D'$} arc[start angle=70, end angle=30, radius=1.5];
\draw[arrow inside] (30:1.9) arc[start angle=30, end angle=70, radius=1.9];
\end{scope}
\end{tikzpicture}
\end{document}


# Asymptote Code

\documentclass{standalone}
\usepackage[inline]{asymptote}
\begin{document}
\begin{asy}
import geometry;
settings.outformat = "pdf";
unitsize(1.5cm);

picture realpane;
unitsize(realpane,1.5cm);

real x = 4.0, y = 3.0;
real a = 1.0, b = 3.0, c = 1.0, d = 2.0;

// Axes
label(realpane, "$O$", (0,0), align=SW);
draw(realpane, (-0.5,0) -- (x,0), L=Label("$x$", align=S, position=EndPoint));
draw(realpane, (0,-0.5) -- (0,y), L=Label("$y$", align=W, position=EndPoint));

// Ticks
draw(realpane, (a,0) -- (a,-0.1), L=Label("$a$",align=S));
draw(realpane, (b,0) -- (b,-0.1), L=Label("$b$",align=S));
draw(realpane, (0,c) -- (-0.1,c), L=Label("$c$",align=W));
draw(realpane, (0,d) -- (-0.1,d), L=Label("$d$",align=W));

// Square
draw(realpane, box((a,c),(b,d)), p=linewidth(2));
label(realpane, "$A$", (a,c), align=SW);
label(realpane, "$B$", (b,c), align=SE);
label(realpane, "$C$", (b,d), align=NE);
label(realpane, "$D$", (a,d), align=NW);
draw(realpane, (a+0.5,c) -- (a+0.5,d), arrow=MidArrow());

picture complexpane;
unitsize(complexpane,1.5cm);

pair A = 1.5*dir(30), B = 3*dir(30), C = 3*dir(70), D = 1.5*dir(70);

// Axes
label(complexpane, "$O$", (0,0), align=SW);
draw(complexpane, (-0.5,0) -- (x,0), L=Label("$u$", align=S, position=EndPoint));
draw(complexpane, (0,-0.5) -- (0,y), L=Label("$v$", align=W, position=EndPoint));

// Help Lines
draw(complexpane, (0,0) -- B);
draw(complexpane, (0,0) -- C);

// Angles
draw(complexpane, arc((x,0),(0,0),D,0.6), L=Label("$\phi = d$", align=NE, position=EndPoint), arrow=Arrow());
draw(complexpane, arc((x,0),(0,0),A,0.8), L=Label("$\phi = c$", align=E, position=MidPoint), arrow=Arrow());

// Transformation
draw(complexpane, A -- B -- arc(B,(0,0),C,3) -- C -- D -- arc(D,(0,0),A,1.5), p=linewidth(2));
label(complexpane, "$A'$", A, align=E);
label(complexpane, "$B'$", B, align=SE);
label(complexpane, "$C'$", C, align=NE);
label(complexpane, "$D'$", D, align=NW);
draw(complexpane, arc(B,(0,0),C,1.9), arrow=MidArrow());

\end{asy}
\end{document}


# Corrected Asymptote code

Thanks to Charles Staats comments, I was able to improve the code and get rid of the extra picture stuff.

\documentclass{standalone}
\usepackage[inline]{asymptote}
\begin{document}
\begin{asy}
import geometry;
settings.outformat = "pdf";
unitsize(1.5cm);
pen thick = linewidth(1.6pt);

real x = 4.0, y = 3.0;
real a = 1.0, b = 3.0, c = 1.0, d = 2.0;

// Axes
label("$O$", (0,0), align=SW);
draw((-0.5,0) -- (x,0), L=Label("$x$", align=S, position=EndPoint));
draw((0,-0.5) -- (0,y), L=Label("$y$", align=W, position=EndPoint));

// Ticks
draw((a,0) -- (a,-0.1), L=Label("$a$",align=S));
draw((b,0) -- (b,-0.1), L=Label("$b$",align=S));
draw((0,c) -- (-0.1,c), L=Label("$c$",align=W));
draw((0,d) -- (-0.1,d), L=Label("$d$",align=W));

// Square
draw(box((a,c),(b,d)), p=thick);
label("$A$", (a,c), align=SW);
label("$B$", (b,c), align=SE);
label("$C$", (b,d), align=NE);
label("$D$", (a,d), align=NW);
draw((a+0.5,c) -- (a+0.5,d), arrow=MidArrow());

currentpicture = shift(-6,0)*currentpicture;

pair A = 1.5*dir(30), B = 3*dir(30), C = 3*dir(70), D = 1.5*dir(70);

// Axes
label("$O$", (0,0), align=SW);
draw((-0.5,0) -- (x,0), L=Label("$u$", align=S, position=EndPoint));
draw((0,-0.5) -- (0,y), L=Label("$v$", align=W, position=EndPoint));

// Help Lines
draw((0,0) -- B);
draw((0,0) -- C);

// Angles
draw(arc((x,0),(0,0),D,0.6), L=Label("$\phi = d$", align=N+1.5E, position=EndPoint), arrow=ArcArrow());
draw(arc((x,0),(0,0),A,0.8), L=Label("$\phi = c$", align=E, position=MidPoint), arrow=ArcArrow());

// Transformation
draw(A -- B -- arc(B,(0,0),C,3) -- C -- D -- arc(D,(0,0),A,1.5), p=thick);
label("$A'$", A, align=SE);
label("$B'$", B, align=SE);
label("$C'$", C, align=NE);
label("$D'$", D, align=NW);
draw(arc(B,(0,0),C,1.9), arrow=MidArcArrow());


Some comments, questions, and suggestions: 1. Your use of picture objects is impressive, especially for a beginner, and probably the best reasonable translation for TikZ scopes. At the same time, there is a much easier way to achieve the desired effect in this image: the line currentpicture = shift(-6,0)*currentpicture; should shift everything that has come before six units to the left. 2. linewidth(2) is used for lines with thickness 2pt, which is extremely thick; by comparison, ultra thick tikz lines have thickness 1.6pt. 3. In the \phi=d label, try using align=N+2E. [to be ctd] –  Charles Staats Dec 29 '13 at 18:25
[ctd from previous comment] 4. Try using ArcArrow() and MidArcArrow() instead of Arrow() and MidArrow(). It will look more like the arrows in the TikZ version. 5. Once again, this is a great answer even without any of the tweaks I suggest. In particular, if you do follow my first suggestion, I think you should append the new version to this answer rather than replacing it, since your use of picture objects may be a useful example for others. –  Charles Staats Dec 29 '13 at 18:36