我试图找到跳过单位球体表面上不同点的点的轨迹的参数方程,以便:
这就是我试过的
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
编辑 - > 任何人都可以找到更规则的轨迹,可能更快地覆盖球体(即跳跃次数最少)并且更均匀?规则轨迹,它应该平稳地改变方向,而不是急剧改变方向。审美之美是一种奖励。这些点应尽可能均匀地分布在球体表面上。
答案 0 :(得分:2)
修改代码的开头以引入底层球体的旋转。这给出了不经常返回极点的轨迹。可能需要对旋转速度进行一些调整以使其看起来“漂亮”(并且当它仅围绕一个轴旋转时可能看起来更好,而不是全部旋转3个)。 rot_angle1
围绕x轴旋转,rot_angle2
和rot_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
相当直接且简单,围绕球体的螺旋在\phi
和theta
中是线性的。 c
是一个常量,表示\theta
中的完整旋转次数,不一定是整数。
在您的示例中,您使用atan2(norm(cross....)
计算向量之间的角度,这很好,但不会对问题有所了解。你的问题出现在球体表面,使用这个事实。所以我考虑点之间的距离using this formula
现在你找到了相邻的点,这些点发生在t +- dt
和theta +- 2pi
,无论发生什么。
在第一种情况t +- dt
中,很容易计算cos(gamma) = 1 - 2 c^2 sin^2(t) dt^2
。 sin^2(t)
依赖性是极点更密集的原因。理想情况下,您希望选择theta(t)
和phi(t)
,以使dtheta^2 * sin^2(phi)
保持不变且最小,以满足此情况。
第二种情况稍微困难一些,并提出我对“惊人”你的观点的评论。如果我们选择N使得dtheta
不均匀地划分2pi,那么在theta
中围绕球体完全旋转后,我不能直接在前一点之下结束。
要比较这种情况下点之间的距离,请使用delta t
以便c delta t = 1
。然后你有delta phi = delta t
和delta theta = 2 c delta t - 2pi
。根据您选择的c
,delta 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;
}