三点求圆公式Matlab 和C++版程序

三点求圆公式Matlab 和C++版程序

%% 给定三个点做圆弧轨迹规划
function P_P=plot_circle(p1,p2,p3)

%% 利用这三个点做一个平面方程

k_11=( p1(2)-p3(2) )*( p2(3)-p3(3) ) - ( p2(2)-p3(2) )*( p1(3)-p3(3) ) ;
k_12=( p2(1)-p3(1) )*( p1(3)-p3(3) ) - ( p1(1)-p3(1) )*( p2(3)-p3(3) ) ;
k_13=( p1(1)-p3(1) )*( p2(2)-p3(2) ) - ( p2(1)-p3(1) )*( p1(2)-p3(2) ) ;
k_14= -( k_11*p3(1) + k_12*p3(2) + k_13*p3(3) );

%% 过p1 p2的中点并且和 p1p2 垂直的平面方程 
k_21=p2(1)-p1(1);
k_22=p2(2)-p1(2);
k_23=p2(3)-p1(3);
k_24= -( ( p2(1)^2-p1(1)^2 ) + ( p2(2)^2-p1(2)^2 ) + ( p2(3)^2-p1(3)^2 )  )/2;


%% 过p2 p3的中点并且和 p2p3 垂直的平面方程 
k_31=p3(1)-p2(1);
k_32=p3(2)-p2(2);
k_33=p3(3)-p2(3);
k_34=-( ( p3(1)^2-p2(1)^2 ) + ( p3(2)^2-p2(2)^2 ) + ( p3(3)^2-p2(3)^2 )  )/2;


%% 圆心肯定在这三个平面上面。利用点法式方程求得圆心
K_123=[k_11 k_12 k_13;k_21 k_22 k_23;k_31 k_32 k_33];
k_4=[-k_14;-k_24;-k_34];

C=inv(K_123)*k_4;

R=sqrt(   ( C(1)-p1(1) )^2 +  ( C(2)-p1(2) )^2 + ( C(3)-p1(3) )^2 );



%% 以这个三个点重新确立一个空间直角坐标系

%% K_11 k_12 k_13 是和 p1p2p3 所在平面垂直的法向量, 故取该法向量的单位向量为 Z轴
W_x=k_11/sqrt(k_11^2+k_12^2+k_13^2);
W_y=k_12/sqrt(k_11^2+k_12^2+k_13^2);
W_z=k_13/sqrt(k_11^2+k_12^2+k_13^2);


%% 以 Op1 的单位向量 为 X 轴
U_x= ( p1(1)- C(1) )/R ;
U_y= ( p1(2)- C(2) )/R ;
U_z= ( p1(3)- C(3) )/R ;

%% 确定 Y 轴,为 Z 轴和 X轴的叉乘
V_x= W_y*U_z-W_z*U_y;
V_y= W_z*U_x-W_x*U_z;
V_z= W_x*U_y-W_y*U_x;


T=[U_x V_x W_x C(1);
   U_y V_y W_y C(2);
   U_z V_z W_z C(3);
   0    0   0    1];


%% 对向量坐标进行相应的齐次化
p1=[p1;1];
p2=[p2;1];
p3=[p3;1];
n_p1=inv(T)*p1;
n_p2=inv(T)*p2;
n_p3=inv(T)*p3;
n_p1=n_p1(1:3);
n_p2=n_p2(1:3);
n_p3=n_p3(1:3);


%% 求圆心角
%% 为了方便求这三个点之间的顺序,还需要求得这三个点的圆心角,因为atan2 的角度范围是 -pi pi,故统一进行变换为正的角度
theta_p2_o_p1=atan2(n_p2(2),n_p2(1));
if theta_p2_o_p1 < 0
    theta_p2_o_p1=theta_p2_o_p1+2*pi;
end

theta_p3_o_p1=atan2(n_p3(2),n_p3(1));
if theta_p3_o_p1 < 0
    theta_p3_o_p1=theta_p3_o_p1+2*pi;
end

%% 经过上面的变换之后,如果 p1p2 的角度 小于 p1p3 的角度,那么就是逆时针转,反之就是顺时针转。
if theta_p2_o_p1 < theta_p3_o_p1
    dir=1;
else
    dir=-1;
end


%% 用五次多项式进行圆弧插补 
delta_t=0.5;
t=0:delta_t:10;

nm=Five_ploynomial(0,10,0,1,0,0,0,0);

n=size(nm);


for i=1:1:n(2)
    u(i)=R*cos(nm(i)*dir*theta_p3_o_p1);
    v(i)=R*sin(nm(i)*dir*theta_p3_o_p1);
    w(i)=0;
end



for j=1:1:i
    p=T*[u(j);v(j);w(j);1];
    x(j)=p(1);
    y(j)=p(2);
    z(j)=p(3);
end
  
P_P=[x;y;z];
end

function qt=Five_ploynomial(t0,tf,q0,qf,d_q0,d_qf,dd_q0,dd_qf)

    A = ( 12*(qf - q0) - 6*(d_qf+d_q0)*tf - (dd_q0-dd_qf)*tf^2 ) /(2*tf^5);
	B = ( -30*(qf - q0) + (16*d_q0 + 14*d_qf)*tf  + (3*dd_q0-2*dd_qf)*tf^2 ) / (2*tf^4);
	C = ( 20*(qf - q0) - (12*d_q0 + 8*d_qf)*tf - (3*dd_q0-dd_qf)*tf^2 ) / (2*tf^3);
    D=dd_q0/2;
	E = d_q0; 
	F = q0;

i=1;
   for t=t0:0.5:tf
       qt(i)=A*t^5+B*t^4+C*t^3+D*t^2+E*t+F;
       i=i+1;
   end



end

C++ 版程序

void plot_circle(Vector3d & p1, Vector3d & p2, Vector3d & p3,MatrixXd& XYZ)
{
	//利用这三个点做一个平面方程

	double k_11 = (p1(1) - p3(1))*(p2(2) - p3(2)) - (p2(1) - p3(1))*(p1(2) - p3(2));
	double k_12 = (p2(0) - p3(0))*(p1(2) - p3(2)) - (p1(0) - p3(0))*(p2(2) - p3(2));
	double k_13 = (p1(0) - p3(0))*(p2(1) - p3(1)) - (p2(0) - p3(0))*(p1(1) - p3(1));
	double k_14 = -(k_11*p3(0) + k_12*p3(1) + k_13*p3(2));

	// 过p1 p2的中点并且和 p1p2 垂直的平面方程
	double k_21 = p2(0) - p1(0);
	double k_22 = p2(1) - p1(1);
	double k_23 = p2(2) - p1(2);
	double k_24 = -( (  pow(p2(0) , 2) - pow(p1(0) , 2) ) + ( pow( p2(1) , 2)  - pow( p1(1),2) ) + ( pow( p2(2) , 2)  - pow( p1(2) , 2) )) / 2;


	// 过p2 p3的中点并且和 p2p3 垂直的平面方程
	double k_31 = p3(0) - p2(0);
	double k_32 = p3(1) - p2(1);
	double k_33 = p3(2) - p2(2);
	double k_34 =  -((pow(p3(0), 2) - pow(p2(0), 2)) + (pow(p3(1), 2) - pow(p2(1), 2)) + (pow(p3(2), 2) - pow(p2(2), 2))) / 2;


	// 圆心肯定在这三个平面上面。利用点法式方程求得圆心
	Matrix3d  K_123=Matrix3d::Zero(); 
	K_123 <<  k_11, k_12, k_13, k_21, k_22, k_23, k_31, k_32, k_33;
	Vector3d   k_4 = Vector3d::Zero();
	k_4<< -k_14, -k_24, -k_34;

	Vector3d C =( K_123.inverse()*k_4);

	double R = sqrt( pow ( (C(0) - p1(0)),2) +  pow ( (C(1) - p1(1)),2) +  pow ( (C(2) - p1(2)),2));



	// 以这个三个点重新确立一个空间直角坐标系
    // K_11 k_12 k_13 是和 p1p2p3 所在平面垂直的法向量, 故取该法向量的单位向量为 Z轴
	double W_x = k_11 / sqrt(pow( k_11,2) + pow( k_12,2) + pow( k_13,2));
	double W_y = k_12 / sqrt(pow( k_11,2) + pow( k_12,2) + pow( k_13,2));
	double W_z = k_13 / sqrt(pow( k_11,2) + pow( k_12,2) + pow( k_13,2));


	// 以 Op1 的单位向量 为 X 轴
	double 	U_x = (p1(0) - C(0)) / R;
	double 	U_y = (p1(1) - C(1)) / R;
	double 	U_z = (p1(2) - C(2)) / R;

	// 确定 Y 轴,为 Z 轴和 X轴的叉乘
	double 	V_x = W_y*U_z - W_z*U_y;
	double 	V_y = W_z*U_x - W_x*U_z;
	double 	V_z = W_x*U_y - W_y*U_x;


	Matrix4d T = Matrix4d::Zero();
	          T<< U_x, V_x, W_x, C(0),
	              U_y, V_y, W_y, C(1),
	              U_z, V_z, W_z, C(2),
	              0,    0,   0,    1;

	// 对向量坐标进行相应的齐次化
			  Vector4d p1_new; 
			  Vector4d p2_new; 
			  Vector4d p3_new; 
			  p1_new << p1(0), p1(1), p1(2), 1;
			  p2_new << p2(0), p2(1), p2(2), 1;
			  p3_new << p3(0), p3(1), p3(2), 1;
			  Vector4d n_p1 = T.inverse()*p1_new;
			  Vector4d n_p2 = T.inverse()*p2_new;
			  Vector4d n_p3 = T.inverse()*p3_new;

	//求圆心角
	//为了方便求这三个点之间的顺序,还需要求得这三个点的圆心角,因为atan2 的角度范围是 - pi pi, 故统一进行变换为正的角度
	double theta_p2_o_p1 = atan2(n_p2(1), n_p2(0));
	if ( theta_p2_o_p1 < 0 )
		theta_p2_o_p1 = theta_p2_o_p1 + 2 * pi;
	double theta_p3_o_p1 = atan2(n_p3(1), n_p3(0));
	if ( theta_p3_o_p1 < 0 )
		theta_p3_o_p1 = theta_p3_o_p1 + 2 * pi;
	//经过上面的变换之后,如果 p1p2 的角度 小于 p1p3 的角度,那么就是逆时针转,反之就是顺时针转。
	int dir = 1;
	if( theta_p2_o_p1 < theta_p3_o_p1 )
		dir = 1;
	else
		dir = -1;

	// 用五次多项式进行圆弧插补
	double t0 = 0;
	double tf = 10;
	double delta_t = 0.5;
	int n = (tf - t0) / delta_t + 1;
	VectorXd qt(n);

	Five_ploynomial(0, 10, 0, 1, 0, 0, 0, 0,qt);
	VectorXd u(n);
	VectorXd v(n);
	VectorXd w(n);
	VectorXd x(n);
	VectorXd y(n);
	VectorXd z(n);
	for (int i = 0; i < n; ++i)
	{
		u(i) = R*cos(qt(i)*dir*theta_p3_o_p1);
		v(i) = R*sin(qt(i)*dir*theta_p3_o_p1);
		w(i) = 0;

	}

	for (int j = 0; j < n; ++j)
	{
		Vector4d temp;
		temp << u(j), v(j), w(j), 1;
		Vector4d p = T*temp;
		XYZ(j,0) = p(0);
		XYZ(j, 1) = p(1);
		XYZ(j, 2) = p(2);
	}


}
void  Five_ploynomial(double t0, double tf, double q0, double qf, double d_q0, double d_qf, double dd_q0, double  dd_qf, VectorXd & qt)
{
	double A, B, C, D, E, F;

	A = (double(12.00 * (qf - q0)) - 6 * (d_qf + d_q0)*tf - (dd_q0 - dd_qf)*pow(tf, 2)) / (2 * pow(tf, 5));
	B = (double(-30 * (qf - q0) + (16 * d_q0 + 14 * d_qf)*tf + (3 * dd_q0 - 2 * dd_qf)*pow(tf, 2))) / (2 * pow(tf, 4));
	C = (double(20 * (qf - q0) - (12 * d_q0 + 8 * d_qf)*tf - (3 * dd_q0 - dd_qf)*pow(tf, 2))) / (2 * pow(tf, 3));
	D = dd_q0 / 2;
	E = d_q0;
	F = q0;

	double i = 0;
	for (double t = 0; t < tf + 0.5; t = t + 0.5)
	{
		qt(i) = A*pow(t, 5) + B*pow(t, 4) + C*pow(t, 3) + D*pow(t, 2) + E*t + F;
		i = i + 1;
	}

}
    原文作者:独坐寒江边
    原文地址: https://blog.csdn.net/u014077947/article/details/82844810
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞