向量法计算平面与直线的交点

  已知有平面上三个点(ABC)坐标,直线上两个点(DE)坐标,求平面ABC与直线DE的交点坐标。

  解:

	/**
	 * 平面与直线的交点
	 * 
	 * @param plantA
	 * @param plantB
	 * @param plantC
	 * @param lineD
	 * @param lineE
	 * @return
	 */
	public static double[] getCrossPointOfPlaneAndLine3D(double[] plantA, double[] plantB, double[] plantC,
			double[] lineD, double[] lineE) {
		// ∵点A,点B,点C在平面ABC上
		// ∴向量AB和向量AC在平面ABC上
		double[] arrowAB = arrow(plantA, plantB);
		double[] arrowAC = arrow(plantA, plantC);
		// 由AB和AC可以计算出平面ABC的法向量plantSide
		double[] plantSide = crossMultiply3D(arrowAB, arrowAC);
		// 若法向量长度为0,则点A点B点C在同一直线上,不能确定平面
		if (Math.sqrt(dotMultiply3D(plantSide, plantSide)) == 0) {
			// 面积为0,平面向量不可用
			StaticJavaUtils.exit("不可使用平行的向量定位平面");
		}
		// 三棱锥ABCD的体积的3倍为向量AB×AC·AD
		double[] arrowAD = arrow(plantA, lineD);
		double volumeD = dotMultiply3D(plantSide, arrowAD);
		// 此步之前已证明底面积不为0,若体积为0,则D点在平面ABC上
		if (volumeD == 0) {
			return lineD;
		}
		// 三棱锥ABCE的体积的3倍为向量AB×AC·AE
		double[] arrowAE = arrow(plantA, lineE);
		double volumeE = dotMultiply3D(plantSide, arrowAE);
		// 此步之前已证明底面积不为0,若体积为0,则E点在平面ABC上
		if (volumeE == 0) {
			return lineE;
		}
		// ABCD与ABCE体积相等,说明D与E到平面的距离相等,且在同一侧,即线段与平面平行
		if (volumeD == volumeE) {
			// 直线与平面平行
			return null;
		}
		// 若直线DE与平面ABC不平行,则必能在直线DE上找到一点F,使三棱锥ABCF的体积为0,点F即直线DE与平面ABC的交点
		double[] ans = new double[3];
		for (int i = 0; i < ans.length; ++i) {
			// 坐标缩放和移动,先把原始坐标减原始坐标系缩放中心的坐标,得到相对缩放中心坐标,再按缩放比例(volumeD-volumeE):(lineD的坐标-lineE的坐标)缩放到目标坐标系的相对缩放中心坐标,再加上目标坐标系的缩放中心坐标,就能把原坐标系的坐标线性映射到目标坐标系。此步相当于普通的一元一次函数。这一步将得到直线上0体积的点的坐标。
			ans[i] = StaticMathUtils.axis(volumeD, volumeE, lineD[i], lineE[i], 0)[0];
		}
		return ans;
	}

  axis函数和Matlab的axis函数类似,但是这个axis是对数字进行缩放,不会作用于显示器。与点积、叉积不同,估计很多人不知道axis是怎样实现的。这里附上axis函数:

/**
	 * 缩放坐标(不支持整数操作,因为整数操作比例计算时会失去小数部分,使比例不正确)
	 * 
	 * @param srcMin 原域最小值
	 * @param srcMax 原域最大值
	 * @param dstMin 新域最小值
	 * @param dstMax 新域最大值
	 * @param x      坐标数组
	 * @return 新坐标
	 */
	public static double[] axis(double srcMin, double srcMax, double dstMin, double dstMax, double... x) {
		if (x.length == 0) {
			return null;
		}
        // 假想的摄像机坐标范围
		double mathRange = srcMax - srcMin;
        // 显示器的尺寸范围
		double displayRange = dstMax - dstMin;
        // 两个范围相除就是两个坐标系的缩放比例
		double slope = displayRange / mathRange;
		double[] ret = new double[x.length];
		for (int i = 0; i < x.length; ++i) {
            // 减去缩放中心的坐标,就变成相对缩放中心的临时坐标
			double relativeSrc = x[i] - srcMin;
            // 相对缩放中心进行缩放
			double relativeDst = relativeSrc * slope;
            // 最后加上显示器的缩放中心坐标
			ret[i] = relativeDst + dstMin;
		}
		return ret;
	}

  axis是可以反向映射的,也就是把源坐标范围或目标坐标范围的最大值和最小值换位,就可以变成源坐标增加,目标坐标减小。axis也支持把一个有长度的范围映射到0长度的范围,就是把目标坐标的最大最小设为相等。这个缩放函数与Matlab图表坐标范围设置不同,Matlab有x和y两个缩放比例,这个axis只有一个缩放比例,如果要像Matlab的axis一样缩放,需要分别为x轴和y轴调用axis,并输入各自的映射范围。Matlab的axis的显示器坐标是自动的,此处的这个axis用于数字的换算,换算的范围和比例是未知的,所以才会有一个目标范围。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值