面用osg::Matrix 来表示。
osg::Vec3 ptOri = osg::(0,0,0) * mat;(面的原点)
osg::Vec3 vecX = mat.getRotate() * osg::X_AXIS ;(X轴)
osg::Vec3 vecY = mat.getRotate() * osg::Y_AXIS ;(Y轴)
要求两个面的交线,首先要判断两个面是否相交,方法是判断两个面的Z轴夹角,如果夹角差不多为0或者Pi那么认为面不想交,没有相交。
<pre name="code" class="cpp">double AngleTo(const osg::Vec3d &vec1, const osg::Vec3d&vec2)
{
assert(vec1.length() > 1.E-7 && vec2.length() > 1.E-7);
osg::Vec3d v1 = vec1, v2 = vec2;
v1.normalize();
v2.normalize();
double dTemp = (v1 * v2) / (v1.length() * v2.length());
if (dTemp > 1.0)
{
dTemp = 1.0;
}
if (dTemp < -1.0)
{
dTemp = -1;
}
return acos(dTemp);
}
int Intersect3dLineSegmentWithPlane( const osg::Vec3d &lineStartPoint, const osg::Vec3d &lineEndPoint,
const osg::Vec3d &planeNormal, const osg::Vec3d &planePoint, osg::Vec3d &intPoint )
{
osg::Vec3d other = lineEndPoint - lineStartPoint;
osg::Vec3d vector2 = lineStartPoint - planePoint;
double num = planeNormal * other;
double num2 = -planeNormal * vector2;
if (fabs(num) < 1.0E-6))
{
if (num2 == 0.0)
{
return 2;
}
else
{
return 0;
}
}
double num3 = num2 / num;
if ((num3 < 0.0) || (num3 > 1.0))
{
return 0;
}
intPoint = lineStartPoint + other * num3;
return 1;
}
// 描述: 求两个面的交线
// matBase:一个面的位置矩阵
// matThis: 另外一个面的位置矩阵
// pt1: 交线点1 (世界坐标系)
// pt2: 交线点2 (世界坐标系)
// dTolAngle: 面夹角容差(如果两个面夹角小于等于这个值,那么认为面平行)
// 返回值:是否相交
bool IntersectWith( const osg::Matrix &matBase, const osg::Matrix &matThis,
osg::Vec3d &pt1, osg::Vec3d &pt2, double dTolAngle /*= osg::PI / 36.0*/ )
{
bool bOk = false;
osg::Vec3d vecZThis = matThis.getRotate() * osg::Z_AXIS;
osg::Vec3d vecZBase = matBase.getRotate() * osg::Z_AXIS;
double dAngle = AngleTo(vecZThis, vecZBase);
if ( dAngle - osg::PI_2 > 1.0E-7)
{
dAngle = osg::PI - dAngle;
}
// 判断方向
if (dAngle - dTolAngle > 1.0E-7)
{
osg::Vec3d vecLine = vecZBase ^ vecZThis; // 两个面相交线向量
osg::Vec3d vecLineInThis = matThis.getRotate().inverse() * vecLine; // 到自身坐标系里
// 相交线垂直的向量
osg::Quat quat;
quat.makeRotate(osg::PI_2, osg::Z_AXIS);
vecLineInThis = quat * vecLineInThis;
double dLength = 10000.0;
osg::Vec3d pt1InThis = vecLineInThis * dLength;
osg::Vec3d pt2InThis = -pt1InThis;
// 变换到世界坐标系
pt1InThis = pt1InThis * matThis;
pt2InThis = pt2InThis * matThis;
// 计算这条垂线和基本面的交点
osg::Vec3d ptRet;
osg::Vec3d ptOri = osg::Vec3d(0,0,0) * matBase;
int iRet = Intersect3dLineSegmentWithPlane(pt1InThis, pt2InThis, vecZBase, ptOri, ptRet);
assert(iRet == 1);
// 然后根据交线向量求出两个点来
pt1 = ptRet + vecLine * dLength;
pt2 = ptRet - vecLine * dLength;
bOk = true;
}
return bOk;
}