# Close the corners of a grid (of tubes) on a surface in asymptote

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);
}

``````

and have a look at the 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: I wonder is there a better way? How should I close nicely the connections of the grid lines (tubes if to be more precise)?

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);
}

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 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;

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: • 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

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;