Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Animating a tumbling polygon
(* ::Package:: *)
(* ::Title:: *)
(*Animating a tumbling polygon*)
(*
See <https://mathematica.stackexchange.com/a/237847>.
Licensed under MIT No Attribution (MIT-0),
see <https://spdx.org/licenses/MIT-0.html>.
*)
(* ::Section:: *)
(*Initial vertices*)
ClearAll["Global`*"];
(* Original post *)
vertexInitialPositions = Complex @@@ {
{-Sqrt[2]/2, -Sqrt[6]/2},
{Sqrt[2]/2, -Sqrt[6]/2},
{Sqrt[2]/2, Sqrt[2] - Sqrt[6]/2},
{-Sqrt[2]/2, Sqrt[2] - Sqrt[6]/2},
Nothing
};
(* Quadrilateral but not a rectangle *)
(*vertexInitialPositions = Complex @@@ {
{0.3 * -Sqrt[2]/2, -Sqrt[6]/2},
{Sqrt[2]/2, -Sqrt[6]/2},
{1.3 * Sqrt[2]/2, Sqrt[2] - Sqrt[6]/2},
{-Sqrt[2]/2, 0.5 * -Sqrt[6]/2},
Nothing
};*)
(* For profile page *)
(*vertexInitialPositions = Complex @@@ {
{1, -0.8},
{0.5, 0.3},
{-0.25, 0.5},
{-0.65, 0.2},
{-0.8, -1},
Nothing
};*)
vertexCount = Length[vertexInitialPositions];
(* ::Section:: *)
(*Equations of motion*)
vertexRotationEquations =
Table[z[i]'[phi] == I (z[i][phi] - p[phi]), {i, vertexCount}];
pivotFixtureEquation = p'[phi] == 0;
vertexInitialConditions =
Table[z[i][0] == vertexInitialPositions[[i]], {i, vertexCount}];
pivotInitialCondition = p[0] == First[vertexInitialPositions];
(* ::Section:: *)
(*Collision handling*)
boundingRadius = Sqrt[2];
collisionHandling =
Table[
whenEventDummy[
(* If this vertex isn't pivot AND goes outside bounding circle *)
z[i][phi] != p[phi] && Abs @ z[i][phi] > boundingRadius,
(* Set the pivot to this vertex *)
p[phi] -> z[i][phi]
]
, {i, vertexCount}
] /. {whenEventDummy -> WhenEvent};
(* ::Section:: *)
(*Equation solving*)
dependentVariables = Table[z[i], {i, vertexCount}] // Append[p];
(* Original post *)
phiMax = Pi;
(* Quadrilateral but not a rectangle *)
(*phiMax = 2 Pi;*)
(* For profile page *)
(*phiMax = 2 Pi;*)
trajectories =
NDSolveValue[
Flatten @ {
vertexRotationEquations, pivotFixtureEquation,
vertexInitialConditions, pivotInitialCondition,
collisionHandling
},
dependentVariables,
{phi, 0, phiMax}
];
(* ::Section:: *)
(*Visualise*)
vertexRealTrajectories[phi_] :=
Most[trajectories][phi] // Through // ReIm // Evaluate;
frame[phi_] :=
Show[
Graphics @ Circle[{0, 0}, boundingRadius],
Graphics @ Polygon @ vertexRealTrajectories[phi],
If[phi == 0, {},
ParametricPlot[
vertexRealTrajectories[phiDummy] // Evaluate
, {phiDummy, 0, phi}
]
]
, ImageSize -> 240
];
Manipulate[frame[phi], {phi, 0, phiMax}]
(* ::Section:: *)
(*Export animation*)
frameCount = 64;
angularSpeed = 1.25; (* radians per second *)
frameDurations = phiMax / frameCount / angularSpeed;
frameList =
Table[
Show[frame[phi], ImageSize -> 120]
, {phi, Subdivide[phiMax, frameCount]}
];
Export["animation.gif", frameList
, AnimationRepetitions -> Infinity
, "DisplayDurations" -> frameDurations
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment