目录
积木绘制
积木拼接
练习
1. 停止标志
2. 跳跃旋转
3. 小步平移
(1)复数欧拉公式:
(2)复数的极坐标形式:
其中
(3)T形积木问题利用了复数乘以将该复数值旋转b角的事实。
findobj 查找具有特定属性的图形对象
function t_puzzle
% Playing pieces and puzzle shapes.
% Four playing pieces.
s = sqrt(2);
T{1} = [0 1 1+2*i 3*i 0];
T{2} = [0 s/2+s/2*i 1+(s-1)*i 1+(2*s-1)*i 2*s*i 0];
T{3} = [0 1 i 0];
T{4} = [0 1 1+(2-s)*i (3-s)*i 0];
% Three puzzle shapes for subplot.
P{1} = [2 2 1 1 0 0 -1 -1 2]-1/2 + [2 1 1 -2 -2 1 1 2 2]*i;
P{2} = [0 2 2-s 2-s 1-s 1-s -2 0] + [2 0 0 -2 -2 0 0 2]*i;
P{3} = [1 3 0 -2 1]-1/2 + [1 -1 -1 1 1]*i;
init_plot(T);
init_subplot(P);
init_buttons
% ------------------------
function button_motion(varargin)
% Button motion, either drag or rotate a piece.
% Use complex arithmetic.
point = get(gca,'currentpoint');
v = point(1,1) + point(1,2)*i;
hit = get(gca,'userdata');
if ~isempty(hit) && ishandle(hit) && hit ~= 1
u = get(hit,'xdata') + get(hit,'ydata')*i;
z = get(hit,'userdata');
% Check if closer to center or vertex.
w = mean(u(1:end-1));
if abs(w-v) < min(abs(u-v))
% Drag
u = u - (z - v);
else
% Rotate about the center by an integer
% multiple of pi/20, which is 9 degrees.
dtheta = pi/20;
theta = angle(v-w) - angle(z-w);
theta = round(theta/dtheta)*dtheta;
omega = exp(i*theta);
u = omega*(u-w) + w;
v = omega*(z-w) + w;
end
set(hit,'xdata',real(u),'ydata',imag(u),'userdata',v);
end
end
% ------------------------
function init_plot(T)
% Initialize primary plot.
clf
shg
set(gcf,'numbertitle','off','menubar','none','name','T-puzzle')
ax(1) = axes('pos',[0 0 1 1],'color',get(gcf,'color'), ...
'xlim',[-4 4],'ylim',[-3 3],'userdata',[]);
hold on
axis off
bluegreen = [0 1/2 1/2];
init_shift = [-2-i -1/2-i 1-i 1+i/4];
for k = 1:4
t = T{k} + init_shift(k);
fill(real(t),imag(t),bluegreen, ...
'markeredgecolor','black','linewidth',2)
end
set(gcf,'userdata',ax);
end
% ------------------------
function init_subplot(P)
% Initialize puzzle shapes subplot.
ax = get(gcf,'userdata');
ax(2) = axes('units','normal','position',[.02 .02 .24 .24]);
shape = 1;
t = P{shape};
buttoncolor = [.8314 .8157 .7843];
bluegreen = [0 1/2 1/2];
fill(real(t),imag(t),bluegreen, ...
'markeredgecolor','black','linewidth',1)
set(ax(2),'xtick',[],'ytick',[],'xlim',[-4 4],'ylim',[-3 3], ...
'color',buttoncolor,'userdata',shape);
set(gcf,'userdata',ax);
end
% ------------------------
function init_buttons
% Initialize buttons and callbacks.
ax = get(gcf,'userdata');
axis(ax(1));
set(gcf,'windowbuttondownfcn',@button_down, ...
'windowbuttonmotionfcn',@button_motion, ...
'windowbuttonupfcn',@button_up)
uicontrol('units','normal','pos',[.83 .12 .12 .05],'style','toggle', ...
'callback','t_puzzle','string','restart')
uicontrol('units','normal','pos',[.83 .06 .12 .05],'style','push', ...
'callback','close(gcf)','string','exit')
end
% ------------------------
function button_down(varargin)
ax = get(gcf,'userdata');
if gca == ax(1)
select_piece;
else
cycle_subplot(P)
end
end
% ------------------------
function select_piece;
% Select a piece and remember it in ax(1) userdata.
point = get(gca,'currentpoint');
z = point(1,1) + point(1,2)*i;
delete(findobj(gca,'type','line'))
h = flipud(get(gca,'children'));
h = h(1:4);
hit = [];
for k = 1:length(h)
x = get(h(k),'xdata');
y = get(h(k),'ydata');
if inregion(real(z),imag(z),x,y)
hit = h(k);
set(hit,'userdata',z)
break
end
end
set(gca,'userdata',hit)
% Right click reflects piece about center horizontally.
if ~isempty(hit) && isequal(get(gcf,'selectiontype'),'alt')
x = 2*mean(x(1:end-1))-x;
set(hit,'xdata',x)
end
end
% ------------------------
function cycle_subplot(P)
% Cycle through puzzle shapes in subplot.
ax = get(gcf,'userdata');
shape = get(ax(2),'userdata');
shape = mod(shape,3)+1;
t = P{shape};
f = get(ax(2),'child');
set(f,'xdata',real(t),'ydata',imag(t))
set(ax(1),'userdata',[])
set(ax(2),'userdata',shape)
axes(ax(1))
end
% ------------------------
function button_up(varargin)
% Button up, snap to any nearby piece, then deselect.
% Use complex arithmetic.
delete(findobj(gca,'type','line'))
hit = get(gca,'userdata');
set(gca,'userdata',[])
% Compute distance to nearest vertex of other pieces.
z = get(hit,'xdata') + get(hit,'ydata')*i;
h = get(gca,'children');
w = [];
for k = 1:length(h)
if h(k) ~= hit
w = [w; get(h(k),'xdata')+get(h(k),'ydata')*i];
end
end
dz = 1;
for k = 1:length(z);
d = z(k)-w;
dw = d(find(abs(d)==min(abs(d)),1));
if abs(dw) < abs(dz)
dz = dw;
end
end
% If close enough, snap to nearby piece.
tol = 1/8;
if abs(dz) < tol
set(hit,'xdata',real(z-dz),'ydata',imag(z-dz))
bluegreen = [0 1/2 1/2];
set(hit,'facecolor',1.25*bluegreen)
pause(.25)
set(hit,'facecolor',bluegreen)
end
end
end % t_puzzle
T形&箭头形&平行四边形
n=8
z=exp(2*pi*i*(0:n)'/n)
plot(z,'-o'), axis square
s=sum(z)
旋转操作是通过固定的角度(9度或π/20弧度)来进行的。这会导致在旋转过程中可能出现明显的跳跃,特别是在慢速旋转时,可能感觉不够平滑。
dtheta = pi/20; theta = angle(v-w) - angle(z-w); theta = round(theta/dtheta)*dtheta; omega = exp(i*theta); u = omega*(u-w) + w; v = omega*(z-w) + w;
程序中的
button_up
函数负责处理鼠标释放事件,即在将T形积木拖动到其他块体附近并释放鼠标键时,程序会检测是否有其他块体的顶点靠近被释放的积木,如果有足够近的块体,则将积木自动吸附到靠近的块体上。function button_up(varargin) % Button up, snap to any nearby piece, then deselect. % Use complex arithmetic. delete(findobj(gca,'type','line')) hit = get(gca,'userdata'); set(gca,'userdata',[]) % Compute distance to nearest vertex of other pieces. z = get(hit,'xdata') + get(hit,'ydata')*i; h = get(gca,'children'); w = []; for k = 1:length(h) if h(k) ~= hit w = [w; get(h(k),'xdata')+get(h(k),'ydata')*i]; end end dz = 1; for k = 1:length(z); d = z(k)-w; dw = d(find(abs(d)==min(abs(d)),1)); if abs(dw) < abs(dz) dz = dw; end end % If close enough, snap to nearby piece. tol = 1/8; if abs(dz) < tol set(hit,'xdata',real(z-dz),'ydata',imag(z-dz)) bluegreen = [0 1/2 1/2]; set(hit,'facecolor',1.25*bluegreen) pause(.25) set(hit,'facecolor',bluegreen) end end end % t_puzzle