MATLAB | 一文解决各类曲面交线绘制,包含三维隐函数曲面交线
Posted slandarer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MATLAB | 一文解决各类曲面交线绘制,包含三维隐函数曲面交线相关的知识,希望对你有一定的参考价值。
本文很自然的分成了三部分两显函数交线
,显函数与隐函数交线
,两隐函数交线
,对于解析解较难表示的函数,以下给出各种情况数值解求法及交线绘制方法:
两显函数交线
这是最简单的一部分,只需要两个显函数相减,使用三维等高线函数contour3
获取两显函数相减的0等高线数据,再绘图即可:
% 显函数绘制曲面交线
[X,Y]=meshgrid(-2:.1:2);
Z1=5-2.*X-1.5.*Y;
Z2=X.^2+Y.^2;
% 绘制曲面
surf(X,Y,Z1,'EdgeColor','none','FaceAlpha',0.5,'FaceColor',[82,124,179]./255)
hold on
surf(X,Y,Z2,'EdgeColor','none','FaceAlpha',0.5,'FaceColor',[169,64,71]./255)
% 求出交线数值解并绘图
Z3=Z1-Z2;
CXY=contour3(X,Y,Z3,[0,0],'Visible','off');
CX=CXY(1,2:end);
CY=CXY(2,2:end);
% 以下两种方式均可,用任意显函数均可
plot3(CX,CY,5-2.*CX-1.5.*CY,'LineWidth',2,'Color',[0,0,0])
% plot3(CX,CY,CX.^2+CY.^2,'LineWidth',2,'Color',[0,0,0])
view(60,14)
显函数与隐函数交线
这个也有很有意思的函数可以处理,contourslice
函数可以在任意三维切片或者三维曲面上绘制等高线,我们使用三维隐函数提供三维体数据,获取该数据体在显函数曲面上的0等高线即可:
% 显函数与隐函数绘制曲面交线
f1=@(x,y,z)5-2.*x-1.5.*y-z;
f2=@(x,y,z)x.^2+y.^2+z.^2-12;
[X,Y]=meshgrid(-3:.1:4);
Z1=5-2.*X-1.5.*Y;
% 绘制曲面
surf(X,Y,Z1,'EdgeColor','none','FaceAlpha',0.5,'FaceColor',[82,124,179]./255)
hold on;
fimplicit3(f2,'EdgeColor','none','FaceAlpha',0.5,'FaceColor',[169,64,71]./255)
% 通过切片contour函数获取0等势面
[CX,CY,CZ]=meshgrid(-3:.1:4);
CV=f1(CX,CY,CZ)-f2(CX,CY,CZ);
S=contourslice(CX,CY,CZ,CV,X,Y,Z1,[0,0]);
S.EdgeColor=[0,0,0];
S.LineWidth=2;
两隐函数交线
这个就贼麻烦了,因为没有显函数提供显式曲面,因此contourslice
函数无法使用,而isosurface
返回形式为三角面而不是折线段,绘制效果会非常粗糙:
因此需要提出新的方案,查阅了一些资料,发现大佬Mike Garrity
在给出了一个对于:
y
−
x
tan
(
z
)
=
0
x
2
+
y
2
=
1
\\begincases y-x\\tan(z)=0\\\\ x^2+y^2=1 \\endcases
y−xtan(z)=0x2+y2=1
问题求隐函数交线有了非常详解的解答,详细内容请查看:https://blogs.mathworks.com/graphics/2015/07/22/implicit-surface-intersections/?from=cn
本人对其给出的代码进行了微调,制作工具函数使其能应对大部分隐函数:
function [nX,nY,nZ]=isocurve3(X,Y,Z,f1,f2)
% 获取f1隐函数的三角面和三角顶点
V1=f1(X,Y,Z);
hel=isosurface(X,Y,Z,V1,0);
% 将f1获取的三角顶点带入f2求得数值
V2=f2(hel.vertices(:,1),hel.vertices(:,2),hel.vertices(:,3));
% 检查三个顶点的数值是否同时含有有大于0数值及小于0数值
mask=V2>0;
outcount=sum(mask(hel.faces),2);
cross=(outcount==2)|(outcount==1);
crossing_tris=hel.faces(cross,:);
% 通过旋转交换三个顶点次序,将小于0的点放在第一列
out_vert=mask(crossing_tris);
flip=sum(out_vert,2)==1;
out_vert(flip,:)=1-out_vert(flip,:);
ntri=size(out_vert,1);
overt=zeros(ntri,3);
for i=1:ntri
v1i=find(~out_vert(i,:));
v2i=1+mod(v1i,3);
v3i=1+mod(v1i+1,3);
overt(i,:)=crossing_tris(i,[v1i v2i v3i]);
end
% 类似于求重心
u=(-V2(overt(:,1)))./(V2(overt(:,2))-V2(overt(:,1)));
v=(-V2(overt(:,1)))./(V2(overt(:,3))-V2(overt(:,1)));
uverts=repmat((1-u),[1 3]).*hel.vertices(overt(:,1),:)+repmat(u,[1 3]).*hel.vertices(overt(:,2),:);
vverts=repmat((1-v),[1 3]).*hel.vertices(overt(:,1),:)+repmat(v,[1 3]).*hel.vertices(overt(:,3),:);
% 因为可能含有多条曲线,因此逐段连线
nX=nan(3,ntri);
nX(1,:)=uverts(:,1)';
nX(2,:)=vverts(:,1)';
nY=nan(3,ntri);
nY(1,:)=uverts(:,2)';
nY(2,:)=vverts(:,2)';
nZ=nan(3,ntri);
nZ(1,:)=uverts(:,3)';
nZ(2,:)=vverts(:,3)';
end
调用函数求解交线示例(注意返回值应使用line
函数而非plot
函数绘制直线):
f1=@(x,y,z)x.^2+y.^2-z.^2;
f2=@(x,y,z)x.^2+1.5*y.^2+z.^2-12;
% 绘制曲面
fimplicit3(f1,'EdgeColor','none','FaceAlpha',0.5,'FaceColor',[82,124,179]./255)
hold on;
fimplicit3(f2,'EdgeColor','none','FaceAlpha',0.5,'FaceColor',[169,64,71]./255)
[X,Y,Z]=meshgrid(-5:.1:5);
[nX,nY,nZ]=isocurve3(X,Y,Z,f1,f2);
line(nX(:),nY(:),nZ(:),'LineWidth',2,'Color',[0,0,0]);
以上是关于MATLAB | 一文解决各类曲面交线绘制,包含三维隐函数曲面交线的主要内容,如果未能解决你的问题,请参考以下文章