6

I have recently started using asymptote for some plotting and drawings for my research. I have however stumbled upon something that I would like to do - but I don't know if it is possible.

I have a figure like this,

enter image description here

That I would like to map to the circumference of a circle, like this

enter image description here

It would be a lot simpler to make this drawing if I could make it like the first figure in a regular cartesian coordinate system $(x,y)$, and then map it onto a polar system (r,\theta), and back to a cartesian system (\tilde x,\tilde y'). The mapping onto the polar coordinates would be,

r = y, \theta = \frac{x}{r} = \frac{x}{y}

and the mapping back to the new cartesian system would be

\tilde x (r,\theta) = r \cos (\theta) = y \cos (\frac{x}{y}),
\tilde y (r,\theta) = r \csin (\theta) = y \sin (\frac{x}{y}).

I have looked at the possible Transformations, but none of them seems to allow this kind of transformation. Is it possible to make my own that allows me to use non-affine transformations?

If this can be done in TikZ I would be very interested in that as well.

Thanks, Christian

Ps. If someone can tell me how to make my math look right, that would be greatly appreciated too.

percusse
  • 157,807
  • Since this site is about TeX rather than math, it was decided that it is more important to be able to write TeX formulas than to make math look right. – Charles Staats Feb 18 '14 at 19:02
  • Note that doing this in Asymptote will require a custom function, not just a standard transformation. Fortunately, in Asymptote, custom functions are not too hard to generate. – Charles Staats Feb 18 '14 at 19:04
  • Hey Charles, thanks for the answers. I can certainly understand the focus on tex.

    With regards to my problem I wouldn't mind writing a function myself, I just haven't been able to find an example that tells me how to write a function that will allow me to map a path or an entire picture with a custom function.

    I'm fairly new to asymptote, so I do not have a good understanding to the framework (yet).

    – christianhaargaard Feb 18 '14 at 19:34

1 Answers1

5

Try this:

\documentclass[margin=10pt]{standalone}
\usepackage{asymptote}

\begin{asydef}
struct planeTransformation {
  int nInterpolate = 4;
  pair apply(real, real);
  pair apply(pair uv) { return apply(uv.x, uv.y); }
  transform derivative(real, real);
  transform derivative(pair uv) { return derivative(uv.x, uv.y); }
  transform linearization(real u, real v) {
    return shift(apply(u,v)) * derivative(u,v) * shift(-(u,v));
  }
  transform linearization(pair uv) {
    return linearization(uv.x, uv.y);
  }
  /* Apply to a single Bezier spline. */
  guide _apply(pair p1, pair c1, pair c2, pair p2) {
    return apply(p1) .. controls linearization(p1)*c1 and linearization(p2)*c2 .. apply(p2);
  }
  guide _apply(path g) {
    assert((length(g)) == 1);
    return _apply(point(g,0), postcontrol(g,0), precontrol(g,1), point(g,1));
  }
  path apply(path g, int nInterpolate = nInterpolate) {
    guide toreturn;
    for (int i = 0; i < nInterpolate*length(g); ++i) {
      real currentpos = i / nInterpolate;
      real nextpos = (i+1) / nInterpolate;
      toreturn = toreturn & _apply(subpath(g, currentpos, nextpos));
    }
    if (cyclic(g)) toreturn = toreturn & cycle;
    return toreturn;
  }
}

planeTransformation polar;

polar.apply = new pair(real r, real theta) {
  return r * expi(theta);
};

polar.derivative = new transform(real r, real theta) {
  transform t = (0, 0, cos(theta), -r*sin(theta), sin(theta), r*cos(theta));
  return t;
};
\end{asydef}

\begin{document}
\begin{asy}
size(5cm);
path curvedbox = polar.apply(box((1, -pi), (2, pi)));
draw(curvedbox);
\end{asy}
\end{document}

The result:

Note that this is only an approximate transformation. To make it more precise, call the function e.g. as polar.apply(g, nInterpolate=16); where g is the path to which the transformation should be applied. The default value is nInterpolate = 4; different paths will require different levels of interpolation. The more intricate the path already is, the fewer interpolation points are likely to be required.

Here's the result with

path curvedbox = polar.apply(box((1, -pi), (2, pi)), nInterpolate=16);


Additional note: The code above maps the y-value to the angle, whereas the OP originally requested mapping the y-value to the radius. Here's a function that should switch to the order originally requested:

path switchedPolar(path g) {
    return polar.apply(reflect((0,0),(1,1)) * g);
}

Alternatively, in the definitions of polar.apply and polar.derivative, the order of r and theta can be switched:

polar.apply = new pair(real theta, real r) {

etc.

  • That looks exactly like what I need! Thank you! I have tested it with a few simple figures, and it works really well. Thank you very much! – christianhaargaard Feb 18 '14 at 21:07
  • 1
    If anyone else finds this solution of interest, be aware that it maps the y-value to the angle - not the x-value as suggested by my drawing earlier on.

    If one already has the drawing in a horizontal format one can use the following function

    guide swapaxis(guide g) {return reflect((0,0),(1,1))*g;}

    to swap the axis.

    One can then draw a picture similar to the ones above with the command

    polar.apply(swapaxis(box((-pi, 1), (pi, 2)));

    – christianhaargaard Feb 20 '14 at 17:06
  • @christianhaargaard: Sorry about that. I think naturally in terms of (r, theta) rather than (theta, r). – Charles Staats Feb 20 '14 at 19:22