Since you want the animation to have explanatory content, I thought it might be best to incorporate the explanatory 2D diagram into the 3D scene.
So I imagine the 2D plot as a "sticker" that can be put onto the cylinder, like a label on a bottle. That way, you can see the explanatory diagram itself wrap around the cylinder and become identical to the solution:
length = 12;
circumference = 4;
radius = circumference/(2 Pi);
s[x_] := Piecewise[{{4 Mod[x, 3]/3,
EvenQ[Quotient[x, 3]]}, {4 Mod[x, 3]/3, True}}]
plot = Plot[s[x], {x, 0, 12}, ExclusionsStyle -> Dashed,
Epilog -> {{Green, Arrowheads[{-0.03, 0.03}],
Arrow[{{0, 0.1}, {3, 0.1}}], Text["3 cm", {1.5, 0.2}]}, {Purple,
Arrowheads[{-0.03, 0.03}], Text["4 cm", {3.7, 2}],
Arrow[{{3.2, 0}, {3.2, 4}}], Text["3 cm", {1.5, 0.2}]}, {Orange,
Arrowheads[{-0.03, 0.03}], Arrow[{{-0.2, 0}, {2.8, 4}}],
Text["5 cm", {1, 2.2}]}}, Axes -> None, Frame -> None,
BaseStyle -> {Thick, Larger}, Background -> LightYellow,
ImageSize -> 400, AspectRatio -> circumference/length,
ImagePadding -> 0, PlotRangePadding -> 0, FrameTicks -> None];
openPrism[pts_List, h_] := Module[
{bottoms, tops, surfacePoints, sidePoints, n},
surfacePoints = Table[
Map[PadRight[#, 3, height] &, pts], {height, {0, h}}];
{bottoms, tops} = {Most[#], Rest[#]} &@surfacePoints;
sidePoints =
Most@Flatten[{bottoms, RotateLeft[bottoms, {0, 1}],
RotateLeft[tops, {0, 1}], tops}, {{2, 3}, {1}}];
n = Length[sidePoints];
MapThread[
Polygon[#1, VertexNormals -> (#1 - #2),
VertexTextureCoordinates -> #3] &,
{sidePoints,
Map[{0, 0, 1} # &, sidePoints, {2}],
Table[{{i/n, 0}, {(i + 1)/n, 0}, {(i + 1)/n, 1}, {i/n, 1}}, {i, 0,
n - 1}]
}]
]
openCyl[{pt1_, pt2_}, r_, {θ1_, θ2_}, n_: 90] :=
Module[{circle =
r Table[{Cos[ϕ],
Sin[ϕ]}, {ϕ, θ1, θ2, (θ2 - θ1)/n}],
h = EuclideanDistance[pt1, pt2]},
GeometricTransformation[openPrism[circle, h],
Composition[TranslationTransform[pt1],
Quiet[Check[RotationTransform[{{0, 0, 1.}, pt2 - pt1}],
Identity]]]]]
img = Rasterize[Rotate[plot, 90 Degree], ImageSize -> 500];
Manipulate[
With[{r = radius + x^2},
Graphics3D[{{Opacity[.7], Specularity[White, 20], Darker[Red],
Cylinder[{{0, 0, -1}, {0, 0, 13}}, .99 radius]},
{FaceForm[Texture[img], Gray], EdgeForm[],
openCyl[{{radius - r, 0, 0}, {radius - r, 0, 12}},
r, {0, 2 Pi radius/r}]}}, Boxed -> False,
Lighting -> "Neutral", ViewPoint -> {4, -2, -4},
ViewVertical -> {0, -1, 0}, SphericalRegion -> True]],
{x, 0, 5}
]
What I did here is modify another answer to How to add texture to solid Graphics3D object such as cylinder? in such a way that the cylinder can be open, by adding the ability to specify an angle interval.
The 2D diagram is rasterized and used as a Texture
, inside FaceForm
so that I can make the back of the label gray (you only see that if you do a 3D rotation - the ViewPoint
by default is chosen so as to show only the front of the label).
Edit
In this animation, the wrapped label is created with the function
openCyl[{pt1, pt2}, r, {θ1, θ2}, n]
It creates a cylindrically warped polygon by extruding a circle segment of radius r
beginning at polar angle θ1
and ending at polar angle θ2
. The orientation and height of this partial cylinder is dictated by {pt1, pt2}
which is a pair of three-dimensional points that form the beginning and end of the cylinder axis. The last argument n
is optional and defines the number of polygons along the side wall.
Speed considerations
The Manipulate
as defined above runs completely smoothly on my laptop with Mathematica version 8, but it's choppy in version 10. To make the animation more responsive if necessary, here are three methods:
The easiest speed improvement is to decrease the number of polygons in openCyl
from its default value 90
to a smaller number, e.g., 30
. This will still give a smooth display because openCyl
creates the warped polygon with VertexNormals
that allow the rendering engine to give the illusion of a smooth surface. With fewer polygons, the rendering speed goes up.
For any kind of animation involving only a single parameter (like the "wrapping stage" x
here), Manipulate
is usually overkill because Animate
and ListAnimate
allow you to explore a one-parameter family of plots equally well. When the drawing of each frame is sluggish, it's better to create the frames as a List
beforehand, and then feed it into ListAnimate
to do the actual animation of the pre-computed frames.
Another factor that can improve the responsiveness is to decrease the ImageSize
in the texture img
from 500
to a smaller value like 200
. I chose a large ImageSize
to get a smoothly rendered texture, but there's always a tradeoff between quality and speed.