MATLAB - 获取点阵列之间的角度

MATLAB - get angle between arrays of points

为了照明分析,基于this document,我试图确定一组灯光和固体表面上一系列点的三件事:

(图片重点:蓝色大点是显示光照方向的灯,小点是我表面的点)

请注意,在此图像中,我复制了法线向量并将其移动以更清楚地显示角度。

最初我嵌套了 for 循环遍历实体上的所有灯光和点,但现在我正在尽最大努力以真正的 MATLAB 风格使用矩阵来完成它:

我已经用pdist2函数找到了所有点之间的距离,但是还没有找到类似的方法来找到灯光和所有点之间的角度,也没有找到灯光和法线之间的角度点的向量。我宁愿用矩阵方法而不是像我一直使用的那样用迭代来做到这一点。

考虑到我已经列出了数据,其中 Lmat 的每一列都有我的 x,y,z 灯的位置向量; Dmat 给出每个光的 x,y,z 方向,因此这两个矩阵的每一行的组合完全定义了光及其朝向的方向。同样,Omeganmat 对曲面上的点执行相同的操作。

我相当确定要获得角度,我想按照以下方式做一些事情:

distMatrix = pdist2(Omega, Lmat);

LmatNew = zeros(numPoints, numLights, 3);
DmatNew = zeros(numPoints, numLights, 3);
OmegaNew = zeros(numPoints, numLights, 3);
nmatNew = zeros(numPoints, numLights, 3);
for i = 1:numLights
    LmatNew(:,i,1) = Lmat(i,1);
    LmatNew(:,i,2) = Lmat(i,2);
    LmatNew(:,i,3) = Lmat(i,3);

    DmatNew(:,i,1) = Dmat(i,1);
    DmatNew(:,i,2) = Dmat(i,2);
    DmatNew(:,i,3) = Dmat(i,3);
end

for j = 1:numPoints
    OmegaNew(j,:,1) = Omega(j,1);
    OmegaNew(j,:,2) = Omega(j,2);
    OmegaNew(j,:,3) = Omega(j,3);

    DmatNew(:,i,1) = Dmat(i,1);
    DmatNew(:,i,2) = Dmat(i,2);
    DmatNew(:,i,3) = Dmat(i,3);
end


angleMatrix = -dot(LmatNew-OmegaNew, DmatNew, 3);
angleMatrix = atand(angleMatrix);

angleMatrix = angleMatrix.*(angleMatrix > 0);

但我在概念上陷入困境,试图弄清楚在我的点积之后要做什么。

我走在正确的轨道上吗?是否有我忽略的相当于 pdist2 的内置角度?

感谢大家的帮助,对于油漆图像感到抱歉!

上下文:这张图片显示了我的灯光(大蓝点)、灯光朝向(黑色小痕迹)和我的模型。

根据MathWorks,没有built-in函数来计算向量之间的角度。但是,您可以使用三角函数来计算角度。

输入

很遗憾,由于您没有详细解释您的输入数据,我将假设您有一个矩阵 Lmat,每行包含一个光源的位置向量和一个矩阵 Dmat 包含光源的方向向量,大小均为 n×3,其中 n 是光源的数量现场.

矩阵OmegaNmat的大小应该是m×3,包含所有的位置向量和法向量m 个曲面点。想要的结果是所有光线方向向量和表面法线向量之间的夹角,其中有nm,光线之间的夹角方向向量和连接光线到表面上每个点的向量,其中有nm

要获得所有光源和表面点组合的结果,必须垂直重复输入矩阵:

Lmat  = repmat(Lmat,  size(Omega,1), 1);
Dmat  = repmat(Dmat,  size(Omega,1), 1);
Omega = repmat(Omega, size(Lmat,1),  1);
Nmat  = repmat(Nmat,  size(Lmat,1),  1);

使用内积/点积

两个向量内积的定义是

其中 θ 是两个向量之间的角度。对等式重新排序得到

因此,您可以像这样计算方向向量 Dmat 和法线向量 Nmat 之间的角度:

normProd = sqrt(sum(Dmat.^2,2)).*sqrt(sum(Nmat.^2,2));
anglesInDegrees = acos(dot(Dmat.',Nmat.')' ./ normProd) * 180 / pi;

要计算 light-to-point 向量与方向向量之间的角度,只需将 Nmat 替换为 Omega - Lmat

使用向量积/叉积

mentioned 上述方法在非常小的 (θ ≈ 0°) 或非常大的 (θ ≈ 180°) 角度时会出现精度问题。建议的解决方案是使用叉积和内积计算角度。

两个向量的向量积的范数是

可以结合上面定义的内积得到

显然可以重新排序为:

相应的 MATLAB 代码如下所示:

normCross = sqrt(sum(cross(Dmat,Nmat,2).^2,2));
anglesInDegrees = atan2(normCross,dot(Dmat.',Nmat.')') * 180/pi;