更新
如果没有等价于silhouette
您能否对我的以下想法发表评论:我可以使用变换获得表面的投影planeproject
。这仍然是一个三维表面,但也许从这个更简单的表面提取轮廓路径更容易?如果这也不可能,也许以下算法可以奏效:
planeproject
表面- 提取变换表面上的密集点网格(这些点应位于同一平面内);或者甚至可以通过某种方式提取平坦表面的边界点(可能通过使它们的斜率不同于平坦表面其他点的斜率)
- 使用一些凹壳算法(当然,必须首先实现)来找到上述点的凹壳。
- 使用沿凹壳的路径作为轮廓
这里我特别不确定是否有简单的方法可以完成第 2 步。我必须考虑当凹壳由多条路径组成时该怎么做,例如对于圆环,你可以得到外部轮廓和中间的洞。你认为这可能吗?
原始问题
该solids
包定义了revolution
一些对象,它们的轮廓可以通过 来访问silhouette
。例如:
size(200);
import solids;
settings.render=0;
settings.prc=false;
currentprojection=perspective(4,4,3);
revolution hyperboloid=revolution(new real(real x) {return sqrt(1+x*x);},
-2,2,20,operator..,X);
draw(hyperboloid.silhouette(64),blue);
有没有等效的方法来获取 的轮廓路径surface
?例如这样的 的轮廓surface
(我知道此示例中的对象是球对称的,因此我可以定义 来revolution
描述它,但我想知道是否有通用的方法来获取 的轮廓surface
):
import graph3;
import palette;
size(200);
currentprojection=orthographic(6,8,2);
viewportmargin=(1cm,0);
real c0=0.1;
real f(real r) {return r*(1-r/6)*exp(-r/3);}
triple f(pair t) {
real r=t.x;
real phi=t.y;
real f=f(r);
real s=max(min(c0/f,1),-1);
real R=r*sqrt(1-s^2);
return (R*cos(phi),R*sin(phi),r*s);
}
bool cond(pair t) {return f(t.x) != 0;}
real R=abs((20,20,20));
surface s=surface(f,(0,0),(R,2pi),100,8,Spline,cond);
s.colors(palette(s.map(abs),Gradient(palegreen,heavyblue)));
render render=render(compression=Low,merge=true);
draw(s,render);
draw(zscale3(-1)*s);
答案1
好的,我想我或多或少已经找到解决方案了。
Silhouette函数由以下代码定义:
import graph3;
import contour;
// A bunch of auxiliary functions.
real fuzz = .001;
real umin(surface s) { return 0; }
real vmin(surface s) { return 0; }
pair uvmin(surface s) { return (umin(s), vmin(s)); }
real umax(surface s, real fuzz=fuzz) {
if (s.ucyclic()) return s.index.length;
else return s.index.length - fuzz;
}
real vmax(surface s, real fuzz=fuzz) {
if (s.vcyclic()) return s.index[0].length;
return s.index[0].length - fuzz;
}
pair uvmax(surface s, real fuzz=fuzz) { return (umax(s,fuzz), vmax(s,fuzz)); }
typedef real function(real, real);
function normalDot(surface s, triple eyedir) {
real toreturn(real u, real v) {
return dot(s.normal(u, v), eyedir);
}
return toreturn;
}
guide[] normalpathuv(surface s, triple eyedir, int n = ngraph) {
return contour(normalDot(s, eyedir), uvmin(s), uvmax(s), new real[] {0}, nx=n)[0];
}
path3 onSurface(surface s, path p) {
triple f(real t) {
pair point = point(p,t);
return s.point(point.x, point.y);
}
if (cyclic(p)) {
guide3 toreturn = f(0);
for (int i = 1; i < size(p); ++i)
toreturn = toreturn -- f(i);
toreturn = toreturn -- cycle;
return toreturn;
}
return graph(f, 0, length(p));
}
/*
* This method returns an array of paths that trace out all the
* points on s at which s is parallel to eyedir.
*/
path3[] silhouetteNoEdges(surface s, triple eyedir, int n = ngraph) {
guide[] uvpaths = normalpathuv(s, eyedir, n);
path3[] toreturn = new path3[uvpaths.length];
for (int i = 0; i < uvpaths.length; ++i) {
toreturn[i] = onSurface(s, uvpaths[i]);
}
return toreturn;
}
/*
* Now, add in the edges (if there are any).
*/
path3[] silhouette(surface s, triple eyedir, int n = ngraph) {
path3[] toreturn = silhouetteNoEdges(s, eyedir, n);
if (!s.ucyclic()) {
toreturn.push(s.uequals(umin(s)));
toreturn.push(s.uequals(umax(s)));
}
if (!s.vcyclic()) {
toreturn.push(s.vequals(vmin(s)));
toreturn.push(s.vequals(vmax(s)));
}
return toreturn;
}
将上述代码保存在名为的文件中后silhouette.asy
,您可以按照以下方式绘制表面轮廓:
settings.outformat="pdf";
int resolutionfactor = 4;
settings.render=2.resolutionfactor;
settings.prc=false;
import silhouette;
size(200);
triple eye = (6,8,2);
currentprojection=orthographic(eye);
viewportmargin=(1cm,0);
real c0=0.1;
real f(real r) {return r*(1-r/6)*exp(-r/3);}
/* Note that the function below has been modified so as not to throw a divide by zero error
* when f(r) == 0.
*/
triple f(pair t) {
real r=t.x;
real phi=t.y;
real f=f(r);
real s;
//This assumes c0 > 0
if (0 > f && f > -c0) s = -1;
else if (0 <= f && f < c0) s = 1;
else s = c0/f;
//real s=max(min(c0/f,1),-1);
real R=r*sqrt(1-s^2);
return (R*cos(phi),R*sin(phi),r*s);
}
bool cond(pair t) {return f(t.x) != 0;}
real R=abs((20,20,20));
surface s=surface(f,(0,0),(R,2pi),nu=100,nv=8,Spline);
draw(silhouette(s,eye,n=200));
draw(s,surfacepen=emissive(white));
surface s2 = zscale3(-1)*s;
draw(silhouette(s2, eye, n=200));
draw(s2, surfacepen=emissive(white));
shipout(scale(resolutionfactor)*currentpicture.fit());
结果如下: