/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/Vector.h" #include "mg/Unit_vector.h" #include "mg/Matrix.h" #include "mg/Transf.h" #include "mg/Tolerance.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // MGMatrix.cc // Implementatation of MGMatrix // // // Constructor. //void constructor:void コンストラクタ MGMatrix::MGMatrix(int sdim) :m_sdim(sdim){ assert(sdim>=0); if(sdim){ int sdim2=sdim*sdim; m_matrix=new double[sdim2]; for(int i=0; i0 && start1=dim) j1=0; j2 +=1; if(j2>=dim2) j2=0; } i1 +=1; if(i1>=dim) i1=0; i2 +=1; if(i2>=dim2) i2=0; } } //Copy constructor. MGMatrix::MGMatrix(const MGMatrix& mat) :m_sdim(mat.m_sdim){ int len=m_sdim*m_sdim; m_matrix=new double[len]; for(int i=0; im) mat(im1,j-1)=ref(i,j); } } value+=mat.determinant()*sign*ref(0,m); sign=-sign; }; break; } return value; } //Construct a matrix to transform one of the axises to a vector 'uvec', // and replace own matrix with it. Inverse matrix of to_axis. // axis can be any number(can be more than 2). MGMatrix& MGMatrix::from_axis( const MGUnit_vector& uvec, // Unit vector to be an axis. int axis) // Axis kind 0:x, 1:y, 2:z, ... { //This program produce matrix by inversing to_axis matrix, //is based on to_axis. int dim=uvec.sdim(); if(axis>=dim) dim=axis+1; int i,j; int axis1=axis, axis2; MGUnit_vector unit=uvec; double len, len1, len2, max_len, cosv, sinv; MGMatrix mat(dim,1.), mat_inverse(dim,1.), m1,m2; //Compute matrix mat_inverse to rotate for axis1 element to be zero //from axis+1 to axis-1. from_axis is the inverse of mat_inverse. for(i=0; i=dim) axis1=0; //Get maximum length element id in axis2. axis2=0; max_len=fabs(unit.ref(0)); for(j=1; jmax_len){ axis2=j; max_len=len;} } if(axis1==axis2) axis2=axis; len1=unit.ref(axis1); len2=unit.ref(axis2); len=sqrt(len1*len1+len2*len2); cosv=len1/len; sinv=len2/len; m1=MGMatrix(dim,axis1,axis2,sinv,cosv); mat_inverse*=m1; //Above mat_inverse is to rotate for axis1 element to be zero. m2=MGMatrix(dim,axis1,axis2,sinv,-cosv); mat=m2*mat; unit=uvec*mat_inverse; } return *this=mat; } // Multiply matrix m1 and m2. MGMatrix MGMatrix::multiply(const MGMatrix& m2) const{ int dim=sdim(), dim2=m2.sdim(),i,j,k; if(dim=3) i=2; j=i+1; if(j>=3) j=0; k=j+1; if(k>=3) k=0; MGMatrix m1(3,1.), m2(3,1.); double a,d; double d2[3]; for(int n=0; n<3; n++){ a=uvec.ref(n); d2[n]=a*a; } double dij=d2[i]+d2[j]; double dki=d2[k]+d2[i]; if(dij>=dki){ d=sqrt(dij); // 1. Rotate around k-axis. m1(i,i)=uvec.ref(i)/d; m1(i,j)=-uvec.ref(j)/d; m1(j,i)=-m1(i,j); m1(j,j)=m1(i,i); // 2. Rotate around j-axis. m2(i,i)=d; m2(i,k)=-uvec.ref(k); m2(k,i)=uvec.ref(k); m2(k,k)=m2(i,i); }else{ d=sqrt(dki); // 1. Rotate around j-axis. m1(i,i)=uvec.ref(i)/d; m1(i,k)=-uvec.ref(k)/d; m1(k,i)=-m1(i,k); m1(k,k)=m1(i,i); // 2. Rotate around k-axis. m2(i,i)=d; m2(i,j)=-uvec.ref(j); m2(j,i)=uvec.ref(j); m2(j,j)=m2(i,i); } (*this)=m1*m2; return *this; } //Construct a matrix to transform a unit vector on an axis // to a vector 'uvec', and replace own matrix with it. //Inverse matrix of set_axis. MGMatrix& MGMatrix::set_vector( const MGUnit_vector& uvec, // Unit vector to be an axis. int axis) // Axis number 0:x, 1:y, 2:z. { assert(uvec.sdim()<=3 && axis<3); int i,j,k; i=axis; j=i+1; if(j>=3) j=0; k=j+1; if(k>=3) k=0; MGMatrix m1(3,1.), m2(3,1.); double a,d; double d2[3]; for(int n=0; n<3; n++){ a=uvec(n); d2[n]=a*a; } double dij=d2[i]+d2[j]; double dki=d2[k]+d2[i]; if(dij>=dki){ d=sqrt(dij); // 1. Rotate around j-axis. m2(i,i)=d; m2(i,k)=uvec(k); m2(k,i)=-uvec(k); m2(k,k)=m2(i,i); // 2. Rotate around k-axis. m1(i,i)=uvec(i)/d; m1(i,j)=uvec(j)/d; m1(j,i)=-m1(i,j); m1(j,j)=m1(i,i); }else{ d=sqrt(dki); // 1. Rotate around k-axis. m2(i,i)=d; m2(i,j)=uvec(j); m2(j,i)=-uvec(j); m2(j,j)=m2(i,i); // 2. Rotate around j-axis. m1(i,i)=uvec(i)/d; m1(i,k)=uvec(k)/d; m1(k,i)=-m1(i,k); m1(k,k)=m1(i,i); } (*this)=m2*m1; return *this; } // 与えられた2つの単位ベクトルを各々、X軸、Y軸にするよう原点の周りに // 回転させる 3D Matrix を生成し,自身のMatrixと入れ替える。もし、 // 2つ目の単位ベクトルが1つ目の単位ベクトルと直交しない場合は、2つのベ // クトルのかわりに両ベクトルを含む平面内で直交するよう変換したベクトルを // 使用する。 MGMatrix& MGMatrix::set_xy_axis (const MGUnit_vector& uvecx, //Unit vector 1 for x axis. const MGUnit_vector& uvecy) //Unit vector 2 for y axis. { assert(uvecx.sdim()<=3 && uvecy.sdim()<=3); double a,b; MGMatrix mx(3,1.), mat; mat.set_axis(uvecx, 0); // mat=the matrix to transform uvecx as x-axis. MGVector vecy=uvecy*mat; a=vecy[1]; b=vecy[2]; double dvecy=sqrt(a*a+b*b); if(dvecy>MGTolerance::mach_zero()){ mx(1,1)=a/dvecy; mx(1,2)=-b/dvecy; mx(2,1)=-mx(1,2); mx(2,2)=mx(1,1); //mx= the matrix to rotate around x-axis for uvecy*mat to be y-axis. (*this)=mat*mx; }else (*this)=mat; return *this; } // X軸、Y軸を各々、与えられた2つの単位ベクトルにするよう原点の周りに // 回転させる 3D Matrix を生成し,自身のMatrixと入れ替える。もし、 // 2つ目の単位ベクトルが1つ目の単位ベクトルと直交しない場合は、2つのベ // クトルのかわりに両ベクトルを含む平面内で直交するよう変換したベクトルを // 使用する。 // This is the inverse matrix of set_xy_axis(). MGMatrix& MGMatrix::set_xy_vector (const MGUnit_vector& uvecx, //Unit vector 1 for x axis. const MGUnit_vector& uvecy) //Unit vector 2 for y axis. { assert(uvecx.sdim()<=3 && uvecy.sdim()<=3); MGVector ay(3); MGMatrix mat1; mat1.set_vector(uvecx, 0); // mat1=the matrix to transform x-axis as uvecx. ay(0)=mat1(1,0); ay(1)=mat1(1,1); ay(2)=mat1(1,2); //ay is the transformed vector of y-axis by matrix mat1. MGUnit_vector vy=(uvecx*uvecy)*uvecx;//vy is normalized uvecy. double cval=ay.cangle(vy); double sval=ay.sangle(vy); if((ay*vy)%uvecx < 0.) sval=-sval; MGMatrix mat2; mat2.set_rotate_3D(uvecx, cval, sval); // mat2 is the matrix to transform ay to be vy(normalized uvecy). return *this=mat1*mat2; } // 原点を通り、指定ベクトルに垂直な平面に関して鏡面変換する 3D Matrix // を作成し,既存のMatrixと入れ換える。 MGMatrix& MGMatrix::set_reflect_3D(const MGVector& vec1) { set_axis(vec1,0); // this = To transform vec1 to x-axis. (*this)(0,0) *= -1.;(*this)(1,0) *= -1.;(*this)(2,0) *= -1.; //Reflection about x-axis. MGMatrix m2; m2.set_vector(vec1,0); // m2 = To transform x-axis to vec1. return (*this)*=m2; } // 与えられたベクトル回りに指定の角度回転させる3D Matrixを作成し既存の // Matrixと入れ換える。 MGMatrix& MGMatrix::set_rotate_3D( const MGVector& vec, //Rotate Axis vector double angle ) //Angle { set_axis(vec,0); // this = To transform vec1 to x-axis. MGMatrix temp; temp.set_rotate_2D(angle); MGMatrix m2=MGMatrix(3,temp,1,0); //m2= Rotation about x-axis. MGMatrix m3; m3.set_vector(vec,0); // m3 = To transform x-axis to vec1. (*this)*=m2; return (*this)*=m3; } //3D rotation matrix around vec. //The angle is given by cval as cos(angle) and sval as sin(angle). MGMatrix& MGMatrix::set_rotate_3D (const MGVector& vec, //Rotate Axis vector double cval, double sval) //Angle in cos() and sin() { set_axis(vec,0); // this = To transform vec1 to x-axis. MGMatrix temp; temp.set_rotate_2D(cval, sval); MGMatrix m2=MGMatrix(3,temp,1,0); //m2= Rotation about x-axis. MGMatrix m3; m3.set_vector(vec,0); // m3 = To transform x-axis to vec1. (*this)*=m2; (*this)*=m3; return *this; } // 各軸方向で等しい Scaling のためのMatrixを生成し、既存の // Matrixと入れ換える。Not change space dimension. MGMatrix& MGMatrix::set_scale(double scale){ int dim=sdim(); for(int i=0; i=dim) dim=axis+1; int i,j; MGUnit_vector unit=uvec; double len, len1, len2, max_len, cosv, sinv; MGMatrix mat(dim,1.); int axis1=axis, axis2; //Compute matrix to rotate for axis1 element to be zero //from axis+1 to axis-1. for(i=0; i=dim) axis1=0; //Get maximum length element id in axis2. axis2=0; max_len=fabs(unit.ref(0)); for(j=1; jmax_len){ axis2=j; max_len=len;} } if(axis1==axis2) axis2=axis; len1=unit.ref(axis1); len2=unit.ref(axis2); len=sqrt(len1*len1+len2*len2); cosv=len1/len; sinv=len2/len; mat*=MGMatrix(dim,axis1,axis2,sinv,cosv); //Above MGMatrix(...) is to rotate for axis1 element to be zero. unit=uvec*mat; // std::cout<<" axis from i="<