11

See the torus as a surface of revolution around the x (or y) axis. Define the height function on it.

How to shade only a part of the torus based on the height function?

enter image description here

There are illustrations of homotopy type and level curves on the torus on wikipedia; illustrations of gradient flows on the torus here.

[wikipedia]

15
  • The aim is to visualize what happens when you push down the region (f<b) to (f<a), a<b, along orthogonal trajectories of the hypersurface f=constant if there is no critical point between a and b and to see that, near a critical point, p, f(p)=c, the set (f<c+epsilon) has the homotopy type of (f<c-epsilon) with a 1-cell attached.
    – suzanne
    Feb 7, 2014 at 21:26
  • 2
    I really think Asymptote would be a better tool for this than TikZ. Feb 7, 2014 at 21:46
  • @CharlesStaats: I agree, and I'd be interested to see Asymptote flex its muscles on this one, really.
    – Werner
    Feb 7, 2014 at 21:57
  • Please explain how is your question different than that, that or that. I please ask future visitors to use the search box at the top right of this website before even talking about Torus drawings.
    – juliohm
    Feb 7, 2014 at 21:58
  • @juliohm: It's different because of the height function illustration--especially the shading. That's a neat effect that is not implemented in any answer to any of the questions you link to. Feb 7, 2014 at 22:02

2 Answers 2

25
+100

Here's a starting point.

enter image description here

It may be compiled as follows.

First, save the following code, inspired by splitpatch.asy, in a file called crop3D.asy:

import three;

/**********************************************/
/* Code for splitting surfaces: */

struct possibleInt {
  int value;
  bool holds;
}

int operator cast(possibleInt i) { return i.value; }

restricted int maxdepth = 20;
restricted void maxdepth(int n) { maxdepth = n; }

surface[] divide(surface s, possibleInt region(patch), int numregions,
         bool keepregion(int) = null) {

  if (keepregion == null) keepregion = new bool(int region) {
      return (0 <= region && region < numregions);
    };

  surface[] toreturn = new surface[numregions];
  for (int i = 0; i < numregions; ++i)
    toreturn[i] = new surface;

  void addPatch(patch P, int region) {
    if (keepregion(region)) toreturn[region].push(P);
  }

  void divide(patch P, int depth) {
    if (depth == 0) {
      addPatch(P, region(P));
      return;
    }

    possibleInt region = region(P);
    if (region.holds) {
      addPatch(P, region);
      return;
    }

    // Choose the splitting function based on the parity of the recursion depth.
    triple[][][] Split(triple[][] P) = (depth % 2 == 0 ? hsplit : vsplit);

    patch[] Split(patch P) {
      triple[][][] patches = Split(P.P);
      return sequence(new patch(int i) {return patch(patches[i]);}, patches.length);
    }

    patch[] patches = Split(P);
    for (patch PP : patches)
      divide(PP, depth-1);
  }

  for (patch P : s.s)
    divide(P, maxdepth);

  return toreturn;
}


surface[] divide(surface s, int region(triple), int numregions,
         bool keepregion(int) = null) {
  possibleInt patchregion(patch P) {
    triple[][] controlpoints = P.P;
    possibleInt theRegion;
    theRegion.value = region(controlpoints[0][0]);
    theRegion.holds = true;
    for (triple[] ta : controlpoints) {
      for (triple t : ta) {
    if (region(t) != theRegion.value) {
      theRegion.holds = false;
      break;
    }
      }
      if (!theRegion.holds) break;
    }
    return theRegion;
  }

  return divide(s, patchregion, numregions, keepregion);
}


/**************************************************/
/* Code for cropping surfaces */

// Return 0 iff the point lies in box(a,b).
int cropregion(triple pt, triple a=O, triple b=(1,1,1)) {
  real x=pt.x, y=pt.y, z=pt.z;
  int toreturn=0;
  real xmin=a.x, xmax=b.x, ymin = a.y, ymax=b.y, zmin=a.z, zmax=b.z;
  if (xmin > xmax) { xmin = b.x; xmax = a.x; }
  if (ymin > ymax) { ymin = b.y; ymax = a.y; }
  if (zmin > zmax) { zmin = b.z; zmax = a.z; }
  if (x < xmin) --toreturn;
  else if (x > xmax) ++toreturn;
  toreturn *= 2;
  if (y < ymin) --toreturn;
  else if (y > ymax) ++toreturn;
  toreturn *= 2;
  if (z < zmin) --toreturn;
  else if (z > zmax) ++toreturn;
  return toreturn;
}

//bool keepregion(int region) { return (region == 0); }

// Crop the surface to box(a,b).
surface crop(surface s, triple a, triple b) {
  int region(triple pt) {
    return cropregion(pt, a, b);
  }
  return divide(s, region=region, numregions=1)[0];
}

// A rectangular solid with opposite vertices a, b:
surface surfacebox(triple a, triple b) {
  return shift(a)*scale((b-a).x,(b-a).y,(b-a).z)*unitcube;
}

bool containedInBox(triple pt, triple a, triple b) {
  return cropregion(pt, a, b) == 0;
}

// Crop a path3 to box(a,b).
path3[] crop(path3 g, triple a, triple b) {
  surface thebox = surfacebox(a,b);
  path3[] toreturn;
  real[] times = new real[] {0};
  real[][] alltimes = intersections(g, thebox);
  for (real[] threetimes : alltimes)
    times.push(threetimes[0]);
  times.push(length(g));
  for (int i = 1; i < times.length; ++i) {
    real mintime = times[i-1];
    real maxtime = times[i];
    triple midpoint = point(g, (mintime+maxtime)/2);
    if (containedInBox(midpoint, a, b))
      toreturn.push(subpath(g, mintime, maxtime));
  }
  return toreturn;
}

path3[] crop(path3[] g, triple a, triple b) {
  path3[] toreturn;
  for (path3 gi : g)
    toreturn.append(crop(gi, a, b));
  return toreturn;
}

/***************************************/
/* Code to return only the portion of the surface facing the camera */

bool facingCamera(triple vec, triple pt=O, projection P = currentprojection, bool towardsCamera = true) {
  triple normal = P.camera;
  if (!P.infinity) {
    normal = P.camera - pt;
  }
  if (towardsCamera) return (dot(vec, normal) >= 0);
  else return (dot(vec, normal) <= 0);
}

surface facingCamera(surface s, bool towardsCamera = true) {

  possibleInt facingregion(patch P) {
    int n = 2;
    possibleInt toreturn;
    unravel toreturn;
    bool facingcamera = facingCamera(P.normal(1/2, 1/2), pt=P.point(1/2,1/2), towardsCamera);
    value = facingcamera ? 0 : 1;
    holds = true;
    for (int i = 0; i <= n; ++i) {
      real u = i/n;
      for (int j = 0; j <= n; ++j) {
    real v = j/n;
    if (facingCamera(P.normal(u,v), P.point(u,v), towardsCamera) != facingcamera) {
      holds = false;
      break;
    }
      }
      if (!holds) break;
    }
    return toreturn;
  }

  return divide(s, facingregion, numregions=1)[0];
}

Then, save the following code in a file (in the same directory) called surfacepaths.asy:

import graph3;
import contour;

// A bunch of auxiliary functions.

real fuzz = .001;

real umin(surface s) { return 0; }
real vmin(surface s) { return 0; }
pair uvmin(surface s) { return (umin(s), vmin(s)); }
real umax(surface s, real fuzz=fuzz) {
  if (s.ucyclic()) return s.index.length;
  else return s.index.length - fuzz;
}
real vmax(surface s, real fuzz=fuzz) {
  if (s.vcyclic()) return s.index[0].length;
  return s.index[0].length - fuzz;
}
pair uvmax(surface s, real fuzz=fuzz) { return (umax(s,fuzz), vmax(s,fuzz)); }

typedef real function(real, real);

function normalDot(surface s, triple eyedir(triple)) {
  real toreturn(real u, real v) {
    return dot(s.normal(u, v), eyedir(s.point(u,v)));
  }
  return toreturn;
}

struct patchWithCoords {
  patch p;
  real u;
  real v;
  void operator init(patch p, real u, real v) {
    this.p = p;
    this.u = u;
    this.v = v;
  }
  void operator init(surface s, real u, real v) {
    int U=floor(u);
    int V=floor(v);
    int index = (s.index.length == 0 ? U+V : s.index[U][V]);

    this.p = s.s[index];
    this.u = u-U;
    this.v = v-V;
  }
  triple partialu() {
    return p.partialu(u,v);
  }
  triple partialv() {
    return p.partialv(u,v);
  }
}

triple[] derivative(surface s, pair pt) {
  patchWithCoords thepatch = patchWithCoords(s, pt.x, pt.y);
  return new triple[] {thepatch.partialu(), thepatch.partialv()};
}

typedef triple paramsurface(pair);

paramsurface tangentplane(surface s, pair pt) {
  patchWithCoords thepatch = patchWithCoords(s, pt.x, pt.y);
  triple partialu = thepatch.partialu();
  triple partialv = thepatch.partialv();
  return new triple(pair tangentvector) {
    return s.point(pt.x, pt.y) + (tangentvector.x * partialu) + (tangentvector.y * partialv);
  };
}

guide[] normalpathuv(surface s, projection P = currentprojection, int n = ngraph) {
  triple eyedir(triple a);
  if (P.infinity) eyedir = new triple(triple) { return P.camera; };
  else eyedir = new triple(triple pt) { return P.camera - pt; };
  return contour(normalDot(s, eyedir), uvmin(s), uvmax(s), new real[] {0}, nx=n)[0];
}

path3 onSurface(surface s, path p) {
  triple f(int t) {
    pair point = point(p,t);
    return s.point(point.x, point.y);
  }

  guide3 toreturn = f(0);
  paramsurface thetangentplane = tangentplane(s, point(p,0));
  triple oldcontrol, newcontrol;
  int size = length(p);
  for (int i = 1; i <= size; ++i) {
    oldcontrol = thetangentplane(postcontrol(p,i-1) - point(p,i-1));
    thetangentplane = tangentplane(s, point(p,i));
    newcontrol = thetangentplane(precontrol(p, i) - point(p,i));
    toreturn = toreturn .. controls oldcontrol and newcontrol .. f(i);
  }

  if (cyclic(p)) toreturn = toreturn & cycle;

  return toreturn;

}

path3[] onSurface(surface s, path[] p) {
  return sequence(new path3(int i) {return onSurface(s,p[i]);}, p.length);
}

/*
 * This method returns an array of paths that trace out all the
 * points on s at which s is parallel to eyedir.
 */

path[] paramSilhouetteNoEdges(surface s, projection P = currentprojection, int n = ngraph) {
   guide[] uvpaths = normalpathuv(s, P, n);
  //Reduce the number of segments to conserve memory
  for (int i = 0; i < uvpaths.length; ++i) {
    real len = length(uvpaths[i]);
    uvpaths[i] = graph(new pair(real t) {return point(uvpaths[i],t);}, 0, len, n=n);
  }
  return uvpaths;
}   

private typedef real function2(real, real);
private typedef real function3(triple);

triple[] normalVectors(triple dir, triple surfacen) {
  dir = unit(dir);
  surfacen = unit(surfacen);
  triple v1, v2;
  int i = 0;
  do {
    v1 = unit(cross(dir, (unitrand(), unitrand(), unitrand())));
    v2 = unit(cross(dir, (unitrand(), unitrand(), unitrand())));
    ++i;
  } while ((abs(dot(v1,v2)) > Cos(10) || abs(dot(v1,surfacen)) > Cos(5) || abs(dot(v2,surfacen)) > Cos(5)) && i < 1000);
  if (i >= 1000) {
    write("problem: Unable to comply.");
    write(" dir = " + (string)dir);
    write(" surface normal = " + (string)surfacen);
  }
  return new triple[] {v1, v2};
}

function3 planeEqn(triple pt, triple normal) {
  return new real(triple r) {
    return dot(normal, r - pt);
  };
}

function2 pullback(function3 eqn, surface s) {
  return new real(real u, real v) {
    return eqn(s.point(u,v));
  };
}


path3[] levelcurve(function3 f, surface s, real value=0) {
  function2 fparam = pullback(f, s);
  path[] paramcurve = contour(fparam, (0,0), uvmax(s), new real[] {value})[0];
  return onSurface(s, paramcurve);
}

/*
 * returns the distinct points in which the surface intersects
 * the line through the point pt in the direction dir
 */

triple[] intersectionPoints(surface s, pair parampt, triple dir) {
  triple pt = s.point(parampt.x, parampt.y);
  triple[] lineNormals = normalVectors(dir, s.normal(parampt.x, parampt.y));
  path[][] curves;
  for (triple n : lineNormals) {
    function3 planeEn = planeEqn(pt, n);
    function2 pullback = pullback(planeEn, s);
    guide[] contour = contour(pullback, uvmin(s), uvmax(s), new real[]{0})[0];

    curves.push(contour);
  }
  pair[] intersectionPoints;
  for (path c1 : curves[0])
    for (path c2 : curves[1])
      intersectionPoints.append(intersectionpoints(c1, c2));
  triple[] toreturn;
  for (pair P : intersectionPoints)
    toreturn.push(s.point(P.x, P.y));
  return toreturn;
}



/*
 * Returns those intersection points for which the vector from pt forms an
 * acute angle with dir.
 */
 int numPointsInDirection(surface s, pair parampt, triple dir, real fuzz=.05) {
  triple pt = s.point(parampt.x, parampt.y);
  dir = unit(dir);
  triple[] intersections = intersectionPoints(s, parampt, dir);
  int num = 0;
  for (triple isection: intersections)
    if (dot(isection - pt, dir) > fuzz) ++num;
  return num;
}

bool3 increasing(real t0, real t1) {
  if (t0 < t1) return true;
  if (t0 > t1) return false;
  return default;
}

int[] extremes(real[] f, bool cyclic = f.cyclic) {
  bool3 lastIncreasing;
  bool3 nextIncreasing;
  int max;
  if (cyclic) {
    lastIncreasing = increasing(f[-1], f[0]);
    max = f.length - 1;
  } else {
    max = f.length - 2;
    if (increasing(f[0], f[1])) lastIncreasing = false;
    else lastIncreasing = true;
  }
  int[] toreturn;
  for (int i = 0; i <= max; ++i) {
    nextIncreasing = increasing(f[i], f[i+1]);
    if (lastIncreasing != nextIncreasing) {
      toreturn.push(i);
    }
    lastIncreasing = nextIncreasing;
  }
  if (!cyclic) toreturn.push(f.length - 1);
  toreturn.cyclic = cyclic;
  return toreturn;
}

int[] extremes(path path, real f(pair) = new real(pair P) {return P.x;})
{
  real[] fvalues = new real[size(path)];
  for (int i = 0; i < fvalues.length; ++i) {
    fvalues[i] = f(point(path, i));
  }
  fvalues.cyclic = cyclic(path);
  int[] toreturn = extremes(fvalues);
  fvalues.delete();
  return toreturn;
}

path[] splitAtExtremes(path path, real f(pair) = new real(pair P) {return P.x;})
{
  int[] splittingTimes = extremes(path, f);
  path[] toreturn;
  if (cyclic(path)) toreturn.push(subpath(path, splittingTimes[-1], splittingTimes[0]));
  for (int i = 0; i+1 < splittingTimes.length; ++i) {
    toreturn.push(subpath(path, splittingTimes[i], splittingTimes[i+1]));
  }
  return toreturn;
}

path[] splitAtExtremes(path[] paths, real f(pair P) = new real(pair P) {return P.x;})
{
  path[] toreturn;
  for (path path : paths) {
    toreturn.append(splitAtExtremes(path, f));
  }
  return toreturn;
}

path3 toCamera(triple p, projection P=currentprojection, real fuzz = .01, real upperLimit = 100) {
  if (!P.infinity) {
    triple directionToCamera = unit(P.camera - p);
    triple startingPoint = p + fuzz*directionToCamera;
    return startingPoint -- P.camera;
  }
  else {
    triple directionToCamera = unit(P.camera);
    triple startingPoint = p + fuzz*directionToCamera;

    return startingPoint -- (p + upperLimit*directionToCamera);
  }
}

int numSheetsHiding(surface s, pair parampt, projection P = currentprojection) {
  triple p = s.point(parampt.x, parampt.y);
  path3 tocamera = toCamera(p, P);
  triple pt = beginpoint(tocamera);
  triple dir = endpoint(tocamera) - pt;
  return numPointsInDirection(s, parampt, dir);
}

struct coloredPath {
  path path;
  pen pen;
  void operator init(path path, pen p=currentpen) {
    this.path = path;
    this.pen = p;
  }
  /* draws the path with the pen having the specified weight (using colors)*/
  void draw(real weight) {
    draw(path, p=weight*pen + (1-weight)*white);
  }
}
coloredPath[][] layeredPaths;
// onTop indicates whether the path should be added at the top or bottom of the specified layer
void addPath(path path, pen p=currentpen, int layer, bool onTop=true) {
  coloredPath toAdd = coloredPath(path, p);
  if (layer >= layeredPaths.length) {
    layeredPaths[layer] = new coloredPath[] {toAdd};
  } else if (onTop) {
    layeredPaths[layer].push(toAdd);
  } else layeredPaths[layer].insert(0, toAdd);
}

void drawLayeredPaths() {
  for (int layer = layeredPaths.length - 1; layer >= 0; --layer) {
    real layerfactor = (1/3)^layer;
    for (coloredPath toDraw : layeredPaths[layer]) {
      toDraw.draw(layerfactor);
    }
  }
  layeredPaths.delete();
}

real[] cutTimes(path tocut, path[] knives) {
  real[] intersectionTimes = new real[] {0, length(tocut)};
  for (path knife : knives) {
    real[][] complexIntersections = intersections(tocut, knife);
    for (real[] times : complexIntersections) {
      intersectionTimes.push(times[0]);
    }
  }
  return sort(intersectionTimes);
}

path[] cut(path tocut, path[] knives) {
  real[] cutTimes = cutTimes(tocut, knives);
  path[] toreturn;
  for (int i = 0; i + 1 < cutTimes.length; ++i) {
    toreturn.push(subpath(tocut,cutTimes[i], cutTimes[i+1]));
  }
  return toreturn;
}

real[] condense(real[] values, real fuzz=.001) {
  values = sort(values);
  values.push(infinity);
  real previous = -infinity;
  real lastMin;
  real[] toReturn;
  for (real t : values) {
    if (t - fuzz > previous) {
      if (previous > -infinity) toReturn.push((lastMin + previous) / 2);
      lastMin = t;
    }
    previous = t;
  }
  return toReturn;
}

Finally, here's the code that actually creates the image (using the previous two modules). Save it in a file called (e.g.) morse_theory.asy in the same directory as the other two files, and then run asy morse_theory at the command line.

settings.outformat="png";
settings.render=16;
settings.prc=false;
usepackage("lmodern");
usepackage("amssymb");
defaultpen(fontsize(10pt));
unitsize(1cm);

import graph3;

/**********************************************/
/* Code for splitting surfaces: */

import crop3D;

/************************************************/
/* Code for drawing a level curve on a surface: */

import surfacepaths;

/************************************************/
/* The actual drawing: */


currentprojection = orthographic(X+.2Z);

real r = 1.4;
real R = 2.6;
real rc = (r+R)/2;
real rtube = (R-r)/2;
transform3 yscale = scale(1,.8,1);

surface torus = yscale * surface(rotate(angle=90,rc*Y,rc*Y+Z)*Circle(c=rc*Y, r=rtube, normal=Z, n=8), c=O, axis=X, n=8);

maxdepth(10);
surface torusFront = facingCamera(torus, towardsCamera=false);
maxdepth(17);

real[] dividerHeights = sort(new real[] {-rc+.1, -r, -rc+2rtube-.1});

int region(triple t) {
  real z = t.z;
  for (int i = 0; i < dividerHeights.length; ++i) {
    if (z < dividerHeights[i]) return i;
  }
  return dividerHeights.length;
}

int numregions = dividerHeights.length + 1;

surface[] torusCells = divide(torusFront, region, numregions);

pen transparency = opacity(0.8);

material[] materials = new material[] {material(black+transparency),
                       material(gray(1/3)+transparency, ambientpen=gray(1/3)),
                       material(gray(2/3)+transparency, ambientpen=gray(2/3)),
                       material(white+transparency, ambientpen=white)};

draw(torusCells[0], surfacepen=materials[0]);
draw(torusCells[1], surfacepen=materials[1]);
draw(torusCells[2], surfacepen=materials[2]);
draw(torusCells[3], surfacepen=materials[3]);

real height(triple pt) { return pt.z; }

for (real h : dividerHeights) {
  draw(levelcurve(height, torus, h));
}

path3[] circularBands = levelcurve(planeEqn(pt=O,normal=Y+.3X), torus, 0);

real maxdivide = dividerHeights[dividerHeights.length - 1];
real mindivide = dividerHeights[0];

path3[] bandsToDraw = crop(circularBands, (-5,-5, mindivide), (5, 5, maxdivide));

// In our case, as it happens, there is only one band--but let's make sure of that.
assert(bandsToDraw.length == 1);
path3 bandToDraw = bandsToDraw[0];

draw(bandToDraw);

triple bandPoint = relpoint(bandToDraw, 0.25);
//dot(bandPoint);
draw(maxdivide*Z {(-1,-.4,-.2)} .. {(-.4,.6,-1)} bandPoint, arrow=ArcArrow3(DefaultHead2,emissive(black)), L=Label("$e^k$", position=BeginPoint, align=ENE));

real y = R;
draw((0,y,-R) -- (0,y,R), L=Label("$\mathbb{R}$",position=EndPoint,align=NE), arrow=Arrow3(TeXHead2,emissive(black)));

//draw bars with size specified in postscript coordinates
draw(shift(0,y,dividerHeights[0]) * ((0,-.1,0) -- (0,.1,0)), L=Label("$c-\varepsilon$",position=EndPoint,align=E));
draw(shift(0,y,dividerHeights[1]) * ((0,-.1,0) -- (0,.1,0)), L=Label("$c$",position=EndPoint,align=E));
draw(shift(0,y,dividerHeights[2]) * ((0,-.1,0) -- (0,.1,0)), L=Label("$c+\varepsilon$",position=EndPoint,align=E));


transform3 shiftright = shift(0,6,0);

real perturbdist = abs(min(torus).y)/2;
path perturbpath = (-2*perturbdist,0) --- (-perturbdist,0) .. (0,.08) .. (perturbdist,0) --- (2*perturbdist,0);

real perturbedHeight(triple pt) {
  real z = pt.z, y=pt.y;
  if (abs(y) > perturbdist) return z;
  else return z + point(perturbpath,times(perturbpath,y)[0]).y;
}

real perturbedDivide = -r + .01;

region = new int(triple t) {
  if (perturbedHeight(t) < perturbedDivide) return 0;
  else if (height(t) < perturbedDivide) return 1;
  else if (height(t) < dividerHeights[2]) return 2;
  else return 3;
};

surface[] newTorusCells = divide(torusFront, region, numregions=3);
newTorusCells.push(torusCells[3]);
for (int i = 0; i < newTorusCells.length; ++i)
  draw(shiftright*newTorusCells[i], surfacepen=materials[i]);

draw(shiftright * crop(levelcurve(perturbedHeight, torus,perturbedDivide), (0,-5,-5), (5,5,5)));
draw(shiftright * crop(levelcurve(height, torus, perturbedDivide), (0,-5,-5), (5,5,5)));
draw(shiftright * levelcurve(height, torus, maxdivide));

draw(shiftright * crop(Circle(c=-rc*Z, r=rtube, normal=Y), (5,5,perturbedDivide-perturbedHeight(O)), (0,-5, 5)));

draw(shiftright * ((0,R,-R) -- (0,R,maxdivide)), Bars3, arrow=Arrows3(DefaultHead2), L=Label("$M \leq c + \varepsilon$", position=MidPoint, align=E));
7
  • Off topic: How can we use Asymptote in Beamer overlay, such as showing progressive annotation? Feb 12, 2014 at 2:59
  • @The: That's a good question. The naive method is to create the Asymptote graphic in a separate imagename.asy file and include periodic shipout commands: shipout(prefix="imagename-1");, shipout(prefix="imagename-2");, etc. Then in your .tex file, put things like \includegraphics<1>{imagename-1}, \includegraphics<2>{imagename-2}, etc. A less naive solution would involve modifying the asy environment to include a continue option or some such that does this for you. That's really about tex rather than Asymptote, so I have no especial expertise. Feb 12, 2014 at 3:56
  • But it does not make sense in a case where, for example, one item in a enumerate points to a certain point on an Asymptote graphics and other items each points to another point on the Asymptote graphics progressively. It is because the nodes are in different world, TeX and Asymptote. Is my argumentation wrong? Feb 12, 2014 at 6:02
  • @The: If I understand what you're saying, then you're right. If you want to have an arrow that is not contained in the image, then Asymptote is not the right choice. In this situation, I would use TikZ, at least for the arrow. The graphic could still be Asymptote-generated if you are willing to treat it as a photograph and place the arrow point manually. Feb 12, 2014 at 11:22
  • I get a long error message. Perhaps recent versions of asymptote are not back compatible enough. Jan 22, 2022 at 14:57
11

Please find attached an inkscape code (download the code and save it with .svg extension). You can freely modify it to your needs. The resulting image is shown below.

enter image description here

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="800"
   height="800"
   id="svg2"
   version="1.1"
   inkscape:version="0.48.4 r9939"
   sodipodi:docname="torus.svg"
   inkscape:export-filename="torus.png"
   inkscape:export-xdpi="600"
   inkscape:export-ydpi="600">
  <defs
     id="defs4">
    <marker
       inkscape:stockid="Arrow2Mstart"
       orient="auto"
       refY="0.0"
       refX="0.0"
       id="Arrow2Mstart"
       style="overflow:visible">
      <path
         id="path4128"
         style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round"
         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
         transform="scale(0.6) translate(0,0)" />
    </marker>
    <marker
       inkscape:stockid="Arrow2Lend"
       orient="auto"
       refY="0.0"
       refX="0.0"
       id="Arrow2Lend"
       style="overflow:visible;">
      <path
         id="path4125"
         style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
         transform="scale(1.1) rotate(180) translate(1,0)" />
    </marker>
    <inkscape:path-effect
       effect="spiro"
       id="path-effect4663"
       is_visible="true" />
    <inkscape:path-effect
       is_visible="true"
       id="path-effect4659"
       effect="spiro" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect4655"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect4550"
       is_visible="true" />
    <marker
       inkscape:stockid="Arrow1Mend"
       orient="auto"
       refY="0.0"
       refX="0.0"
       id="Arrow1Mend"
       style="overflow:visible;">
      <path
         id="path4113"
         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
         transform="scale(0.4) rotate(180) translate(10,0)" />
    </marker>
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3918"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767"
       is_visible="true" />
    <linearGradient
       id="linearGradient3821"
       osb:paint="solid">
      <stop
         style="stop-color:#000000;stop-opacity:1;"
         offset="0"
         id="stop3823" />
    </linearGradient>
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767-1"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767-4"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767-1-0"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767-4-8"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767-1-0-8"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767-1-1"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect3767-7"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect4550-5"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect4550-5-7"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect4550-1"
       is_visible="true" />
    <inkscape:path-effect
       effect="spiro"
       id="path-effect4550-2"
       is_visible="true" />
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.98994949"
     inkscape:cx="387.50934"
     inkscape:cy="370.63809"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     units="mm"
     inkscape:window-width="1920"
     inkscape:window-height="1018"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1" />
  <metadata
     id="metadata7">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(0,-343.70081)">
    <path
       style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none"
       d="m 164.13893,520.32659 c -19.54656,-0.90463 -34.93259,-2.35844 -53.21428,-5.02816 -7.77341,-1.13518 -11.428699,-2.40282 -6.92857,-2.40282 1.85801,0 2.28571,-0.28549 2.28571,-1.52566 0,-1.63422 -0.1632,-1.63826 -9.002854,-0.22301 l -2.931427,0.46933 -2.615115,-7.39605 c -4.742595,-13.41296 -14.022032,-46.68966 -14.022032,-50.28398 0,-0.62626 1.932295,-0.49656 7.321429,0.49144 45.724619,8.38276 99.552799,8.45608 145.114409,0.19766 11.16066,-2.02296 10.54948,-2.20876 11.91183,3.62119 2.71318,11.61056 12.78303,39.43373 17.32286,47.86336 1.87674,3.48477 2.17164,4.58607 1.57798,5.89286 -0.90401,1.98991 -2.08339,2.13388 -1.46279,0.17857 0.24938,-0.78571 0.35139,-1.42901 0.2267,-1.42955 -0.12469,-5.3e-4 -2.95885,-0.48224 -6.29813,-1.07045 -3.33929,-0.58821 -6.15179,-1.06991 -6.25,-1.07045 -0.0982,-5.4e-4 -0.17857,0.61852 -0.17857,1.37568 0,1.16179 0.8474,1.51336 5.42951,2.25253 3.07187,0.49554 5.01039,1.09868 4.46429,1.38898 -2.08342,1.10752 -28.6699,4.52937 -43.82237,5.64023 -11.035,0.809 -40.53045,1.44697 -48.92858,1.0583 z m -48.57142,-9.30547 c 4.5063,-0.54637 5.03268,-0.78064 4.55439,-2.02705 -0.50108,-1.30578 -1.86649,-1.35958 -7.88874,-0.31085 -3.80363,0.66237 -4.5228,1.0173 -4.5228,2.23214 0,1.25088 0.31121,1.38092 2.32143,0.97 1.27679,-0.26099 3.76786,-0.6499 5.53572,-0.86424 z m 129.86552,-1.51837 c -0.31893,-1.66646 -11.13427,-3.02148 -12.06726,-1.51188 -0.80271,1.29881 -0.3631,1.56411 3.48176,2.10122 6.6712,0.93195 8.84805,0.78253 8.5855,-0.58934 z m -112.90124,-0.6673 c 0.99027,-0.23441 1.60714,-0.91751 1.60714,-1.7797 0,-0.99719 -0.35918,-1.29311 -1.25,-1.02982 -0.6875,0.2032 -3.58035,0.58783 -6.42857,0.85472 -4.52855,0.42435 -5.17857,0.66343 -5.17857,1.90475 0,1.3251 0.32058,1.38661 4.82143,0.92498 2.65179,-0.27197 5.54464,-0.66569 6.42857,-0.87493 l 0,0 z m 99.46429,-0.84035 c 0,-1.06994 -0.73115,-1.4169 -3.75,-1.77951 -6.31457,-0.75847 -9.10715,-0.58178 -9.10715,0.57622 0,0.98755 1.3566,1.39902 6.78572,2.05816 5.20644,0.63211 6.07143,0.51032 6.07143,-0.85487 l 0,0 z m -88.125,-0.0995 c 3.36309,0 3.83928,-0.17719 3.83928,-1.42858 0,-1.59431 -1.61371,-1.77999 -8.39285,-0.96572 -3.11359,0.37398 -3.75,0.69114 -3.75,1.86879 0,1.20761 0.33166,1.35203 2.23214,0.97193 1.22768,-0.24553 3.95982,-0.44642 6.07143,-0.44642 z m 73.83928,-1.32651 c 0,-1.15251 -0.77194,-1.37941 -5.8852,-1.72989 -5.59908,-0.38376 -6.92102,-0.0481 -6.961,1.76726 -0.0106,0.47938 3.4755,0.89171 9.81049,1.16039 2.52788,0.10721 3.03571,-0.0932 3.03571,-1.19776 l 0,0 z m -58.39285,0.15376 c 1.57541,-0.2604 2.67857,-0.84551 2.67857,-1.42071 0,-0.73988 -1.29,-0.97797 -5.29872,-0.97797 -5.92235,0 -7.55843,0.40307 -7.55843,1.86213 0,1.08554 5.19913,1.3596 10.17858,0.53655 z m 44.82142,-0.97011 c 0,-1.24617 -0.47881,-1.42958 -3.75,-1.43643 -2.0625,-0.004 -4.95535,-0.2071 -6.42857,-0.45061 -2.38104,-0.39356 -2.67857,-0.27715 -2.67857,1.048 0,1.35171 0.48295,1.51373 5.17857,1.73725 2.84822,0.13558 5.74107,0.31037 6.42857,0.38843 0.82113,0.0932 1.25,-0.34822 1.25,-1.28664 z m -27.99051,-0.53572 c -0.19214,-1.00862 -1.12901,-1.29184 -4.85176,-1.46671 -5.53083,-0.2598 -7.87201,0.23356 -7.87201,1.65889 0,0.85652 1.23335,1.05782 6.48094,1.05782 5.78686,0 6.45545,-0.13387 6.24283,-1.25 z m 13.7048,-0.17857 c 0,-1.32275 -0.47619,-1.42857 -6.42857,-1.42857 -5.95238,0 -6.42857,0.10582 -6.42857,1.42857 0,1.32275 0.47619,1.42857 6.42857,1.42857 5.95238,0 6.42857,-0.10582 6.42857,-1.42857 z"
       id="path3896"
       inkscape:connector-curvature="0"
       transform="translate(0,343.70081)" />
    <path
       style="fill:none;stroke:#c80000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
       d="m 75.892857,451.69709 c 26.902353,5.4247 54.341923,8.18168 81.785733,8.21738 28.10453,0.0366 56.21199,-2.78122 83.74998,-8.39595"
       id="path3765"
       inkscape:path-effect="#path-effect3767"
       inkscape:original-d="m 75.892857,451.69709 c 0,0 54.386563,8.21434 81.785733,8.21738 28.05659,0.003 83.74998,-8.39595 83.74998,-8.39595"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac"
       transform="translate(0,343.70081)" />
    <path
       style="fill:none;stroke:#c80000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:9, 1.5;stroke-dashoffset:0"
       d="m 76.303574,794.77462 c 26.902356,-5.4247 54.341926,-8.18168 81.785736,-8.21738 28.10453,-0.0366 56.21198,2.78122 83.74997,8.39595"
       id="path3765-7"
       inkscape:path-effect="#path-effect3767-1"
       inkscape:original-d="m 76.303574,794.77462 c 0,0 54.386566,-8.21434 81.785736,-8.21738 28.05658,-0.003 83.74997,8.39595 83.74997,8.39595"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac" />
    <path
       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
       d="m 93.677498,857.48591 c 28.076012,5.41968 56.666312,8.1719 85.260612,8.20754 29.28258,0.0365 58.56802,-2.77635 87.3083,-8.3859"
       id="path3765-9"
       inkscape:path-effect="#path-effect3767-4"
       inkscape:original-d="m 93.677498,857.48591 c 0,0 56.697322,8.20451 85.260612,8.20754 29.24864,0.003 87.3083,-8.3859 87.3083,-8.3859"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac" />
    <path
       style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none"
       d="m 339.85322,520.32096 c -21.22323,-0.77301 -51.36858,-3.88267 -63.21429,-6.52091 l -2.14285,-0.47725 2.49189,-0.39217 c 1.67131,-0.26303 2.57555,-0.82946 2.74596,-1.72012 0.23347,-1.2203 -0.0998,-1.28689 -4.11042,-0.8214 l -4.36448,0.50655 2.89733,-5.80629 c 5.805,-11.6333 11.08864,-26.49219 18.21351,-51.22079 0.16836,-0.58433 2.30675,-0.43543 7.60876,0.52979 23.37626,4.2556 47.78437,6.35602 73.78686,6.34966 27.0432,-0.007 50.36742,-2.02645 74.41064,-6.44381 4.1994,-0.77154 7.7413,-1.29679 7.87087,-1.16721 0.84629,0.84629 -10.68899,41.92778 -15.01112,53.46026 -1.57538,4.20351 -1.84505,4.5155 -3.9369,4.5546 -1.3268,0.0248 -2.69921,0.60934 -3.35412,1.42858 -1.0792,1.34998 -1.09699,1.34478 -0.67375,-0.19676 0.4783,-1.74214 0.52765,-1.721 -7.09908,-3.04051 -5.49486,-0.95068 -5.40452,-0.96123 -5.40452,0.63075 0,1.14095 0.84691,1.49944 5.17857,2.19201 2.84821,0.45539 5.5,0.91563 5.89285,1.02276 2.41862,0.65956 -31.50041,5.06025 -46.78571,6.07004 -12.66201,0.83648 -36.04419,1.38842 -45,1.06222 z m -50.36545,-9.43706 c 2.6944,-0.38079 3.62658,-0.83314 3.82344,-1.85536 0.23997,-1.24604 -0.0821,-1.316 -4.11697,-0.89428 -6.54458,0.68405 -7.91245,1.1557 -7.91245,2.72829 0,1.17275 0.35364,1.31811 2.32143,0.95421 1.27679,-0.23612 3.92483,-0.6559 5.88455,-0.93286 l 0,0 z m 129.65116,-1.48538 c 0,-1.17611 -0.76286,-1.42176 -5.80006,-1.86765 -4.50121,-0.39845 -5.93211,-0.29976 -6.38973,0.44069 -0.80451,1.30171 -0.59207,1.41783 3.75022,2.05012 6.86928,1.00025 8.43957,0.8843 8.43957,-0.62316 z m -114.10714,-0.52405 c 2.08272,-0.30336 2.67857,-0.7112 2.67857,-1.83337 0,-1.1332 -0.34523,-1.3615 -1.60714,-1.06279 -0.88393,0.20923 -3.77679,0.60295 -6.42857,0.87493 -4.1601,0.42668 -4.82143,0.68823 -4.82143,1.90689 0,1.48714 0.69967,1.495 10.17857,0.11434 z m 100.53572,-0.92201 c 0,-1.17279 -0.6992,-1.43706 -4.82143,-1.82225 -2.65179,-0.24779 -5.54465,-0.60093 -6.42857,-0.78475 -1.23083,-0.25596 -1.60715,-0.009 -1.60715,1.05657 0,1.16323 0.67199,1.46657 4.10715,1.85398 2.25892,0.25475 4.42857,0.57394 4.82142,0.70929 2.15154,0.74128 3.92858,0.28314 3.92858,-1.01284 l 0,0 z m -85.17858,-0.43628 c 0.49108,-0.15951 0.89286,-0.78226 0.89286,-1.38387 0,-1.20723 -3.59407,-1.45503 -9.45409,-0.65182 -2.53914,0.34802 -3.15896,0.69424 -2.91475,1.62811 0.26059,0.99647 1.13136,1.14704 5.44665,0.94185 2.82506,-0.13434 5.53826,-0.37476 6.02933,-0.53427 z m 70.89286,-0.94645 c 0,-1.14371 -0.80157,-1.39272 -5.83419,-1.81243 -4.40966,-0.36775 -5.97665,-0.26202 -6.41764,0.43302 -1.24225,1.95795 -1.43036,1.90926 9.9304,2.57023 1.83381,0.10669 2.32143,-0.14345 2.32143,-1.19082 z m -59.46428,0.14875 c 2.46585,-0.29619 3.75,-0.78326 3.75,-1.42237 0,-0.74773 -1.48296,-0.97193 -6.42858,-0.97193 -5.95238,0 -6.42857,0.10582 -6.42857,1.42857 0,1.59285 2.06395,1.81171 9.10715,0.96573 z m 45.89285,-1.26554 c 0,-0.94763 -4.8591,-1.82451 -10.17857,-1.83684 -2.18606,-0.005 -2.67857,0.25115 -2.67857,1.39348 0,1.26018 0.58731,1.42036 5.89286,1.60714 6.55644,0.23082 6.96428,0.16267 6.96428,-1.16378 z m -27.99138,-0.23591 c -0.20213,-1.05728 -1.2013,-1.28181 -6.48094,-1.45638 -5.87298,-0.19418 -6.24196,-0.12029 -6.24196,1.25 0,1.35865 0.43494,1.45638 6.48094,1.45638 5.78719,0 6.45536,-0.1338 6.24196,-1.25 l 0,0 z m 13.70567,-0.17857 c 0,-1.32275 -0.47619,-1.42857 -6.42857,-1.42857 -5.95238,0 -6.42857,0.10582 -6.42857,1.42857 0,1.32275 0.47619,1.42857 6.42857,1.42857 5.95238,0 6.42857,-0.10582 6.42857,-1.42857 z"
       id="path3898"
       inkscape:connector-curvature="0"
       transform="translate(0,343.70081)" />
    <path
       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
       d="m 267.24043,857.39452 c 28.07601,5.41968 56.66632,8.1719 85.26062,8.20754 29.28258,0.0365 58.56802,-2.77635 87.3083,-8.3859"
       id="path3765-9-2"
       inkscape:path-effect="#path-effect3767-4-8"
       inkscape:original-d="m 267.24043,857.39452 c 0,0 56.69733,8.20451 85.26062,8.20754 29.24864,0.003 87.3083,-8.3859 87.3083,-8.3859"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac" />
    <path
       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:12, 2;stroke-dashoffset:0"
       d="m 94.105669,856.86337 c 28.076011,-5.41968 56.666311,-8.1719 85.260611,-8.20754 29.28258,-0.0365 58.56801,2.77635 87.30829,8.3859"
       id="path3765-7-4"
       inkscape:path-effect="#path-effect3767-1-0"
       inkscape:original-d="m 94.105669,856.86337 c 0,0 56.697321,-8.20451 85.260611,-8.20754 29.24863,-0.003 87.30829,8.3859 87.30829,8.3859"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac" />
    <path
       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:12, 2;stroke-dashoffset:0"
       d="m 267.66861,856.77198 c 28.07601,-5.41968 56.66631,-8.1719 85.26061,-8.20754 29.28258,-0.0365 58.56801,2.77635 87.30829,8.3859"
       id="path3765-7-4-4"
       inkscape:path-effect="#path-effect3767-1-0-8"
       inkscape:original-d="m 267.66861,856.77198 c 0,0 56.69732,-8.20451 85.26061,-8.20754 29.24863,-0.003 87.30829,8.3859 87.30829,8.3859"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac" />
    <path
       style="fill:none;stroke:#c80000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
       d="m 291.64154,795.46462 c 26.90235,5.4247 54.34192,8.18168 81.78573,8.21738 28.10453,0.0366 56.21199,-2.78122 83.74998,-8.39595"
       id="path3765-1"
       inkscape:path-effect="#path-effect3767-7"
       inkscape:original-d="m 291.64154,795.46462 c 0,0 54.38656,8.21434 81.78573,8.21738 28.05659,0.003 83.74998,-8.39595 83.74998,-8.39595"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac" />
    <path
       style="fill:none;stroke:#c80000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:9, 1.5;stroke-dashoffset:0"
       d="m 292.05226,794.84134 c 26.90235,-5.4247 54.34192,-8.18168 81.78573,-8.21738 28.10453,-0.0366 56.21198,2.78122 83.74997,8.39595"
       id="path3765-7-1"
       inkscape:path-effect="#path-effect3767-1-1"
       inkscape:original-d="m 292.05226,794.84134 c 0,0 54.38656,-8.21434 81.78573,-8.21738 28.05658,-0.003 83.74997,8.39595 83.74997,8.39595"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="cac" />
    <path
       sodipodi:type="arc"
       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
       id="path2985"
       sodipodi:cx="372.85715"
       sodipodi:cy="395.52304"
       sodipodi:rx="154.28572"
       sodipodi:ry="247.14287"
       d="m 527.14287,395.52304 c 0,136.49324 -69.07607,247.14287 -154.28572,247.14287 -85.20965,0 -154.28572,-110.64963 -154.28572,-247.14287 0,-136.49324 69.07607,-247.14287 154.28572,-247.14287 85.20965,0 154.28572,110.64963 154.28572,247.14287 z"
       transform="matrix(1.3093846,0,0,1.3093846,-221.4223,173.77713)" />
    <path
       style="fill:none;stroke:#000000;stroke-width:1.87385845;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
       d="m 306.11278,683.50593 c 0,95.90577 -33.67964,173.65275 -39.32166,173.65275 -6.6995,0 -39.32165,-77.74698 -39.32165,-173.65275 0,-95.90576 30.17035,-173.65274 39.32165,-173.65274 9.15131,0 39.32166,77.74698 39.32166,173.65274 z"
       id="path2987"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="sssss" />
    <path
       sodipodi:type="arc"
       style="fill:#b3b3b3;stroke:#000000;stroke-width:0.64120531;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3.8472319, 0.64120531;stroke-dashoffset:0"
       id="path2991-7-4"
       sodipodi:cx="273.57144"
       sodipodi:cy="433.38019"
       sodipodi:rx="51.785713"
       sodipodi:ry="10.714286"
       d="m 325.35715,433.38019 c 0,5.91733 -23.18525,10.71428 -51.78571,10.71428 -28.60046,0 -51.78571,-4.79695 -51.78571,-10.71428 0,-5.91734 23.18525,-10.71429 51.78571,-10.71429 28.60046,0 51.78571,4.79695 51.78571,10.71429 z"
       transform="matrix(2.7832805,0,0,1.5490066,-494.35602,244.64417)" />
    <path
       style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
       d="m 260.76761,1013.6598 c -6.99466,-0.3235 -16.8269,-1.7513 -23.80459,-3.4568 -37.53847,-9.1753 -72.34311,-34.88831 -100.97293,-74.59692 -4.34208,-6.02231 -10.25816,-14.95601 -10.0452,-15.16897 0.0767,-0.0767 0.94336,0.22642 1.92587,0.67364 4.96329,2.25923 16.86498,4.79053 31.21595,6.63914 32.18324,4.14567 75.56423,6.00749 125.90245,5.40344 46.96673,-0.5636 88.15049,-3.86203 110.42548,-8.84404 4.69004,-1.04897 9.41979,-2.44597 10.96097,-3.23745 0.51703,-0.26555 1.00644,-0.41643 1.08756,-0.33531 0.0812,0.0812 -1.36785,2.43572 -3.21994,5.23243 -11.61754,17.54299 -23.81064,32.06737 -37.99204,45.25591 -31.51364,29.30743 -68.40829,44.14973 -105.48358,42.43493 z"
       id="path3819"
       inkscape:connector-curvature="0" />
    <path
       style="fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none"
       d="m 119.3923,565.37628 c -6.15304,-10.47115 -24.589899,-49.774 -23.344895,-49.76556 0.11201,7.6e-4 4.067485,0.68612 8.789955,1.52303 46.26075,8.19827 100.65096,8.1486 150.42329,-0.13736 9.03447,-1.50403 11.66904,-1.5771 18.68782,-0.51827 24.64235,3.71745 38.65303,5.21157 57.73602,6.15707 31.08824,1.5403 69.46423,-0.68771 96.2635,-5.58884 4.64647,-0.84975 8.66286,-1.33027 8.92533,-1.06781 0.87248,0.87248 -10.78633,27.21327 -18.06691,40.81866 -6.44399,12.042 -7.34059,13.26125 -8.79677,11.96239 -3.61107,-3.22094 -21.70261,-7.24128 -41.52247,-9.22722 -1.94454,-0.19484 -7.62665,-0.82411 -12.62691,-1.39837 -5.00025,-0.57426 -16.13718,-1.3995 -24.74873,-1.83387 -20.15439,-1.0166 -108.06365,-1.02444 -127.7843,-0.0114 -15.10673,0.77602 -44.08188,3.42942 -46.98727,4.30286 -0.84172,0.25305 -3.79642,0.71723 -6.56599,1.03152 -8.0355,0.91187 -20.66496,4.31178 -24.2522,6.52882 l -3.3,2.03951 -2.82947,-4.81516 z"
       id="path3892"
       inkscape:connector-curvature="0"
       transform="translate(0,343.70081)" />
    <path
       style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-mid:none;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
       d="M 600,684.37566 600.0306,27.439751"
       id="path3916"
       inkscape:path-effect="#path-effect3918"
       inkscape:original-d="M 600,684.37566 C 600,27.232803 600.0306,27.439751 600.0306,27.439751"
       inkscape:connector-curvature="0"
       transform="translate(0,343.70081)" />
    <text
       xml:space="preserve"
       style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
       x="614.17279"
       y="391.72241"
       id="text4544"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         id="tspan4546"
         x="614.17279"
         y="391.72241"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:CMU Serif;-inkscape-font-specification:CMU Serif">R</tspan></text>
    <path
       style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
       d="m 587.9765,795.5309 23.55015,0 0.0392,0"
       id="path4548"
       inkscape:path-effect="#path-effect4550"
       inkscape:original-d="m 587.9765,795.5309 c 23.55015,0 23.55015,0 23.55015,0 l 0.0392,0"
       inkscape:connector-curvature="0" />
    <path
       style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
       d="m 587.9765,857.00504 23.55015,0 0.0392,0"
       id="path4548-4"
       inkscape:path-effect="#path-effect4550-1"
       inkscape:original-d="m 587.9765,857.00504 c 23.55015,0 23.55015,0 23.55015,0 l 0.0392,0"
       inkscape:connector-curvature="0" />
    <path
       style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
       d="m 587.9765,917.00504 23.55015,0 0.0392,0"
       id="path4548-3"
       inkscape:path-effect="#path-effect4550-2"
       inkscape:original-d="m 587.9765,917.00504 c 23.55015,0 23.55015,0 23.55015,0 l 0.0392,0"
       inkscape:connector-curvature="0" />
    <text
       xml:space="preserve"
       style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
       x="617.48987"
       y="803.03082"
       id="text4544-2"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         id="tspan4546-2"
         x="617.48987"
         y="803.03082"
         style="font-size:30px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:CMU Serif;-inkscape-font-specification:CMU Serif">c+ε</tspan></text>
    <text
       sodipodi:linespacing="125%"
       id="text4645"
       y="864.50494"
       x="618.2041"
       style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
       xml:space="preserve"><tspan
         style="font-size:30px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:CMU Serif;-inkscape-font-specification:CMU Serif"
         y="864.50494"
         x="618.2041"
         id="tspan4647"
         sodipodi:role="line">c</tspan></text>
    <text
       sodipodi:linespacing="125%"
       id="text4649"
       y="924.50494"
       x="616.06134"
       style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
       xml:space="preserve"><tspan
         style="font-size:30px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:CMU Serif;-inkscape-font-specification:CMU Serif"
         y="924.50494"
         x="616.06134"
         id="tspan4651"
         sodipodi:role="line">c-ε</tspan></text>
    <path
       style="fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
       d="m 266.49336,857.87643 c -6.973,7.54801 -12.69393,16.25 -16.85906,25.64397 -6.6819,15.07024 -9.29521,31.92155 -7.49159,48.30773"
       id="path4653"
       inkscape:path-effect="#path-effect4655"
       inkscape:original-d="m 266.49336,857.87643 c -4.85641,3.56657 -13.828,21.53612 -16.85906,25.64397 -5.28554,7.16323 -7.49159,48.30773 -7.49159,48.30773"
       inkscape:connector-curvature="0"
       sodipodi:nodetypes="csc" />
    <path
       sodipodi:nodetypes="csc"
       inkscape:connector-curvature="0"
       inkscape:original-d="m 266.63974,857.49743 c 5.73632,3.5999 15.93398,22.09454 16.8141,25.88364 2.02448,8.71579 1.9359,15.90208 1.9359,15.90208"
       inkscape:path-effect="#path-effect4659"
       id="path4657"
       d="m 266.63974,857.49743 c 8.02873,6.68133 13.97322,15.83227 16.8141,25.88364 1.45812,5.15898 2.11368,10.54395 1.9359,15.90208"
       style="fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:6,3;stroke-dashoffset:0" />
    <path
       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:none;marker-start:url(#Arrow2Mstart)"
       d="m 247.23483,538.19814 c -6.77522,-10.42278 -9.85443,-23.19651 -8.57239,-35.56155 1.60995,-15.52764 10.20675,-30.19676 22.96707,-39.18975"
       id="path4661"
       inkscape:path-effect="#path-effect4663"
       inkscape:original-d="m 247.23483,538.19814 c 3.61501,-20.78631 -10.75113,-23.0338 -8.57239,-35.56155 7.56224,-43.48289 22.96707,-39.18975 22.96707,-39.18975"
       inkscape:connector-curvature="0"
       transform="translate(0,343.70081)"
       sodipodi:nodetypes="csc" />
    <text
       id="text5223"
       y="808.20941"
       x="261.59702"
       xml:space="preserve"><tspan
         y="808.20941"
         x="261.59702"
         id="tspan5225"
         sodipodi:role="line"
         style="font-size:20px">e<tspan
   style="font-size:65%;baseline-shift:super"
   id="tspan5232">κ</tspan></tspan></text>
  </g>
</svg>
2
  • To make sure this answer is useful in future, it would better to replace the link with the actual code. Feb 9, 2014 at 12:08
  • @suzanne I enhanced the inkscape figure with some new objects. You can find attached the updated code.
    – TeXFun
    Feb 9, 2014 at 14:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .