使用C或C ++在3D空间实现中从3点构建圆 [英] Build Circle from 3 Points in 3D space implementation in C or C++

查看:295
本文介绍了使用C或C ++在3D空间实现中从3点构建圆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有3(三)个xyz点在3D空间中定义一个圆,这个圆需要转换为折线(用于进一步渲染)。我正在寻找一个准备好的C或C ++函数或可以做这项工作的免费库。



不明白为什么已关闭。我甚至不能回答我自己的问题。耻辱你们。但你不会停止知识传播!

解决方案

有一篇很好的文章和代码示例介绍了如何在2D,XY平面中通过3点构建圆。 / p>

http://paulbourke.net/geometry/circlesphere/



http:// paulbourke.net/geometry/circlesphere/Circle.cpp



要建立3D圆形,我们必须:




  • 将我们的3个点旋转到XY平面

  • 计算圆心




旋转时使用最好使用四元数。



要查找正确的四元数,我查看了Ogre3d源代码:
void Quaternion :: FromAngleAxis(const Radian& rfAngle,const Vector3& rkAxis)



还有一个有用的函数:
Quaternion getRotationTo(const Vector3& dest,const Vector3& fallbackAxis = Vector3 :: ZERO)const
但我没有使用它。



对于数学和向量,我使用了我们自己的类。这是完成作业的函数的完整源代码:

  bool IsPerpendicular(Point3d * pt1,Point3d * pt2,Point3d * pt3); 
double CalcCircleCenter(Point3d * pt1,Point3d * pt2,Point3d * pt3,Point3d * center);

void FindCircleCenter(const Point3d * V1,const Point3d * V2,const Point3d * V3,Point3d * center)
{
Point3d * pt1 = new Point3d(* V1);
Point3d * pt2 = new Point3d(* V2);
Point3d * pt3 = new Point3d(* V3);


if(!IsPerpendicular(pt1,pt2,pt3))CalcCircleCenter(pt1,pt2,pt3,center);
else if(!IsPerpendicular(pt1,pt3,pt2))CalcCircleCenter(pt1,pt3,pt2,center);
else if(!IsPerpendicular(pt2,pt1,pt3))CalcCircleCenter(pt2,pt1,pt3,center);
else if(!IsPerpendicular(pt2,pt3,pt1))CalcCircleCenter(pt2,pt3,pt1,center);
else if(!IsPerpendicular(pt3,pt2,pt1))CalcCircleCenter(pt3,pt2,pt1,center);
else if(!IsPerpendicular(pt3,pt1,pt2))CalcCircleCenter(pt3,pt1,pt2,center);
else {
delete pt1;
delete pt2;
delete pt3;
return;
}
delete pt1;
delete pt2;
delete pt3;

}

bool IsPer垂直(Point3d * pt1,Point3d * pt2,Point3d * pt3)
//检查给定点垂直于x或y轴
{
double yDelta_a = pt2-> y - pt1-> y;
double xDelta_a = pt2-> x - pt1-> x;
double yDelta_b = pt3-> y - pt2-> y;
double xDelta_b = pt3-> x - pt2-> x;

//检查两个点的线是否是垂直的
if(fabs(xDelta_a)<= 0.000000001&& fabs(yDelta_b)<= 0.000000001){
return false;
}

if(fabs(yDelta_a)< = 0.0000001){
return true;
}
else if(fabs(yDelta_b)< = 0.0000001){
return true;
}
else if(fabs(xDelta_a)< = 0.000000001){
return true;
}
else if(fabs(xDelta_b)< = 0.000000001){
return true;
}
else
return false;
}

double CalcCircleCenter(Point3d * pt1,Point3d * pt2,Point3d * pt3,Point3d * center)
{
double yDelta_a = pt2-> y - pt1-> y;
double xDelta_a = pt2-> x - pt1-> x;
double yDelta_b = pt3-> y - pt2-> y;
double xDelta_b = pt3-> x - pt2-> x;

if(fabs(xDelta_a)< = 0.000000001&& fabs(yDelta_b)< = 0.000000001){
center-> x = 0.5 *(pt2-> x + pt3-> x);
center-> y = 0.5 *(pt1-> y + pt2-> y);
center-> z = pt1-> z;

return 1;
}

// IsPerpendicular()确保xDelta不为零
double aSlope = yDelta_a / xDelta_a; //
double bSlope = yDelta_b / xDelta_b;
if(fabs(aSlope-bSlope)< = 0.000000001){//检查给定的点是否是共线的。
return -1;
}

// calc center
center-> x =(aSlope * bSlope *(pt1-> y - pt3-> y)+ bSlope *(pt1 - > x + pt2-> x)
-aSlope *(pt2-> x + pt3-> x))/(2 *(bSlope-aSlope)
center-> y = -1 *(center-> x-(pt1-> x + pt2-> x)/ 2)/ aSlope +(pt1-> y + pt2-& y)/ 2;

return 1;
}

//!在3D空间中通过3点和一个可选的中心建立一个圆圈
void buildCircleBy3Pt(const float * pt1,
const float * pt2,
const float * pt3,
const float * c,// center,可以为NULL
std :: vector< float> * circle)
{
/ *获取由3点形成的三角形的法线向量
从0,0,1轴的法线计算旋转四元数
使用四元数旋转3个点。点将在XY平面中
在XY平面上通过3点建立一个圆
使用四元数将一个圆旋转回原始平面
* /
Point3d p1(pt1 [0] pt1 [1],pt1 [2]);
Point3d p2(pt2 [0],pt2 [1],pt2 [2]);
Point3d p3(pt3 [0],pt3 [1],pt3 [2]);
Point3d center;
if(c)
{
center.set(c [0],c [1],c [2]);
}

const Vector3d p2top1 = p1 - p2;
const Vector3d p2top3 = p3 - p2;

const Vector3d circle_normal = p2top1.crossProduct(p2top3).normalize();
const Vector3d xy_normal(0,0,1);


四元数rot_quat;
//构造旋转四元数
{
//我们将围绕它旋转我们的圆到XY平面中的旋转轴
Vector3d rot_axis = xy_normal.crossProduct(circle_normal).normalize();
const double rot_angle = xy_normal.angleTo(circle_normal); // radians

const double w = cos(rot_angle * 0.5);
rot_axis * = sin(rot_angle * 0.5);

rot_quat.set(w,rot_axis.X,rot_axis.y,rot_axis.z);
}

四元数rot_back_quat;
//构造反向旋转四元数,与上一样相同。但是-angle
{
const double rot_angle = - (xy_normal.angleTo(circle_normal)); // radians
const double w_back = cos(rot_angle * 0.5);
Vector3d rot_back_axis = xy_normal.crossProduct(circle_normal).normalize();
rot_back_axis * = sin(rot_angle * 0.5);
rot_back_quat.set(w_back,rot_back_axis.x,rot_back_axis.y,rot_back_axis.z);
}

rot_quat.rotate(p1);
rot_quat.rotate(p2);
rot_quat.rotate(p3);
rot_quat.rotate(center);

if(!c)
{
//计算2D中心
FindCircleCenter(& p1,& p2,& p3,& center);
}

//计算半径
const double radius = center.distanceTo(p1);

const float DEG2RAD = 3.14159f / 180.0f;
//构建循环
for(int i = 0; i <360; ++ i)
{
float degInRad = i * DEG2RAD;
Point3d pt(cos(degInRad)* radius + center.x,sin(degInRad)* radius + center.y,0);

//将点旋转回原来的平面
rot_back_quat.rotate(pt);

circle-> push_back(pt.x);
circle-> push_back(pt.y);
circle-> push_back(pt.z);
}
}


We have 3(three) xyz points that define a circle in 3D space, this circle needs to be converted into a polyline(for further rendering). I'm looking for a ready C or C++ function or free library that can do the job.

Don't understand why this was closed. And I can't even answer my own question there. Shame on you guys. But you will not stop the knowledge spreading!

解决方案

There is a nice article and a code sample on how to build a circle by 3 points in 2D, XY plane.

http://paulbourke.net/geometry/circlesphere/

http://paulbourke.net/geometry/circlesphere/Circle.cpp

To build a 3D circle we'll have to:

  • rotate our 3 points into XY plane
  • Calculate circle center
  • build a circle in XY plane using the code in the article
  • rotate it back into it's original plane

For rotations it is best to use quaternions.

To find a correct quaternion I looked at Ogre3d source code: void Quaternion::FromAngleAxis (const Radian& rfAngle, const Vector3& rkAxis)

There is one more useful function there: Quaternion getRotationTo(const Vector3& dest, const Vector3& fallbackAxis = Vector3::ZERO) const But I didn't use it.

For quaterions and vectors I used our own classes. Here is the full source code of the function that does the job:

bool IsPerpendicular(Point3d *pt1, Point3d *pt2, Point3d *pt3);
double CalcCircleCenter(Point3d *pt1, Point3d *pt2, Point3d *pt3, Point3d *center);

void FindCircleCenter(const Point3d *V1, const Point3d *V2, const Point3d *V3, Point3d *center)
{
    Point3d *pt1=new Point3d(*V1);
    Point3d *pt2=new Point3d(*V2);
    Point3d *pt3=new Point3d(*V3);


    if (!IsPerpendicular(pt1, pt2, pt3) )       CalcCircleCenter(pt1, pt2, pt3, center);
    else if (!IsPerpendicular(pt1, pt3, pt2) )  CalcCircleCenter(pt1, pt3, pt2, center);
    else if (!IsPerpendicular(pt2, pt1, pt3) )  CalcCircleCenter(pt2, pt1, pt3, center);
    else if (!IsPerpendicular(pt2, pt3, pt1) )  CalcCircleCenter(pt2, pt3, pt1, center);
    else if (!IsPerpendicular(pt3, pt2, pt1) )  CalcCircleCenter(pt3, pt2, pt1, center);
    else if (!IsPerpendicular(pt3, pt1, pt2) )  CalcCircleCenter(pt3, pt1, pt2, center);
    else {
        delete pt1;
        delete pt2;
        delete pt3;
        return;
    }
    delete pt1;
    delete pt2;
    delete pt3;

}

bool IsPerpendicular(Point3d *pt1, Point3d *pt2, Point3d *pt3)
// Check the given point are perpendicular to x or y axis
{
    double yDelta_a= pt2->y - pt1->y;
    double xDelta_a= pt2->x - pt1->x;
    double yDelta_b= pt3->y - pt2->y;
    double xDelta_b= pt3->x - pt2->x;

    // checking whether the line of the two pts are vertical
    if (fabs(xDelta_a) <= 0.000000001 && fabs(yDelta_b) <= 0.000000001){
        return false;
    }

    if (fabs(yDelta_a) <= 0.0000001){
        return true;
    }
    else if (fabs(yDelta_b) <= 0.0000001){
        return true;
    }
    else if (fabs(xDelta_a)<= 0.000000001){
        return true;
    }
    else if (fabs(xDelta_b)<= 0.000000001){
        return true;
    }
    else
        return false ;
}

double CalcCircleCenter(Point3d *pt1, Point3d *pt2, Point3d *pt3, Point3d *center)
{
    double yDelta_a = pt2->y - pt1->y;
    double xDelta_a = pt2->x - pt1->x;
    double yDelta_b = pt3->y - pt2->y;
    double xDelta_b = pt3->x - pt2->x;

    if (fabs(xDelta_a) <= 0.000000001 && fabs(yDelta_b) <= 0.000000001){
        center->x= 0.5*(pt2->x + pt3->x);
        center->y= 0.5*(pt1->y + pt2->y);
        center->z= pt1->z;

        return 1;
    }

    // IsPerpendicular() assure that xDelta(s) are not zero
    double aSlope=yDelta_a/xDelta_a; //
    double bSlope=yDelta_b/xDelta_b;
    if (fabs(aSlope-bSlope) <= 0.000000001){    // checking whether the given points are colinear.
        return -1;
    }

    // calc center
    center->x= (aSlope*bSlope*(pt1->y - pt3->y) + bSlope*(pt1->x + pt2 ->x)
                         - aSlope*(pt2->x+pt3->x) )/(2* (bSlope-aSlope) );
    center->y = -1*(center->x - (pt1->x+pt2->x)/2)/aSlope +  (pt1->y+pt2->y)/2;

    return 1;
}

//! Builds a circle in 3D space by 3 points on it and an optional center
void buildCircleBy3Pt(const float *pt1,
                      const float *pt2,
                      const float *pt3,
                      const float *c,       // center, can be NULL
                      std::vector<float> *circle)
{
    /*  Get the normal vector to the triangle formed by 3 points
        Calc a rotation quaternion from that normal to the 0,0,1 axis
        Rotate 3 points using quaternion. Points will be in XY plane 
        Build a circle by 3 points on XY plane 
        Rotate a circle back into original plane using quaternion
     */
    Point3d p1(pt1[0], pt1[1], pt1[2]);
    Point3d p2(pt2[0], pt2[1], pt2[2]);
    Point3d p3(pt3[0], pt3[1], pt3[2]);
    Point3d center;
    if (c)
    {
        center.set(c[0], c[1], c[2]);
    }

    const Vector3d p2top1 = p1 - p2;
    const Vector3d p2top3 = p3 - p2;

    const Vector3d circle_normal = p2top1.crossProduct(p2top3).normalize();
    const Vector3d xy_normal(0, 0, 1);


    Quaternion rot_quat;
    // building rotation quaternion
    {
        // Rotation axis around which we will rotate our circle into XY plane
        Vector3d rot_axis = xy_normal.crossProduct(circle_normal).normalize();
        const double rot_angle = xy_normal.angleTo(circle_normal); // radians

        const double w = cos(rot_angle * 0.5);
        rot_axis *= sin(rot_angle * 0.5);

        rot_quat.set(w, rot_axis.x, rot_axis.y, rot_axis.z);
    }

    Quaternion rot_back_quat;
    // building backward rotation quaternion, same as prev. but -angle
    {
        const double rot_angle = -(xy_normal.angleTo(circle_normal)); // radians
        const double w_back = cos(rot_angle * 0.5);
        Vector3d rot_back_axis = xy_normal.crossProduct(circle_normal).normalize();
        rot_back_axis *= sin(rot_angle * 0.5);
        rot_back_quat.set(w_back, rot_back_axis.x, rot_back_axis.y, rot_back_axis.z);
    }

    rot_quat.rotate(p1);
    rot_quat.rotate(p2);
    rot_quat.rotate(p3);
    rot_quat.rotate(center);

    if (!c)
    {
        // calculate 2D center
        FindCircleCenter(&p1, &p2, &p3, &center);
    }

    // calc radius
    const double radius = center.distanceTo(p1);

    const float DEG2RAD = 3.14159f / 180.0f;
    // build circle
    for (int i = 0; i < 360; ++i)
    {
        float degInRad = i * DEG2RAD;
        Point3d pt(cos(degInRad) * radius + center.x, sin(degInRad) * radius + center.y, 0);

        // rotate the point back into original plane 
        rot_back_quat.rotate(pt);

        circle->push_back(pt.x);
        circle->push_back(pt.y);
        circle->push_back(pt.z);
    }
}

这篇关于使用C或C ++在3D空间实现中从3点构建圆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆