![閉合漸近線表面上(管子)網格的角](https://rvso.com/image/281492/%E9%96%89%E5%90%88%E6%BC%B8%E8%BF%91%E7%B7%9A%E8%A1%A8%E9%9D%A2%E4%B8%8A%EF%BC%88%E7%AE%A1%E5%AD%90%EF%BC%89%E7%B6%B2%E6%A0%BC%E7%9A%84%E8%A7%92.png)
考慮以下使用以下簡單繪製的鞍形表面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));
我定義了一些額外的參數和一個函數,可以幫助在正確的位置繪製球體。