填充球体上的封闭区域

填充球体上的封闭区域

给定球体上多个点的经度和纬度坐标,我可以使用圆弧段连接它们,方法Arc是使用渐近线

path3 arc(triple c,real r,real theta1,real phi1,real theta2,real phi2,triple normal=O);

举例来说,给定(-10,0)(0,10)(10,0)(-10,0)度数,我可以使用以下代码在球体上绘制四个黑色圆弧,使其看起来像是我从头到尾连接了四个点(并循环)。

settings.render = 0;

import solids;
import three;
size(6cm);

real zenith  = pi/12.0;
real azimuth = pi/12.0;
currentprojection = perspective(cos(azimuth)*cos(zenith),
                                sin(azimuth)*cos(zenith),
                                sin(zenith));
real r = 1;
real ar = 1.2;

path3 myarc = Arc(c=O,normal=X, v1=-Z*r, v2=Z*r, n=12);
surface sphere = surface(myarc, angle1=0, angle2=360, c=O, axis=Z, n=12);

draw((0,0,  0)--(ar,0,0),   red+linewidth(1pt));
draw((0,0,  0)--(0,ar,0), green+linewidth(1pt));
draw((0,0,-ar)--(0,0,ar),  blue+linewidth(1pt));

label("$S$",(0,0,-ar),S);
draw(sphere, surfacepen=material(white+opacity(0.8),ambientpen=white));
label("$N$",(0,0,ar),N);

pair[] region = new pair[] {(-10,0),(0,10),(10,0),(0,-10),(-10,0)};
for(int i=1; i<region.length; ++i){
  pair one, two;
  if(region[i-1].y < region[i].y){
    one = (region[i]  .x, 90 - region[i]  .y);
    two = (region[i-1].x, 90 - region[i-1].y);
  }else if(region[i-1].y > region[i].y){
    one = (region[i-1].x, 90 - region[i-1].y);
    two = (region[i]  .x, 90 - region[i]  .y);
  }else if(region[i-1].x > region[i].x){
    one = (region[i]  .x, 90 - region[i]  .y);
    two = (region[i-1].x, 90 - region[i-1].y);
  }else{
    one = (region[i-1].x, 90 - region[i-1].y);
    two = (region[i]  .x, 90 - region[i]  .y);
  }
  path3 temp = arc(O,r,one.y,one.x,two.y,two.x);
  draw(temp,black+linewidth(.5pt));
}

笔记:if - else if - else if - else块用于绘制每对点之间两个可能的圆弧中较短的圆弧。

上述代码在未启用 3D 查看器的情况下生成了此图像。

上述代码的输出

现在,我想用任意颜色填充球体上的该区域(例如,透明度为 50% 的红色)。如何使用渐近线

答案1

抱歉,我在第一个答案中对区域(平行圆和大圆)造成了混淆,您可以在最后看到代码(对于小于 30 的小角度值,近似值是可以的)。

关于第二种解决方案,即用单个面片构造区域,计算导数很容易(从 Asymptote 的弧计算),但得到的表面与期望结果相差甚远(尝试oo3在代码中绘制表面)。我认为通过将区域分解为 4 或 8 个部分是可能的,但无论如何,计算贝塞尔面片的内部控制点至关重要。它需要一些关于贝塞尔面片和曲面近似的知识。

所以我尝试完成第一个解决方案:区域的参数定义。由于我不想自己定义,所以我使用了Arc渐近线的定义。奇怪的需要参数化(参见 f 的定义)以避免插值中的一些数值伪影,并且您可以识别切比雪夫点。对于小于或等于 80 的角度,这似乎没问题。请考虑代码

import solids;
import three;
size(6cm);

real zenith  = pi/12.0;
real azimuth = pi/12.0;
currentprojection = perspective(cos(azimuth)*cos(zenith),
                                sin(azimuth)*cos(zenith),
                                sin(zenith));
real r = 1;
real ar = 1.2;

path3 myarc = Arc(c=O,normal=X, v1=-Z*r, v2=Z*r, n=12);
surface sphere = surface(myarc, angle1=0, angle2=360, c=O, axis=Z, n=12);

draw((0,0,  0)--(ar,0,0),   red+linewidth(1pt));
draw((0,0,  0)--(0,ar,0), green+linewidth(1pt));
draw((0,0,-ar)--(0,0,ar),  blue+linewidth(1pt));

label("$S$",(0,0,-ar),S);
draw(sphere, surfacepen=material(white+opacity(0.8),ambientpen=white));
label("$N$",(0,0,ar),N);
real angle=80;
path3[] aar;
pair[] region = new pair[] {(-angle,0),(0,angle),(angle,0),(0,-angle),(-angle,0)};
for(int i=1; i<region.length; ++i){
  pair one, two;
  if(region[i-1].y < region[i].y){
    one = (region[i]  .x, 90 - region[i]  .y);
    two = (region[i-1].x, 90 - region[i-1].y);
  }else if(region[i-1].y > region[i].y){
    one = (region[i-1].x, 90 - region[i-1].y);
    two = (region[i]  .x, 90 - region[i]  .y);
  }else if(region[i-1].x > region[i].x){
    one = (region[i]  .x, 90 - region[i]  .y);
    two = (region[i-1].x, 90 - region[i-1].y);
  }else{
    one = (region[i-1].x, 90 - region[i-1].y);
    two = (region[i]  .x, 90 - region[i]  .y);
  }
  path3 temp = Arc(O,r,one.y,one.x,two.y,two.x,32);
  draw(temp,black+linewidth(.5pt));
  aar.push(temp);
}
dot((cos(angle/180*pi),sin(angle/180*pi),0));
triple AA=(cos(angle/180*pi),sin(angle/180*pi),0);
dot((cos(angle/180*pi),sin(-angle/180*pi),0),blue);
triple BB=(cos(angle/180*pi),sin(-angle/180*pi),0);
dot((cos(angle/180*pi),0,-sin(angle/180*pi)),red);
triple CC=(cos(angle/180*pi),0,-sin(angle/180*pi));
dot((cos(angle/180*pi),0,sin(angle/180*pi)),green);
triple DD=(cos(angle/180*pi),0,sin(angle/180*pi));

real angr=angle/180*pi;
triple f(pair t)
{
  triple x1=point(aar[1],(1+cos((2*t.x+1)*pi))/2*length(aar[1]));
  triple x2=point(aar[3],(1+cos((2*t.x+1)*pi))/2*length(aar[3]));
  path3 temp_arc=Arc(O,x1,x2,32);
  return(point(temp_arc, (1+cos((2*t.y+1)*pi))/2*length(temp_arc)));
}
surface s=surface(f,(0,0),(1,1),32,32,Spline);
draw(shift(0.005*ar,0,0)*s,2bp+blue);

patch oo3=patch(AA{-dir(aar[1])}..{-dir(aar[1],0)}DD{dir(aar[0],0)}..{dir(aar[0])}BB{dir(aar[3],0)}..{dir(aar[3])}CC{-dir(aar[2])}..{-dir(aar[2],0)}cycle);

并使用 OpenGL 渲染器得到的结果(角度=80)。

在此处输入图片描述

上一个答案: 通过一些计算,就可以通过参数表面描述该区域,然后绘制它。

按照 Charles Staats 的指示,您可以使用构造函数对表面进行近似patch。通过指定顶点处的切线,近似对于低角度是可以的。最好的方法应该是计算表面的最后四个控制点(参见 中的球体定义)。为了避免一些伪影,表面被移动,并与OpenGL 渲染器three_surface.asy一起工作。render=0

import solids;
import three;
size(6cm);

real zenith  = pi/12.0;
real azimuth = pi/12.0;
currentprojection = perspective(cos(azimuth)*cos(zenith),
                               sin(azimuth)*cos(zenith),
                               sin(zenith));
real r = 1;
real ar = 1.2;

path3 myarc = Arc(c=O,normal=X, v1=-Z*r, v2=Z*r, n=12);
surface sphere = surface(myarc, angle1=0, angle2=360, c=O, axis=Z, n=12);

draw((0,0,  0)--(ar,0,0),   red+linewidth(1pt));
draw((0,0,  0)--(0,ar,0), green+linewidth(1pt));
draw((0,0,-ar)--(0,0,ar),  blue+linewidth(1pt));

label("$S$",(0,0,-ar),S);
draw(sphere, surfacepen=material(white+opacity(0.8),ambientpen=white));
label("$N$",(0,0,ar),N);

pair[] region = new pair[] {(-10,0),(0,10),(10,0),(0,-10),(-10,0)};
triple[] mypoints;
for(int i=1; i<region.length; ++i){
  pair one, two;
  if(region[i-1].y < region[i].y){
    one = (region[i]  .x, 90 - region[i]  .y);
    two = (region[i-1].x, 90 - region[i-1].y);
  }else if(region[i-1].y > region[i].y){
    one = (region[i-1].x, 90 - region[i-1].y);
    two = (region[i]  .x, 90 - region[i]  .y);
  }else if(region[i-1].x > region[i].x){
    one = (region[i]  .x, 90 - region[i]  .y);
    two = (region[i-1].x, 90 - region[i-1].y);
  }else{
    one = (region[i-1].x, 90 - region[i-1].y);
    two = (region[i]  .x, 90 - region[i]  .y);
  }
  path3 temp = arc(O,r,one.y,one.x,two.y,two.x);
  draw(temp,black+linewidth(.5pt));
}
real angle=10;
dot((cos(angle/180*pi),sin(angle/180*pi),0));
triple AA=(cos(angle/180*pi),sin(angle/180*pi),0);
dot((cos(angle/180*pi),sin(-angle/180*pi),0),blue);
triple BB=(cos(angle/180*pi),sin(-angle/180*pi),0);
dot((cos(angle/180*pi),0,-sin(angle/180*pi)),red);
triple CC=(cos(angle/180*pi),0,-sin(angle/180*pi));
dot((cos(angle/180*pi),0,sin(angle/180*pi)),green);
triple DD=(cos(angle/180*pi),0,sin(angle/180*pi));

patch oo=patch(AA{cross(AA,AA-CC)}..{cross(DD,DD-BB)}DD{cross(DD,DD-AA)}.. {cross(BB,BB-CC)}BB{cross(BB,BB-DD)}..{cross(CC,CC-AA)}CC{cross(CC,AA-DD)}..{cross(AA,AA-DD)}cycle);
draw(shift(.005*ar,0,0)*surface(oo),blue);

结果 在此处输入图片描述

对于角度=45,差异很明显(使用 OpenGL 渲染器)...

相关内容