用渐近线封闭表面上网格(管)的角

用渐近线封闭表面上网格(管)的角

考虑以下使用以下简单的马鞍形曲面图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);

并查看输出的快照:

输出快照

您可能已经看到了令人不快的方式,即构成网格线的管子在表面的角落处连接。我可能会手动在角落处添加半径合适的球作为解决方法。例如,添加以下行:

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

并获得以下改进: 在此处输入图片描述

我想知道有没有更好的方法?我应该如何完美地关闭网格线(更准确地说是管子)的连接?

答案1

作为一般规则,除非使用settings.render=0,否则我建议不要meshpen在绘制表面时使用该选项。自己绘制网格有许多优点;解决问题是这些优点中最不重要的一个。

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

有结果

在此处输入图片描述

请注意,我通常更喜欢更细的网格线,但我把它们弄粗了,以便您可以真正看到您的问题是否出现。

另一方面,如果您确实希望网格线变粗并且像管子一样有阴影,那么您的解决方案就很不错;基本上,您要为线条添加圆形端点(当您绘制没有管子阴影的网格线时,这会自动完成)。如果您想手动绘制管状路径,您应该查看tube模块手册部分中描述的方法three(Asymptote 2.23 手册第 134 页)。使用此方法的另一种方法是在图形边缘绘制(管子)循环路径,而不是在网格边缘绘制网格线。


更新:以下是手工绘制网格的方法(使用管子和单独的轮廓)。我更改了笔的名称以避免混淆。请注意,该运算符&用于连接共享一个端点的两条路径。

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

结果:

在此处输入图片描述

答案2

这是我在 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));

我定义了一些额外的参数和一个可以帮助在正确的位置绘制球体的函数。

相关内容