Matlab的面向对象编程逻辑更为清晰,当面向过程的程序较为复杂时,最好将其改写为面向对象的。这样能大大增强代码可读性,逻辑性也好理解。
Matlab的面向对象跟C++大体一致,但还是有一点小的不同,初学起来可能会有些坑。这里稍微讲一下。
类的写法:
classdef ClassName
properties
end
% 受保护 继承序列可访问
properties (Access = protected)
end
% 常数不可更改
properties (Constant)
end
% 通过计算得到的
properties (Dependent)
end
methods
% 构造函数
function newobj = GeoPL(name,type,x0,y0,x1,y1)
end
end
methods (Access = protected)
end
end
其中,类也写为两个区域,1个是属性区,1个是方法区。属性区什么限制也不加就是公有的,可以继承,加了protected就是保护性继承,加了depedent就是依赖,需要用get函数建立约束。
值得注意的是,get函数是自动执行的,我感觉不太好使,因此放弃了这种写法。
此外,貌似类文件只能单独写成文件,而且类名和文件名必须相同,还不能在类文件里写别的事儿,或者把类写到script中,不知道是不是这样?
类写完之后,放到同一个文件夹下,或者设置工作路径,否则就可能无法调用
二维点是单纯的几何点,只有x和y两个属性,可以通过构造函数定义。
classdef Point2D
%POINT2D 二维点
% Detailed explanation goes here
properties
x
y
end
methods
% 构造函数
function obj = Point2D(x,y)
if (nargin==0)
obj.x = nan;
obj.y = nan;
elseif (nargin==1)
obj.x = nan;
obj.y = nan;
elseif (nargin==2)
obj.x = x;
obj.y = y;
end
end
end
end
地理点是继承于二维点,有x和y两个属性和nam属性,可以通过构造函数定义。同时也考虑了用角度和长度来延伸定义。注意:这里的角度和长度并不是地理点对象的属性,而是外部获取的。
classdef GeoPoint < Point2D
%GEOPIONT 点对象
% Detailed explanation goes here
properties
name
end
methods
% 构造函数
function obj = GeoPoint(name,x,y)
if (nargin==0)
name = '';
x = nan;
y = nan;
elseif (nargin==1)
x = nan;
y = nan;
elseif (nargin==2)
x = nan;
y = nan;
end
obj = obj@Point2D(x,y);
obj.name = name;
end
% 角度,距离新建点对象
function new_obj = NewByDeg(obj,name,deg,len)
new_obj = GeoPoint(name);
new_obj.x = obj.x+len*cosd(deg);
new_obj.y = obj.y+len*sind(deg);
end
% 重载绘图函数
function h = plot(obj,style)
x = obj.x;
y = obj.y;
if(nargin==1)
h = plot(x,y,'o');
elseif(nargin==2)
h = plot(x,y,style);
end
end
% 重载信息打印
function disp(obj)
fprintf('%s, x=%.2f, y=%.2f\n',obj.name,obj.x,obj.y);
end
end
end
在方法中,实现了plot和disp的重载,方便查看信息。
地理线的概念要复杂一些,包括名称,起始点,终止点,角度,长度,点距,点数,元素数组。
其中元素数组占用空间开销稍大,一般情况下可空着。前面几个属性也是相互咬合的关系,在新建对象是,要考虑到约束关系。
classdef GeoLine
%GEOLINE Summary of this class goes here
% Detailed explanation goes here
properties
name
head
tail
deg
len
space
num
items
end
methods
% 构造函数
function obj = GeoLine(name,head,tail,deg,len,space,num)
if (nargin==0)
obj.name = '';
obj.head = GeoPoint;
obj.tail = GeoPoint;
obj.deg = nan;
obj.len = nan;
obj.space = nan;
obj.num = nan;
elseif (nargin==1)
obj.name = name;
obj.head = GeoPoint;
obj.tail = GeoPoint;
obj.deg = nan;
obj.len = nan;
obj.space = nan;
obj.num = nan;
elseif (nargin==3)
obj.name = name;
obj.head = head;
obj.tail = GeoPoint;
obj.deg = nan;
obj.len = nan;
obj.space = nan;
obj.num = nan;
elseif (nargin==4)
obj.name = name;
obj.head = head;
obj.tail = tail;
obj.deg = deg;
obj.len = nan;
obj.space = nan;
obj.num = nan;
elseif (nargin==5)
obj.name = name;
obj.head = head;
obj.tail = tail;
obj.deg = deg;
obj.len = len;
obj.space = nan;
obj.num = nan;
elseif (nargin==6)
obj.name = name;
obj.head = head;
obj.tail = tail;
obj.deg = deg;
obj.len = len;
obj.space = space;
obj.num = nan;
elseif (nargin==7)
obj.name = name;
obj.head = head;
obj.tail = tail;
obj.deg = deg;
obj.len = len;
obj.space = space;
obj.num = num;
end
end
% 从首尾点计算角度
function obj = get_deg(obj)
x0 = obj.head.x;
y0 = obj.head.y;
x1 = obj.tail.x;
y1 = obj.tail.y;
dx = x1-x0;
dy = y1-y0;
obj.deg = rad2deg(atan2(dy,dx));
end
% 从首尾点计算长度
function obj = get_len(obj)
x0 = obj.head.x;
y0 = obj.head.y;
x1 = obj.tail.x;
y1 = obj.tail.y;
dx = x1-x0;
dy = y1-y0;
obj.len = sqrt(dx^2+dy^2);
end
% 从长度和点数计算点距
function obj = get_space(obj)
obj.space = obj.len/(obj.num-1);
end
% 从起点和角度、长度计算终点
function obj = get_tail(obj)
obj.tail = GeoPoint;
x0 = obj.head.x;
y0 = obj.head.y;
obj.tail.x = x0+obj.len*cosd(obj.deg);
obj.tail.y = y0+obj.len*sind(obj.deg);
end
% 计算测线元素
function obj = get_items(obj,n,d)
if (nargin==1)
n = 1; % 重新编号
d = 1; % 默认编号间隔
elseif (nargin==2)
d = 1;
end
Items(obj.num) = GeoPoint;
Items(1) = obj.head;
Items(1).name = [obj.name,'-',num2str(n)];
Items(obj.num) = obj.tail;
Items(obj.num).name = [obj.name,'-',num2str(n+(obj.num-1)*d)];
if(obj.num<3)
return;
end
for i = 2:obj.num-1
Items(i).name = [obj.name,'-',num2str(n+(i-1)*d)];
Items(i).x = obj.head.x+(i-1)*obj.space*cosd(obj.deg);
Items(i).y = obj.head.y+(i-1)*obj.space*sind(obj.deg);
end
obj.items = Items;
end
function obj = remove_items(obj)
if(isempty(obj.items))
return;
else
obj.items = [];
end
end
% 重载绘图函数
function h = plot(obj,style)
x(1) = obj.head.x;
y(1) = obj.head.y;
x(2) = obj.tail.x;
y(2) = obj.tail.y;
if(nargin==1)
h = plot(x,y,'o');
elseif(nargin==2)
h = plot(x,y,style);
end
end
% 元素绘图函数
function h = plot_items(obj,style)
x = zeros(obj.num,1);
y = zeros(obj.num,1);
for i = 1:obj.num
x(i) = obj.items(i).x;
y(i) = obj.items(i).y;
end
if(nargin==1)
h = plot(x,y,'o');
elseif(nargin==2)
h = plot(x,y,style);
end
end
% 重载信息打印
function disp(obj)
fprintf('%s, O=(%.2f,%.2f), End=(%.2f,%.2f),θ=%.2f ,L=%.2f, Δ=%.2f, N=%d \n',...
obj.name,obj.head.x,obj.head.y,obj.tail.x,...
obj.tail.y,obj.deg,obj.len,obj.space,obj.num);
end
% 元素信息打印
function disp_items(obj)
for i = 1:obj.num
disp(obj.items(i));
end
end
end
end
这里实现了地理线的角度、长度、点距、元素的计算,以及可视化重载。地理线的首尾点,元素等用到了地理点对象。
下面做一个简单的应用:
clc;clear;
% clear classes;
% 定义首尾两点
p1 = GeoPoint('P1',0,0);
p2 = p1.NewByDeg('P2',-100,4);
%
h1 = plot(p1,'s');
hold on;
h2 = plot(p2,'*');
% 从首尾点确定测线
np = 50;
L1 = GeoLine('L1',p1,p2,[],[],[],np);
L1.disp();
% 计算角度
L1 = L1.get_deg();
L1.disp();
% 计算长度
L1 = L1.get_len();
L1.disp();
% 计算点距
L1 = L1.get_space();
L1.disp();
% 计算元素
L1 = L1.get_items();
disp_items(L1);
% 绘制
h3 = plot(L1,'k-o');
h4 = plot_items(L1);
axis equal;
% 去除元素
L1 = L1.remove_items();
L1 = L1.get_items(100,2);
效果如下:
可用流程图简单讲解下:
后续,将继续考虑新建地理对象类,其中包含点和线,同时实现链表式管理。