7

Consider the following simple drawing of a saddle surface using asymptote

import graph3;

real f (pair p) {
  real x = p.x;
  real y = p.y;
  return 0.5*(x^2-y^2);
}

surface saddle=surface(f,(-2,-2),(2,2),nx=5,Spline);

draw(saddle,gray,0.1+blue);

and have a look at the snapshot from the output:

snapshot from the output

You can probably see the unpleasent way that the tube, which form the grid lines, join at the corners of the surface. I could probably add, manually, balls of the right radius at the corners as a workaround. For example, add the following line:

draw(shift(-2,-2,f((-2,-2)))*scale(0.05,0.05,0.05)*unitsphere,blue);

and obtain the following improvement: enter image description here

I wonder is there a better way? How should I close nicely the connections of the grid lines (tubes if to be more precise)?

6

As a general rule, unless using settings.render=0, I recommend against using the meshpen option when drawing a surface. Drawing the mesh yourself has a number of advantages; solving your problem is one of the least significant of these advantages.

settings.outformat="png";
settings.render=8;
unitsize(1cm);

import graph3;

currentprojection=perspective(5,5,5);

pen meshpen = 2pt + 0.7blue + 0.1green;

real f (pair p) {
  real x = p.x;
  real y = p.y;
  return 0.5*(x^2-y^2);
}

surface saddle=surface(f,(-2,-2),(2,2),nx=5,Spline);

draw(saddle, surfacepen=gray);

for(int x = -2; x <= 2; ++x) {
  draw(graph(new triple(real y) {return (x,y,f((x,y)) );}, -2, 2), meshpen);
}
for (int y = -2; y <= 2; ++y) {
  draw(graph(new triple(real x) {return (x,y,f((x,y)) );}, -2, 2), meshpen);
}

has result

enter image description here

Note that I generally prefer much thinner gridlines, but have made these thick so that you can actually see whether your problem shows up.

On the other hand, if you actually want the gridlines to be thick and shaded like tubes, then your solution is a pretty good one; basically, you are adding round caps to the lines (which is done automatically when you draw the gridlines without tube shading). If you want to draw tubular paths by hand, you should check out the tube method, which is described in the manual section on the three module (p. 134 in the manual for Asymptote 2.23). An alternative using this approach would be to draw (a tube for) the cyclic path at the edge of the graph, instead of or addition to drawing the gridlines at the edge of the grid.


Update: Here is how to draw the mesh by hand (with tubes and a separate outline). I've changed the name of the the pen to avoid confusion. Note that the operator & is for concatenating two paths that share an endpoint.

settings.outformat="png";
settings.render=8;
unitsize(1cm);

import graph3;

surface operator cast(tube t) {
  return t.s;
}

currentprojection=perspective(5,5,5);

pen gridpen = blue;

real f (pair p) {
  real x = p.x;
  real y = p.y;
  return 0.5*(x^2-y^2);
}

int xmin = -2, xmax=2, ymin=-2, ymax=2;

surface saddle=surface(f,(xmin,ymin),(xmax,ymax),nx=5,Spline);

draw(saddle, surfacepen=gray);

int nx=5, ny=5;

path3 x_equals(real x) {
  return graph(new triple(real y) {return (x,y,f((x,y)));}, ymin, ymax);
}
path3 y_equals(real y) {
  return graph(new triple(real x) {return (x,y,f((x,y)));}, xmin, xmax);
}

real tubewidth = 0.1;

for(int i = 1; i < nx; ++i) {
  real x = (xmax-xmin)*(i/nx) + xmin;
  surface todraw = tube(x_equals(x), width=tubewidth);
  draw(todraw, gridpen);
}
for (int i = 1; i < ny; ++i) {
  real y = (ymax-ymin)*(i/ny) + ymin;
  surface todraw = tube(y_equals(y), width=tubewidth);
  draw(todraw, gridpen);
}

path3 outline = x_equals(xmin) & y_equals(ymax) & reverse(x_equals(xmax)) & reverse(y_equals(ymin)) & cycle;
draw(tube(outline,width=tubewidth), gridpen);

The result:

enter image description here

  • You say you're against meshpen but you're still using it - can you explain? Am I using it implicitly? – Dror Dec 28 '13 at 17:19
  • BTW: I didn't mean to have tube-like gridlines, but I liked the result. – Dror Dec 28 '13 at 17:20
  • @Dror: I'm using meshpen as the name a variable. What I generally recommend against is something like draw(s, gray, blue); where s is a surface. If you refer to optional parameters by name (which allows you to mix up the order), this command becomes draw(s, surfacepen=gray, meshpen=blue);. My recommendation is that the third parameter meshpen=blue be eliminated. – Charles Staats Dec 28 '13 at 18:10
  • Thanks for the clarification. I have two more questions: 1. What is the role of the first function (with the cast), and what is t.s? 2. Correct me if I'm wrong, but your solution yields a much "heavier" graphics. In what other ways your approach is better (as per the first paragraph of your answer) – Dror Dec 29 '13 at 6:12
  • @Dror: 1. The tube function used farther down in the code returns an object of type tube. The purpose of the cast function is to tell Asymptote it is allowed to convert a tube to a surface automatically (for instance, if a tube is passed to a draw command). Here is the conversion procedure: If t is an object of type tube, then t.center is the path3 running through the center and t.s is the surface corresponding to the actual tube. When I pass a tube (call it t) to the draw command, Asymptote knows to use the surface t.s instead. – Charles Staats Dec 29 '13 at 19:20
2

Here is the workaround I mentioned in the OP.

import graph3;

real gridWidth=0.05;
pen  gridPen=blue;

real f (pair p) {
  real x = p.x;
  real y = p.y;
  return 0.5*(x^2-y^2);
}

void fillGap (pair p) {
  real width=0.5*gridWidth;
  draw(shift(p.x,p.y,f(p))*scale(width,width,width)*unitsphere,gridPen);
}

real minVal = -2;
real maxVal = -minVal;

surface saddle=surface(f,(minVal,minVal),(maxVal,maxVal),nx=5,Spline);

draw(saddle,gray+opacity(0.95),gridWidth+gridPen);

fillGap((minVal,minVal));
fillGap((minVal,maxVal));
fillGap((maxVal,minVal));
fillGap((maxVal,maxVal));

I defined some extra parameters and a function that can help drawing the sphere at the right places.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.