61阅读

matlab实现分段函数-实现opengl 中gluLookAt函数

发布时间:2018-04-27 所属栏目:软件教程

一 : 实现opengl 中gluLookAt函数

opengl Distilled 中介绍了view 坐标转换的原理,先列一下原著中的介绍:

The view transformation transforms vertices into eye coordinates and is the inverse of atransformation to place and orient the viewer in world coordinates. The view transformation hastwo components: a 4 x 4 orientation matrix, O, and a 4 x 4 translation matrix, T. The viewtransformation matrix, V, is the concatenation of the two 4 x 4 matrices:V = OTThe orientation matrix O is an orthonormal basis derived from the view direction and upvectors. Given an [ x y z ] view direction d and an [ x y z ] up vector u, compute their crossproduct c as:c = d x uDiscard u and compute the actual up vector u' as:u' = c x dNormalize d, c, and u' to unit length, and create the orientation matrix O as follows:



The translation matrix T is simply the inverse translation to the eye location. If you alreadyhave the eye location stored in your application, you can use it directly in a call to glTranslated(), as shown in the code below. If you don't have the eye location, scale the view directionvector by the distance to the eye, negate it, and add it to the center location. The result is the

eye location.So if an application creates a double-precision orientation matrix called orientMatrix using thesteps above and has the eye location stored in a double-precision [ x y z ] array called eye, thecode to create the view transformation isglMatrixMode( GL_MODELVIEW );glLoadMatrixd( orientMatrix );glTranslated( -eye[0], -eye[1], -eye[2] );In fact, gluLookAt() does essentially the same thing internally. It computes the view directionby subtracting eye from center and then follows the above method to create the orientationmatrix. For this reason, if your application already stores the center location, view direction,and view distance, gluLookAt() is slightly less efficient than creating the view transformation inyour application code.

下面我大体翻译一下:

视图坐标转换实际上就是把定点的坐标转换进眼睛(摄像机)坐标系中,这个操作与将眼睛转换到相应位置并设定朝向的操作相反。

来完成视图变换操作的矩阵V由两部分矩阵连乘形成的,一部分是朝向矩阵O,一部分是平移矩阵T,所以我们有:

V= OT;

朝向矩阵是由视线朝向D和眼睛的上方向U决定的,这两个方向向量叉乘得到向量C,向量C和向量D叉乘得到U‘,C,U,D(对应x,y,z),形成了眼睛坐标系的三个方向,它们属于右手坐标系,

相关的公式如下:

c = d x u,

u' = c x d,

将得到的三个变量相应的单位化,分别用这三个变量传到下面的矩阵中,就得到了转换需要的朝向矩阵O:



,注意向量d的各个分量都被取了原值的负值。

而平移矩阵,则是将眼睛移动操作的反操作,如果你有眼睛的位置,直接将眼睛的位置全取原值负值就OK了,否则可以用Center位置加一个向量就得到眼睛的位置了。

有了上面的处理后,后面的处理就很简单了,将矩阵加载的opengl中,根据眼睛的位置平移就OK了。代码如下:

glMatrixMode( GL_MODELVIEW );glLoadMatrixd( orientMatrix );glTranslated( -eye[0], -eye[1], -eye[2] );

实际上glLookAt做了一样的事情。

下面上我的代码:

[cpp] view plaincopy

classFVector3

{

public:

union

{

struct

{

GLdoubleX,Y,Z;

};

struct

{

GLdoublex,y,z;

};

GLdoublev[3];

};

public:

FVector3(){}

FVector3(GLdoublex1,GLdoubley1,GLdoublez1):x(x1),y(y1),z(z1)

{}

FVector3(constFVector3&InV);

FVector3operator^(constFVector3&V)const;

FVector3&Normalize();

};

inline

FVector3::FVector3(constFVector3&InV)

{

x=InV.x;

y=InV.y;

z=InV.z;

}

inlineGLdoubleappInvSqrt(GLdoublef){return1.f/sqrt(f);}

inlineFVector3&

FVector3::Normalize()

{

GLdoubleSquareSum=X*X+Y*Y+Z*Z;

if(SquareSum<0.000001)

return*this;

GLdoubleScale=appInvSqrt(SquareSum);

X*=Scale;

Y*=Scale;

Z*=Scale;

return*this;

}

inlineFVector3

FVector3::operator^(constFVector3&V)const

{

returnFVector3(Y*V.Z-Z*V.Y,Z*V.X-X*V.Z,X*V.Y-Y*V.X);

}

上面的是工具类,下面是实现函数:

[cpp] view plaincopy

staticvoidsuLookAt(GLdoubleeyeX,GLdoubleeyeY,GLdoubleeyeZ,GLdoublecenterX,GLdoublecenterY,GLdoublecenterZ,GLdoubleupX,GLdoubleupY,GLdoubleupZ)

{

GLdoubledirectMat[16];

for(inti=0;i<16;i++)

{

directMat[i]=0;

}

directMat[15]=1;

FVector3fvDirect(centerX-eyeX,centerY-eyeY,centerZ-eyeZ);

fvDirect.Normalize();

FVector3fvUpD(upX,upY,upZ);

fvUpD.Normalize();

FVector3fvC=fvDirect^fvUpD;

fvC.Normalize();

FVector3fvUp=fvC^fvDirect;

fvUp.Normalize();

fvDirect.x=-fvDirect.x;

fvDirect.y=-fvDirect.y;

fvDirect.z=-fvDirect.z;

directMat[0]=fvC.x;

directMat[4]=fvC.y;

directMat[8]=fvC.z;

directMat[1]=fvUp.x;

directMat[5]=fvUp.y;

directMat[9]=fvUp.z;

directMat[2]=fvDirect.x;

directMat[6]=fvDirect.y;

directMat[10]=fvDirect.z;

glLoadMatrixd(directMat);

glTranslated(-eyeX,-eyeY,-eyeZ);

}

调用方法跟gluLookAt一样

二 : 函数实现-aoti-atol

1. 函数原型

   int atoi ( const char * str );
   long int atol ( const char * str );

2. 函数工作

   atoi是将字符串转化为整型,atol是将字符串转化为长整型,这两个函数的实现十分相似。(www.61k.com]工作步骤基本如下:
  ·跳过若干空格、制表符等
  ·如果有正号或者负号,进行识别
  ·将数字整合到结果中,直到字符串遍历完毕或者遇到数字以外的其他字符为止。
   C库中的atoi会尽可能的把更多的数字整合到结果中,不能发现数值溢出的问题。而且对于“整数+其他字符”这样的字符串识别出其中的“整数”,并不考虑后面的字符串中有没有非法字符。比如"1234abc",atoi的结果是1234,而不会认为"1234abc"本身是非法的。
   本文给出的aoti实现会考虑到如下几个方面:
   如果没有一个数字被整合到字符串中,抛出异常“没有数字存在”。
   如果数值溢出,抛出异常,“数值溢出”。
    对于"1234abc"这样的数字,保留原有atoi的处理形式,也识别出1234。

3. 函数设计

    为了更好的展示思路,这里我给出一个基于状态机的aoti实现。   

#include<iostream>
using namespace std;

int my_atoi(const char *str) {
  if(str == NULL)
    throw "str == NULL!";
  enum STATE {STATE_SKIP_SPACE, STATE_RECOGNIZE_SIGN, STATE_RECOGNIZE_NUM,
    STATE_RECOGNIZE_LAST_NUM, STATE_RECOGNIZE_TAIL_CHAR};
  STATE state = STATE_SKIP_SPACE;
  int max = INT_MAX;
  int min = INT_MIN;
  int bound = max / 10;
  int sign = 1;
  unsigned int result = 0;
  bool find_num = false;
  while(true) {
    switch(state) {
      case STATE_SKIP_SPACE: // 跳过尽可能多的空格
        if(*str==' '||*str=='\t'||*str=='\n'||*str=='\f'||*str=='\b'||*str=='\r')
          str++;
        else 
          state = STATE_RECOGNIZE_SIGN;
        break;
      case STATE_RECOGNIZE_SIGN: // 识别可能的正负符号
        if(*str == '-') {
          str++;
          sign = -1;          
        }
        else if(*str == '+') {
          str++;
        }
        state = STATE_RECOGNIZE_NUM;
        break;
      case STATE_RECOGNIZE_NUM: // 最多识别max/10的位数的数字 
        if(*str <'0' || *str>'9' || *str=='\0') // 当前字符不是数字,或者已经结束 
          if(find_num == false) // 一个数字都还没遇到过 
            throw  "no num found!";
          else  // 已经遇到过数字了 
            return result * sign;
        else { // 当前字符是数字 
          if(find_num == false)
            find_num = true;  
          result *= 10;
          result += (*str-'0');
          bound /= 10;
          if(bound ==0) {
            state = STATE_RECOGNIZE_LAST_NUM;
          }
          str++;
        }
        break;
      case STATE_RECOGNIZE_LAST_NUM: // 识别最后一个数字
        if(*str <'0' || *str>'9' || *str=='\0') // 当前字符不是数字,或者已经结束 
          return result * sign; // 能到这一步,肯定是已经遇到了很多数字 
        else { // 当前字符是数字
          if((result > max/10) || (sign==1 && (*str-'0')>(max%10)) || (sign==-1 && (*str-'0')>abs(min%10))) {
            throw "over num limit !";
          }
          else {
            result *= 10;
            result += (*str - '0');
            state = STATE_RECOGNIZE_TAIL_CHAR;
            str++;
          }
        }
        break;
      case STATE_RECOGNIZE_TAIL_CHAR: // 不能再识别数字了
        if(*str <'0' || *str>'9' || *str=='\0') // 当前字符不是数字,或者已经结束
          return result * sign;
        else // 当前字符是数字,此时必然溢出 
          throw "over num limit !";
        break;
      default:
        break;
    }
  }
  return 0;
}

int main() {
  char* a = "        +123213123abc";
  char* max = "     2147483647abc";
  char* min = "     -2147483648abc";
  char* max_more_1 = "     2999999997abc";
  char* max_more_2 = "     2147483648abc";
  char* min_more_1 = "     -2147483649abc";
  cout << a << ":  " << my_atoi(a) << endl;
  cout << max << ":  " << my_atoi(max) << endl;
  cout << min << ":  " << my_atoi(min) << endl; 
  try {
    cout << max_more_1 << ":  ";
    my_atoi(max_more_1);
  }
  catch (const char* info){
    cout << info << endl;
  }
  try {
    cout << max_more_2 << ":  ";
    my_atoi(max_more_2);
  }
  catch (const char* info){
    cout << info << endl;
  }
  try {
    cout << min_more_1 << ":  ";
    my_atoi(min_more_1);
  }
  catch (const char* info){
    cout << info << endl;
  }
  char wait;
  cin >> wait;
  return 0;
}

   long int 的转化与int的转化差不多。

4. 参考资料
    C++ Reference atoi   http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ 
    C/C++常见面试题(30)----atoi函数   http://blog.csdn.net/lzueclipse/archive/2011/05/26/6446945.aspx
   程序员面试题精选---“itoa函数”和“atoi函数   http://blog.csdn.net/zhangxinrun/archive/2010/12/01/6048695.aspx
   atoi的实现,一道对数值边界考察的题目   
   C库函数atoi的实现和一些讨论_c/c++_电脑编程网   http://blog.csdn.net/udknight/archive/2007/10/22/1836799.aspx   

三 : Matlab如何实现函数重载?Matlab实现函数重载的方法

大家应该都知道C++和Java编程能够实现函数的重载,而当我们使用Matlab的一些函数,如:plot函数,可以发现该函数可以有不同的输入,如:plot(data)、plot(t,data)和plot(X,Y,'LineWidth',2)等。这些就是matlab函数重载的应用。

软件名称:
数学软件Matlab R2016a 64位 完全破解版(附破解文件+密钥+安装教程)
软件大小:
7.6GB
更新时间:
2016-11-23

软件名称:
Matlab(商业数学软件) v7.0正式版(附序列号及安装教程)
软件大小:
968.92MB
更新时间:
2014-05-14

下面我就通过一个简单的输出输入数中的最大数的函数fun()来说明Matlab在编辑函数时如何实现重载。

方法/步骤:

1.首先打开Matlab(本人使用的是Matlab 2015a,使用其他版本的Matlab影响不大)。在Common Window里输入edit fun(fun可改为任意字符,只为演示用),打开M文件编辑器,此时已创建M文件,文件名为fun。

2.在编辑器内输入 function y=fun(varargin),varargin是Matlab内部变量,类型为元胞数组,如果改为其他变量则会报错。

3.添加代码 narginchk(2,3); 保证输入量的个数,当个数小于2或大于3时程序会报错。

4.Matlab内部有一个nargin变量用于存储函数中输入量的个数。下面用If语句来实现函数的重载。

输入

if nargin==2

a=varargin{1};

b=varargin{2};

y=max([a,b]);

...

通过这段代码,函数可实现输入两个量时的功能。

其中用a来存放输入量的第一个量,用b来存放输入量的第二个量。max()函数返回输入矩阵的最大元素。

5.再输入

elseif nargin==3

a=varargin{1};

b=varargin{2};

c=varargin{3};

y=max([a,b,c]);

end

通过这段代码,函数可实现输入两个量时的功能。

其中用a来存放输入量的第一个量,用b来存放输入量的第二个量,用c来存放输入量的第三个量。

效果如下图

6.保存之后,下面对所编辑的函数进行验证。

Command Window 中分别输入

answer1=fun(12,13,14)

answer2=fun(16,25)

answer3=fun(16)

answer4=fun(12,13,14,15)

结果如下图

7.准确的讲,matlab函数的重载并不是严格意义上的函数重载,但是通过对变量的合理运用,能够实现重载的功能。

希望这一条经验能够帮助到大家!

注意事项

编辑函数是输入变量一定得是varargin,否则Matlab会将输入变量视为一个。

if语句一定要加end

本文标题:matlab实现分段函数-实现opengl 中gluLookAt函数
本文地址: http://www.61k.com/1164992.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1