球体表面上的最佳轨迹

时间:2013-10-29 20:26:22

标签: matlab path geometry geometry-surface

我试图找到跳过单位球体表面上不同点的点的轨迹的参数方程,以便:

  1. 每个跳跃很小(pi / 4
  2. 该点尽可能快速且均匀地访问球体的大部分区域
  3. 该点沿着“方向向量”尽可能不同地移动
  4. 这就是我试过的

    N = 3600;    % number of points
    t = (1:N) * pi / 180;    % parameter
    theta_sph = sqrt(2) * t * pi;    % first angle
    phi_sph = sqrt(3) * t * pi;    % second angle
    rho_sph = 1;    % radius
    % Coordinates of a point on the surface of a sphere
    x_sph = rho_sph * sin(phi_sph) .* cos(theta_sph);
    y_sph = rho_sph * sin(phi_sph) .* sin(theta_sph);
    z_sph = rho_sph * cos(phi_sph);
    
    % Check length of jumps (it is intended that this is valid only for small jumps!!!)
    aa = [x_sph(1:(N-1)); y_sph(1:(N-1)); z_sph(1:(N-1))];
    bb = [x_sph(2:N); y_sph(2:N); z_sph(2:N)];
    cc = cross(aa, bb);
    d = rho_sph * atan2(arrayfun(@(n) norm(cc(:, n)), 1:size(cc,2)), dot(aa, bb));
    figure
    plot(d, '.')
    figure
    plot(diff(d), '.')
    
    % Check trajectory on the surface of the sphere
    figure
    hh = 1;
    h_plot3 = plot3(x_sph(hh), y_sph(hh), z_sph(hh), '-');
    hold on
    axis square
    % axis off
    set(gca, 'XLim', [-1 1])
    set(gca, 'YLim', [-1 1])
    set(gca, 'ZLim', [-1 1])
    for hh = 1:N
      h_point3 = plot3(x_sph(hh), y_sph(hh), z_sph(hh), ...
          'o', 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'r');
      drawnow
      delete(h_point3)
      set(h_plot3, 'XData', x_sph(1:hh))
      set(h_plot3, 'YData', y_sph(1:hh))
      set(h_plot3, 'ZData', z_sph(1:hh))
    end
    

    编辑 - > 任何人都可以找到更规则的轨迹,可能更快地覆盖球体(即跳跃次数最少)并且更均匀?规则轨迹,它应该平稳地改变方向,而不是急剧改变方向。审美之美是一种奖励。这些点应尽可能均匀地分布在球体表面上。

5 个答案:

答案 0 :(得分:2)

修改代码的开头以引入底层球体的旋转。这给出了不经常返回极点的轨迹。可能需要对旋转速度进行一些调整以使其看起来“漂亮”(并且当它仅围绕一个轴旋转时可能看起来更好,而不是全部旋转3个)。 rot_angle1围绕x轴旋转,rot_angle2rot_angle3围绕y轴和z轴旋转。也许这至少给你一个想法!

N = 3600;    % number of points
t = (1:N) * pi / 180;    % parameter
theta_sph = sqrt(2) * t * pi;    % first angle
phi_sph = sqrt(3) * t * pi;    % second angle
rho_sph = 1;    % radius
rot_angle1 = sqrt(2) * t * pi;
rot_angle2 = sqrt(2.5) * t * pi;
rot_angle3 = sqrt(3) * t * pi;
% Coordinates of a point on the surface of a sphere
x_sph0 = rho_sph * sin(phi_sph) .* cos(theta_sph);
y_sph0 = rho_sph * sin(phi_sph) .* sin(theta_sph);
z_sph0 = rho_sph * cos(phi_sph);

x_sph1 = x_sph0;
y_sph1 = y_sph0.*cos(rot_angle1)-z_sph0.*sin(rot_angle1);
z_sph1 = y_sph0.*sin(rot_angle1)+z_sph0.*cos(rot_angle1);

x_sph2 = x_sph1.*cos(rot_angle2)+z_sph1.*sin(rot_angle2);
y_sph2 = y_sph1;
z_sph2 = -x_sph1.*sin(rot_angle2)+z_sph1.*cos(rot_angle2);

x_sph = x_sph2.*cos(rot_angle3)-y_sph2.*sin(rot_angle3);
y_sph = x_sph2.*sin(rot_angle3)+y_sph2.*cos(rot_angle3);
z_sph = z_sph2;

答案 1 :(得分:1)

我没有matlab的副本,但我会发布我对你的曲线所做的修改。

为了清楚起见,因为对于球面角度存在n-finity + 1个不同的定义。我将使用以下内容,它从你的定义中向后倾斜,但如果我尝试切换,我肯定会犯错误。

  • \phi - 与z轴的角度
  • \theta - x-y平面中的投影角度。

参数化

t成为从0到pi(包括)的N个均匀间隔点的离散集合。

\phi(t) = t
\theta = 2 * c * t

相当直接且简单,围绕球体的螺旋在\phitheta中是线性的。 c是一个常量,表示\theta中的完整旋转次数,不一定是整数。

邻居点

在您的示例中,您使用atan2(norm(cross....)计算向量之间的角度,这很好,但不会对问题有所了解。你的问题出现在球体表面,使用这个事实。所以我考虑点之间的距离using this formula

现在你找到了相邻的点,这些点发生在t +- dttheta +- 2pi,无论发生什么。

在第一种情况t +- dt中,很容易计算cos(gamma) = 1 - 2 c^2 sin^2(t) dt^2sin^2(t)依赖性是极点更密集的原因。理想情况下,您希望选择theta(t)phi(t),以使dtheta^2 * sin^2(phi)保持不变且最小,以满足此情况。

第二种情况稍微困难一些,并提出我对“惊人”你的观点的评论。如果我们选择N使得dtheta不均匀地划分2pi,那么在theta中围绕球体完全旋转后,我不能直接在前一点之下结束。 要比较这种情况下点之间的距离,请使用delta t以便c delta t = 1。然后你有delta phi = delta tdelta theta = 2 c delta t - 2pi。根据您选择的cdelta phi可能会或可能不会小到可以使用小角度近似值。

最后的笔记

显然c=0是球体的直线。通过增加c,您可以增加“螺旋密度”,从而获得更多的覆盖范围。但是,您也增加了相邻点之间的距离。您需要为所选c选择N,使两个距离公式大致相等。

EDIT 把一些东西搬到了数学家的清洁度

答案 2 :(得分:0)

我在这里编辑,因为它是一个很长的代码。在David和kalhartt的暗示之后,我尝试了这个:

N = 3600;    % number of points
t = (1:N) * pi / 180;    % parameter
% theta_sph much faster than phi_sph to avoid overly visiting the poles
theta_sph = sqrt(20.01) * t * pi;    % first angle
phi_sph = sqrt(.02) * t * pi;    % second angle
rho_sph = 1;    % radius
% Coordinates of a point on the surface of a sphere
x_sph0 = rho_sph * sin(phi_sph) .* cos(theta_sph);
y_sph0 = rho_sph * sin(phi_sph) .* sin(theta_sph);
z_sph0 = rho_sph * cos(phi_sph);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Use David's hint to rotate axes (but only the first now):
rot_angle1 = t * pi / 10;
rot_angle2 = 0;
rot_angle3 = 0;

x_sph1 = x_sph0;
y_sph1 = y_sph0.*cos(rot_angle1)-z_sph0.*sin(rot_angle1);
z_sph1 = y_sph0.*sin(rot_angle1)+z_sph0.*cos(rot_angle1);

x_sph2 = x_sph1.*cos(rot_angle2)+z_sph1.*sin(rot_angle2);
y_sph2 = y_sph1;
z_sph2 = -x_sph1.*sin(rot_angle2)+z_sph1.*cos(rot_angle2);

x_sph = x_sph2.*cos(rot_angle3)-y_sph2.*sin(rot_angle3);
y_sph = x_sph2.*sin(rot_angle3)+y_sph2.*cos(rot_angle3);
z_sph = z_sph2;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Check length of jumps
aa = [x_sph(1:(N-1)); y_sph(1:(N-1)); z_sph(1:(N-1))];
bb = [x_sph(2:N); y_sph(2:N); z_sph(2:N)];
cc = cross(aa, bb);
d = rho_sph * atan2(arrayfun(@(n) norm(cc(:, n)), 1:size(cc,2)), dot(aa, bb));
figure
plot(d, '.')

% Check trajectory on the surface of the sphere
figure
hh = 1;
h_plot3 = plot3(x_sph(hh), y_sph(hh), z_sph(hh), '-');
hold on
axis square
% axis off
set(gca, 'XLim', [-1 1])
set(gca, 'YLim', [-1 1])
set(gca, 'ZLim', [-1 1])
for hh = 1:N
  h_point3 = plot3(x_sph(hh), y_sph(hh), z_sph(hh), ...
      'o', 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'r');
  drawnow
  delete(h_point3)
  set(h_plot3, 'XData', x_sph(1:hh))
  set(h_plot3, 'YData', y_sph(1:hh))
  set(h_plot3, 'ZData', z_sph(1:hh))
end

我认为它比以前好多了!我发现两件事情很重要:1。theta_sph必须比phi_sph快得多,以避免经常访问两个相反的极点; 2.如果theta_sph比phi_sph快,那么你必须在rot_angle1或rot_angle2上慢慢旋转,以获得一个不太乱的轨迹。我仍然愿意接受任何其他提示以改善结果。

答案 3 :(得分:0)

clear all
close all

u = pi/2:(-pi/36):-pi/2;
v = 0:pi/36:2*pi;

nv = length(v);
nu = length(u);

f = myfigure(1);
ax = myaxes(f,1,1);

hold on

for aa = 1:nv
    tv = v(aa);
    for bb = 1:nu
        tu = u(bb);
        x = sin(tu)*cos(tv);
        y = cos(tu)*cos(tv);
        z = sin(tv);
        plot3(x,y,z,'*')
    end
end

编辑:myfigure和myaxes是我创建图形和轴的函数

答案 4 :(得分:0)

我在C中写了一个快速版本,在给定固定数量的点数的情况下表现非常好。你可以在ideone玩它。如果您启用了WebGL浏览器(Chrome,Firefox),则可以粘贴这些结果here以查看它们的绘制情况。由于在推导公式时使用了一些积分近似值,这些极点有点偏,但除此之外很难看到缺陷。除了你想要输出的点数之外,没有任何常量需要调整。

#include <stdio.h>
#include <math.h>

int main(void) {
    int i, numPoints = 200;
    double slope = sqrt(1.2) / sqrt(numPoints);
    for (i = 0; i < numPoints; i++) {
        double s = asin((double)i / (double)(numPoints - 1) * 2.0 - 1.0);
        double z = sin(s);
        double r = sqrt(1.0 - z * z);
        double ss = (2.0 * s + M_PI) / slope;
        double x = cos(ss) * r;
        double y = sin(ss) * r;
        printf("%lf,%lf,%lf,\"1\"\n", x, y, z);
    }
    return 0;
}