Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
////////////////////////////////////////////////////////////////////////////////////////////////
// 3d geometry classes - implements some 3d stuff
//
// g.j.hawkesford August 2003
//
// This program is released under the BSD license. See the file COPYING for details.
//
////////////////////////////////////////////////////////////////////////////////////////////////
#include "geometry.h"
////////////////////////////////////////////////////////////////////////////////////////////////
// matrix
////////////////////////////////////////////////////////////////////////////////////////////////
Matrix::Matrix(){
Unit();
}
Matrix::Matrix(const double m[16]) {
memcpy(e, m, sizeof(e));
this->IsUnit();
this->IsMirrored();
}
Matrix::Matrix(const Point3d &origin, const Point3d &x_axis, const Point3d &y_axis)
{
Point3d unit_x = x_axis;
unit_x.normalise();
double t = unit_x.x * y_axis.x
+ unit_x.y * y_axis.y
+ unit_x.z * y_axis.z;
Point3d y_orthogonal(y_axis.x - unit_x.x * t, y_axis.y - unit_x.y * t, y_axis.z - unit_x.z * t);
Point3d unit_y = y_orthogonal;
unit_y.normalise();
Point3d unit_z = (unit_x ^ y_orthogonal);
unit_z.normalise();
double m[16] = { unit_x.x, unit_y.x, unit_z.x, origin.x, unit_x.y, unit_y.y, unit_z.y, origin.y, unit_x.z, unit_y.z, unit_z.z, origin.z, 0, 0, 0, 1 };
memcpy(e, m, sizeof(e));
this->IsUnit();
this->IsMirrored();
}
Matrix::Matrix( const Matrix& m)
{
*this = m;
}
bool Matrix::operator==(const Matrix &m)const{
// m1 == m2
if(this->m_unit != m.m_unit || this->m_mirrored != m.m_mirrored) return false;
for(int i = 0; i < 16; i++)
if(FEQ(this->e[i], m.e[i], TIGHT_TOLERANCE) == false) return false;
return true;
}
const Matrix Matrix::operator*(const Matrix &m)const
{
Matrix mat(*this);
mat.Multiply(m);
return mat;
}
#if 0
const Matrix& Matrix::operator=( Matrix &m) {
for(int i = 0; i < 16; i++) e[i] = m.e[i];
m_unit = m.m_unit;
m_mirrored = m.m_mirrored;
return *this;
}
#endif
void Matrix::Unit()
{
// homogenous matrix - set as unit matrix
memset(e, 0, sizeof(e));
e[0] = e[5] = e[10] = e[15] = 1;
m_unit = true;
m_mirrored = false;
}
void Matrix::Get(double* p) const
{
// copy the matrix
memcpy(p, e, sizeof(e));
}
void Matrix::GetTransposed(double* p) const
{
p[0] = e[0];
p[1] = e[4];
p[2] = e[8];
p[3] = e[12];
p[4] = e[1];
p[5] = e[5];
p[6] = e[9];
p[7] = e[13];
p[8] = e[2];
p[9] = e[6];
p[10] = e[10];
p[11] = e[14];
p[12] = e[3];
p[13] = e[7];
p[14] = e[11];
p[15] = e[15];
}
void Matrix::Put(double* p)
{
// assign the matrix
memcpy(e, p, sizeof(e));
m_unit = false; // don't know
m_mirrored = -1; // don't know
}
void Matrix::Translate(double x, double y, double z)
{
// translation
e[3] += x;
e[7] += y;
e[11] += z;
m_unit = false;
}
void Matrix::Translate(const Point3d& v)
{
Translate(v.x, v.y, v.z);
}
void Matrix::Rotate(double angle, const Point3d &rotAxis) {
/// Rotation about rotAxis with angle
Rotate(sin(angle), cos(angle), rotAxis);
}
void Matrix::Rotate(double sinang, double cosang, const Point3d &rotAxis) {
/// Rotation about rotAxis with cp & dp
Matrix rotate;
double oneminusc = 1.0 - cosang;
rotate.e[0] = rotAxis.x * rotAxis.x * oneminusc + cosang;
rotate.e[1] = rotAxis.x * rotAxis.y * oneminusc - rotAxis.z * sinang;
rotate.e[2] = rotAxis.x * rotAxis.z * oneminusc + rotAxis.y * sinang;
rotate.e[4] = rotAxis.x * rotAxis.y * oneminusc + rotAxis.z * sinang;
rotate.e[5] = rotAxis.y * rotAxis.y * oneminusc + cosang;
rotate.e[6] = rotAxis.y * rotAxis.z * oneminusc - rotAxis.x * sinang;
rotate.e[8] = rotAxis.x * rotAxis.z * oneminusc - rotAxis.y * sinang;
rotate.e[9] = rotAxis.y * rotAxis.z * oneminusc + rotAxis.x * sinang;
rotate.e[10] = rotAxis.z * rotAxis.z * oneminusc + cosang;
Multiply(rotate); // concatinate rotation with this matrix
m_unit = false;
m_mirrored = -1; // don't know
}
void Matrix::Rotate(double angle, int Axis)
{ // Rotation (Axis 1 = x , 2 = y , 3 = z
Rotate(sin(angle), cos(angle), Axis);
}
void Matrix::Rotate(double sinang, double cosang, int Axis)
{ // Rotation (Axis 1 = x , 2 = y , 3 = z
Matrix rotate;
rotate.Unit();
switch(Axis)
{
case 1:
// about x axis
rotate.e[5] = rotate.e[10] = cosang;
rotate.e[6] = -sinang;
rotate.e[9] = sinang;
break;
case 2:
// about y axis
rotate.e[0] = rotate.e[10] = cosang;
rotate.e[2] = sinang;
rotate.e[8] = -sinang;
break;
case 3:
// about z axis
rotate.e[0] = rotate.e[5] = cosang;
rotate.e[1] = -sinang;
rotate.e[4] = sinang;
break;
}
Multiply(rotate); // concatinate rotation with this matrix
m_unit = false;
m_mirrored = -1; // don't know
}
void Matrix::Scale(double scale)
{
// add a scale
Scale(scale, scale, scale);
}
void Matrix::Scale(double scalex, double scaley, double scalez)
{
// add a scale
Matrix temp;
temp.Unit();
temp.e[0] = scalex;
temp.e[5] = scaley;
temp.e[10] = scalez;
Multiply(temp);
m_unit = false;
m_mirrored = -1; // don't know
}
void Matrix::Multiply(const Matrix& m)
{
// multiply this by give matrix - concatinate
int i, k, l;
Matrix ret;
for (i = 0; i < 16; i++)
{
l = i - (k = (i % 4));
ret.e[i] = m.e[l] * e[k] + m.e[l+1] * e[k+4] + m.e[l+2] * e[k+8] + m.e[l+3] * e[k+12];
}
*this = ret;
this->IsUnit();
m_mirrored = -1;
}
void Matrix::Transform(double p0[3], double p1[3]) const
{
// transform p0 thro' this matrix
if(m_unit)
memcpy(p1, p0, 3 * sizeof(double));
else {
p1[0] = p0[0] * e[0] + p0[1] * e[1] + p0[2] * e[2] + e[3];
p1[1] = p0[0] * e[4] + p0[1] * e[5] + p0[2] * e[6] + e[7];
p1[2] = p0[0] * e[8] + p0[1] * e[9] + p0[2] * e[10] + e[11];
}
}
void Matrix::TransformOnlyRotation(double p0[3], double p1[3]) const
{
// transform p0 thro' this matrix
if (m_unit)
memcpy(p1, p0, 3 * sizeof(double));
else {
p1[0] = p0[0] * e[0] + p0[1] * e[1] + p0[2] * e[2];
p1[1] = p0[0] * e[4] + p0[1] * e[5] + p0[2] * e[6];
p1[2] = p0[0] * e[8] + p0[1] * e[9] + p0[2] * e[10];
}
}
void Matrix::Transform2d(double p0[2], double p1[2]) const
{
// transform p0 thro' this matrix (2d only)
if(m_unit)
memcpy(p1, p0, 2 * sizeof(double));
else {
p1[0] = p0[0] * e[0] + p0[1] * e[1] + e[3];
p1[1] = p0[0] * e[4] + p0[1] * e[5] + e[7];
}
}
void Matrix::Transform(double p0[3]) const
{
double p1[3];
if(!m_unit) {
Transform(p0, p1);
memcpy(p0, p1, 3 * sizeof(double));
}
}
int Matrix::IsMirrored()
{
// returns true if matrix has a mirror
if(m_unit)
m_mirrored = false;
else if(m_mirrored == -1) {
m_mirrored = ((e[0] * (e[5] * e[10] - e[6] * e[9])
- e[1] * (e[4] * e[10] - e[6] * e[8])
+ e[2] * (e[4] * e[9] - e[5] * e[8])) < 0);
}
return m_mirrored;
}
int Matrix::IsUnit() {
// returns true if unit matrix
for(int i = 0; i < 16; i++) {
if(i == 0 || i == 5 || i == 10 || i == 15) {
if(e[i] != 1) return m_unit = false;
}
else {
if(e[i] != 0) return m_unit = false;
}
}
m_mirrored = false;
return m_unit = true;
}
void Matrix::GetTranslate(double& x, double& y, double& z) const
{
// return translation
x = e[3];
y = e[7];
z = e[11];
}
void Matrix::GetScale(double& sx, double& sy, double& sz) const
{
// return the scale
if(m_unit) {
sx = sy = sz = 1;
}
else {
sx = sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);
sy = sqrt(e[4] * e[4] + e[5] * e[5] + e[6] * e[6]);
sz = sqrt(e[8] * e[8] + e[9] * e[9] + e[10] * e[10]);
}
}
bool Matrix::GetScale(double& sx) const
{
// return a uniform scale (false if differential)
double sy, sz;
if(m_unit) {
sx = 1;
return true;
}
GetScale(sx, sy, sz);
return (fabs(fabs(sx) - fabs(sy)) < 0.000001)?true : false;
}
void Matrix::GetRotation(double& ax, double& ay, double& az) const
{
// return the rotations
if(m_unit) {
ax = ay = az = 0;
return;
}
double a; /* cos(bx) */
double b; /* sin(bx) */
double c; /* cos(by) */
double d; /* sin(by) */
double ee; /* cos(bz) */
double f; /* sin(bz) */
double sx, sy, sz;
GetScale(sx, sy, sz);
if(this->m_mirrored == -1) FAILURE(L"Don't know mirror - use IsMirrored method on object");
if(this->m_mirrored) sx = -sx;
// solve for d and decide case and solve for a, b, c, e and f
d = - e[8] / sz;
if((c = (1 - d) * (1 + d)) > 0.001)
{
// case 1
c = sqrt( c );
a = e[10] / sz / c;
b = e[9] / sz / c;
ee = e[0] / sx / c;
f = e[4] / sy / c;
}
else
{
// case 2
double coef;
double p, q;
d = ( d < 0 ) ? -1 : 1 ;
c = 0 ;
p = d * e[5] / sy - e[2] / sx;
q = d * e[6] / sy + e[1] / sx;
if((coef = sqrt( p * p + q * q )) > 0.001) {
a = q / coef;
b = p / coef;
ee = b;
f = -d * b;
}
else
{
/* dependent pairs */
a = e[5] / sy;
b = -e[6] / sy;
ee = 1 ;
f = 0 ;
}
}
// solve and return ax, ay and az
ax = atan2( b, a );
ay = atan2( d, c );
az = atan2( f, ee );
}
Matrix Matrix::Inverse()const
{
// matrix inversion routine
// a is input matrix destroyed & replaced by inverse
// method used is gauss-jordan (ref ibm applications)
double hold , biga ;
int i , j , k , nk , kk , ij , iz ;
int ki , ji , jp , jk , kj , jq , jr , ik;
int n = 4; // 4 x 4 matrix only
Matrix a = *this;
int l[4], m[4];
if(a.m_unit) return a; // unit matrix
// search for largest element
nk = - n ;
for ( k = 0 ; k < n ; k++ ) {
nk += n ;
l [ k ] = m [ k ] = k ;
kk = nk + k ;
biga = a.e[ kk ] ;
for ( j = k ; j < n ; j++ ) {
iz = n * j ;
for ( i = k ; i < n ; i++ ) {
ij = iz + i ;
if ( fabs ( biga ) < fabs ( a.e[ ij ] ) ) {
biga = a.e[ ij ] ;
l[ k ] = i ;
m[ k ] = j ;
}
}
}
// interchange rows
j = l[ k ] ;
if ( j > k ) {
ki = k - n ;
for ( i = 0 ; i < n ; i++ ) {
ki += n ;
hold = - a.e[ ki ] ;
ji = ki - k + j ;
a.e[ ki ] = a.e[ ji ] ;
a.e[ ji ] = hold ;
}
}
// interchange columns
i = m[ k ] ;
if ( i > k ) {
jp = n * i ;
for ( j = 0 ; j < n ; j++ ) {
jk = nk + j ;
ji = jp + j ;
hold = - a.e[ jk ] ;
a.e[ jk ] = a.e[ ji ] ;
a.e[ ji ] = hold ;
}
}
// divide columns by minus pivot (value of pivot element is contained in biga)
if ( fabs ( biga ) < 1.0e-10 )FAILURE(getMessage(L"Singular Matrix - Inversion failure",GEOMETRY_ERROR_MESSAGES, -1)); // singular matrix
for ( i = 0 ; i < n ; i++ ) {
if ( i != k ) {
ik = nk + i ;
a.e[ ik ] = - a.e[ ik ] /biga ;
}
}
// reduce matrix
for ( i = 0 ; i < n ; i++ ) {
ik = nk + i ;
hold = a.e[ ik ] ;
ij = i - n ;
for ( j = 0 ; j < n ; j++ ) {
ij = ij + n ;
if ( i != k && j != k ) {
kj = ij - i + k ;
a.e[ ij ] = hold * a.e[ kj ] + a.e[ ij ] ;
}
}
}
// divide row by pivot
kj = k - n ;
for ( j = 0 ; j < n ; j++ ) {
kj = kj + n ;
if ( j != k ) a.e[ kj] = a.e[ kj ] /biga ;
}
// replace pivot by reciprocal
a.e[ kk ] = 1 / biga ;
}
// final row and column interchange
k = n - 1 ;
while ( k > 0 ) {
i = l[ --k ] ;
if ( i > k ) {
jq = n * k ;
jr = n * i ;
for ( j = 0 ; j < n ; j++ ) {
jk = jq + j ;
hold = a.e[jk] ;
ji = jr + j ;
a.e[jk] = - a.e[ji] ;
a.e[ji] = hold ;
}
}
j = m[ k ] ;
if ( j > k ) {
ki = k - n ;
for ( i = 1 ; i <= n ; i ++ ) {
ki = ki + n ;
hold = a.e[ ki ] ;
ji = ki - k + j ;
a.e[ ki ] = - a.e[ ji ] ;
a.e[ ji ] = hold ;
}
}
}
return a;
}
Matrix UnitMatrix; // a global unit matrix
ostream & operator<<(ostream &os, const Matrix &m)
{
os << "Matrix[";
for (int i = 0; i < 16; i++)
os << m.e[i] << ",";
return os << "]";
}
void Point3d::arbitrary_axes(Point3d& x, Point3d& y)const{
// arbitrary axis algorithm - acad method of generating an arbitrary but
// consistant set of axes from a single normal ( z )
// arbitrary x & y axes
if ( ( fabs ( this->x ) < 1.0/64.0 ) && (fabs(this->y) < 1.0/64.0))
x = Y_VECTOR ^ *this;
else
x = Z_VECTOR ^ *this;
x.normalise();
y = *this ^ x;
y.normalise();
}
void Plane::Mirrored(Matrix* tmMirrored) {
// calculates a mirror transformation that mirrors 2d about plane
//Point3d p1 = this->Near(Point3d(0.,0.,0.));
if(tmMirrored->m_unit == false) tmMirrored->Unit();
double nx = this->normal.x;
double ny = this->normal.y;
double nz = this->normal.z;
// the translation
tmMirrored->e[ 3] = -2. * nx * this->d;
tmMirrored->e[ 7] = -2. * ny * this->d;
tmMirrored->e[11] = -2. * nz * this->d;
// the rest
tmMirrored->e[ 0] = 1. - 2. * nx * nx;
tmMirrored->e[ 5] = 1. - 2. * ny * ny;
tmMirrored->e[10] = 1. - 2. * nz * nz;
tmMirrored->e[ 1] = tmMirrored->e[ 4] = -2. * nx * ny;
tmMirrored->e[ 2] = tmMirrored->e[ 8] = -2. * nz * nx;
tmMirrored->e[ 6] = tmMirrored->e[ 9] = -2. * ny * nz;
tmMirrored->m_unit = false;
tmMirrored->m_mirrored = true;
}
void Plane::Transform(const Matrix& m)
{
Point3d p = normal * d;
p = p.Transformed(m);
normal = normal.Transformed(m) - p;
normal.Normalize();
d = Point3d(0, 0, 0) * normal;
}
double Matrix::GetX()const{ return e[3]; }
double Matrix::GetY()const{ return e[7]; }
double Matrix::GetZ()const{ return e[11]; }
void Matrix::SetX(double value){ e[3] = value; }
void Matrix::SetY(double value){ e[7] = value; }
void Matrix::SetZ(double value){ e[11] = value; }
// code for AxesToAngles copied from http://tog.acm.org/GraphicsGems/gemsiv/euler_angle/EulerAngles.c
#define EulSafe "\000\001\002\000"
#define EulNext "\001\002\000\001"
#define EulGetOrd(ord,i,j,k,n,s,f) {unsigned o=ord;f=o&1;o>>=1;s=o&1;o>>=1;n=o&1;o>>=1;i=EulSafe[o&3];j=EulNext[i+n];k=EulNext[i+1-n];}
#define EulOrd(i,p,r,f) (((((((i)<<1)+(p))<<1)+(r))<<1)+(f))
#define EulOrdZXZs EulOrd(2,0,1,0)
//static
void Matrix::AxesToAngles(const Point3d &x, const Point3d &y, double &v_angle, double &h_angle, double &t_angle)
{
double M[4][4];
Matrix(Point3d(0, 0, 0), x, y).Get(M[0]);
int order = EulOrdZXZs;
int i,j,k,n,s,f;
EulGetOrd(order,i,j,k,n,s,f);
if (s==1) {
double sy = sqrt(M[i][j]*M[i][j] + M[i][k]*M[i][k]);
if (sy > 16 * 1.192092896e-07F) {
t_angle = atan2(M[i][j], M[i][k]);
v_angle = atan2(sy, M[i][i]);
h_angle = atan2(M[j][i], -M[k][i]);
} else {
t_angle = atan2(-M[j][k], M[j][j]);
v_angle = atan2(sy, M[i][i]);
h_angle = 0;
}
} else {
double cy = sqrt(M[i][i]*M[i][i] + M[j][i]*M[j][i]);
if (cy > 16 * 2.2204460492503131e-016) {
t_angle = atan2(M[k][j], M[k][k]);
v_angle = atan2(-M[k][i], cy);
h_angle = atan2(M[j][i], M[i][i]);
} else {
t_angle = atan2(-M[j][k], M[j][j]);
v_angle = atan2(-M[k][i], cy);
h_angle = 0;
}
}
if (n==1) {t_angle = -t_angle; v_angle = - v_angle; h_angle = -h_angle;}
if (f==1) {double t = t_angle; t_angle = h_angle; h_angle = t;}
}
//static
void Matrix::AnglesToAxes(const double &v_angle, const double
&h_angle, const double &t_angle, Point3d &x, Point3d &y)
{
#if 0
to do
Matrix zmat1;
zmat1.SetRotation(gp_Ax1(Point3d(0, 0, 0), Point3d(0, 0, 1)), t_angle);
Matrix xmat;
xmat.SetRotation(gp_Ax1(Point3d(0, 0, 0), Point3d(1, 0, 0)), v_angle);
Matrix zmat2;
zmat2.SetRotation(gp_Ax1(Point3d(0, 0, 0), Point3d(0, 0, 1)), h_angle);
Matrix mat = zmat2 * xmat * zmat1;
x = Point3d(1, 0, 0).Transformed(mat);
y = Point3d(0, 1, 0).Transformed(mat);
#endif
} c5721c306This file is pinned to the selected release. Download the original to open it in your design tool.