Contents
球面上の三角形の面積
理屈は考えず、公式集の結果だけを使います。 http://hooktail.sub.jp/vectoranalysis/SphereTriangle/ などを参考にしました。 原点をOとし、半径1の球面上の点A、B、Cがあり、∠AOBをc、∠AOCをb、∠BOCをaとします。 球面上の∠BAC(内角)をαとし、平面AOBと平面AOCの為す角とします。 平面AOBの平面AOCの為す角は平面AOBと平面AOCの法線の為す角とします。 平面AOCの単位法線はOAとOCの外積の規格化したものとします。
figure('color',[1,1,1],'position',[50,50,200,100]); st='$$\frac{\vec{OA}\times\vec{OC}}{|\vec{OA}\times\vec{OC}|}$$'; text(0,0.5,st,'interpreter','latex','Fontsize',18); axis off;
平面AOBの単位法線はOAとOBの外積を規格化したものとします。
figure('color',[1,1,1],'position',[50,50,200,100]); st='$$\frac{\vec{OA}\times\vec{OB}}{|\vec{OA}\times\vec{OB}|}$$'; text(0,0.5,st,'interpreter','latex','Fontsize',18); axis off;
内角BACは平面AOCと平面AOBの法線の為す角ということで内積を用います。 外積と内積の公式を使ってカッコを展開します。
close all; figure('color',[1,1,1],'position',[50,50,650,200]); st1='$$\cos\alpha=\frac{\vec{OA}\times\vec{OC}}{|\vec{OA}\times\vec{OC}|}\cdot\frac{\vec{OA}\times\vec{OB}}{|\vec{OA}\times\vec{OB}|}$$'; st2='$$=\frac{(\vec{OA}\cdot\vec{OA})(\vec{OC}\cdot\vec{OB})-(\vec{OC}\cdot\vec{OA})(\vec{OA}\cdot\vec{OB})}{|\vec{OA}\times\vec{OC}||\vec{OA}\times\vec{OB}|}$$'; text(-0.1,0.75,st1,'interpreter','latex','Fontsize',18); text(0.02,0.25,st2,'interpreter','latex','Fontsize',18); axis off;
半径は1なので外積はsinだけとなり、絶対値のところは以下のようにかけます。
figure('color',[1,1,1],'position',[50,50,350,150]); st1='$$|\vec{OA}\times\vec{OC}|=\sin b$$'; st2='$$|\vec{OA}\times\vec{OB}|=\sin c$$'; st3='$$|\vec{OB}\times\vec{OC}|=\sin a$$'; text(0,0.8,st1,'interpreter','latex','Fontsize',18); text(0,0.5,st2,'interpreter','latex','Fontsize',18); text(0,0.2,st3,'interpreter','latex','Fontsize',18); axis off;
内積・外積をcos、sinで書き換えます。
figure('color',[1,1,1],'position',[50,50,350,100]); st='$$\cos\alpha=\frac{\cos a -\cos b \cos c}{\sin b \sin c}$$'; text(0,0.5,st,'interpreter','latex','Fontsize',18); axis off;
球面上の三角形の面積Sは、内角をα、β、γ、半径をRとすると以下の公式が使えます。
figure('color',[1,1,1],'position',[50,50,350,100]); st='$$S=R^2(\alpha+\beta+\gamma-\pi)$$'; text(0,0.5,st,'interpreter','latex','Fontsize',18); axis off;
半径1のときの球面上の3点ABCが為す三角形の面積は以下の通りになります。
close all; figure('color',[1,1,1],'position',[50,50,1000,200]); st1='$$S=\cos^{-1}\alpha+\cos^{-1}\beta+\cos^{-1}\gamma-\pi$$'; st2='$$=\cos^{-1}\frac{\cos a - \cos b \cos c}{\sin b \sin c}+\cos^{-1}\frac{\cos b - \cos c \cos a}{\sin c \sin a}+\cos^{-1}\frac{\cos c - \cos b \cos a}{\sin a \sin b}-\pi$$'; text(-0.1,0.75,st1,'interpreter','latex','Fontsize',18); text(-0.07,0.25,st2,'interpreter','latex','Fontsize',18); axis off;
メッシュの内外判定
ある点が三角メッシュの内か外かの判定は、その点を中心とした各三角メッシュの立体角の総和が±4π,±12π,±20π・・・かどうかとなります。 MATLABにあるmriファイルで試してみます。 isosurface関数を使ってメッシュを作成しますが、そのままだとメッシュが閉じてくれないので、蓋を作るべく、上下にゼロ行列を挿入します。
clear;close all; load mri; D=squeeze(D); D0=repmat(uint8(0),[siz(1),siz(2),1]); D=cat(3,D0,D,D0); hmesh=isosurface(D,1); hmesh=reducepatch(hmesh,5000); hmesh.vertices(:,3)=hmesh.vertices(:,3)*2.5; figure('color',[1,1,1]); hskull=patch(hmesh,'edgecolor','none','facecolor',[1,0.5,0.5]); set(hskull,'facealpha',0.1);hold on; daspect([1,1,1]); axis off;axis tight; rotate3d on;view([40,25]);
1cmおきに格子点を設け、メッシュの内外判定を行い、メッシュの内側だけ表示させます。
sg=10; limx=round(xlim/sg)*sg; limy=round(ylim/sg)*sg; limz=round(zlim/sg)*sg; limx=min(limx):sg:max(limx); limy=min(limy):sg:max(limy); limz=min(limz):sg:max(limz); [x,y,z]=meshgrid(limx,limy,limz); P=[x(:),y(:),z(:)]; S=zeros(size(P,1),1); N=size(P,1); pt=1:N; nv=size(hmesh.vertices,1); for n=1:N p=hmesh.vertices-ones(nv,1)*P(n,:); p=p./(sum(p.^2,2).^0.5*ones(1,3)); p1=p(hmesh.faces(:,1),:); p2=p(hmesh.faces(:,2),:); p3=p(hmesh.faces(:,3),:); ang1=acos(sum(p1.*p2,2)); ang2=acos(sum(p2.*p3,2)); ang3=acos(sum(p3.*p1,2)); ca1=cos(ang1);sa1=sin(ang1); ca2=cos(ang2);sa2=sin(ang2); ca3=cos(ang3);sa3=sin(ang3); s=acos((ca1-ca2.*ca3)./(sa2.*sa3))+acos((ca2-ca3.*ca1)./(sa3.*sa1))+acos((ca3-ca2.*ca1)./(sa1.*sa2))-pi; s=sum(s)/pi; S(n)=s; if s<3.95 pt(n)=0; end; end; pt(pt==0)=[]; plot3(P(pt,1),P(pt,2),P(pt,3),'b.'); daspect([1,1,1]);view([40,25]); rotate3d on;
頭皮メッシュから仮想球を作成
頭皮メッシュから仮想球を作成します。
figure('color',[1,1,1],'position',[50,50,500,50]); st='$$x^2+y^2+z^2+ax+by+cz+d=0$$'; text(-0.1,0.5,st,'interpreter','latex','fontsize',18);axis off;
%という球を仮定します。変形します。 figure('color',[1,1,1],'position',[50,50,500,50]); st='$$ax+by+cz+d=-(x^2+y^2+z^2)$$'; text(-0.1,0.5,st,'interpreter','latex','fontsize',18);axis off;
%x,y,zは頭皮の座標になります。a,b,c,dは行列の割り算で簡単に求まります。 % 球の中心は figure('color',[1,1,1],'position',[50,50,200,100]); st='$$\left(-\frac{a}{2},-\frac{b}{2},-\frac{c}{2}\right)$$'; text(-0.1,0.5,st,'interpreter','latex','fontsize',18);axis off;
となります。また半径は
figure('color',[1,1,1],'position',[50,50,300,100]); st='$$\sqrt{\frac{a^2}{4}+\frac{b^2}{4}+\frac{c^2}{4}-d}$$'; text(-0.1,0.5,st,'interpreter','latex','fontsize',18);axis off;
となります。 実際に試してみます。
figure('color',[1,1,1]); p=hmesh.vertices; plot3(p(:,1),p(:,2),p(:,3),'r.');hold on; axis equal;axis tight;axis off; q=[p,ones(size(p,1),1)]\(-sum(p.^2,2)); c0=-q(1:3)/2; r=sqrt(sum(c0.^2)-q(4)); [sx,sy,sz]=sphere(20); sx=sx*r+c0(1); sy=sy*r+c0(2); sz=sz*r+c0(3); h0=surf(sx,sy,sz,'facecolor',[1,1,0],'facealpha',0.2,'edgecolor','none'); rotate3d on;