计算几何算法二:向量/线段

向量的基本运算(加、减),点乘、单位叉乘模、点与线段的关系、线段上离某点最近的点、二线段是否相交、点与线段的面积、点到线段所在直线上的垂足。

// RtVector.h: interface for the CRtVector class.
//
//

#if !defined(AFX_RTVECTOR_H__150FF33B_0C72_4C7D_97FE_2D9ADA5AA897__INCLUDED_)
#define AFX_RTVECTOR_H__150FF33B_0C72_4C7D_97FE_2D9ADA5AA897__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "RtPoint.h"

template<class T,int dim = 2 >
class CRtVector
{
public:
 CRtVector()
 {
 }
 CRtVector( CRtPoint<T, dim>& start,CRtPoint<T, dim>& stop ): mvo_start( start ),mvo_stop( stop )
 {
 }
 virtual ~CRtVector()
 {
 }

 //copy constructor
 CRtVector(const CRtVector& in)
 {
  mvo_start = in.mvo_start;
  mvo_stop = in.mvo_stop;
 }

//operators overload:
 //Accumulative addition of two vectors
 CRtVector& operator += (const CRtVector& in )
 {
  mvo_start += in.mvo_start;
  mvo_stop += in.mvo_stop;

  return *this;
 }
 // Accumulative subtraction of two vectors
 CRtVector& operator -= (const CRtVector& in )
 {
  mvo_start -= in.mvo_start;
  mvo_stop -= in.mvo_stop;

  return *this;
 }

 //Vector Equality, epsilon used due to numerical imprecision
 bool operator == (const CRtVector& in )
 {
  if ((mvo_start == in.mvo_start) && (mvo_stop == in.mvo_stop))
  {
   return true;
  }
  
  return false;
 }
 //evaluate to point
 CRtVector& operator = (const CRtVector& in)
 {
  mvo_start = in.mvo_start;
  mvo_stop = in.mvo_stop;

  return *this;
 }
 //get a  element
 CRtPoint<T, dim> operator [] (const int index)
 {
  return index == 0 ? mvo_start:mvo_stop;
 }
 
 //Reassign a vectors without making a temporary structure
 void SetData( CRtPoint<T, dim>& start,CRtPoint<T, dim>& stop )
 {
  mvo_start = start;
  mvo_stop = stop;
 }
 
 //Dot Product
 double DotProduct( CRtVector& in );
 
 //Cross Product Mode
 double CrossProductMode( CRtPoint<T, dim>& in);

 //the relation a point and line segment
 double RelationPoint( CRtPoint<T, dim>& in);

 //Point C to the straight line segment AB where the pedal
 const CRtPoint<T, dim> PedalLine( CRtPoint<T, dim>& in);

 //Seek the shortest distance from point to line segment and return segment from that point on the nearest point of
 //Segment to the point nearest point, not necessarily Pedal
 double NearestPoint( CRtPoint<T, dim>& in,CRtPoint<T, dim>& out);

 //Whether the two line segments intersect
 bool IsIntersect( CRtVector& in );

 //the area of a point and line segments
 double AreaTriangle( CRtPoint<T>& in);

private:
 CRtPoint<T, dim> mvo_start;//vector start point
 CRtPoint<T, dim> mvo_stop;//vector stop point
};

//Adds two vectors together
template<class T, int dim>
inline const CRtVector<T, dim> operator + (const CRtVector<T, dim>& src0, const CRtVector<T, dim>& src1 )
{
 return CRtVector<T, dim>( src0.mvo_start + src1.mvo_start , src0.mvo_stop + src1.mvo_stop );
}

//Subtracts two vectors
template<class T, int dim>
inline const CRtVector<T, dim> operator - (const CRtVector<T, dim>& src0, const CRtVector<T, dim>& src1 )
{
 return CRtVector<T, dim>( src0.mvo_start - src1.mvo_start , src0.mvo_stop - src1.mvo_stop );
}

/***************************************************************************** 
Dot Product:
If two vectors are non-zero vector 
 return value < 0:The angle between two vectors is acute angle
 return value = 0:The angle between two vectors for the rectangular
 return value > 0:Angle between two vectors as the obtuse angle
*******************************************************************************/
template<class T,int dim>
double CRtVector<T, dim>::DotProduct( CRtVector& in )
{
 CRtPoint<T,dim> point;
 double val = 0;
 point = (mvo_stop - mvo_start) * (in.mvo_stop - in.mvo_start);
 T *data = point.GetData();

 for (int i = 0; i < dim; i++)
  val += *(data + i);

 return val;
}

/****************************************************************************** 
Cross Product Mode:
Unit vector of the mode is 1, the available cross product of the modulus:
Cross product of a very important property can be judged by its symbol between  the two vectors
of cis-anti-clockwise relationship:
 If the P × OQ < 0, then P in the OQ in a clockwise direction.
 If the P × OQ > 0, then P in the OQ of the counter-clockwise.
 If the P × OQ = 0, then P and OQ collinear, but may in the same direction may reverse.
*******************************************************************************/ 
template<class T,int dim>
double CRtVector<T, dim>::CrossProductMode( CRtPoint<T, dim>& in)
{
 CRtPoint<T, dim> p0,p1;
 p0 = mvo_stop - mvo_start;
 p1 = in - mvo_start;

 if (2 == dim) return p0[0] * p1[1] - p0[1] * p1[0];
 if (3 == dim) return p0[1] * p1[2] + p0[2] * p1[0] + p0[0] * p1[1]
                - p0[2] * p1[1] + p0[0] * p1[2] + p0[1] * p1[0];
}

/******************************************************************************   
   AC dot AB    (Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay) 
  r = --------- =  -------------------------------
   ||AB||^2                  L^2 
 
  r has the following meaning: 
   r=0      P = A 
   r=1      P = B 
   r<0    P is on the backward extension of AB 
   r>1      P is on the forward extension of AB 
   0<r<1  P is interior to AB 
*******************************************************************************/ 
template<class T,int dim>
double CRtVector<T, dim>::RelationPoint( CRtPoint<T, dim>& in) 
{  
 CRtVector<T, dim> vector;
 vector.SetData(mvo_start, in);
 return DotProduct(vector) / pow( mvo_start.DistEuclidean(mvo_stop) , 2 ); 
}

//Point C to the straight line segment AB where the pedal
template<class T,int dim>
const CRtPoint<T, dim> CRtVector<T, dim>::PedalLine( CRtPoint<T, dim>& in) 

 double r = RelationPoint( in ); 
 CRtPoint<T, dim> point = mvo_stop - mvo_start;
 point *= r;
 point += mvo_start;
 return point; 

//Seek the shortest distance from point to line segment and return segment from that point on the nearest point of
//Segment to the point nearest point, not necessarily Pedal
template<class T,int dim>
double CRtVector<T, dim>::NearestPoint( CRtPoint<T, dim>& in,CRtPoint<T, dim>& out) 

 double val = RelationPoint( in );
 
 if( val < 0 )  out = mvo_start; 
 if( val > 1 )  out = mvo_stop;  
 if( val >= 0 && val <= 1) out = PedalLine( in);
 
 return in.DistEuclidean(out);
}
/******************************************************************************
1) Fast exclusion test
 Is located in the diagonal line segment P1P2 rectangle of R,
 Is located in the diagonal line segment Q1Q2 rectangle of T,
 If the R and T do not intersect, and apparently two line segments do not intersect.

2) Cross-li test
 If the two line segments intersect, then the two line segments bound to each other cross-li.
 If the P1P2 cross-li Q1Q2, then the vector (P1 - Q1)
 And (P2 - Q1) in the vector (Q2 - Q1) on both sides,
 Namely, (P1 - Q1) × (Q2 - Q1) * (P2 - Q1) × (Q2 - Q1) <0.
 On the type can be rewritten as (P1 - Q1) × (Q2 - Q1) * (Q2 - Q1) × (P2 - Q1)> 0.
 When the (P1 - Q1) × (Q2 - Q1) = 0, the statement (P1 - Q1) and (Q2 - Q1) of lines,
 However, as it has been a quick rejection test, so a certain line segment Q1Q2 on P1;
 By the same token, (Q2 - Q1) × (P2 - Q1) = 0 shows a certain line segment Q1Q2 on the P2.
 Therefore, to determine P1P2 is based on cross-li Q1Q2:
 (P1 - Q1) × (Q2 - Q1) * (Q2 - Q1) × (P2 - Q1) <= 0.
 By the same token to determine Q1Q2 is based on cross-li P1P2:
 (Q1 - P1) × (P2 - P1) * (P2 - P1) × (Q2 - P1) <= 0.
*******************************************************************************/
template<class T,int dim>
bool CRtVector<T, dim>::IsIntersect( CRtVector& in )
{
 if (dim != 2) return false;

 if ( max(mvo_start[0], mvo_stop[0]) >= min(in.mvo_start[0], in.mvo_stop[0]) &&
   min(mvo_start[0], mvo_stop[0]) <= max(in.mvo_start[0], in.mvo_stop[0]) &&
   max(mvo_start[1], mvo_stop[1]) >= min(in.mvo_start[1], in.mvo_stop[1]) &&
   min(mvo_start[0], mvo_stop[1]) <= max(in.mvo_start[1], in.mvo_stop[1]) )//exclude
 {
  //cross-li
  double val = 0;
  CRtVector<T, dim> vector(in.mvo_stop, mvo_start);  
  val = vector.CrossProductMode(in.mvo_start);
  vector.SetData(in.mvo_stop, mvo_stop);
  val *= vector.CrossProductMode(in.mvo_start);
  
  if ( val <= 0 )
  {
   vector.SetData(in.mvo_start, mvo_stop);
   val = vector.CrossProductMode(mvo_start);
   vector.SetData(in.mvo_stop, mvo_stop);
   val *= vector.CrossProductMode(mvo_start);
   
   return val <= 0 ? true : false;
  }
 }

 return false;
}

//the area of a point and line segments
template<class T,int dim>
double CRtVector<T, dim>::AreaTriangle( CRtPoint<T>& in)
{
    return fabs( ( mvo_start[0] * mvo_stop[1] + mvo_stop[0] * in[1] + in[0] * mvo_start[1] )
         - ( mvo_start[0] * in[1] + mvo_stop[0] * mvo_start[1] + in[0] * mvo_stop[1] ) / 2.0 );  
}

#endif // !defined(AFX_RTVECTOR_H__150FF33B_0C72_4C7D_97FE_2D9ADA5AA897__INCLUDED_)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值