How to plot contours on the faces of a cube
Yet another method:
Let us calculate values of function on appropriate rectangular grids, which we will convert to textures (1 pixel = 1 value). Interpolation between pixels is built-in.
f = 2 #1^2 + 2 #2^2 + #3^2 + #1 #2 &;
PolyhedronData["Cube"] // N // Normal // toTriangles //
texturize[f, 50, Hue, Lighting -> "Neutral", Axes -> True]
Here Normal
convert GraphicsComplex
to separate polygons, toTriangles
split polygons to triangles, and texturize
put textures on every triangle (f
assumed to be Listable
)
toTriangles = # /. Polygon[v_ /; Length[v] > 3] :> (Polygon@Append[#, Mean[v]] & /@
Partition[v, 2, 1, 1]) &;
texturize[f_, n_, colf_, opts : OptionsPattern[]] := # /.
Polygon[{v1_, v2_, v3_}] :> {EdgeForm[],
Texture@ImageData@Colorize[Image@
f[v3[[1]] + (v1[[1]] - v3[[1]]) #1 + (v2[[1]] - v3[[1]]) #2,
v3[[2]] + (v1[[2]] - v3[[2]]) #1 + (v2[[2]] - v3[[2]]) #2,
v3[[3]] + (v1[[3]] - v3[[3]]) #1 + (v2[[3]] - v3[[3]]) #2] &
[#, Transpose[#]] &@
ConstantArray[Range[-1./n, 1 + 1/n, 1./n], n + 3],
ColorFunction -> colf, ColorFunctionScaling -> False],
Polygon[{v1, v2, v3}, VertexTextureCoordinates -> {{1 - 1.5/(n+3), 1 - 1.5/(n+3)},
{1.5/(n+3), 1.5/(n+3)}, {1.5/(n+3), 1 - 1.5/(n+3)}}]} /.
Graphics3D[data__] :> Graphics3D[data, opts] &;
It is really fast because it uses packed arrays (almost 100 times faster the belisarius's rasterization of DensityPlot
)!
Moreover, it is applicable to arbitrary complex mesh:
PolyhedronData["MathematicaPolyhedron"] // N // Normal // toTriangles //
texturize[0.7 (#1^2 + #2^2 + #3^2) &, 50, Hue, Lighting -> "Neutral", Boxed -> False]
To obtain "contours" one can use simple discretization with bigger number of points (sometimes it can be faster then ContourPlot
):
f = Floor[2 #1^2 + 2 #2^2 + #3^2 + #1 #2, .1] &;
PolyhedronData["Cube"] // N // Normal // toTriangles //
texturize[f, 200, Hue, Lighting -> "Neutral", Axes -> True]
The same with the simple cut
Graphics3D[
GraphicsComplex[
Tuples[{-0.5, 0.0, 0.5}, 3], {Polygon[{1, 3, 9, 7}],
Polygon[{1, 3, 21, 19}], Polygon[{1, 7, 25, 19}],
Polygon[{19, 21, 24, 23}], Polygon[{19, 25, 26, 23}],
Polygon[{7, 25, 26, 17}], Polygon[{7, 9, 18, 17}],
Polygon[{3, 9, 18, 15}], Polygon[{3, 21, 24, 15}],
Polygon[{23, 14, 15, 24}], Polygon[{23, 14, 17, 26}],
Polygon[{15, 14, 17, 18}]}]] // N // Normal // toTriangles //
texturize[f, 100, Hue, Lighting -> "Neutral", Axes -> True]
One can also use MeshFunctions
:
Clear[f];
f = {x, y, z} \[Function] x + Sin[5 z] + y^2;
cube = PolyhedronData["Cube", "RegionFunction"];
mesh = 15;
RegionPlot3D[cube[x/2, y/2, z/2],
{x, -1, 1}, {y, -1, 1}, {z, -1, 1},
MeshFunctions -> {f}, Mesh -> mesh,
MeshShading -> ColorData["Rainbow"] /@ Range[0, 1, 1/(mesh + 1)],
PlotPoints -> 50, Lighting -> "Neutral"]
@ybeltukov discovered that the region expression can simply be True
, if the region is the same as the plot region -- neat!:
RegionPlot3D[True,
{x, -1, 1}, {y, -1, 1}, {z, -1, 1},
MeshFunctions -> {f}, Mesh -> mesh,
MeshShading -> ColorData["Rainbow"] /@ Range[0, 1, 1/(mesh + 1)]]
Another way using textures:
v = {{-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {-1, 1, -1}, {-1, -1, 1}, {1, -1, 1},
{1, 1, 1}, {-1, 1, 1}};
idx = {{1, 2, 3, 4}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 4, 8, 7}, {4, 1, 5, 8}, {5, 6, 7, 8}};
vtc = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
f[{x_, y_, z_}] := x^2 - y^2 - z^2
q[j_] := MapThread[ Prepend, {{Min@#, Max@#} & /@ Transpose@v[[idx[[j]]]], {x, y, z}}]
ranges[i_] := DeleteCases[q[i], {s_, a_, a_}]
anchoredVars[i_] := Cases[q[i], {s_, a_, a_} :> s -> a]
sides = Table[ Rasterize@ ContourPlot[f[{x, y, z}] /. anchoredVars[i],
Evaluate[Sequence @@ ranges[i]], Frame -> False, ColorFunction -> Hue,
ColorFunctionScaling -> False, Method -> {"ShrinkWrap" -> True}], {i, 6}];
Graphics3D[{Black, EdgeForm[None],
Table[{Texture[sides[[i]]],
GraphicsComplex[v, Polygon[idx[[i]], VertexTextureCoordinates -> vtc]]}, {i, 6}]},
Boxed -> False, Method -> {"RotationControl" -> "Globe"}]
Edit
If you want to use DensityPlot instead of ContourPlot, with PlotPoints->100 you get: