计算几何模板补充(三维空间体积、平面、直线、向量相关计算。附上hdu4741,求异面直线的最短距离与交点)

181 篇文章 0 订阅
173 篇文章 3 订阅


转自:http://www.cnblogs.com/wulangzhou/p/3326187.html


Link:http://acm.hdu.edu.cn/showproblem.php?pid=4741


Save Labman No.004

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1839    Accepted Submission(s): 603


Problem Description
Due to the preeminent research conducted by Dr. Kyouma, human beings have a breakthrough in the understanding of time and universe. According to the research, the universe in common sense is not the only one. Multi World Line is running simultaneously. In simplicity, let us use a straight line in three-dimensional coordinate system to indicate a single World Line.

During the research in World Line Alpha, the assistant of Dr. Kyouma, also the Labman No.004, Christina dies. Dr. Kyouma wants to save his assistant. Thus, he has to build a Time Tunnel to jump from World Line Alpha to World Line Beta in which Christina can be saved. More specifically, a Time Tunnel is a line connecting World Line Alpha and World Line Beta. In order to minimizing the risks, Dr. Kyouma wants you, Labman No.003 to build a Time Tunnel with shortest length.
 

Input
The first line contains an integer T, indicating the number of test cases. 

Each case contains only one line with 12 float numbers (x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4), correspondingly indicating two points in World Line Alpha and World Line Beta. Note that a World Line is a three-dimensional line with infinite length. 

Data satisfy T <= 10000, |x, y, z| <= 10,000.
 

Output
For each test case, please print two lines.

The first line contains one float number, indicating the length of best Time Tunnel. 

The second line contains 6 float numbers (xa, ya, za), (xb, yb, zb), seperated by blank, correspondingly indicating the endpoints of the best Time Tunnel in World Line Alpha and World Line Beta. 

All the output float number should be round to 6 digits after decimal point. Test cases guarantee the uniqueness of the best Time Tunnel.
 

Sample Input
  
  
1 1 0 1 0 1 1 0 0 0 1 1 1
 

Sample Output
  
  
0.408248 0.500000 0.500000 1.000000 0.666667 0.666667 0.666667
 

Source
 

编程思想: 求解 空间两条异面直线的距离 问题。

利用空间向量投影的原理求解:(转自:http://blog.sina.com.cn/s/blog_648868460100nen1.html)

假设用全站仪采集空间四个点的坐标为:

    A(x1,y1,z1),B(x2,y2,z2),C(x3,y3,z3),D(x4,y4,z4)

    过点A和点B的直线记为L1,过点C和点D的直线记为L2,L1和L2为空间异面直线,利用空间向量及投影原理求解L1和L2的距离d。

    首先求出直线L1和L2的方向向量:

    空间异面直线距离的向量解算方法

    求L1和L2的公垂线方向向量:

    空间异面直线距离的向量解算方法
   在直线L1和L2上各任取一点,这里就取点A和点C,则线段AC在公垂线方向向量上的投影就是这两个异面直线的距离。

   线段AC的方向向量为:

   空间异面直线距离的向量解算方法

   则异面直线L1和L2的距离d为:

   空间异面直线距离的向量解算方法


而题目不止要求距离,还有求交点,怎么求呢?通过构造平面,然后求平面与另外一条直线的交点即可得,解题思路详见如下代码。


AC code:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<cmath>
#define eps 1e-10
#define inf 0x1f1f1f1f
using namespace std;
 
int dcmp( double a ){ if( abs(a) < eps ) return 0; if(a > 0) return 1;return -1;}
struct point{
   double x,y,z;
   point(){}
   point( double x,double y,double z ):x(x),y(y),z(z){}
};
typedef point Vector ;
point operator + ( point a,point b ){
    return point( a.x+b.x , a.y+b.y , a.z+b.z );
}
// 确定一个平面;一般式:ax+by+cz+d=0;
struct plane{
    double a,b,c,d;
    plane( double a = 0,double b = 0,double c = 0,double d = 0 ):a(a),b(b),c(c),d(d){}
};
point operator - ( point a,point b ){
    return point( a.x-b.x , a.y-b.y, a.z-b.z );
}
point operator * ( point a,double p ){
    return point( a.x*p , a.y*p , a.z*p );
}
point operator / ( point a,double p ){
    return point( a.x/p , a.y/p , a.z/p );
}
bool operator == ( point a,point b ){
    if( dcmp(a.x-b.x)  == 0&& dcmp(a.y-b.y) == 0 && dcmp(a.z-b.z) == 0 )return 1;
    return 0;
}
double Dot( point a,point b ){ return a.x*b.x + a.y*b.y + a.z*b.z; }
double Length( point a ){ return sqrt(Dot(a,a));}
double Angle(  point a,point b ){ return acos(Dot(a,b))/Length(a)/Length(b); }
//  点到  平面p0 - n 的距离;n 必须为单位向量 n 是平面法向量
double p_po_n( const point &p,const point &po,const point n ){
    return abs(Dot( p-po,n ));
}
//  点在 平面p0 - n 的投影 ; n 必须为单位向量 n 是平面法向量
point p_po_n_jec( const point &p,const point &p0,const point &n ){
    return p-n*Dot( p-p0,n );
}
//  直线p1 p2 在平面 p0 - n 的交点,假设交点存在;唯一
point p_p_p( point p1,point p2,point p0,point n ){
    point  v = p2 - p1;
    double t = ( Dot(n,p0-p1)/Dot(n,p2-p1) );
    return p1 + v*t;
}
point cross( point a,point b ){
    return point( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z,a.x*b.y - a.y*b.x );
}
double area( point a,point b,point c ){ return Length(cross(b-a,c-a)); }
double dis_to_line( point p, point a,point b ){
    point v1 = b-a, v2 = p-a;
    return Length( cross(v1,v2)/Length(v1) );
}
// p 到 ab 线段的距离
double dis_to_segm( point p,point a,point b ){
    if( a == b )return Length(p-a);
    point v1 = b-a, v2 = p-a, v3 = p-b;
        if( dcmp( Dot(v1,v2) ) < 0 ) return Length(v2);
   else if( dcmp( Dot(v1,v3) ) > 0 ) return Length(v3);
   else return Length(cross(v1,v2))/Length(v1);
}
// 四面体的体积
double dis_l_to_l( point a,point b,point lt,point rt )
{
    while( abs(rt.x - lt.x) > eps || abs(rt.y - lt.y) > eps || abs( rt.z - lt.z) > eps )
    {
        point temp; temp = lt + ( rt - lt )/3.0;
        point now;   now = lt + ( rt - lt )/3.0*2.0;
        if( dis_to_segm(temp,a,b) < dis_to_segm(now,a,b) )
             rt = now;
        else lt = temp;
    }
    return dis_to_segm( rt,a,b );
}
// 获取平面 a*x + b*y + c*z + d; 由两个向量和一个平面上一个点确定一个平面
plane get_plane( Vector a,Vector b,point c )
{
    Vector p = cross( a,b ); // 由平面两个向量a,b,  可以确定平面法向量;
    double d = ( p.x*c.x + p.y*c.y + p.z*c.z)*-1;
    return plane( p.x,p.y,p.z,d );
}
// 获取 直线cd与平面p的交点;
point get_point( plane p,point c,point d )
{
    Vector v = c - d;
    double t =  p.a*c.x+p.b*c.y + p.c*c.z + p.d ;
    double s =  p.a*(d.x - c.x) + p.b*(d.y-c.y) + p.c*(d.z - c.z);
    double k = t/s;
    return c + v*k;
}
 
point A[5];
int main( )
{
   int T; scanf("%d",&T);
   while( T-- )
   {
       for( int i = 1; i <= 4; i++ )
         scanf("%lf %lf %lf",&A[i].x,&A[i].y,&A[i].z);
       Vector v1 = A[2] - A[1];
       Vector v2 = A[4] - A[3];
       Vector v3 = cross( v1,v2 ); // 获取公垂线;
        plane a1 = get_plane( v1,v3,A[1] ); // 两个向量和一个点确定一个平面;
        plane a2 = get_plane( v2,v3,A[3] );
       point p1 = get_point( a1,A[4],A[3] ); // 获取交点;
       point p2 = get_point( a2,A[1],A[2] );
       printf("%.6lf\n",Length(p1-p2));
       printf("%.6lf %.6lf %.6lf %.6lf %.6lf %.6lf\n",p2.x,p2.y,p2.z,p1.x,p1.y,p1.z);
   }
   return 0;
}







附上向量叉积公式:

a(x1,y1,z1),b(x2,y2,z2);

            |  i    j   k   |

a*b=    |x1  y1  z1|  ={(y1*z2-z1*y2)i, (x2*z1-z2*x1)j, (x1*y2-y1*x2)k}

           |x2  y2  z2|


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、资源详解 实验报告:通过实际操作与数据记录,让您深入理解计算机内部的工作原理。每份实验报告都详细记录了实验步骤、结果及分析,助您巩固知识点。 学习笔记:由资深学者精心整理的学习笔记,重点突出,为您梳理课程脉络,把握核心内容。 复习资料与试卷:涵盖了各类复习资料和历年试卷,助您备战考试,查漏补缺,提高应试能力。 作业答案:提供完整的作业答案及解析,让您在完成课后作业时更有信心,确保理解每一个知识点。 一二、计算机组成原理:从基础到进阶,全突破的必备资源 在信息爆炸的时代,计算机组成原理作为计算机科学的核心课程,显得尤为重要。为了帮助广大学子更好地掌握这一关键领域,我们特地整理了这一系列与计算机组成原理相关的资源,助力您的学术旅程。 三、适用场景广泛 无论是期末考试冲刺、计算机组成原理实验报告作业、还是复习题、试题、考研资料等需求,这些资源都能满足您的要求。全覆盖理论要点与实践操作,让您在学习和备考过程中游刃有余。 四、使用建议 系统学习:建议按照章节顺序进行系统学习,结合实验报告进行实践操作,以加深理解。 备考策略:利用复习资料与试卷资源,制定有效的备考计划,提高考试通过率。 持续反馈与改进:根据作业答案进行自我评估,找出薄弱环节,及时调整学习策略。 五、版权与安全提示 尊重知识产权:在使用这些资源时,请尊重原作者的权益,遵守版权法规。 安全使用:确保在使用过程中不侵犯他人权益,避免任何形式的学术不端行为。 感谢您选择我们的计算机组成原理资源库!让我们一起深入探索计算机的奥秘,用知识武装自己,开启精彩的学术之旅!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值