一 简介
圆作为几何图形中一种常见的图形,经常被用于描述生活中的各种物体,如隧道截面轮廓、结构柱截面轮廓、树干截面轮廓。因此,如何对圆进行参数方程表达,将是对这些对象建模的关键之处,而如何对三维空间中的圆(任意圆)进行参数方程表达,将是我们这次的主要任务。
这次的内容主要包括三个:
(1)2D特殊圆的参数方程表达;
(2)2D任意圆的参数方程表达;
(3)3D任意圆的参数方程表达;
(4)代码展示:
二 2D特殊圆的参数方程表达
如上图所示,该处2D特殊圆是指圆心在坐标空间原点。众所周知,圆心在原点,半径为r的圆形参数方程可以表示为:
x=r*cosα,可以理解为OP在X轴上的投影为圆周上点P的x坐标
y=r*sinα,可以理解为OP在Y轴上的投影为圆周上点P的y坐标
也可以通过向量的思路去理解:
OP为向量,可视作直角三角形斜边向量,因此,可通过两条直角边向量相加得到,
OP=OP*cosα+OP*sinα
三 2D任意圆的参数方程表达
同上,我们通过向量的思维来理解2D任意圆的参数方程表达(以下表达均为向量)。
首先,OP=OC+CP
接着,CP=CP_a+CP_b,其中,CP_a为向量CP在坐标轴a上的投影向量,CP_b为向量CP在坐标轴b上的投影向量。
然后,CP_a=||CP||*cosα*a=r*cosα*a,CP_b=||CP||*sinα*b=r*sinα*b,其中a可认为是x轴单位向量(1,0),b可认为是y轴单位向量(0,1)。
最后,OC为圆心与原点构建的向量(cx,cy)。
综上所述,2D任意圆的参数方程能够表示为:
x=cx+r*cosα*a_x+r*sinα*b_x
y=cy+r*cosα*a_y+r*sinα*b_y
因此,如果已知圆心坐标、圆半径,并能在二维空间中描绘出圆形。
四 3D任意圆的参数方程表达
同上,我们通过向量法来推导3D任意圆的参数方程表达式(以下均为向量表示):
首先,OP=OC+CP
接着,CP=CP_a+CP_b,其中,CP_a为向量CP在坐标轴a上的投影向量,CP_b为向量CP在坐标轴b上的投影向量。
然后,CP_a=||CP||*cosα*a=r*cosα*a,CP_b=||CP||*sinα*b=r*sinα*b。
其中,向量a和向量b为3D圆所在平面中一组正交的单位向量,可以通过法向量N进行求得。
如:
c=(0,0,1)——可任意设置,只要不与法向量平行即可
a=N x c
b=N x a
x表示叉乘。
最后,OC为圆心与原点构建的向量(cx,cy,cz)。
综上所述,3D任意圆的参数方程能够表示为:
x=cx+r*cosα*a_x+r*sinα*b_x
y=cy+r*cosα*a_y+r*sinα*b_y
z=cz+r*cosα*a_z+r*sinα*b_z
因此,如果已知圆心坐标、圆半径以及圆所在平面法向量,并能在三维空间中描绘出圆形。
五 代码展示
// 三维空间中,根据圆心、半径、法向量求 require_number 个圆上的点(按顺序排列)
/*
* 注:根据一个 7 维向量拟合圆,coefM_为一个 7 维向量,依次为:圆心(x,y,z),半径,法向量(nx,ny,nz)
*/
std::vector<Eigen::Vector3f> createCircleBy_Center_Radius_Normal_3D(Eigen::VectorXf coefM_,
int require_number)
{
assert(coefM_.size() == 7);
assert(require_number > 0);
std::vector<Eigen::Vector3f> circleEdge;
float stepSize = 2 * M_PI / require_number;
Eigen::VectorXf theta(require_number+1);
for (int i = 0; i <= require_number; ++i) {
theta[i] = i * stepSize;
}
Eigen::Vector3f Center = coefM_.head(3);
Eigen::Vector3f N = coefM_.tail(3);
float R = coefM_[3];
Eigen::Vector3f V1 = N.cross(Eigen::Vector3f(0, 0, 1));
if (V1[0] == 0 && V1[1] == 0 && V1[2] == 0) {
V1 = N.cross(Eigen::Vector3f(0, 1, 0));
}
V1.normalize();
Eigen::Vector3f V2 = N.cross(V1);
V2.normalize();
circleEdge.resize(require_number);
for (int i = 0; i < require_number; ++i) {
if (i > 9) continue;
circleEdge[i][0] = std::cos(theta[i]) * R * V1[0] + std::sin(theta[i]) * R * V2[0] + Center[0];
circleEdge[i][1] = std::cos(theta[i]) * R * V1[1] + std::sin(theta[i]) * R * V2[1] + Center[1];
circleEdge[i][2] = std::cos(theta[i]) * R * V1[2] + std::sin(theta[i]) * R * V2[2] + Center[2];
}
return circleEdge;
}