|
|
发表于 2007-1-22 23:29:00
|
显示全部楼层
Re:矩阵求逆函数实现,继续扫盲
我的这个有更多的函数........包括求逆........
//CGraphicX.h
#ifndef CGRAPHICX_H
#define CGRAPHICX_H
//定义实用结构和计算类
#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
#ifndef NULL
#define NULL 0
#endif
//3*3矩阵,是2维齐次坐标系
typedef struct Matrix_2_2
{
Matrix_2_2();
float mat[3][3];
const Matrix_2_2 operator*(const Matrix_2_2& opMat);
} Matrix_2_2;
typedef struct GVertex
{
float x,y,z;
GVertex();
//顶点与矩阵乘法
const GVertex operator*(const Matrix_2_2& opMat);
}GVertex;
typedef struct FRect
{
FRect():left(0),top(0),right(0),bottom(0){}
float left,top,right,bottom;
}FRect;
class CGraphicX
{
public:
//单位矩阵
static void MatrixIdentility(Matrix_2_2 *op);
//矩阵乘法
static void MatrixMul(Matrix_2_2 *op1,Matrix_2_2 *op2,Matrix_2_2 *result);
//求逆
static void MatrixOther(Matrix_2_2 *op,Matrix_2_2 *result);
//求位移
static void MatrixTrans(Matrix_2_2 *result,float x,float y);
//求旋转
static void MatrixRotate(Matrix_2_2 *result,float rad);
//求缩放
static void MatrixScale(Matrix_2_2 *result,float x,float y);
//错切变换
static void MatrixTiltedX(Matrix_2_2 *result,float c);
static void MatrixTiltedY(Matrix_2_2 *result,float c);
//设置视矩阵
static void MatrixView(Matrix_2_2 *result,int width,int height,int left,int top,int right,int bottom);
static int Clip_Line(int &x1,int &y1,int &x2, int &y2,FRect *pRect);
private:
//求2*2矩阵行列式
static float MatrixValue(float a1,float a2,float a3,float a4);
//求3*3矩阵行列式
static float MatrixValue_2_2(Matrix_2_2 *op);
};
#endif
#include "CGraphicX.h"
#include <math.h>
int CGraphicX::Clip_Line(int &x1,int &y1,int &x2,int &y2,FRect *pRect)
{
// this function clips the sent line using the globally defined clipping
// region
// internal clipping codes
#define CLIP_CODE_C 0x0000
#define CLIP_CODE_N 0x0008
#define CLIP_CODE_S 0x0004
#define CLIP_CODE_E 0x0002
#define CLIP_CODE_W 0x0001
#define CLIP_CODE_NE 0x000a
#define CLIP_CODE_SE 0x0006
#define CLIP_CODE_NW 0x0009
#define CLIP_CODE_SW 0x0005
int xc1=x1,
yc1=y1,
xc2=x2,
yc2=y2;
int p1_code=0,
p2_code=0;
int min_clip_y;
int max_clip_y;
int min_clip_x;
int max_clip_x;
if(pRect->top<pRect->bottom)
{
min_clip_y=(int)(pRect->top);
max_clip_y=(int)(pRect->bottom);
}
else
{
max_clip_y=(int)(pRect->top);
min_clip_y=(int)(pRect->bottom);
}
if(pRect->left<pRect->right)
{
min_clip_x=(int)(pRect->left);
max_clip_x=(int)(pRect->right);
}
else
{
max_clip_x=(int)(pRect->left);
min_clip_x=(int)(pRect->right);
}
// determine codes for p1 and p2
if (y1 < min_clip_y)
p1_code|=CLIP_CODE_N;
else
if (y1 > max_clip_y)
p1_code|=CLIP_CODE_S;
if (x1 < min_clip_x)
p1_code|=CLIP_CODE_W;
else
if (x1 > max_clip_x)
p1_code|=CLIP_CODE_E;
if (y2 < min_clip_y)
p2_code|=CLIP_CODE_N;
else
if (y2 > max_clip_y)
p2_code|=CLIP_CODE_S;
if (x2 < min_clip_x)
p2_code|=CLIP_CODE_W;
else
if (x2 > max_clip_x)
p2_code|=CLIP_CODE_E;
// try and trivially reject
if ((p1_code & p2_code))
return(0);
// test for totally visible, if so leave points untouched
if (p1_code==0 && p2_code==0)
return(1);
// determine end clip point for p1
switch(p1_code)
{
case CLIP_CODE_C: break;
case CLIP_CODE_N:
{
yc1 = min_clip_y;
xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
} break;
case CLIP_CODE_S:
{
yc1 = max_clip_y;
xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
} break;
case CLIP_CODE_W:
{
xc1 = min_clip_x;
yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
} break;
case CLIP_CODE_E:
{
xc1 = max_clip_x;
yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
} break;
// these cases are more complex, must compute 2 intersections
case CLIP_CODE_NE:
{
// north hline intersection
yc1 = min_clip_y;
xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
// east vline intersection
xc1 = max_clip_x;
yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if
} break;
case CLIP_CODE_SE:
{
// south hline intersection
yc1 = max_clip_y;
xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
// east vline intersection
xc1 = max_clip_x;
yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if
} break;
case CLIP_CODE_NW:
{
// north hline intersection
yc1 = min_clip_y;
xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
xc1 = min_clip_x;
yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if
} break;
case CLIP_CODE_SW:
{
// south hline intersection
yc1 = max_clip_y;
xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
xc1 = min_clip_x;
yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if
} break;
default:break;
} // end switch
// determine clip point for p2
switch(p2_code)
{
case CLIP_CODE_C: break;
case CLIP_CODE_N:
{
yc2 = min_clip_y;
xc2 = x2 + (min_clip_y-y2)*(x1-x2)/(y1-y2);
} break;
case CLIP_CODE_S:
{
yc2 = max_clip_y;
xc2 = x2 + (max_clip_y-y2)*(x1-x2)/(y1-y2);
} break;
case CLIP_CODE_W:
{
xc2 = min_clip_x;
yc2 = y2 + (min_clip_x-x2)*(y1-y2)/(x1-x2);
} break;
case CLIP_CODE_E:
{
xc2 = max_clip_x;
yc2 = y2 + (max_clip_x-x2)*(y1-y2)/(x1-x2);
} break;
// these cases are more complex, must compute 2 intersections
case CLIP_CODE_NE:
{
// north hline intersection
yc2 = min_clip_y;
xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
// east vline intersection
xc2 = max_clip_x;
yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if
} break;
case CLIP_CODE_SE:
{
// south hline intersection
yc2 = max_clip_y;
xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);
// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
// east vline intersection
xc2 = max_clip_x;
yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if
} break;
case CLIP_CODE_NW:
{
// north hline intersection
yc2 = min_clip_y;
xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
xc2 = min_clip_x;
yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if
} break;
case CLIP_CODE_SW:
{
// south hline intersection
yc2 = max_clip_y;
xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);
// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
xc2 = min_clip_x;
yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if
} break;
default:break;
} // end switch
// do bounds check
if ((xc1 < min_clip_x) || (xc1 > max_clip_x) ||
(yc1 < min_clip_y) || (yc1 > max_clip_y) ||
(xc2 < min_clip_x) || (xc2 > max_clip_x) ||
(yc2 < min_clip_y) || (yc2 > max_clip_y) )
{
return(0);
} // end if
// store vars back
x1 = xc1;
y1 = yc1;
x2 = xc2;
y2 = yc2;
return(1);
} // end Clip_Line
Matrix_2_2::Matrix_2_2()
{
int i,j;
for(i=0;i<3;++i)
for(j=0;j<3;++j)
mat[j]=0.0f;
}
const Matrix_2_2 Matrix_2_2: perator *(const Matrix_2_2 &opMat)
{
Matrix_2_2 tmpMat;
int i,j,k;
for(i=0;i<3;++i)
for(j=0;j<3;++j)
for(k=0;k<3;++k)
{
tmpMat.mat[j]+=(this->mat[k])*(opMat.mat[k][j]);
}
return tmpMat;
}
const GVertex GVertex::operator*(const Matrix_2_2& opMat)
{
GVertex tmpVertex;
tmpVertex.x=x*opMat.mat[0][0]+y*opMat.mat[1][0]+z*opMat.mat[2][0];
tmpVertex.y=x*opMat.mat[0][1]+y*opMat.mat[1][1]+z*opMat.mat[2][1];
tmpVertex.z=x*opMat.mat[0][2]+y*opMat.mat[1][2]+z*opMat.mat[2][2];
return tmpVertex;
}
GVertex::GVertex()
{
x=y=z=0.0f;
}
float CGraphicX::MatrixValue(float a1, float a2, float a3, float a4)
{
return a1*a4-a2*a3;
}
float CGraphicX::MatrixValue_2_2(Matrix_2_2 *op)
{
return (op->mat[0][0])*(op->mat[1][1])*(op->mat[2][2])+
(op->mat[0][1])*(op->mat[1][2])*(op->mat[2][0])+
(op->mat[0][2])*(op->mat[1][0])*(op->mat[2][1])-
(op->mat[0][0])*(op->mat[1][2])*(op->mat[2][1])-
(op->mat[0][1])*(op->mat[1][0])*(op->mat[2][2])-
(op->mat[0][2])*(op->mat[1][1])*(op->mat[2][0]);
}
void CGraphicX::MatrixOther(Matrix_2_2 *op, Matrix_2_2 *result)
{
Matrix_2_2 a;
float sa=MatrixValue_2_2(op);
if(op==0)
{
result=0;
return;
}
sa=1.0f/sa;
a.mat[0][0]=sa*MatrixValue(op->mat[1][1],op->mat[1][2],op->mat[2][1],op->mat[2][2]);
a.mat[1][0]=(-1.0f)*sa*MatrixValue(op->mat[1][0],op->mat[1][2],op->mat[2][0],op->mat[2][2]);
a.mat[2][0]=sa*MatrixValue(op->mat[1][0],op->mat[1][1],op->mat[2][0],op->mat[2][1]);
a.mat[0][1]=(-1.0f)*sa*MatrixValue(op->mat[0][1],op->mat[0][2],op->mat[2][1],op->mat[2][2]);
a.mat[1][1]=sa*MatrixValue(op->mat[0][0],op->mat[0][2],op->mat[2][0],op->mat[2][2]);
a.mat[2][1]=(-1.0f)*sa*MatrixValue(op->mat[0][0],op->mat[0][1],op->mat[2][0],op->mat[2][1]);
a.mat[0][2]=sa*MatrixValue(op->mat[0][1],op->mat[0][2],op->mat[1][1],op->mat[1][2]);
a.mat[1][2]=(-1.0f)*sa*MatrixValue(op->mat[0][0],op->mat[0][2],op->mat[1][0],op->mat[1][2]);
a.mat[2][2]=sa*MatrixValue(op->mat[0][0],op->mat[0][1],op->mat[1][0],op->mat[1][1]);
*result=a;
}
void CGraphicX::MatrixIdentility(Matrix_2_2 *op)
{
for(int i=0;i<3;++i)
{
op->mat[0]=0.0f;
op->mat[1]=0.0f;
op->mat[2]=0.0f;
op->mat=1.0f;
}
}
void CGraphicX::MatrixMul(Matrix_2_2 *op1, Matrix_2_2 *op2, Matrix_2_2 *result)
{
Matrix_2_2 tmpMat;
int i,j,k;
for(i=0;i<3;++i)
for(j=0;j<3;++j)
for(k=0;k<3;++k)
{
tmpMat.mat[j]+=(op1->mat[k])*(op2->mat[k][j]);
}
*result=tmpMat;
}
void CGraphicX::MatrixTrans(Matrix_2_2 *result, float x, float y)
{
MatrixIdentility(result);
result->mat[2][0]=x;
result->mat[2][1]=y;
}
void CGraphicX::MatrixRotate(Matrix_2_2 *result,float rad)
{
MatrixIdentility(result);
result->mat[0][0]=cosf(rad);
result->mat[0][1]=sinf(rad);
result->mat[1][0]=(-1)*sinf(rad);
result->mat[1][1]=cosf(rad);
}
void CGraphicX::MatrixScale(Matrix_2_2 *result, float x, float y)
{
MatrixIdentility(result);
result->mat[0][0]=x;
result->mat[1][1]=y;
}
void CGraphicX::MatrixTiltedX(Matrix_2_2 *result, float c)
{
MatrixIdentility(result);
result->mat[1][0]=c;
}
void CGraphicX::MatrixTiltedY(Matrix_2_2 *result, float c)
{
MatrixIdentility(result);
result->mat[0][1]=c;
}
void CGraphicX::MatrixView(Matrix_2_2 *result,int width, int height, int left, int top, int right, int bottom)
{
if(left<0)
left=0;
if(top<0)
top=0;
if(right<0)
right=0;
if(bottom<0)
bottom=0;
if(left>=width)
left=width-1;
if(top>=height)
top=height-1;
if(right>=width)
right=width-1;
if(bottom>=height)
bottom=height-1;
Matrix_2_2 matScale;
Matrix_2_2 matTrans;
float xScale=((float)right-(float)left)/(float)width;
float yScale=((float)bottom-(float)top)/(float)height;
MatrixScale(&matScale,xScale,yScale);
MatrixTrans(&matTrans,(float)left,(float)top);
*result=matScale*matTrans;
} |
|