preface:
2010年11月开始跟师兄做图形学的研究。开始看图形学,看数值逼近,看微分几何。
1.数值逼近可以用matlab来做实验。
2.微分几何太抽象了,可以用matlab来画出图形看看。
3.正好师兄推荐用matlab先做些简单的图形实验。
所以这两天就用了下matlab, 下面记录一些个人认为比较有用的心得。
注释:%
块注释:
%{
注释语句(注意,'%{' 行后面与 '%}'行前面 都不能有其他字符)
%}
连接符: ...
如果一个语句在一行内书写太长了,要再下一行接着写,这时可以在上一行末尾打上半个省略号(...),然后再在下一行接着写。
比如,下面俩个语句是等价的:
x1 = 1 + 1/2 + 1/3 + 1/4 + 1/5 + 1/6;
和 x1 = 1 + 1/2 + 1/3 +...
1/4 + 1/5 + 1/6;
1.构造矩阵(数组)
x = [1 2 3]
x = [1 2 3; 4 5 6]
x = linspace(1,50) %创建100个(默认)元素的行向量,元素值依次从1~50
x = linspace(0,0,5) %创建5个元素都是0的行向量
x = [0:2:100] 或 x = 0:2:100
x = zeros(m,n) %创建m*n的全0矩阵
y = x(1:3 , 2:5) %y矩阵为取x矩阵的1~3行,2~5列的数据
y = x(:, 1:3) %y矩阵为取x矩阵1~3列的数据
2.矩阵运算
A*B 即矩阵乘法
A.*B 即矩阵对应元素相乘 (相应的,还有./等运算)
A' 即矩阵转置
inv(A) 即矩阵求逆
det(A) 即求方阵行列式
rank(A)即求矩阵的秩
3.参数曲线绘制 r(t)=(x(t), y(t), z(t))
eg:
%绘制螺旋线 r(t)=(cos(t), sin(t), t) t=0:0.1:30; x = cos(t); y = sin(t); z = t; plot3(x,y,z); grid on; title('螺旋线'); xlabel('x'); ylabel('y'); zlabel('z');
4.参数曲面的绘制 z = f(x,y) 和 r(u,v) = (x(u,v), y(u,v), z(u,v))
eg:
%d z = f(x,y) 显式表达式 %d 绘制椭圆抛物面:z = x^2 + y^2 [x,y]=meshgrid(-2:0.2:2,-2:0.2:2); z=x.^2 + y.^2; surf(x,y,z); title('椭圆抛物面') xlabel('x'); ylabel('y'); zlabel('z');
==================================
%d r(u,v) = (x(u,v), y(u,v), z(u,v)) 参数表达式 %d 绘制螺旋面:r(u,v) = (u*cos(v), u*sin(v), v) u=linspace(0,pi,30); v=linspace(0,3*pi,30); [U,V]=meshgrid(u,v); x = U.*cos(V); y = U.*sin(V); z = V; mesh(x,y,z); title('螺旋面'); xlabel('x'); ylabel('y');
5.关于 mesh 与 meshgrid (surf与mesh本质一样)
首先,mesh只能画四边形网格(要想画三角形网格、或者其他多边形网格,就得自己用plot3等等其他或一个叫patch的函数来画了)
其次,这是对help的补充,你还是先看看matlab的help文档吧。
meshgrid
用法:[X,Y]=meshgrid(x,y); [X,Y]=meshgrid(x); [X,Y,Z]=meshgrid(x,y,z);
最后一种暂时没用到,不管他;
第二种 [X,Y]=meshgrid(x) == meshgrid(x,x);
所以我们来了解第一种 [X,Y]=meshgrid(x,y);
该函数的作用是,将向量 x=[x1, x2, ... xn] 与 y=[y1, y2, ... ym] 转换成m*n的矩阵X,Y
其中,X的每行都是x, Y的每列都是y
即:
x1 x2 ... xn y1 y1 ...
X[m*n] = x1 x2 ... xn 与 Y[m*n]= y2 y2 ...
... ...
x1 x2 ... xn ym ym ...
这样的效果,等于在笛卡尔坐标中将XY平面用x,y网格化了。
然后只要再对应上每个 XY平面网格交点 对应的Z值,就能画出空间上的曲面网格了。
mesh
用法:mesh(X,Y,Z); mesh(x,y,Z); mesh(Z). 其中X Y Z都是m*n矩阵; x是n维向量,y是m维向量。
实际上, mesh(Z) = mesh(1:n, 1:m, Z);
mesh(x,y,Z) = [X,Y]=meshgrid(x,y) + mesh(X,Y,Z);
至于 mesh(X,Y,Z),
其实如上所述,就是先通过X,Y将笛卡尔坐标的XY平面网格化,然后对应上每个交点的Z轴值,就得到我们要的网格曲面了。
PS:如果X,Y是从meshgrid得到的,那么XY平面网格就是一个个矩形的网格。
但X,Y不一定都想meshgrid得到的一样,X的每行都是x,Y的每列都是y。 这时候,XY平面网格就未必是一个个矩形了,但当然仍是四边形。(通常,像4中参数表达书获得的XY就这样。)
6. 数据的保存与读取(save & load)
save:将工作空间的所有变数储存到名为matlab.mat的二进制档案。
save filename:将工作空间的所有变数储存到名为filename.mat的二进制档案。
save filename x y z :将变数x、y、z储存到名为filename.mat的二进制档案。
以二进制的方式储存变数,通常档案会比较小,而且在载入时速度较快,但是就无法用普通的文书软体(例如pe2或记事本)看到档案内容。若想看到档案内容,则必须加上-ascii选项。若非有特殊需要,我们应该尽量以二进制方式储存资料。
save filename x -ascii:将变数x存到名为filename的ASCII档案。
save filename -ascii:将所有变量存到名为filename的ASCII档案。但ascii文档无法区别各个变量。
=======================
load filename:load会寻找名称为filename.mat的档案,并以二进制格式载入。若找不到filename.mat,则寻找名称为filename的档案,并以ASCII格式载入。若以ASCII格式载入,则变数名称即为档案名称。
load filename -ascii:load会寻找名称为filename的档案,并以ASCII格式载入。
7. 用patch绘制
patch图形对象是由一个或多个多边形(连接或不连接的)组成的。patchs在真实物体的建模中非常有用,比如飞机,汽车的建模。它还能绘制任意形状的二维三维多边形。
相比之下,surface对象是由四边形网格组成的,更适合于显示平滑的图形,比如绘制数学上的二元函数值的图形。
patch的用法参考help。
这里贴一个Defining a Cube的例子。
一个立方体有8个顶点、6个面。如下图所示:
1. 如果我们将x、y、z坐标参数定义为行向量形式。
那么不幸的是,他们将会被简单地识别成由每个顶点直接连接起来的单个“多边形。”
X = [0 1 1 0 0 0 1 1]
Y = [0 0 1 1 1 0 0 1]
Z = [0 0 0 0 1 1 1 1]
patch(X,Y,Z,’y’);
2.如果x、y、z坐标参数 是由矩阵[m*n]表示的话,MATLAB用三个矩阵对应的每列绘制一个多边形face(每个face可以由m个点),然后通过着n列的n个faces组成一个patch。这些faces可以不是连接的,并且可以自交叉。
因为立方体有六个面,每个面四个点。所以这时x、y、z坐标矩阵为4*6; 每一列代表一个face。如下图所示:
从上面我们可以注意到,一个立方体其实只需要8个顶点,但是用这种方法却需要4*6=24个顶点来定义,消耗太大。所以我们引入Vertices 和 Faces属性。
3. Specifying Faces and Vertices。如下图所示:
使用这种方法能大量降低消耗,尤其当patches有大量的faces的时候。这种方法要求用户调用更正式的patch函数定义Vertices和Faces属性,比如:
patch('Vertices',vertex_matrix,'Faces',faces_matrix)
因为这种语法不会自动定义face与edge的颜色,所以用户需要调用set函数来设置这些颜色属性,如果不想使用默认的白色face和黑色edge的话。
Reamark
l 如果坐标参数未能定义一个闭合的多边形,patch能自动闭合该多边形。
l MATLAB并不要求每个面都有相同的顶点数。如果当有些faces的顶点数与其他不同时候,将这些顶点数较少的faces用NaN填充成一样多的顶点数即可。
8. 可变长参数的函数
参见help中的 varargin, varargout 和 nargin, nargout
9. GUI中的交互
鼠标交互:
对于菜单对象,鼠标操作可以激活菜单的callback属性;
对于控件对象,鼠标操作可以激活控件对象的callback属性与ButtondownFcn属性;
对于图形窗口对象,鼠标操作可以激活图形窗口的ButtondownFcn属性、WindowButtondownFcn属性、WindowButtonmotionFcn属性和WindowButtonupFcn属性。
获取鼠标位置:
get(gca, 'currentpoint')
一个用鼠标画线的例子:
function interplot %funway:这事一个画橡皮线的实例程序。里面有交互信息。 global istep %记录鼠标点击数。(1画线头,2画线尾然后清0) global xdata global ydata istep = 0; set(gcf, 'pointer', 'cross'); set(gcf, 'WindowButtonDownFcn', @WindowButtonDown); set(gcf, 'WindowButtonMotionFcn', @WindowButtonMotion); function WindowButtonDown(hObject, eventdata, handles) global istep global xdata global ydata global h istep = istep + 1; p = get(gca, 'currentpoint'); %获取当前坐标系上的currentpoint属性,gca获得当前坐标系句柄 disp('CLICK! gca currentpoint:'); disp(p); if(istep == 1) xdata(1) = p(1,1); ydata(1) = p(1,2); xdata(2) = p(1,1); ydata(2) = p(1,2); h = line(xdata,ydata, 'EraseMode', 'xor'); elseif(istep == 2) xdata(2) = p(1,1); ydata(2) = p(1,2); set(h, 'XData', xdata, 'YData',ydata, 'EraseMode', 'normal'); istep = 0; end function WindowButtonMotion(hObject, eventdata, handles) global istep global xdata global ydata global h p = get(gca, 'currentpoint'); disp('MOVE! gca currentpoint:'); disp(p); if(istep ==1) xdata(2)=p(1,1); ydata(2)=p(1,2); set(h, 'XData',xdata, 'YData',ydata); end
10. 关于对象句柄
10.1 句柄图形对象的层次结构
10.2 每个控件对象都有一个句柄(即ID)
gcf 获得当前figure句柄(当前窗口) ( = get(0, ‘CurrentFigure’) )
gca 获得当前坐标轴的句柄 ( = get(gcf, ‘CurrentAxes’) )
gco 获得当前控件句柄 ( = get(gca, ‘CurrentObject’) )
get(handle) 获取句柄对象的各个属性
set(handle) 设置句柄对象的各个属性
findobj 函数通过属性值来查找对象 (eg: text_handle = findobj(‘String’, ‘xxx’) )
copyobj 函数用来复制对象
delete 函数可以用来删除对象 (eg: delete(gca) )
10.3 句柄对象的Callback属性
对象的callback属性通常指向一个函数(称为回调函数)。用作句柄对象的回调函数的function必须至少定义两个输入参数,一个是触发该回调函数的对象句柄,一个是触发事件数据结构。不论什么时候执行callback,matlab都会传递这两个变量。 例如:
function myGui
set(gcf, ‘WindowButtonDownFcn’, @myCallback);
%@格式为函数句柄(类似C中的函数指针)
function myCallback(obj, eventdata)
当然,回调函数还能添加其他参数。例如 function myCallback(obj, eventdata, arg1, arg2)
要想使用其他参数,有如下两种办法:
1.将对象句柄的callbak属性值设置为单元数组。 例如
figure(‘WindowButtonDownFcn’, {@myCallback, arg1, arg2} )
2.通过guidata() 来传递其他参数。 例如
function myCallback(obj, eventdata, handles)
handles = guidata(obj);
通过GUIDE设置的默认的回调函数通常为如下格式:
XXX_Callback(hObject, eventdata, handles)
hObject 为触发该函数的控件的句柄
eventdata 保留,为以后版本使用
handles 通常包括所有的控件句柄,还可以用来存储传递用户自定义的数据。
(注意:自动设置的回调函数已经默认通过guidata(hObject)传递handles参数了,你可以在调试中get查看。但是如果是自定义的回调函数。就必须通过上面说的两种方法传递)
11. Mechanisms for Managing Data
11.1 guidata