Feche os cantos de uma grade (de tubos) em uma superfície em assíntota

Feche os cantos de uma grade (de tubos) em uma superfície em assíntota

Considere o seguinte desenho simples de uma superfície de sela usandoasymptote

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

e dê uma olhada no instantâneo da saída:

instantâneo da saída

Você provavelmente pode ver a maneira desagradável com que os tubos, que formam as linhas da grade, se unem nos cantos da superfície. Eu provavelmente poderia adicionar, manualmente, bolas com o raio certo nos cantos como solução alternativa. Por exemplo, adicione a seguinte linha:

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

e obtenha a seguinte melhoria: insira a descrição da imagem aqui

Eu me pergunto se existe uma maneira melhor? Como devo fechar bem as conexões das linhas de grade (tubos, para ser mais preciso)?

Responder1

Como regra geral, a menos que use settings.render=0, não recomendo usar a meshpenopção ao desenhar uma superfície. Desenhar você mesmo a malha tem várias vantagens; resolver seu problema é uma das vantagens menos significativas.

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

tem resultado

insira a descrição da imagem aqui

Observe que geralmente prefiro linhas de grade muito mais finas, mas as tornei mais grossas para que você possa realmente ver se o seu problema aparece.

Por outro lado, se você realmente deseja que as linhas de grade sejam grossas e sombreadas como tubos, então sua solução é muito boa; basicamente, você está adicionando tampas redondas às linhas (o que é feito automaticamente quando você desenha as linhas de grade sem sombreamento de tubo). Se você quiser desenhar caminhos tubulares manualmente, você deve verificar o tubemétodo, que está descrito na seção do manual do threemódulo (p. 134 no manual do Assíntota 2.23). Uma alternativa para usar esta abordagem seria desenhar (um tubo para) o caminho cíclico na borda do gráfico, em vez de desenhar as linhas de grade na borda da grade.


Atualização: Veja como desenhar a malha à mão (com tubos e contorno separado). Mudei o nome da caneta para evitar confusão. Observe que o operador &serve para concatenar dois caminhos que compartilham um ponto final.

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

O resultado:

insira a descrição da imagem aqui

Responder2

Aqui está a solução alternativa que mencionei no 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));

Defini alguns parâmetros extras e uma função que pode ajudar a desenhar a esfera nos lugares certos.

informação relacionada