C++ 在C或C+中从3D空间中的3个点构建圆+;
我们有3(三)个xyz点在3D空间中定义一个圆,这个圆需要转换成多段线(用于进一步渲染)。我正在寻找一个可以做的工作的准备好的C或C++函数或免费库。C++ 在C或C+中从3D空间中的3个点构建圆+;,c++,geometry,C++,Geometry,我们有3(三)个xyz点在3D空间中定义一个圆,这个圆需要转换成多段线(用于进一步渲染)。我正在寻找一个可以做的工作的准备好的C或C++函数或免费库。 我不明白为什么要关门。我甚至不能回答我自己的问题。你们真丢脸。但是你不会阻止知识的传播 有一篇很好的文章和一个代码示例,介绍如何在2D、XY平面上用3个点构建一个圆 要构建三维圆,我们必须: 将3个点旋转到XY平面 计算圆心 使用本文中的代码在XY平面上构建一个圆 将其旋转回原始平面 对于旋转,最好使用四元数 为了找到正确的四元数,我查看
我不明白为什么要关门。我甚至不能回答我自己的问题。你们真丢脸。但是你不会阻止知识的传播 有一篇很好的文章和一个代码示例,介绍如何在2D、XY平面上用3个点构建一个圆 要构建三维圆,我们必须:
- 将3个点旋转到XY平面
- 计算圆心
- 使用本文中的代码在XY平面上构建一个圆
- 将其旋转回原始平面
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, ¢er);
}
// 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);
}
}
bool是垂直的(点3d*pt1、点3d*pt2、点3d*pt3);
双计算中心(点3D*pt1、点3D*pt2、点3D*pt3、点3D*中心);
无效FindCircleCenter(常量点3D*V1、常量点3D*V2、常量点3D*V3、Point3d*center)
{
Point3d*pt1=新的Point3d(*V1);
Point3d*pt2=新的Point3d(*V2);
Point3d*pt3=新的Point3d(*V3);
如果(!i垂直(pt1,pt2,pt3))计算中心(pt1,pt2,pt3,中心);
否则如果(!i垂直(pt1,pt3,pt2))计算中心(pt1,pt3,pt2,中心);
否则如果(!i垂直(pt2,pt1,pt3))计算中心(pt2,pt1,pt3,中心);
否则如果(!i垂直(pt2,pt3,pt1))计算中心(pt2,pt3,pt1,中心);
否则如果(!i垂直(pt3,pt2,pt1))计算中心(pt3,pt2,pt1,中心);
否则如果(!i垂直(pt3,pt1,pt2))计算中心(pt3,pt1,pt2,中心);
否则{
删除pt1;
删除pt2;
删除pt3;
返回;
}
删除pt1;
删除pt2;
删除pt3;
}
布尔垂直(点3D*pt1、点3D*pt2、点3D*pt3)
//检查给定点是否垂直于x轴或y轴
{
双yDelta_a=pt2->y-pt1->y;
双xDelta_a=pt2->x-pt1->x;
双yDelta_b=pt3->y-pt2->y;
双xDelta_b=pt3->x-pt2->x;
//检查两个pts的线路是否垂直
if(fabs(xDelta_a)y;
双xDelta_b=pt3->x-pt2->x;
if(晶圆厂(xDelta_a)x+pt3->x);
中心->y=0.5*(pt1->y+pt2->y);
中心->z=pt1->z;
返回1;
}
//IsPerpendicular()确保xDelta不为零
双斜线=yDelta\u a/xDelta\u a//
双坡度=yDelta\u b/xDelta\u b;
如果(fabs(aSlope bSlope)x=(aSlope*bSlope*(pt1->y-pt3->y)+bSlope*(pt1->x+pt2->x)
-aSlope*(pt2->x+pt3->x))/(2*(bSlope aSlope));
中心->y=-1*(中心->x-(pt1->x+pt2->x)/2)/aSlope+(pt1->y+pt2->y)/2;
返回1;
}
//!在三维空间中通过3个点和一个可选中心构建一个圆
无效构建循环3pt(常数浮点*pt1,
常量浮点*pt2,
常量浮点*pt3,
常量float*c,//中心,可以为NULL
标准::向量*圆)
{
/*获取由3个点组成的三角形的法向量
计算从法线到0,0,1轴的旋转四元数
使用四元数旋转3个点。点将位于XY平面中
在XY平面上通过3个点构建一个圆
使用四元数将圆旋转回原始平面
*/
点3D p1(pt1[0],pt1[1],pt1[2]);
点3D p2(pt2[0],pt2[1],pt2[2]);
点3D p3(pt3[0],pt3[1],pt3[2]);
点三维中心;
如果(c)
{
中心集(c[0],c[1],c[2]);
}
常量向量3D p2top1=p1-p2;
常量向量3D p2top3=p3-p2;
常量向量3D圆_normal=p2top1.crossProduct(p2top3.normalize();
常量向量3D xy_法线(0,0,1);
四元数;
//建筑旋转四元数
{
//旋转轴,我们将围绕该轴将圆旋转到XY平面
Vector3d旋转_轴=xy_法线。叉积(圆_法线)。规格化();
常数双旋转角度=xy_法线。角度到(圆_法线);//弧度
常数双w=cos(旋转角*0.5);
旋转轴*=正弦(旋转角*0.5);
旋转四轴集(w、旋转轴x、旋转轴y、旋转轴z);
}
四元数rot\u back\u quat;
//构建反向旋转四元数,与上一个相同,但-角度
{
常数双旋转角=-(xy_法线。角度到(圆_法线));//弧度
常数双w_后=cos(旋转角*0.5);
Vector3d rot_back_轴=xy_法线。叉积(圆_法线)。规格化();
旋转后旋转轴*=sin(旋转角*0.5);
rot_back_quat.set(w_back,rot_back_axis.x,rot_back_axis.y,rot_back_axis.z);
}
旋转(p1);
旋转(p2);
旋转(p3);
旋转(中心);
如果(!c)
{
//计算二维中心
FindCircleCenter(p1、p2、p3和中心);
}
//计算半径
常数双半径=中心距离(p1);
恒浮点数DEG2RAD=3.14159f/180.0f;
//构建循环
对于(int i=0;i<360;++i)
{
浮点数degInRad=i*DEG2RAD;
点3d pt(cos(degInRad)*半径+中心x,sin(degInRad)*半径+中心y,0);
//将点旋转回原始平面
旋转后四次旋转(pt);
循环->推回(第x部分);
圆圈->推回(第y部分);
圆圈->推回(点z);
}
}
有一个更简单的解决方案,可以在真实3D中找到圆参数,只需查看中的“重心坐标”部分。
您可以从中提取以下优化代码:
// triangle "edges"
const Vector3d t = p2-p1;
const Vector3d u = p3-p1;
const Vector3d v = p3-p2;
// triangle normal
const Vector3d w = t.crossProduct(u);
const double wsl = w.getSqrLength();
if (wsl<10e-14) return false; // area of the triangle is too small (you may additionally check the points for colinearity if you are paranoid)
// helpers
const double iwsl2 = 1.0 / (2.0*wsl);
const double tt = t*t;
const double uu = u*u;
// result circle
Vector3d circCenter = p1 + (u*tt*(u*v) - t*uu*(t*v)) * iwsl2;
double circRadius = sqrt(tt * uu * (v*v) * iwsl2*0.5);
Vector3d circAxis = w / sqrt(wsl);
//三角形“边”
常数向量3d t=p
// find orthogonal vector to the circle axis
const Vector3d an = circAxis.getNormalized();
const Vector3d ao = Vector3d(4.0+an[0], 4.0+an[0]+an[1], 4.0+an[0]+an[1]+an[2]).crossProduct(an).getNormalized();
// 4x4 rotation matrix around the circle axis
const int steps = 360; // maybe adjust according to circle size on screen
Matrix4d R = makeRotMatrix4d(circCenter, circAxis, 2.0*M_PI/double(steps));
// one point on the circle
Vector3d cp = circCenter + ao*circRadius;
// rotate point on the circle
for (int i=0; i<steps; ++i)
{
circlePoints.push_back(cp);
cp = transformPoint(cp, R); // apply the matrix
}