三维空间中如何寻找和一组给定直线垂直程度最高的直线

这是个挺有意思的小问题,给定一组直线(至少两条不平行),希望能找到和这组直线尽可能垂直的直线。打个比方,比如在三维空间中,如下图(forked from
wiki)

ab分别是在一个平面上不平行的两条直线上,那么显而易见与ab所在直线垂直程度最高的就是与ab俩俩垂直的竖线,也就是叉积axb方向平行的直线。两条直线可以用叉积,那么多于两条的情况呢?想象如果又有了一条直线,其一端的方向可以用向量c表示,如果cab在一个平面上的话,那么好办,还是axb,或者bxc也行;但是如果cab不在一个平面上的话,那么叉积的办法就不管用了。回到问题的最开始,其实是如何定义和其他直线最大程度垂直。还是考虑只有ab的情况,axb其实就是在ab上的投影均为零,也就是点积为零,所以不妨把在其他所有向量上投影最少的向量定义为最大程度垂直的方向。

那么考虑有n条直线,对应n个单位向量代表每条直线的一个方向,其中第i个向量可以表示为vi=(xi,yi,zi)

,那么对于一个向量v=(x,y,z)

,在vi

上投影的长度为:

|?v,vi? |=|xxi+yyi+zzi|

那么一个很直接的办法就是用优化算法来求出使投影绝对值之和最小的v

min: ∑i=1n|?v,vi? |

subject to: |vi|=1 and |v|=1

|vi|=1

是为了是每一个向量上的投影能够相加比较,|v|=1

是为了优化,否则最后的结果就是(0,0,0)

。这个方法固然直观,但是考虑到1)要利用绝对值相加,2)要利用优化算法还是觉得有些麻烦。考虑一下用平方和作为优化目标,当然这会和绝对值的办法有些许不一样,主要是每一个投影大小对结果影响的sensitivity变了,不过总体而言是差不多的,总之,要求的目标变成了:

i=1n?v,vi?2

=∑i=1n(xxi+yyi+zzi)2

=∑i=1nx2xi2+y2yi2+z2zi2+2xyxiyi+2yzyizi+2zxzixi

=x2i=1nxi2+y2i=1nyi2+z2i=1nzi2+xy∑i=1n2xiyi+yz∑i=1n2yizi+zx∑i=1n2zixi

注意观察最后的展开,如果右边加个等于常数项的话,就是个椭球嘛,而且没有一次项,所以是个中心在原点的椭球。这样一来就很简单了,考虑之前提出的限制条件|v|=1

,相当于有一个半径为1,球心在原点的球面,和一个中心也在原点,大小未定,但是三个极轴比例确定的椭球面。我们要寻找这么一种情况:球面和椭球面有交点(v存在),并且椭球的轴长尽可能小(∑i=1n?v,vi?2

最小)。很显然这种情况就是椭球内切于单位球面,而此时v对应的就是长轴的方向,所以问题就更简单了,我们都不需要求出椭球的具体表达式,而是找出长轴的方向向量就可以了。回顾一下椭球的知识:任意一个椭球可以表达如下:

(v?v0)TM(v?v0)=1

其中v0是中心坐标,当然对于本文的情况这是个零向量,M的特征向量就是三个极轴的方向,特征值就是三个轴半长的平方分之一,所以我们只要求出M,然后找到M对应特征值绝对值最小的那个特征向量,该向量就是我们最终要求的方向向量v。所以,将椭球表达式展开,为简便,首先假设M如下:

M=??  A  D  FDBE??

于是有:

vTMv

=??  x   y   z ??T??  A  D  FDBE????  x   y   z ??

=Ax2+By2+Cz2+2Dxy+2Eyz+2Fzx

把这个结果和前面的公式(3)对照,得到AB、C、DEF的值,代入M,得到如下:

M=????????????  ∑i=1nxi2  ∑i=1nxiyi  ∑i=1nzixii=1nxiyii=1nyi2i=1nyizii=1nzixi i=1nyizi i=1nzi2 ????????????

对这个矩阵求绝对特征值最小的特征向量,就得到了最大程度垂直于给定直线的向量了。需要注意的是当所有给定直线在一个平面时,M不满秩,不过这种情况恰好对应绝对值最小的特征值就是0,所以应用到这个算法里还是没有问题。这个办法还可以类似地推广到二维或者更高维,只不过对三维以上的情况矩阵不满秩的处理会比较麻烦一些。

下面是三维情况下的一段Python验证程序:


 1 from __future__ import division
2 import numpy as np
3 import matplotlib.pyplot as plt
4 from mpl_toolkits.mplot3d import Axes3D
5
6 # Distance from x to the plane with v as the normal vector, passing through (0, 0, 0)
7 d = lambda x, v: abs(x[0]*v[0]+x[1]*v[1]+x[2]*v[2]) / np.linalg.norm(v)
8
9 # Random normal vector for test
10 norm_v_plane = np.random.randn(3)
11 N = 200
12
13 # Generate test unit vectors that within 0.2 to the test plane
14 v_test = [x for x in [x/np.linalg.norm(x) for x in np.random.randn(N, 3)] if d(x, norm_v_plane) < 0.2]
15
16 # Plot test vectors
17 fig = plt.figure(‘Minimum dot product vector‘)
18 ax = fig.add_subplot(111, projection=‘3d‘)
19 for v in v_test:
20 ax.plot([0, v[0]], [0, v[1]], [0, v[2]], ‘b‘)
21
22 # Calculate the coefficients matrix of the arbitrary ellipsoid
23 A, B, C, D, E, F = [0] * 6
24 for v in v_test:
25 x, y, z = v
26 A += x * x
27 B += y * y
28 C += z * z
29 D += x * y
30 E += y * z
31 F += x * z
32 M = np.array([[A, D, F],
33 [D, B, E],
34 [F, E, C]])
35
36 # Pick the eigenvector with the minimum egienvalue
37 u, v = np.linalg.eig(M)
38 vp = v[:, np.argmin(np.abs(u))]
39 if vp[2] < 0:
40 vp = -vp
41
42 ax.plot([0, vp[0]], [0, vp[1]], [0, vp[2]], ‘r‘)
43
44 plt.show()

这段小程序会随机选取一个过原点的平面,然后在距离平面0.2的距离范围内产生一些随机向量,然后找到最大程度垂直于这些向量的向量,比如下图:

三维空间中如何寻找和一组给定直线垂直程度最高的直线,布布扣,bubuko.com

时间: 2024-08-26 11:56:04

三维空间中如何寻找和一组给定直线垂直程度最高的直线的相关文章

【LeetCode-面试算法经典-Java实现】【025-Reverse Nodes in k-Group(单链表中k个结点一组进行反转)】

[025-Reverse Nodes in k-Group(单链表中k个结点一组进行反转)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If the number of nodes is not a multiple of k then left-out nodes i

在字符串中,寻找第一个只出现一次的字符

在字符串中,寻找第一个只出现一次的字符,如str="abddggdbacdd", 结果是c 三种方法: 1. 使用字符字典数组,每个元素是一个结构体,第一个字段记录字符出现的次数,第二个字段记录该字符在字符串中第一次出现的位置, 先遍历一遍字符串,对字符字典数组赋值,然后遍历一遍字符字典数组,找到第一个字段为1,且位置最小的字符即为需要寻找的字符.如下: struct node{ int num; //出现次数 int index; //首次出现的位置 }; char str[1000

Delphi中怎样将字符串按给定字符分隔(类似split函数的功能)

Delphi中怎样将字符串按给定字符分隔(类似split函数的功能) 分类:            Delphi2007-05-16 11:094911人阅读评论(2)收藏举报 delphiintegerstringbutton文本编辑function 今天偶尔要做的Delphi程序,其中涉及到了字符串处理,里面有一个功能类似于VB里的split()函数的功能,于是查了很久才查到些资料,现将这些资料整理一下,方便大家. 首先是一个网友自己编的函数.实现了和split()函数的功能. unit U

【安卓】在java代码中设置drawableLeft时如何给定合适尺寸?

textView.setCompoundDrawables(drawable, null, null, null);时看不到图片,是因为需要手动给定drawable对应的尺寸,即用drawable.setBounds. 如果该drawable为图片,可直接drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());. 即直接给定图片自身尺寸,此时效果和在xml中给定一样. [安卓]在java

php 抓取微信列表中的最新的一组微信消息

<?php $_G['wx_g'] = array('init' => array( "wx_content" => array("weixin_user" => "微信号码", "weixin_pass" => "微信密码") ) ); wx_login(); $messge_list = get_message_list(); $file_id=$messge_list['

将1、2、3、……、81这八十一个连续自然数分成三组,使每组的和相等。三组中个数最多的一组有几个?

1 <script type="text/javascript"> 2 window.onload = function() { 3 var n =81; 4 // 求组数 5 var zushu = Math.floor(n / 2); 6 var sum = (1 + 81) * (zushu) + (zushu + 1) * (n % 2); 7 console.log("总和为:" + sum); 8 var avg = sum / 3; 9 c

线性代数的本质-04补充-三维空间中的线性变换

二维空间向三维空间中扩展,暂且没有感觉有哪些难度,听听视频中是怎么说的? 弹幕刚刚开始,已经有同学理解了矩阵的逆求法的原理,虎躯一震! 按下暂停键思考了一会儿,逆的求法暂且不懂如何变换得来,但是逆的概念应该是反方向变换过程,逆和本身相乘应该是一个没有变换的过程(矩阵考虑成为线性变换),也就是回到最初的初始状态E. 三维矩阵相乘 三维矩阵相乘,同样理解成为线性变换的复合变换,但是并不如二维直观. 原文地址:https://www.cnblogs.com/sky-z/p/9463721.html

用中点Bresenham画直线算法绘制任意斜率直线

使用VC 6.0 mfc实现编程 刚学的图像学,挺难学的,show 代码吧 void CLineView::OnDraw(CDC* pDC) { CLineDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here int x1 ,x2 ,y1,y2 ; x1 = 0 ; y1 = 0 ;  x2 = 1000 ; y2 = 500 ; COLORREF c = RGB(25

SAP 中如何寻找增强

方法一.利用TCODE寻找增强(第二代的增强) 执行一个程序(源代码后附),在选择屏幕处输入你所需要增强的程序TCODE,执行後,就会出现一个列表,那里就有关于如何增强这个的绝大部分SMOD增强. 点击进去,自己手动寻找需要的增强. 这是第二代增强 方法二.利用系统函数寻找         MODX_FUNCTION_ACTIVE_CHECK 在这个FUNCTION的代码最后添加一个断点.执行需要增强的TCODE,如果有增强,就会自动跳入DEBUG界面.在DEBUG界面,查看f_tab字段,这里