作品
アニメ1
解説
私の学生時代には、2次方程式の「根」と教わりましたが、今の高校の教科書には「解」と書いてあります。これはどちらが正しいのか、数学の先生方の中でも議論があるようです(数学の素朴な疑問(実教出版) https://www.jikkyo.co.jp/download/detail/37/6100508415 )。そんな社会問題なども絡めて、MATLABを使った複素数入門の動画教材を作ってみました。
以前にも、リアルタイムで動くMATLABの簡単なアニメーションを作ったことはあります。しかし、外部ファイルに出力しなければ見られないような複雑な動きの動画の作成は初めてです。色々な難関に阻まれながらも何とか完成できました。
gif形式にしては高画素数の長編アニメーションが作れました。Qiitaの1ファイル当たりの容量制限(10MB)に何とか収まる9,889KB、4分12秒の作品です。
最後の複素平面上の根の動きの場面は、アンコールに応えて何回か繰り返すバターンを指向していましたが、10MBを超えてしまうのであきらめました。代わりに、爺のくだらないコメントを一切排除した、この場面だけの動画も作っておきました。一投稿(月間投稿?)での制限は100MBとのことなので、これは大丈夫そうです。アニメ1の動画部は10fpsですが、アニメ2は映画と同じ24fpsなので、動きがかなり滑らかです。
アニメ2
プログラム
できる限り、素のMATLABだけで仕上げようと思っていたのですが、grayconnectedやimrotateコマンドの便利さには勝てず、意思の弱さを感じながらも、ついつい Image Processing Toolbox を使ってしまいました。grayconnectedコマンドは絵文字画像の背景の透明化に大いに役立ちました。
高フレームレートで作ったmp4動画のスムーズさは魅力的だし、どこからでも再生可能で、好きなところで止められる機能も便利ですが、ファイルサイズが大きくなります。gifはフレームレートが固定ではなく、1コマ毎に表示時間を指定できるので、特に静止画が多い教材には、ファイルサイズを節約できて便利です。
プログラム中では、根の軌跡を表現するために、以前の投稿で紹介したユーザー関数「intersection_of_two_curves.m」を使用しています。
投稿本文では割愛しましたが、他にも作成に当たって調べたノウハウが沢山あります。これらは備忘録のつもりで、スクリプト中にコメントとして記載しています。興味があればリストを覗いてみてください。
% quad_equ_roots01.m
%
% 2次方程式の複素平面上の曲面のグラフを描く。
% これをアニメーションで動画にし、実根から虚根への変化を可視化する。
clear
close all
% ■■■■■■ 舞台裏・準備
%
% ■【大道具: figure,axesの準備】
%
% この動画では1つのfugure内に3つのaxesを設定する。
% ①メインのグラフを表示するための標準サイズの3D座標。
% 最初のグラフは2Dだが、3Dへの移行の利便性を考え、
% [az,el]=[0,0]として2D的に見せる。
% 標準スケールのままだと、2D⇒3Dのワープのときに乗物酔い感があ
% るので、axes equalにしたいところだが、グラフのスペースファクター
% が悪くなるので、標準のまま使う。
% ②サブのグラフを表示するための左上隅の小さな3D座標。
% 今回のパラメータ変化では、虚数曲面は全く動くことがないので、小さ
% な画面に参考表示するだけとした。
% ③コメント文字を表示するための特大サイズの透明2D座標。
% 3D座標では、最適位置へのコメント文字の配置は非常に手間がかかる
% ため、figure画面のほぼ全領域を2Dの透明座標で覆い、ここに文字を
% 表示することにした。文字だけであれば座標外へも表示できるが、絵文
% 字の画像は座標外への表示が不便なので、ここは特大サイズにしておく
% のが賢明である。
%
% この目的のために次のローカル関数を作成した。(プログラム末に添付)
% function [fig,ha1,ha2,ha3] = call_fig()
%
% ■【小道具: 絵文字などの画像の準備】
%
%%%%% % 画像関連コマンドについてのメモ。
%%%%% % コマンドが多すぎて分かりにくい。
%%%%% %
%%%%% % ■読込み系:
%%%%% % 画像の単純読込みは、
%%%%% % img = imread('peppers.png'); .bmpや.jpgもOK。
%%%%% % 透過データ付きの読込みは、
%%%%% % [img,map,alpha] = imread('peppers.png');
%%%%% %
%%%%% % ■貼り付け、表示系:
%%%%% % 2D表示は、image, imagesc, imshow(使い分けの調査不十分)
%%%%% % 3D表示は、surf, surface, warp(使い分けの調査不十分)
%%%%% % 2D表示は3D座標にも使えるが、z=0の面にしか貼り付かない。
%%%%% % 以下には、このプログラムで使用したコマンドのみ記す。
%%%%% % image([x1 x2],[y1 y2],img); 透過なし
%%%%% % image([x1 x2],[y1 y2],img,'AlphaData',alpha); 透過付き
%%%%% % (x1,y1)、(x2,y2)は、画像の左上,右下の隅の配置先。
%%%%% % warp(X,Y,Z,img);
%%%%% % X,Yは、お手軽を望むなら[X,Y]=meshgrid(x,y)から得られた
%%%%% % 行列(3行3列以上)。ZはXやYと同一サイズのf(X,Y)の行列。
%%%%% % x,yは、貼付け指定領域内のメッシュ分割点を示すベクトル。
%%%%% % surfは本プログラムでも使用しているが、画像とは別用途。
%%%%% % しかし、以下のようにすれば、画像の貼り付けにも使える。
%%%%% % surf(X,Y,Z,'CData',img,'FaceColor','texturemap');
%%%%% % X,Y,Zはwarpと同様。ただし、2行2列でも可。
% この動画では、外部から様々な画像を取り込んで、曲面のマッピングに使っ
% たり、絵文字の代用にしたりする。絵文字として利用する画像は背景が透
% 明である方が都合が良い。この透明化には、外部処理用の沢山の便利ツー
% ルがあるが、ここではMATLABの機能を利用して行うことにする。
% さらに、透明化の前に希望の角度で回転できるようにも配慮する。
% 絵文字を回転できれば表現力が豊かになるが、これは、MATLABさえ使えば
% 容易に実現できるだろうと楽観視していた。しかし次に示すように、それ
% ほど甘いものではなかった。
% imageで貼り付けた絵文字画像は、rotateコマンドに対して何らかの反応
% はするが、surfで貼り付けた画像に比べ、その動き方は不可解で理解困難
% である。一方、回転が理想的にできるsurf画像では、透明化した背景を表
% 現する手段がなく、今回の用途には不向きである。
% ということで、一つの絵文字について、色々な角度に傾けた複数の画像を
% 用意する必要が生じた。
%
% この目的のために次のローカル関数を作成した。(プログラム末に添付)
% [rgb,alpha,aspect] = remake_image(imgfile,angle)
% 図形の読み込み(絵文字代用)
[rgb_jy,alpha_jy, aspect_jy] = remake_image('爺.bmp',0);
[rgb_jo,alpha_jo, aspect_jo] = remake_image('嬢.bmp',0);
[rgb_fx,alpha_fx, aspect_fx] = remake_image('狐.bmp',0);
[rgb_fx1,alpha_fx1, aspect_fx1] = remake_image('狐.bmp',-10);
[rgb_fx2,alpha_fx2, aspect_fx2] = remake_image('狐.bmp',10);
[rgb_sl,alpha_sl, aspect_sl] = remake_image('貝.bmp',120);
[rgb_sl1,alpha_sl1, aspect_sl1] = remake_image('貝.bmp',110);
[rgb_sl2,alpha_sl2, aspect_sl2] = remake_image('貝.bmp',130);
[rgb_an,alpha_an, aspect_an] = remake_image('怒.bmp',0);
[rgb_sp,alpha_sp, aspect_sp] = remake_image('輝.bmp',0);
[rgb_sd,alpha_sd, aspect_sd] = remake_image('音.bmp',0);
[rgb_ht,alpha_ht, aspect_ht] = remake_image('怨.bmp',0);
[rgb_sw,alpha_sw, aspect_sw] = remake_image('汗.bmp',0);
[rgb_tm,alpha_tm, aspect_tm] = remake_image('×.bmp',0);
% 図形の読み込み(マッピング用)
meadow=imread('原.jpg');
% ■【小道具: その他のユーザー関数の準備】
%
% 2つのローカル関数と、1つの別ファイルのユーザー関数を使用する。
%
% ①等高線データの加工
% contourコマンドから出力される等高線群のデータは特殊なフォーマッ
% トになっており、そのままでは扱い難いため、NaNで区切られた単純な
% 形式に変換する。
%
% この目的のために次のローカル関数を作成した。(プログラム末に添付)
% [new_cont] = separate_contour(cont)
%
% ②絵文字の位置決め補助
% MATLABの2D座標上に書くつもりのコメントには、文字コードとして存在
% する全文字種を使える訳ではない。絵文字は使えないので、画像として
% 作ったものをimageコマンドで貼り付けなければならない。しかし、こ
% のコマンドは、画像の位置や大きさを指定する方法が難しくて使い難
% い。この絵文字画像の貼り付けが、textコマンドの文字配置やフォント
% サイズの指定と同様な要領でできるように、imageコマンドへの入力様
% 式に対応した座標データが生成できると都合が良い。
%
% この目的のために次のローカル関数を作成した。(プログラム末に添付)
% [xlr,ytb] = img_position(x,y,pos,pt,asp)
%
% ③2つの曲線群どうしの多数の交点の検出
% 方程式の根の位置は、2本の曲線の交点として求める必要がある。
%
% この目的のために次のユーザー関数を使用した。(以前、Qiitaに投稿済)
% [x,y,uc_code] = intersection_of_two_curves(x1,y1,x2,y2)
% ■【小道具: 動画記録用のフィルムの準備ほか】
% 各フレームの画像データを格納する配列を準備する。
frames = struct('cdata',[],'colormap',[]);
% 座標のメッシュ切り
x=-2:0.1:4; % 複素座標の実軸のメッシュ切り
y=-3:0.1:3; % 〃 虚軸 〃
[X,Y]=meshgrid(x,y);
Z=X+i*Y; % メッシュ切りされた複素平面
% 固定データの設定
a=1; % 2次方程式の各係数。
b=-2; % cの値は可変にするので、ここでは未定。
% ■■■■■■ 第1幕 第1場
% 動画タイトル
nf=1; % これから作る動画場面のコマ番号(初期値)
[fig,ha1,ha2,ha3]= call_fig(); % 座標の作成
axes(ha1);
axis off
axes(ha2);
axis off
axes(ha3);
text(0.5,0.6,'【2次方程式】 根はどこに消えたの?', ...
'FontSize',25,'Color',[0.8 0 0], ...
'VerticalAlignment','middle', ...
'HorizontalAlignment','center');
text(0.5,0.5,'$$f(x)=ax^2+bx+c=0$$','Interpreter','latex', ...
'FontSize',20,'Rotation',0, ...
'VerticalAlignment','middle', ...
'HorizontalAlignment','center');
text(0.5,0.10,'Posted on Qiita by tsubolabo', ...
'FontSize',15,'Color',[0 0 0], ...
'VerticalAlignment','middle', ...
'HorizontalAlignment','center');
% 出演者ご挨拶
[xlr,ytb] = img_position(0.2,0.3,'cm',50,aspect_jo); % 嬢
image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
[xlr,ytb] = img_position(0.4,0.3,'cm',50,aspect_sl); % 貝
image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
[xlr,ytb] = img_position(0.6,0.3,'cm',50,aspect_jy); % 爺
image(xlr,ytb,rgb_jy,'AlphaData',alpha_jy);
[xlr,ytb] = img_position(0.8,0.3,'cm',50,aspect_fx); % 狐
image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 動画タイトル']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
% ■■■■■■ 第1幕 第2場
% 実数世界の2次曲線(事前説明)
clf; % 前画面を消去
[fig,ha1,ha2,ha3]= call_fig(); % 座標の作成
axes(ha2);
axis off
axes(ha1);
view([0,0]); % 3D座標が2D風に見える位置にカメラを設定。
c=-2; % 2次方程式の係数c(待機値)
% 実数世界の二次曲線を黒色で描く
plot3(x,0*x,a*x.^2+b*x+c,'LineWidth',2,'Color','black');
% 座標の軸を黒色で描く
ax=axis;
plot3([ax(1),ax(2)],[0 0],[0,0],'LineWidth',1,'Color','black');
% x軸
plot3([0 0],[ax(3),ax(4)],[0,0],'LineWidth',1,'Color','black');
% 今は見えない。
plot3([0 0],[0,0],[ax(5),ax(6)],'LineWidth',1,'Color','black');
% 3D図のz軸だが、今はy軸に見える。
% 根の位置を黒丸で表示する(ユーザー関数を利用)。
[xc,yc,~] = intersection_of_two_curves( ...
[ax(1),ax(2)],[0 0],x,a*x.^2+b*x+c);
plot3(xc,xc*0,yc,'ok','MarkerSize',10,'LineWidth',2);
% 軸名は、x,y,zlabel での書き込みは、位置決め自由度が
% 低いので、textコマンドで代用。
% x軸タイトル代用
text(0.9,0,-23,'$$x$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
% z軸タイトル代用
text(-2.4,0,-2.5,'$$f(x)$$','Interpreter','latex', ...
'FontSize',17,'Rotation',90);
axes(ha3); % コメント座標をアクティブ化
% 数式の表示
if c<0
cnum=['\,-\,' num2str(abs(c))]; % 係数cの文字列化
else
cnum=['\,+\,' num2str(c)];
end
heq1=text(0.58,0.71,'$$f(x)=ax^2+bx+c$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
heq2=text(0.68,0.66,['$$=x^2-2x$$' '$$' cnum '$$'],'Interpreter', ...
'latex','FontSize',18,'Rotation',0);
% 嬢の台詞
hjo0=fill([0.1 0.1 0.93 0.93],[0.26 0.15 0.15 0.26],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.15,0.21,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.20,0.23,'これ知ってる! パラボラアンテナの放物線!' ...
,'FontSize',17,'Color',[0.8 0 0]);
hjo3=text(0.20,0.18,'〇印が','FontSize',17,'Color',[0.8 0 0]);
hjo4=text(0.333,0.177,'$$f(x)=0$$','Interpreter','latex', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo5=text(0.51,0.18,'の解ね。','FontSize',17,'Color',[0.8 0 0]);
[xlr,ytb] = img_position(0.68,0.175,'cm',20,aspect_sl);
hjo6=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': これ知ってる!']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hjo0); % 嬢の台詞の黄色背景を消す。
% 爺の台詞
hjy0=fill([0.3 0.3 0.87 0.87],[0.15 0.06 0.06 0.15],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.35,0.10,'cm',28,aspect_jy);
hjy1=image(xlr,ytb,rgb_jy,'AlphaData',alpha_jy);
hjy2=text(0.40,0.10,'いや!', ...
'FontSize',17,'Color',[0 0 0]);
hjy3=text(0.52,0.097,'$$f(x)$$','Interpreter','latex', ...
'FontSize',17,'Color',[0 0 0]);
hjy4=text(0.61,0.10,'の根じゃ。', ...
'FontSize',17,'Color',[0 0 0]);
[xlr,ytb] = img_position(0.83,0.10,'cm',21,aspect_fx);
hjy5=image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': いや! f(x)の根じゃ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hjo1,hjo2,hjo3,hjo4,hjo5,hjo6,hjy0,hjy1,hjy2,hjy3,hjy4,hjy5]);
% 嬢・爺の古い台詞を消す。
% 嬢の台詞
hjo0=fill([0.1 0.1 0.87 0.87],[0.25 0.165 0.165 0.25],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.15,0.21,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.20,0.21,'解よ! だって先生が言ってたもん。', ...
'FontSize',17,'Color',[0.8 0 0]);
[xlr,ytb] = img_position(0.82,0.21,'cm',20,aspect_sl);
hjo3=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
[xlr,ytb] = img_position(0.17,0.24,'cm',15,aspect_an);
hjo4=image(xlr,ytb,rgb_an,'AlphaData',alpha_an);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 解よ! だって']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hjo0);
% 爺の台詞
hjy0=fill([0.17 0.17 0.9 0.9],[0.16 0.07 0.07 0.16],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.22,0.11,'cm',28,aspect_jy);
hjy1=image(xlr,ytb,rgb_jy,'AlphaData',alpha_jy);
hjy2=text(0.27,0.11,'い~や! 根じゃ、間違いない!', ...
'FontSize',17,'Color',[0 0 0]);
[xlr,ytb] = img_position(0.86,0.11,'cm',21,aspect_fx);
hjy3=image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx);
[xlr,ytb] = img_position(0.24,0.14,'cm',15,aspect_an);
hjo4=image(xlr,ytb,rgb_an,'AlphaData',alpha_an);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': い~や! 根じゃ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
% ■■■■■■ 第1幕 第3場
% 実数世界の2次曲線(c変化アニメ開始)
cx=-7.5:0.25:4; % 係数cのスキャン域
Nframe=length(cx);
frl=1; % 絵文字の傾きフラグ(0:右、1:左)
nf=nf-1; % forループ内で加算されるので事前補正。
for n=1:Nframe
clf; % 心機一転。二度手間にはなるが・・・。
[fig,ha1,ha2,ha3]= call_fig(); % 座標の作成
axes(ha2);
axis off
axes(ha1); % 標準3D座標がアクティブ
view([0,0]); % 3D座標が2D風に見える位置にカメラを設定。
c=cx(n);
nf=nf+1;
% 実数世界の二次曲線を黒色で描く
plot3(x,0*x,a*x.^2+b*x+c,'LineWidth',2,'Color','black');
% 根の位置を黒丸で表示する。
[xc,yc,~] = intersection_of_two_curves( ...
[ax(1),ax(2)],[0 0],x,a*x.^2+b*x+c);
plot3(xc,xc*0,yc,'ok','MarkerSize',10,'LineWidth',2);
% 座標の軸を黒色で描く
ax=axis;
plot3([ax(1),ax(2)],[0 0],[0,0],'LineWidth',1,'Color','black');
% x軸
plot3([0 0],[ax(3),ax(4)],[0,0],'LineWidth',1,'Color','black');
% 今は見えない。
plot3([0 0],[0,0],[ax(5),ax(6)],'LineWidth',1,'Color','black');
% 3D図のz軸だが、今はy軸に見える。
% x軸タイトル代用
text(0.9,0,-23,'$$x$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
% z軸タイトル代用
text(-2.4,0,-2.5,'$$f(x)$$','Interpreter','latex', ...
'FontSize',17,'Rotation',90);
axes(ha3); % 2Dコメント座標がアクティブ
% 数式の表示
if c<0
cnum=['\,-\,' num2str(abs(c))]; % 係数cの文字列化
else
cnum=['\,+\,' num2str(c)];
end
heq1=text(0.58,0.71,'$$f(x)=ax^2+bx+c$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
heq2=text(0.68,0.66,['$$=x^2-2x$$' '$$' cnum '$$'], ...
'Interpreter','latex','FontSize',18,'Rotation',0);
if c<=2.5
% 嬢の台詞
hjo0=fill([0.1 0.1 0.59 0.59],[0.25 0.165 0.165 0.25],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.15,0.21,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.20,0.21,'あっ! 動き始めたよ。', ...
'FontSize',17,'Color',[0.8 0 0]);
end
if c<=1.0 % 貝・狐 小躍り
if frl==0 % 右傾
[xlr,ytb] = img_position(0.47,0.5,'cm',30,aspect_sl1);
hjo3=image(xlr,ytb,rgb_sl1,'AlphaData',alpha_sl1);
[xlr,ytb] = img_position(0.575,0.5,'cm',32,aspect_fx1);
hjo4=image(xlr,ytb,rgb_fx1,'AlphaData',alpha_fx1);
else % 左傾
[xlr,ytb] = img_position(0.47,0.5,'cm',30,aspect_sl2);
hjo3=image(xlr,ytb,rgb_sl2,'AlphaData',alpha_sl2);
[xlr,ytb] = img_position(0.575,0.5,'cm',32,aspect_fx2);
hjo4=image(xlr,ytb,rgb_fx2,'AlphaData',alpha_fx2);
end
frl=~frl; % 方向反転
end
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesに次々に画像を追加。
staysec(nf)=0; % このコマの表示継続時間(秒)
% 0のときは、既定のフレームレート
if n==1
disp(['frame' num2str(nf) ': 2Dの放物線が動き始める']);
elseif n==Nframe
disp(['frame' num2str(nf) ': 2Dの放物線が停止する']);
end
% =================================================================
end
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
axis on; % 現在のアクティブ座標は、2Dコメント座標のha3
% ■■■■■■ 第1幕 第4場
% 実数世界の2次曲線(次幕への準備)
% 嬢の台詞
hjo0=fill([0.1 0.1 0.87 0.87],[0.25 0.165 0.165 0.25],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.15,0.21,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.20,0.21,'あれっ? 解はどこに消えてしまったの?', ...
'FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 解はどこに消えてしまったの']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
clf; % 前画面を消去
[fig,ha1,ha2,ha3]= call_fig(); % 座標の作成
axes(ha2);
axis off
axes(ha1);
view([0,0]); % 3D座標が2D風に見える位置にカメラを設定。
c=-2;
% 実数世界の二次曲線を黒色で描く
hbc = plot3(x,0*x,a*x.^2+b*x+c,'LineWidth',2,'Color','black');
% 座標の軸を黒色で描く
ax=axis;
hbx = plot3([ax(1),ax(2)],[0 0],[0,0],'LineWidth',1,'Color','black');
% x軸
hby = plot3([0 0],[ax(3),ax(4)],[0,0],'LineWidth',1,'Color','black');
% y軸。最初は見えない。
hbz = plot3([0 0],[0,0],[ax(5),ax(6)],'LineWidth',1,'Color','black');
% 最初はy軸に見える。実はz軸。
% 根の位置を黒丸で表示する。
[xc,yc,uc_code] = intersection_of_two_curves( ...
[ax(1),ax(2)],[0 0],x,a*x.^2+b*x+c);
hbo = plot3(xc,xc*0,yc,'ok','MarkerSize',10,'LineWidth',2);
% xy平面の描画(最初は見えない)
% 2D図⇒3D図のワープのときだけ使用する粗いメッシュ。
% モアレ防止とファイルサイズ節約のため。
xt=-2:0.2:4; % 正規メッシュの半分の密度
yt=-3:0.2:3; % 〃
[Xt,Yt]=meshgrid(xt,yt);
%C(:,:,1)=X*0+24/255; % 赤 デフォルト0レベル標準色。
%C(:,:,2)=X*0+191/255; % 緑 他の色曲面と混在しても変色しないように
%C(:,:,3)=X*0+181/255; % 青 強制的にこの色を指定しておく。
hmesh = mesh(Xt,Yt,0*Xt);
alpha(hmesh,'0.85'); % 曲面をやや透明にする。
% x軸タイトル代用
haxx = text(0.9,0,-23,'$$x$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
% z軸タイトル代用
haxz = text(-2.4,0,-2.5,'$$f(x)$$','Interpreter','latex', ...
'FontSize',17,'Rotation',90);
axes(ha3);
% 数式の表示
if c<0
cnum=['\,-\,' num2str(abs(c))]; % 係数cの文字列化
else
cnum=['\,+\,' num2str(c)];
end
heq1=text(0.58,0.71,'$$f(x)=ax^2+bx+c$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
heq2=text(0.68,0.66,['$$=x^2-2x$$' '$$' cnum '$$'],'Interpreter', ...
'latex','FontSize',18,'Rotation',0);
[xlr,ytb] = img_position(0.47,0.5,'cm',30,aspect_sl);
hsl=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
[xlr,ytb] = img_position(0.575,0.5,'cm',32,aspect_fx);
hfx=image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=1; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 2Dグラフのみ。台詞なし。']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on; % 今は、ha3がアクティブ。
% 嬢の台詞
hjo0=fill([0.1 0.1 0.57 0.57],[0.29 0.18 0.18 0.29],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.15,0.24,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.20,0.26,'また、でてきた。', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo3=text(0.20,0.21,'どこに隠れていたの?', ...
'FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': また、でてきた']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hjo0);
% 貝・狐の台詞
hsl0=fill([0.57 0.57 0.92 0.92],[0.29 0.18 0.18 0.29],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.62,0.23,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
[xlr,ytb] = img_position(0.70,0.23,'cm',25,aspect_fx);
hsl2=image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx);
hsl3=text(0.75,0.235,'ひ・み・つ' ...
,'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=2; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': ひ・み・つ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsl0)
% 嬢の台詞
hjo0=fill([0.03 0.03 0.50 0.5],[0.18 0.07 0.07 0.18],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.08,0.13,'cm',25,aspect_jo);
hjo4=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo5=text(0.13,0.15,'あら、貝さん、', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo6=text(0.13,0.10,'おめめ かわいいわね。', ...
'FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': おめめ かわいい']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hjo0)
% 貝の台詞
hsl0=fill([0.50 0.50 0.90 0.90],[0.18 0.07 0.07 0.18],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.55,0.125,'cm',25,aspect_sl);
hsl4=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl5=text(0.60,0.15,'チョットだけなら、' ...
,'FontSize',17,'Color',[0 0.4 0]);
hsl6=text(0.60,0.10,'教えちゃおうかな。' ...
,'FontSize',17,'Color',[0 0.4 0]);
[xlr,ytb] = img_position(0.95,0.125,'cm',25,aspect_fx);
hsl7=image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx); % 狐、困惑
[xlr,ytb] = img_position(0.97,0.15,'cm',15,aspect_sw);
hsl8=image(xlr,ytb,rgb_sw,'AlphaData',alpha_sw);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': チョットだけなら']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
% ■■■■■■ 第2幕 第1場
% 複素数の世界へワープ
delete([haxx,haxz,heq1,heq2,hjo1,hjo2,hjo3,hjo4,hjo5,hjo6, ...
hsl,hfx,hsl0,hsl1,hsl2,hsl3,hsl4,hsl5,hsl6,hsl7,hsl8]);
%%%%% % 一定速で視点を変えると何となく不自然。加減速期間を設ける。
%%%%% % 最終変位量をU、移動途中の変位をx、定速域の速度をv、
%%%%% % 増速加速度をa、減速加速度をb(<0)、
%%%%% % フレームレートの時間刻みをdt、加速域フレーム数をn1、
%%%%% % 等速域フレーム数をn2、減速域フレーム数をn3とすると、
%%%%% % 次式が成立する。
%%%%% % v = a*n1*dt = -b*n3*dt
%%%%% % x(@n1) = (a/2)*(n1*dt)^2
%%%%% % x(@n1+n2) - x(@n1) = v*n2*dt
%%%%% % x(@n1+n2+n3) - x(@n1+n2) = (-b/2)*(n3*dt)^2
%%%%% % U = x(@n1+n2+n3)
%%%%% % これを解くと
%%%%% % a*(dt)^2 = 2*U / (n1^2 + 2*n1*n2 + n1*n3) = kk とおく。
%%%%% % が得られる。これを利用して、
%%%%% % n <= n1 では、
%%%%% % x(@n) = (n^2/2)*kk
%%%%% % n1 < n <= (ni+n2) では、
%%%%% % x(@n) = (n*n1 - n1^2)*kk + x(@n1)
%%%%% % (n1+n2) < n <= (n1+n2+n3) では、
%%%%% % x(@n) = n1*(n-n1-n2)*{1-(n-n1-n2)/(2*n3)}*kk
%%%%% % + x(@n1+n2)
%%%%% % となる。
U=1; % 最終変位量(puの基準値)
n1=20; % 等加速度で増速期間のフレーム数(0は不可)
n2=2; % 定速移動期間のフレーム数(0は不可)
n3=1; % 等加速度で減速中のフレーム数(0は不可)
kk = 2*U/(n1^2 + 2*n1*n2 + n1*n3);
nn = 1:n1;
uratio(nn) = kk*(nn.^2)/2; % uratio: 上記のx相当量。
nn = n1+1:n1+n2;
uratio(nn) = kk*n1*(nn-n1) + uratio(n1);
nn = n1+n2+1:n1+n2+n3;
uratio(nn)=kk*n1*((nn-n1-n2)-(nn-n1-n2).^2/(2*n3)) + uratio(n1+n2);
% 各フレームでの変位量(pu)
Nframe=length(uratio);
az_max = -30; % 方位角の最終目標値(度)
el_max = 35; % 伏角 〃
nf=nf-1; % forループ内でまた加算されるので、事前に補正。
for n=1:Nframe
nf=nf+1;
if n==floor((n1+n2+n3)/5)
axes(ha3)
% 嬢の台詞
hjo0=fill([0.1 0.1 0.52 0.52],[0.16 0.05 0.05 0.16],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.15,0.11,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.20,0.13,'わ~っ。' ...
,'FontSize',17,'Color',[0.8 0 0]);
hjo3=text(0.20,0.08,'天にも昇る ここち。', ...
'FontSize',17,'Color',[0.8 0 0]);
elseif n==n1+n2+n3
axes(ha3)
delete([hjo0,hjo1,hjo2,hjo3]);
end
axes(ha1);
view([az_max,el_max]*uratio(n));
axes(ha3); % 下層に隠れたであろうha3を上層へ。
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow; % 他の処理を待たないで、すぐに描画。
frames(nf)=getframe(fig); % 構造体framesに次々に画像を追加。
staysec(nf)=0.2; % このコマの表示継続時間(秒)
% 0のときは、既定のフレームレート
if n==1
disp(['frame' num2str(nf) ': ワープ開始']);
elseif n==Nframe
disp(['frame' num2str(nf) ': ワープ完了']);
end
% =================================================================
end
% ■■■■■■ 第2幕 第2場
% 複素世界の説明
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
axis on; % 現在のアクティブ座標は、2Dコメント座標のha3
axes(ha1);
% xy平面の粗いメッシュを細かいメッシュに変える
delete(hmesh);
C(:,:,1)=X*0+24/255; % 赤 デフォルト0レベル標準色。
C(:,:,2)=X*0+191/255; % 緑 他の色曲面と混在しても変色しないように
C(:,:,3)=X*0+181/255; % 青 強制的にこの色を指定しておく。
hmesh = mesh(X,Y,0*X,C);
alpha(hmesh,'0.70'); % 曲面をやや透明にする。
% x軸タイトル代用
text(0.7,-4.3,-20,'$$x$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
% y軸タイトル代用
text(-3.3,-0.2,-20,'$$y\,i$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
% z軸タイトル代用
text(-3,3,-2,'$$f(z)$$','Interpreter','latex', ...
'FontSize',17,'Rotation',90);
axes(ha3);
% 数式の表示
if c<0
cnum=['\,-\,' num2str(abs(c))]; % 係数cの文字列化
else
cnum=['\,+\,' num2str(c)];
end
heq1=text(0.58,0.71,'$$f(z)=az^2+bz+c$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
heq2=text(0.68,0.66,['$$=z^2-2z$$' '$$' cnum '$$'],'Interpreter', ...
'latex','FontSize',18,'Rotation',0);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=2; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': ワープ直後']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on;
% 嬢の台詞
hjo0=fill([0.1 0.1 0.82 0.82],[0.11 0.00 0.00 0.11],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.15,0.06,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.20,0.08,'放物線だけの殺風景な広っぱ・・・。' ...
,'FontSize',17,'Color',[0.8 0 0]);
hjo3=text(0.20,0.03,'でも、','FontSize',17,'Color',[0.8 0 0]);
hjo4=text(0.30,0.027,'$$f(x)$$','Interpreter','latex', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo5=text(0.40,0.03,'が','FontSize',17,'Color',[0.8 0 0]);
hjo6=text(0.45,0.027,'$$f(z)$$','Interpreter','latex', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo7=text(0.55,0.03,'に変わっている。', ...
'FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 殺風景な広っぱ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hjo0,hjo1,hjo2,hjo3,hjo4,hjo5,hjo6,hjo7]);
% 貝の台詞
hsl0=fill([0.01 0.01 0.53 0.53],[0.74 0.58 0.58 0.74],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.06,0.66,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'ここは複素平面よ。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'心が豊かなら、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl4=text(0.11,0.61,'何か見えてくるはずだわ。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': ここは複素平面よ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsl0);
% 嬢の台詞
hjo0=fill([0.01 0.01 0.35 0.35],[0.57 0.485 0.485 0.57],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.06,0.53,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.11,0.53,'ぜ~んぜん!','FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=2; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': ぜ~んぜん']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl1,hsl2,hsl3,hsl4,hjo0,hjo1,hjo2]);
% 台詞がない複素平面だけの場面
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=1; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 複素平面(台詞なし)']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
% 貝の台詞
hsl0=fill([0.01 0.01 0.59 0.59],[0.74 0.58 0.58 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.66,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'心で感じられないのなら、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'体で感じてもらうしかないわ。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl4=text(0.11,0.61,'はい、目をつぶって!', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': はい、目をつぶって']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3,hsl4]);
xtic=xticklabels; % 暗転中はコメント座標の目盛数値を消すので、
ytic=yticklabels; % 元に戻すときのために記憶しておく。
% この目盛数値は本番では表示させないが、編集時の位置合わせには、
% これがないと困る。普通の場面では、フレーム画像を記録する直前に
% axis off で消している。しかし、axis off にすると、暗転させた座
% 標の背景色まで消えてしまうため、ここでは使えない。
% 代わりに、フレーム画像を記録する直前に、目盛数値だけを強制的に
% 消去する。記録完了後に元に戻す。
% 暗転場面
set(ha3,'Color',[0.3 0.3 0.3]); % 場面暗転
% 嬢の台詞
hjo0=fill([0.21 0.21 0.66 0.66],[0.51 0.425 0.425 0.51],[0 0 0], ...
'LineStyle','none','FaceAlpha',1);
[xlr,ytb] = img_position(0.26,0.47,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.31,0.47,'え~っ。なんだろう?', ...
'FontSize',17,'Color',[1 0.8 0.8]);
%input('一旦停止中。再開は"Enter"')
xticklabels({''});
yticklabels({''});
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(暗転背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': え~っ。なんだろう']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
xticklabels(xtic);
yticklabels(ytic);
delete(hjo0);
% 貝の台詞
hsl0=fill([0.21 0.21 0.76 0.76],[0.30 0.19 0.19 0.30],[0 0 0], ...
'LineStyle','none','FaceAlpha',1);
[xlr,ytb] = img_position(0.26,0.25,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.31,0.27,'はいっ。','FontSize',17,'Color',[0.8 1 0.8]);
hsl3=text(0.31,0.22,'もう、目を開けてもいいわ。', ...
'FontSize',17,'Color',[0.8 1 0.8]);
%input('一旦停止中。再開は"Enter"')
xticklabels({''});
yticklabels({''});
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(暗転背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 目を開けてもいいわ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
xticklabels(xtic);
yticklabels(ytic);
delete([hjo1,hjo2,hsl0,hsl1,hsl2,hsl3]);
set(ha3,'Color','none'); % コメント座標を暗転から透明に戻す。
% ■■■■■■ 第2幕 第3場
% f(x)の計算ポイントの指示
axes(ha1);
hcc=[]; % ×印の一括ハンドル
ax=axis;
xpv=ax(1):ax(2);
ypv=ax(3):ax(4);
for yp=ypv
if yp==0 % 実軸上のf(z)は、放物線と同値なので割愛。
continue
end
for xp=xpv % 計算ポイントに×印。
[xlr,ytb] = img_position(xp,yp,'cm',200,aspect_tm);
% 2Dコメント座標に専用の関数なので、
% 3Dメイン座標に使うときは、フォントサイズの数値が変則的。
hccx=image(xlr,ytb,rgb_tm,'AlphaData',alpha_tm);
hcc=[hcc hccx];
end
end
% ×印が水平面と重なって見えにくい。気付かれない程度に水平面を下げる。
set(hmesh,'ZData',X*0-0.1);
axes(ha3)
% 貝の台詞
hsl0=fill([0.01 0.01 0.61 0.61],[0.74 0.58 0.58 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.66,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'いま×印を置いた42ヶ所で、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'$$f(z)$$','Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl4=text(0.20,0.66,'の値を計算してみてね。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl5=text(0.11,0.61,'明日までの宿題よ。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': この42ヶ所の×印の']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsl0);
% 嬢の台詞
hjo0=fill([0.01 0.01 0.77 0.77],[0.16 0.05 0.05 0.16],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.11,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.11,0.13,'げっ。来なければよかった・・・。' ...
,'FontSize',17,'Color',[0.8 0 0]);
hjo3=text(0.11,0.08,'複素数の計算方法なんて知らね~し。', ...
'FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 来なければよかった']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl1,hsl2,hsl3,hsl4,hsl5,hjo0,hjo1,hjo2,hjo3]);
% コメント座標をホワイトボード化
set(ha3,'Color',[0.95 1 0.95]);
set([heq1,heq2],'Visible','off'); % 数式は一時的に隠しておく。
% 貝の台詞
hsl0=fill([0.11 0.11 0.72 0.72],[0.705 0.54 0.54 0.705],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.66,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.21,0.65,'何をいまさら。恥ずかしいわよ。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl3=text(0.21,0.59,'$$i^2=-1$$', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl4=text(0.38,0.60,'を知ってさえいれば、', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl5=text(0.21,0.55,'中学生でも楽勝よ。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
axcol=get(gca,'XColor'); % 軸の標準色を取得しておく。
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 中学生でも楽勝よ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
delete(hsl0)
% 貝の台詞
hsl0=fill([0.11 0.11 0.74 0.74],[0.535 0.37 0.37 0.535],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.48,'cm',25,aspect_sl);
hsl6=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl7=text(0.21,0.48,'例えば、', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl8=text(0.36,0.473,'$$z=3+2i$$', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl9=text(0.57,0.48,'の点なら、', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl10=text(0.21,0.423,'$$f(z)=z^2-2z-2$$ ', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl11=text(0.58,0.43,'の', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl12=text(0.21,0.37,'$$z$$', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl13=text(0.25,0.38,'を', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl14=text(0.30,0.37,'$$3+2i$$', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl15=text(0.43,0.38,'に置きかえて、', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w');
set(gca,'YColor','w');
grid off
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 例えば、']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on
delete(hsl0)
% 貝の台詞
hsl0=fill([0.11 0.11 0.91 0.91],[0.362 0.13 0.13 0.362],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.31,'cm',25,aspect_sl);
hsl16=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl17=text(0.21,0.303,'$$f(3+2i)=(3+2i)^2-2(3+2i)-2$$', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl18=text(0.39,0.253,'=', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl19=text(0.45,0.26,'かくかくしかじか', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl20=text(0.39,0.203,'$$=-3+8i$$', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl21=text(0.21,0.14,'だわ!。簡単でしょ?。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w');
set(gca,'YColor','w');
grid off
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 簡単でしょ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on
delete(hsl0)
% 嬢の台詞
hjo0=fill([0.11 0.11 0.34 0.34],[0.11 0.03 0.03 0.11],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.07,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
[xlr,ytb] = img_position(0.17,0.08,'cm',15,aspect_ht);
hjo2=image(xlr,ytb,rgb_ht,'AlphaData',alpha_ht);
hjo3=text(0.21,0.07,'げげっ。', ...
'FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w');
set(gca,'YColor','w');
grid off
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': げげっ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on
delete([hsl1,hsl2,hsl3,hsl4,hsl5,hsl6,hsl7,hsl8,hsl9,hsl10, ...
hsl11,hsl12,hsl13,hsl14,hsl15,hsl16,hsl17,hsl18,hsl19, ...
hsl20,hsl21,hjo0,hjo1,hjo2,hjo3]);
set([heq1,heq2],'Visible','on'); % 隠していた数式を再表示。
set(ha3,'Color','none'); % ホワイトボードを透明に戻す。
axes(ha1);
delete(hcc); % ×印を消す。
set(hmesh,'ZData',X*0); % 水平面を本来の正確な位置に戻す。
axes(ha3);
hsd1=text(0.06,0.68,'翌日','FontSize',30,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off;
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 翌日']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsd1);
% 貝の台詞
hsl0=fill([0.01 0.01 0.52 0.52],[0.74 0.63 0.63 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.685,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'宿題はやってきたようね。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'簡単だったでしょ。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off;
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 宿題はやってきた']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsl0);
% 貝の台詞
hsl0=fill([0.01 0.01 0.70 0.70],[0.62 0.54 0.54 0.62],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.58,'cm',25,aspect_sl);
hsl4=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl5=text(0.11,0.58,'これをグラフ上にプロットしてみるわ。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off;
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': これをグラフ上にプロット']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3,hsl4,hsl5]);
axes(ha1);
% ■■■■■■ 第2幕 第4場
% f(z)の指示ポイントの計算結果の図示
[Xpv,Ypv]=meshgrid(xpv,ypv);
Zpv=Xpv+i*Ypv;
Fpv=a*Zpv.^2+b*Zpv+c; % f(z)の値
Fpvr=real(Fpv); % f(z)の実数部
Fpvi=imag(Fpv); % f(z)の虚数部
Fpvo=Xpv*0;
xx=reshape(Xpv,1,[]);
yy=reshape(Ypv,1,[]);
zzr=reshape(Fpvr,1,[]);
zzi=reshape(Fpvi,1,[]);
hlvr=plot3([xx;xx],[yy;yy],[zzr;zzr*0],'k','LineWidth',2);
hlvi=plot3([xx;xx],[yy;yy],[zzi;zzi*0],'k','LineWidth',2);
% 水平面上の計算ポイントを小さい黒点で示す。
hpvo=plot3(Xpv,Ypv,Fpvo,'.k','MarkerSize',20);
% f(z)の実数部の値と虚数部の値を、赤〇と青〇で示す。
% なお、線と〇の内面が重なって汚いので、〇を少しだけ前面に移動する。
% しかし、なかなかしぶとい。epsレベルどころではない、かなりの量の移
% 動が必要。
% 線が完全に垂直に立っているのに対し、〇の面の法線は真横ではなく、
% viewの視線の方向を向いている。少々移動したくらいでは、串刺しにされ
% た垂直線から抜け出せない。
hpvr=plot3(Xpv-0.02,Ypv-0.02,Fpvr,'or', ...
'LineWidth',2,'MarkerFaceColor','w');
hpvi=plot3(Xpv-0.02,Ypv-0.02,Fpvi,'ob', ...
'LineWidth',2,'MarkerFaceColor','w');
% 前面に移動した〇が、axis範囲からほんの少しはみ出すだけなのに、画面に
% 表示されなくなってしまうので、特例として、axis外の図形も表示可能に
% 設定する。ただし、下記の2行は、1行にまとめるとエラーになる。
% 「連結する配列の次元が一致しません。」
set([hlvr,hlvi],'Clipping','off');
set([hpvr,hpvi,hpvo],'Clipping','off');
axes(ha3)
% 貝の台詞
hsl0=fill([0.01 0.01 0.42 0.42],[0.74 0.63 0.63 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.685,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'赤〇が実数部、','FontSize',17,'Color',[1 0 0]);
hsl3=text(0.11,0.66,'青〇が虚数部よ。','FontSize',17,'Color',[0 0 1]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off;
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 計算結果の図示']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsl0);
% 貝の台詞
hsl0=fill([0.01 0.01 0.67 0.67],[0.13 0.02 0.02 0.13],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.075,'cm',25,aspect_sl);
hsl4=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl5=text(0.11,0.10,'ごちゃごちゃして分かりにくいわね。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl6=text(0.11,0.05,'赤〇だけにしてみるわ。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 赤〇だけにしてみるわ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3,hsl4,hsl5,hsl6]);
% ■■■■■■ 第2幕 第5場
% 計算結果の実数部分だけを残す
axes(ha1);
set(hmesh,'Visible','off'); % 水平面を隠す。
set(hlvi,'Visible','off'); % この2行を1行にまとめると
set(hpvi,'Visible','off'); % エラーになる。
delete(hpvo);
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 計算結果の実数部分だけを残す']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
% ■■■■■■ 第3幕 第1場
% 2次複素曲面(実数部)の出現
axes(ha1)
set(hmesh,'Visible','off');
F=a*Z.^2+b*Z+c; % f(z)の値
Fr=real(F); % f(z)の実数部
Fi=imag(F); % f(z)の虚数部
hsr = surf(X,Y,Fr); % f(z)の実数部の曲面。
hsr.EdgeColor='none'; % 網目は邪魔なので消去。
Nframe=8; % 徐々に見えてくる曲面に使うコマ数
alp=linspace(0,0.5,Nframe); % フレーム毎の不透明度の変化。
wid=linspace(2,0.1,Nframe); % フレーム毎の線の太さの変化。
nf=nf-1;
for n=1:Nframe
nf=nf+1;
alpha(hsr,num2str(alp(n))); % 曲面を徐々に可視化する。
set(hlvr,'LineWidth',wid(n)); % 〇印や、それを支える直線の太さを
set(hpvr,'LineWidth',wid(n)); % 徐々に細くする。
axes(ha3); % 下層に隠れたであろうha3を上層へ。
if n==1
% 嬢の台詞
hjo0=fill([0.01 0.01 0.57 0.57],[0.73 0.65 0.65 0.73],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.06,0.69,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.11,0.69,'あっ! 何か見えてきたわ。', ...
'FontSize',17,'Color',[0.8 0 0]);
end
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow; % 他の処理を待たないで、すぐに描画。
frames(nf)=getframe(fig); % 構造体framesに次々に画像を追加。
staysec(nf)=0; % このコマの表示継続時間(秒)
% 0のときは、既定のフレームレート
if n==1
disp(['frame' num2str(nf) ': 実数曲面出現開始']);
elseif n==Nframe
disp(['frame' num2str(nf) ': 実数曲面出現終了']);
end
% =================================================================
axis on
axes(ha1)
end
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% 可視化後、計算ポイントのプロットを消して画像を暫く保持する。
delete(hlvr);
delete(hpvr);
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 2次複素曲面(実数部)の出現(多色)']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hjo0,hjo1,hjo2]);
% 台詞を消した画面を暫く保持する。
% 曲面が明瞭に見えきっているのに、まだ台詞が残っているのは不自然。
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=2; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 「何か見えてきたわ」削除']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
axes(ha1)
delete(hsr); % 多色surf曲面を削除
set([hbc,hbo,hbx,hby,hbz],'Visible','off')
%%%%% % 曲面への画像貼り付けコマンドwarpについての注意メモ。
%%%%% %
%%%%% % なぜか? warpコマンドで画像を貼り付けると、y軸座標の数値の
%%%%% % 並びが、標準の昇順('normal')から降順('reverse')に入れ替わ
%%%%% % ってしまう。これによって、既に描画済みのオブジェクトの配
%%%%% % 置が、y軸の中央値を中心として逆転して大混乱となる。これを
%%%%% % 元の向きに直すために、'YDir'を'normal'に設定しなおす必要
%%%%% % がある。
%%%%% % しかし、これによって、折角正しい向きに貼られた画像までもが
%%%%% % 反転してしまうので、貼り付け前に画像の上下を逆向きに加工
%%%%% % しておく必要ががある。
%%%%% % さらにさらに、'YDir'の'normal'への設定変更によって、なぜか
%%%%% % ?、3D座標のviewポイントが変わってしまうので、これも、本
%%%%% % 来の値に設定し直す必要がある。大変な手間がかかる。
meadow=flipud(meadow); % 上述の理由で草原の画像を上下反転。
hmeadow=warp(X,Y,Fr,meadow); % 実数曲面に草原の画像を被せる。
alpha(hmeadow,'1'); % 画像表面を完全に不透明化。
hmeadow.EdgeColor='none'; % 網目は邪魔なので消去。
set(gca,'YDir','normal'); % 上述の理由により、軸目盛の順序反転
view(az_max,el_max); % 同じく、viewポイントの再設定。
axes(ha3); % アクティブ座標をコメント面へ切替。
% 嬢の台詞
hjo0=fill([0.05 0.05 0.50 0.50],[0.70 0.59 0.59 0.70],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.10,0.65,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
[xlr,ytb] = img_position(0.13,0.69,'cm',15,aspect_sp);
hjo2=image(xlr,ytb,rgb_sp,'AlphaData',alpha_sp);
hjo3=text(0.15,0.67,'わ~っ', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo4=text(0.15,0.62,'草スキーの丘だわ!', ...
'FontSize',17,'Color',[0.8 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 実数曲面(草原)']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
axes(ha1)
delete([hmeadow,hjo0,hjo1,hjo2,hjo3,hjo4]);
hsurf=surf(X,Y,Fr,'EdgeColor','none', ...
'FaceColor',[0.996 0.863 0.741]); % 肌色
alpha(hsurf,'1'); % 曲面を不透明にする。
hsurf.EdgeColor='none'; % 表面の網目を消す。
%%%%% % 照明のコマンドは多すぎて分かり難いが、概略、次のとおり。
%%%%% %
%%%%% % lightangle(AZ,EL); : axesの固定座標を基準にして
%%%%% % AZ,ELの絶対位置に光源を置く。
%%%%% % camlight(AZ,EL); : カメラ(viewポイント)を基準にして
%%%%% % AZ,ELの相対位置に光源を置く。
%%%%% % light(...);
%%%%% % 括弧内に示した各種property機能を持つ照明を置く。
%%%%% % lightangleやcamlightで設置した照明とは別の器具のようだ。
%%%%% % 同じ器具を呼び出すのに、呼び出し方が色々あるのかと思った
%%%%% % がそうではなさそう。
%%%%% % lighting;
%%%%% % 光源ではなく、物体表面の陰影表現に関する事項。
%%%%% % lighting flat; 簡易な陰影づけ。ポリゴンが不自然に光る。
%%%%% % lighting gouraud; 滑らかな陰影付け。
%%%%% % lighting none; 陰影の表現なし。凹凸感の無い無表情な面。
%%%%% % material;
%%%%% % 光源ではなく、物体表面の光沢に関する事項。
%%%%% % material dull; つや消し面
%%%%% % material shiny; 光沢面
%%%%% % material metal; 金属的な強光沢面
Nframe=9; % 照明演出に使うコマ数。
az_vec = linspace(-10,10,Nframe); % コマ毎の照明位置の変化。
el_vec = linspace(-20,10,Nframe);
hcam=camlight(az_vec(1),el_vec(1)); % 指定位置に照明灯を点灯。
lighting gouraud; % ポリゴン感がない滑らか表面。
material dull; % 無光沢の表面。
nf=nf-1;
for n=1:Nframe % 照明灯の位置を移動させて、肌色に現実味を与える。
camlight(hcam,az_vec(n),el_vec(n));
nf=nf+1;
axes(ha3); % コメント面をアクティブに。
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow; % 他の処理を待たないで、すぐに描画。
frames(nf)=getframe(fig); % 構造体framesに次々に画像を追加。
staysec(nf)=0; % このコマの表示継続時間(秒)
% 0のときは、既定のフレームレート
if n==1
disp(['frame' num2str(nf) ': 照明開始']);
elseif n==Nframe
disp(['frame' num2str(nf) ': 照明完了']);
end
% =================================================================
axis on
axes(ha1)
end
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% 照明の移動後も、その画像を暫く保持する。
axes(ha3)
% 爺の台詞
hjy0=fill([0.05 0.05 0.55 0.55],[0.70 0.59 0.59 0.70],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.10,0.65,'cm',25,aspect_jy);
hjy1=image(xlr,ytb,rgb_jy,'AlphaData',alpha_jy);
[xlr,ytb] = img_position(0.12,0.69,'cm',15,aspect_sd);
hjy2=image(xlr,ytb,rgb_sd,'AlphaData',alpha_sd);
hjy3=text(0.15,0.67,'うほ~っ','FontSize',17,'Color',[0 0 0]);
hjy4=text(0.15,0.62,'なかなかのフォルムじゃ。', ...
'FontSize',17,'Color',[0 0 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 実数曲面(肌色)']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsurf,hcam,hjy0,hjy1,hjy2,hjy3,hjy4]);
set([hbc,hbo,hbx,hby,hbz],'Visible','on')
% ■■■■■■ 第3幕 第2場
% 2次複素曲面(実数部)の出現
axes(ha1);
set(hlvi,'Visible','on'); % f(x)の虚数部のプロットが再登場
set(hpvi,'Visible','on');
axes(ha3)
% 貝の台詞
hsl0=fill([0.01 0.01 0.54 0.54],[0.73 0.65 0.65 0.73],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.69,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.69,'次は虚数部のプロットよ。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 次は虚数部のプロット']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2]);
axes(ha1);
hsi = surf(X,Y,Fi); % f(z)の虚数部の曲面。
hsi.EdgeColor='none'; % 網目は邪魔なので消去。
Nframe=8; % 徐々に見えてくる曲面に使うコマ数
alp=linspace(0,0.5,Nframe); % フレーム毎の不透明度の変化。
wid=linspace(2,0.1,Nframe); % フレーム毎の線の太さの変化。
nf=nf-1;
for n=1:Nframe
nf=nf+1;
alpha(hsi,num2str(alp(n))); % 曲面を徐々に可視化する。
set(hlvi,'LineWidth',wid(n)); % 〇印や、それを支える直線の太さを
set(hpvi,'LineWidth',wid(n)); % 徐々に細くする。
axes(ha3); % 下層に隠れたであろうha3を上層へ。
if n==1
% 嬢の台詞
hjo0=fill([0.01 0.01 0.67 0.67],[0.22 0.14 0.14 0.22],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.06,0.18,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.11,0.18,'あっ! これも何か見えてきたわ。', ...
'FontSize',17,'Color',[0.8 0 0]);
end
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow; % 他の処理を待たないで、すぐに描画。
frames(nf)=getframe(fig); % 構造体framesに次々に画像を追加。
staysec(nf)=0; % このコマの表示継続時間(秒)
% 0のときは、既定のフレームレート
if n==1
disp(['frame' num2str(nf) ': 虚数曲面出現開始']);
elseif n==Nframe
disp(['frame' num2str(nf) ': 虚数曲面出現終了']);
end
% =================================================================
axis on
axes(ha1)
end
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% 可視化後、計算ポイントのプロットを消して画像を暫く保持する。
delete(hlvi);
delete(hpvi);
axes(ha3)
% 貝の台詞
hsl0=fill([0.01 0.01 0.58 0.58],[0.13 0.02 0.02 0.13],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.075,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.10,'やっと心豊かになったようね。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.05,'おめでとう。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 2次複素曲面(虚数部)の出現(多色)']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hjo0,hjo1,hjo2]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 台詞の一部を消して、暫く保持']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3]);
axes(ha1);
delete(hsi); % 多色surf曲面を削除
% ■■■■■■ 第3幕 第3場
% 2次曲面と水平面の交線
axes(ha3);
% コメント座標をホワイトボード化
set(ha3,'Color',[0.95 1 0.95]);
set([heq1,heq2],'Visible','off'); % 数式は一時的に隠しておく。
% 貝の台詞
hsl0=fill([0.11 0.11 0.69 0.69],[0.615 0.53 0.53 0.615],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.57,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.21,0.55,'ここまでくれば、話は早いわ。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': ここまでくれば、話は早い']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
delete(hsl0);
% 貝の台詞
hsl0=fill([0.11 0.11 0.84 0.84],[0.505 0.34 0.34 0.505],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.425,'cm',25,aspect_sl);
hsl3=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl4=text(0.21,0.445,'$$f(z)=0$$', ...
'Interpreter','latex', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl5=text(0.39,0.45,'という要求は、', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl6=text(0.21,0.40,'実数部と虚数部が両方とも0になって', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl7=text(0.21,0.35,'初めて満たされるのよ。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 実数部と虚数部が両方とも']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
delete(hsl0);
% 貝の台詞
hsl0=fill([0.11 0.11 0.81 0.81],[0.305 0.19 0.19 0.305],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.25,'cm',25,aspect_sl);
hsl8=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl9=text(0.21,0.25,'実数部と虚数部が0になる条件を', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl10=text(0.21,0.20,'グラフを見ながら考えてみましょうね。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': グラフを見ながら考えて']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
delete([hsl0,hsl1,hsl2,hsl3,hsl4,hsl5,hsl6,hsl7,hsl8,hsl9,hsl10,]);
set(ha3,'Color','none'); % コメント座標を透明に戻す。
set([heq1,heq2],'Visible','on'); % 数式を再表示する。
% 貝の台詞
hsl0=fill([0.01 0.01 0.73 0.73],[0.74 0.63 0.63 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.685,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'これが実数部の曲面よ。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'こんどは赤一色の網目にしてみたわ。', ...
'FontSize',17,'Color',[0 0.4 0]);
axes(ha1)
delete(hsi);
set([hbc,hbo,hbx,hby,hbz],'Visible','on')
F=a*Z.^2+b*Z+c; % f(z)の値
Fr=real(F); % f(z)の実数部
Fi=imag(F); % f(z)の虚数部
C(:,:,1)=X*0+1; % 赤
C(:,:,2)=X*0+0.5; % 緑
C(:,:,3)=X*0+0.5; % 青
hsr = mesh(X,Y,Fr,C);
alpha(hsr,'0.70'); % 曲面をやや透明にする。
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': これが実数部の曲面よ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3]);
% 貝の台詞
hsl0=fill([0.01 0.01 0.50 0.50],[0.74 0.63 0.63 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.685,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'さっき隠した水平面を、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'これに重ねてみましょ。', ...
'FontSize',17,'Color',[0 0.4 0]);
axes(ha1)
set(hmesh,'Visible','on');
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': さっき隠した水平面を']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsl0);
% 貝の台詞
hsl0=fill([0.01 0.01 0.59 0.59],[0.12 0.01 0.01 0.12],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.065,'cm',25,aspect_sl);
hsl4=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl5=text(0.11,0.09,'実数部が0になるのは、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl6=text(0.11,0.04,'2つの面の交線部分だけよ。', ...
'FontSize',17,'Color',[0 0.4 0]);
axes(ha1)
set(hmesh,'Visible','on');
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 2つの面の交線部分']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3,hsl4,hsl5,hsl6]);
% 貝の台詞
hsl0=fill([0.01 0.01 0.61 0.61],[0.74 0.63 0.63 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.685,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'ここには赤色の太線を引いて', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'目立つようにしておきましょ。', ...
'FontSize',17,'Color',[0 0.4 0]);
axes(ha1)
[cont_liner,hcr] = contour(X,Y,Fr,[0 0],'LineWidth',2,'Color','red');
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': ここには赤色の太線']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3]);
% 貝の台詞
hsl0=fill([0.01 0.01 0.64 0.64],[0.74 0.63 0.63 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.685,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.71,'こんどは虚数部を見てみましょ。', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl3=text(0.11,0.66,'こちらは青一色の網目よ。', ...
'FontSize',17,'Color',[0 0.4 0]);
axes(ha1)
set(hsr,'Visible','off');
set(hmesh,'Visible','off');
set(hcr,'Visible','off');
C(:,:,1)=X*0+0.5; % 赤
C(:,:,2)=X*0+0.5; % 緑
C(:,:,3)=X*0+1; % 青
hsi = mesh(X,Y,Fi,C);
alpha(hsi,'0.70'); % 曲面をやや透明にする。
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': こんどは虚数部を']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2,hsl3]);
% 貝の台詞
hsl0=fill([0.01 0.01 0.45 0.45],[0.73 0.65 0.65 0.73],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.69,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.69,'水平面を重ねるよ。', ...
'FontSize',17,'Color',[0 0.4 0]);
axes(ha1)
set(hmesh,'Visible','on');
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 水平面を重ねるよ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2]);
% 貝の台詞
hsl0=fill([0.01 0.01 0.63 0.63],[0.73 0.65 0.65 0.73],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.69,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.11,0.69,'こちらの交線は青色の太線よ。', ...
'FontSize',17,'Color',[0 0.4 0]);
axes(ha1)
[cont_linei,hci] = contour(X,Y,Fi,[0 0],'LineWidth',2,'Color','blue');
axes(ha3)
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 交線は青色の太線よ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete(hsl0);
% 貝の台詞
hsl0=fill([0.01 0.01 0.76 0.76],[0.17 0.01 0.01 0.17],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.09,'cm',25,aspect_sl);
hsl3=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl4=text(0.11,0.14,'だけど、今回のように、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl5=text(0.11,0.09,'係数cを変化させるだけでは、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl6=text(0.11,0.04,'虚数部のグラフは全く変化しないのよ。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 虚数部のグラフは全く変化しない']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl1,hsl2]);
% 貝の台詞
hsl0=fill([0.01 0.01 0.57 0.57],[0.74 0.63 0.63 0.74],[1 1 0.5], ...
'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.685,'cm',25,aspect_sl);
hsl7=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl8=text(0.11,0.71,'虚数部は脇役なんだけど、', ...
'FontSize',17,'Color',[0 0.4 0]);
hsl9=text(0.11,0.66,'青い太線だけは大切なの。', ...
'FontSize',17,'Color',[0 0.4 0]);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=5; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 青い太線だけは大切']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl0,hsl3,hsl4,hsl5,hsl6,hsl7,hsl8,hsl9]);
% ■■■■■■ 第4幕 第1場
% 2次曲面(c変化アニメ開始)
% コメント座標をホワイトボード化
set(ha3,'Color',[0.95 1 0.95]);
set([heq1,heq2],'Visible','off'); % 数式は一時的に隠しておく。
% 貝の台詞
hsl0=fill([0.07 0.07 0.77 0.77],[0.555 0.44 0.44 0.555],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.12,0.495,'cm',25,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl2=text(0.17,0.50,'脇役の曲面は隅の方において、', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl3=text(0.17,0.45,'青い太線だけは残しておきましょう。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 脇役の曲面は隅の方']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
delete(hsl0);
% 貝の台詞
hsl0=fill([0.07 0.07 0.85 0.85],[0.405 0.24 0.24 0.405],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.12,0.325,'cm',25,aspect_sl);
hsl4=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl);
hsl5=text(0.17,0.35,'係数cの値を変えながら、', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl6=text(0.17,0.30,'実数部の曲面の動きを追ってみましょう。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
hsl7=text(0.17,0.25,'ここからが本番よ。', ...
'FontSize',17,'Color',[0 0.4 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': ここからが本番よ']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
clf;
cx=-7.5:0.25:9.5; % 係数cのスキャン域
Nframe=length(cx);
nf=nf-1;
for n=1:Nframe
nf=nf+1;
c=cx(n);
clf; % figureをクリアする。
[fig,ha1,ha2,ha3]= call_fig(); % 座標の作成
axes(ha1);
view([az_max,el_max]);
F=a*Z.^2+b*Z+c; % f(z)の値
Fr=real(F); % f(z)の実数部
Fi=imag(F); % f(z)の虚数部
hcr=mesh(X,Y,Fr); % f(z)の実数部の曲面を描く
alpha(hcr,'0.7'); % 曲面をやや透明にする。
% 座標の軸を黒色で描く
ax=axis;
plot3([ax(1),ax(2)],[0 0],[0,0],'LineWidth',1,'Color','black');% x軸
plot3([0 0],[ax(3),ax(4)],[0,0],'LineWidth',1,'Color','black');% y軸
plot3([0 0],[0,0],[ax(5),ax(6)],'LineWidth',1,'Color','black');% z軸
% 実数世界の二次曲線を黒色で描く
plot3(x,0*x,a*x.^2+b*x+c,'LineWidth',2,'Color','black');
% Fの実数部の高さ=0 の等高線を赤色で描き、その座標データも取得する。
cont_liner = contour(X,Y,Fr,[0 0],'LineWidth',2,'Color','red');
% MATLABの特殊形式の等高線データを常用形式に変換する。
% (ローカル関数の呼び出しによる)
cont_liner = separate_contour(cont_liner);
% Fの虚数部についても、青色で同様の処理。
cont_linei = contour(X,Y,Fi,[0 0],'LineWidth',2,'Color','blue');
cont_linei = separate_contour(cont_linei);
% Fの実数部と虚数部の曲面が0になるような等高線どうしの交点を求める。
% (別ファイルのユーザー関数の呼び出しによる)
if ~isempty(cont_liner) && ~isempty(cont_linei)
[xc,yc,uc] = intersection_of_two_curves ...
(cont_liner(1,:),cont_liner(2,:), ...
cont_linei(1,:),cont_linei(2,:));
if ~isnan(xc) % 交点が存在すれば、そこに〇印をつける。
plot3(xc,yc,0*xc,'ok','MarkerSize',10,'LineWidth',2);
end
end
% x軸タイトル代用
text(0.7,-4.3,-20,'$$x$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
% y軸タイトル代用
text(-3.3,-0.2,-20,'$$y\,i$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
% z軸タイトル代用
text(-3,3,-5,'$$f(z)_{real}$$','Interpreter','latex', ...
'FontSize',17,'Rotation',90);
% z=0のメッシュ面は、図を複雑にし過ぎるので、
% 代わりに、その外枠だけを描く。
ax=axis;
plot3([ax(1) ax(1) ax(2) ax(2) ax(1)], ...
[ax(4) ax(3) ax(3) ax(4) ax(4)],[0 0 0 0 0],'k');
% 左上の小画面の描画
axes(ha2);
hci=mesh(X,Y,Fi); % 小画面にf(z)の虚数部の曲面を描く
alpha(hci,'0.7'); % 曲面をやや透明にする。
axis(axis(ha1)); % 表示座標域は大画面3D図と合わせる。
view([az_max,el_max]);
% z軸タイトル代用
text(-4,3,-15,'$$f(z)_{imag}$$','Interpreter','latex', ...
'FontSize',12,'Rotation',90);
% Fの虚数部について、青色で0レベル等高線を引く。
contour(X,Y,Fi,[0 0],'LineWidth',2,'Color','blue');
% 前面のコメント画面の描画
axes(ha3)
axis on
% 数式の表示
if c<0
cnum=['\,-\,' num2str(abs(c))]; % 係数cの文字列化
else
cnum=['\,+\,' num2str(c)];
end
heq1=text(0.58,0.71,'$$f(z)=az^2+bz+c$$','Interpreter','latex', ...
'FontSize',18,'Rotation',0);
heq2=text(0.68,0.66,['$$=z^2-2z$$' '$$' cnum '$$'], ...
'Interpreter','latex','FontSize',18,'Rotation',0);
if n>=1 && c<1
% 嬢の台詞
hjo0=fill([0.01 0.01 0.62 0.62],[0.17 0.01 0.01 0.17], ...
[1 1 0.5],'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.09,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.11,0.14,'あっ!', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo3=text(0.11,0.09,'赤い線と青い線の交点が、', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo4=text(0.11,0.04,'解の〇印になって動いている。', ...
'FontSize',17,'Color',[0.8 0 0]);
end
if c>1 && n<Nframe
% 嬢の台詞
hjo0=fill([0.01 0.01 0.79 0.79],[0.12 0.01 0.01 0.12], ...
[1 1 0.5],'LineStyle','none','FaceAlpha',0.9);
[xlr,ytb] = img_position(0.06,0.065,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.11,0.09,'あれっ!', ...
'FontSize',17,'Color',[0.8 0 0]);
hjo3=text(0.11,0.04,'消えないで、横に曲がって動き続けてる。', ...
'FontSize',17,'Color',[0.8 0 0]);
end
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow; % 他の処理を待たないで、すぐに描画。
frames(nf)=getframe(fig); % 構造体framesに次々に画像を追加。
staysec(nf)=0; % このコマの表示継続時間(秒)
% 0のときは、既定のフレームレート
if n==1
disp(['frame' num2str(nf) ': 複素数根の移動開始']);
elseif n==Nframe
disp(['frame' num2str(nf) ': 複素数根の移動完了']);
end
% =================================================================
axis on
axes(ha1);
end
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% 移動後も、その画像を暫く保持する。
axes(ha2); % ha1の裏に隠れてしまったha2を、表に引き出す。
axes(ha3);
[xlr,ytb] = img_position(0.63,0.12,'cm',50,aspect_sl);
hsl1=image(xlr,ytb,rgb_sl,'AlphaData',alpha_sl); % 貝
[xlr,ytb] = img_position(0.59,0.20,'cm',30,aspect_sp);
hsl2=image(xlr,ytb,rgb_sp,'AlphaData',alpha_sp); % 貝輝
[xlr,ytb] = img_position(0.78,0.12,'cm',50,aspect_fx);
hfx1=image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx); % 狐
[xlr,ytb] = img_position(0.80,0.15,'cm',30,aspect_ht);
hfx2=image(xlr,ytb,rgb_ht,'AlphaData',alpha_ht); % 狐怨
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 複素数根の最終状態']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
% 狐 消滅
for fx_size=[40 30 20 10]
delete(hfx1);
[xlr,ytb] = img_position(0.78,0.12,'cm',fx_size,aspect_fx);
hfx1=image(xlr,ytb,rgb_fx,'AlphaData',alpha_fx); % 狐
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=0.2; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 狐' num2str(fx_size)]);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
end
axis on
delete(hfx1);
%input('一旦停止中。再開は"Enter"')
% 動画の一コマとして登録
axis off
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=3; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 貝だけ残る']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
axis on
delete([hsl1,hsl2,hfx2]);
% ■■■■■■ 第4幕 第3場
% 複素根のまとめ
% コメント座標をホワイトボード化
set(ha3,'Color',[0.95 1 0.95]);
set([heq1,heq2],'Visible','off'); % 数式は隠す。
text(0.5,0.68,'まとめ','FontSize',20,'Color',[0 0 0], ... ...
'VerticalAlignment','middle', ...
'HorizontalAlignment','center');
% 嬢の台詞
hjo0=fill([0.11 0.11 0.64 0.64],[0.635 0.45 0.45 0.635],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.57,'cm',25,aspect_jo);
hjo1=image(xlr,ytb,rgb_jo,'AlphaData',alpha_jo);
hjo2=text(0.21,0.57,'とても良く分かったわ。', ...
'FontSize',17,'Color',[0.8 0 0],'VerticalAlignment','bottom');
hjo3=text(0.21,0.52,'貝さん ありがとう。', ...
'FontSize',17,'Color',[0.8 0 0],'VerticalAlignment','bottom');
hjo3=text(0.21,0.47,'コンコンさんは 役立たず。', ...
'FontSize',17,'Color',[0.8 0 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=4; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 貝さん ありがとう']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
delete(hjo0);
% 爺の台詞
hjy0=fill([0.11 0.11 0.84 0.84],[0.455 0.27 0.27 0.455],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.39,'cm',28,aspect_jy);
hjy1=image(xlr,ytb,rgb_jy,'AlphaData',alpha_jy);
hjy2=text(0.21,0.39,'複素数の世界では、', ...
'FontSize',17,'Color',[0 0 0],'VerticalAlignment','bottom');
hjy3=text(0.21,0.34,'赤い線と青い線が絡まり合いながら、', ...
'FontSize',17,'Color',[0 0 0],'VerticalAlignment','bottom');
hjy4=text(0.21,0.29,'解や根を求め続けているんじゃの~。', ...
'FontSize',17,'Color',[0 0 0],'VerticalAlignment','bottom');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=6; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': 複素数の世界では']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
delete(hjy0);
% 爺の台詞
hjy0=fill([0.11 0.11 0.90 0.90],[0.275 0.14 0.14 0.275],[1 1 0], ...
'LineStyle','none','FaceAlpha',0.5);
[xlr,ytb] = img_position(0.16,0.21,'cm',28,aspect_jy);
hjy5=image(xlr,ytb,rgb_jy,'AlphaData',alpha_jy);
hjy6=text(0.21,0.21,'それにしても、', ...
'FontSize',17,'Color',[0 0 0],'VerticalAlignment','bottom');
hjy7=text(0.21,0.16,'コンの奴はどこに消えてしまったんじゃろう。', ...
'FontSize',17,'Color',[0 0 0],'VerticalAlignment','bottom');
text(0.5,0.06,'Created with MATLAB','FontSize',15,'Color',[0 0 0], ...
'VerticalAlignment','middle', ...
'HorizontalAlignment','center');
%input('一旦停止中。再開は"Enter"')
set(gca,'XColor','w'); % 軸の線が邪魔なので、
set(gca,'YColor','w'); % getframeのときだけ消えてもらう。
grid off; % grid線も同様。
% 動画の一コマとして登録
%axis off; %%%%% この場面に限り無効化(背景が消えてしまうので)
drawnow
frames(nf)=getframe(fig); % 構造体framesにfigure画像を登録。
staysec(nf)=7; % このコマの表示継続時間(秒)
disp(['frame' num2str(nf) ': コンの奴はどこに消えて']);
nf=size(frames,2)+1; % 次に作る動画場面の開始コマ番号
% =================================================================
set(gca,'XColor',axcol); % 軸の線を原状回復
set(gca,'YColor',axcol);
grid on; % grid線も同様。
% 全コマをgif動画ファイルとして書き出す。
Nf=size(frames,2);
filename = 'animation_01.gif'; % ファイル名
for i = 1:Nf
[A, map] = rgb2ind(frame2im(frames(i)), 256); % 画像形式変換
if staysec(i)~=0 % 0以外のときは、その秒数だけの静止画。
delay=staysec(i);
else % 0のときはフレームレート10fpsの動画。
delay=1/10;
end
if i == 1
imwrite(A, map, filename, 'gif', 'DelayTime', delay, ...
'LoopCount',Inf);
% 表示はdelay秒間。1コマ目で繰返し再生回数の設定。
else
imwrite(A, map, filename, 'gif', 'DelayTime', delay, ...
'WriteMode', 'append');
% 2コマ目以降には、"追記"の指示が必要。
end
end
Time=sum(staysec)+ sum(staysec==0)/10;
disp(['推定上映時間: ' num2str(Time) '秒']);
%%%%% % % 参考: 書き出し先を mp4 にする場合に備えてのメモ。
%%%%% % % 但し、均一なフレームレートで、gifと同時間の静止場面を
%%%%% % % 作るには、フレーム作成の処理に、ある程度の改修が必要。
%%%%% % video = VideoWriter('animation_01.mp4', 'MPEG-4');
%%%%% % video.FrameRate = 30; % フレームレート(fps)
%%%%% % open(video); % 書き込むファイルを開く
%%%%% % writeVideo(video, frames); % ファイルに書き込む
%%%%% % close(video); % 書き込んだファイルを閉じる
% ====================================================================
function [fig,ha1,ha2,ha3]= call_fig()
% 3つの座標を準備する関数
%
% 【入力】
% 不要
%
% 【出力】
% fig: figure(1)のハンドル
% ha1: 3Dメイン座標のハンドル
% ha2: 3Dサブ座標のハンドル
% ha3: 2Dコメント座標のハンドル
%
% 【利用方法】
% [fig,ha1,ha2,ha3] = call_fig(); を実行後、操作が必要なfigure
% や各座標を呼び出すためには、
% fig;, axes(ha1);, axes(ha2);, axes(ha3); などと記述する。
% なお、各axesの本来の重なりの順序は、背後からha1,ha2,ha3となっ
% ている。しかし、例えば axes(ha1);とすると、それより前面にあ
% るべきha2やha3が背後に隠れてしまう。これを正規の重なり順に戻
% すために、適宜、必要に応じて、前面に出すべきaxesの空呼び
% 出しを行う。
fig=figure(1);
set(fig,'Color','w');
% 3Dメイン座標(ha1)================
% axes枠の位置と大きさは、デフォルト値をそのまま使う。
axis([-2,4,-3,3,-20,20]);
grid on
hold on
ha1=gca; % 3Dメイン座標のハンドル名
% 3Dサブ座標(ha2)================
axes('Position',[0.1 0.72 [ha1.Position(3) ha1.Position(4)]*0.3225]);
% 大画面3D図と同一アスペクト比とし、左上に配置。
axis(axis(ha1)); % 表示座標域は大画面3D図と合わせる。
grid on
hold on
xticklabels({''}); % 小さな図に目盛数値まで入ると煩わしいので、
yticklabels({''}); % x軸とy軸のものだけ削除する。
ha2=gca; % 3Dサブ座標のハンドル名
% 2Dコメント座標(ha3)================
axes('Position',[0.03 0.03 0.94 0.94],'Color','none');
% 余白は最小限にして、figure内にできるだけ大きな
% axes枠を確保する。textはaxes外にも表示できるが、
% 絵文字はaxes外に食み出すと表示されなくなるので、
% 領域は広くとっておいたほうが都合が良い。
% なお、背後の座標が隠れないように、この座標面は基
% 本的には透明にしておく。
axis equal; % 理由は下記
% 横軸と縦軸のスケールが異なると、絵文字の縦横比を保つのが面倒にな
% るので、両軸のスケール合わせのためにaxis equalを指定している。
ha3=gca; % 2Dコメント座標のハンドル名
% しかし、axis equalモードにすると、指定axis全体が、アスペクト比一
% 定のまま axesの枠内に欠損なく収まるように、axisの大きさが自動調
% 整される。そのため、axesとaxisのアスペクト比が一致しない場合、
% axisのx軸かy軸いずれかのフルスケール幅が、axesのそれと一致しな
% くなる。本プログラムでは、高さよりも幅を一致させる方が都合が良
% いので、安全のため、axisの縦/横比をaxesのそれよりも若干小さめに
% 設定する。
Kasp=(fig.Position(4)*ha3.Position(4))/ ...
(fig.Position(3)*ha3.Position(3));
% axisの横幅を1.0に設定するので、
% そのとき許される高さの最大値を計算しておく。
% 高さを上記より少々抑え気味にして、axisを設定。
axis([0 1 0 Kasp-0.01]);
grid on;
axis off;
hold on
end
% ====================================================================
% ====================================================================
function [rgb,alpha,aspect]= remake_image(imgfile,angle)
% 指定した画像を取り込んで、回転させた後、背景を透明化する。
%
% 【入力】
% imgfile: 取り込む画像のファイル名(拡張子も含めて' 'で囲む)
% angle: 回転角度(単位:度、反時計回りが正)
%
% 【出力】
% rgb: 加工後のRGB画像データ
% alpha: 加工後の画像の背景透過用のマスク
% aspect: 加工後の画像の縦/横比
% 背景が透明化されていない普通の画像を取り込む。
img_origin = imread(imgfile);
% 画像枠の端にまで中身の画像があり、白い背景が途切れていると、後の処
% 理に支障が出ることがあるので、原画像の周囲に若干の白背景を付け加
% える。
orgn_size=size(img_origin);
img_expand=ones(orgn_size(1)+10,orgn_size(2)+10,3)*255;
img_expand=uint8(img_expand);
% 縦横とも、原画像よりも10ピクセル分だけ大きい純白画像を用意。
% この画像の中央部を原画像で置き換える。
img_expand(6:5+orgn_size(1),6:5+orgn_size(2),:)=img_origin;
img_origin=img_expand; % これを新たなimg_originとみなす。
% 画像を左右に回転する。
rot_img=imrotate(img_origin,angle); % 反時計回りにangle度回転
Srot=size(rot_img);
% 傾けた画像が全て収容できるように、画像の外枠が広がって、
% 原画像よりもサイズが大きくなっている。
% (原画像以外の部分は黒く塗り潰される。)
% 原画像には存在しない4隅の黒色の領域を白く塗り潰す。
rot_gray=rgb2gray(rot_img); % カラーのままだと処理に手間がかかるの
% で、カラー画像を一時的に白黒に変換。
mask1=grayconnected(rot_gray, 1, 1, 2);
% 画像の1行1列の点にあるピクセルの明度(0~255)を取得。この点と±2
% の許容差で同一明度で隣接しながら繋がる領域を認識。その領域のピ
% クセルの値を1、その他のピクセルの値を0として、rot_grayと同一サ
% イズのマスク行列を作成する。
% 上記の左上隅に続き、以下、右上・左下、右下も同様に処理する。
mask2=grayconnected(rot_gray, 1, Srot(2),2);
mask3=grayconnected(rot_gray, Srot(1), 1, 2);
mask4=grayconnected(rot_gray, Srot(1), Srot(2), 2);
% 4隅の情報を集約。原画には無かった領域だけが1、他は0のマスク行列。
mask_corner=(mask1 | mask2 | mask3 | mask4);
% このマスクを利用して、4隅の黒色領域を純白化する。
rot_img(:,:,1) = 255*mask_corner + double(rot_img(:,:,1)); % R
rot_img(:,:,2) = 255*mask_corner + double(rot_img(:,:,2)); % G
rot_img(:,:,3) = 255*mask_corner + double(rot_img(:,:,3)); % B
% 行列の要素どうしの加算では、型の自動変換はされないようだ、
% uint8形式のrot_imgを倍精度に変換する必要がある。
% 加算結果が255を超えても、rot_imgに再代入するときに、
% 自動的にuint8形式に変換され、255にクリップされる。
% できた画像をトリミングする。白地に少々の余裕を残して、
% 上下左右の無駄な部分をカットする。
rot_gray=rgb2gray(rot_img); % 4隅を清浄後のカラー画像を
% 再度、グレースケールに変換。
% 以前と同一変数名だが中身は異なる。
% まず、背景を除いた[画像部だけ]を囲む正立長方形の位置座標を求める。
% 長方形の上端
for n=1:Srot(1) % 画像の行列の全行を上の行からチェックしていく。
if sum(rot_gray(n,:)<=254)>0 % 純白以外のピクセルが1つでも含まれ
top=n-1; % ていれば、そこを画像の頂部と判断
break; % し、1ピクセル上方をtopとする。
end
top=n; % 画像が全く無いときは、最下行まで行き着く。
end
% 長方形の下端
for n = Srot(1):-1:1
if sum(rot_gray(n,:)<=254)>0
bot=n+1;
break;
end
bot=n;
end
% 長方形の左端
for n=1:Srot(2)
if sum(rot_gray(:,n)<=254)>0
left=n-1;
break;
end
left=n;
end
% 長方形の右端
for n = Srot(2):-1:1
if sum(rot_gray(:,n)<=254)>0
right=n+1;
break;
end
right=n;
end
% 画像が無いときはエラー。
if ( top>bot || right<left )
error('画像は空のようです。')
end
dd=5; % 画像の周囲に確保する余裕(単位:ピクセル)
top=top-dd;
bot=bot+dd;
left=left-dd;
right=right+dd;
% 長方形より外側の過剰な余白をカットする。
rot_img([1:top bot:Srot(1)],:,:)=[];
rot_img(:,[1:left right:Srot(2)],:)=[];
rgb=rot_img;
% 背景透過用のマスクを作る。
rot_gray=rgb2gray(rot_img); % カラー画像をグレースケールに変換。
% 前回と同名変数だが、中身は別もの。
alpha=~grayconnected(rot_gray, 1, 1, 2); % 背景透過マスク完成。
% 1行1列にあるピクセルの明度(0~255)と、±2の許容差
% で同明度の連続領域にあるピクセルの値を1、その他
% のピクセルの値を0とした行列を作り、その全要素を
% 論理否定したものが背景透過マスクとなる。
aspect=size(rgb,2)/size(rgb,1);
end
%%%%% % 参考:
%%%%% % これらの結果を、透過データ付きのpngファイルとして出力する場
%%%%% % 合には、次のように記述する。
%%%%% %
%%%%% % alpha=double(alpha); % 論理値のままでは受付けられない。
%%%%% % imwrite(rgb,['出力ファイル名' '.png'],'png','Alpha',alpha);
% ====================================================================
% ====================================================================
% MATLABの特殊形式の等高線データを常用形式に変換するローカル関数。
function [new_cont] = separate_contour(cont)
% 【入力】
% cont: contourコマンドから得られた生の等高線座標(2行の行列)
%
% 【出力】
% new_cont: 変換後の等高線座標(2行の行列)
% (入力行列の区切り列を[NaN;NaN]と置き換えたもの)
new_cont=[];
n=1; % contの最初の要素番号
while true
if n>length(cont)
break;
end
np=cont(2,n); % そのグループに属する後続の折点数を取得
new_cont=[new_cont cont(:,n+1:n+np) [NaN;NaN]];
n=n+1+np; % contの次のグループの先頭要素番号
end
return;
end
% ====================================================================
% ====================================================================
% 絵文字の位置決めのためのローカル関数
function [xlr,ytb] = img_position(x,y,pos,pt,asp)
% 絵文字を、文字列と一緒に行を揃えて表示しようとすると、非常に面倒。
% それを少しでも楽にするためのもの。imageコマンド用の最適入力座標を
% 求めるための関数。
%
% 【入力】
% x,y: 絵文字を置きたい位置の座標
% (単位は、axesの横幅を1.0としたpu表示。出力の単位も同様)
% pos: 上記の座標を絵文字のどこに合わせるかの指定
% (下の左右のグループから各1個を選び、)
% ( 'lm'とか'lb'などと指定。 )
% 'l' : 左端 't' : 上端
% 'c' : 中央 'm' : 中間
% 'r' : 右端 'b' : 下端
% pt: 絵文字の高さを、一般文字の何ポイント相当にするかを指示
% asp: 絵文字の本来のアスペクト比(横幅/高さ)を設定
% (正しく設定しないと表示が歪む)
%
% 【出力】
% xlr: imageコマンドに指示するx座標行ベクトル([xl xr])
% ytb: 〃 y 〃 ([yt yb])
% ( image(xlr,ytb,イメージ名,.....)として使用 )
Kwa = 0.11/39; % ポイント値をpu単位の高さに換算するための係数。
h = pt*Kwa; % 絵文字の高さ(pu)
w = h*asp; % 絵文字の横幅(pu)
if sum(pos=='l')>0
xl = x;
xr = x + w;
elseif sum(pos=='c')>0
xl = x - w/2;
xr = x + w/2;
elseif sum(pos=='r')>0
xl = x - w;
xr = x;
else
xl = NaN;
xr = NaN;
return;
end
if sum(pos=='t')>0
yt = y;
yb = y - h;
elseif sum(pos=='m')>0
yt = y + h/2;
yb = y - h/2;
elseif sum(pos=='b')>0
yt = y + h;
yb = y;
else
yt = NaN;
yb = NaN;
return;
end
xlr = [xl xr];
ytb = [yt yb];
end
% ====================================================================