邪恶的GFW,你就饶了我吧:(

2014-12-27

如何制作带投影的3D图

1Matlab
Matlab已经考虑到了制作带投影的3D图的需求,提供了专门函数,只需要用surfc/meshc代替surf/mesh即可。
如:
[X,Y] = meshgrid(-3:.1:3);
Z=peaks(X,Y);
figure;
subplot(2,2,1);surf(Z);
subplot(2,2,2);mesh(Z);
subplot(2,2,3);surfc(Z);
subplot(2,2,4);meshc(Z);
则得到:


2Mathematica
Mathematica没有像Matlab那样提供直接的函数带投影的3D图,因此需要一些技巧。

2.1、利用纹理
思路:生成函数的投影图后作为纹理植入3D空间,然后与函数图共同显示
peaks[x_,y_]=3(1-x)^2*E^(-x^2-(y+1)^2)-10(x/5-x^3-y^5)*E^(-x^2-y^2)-1/3*E^(-(x+1)^2-y^2)
xLim = 3.0;
yLim = 4.0;
zPos = -10.0;
p3D = Plot3D[peaks[x, y], {x, -xLim, xLim}, {y, -yLim, yLim}, PlotRange -> All]
con = ContourPlot[peaks[x, y], {x, -xLim, xLim}, {y, -yLim, yLim}, PlotRangePadding -> 0]
tex = Texture[con];
reg = {{-xLim, -yLim, zPos}, {xLim, -yLim, zPos}, {xLim, yLim, zPos}, {-xLim, yLim, zPos}};
vtc = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
c3D = Graphics3D[{tex, Polygon[reg, VertexTextureCoordinates -> vtc]}];
Show[p3D, c3D]




2.2、提取“等高线”的坐标
conPt = Append[#, zPos] & /@ con[[1, 1]];
conLn = Cases[con, Line[l_], Infinity];
con3D = Graphics3D[GraphicsComplex[conPt, conLn]];
Show[p3D, con3D]


投影目前只是“线划图”如果想得到上面那样的“渲染图”,需要将Line替换成Polygon,并用FaceForm着色。
这种方法需要对Graphics的结构有深入了解,而且由于Mathematica并没有公开Graphics的结构,其在不同版本间可能有变化,因此程序的兼容性并不好,不推荐。

2.3、将3D实体压成一个薄面
XY平面投影:
p3D /. Graphics3D[gr_, opts___] :>
  Graphics3D[{gr, Scale[gr, {1, 1, 1/5}, {0, 0, zPos}]}, opts]
此时XY平面的投影并不清晰,需要利用Mesh等对Plot3D进行调整后才有较好效果。

进一步,3个平面同时投影:
p3D /. Graphics3D[gr_, opts___] :>
  Graphics3D[{gr, Scale[gr, {1, 1, 1/5}, {0, 0, zPos}],
    Scale[gr, {1/100, 1, 1}, {-xLim, 0, 0}],
    Scale[gr, {1, 1/100, 1}, {0, -yLim, 0}]}, opts]


3MatlabMathematica解决方案的简单比较
乍看上去,Matlab的解决方案比Mathematica简单,但Mathematica由于提供了底层函数Graphics3D使得方法较为灵活,比如当需要3面投影时,Mathematica稍作扩展即可,我不知道Matlab是否能做到这一点。

4、需要改进之处
A、节2.1中的程序在Mathematica 9中运行良好,但在Mathematica 10中总是崩溃,需要进一步9
B、节2.3中的程序在XY平面的效果糟糕,难道一定需要“条带”有无其它方法

5、致谢
本文主要参考了StackExchange.comVitaliy KaurovMatariki两人的精彩答案,具体参见:
http://mathematica.stackexchange.com/questions/14863/placing-a-contourplot-under-a-plot3d/
我针对主题做了大量简化,主要是去除了调色等一系列细节,所以图形显得单调,而Vitaliy Kaurov做的图很漂亮喔!


修订2014-12-28:Plot3D加上MeshFunctions->{#3&},则节4中,B的问题就解决了,如下图所示:


修订2015-01-02:
1、为方便应用,peaks的定义用文本而不是图给出
2、提取点语句中应该是con[[1, 1]],误为con[1, 1]]


No comments: