You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
508 lines
15 KiB
508 lines
15 KiB
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "substantial-impact",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Vítej!"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "first-armenia",
|
|
"metadata": {},
|
|
"source": [
|
|
"Tento dokument obsahuje zdrojové kódy animací k páté sérii seriálu KSP. Před spouštěním opět nezapomeň Manim importovat spuštěním následujícího řádku!"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "e03b150c",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Manim Community <span style=\"color: #008000; text-decoration-color: #008000\">v0.15.0</span>\n",
|
|
"\n",
|
|
"</pre>\n"
|
|
],
|
|
"text/plain": [
|
|
"Manim Community \u001b[32mv0.\u001b[0m\u001b[32m15.0\u001b[0m\n",
|
|
"\n"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"from manim import *"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "5bd0ac2f",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Vlastní animace"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "01394a96",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" \r"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<video src=\"media/jupyter/StarFox@2022-05-01@14-58-31.mp4\" controls autoplay loop style=\"max-width: 60%;\" >\n",
|
|
" Your browser does not support the <code>video</code> element.\n",
|
|
" </video>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Video object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"%%manim -v WARNING -qh --disable_caching StarFox\n",
|
|
"# POZOR! Při změnách musíme opět zakázat cachování\n",
|
|
"# (Manim při změně animace nepozná změnu ve scéně)\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"class Roll(Animation):\n",
|
|
" \"\"\"Animace, která otočí objekt o daný úhel, trochu ho při tom zmenší a posune se do strany.\"\"\"\n",
|
|
" \n",
|
|
" def __init__(self, mobject: Mobject, angle, direction, scale_ratio=0.85, **kwargs):\n",
|
|
" \"\"\"Konstruktor. Inicializuje potřebné věci animace.\"\"\"\n",
|
|
" # bude se nám hodit původní verze objektu, který animujeme\n",
|
|
" # (v animaci ho otiž budeme měnit)\n",
|
|
" self.original = mobject.copy()\n",
|
|
" \n",
|
|
" self.scale_ratio = scale_ratio\n",
|
|
" self.angle = angle\n",
|
|
" self.direction = direction\n",
|
|
" \n",
|
|
" super().__init__(mobject, **kwargs)\n",
|
|
"\n",
|
|
" def interpolate_mobject(self, alpha: float) -> None:\n",
|
|
" \"\"\"Funkce, která se volá každý snímek, aby se animace animovala.\"\"\"\n",
|
|
" \n",
|
|
" # alpha je od 0 do 1, ale animace mohla jako parametr dostat rate funkci\n",
|
|
" # proto je třeba tuto funkci na alphu aplikovat, a by se animace chovala správně\n",
|
|
" actual_alpha = self.rate_func(alpha)\n",
|
|
"\n",
|
|
" # chceme, aby objekt měl na začátku scale 1, v půlce scale_ratio a na konci 1\n",
|
|
" # tohle možná není nejelegantnější způsob, ale funguje\n",
|
|
" scale_alpha = 1 - (1 - self.scale_ratio) * 2 * (0.5 - abs(actual_alpha - 0.5))\n",
|
|
" \n",
|
|
" # chceme, aby objekt měl na začátku startovní pozici, pak se posunul a nakonec se vrátil\n",
|
|
" direction_alpha = there_and_back(actual_alpha)\n",
|
|
" \n",
|
|
" self.mobject.become(self.original.copy())\\\n",
|
|
" .rotate(actual_alpha * self.angle)\\\n",
|
|
" .scale(scale_alpha)\\\n",
|
|
" .shift(self.direction * direction_alpha)\n",
|
|
"\n",
|
|
" \n",
|
|
"class Dissolve(AnimationGroup):\n",
|
|
" \"\"\"Animace, která 'zmizí' objekt. Používáme zde AnimationGroup,\n",
|
|
" jelikož animace mizení je tvořena dvěma různými animacemi.\"\"\"\n",
|
|
" \n",
|
|
" def __init__(self, mobject: Mobject, **kwargs):\n",
|
|
" \"\"\"Konstruktor. Inicializuje potřebné věci animace.\"\"\"\n",
|
|
" self.original = mobject.copy()\n",
|
|
" \n",
|
|
" # způsob, jak do animate syntaxu dostaneme argumenty\n",
|
|
" a1 = mobject.animate.scale(0)\n",
|
|
" a2 = Flash(mobject, color=mobject.color)\n",
|
|
" \n",
|
|
" super().__init__(a1, a2, lag_ratio=0.75, **kwargs)\n",
|
|
" \n",
|
|
" \n",
|
|
"class StarFox(Scene):\n",
|
|
" def construct(self):\n",
|
|
" square = Square(color=BLUE, fill_opacity=0.75).scale(1.5)\n",
|
|
" \n",
|
|
" self.play(Roll(square, angle=PI, direction=LEFT * 0.75))\n",
|
|
" self.play(Roll(square, angle=-PI, direction=RIGHT * 0.75))\n",
|
|
" \n",
|
|
" self.play(Dissolve(square))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cb6584c4",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Pluginy"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "226fa759",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Fyzika"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "49f08ea5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from manim_physics import *"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "18742bd7",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" \r"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<video src=\"media/jupyter/FallingObjectsExample@2022-05-01@14-58-40.mp4\" controls autoplay loop style=\"max-width: 60%;\" >\n",
|
|
" Your browser does not support the <code>video</code> element.\n",
|
|
" </video>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Video object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"%%manim -v WARNING -qh FallingObjectsExample\n",
|
|
"\n",
|
|
"\n",
|
|
"# příklad z https://github.com/Matheart/manim-physics\n",
|
|
"# SpaceScene je třída podporující fyzikální interakce\n",
|
|
"class FallingObjectsExample(SpaceScene):\n",
|
|
" def construct(self):\n",
|
|
" circle = Circle().shift(UP)\n",
|
|
" circle.set_fill(RED, 1)\n",
|
|
" circle.shift(DOWN + RIGHT)\n",
|
|
"\n",
|
|
" rect = Square().shift(UP)\n",
|
|
" rect.rotate(PI / 4)\n",
|
|
" rect.set_fill(YELLOW_A, 1)\n",
|
|
" rect.shift(UP * 2)\n",
|
|
" rect.scale(0.5)\n",
|
|
"\n",
|
|
" ground = Line([-4, -3.5, 0], [4, -3.5, 0])\n",
|
|
" wall1 = Line([-4, -3.5, 0], [-4, 3.5, 0])\n",
|
|
" wall2 = Line([4, -3.5, 0], [4, 3.5, 0])\n",
|
|
" walls = VGroup(ground, wall1, wall2)\n",
|
|
" self.add(walls)\n",
|
|
"\n",
|
|
" self.play(\n",
|
|
" DrawBorderThenFill(circle),\n",
|
|
" DrawBorderThenFill(rect),\n",
|
|
" )\n",
|
|
" \n",
|
|
" # až doposud se jednalo o normální Manim kód\n",
|
|
" # nyní použijeme funkce, které objektům přidají fyziku\n",
|
|
" self.make_rigid_body(rect, circle) # čtverec a kruh jsou rigidní (hýbou se)\n",
|
|
" self.make_static_body(walls) # zdi jsou statické (nehýbou jse)\n",
|
|
" \n",
|
|
" # nyní počkáme - funkce výše přidaly objektům updatery\n",
|
|
" self.wait(5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "61d9d3aa",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" \r"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<video src=\"media/jupyter/ElectricFieldExample@2022-05-01@15-17-33.mp4\" controls autoplay loop style=\"max-width: 60%;\" >\n",
|
|
" Your browser does not support the <code>video</code> element.\n",
|
|
" </video>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Video object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"%%manim -v WARNING -qh ElectricFieldExample\n",
|
|
"\n",
|
|
"\n",
|
|
"# zde stačí Scene, protože používáme pouze nové objekty\n",
|
|
"# příklad upravený z https://github.com/Matheart/manim-physics\n",
|
|
"# POZOR: kód trvá postavit opravdu dlouho, doporučuji používat nižší kvalitu\n",
|
|
"class ElectricFieldExample(Scene):\n",
|
|
" def construct(self):\n",
|
|
" charge1 = Charge(-1, LEFT + DOWN)\n",
|
|
" charge2 = Charge(2, RIGHT + DOWN)\n",
|
|
" charge3 = Charge(-1, UP)\n",
|
|
" \n",
|
|
" def rebuild(field):\n",
|
|
" \"\"\"Funkce která přestaví elektrické pole.\"\"\"\n",
|
|
" field.become(ElectricField(charge1, charge2, charge3))\n",
|
|
" \n",
|
|
" field = ElectricField(charge1, charge2, charge3)\n",
|
|
" \n",
|
|
" self.add(field, charge1, charge2, charge3)\n",
|
|
" \n",
|
|
" self.play(Write(field), FadeIn(charge1), FadeIn(charge2), FadeIn(charge3))\n",
|
|
" \n",
|
|
" field.add_updater(rebuild)\n",
|
|
" \n",
|
|
" self.play(\n",
|
|
" charge1.animate.shift(LEFT),\n",
|
|
" charge2.animate.shift(RIGHT),\n",
|
|
" charge3.animate.shift(DOWN * 0.5),\n",
|
|
" run_time=2,\n",
|
|
" )"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "bba36496",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" \r"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<video src=\"media/jupyter/MagnetismExample@2022-05-01@15-24-37.mp4\" controls autoplay loop style=\"max-width: 60%;\" >\n",
|
|
" Your browser does not support the <code>video</code> element.\n",
|
|
" </video>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Video object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"%%manim -v WARNING -qh MagnetismExample\n",
|
|
"\n",
|
|
"\n",
|
|
"# příklad upravený z https://github.com/Matheart/manim-physics\n",
|
|
"# OPĚT POZOR: kód trvá postavit opravdu dlouho, doporučuji používat nižší kvalitu\n",
|
|
"class MagnetismExample(Scene):\n",
|
|
" def construct(self):\n",
|
|
" current1 = Current(LEFT * 2.5)\n",
|
|
" current2 = Current(RIGHT * 2.5, direction=IN)\n",
|
|
" \n",
|
|
" def rebuild(field):\n",
|
|
" \"\"\"Funkce která přestaví magnetické pole.\"\"\"\n",
|
|
" field.become(MagneticField(current1, current2))\n",
|
|
" \n",
|
|
" field = MagneticField(current1, current2)\n",
|
|
" \n",
|
|
" self.play(Write(field), FadeIn(current1), FadeIn(current2))\n",
|
|
" \n",
|
|
" field.add_updater(rebuild)\n",
|
|
" \n",
|
|
" self.play(\n",
|
|
" Rotate(current1, about_point=ORIGIN, angle=PI),\n",
|
|
" Rotate(current2, about_point=ORIGIN, angle=PI),\n",
|
|
" run_time=2,\n",
|
|
" )"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "a63686ae",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" \r"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<video src=\"media/jupyter/Pendulum@2022-05-01@15-24-56.mp4\" controls autoplay loop style=\"max-width: 60%;\" >\n",
|
|
" Your browser does not support the <code>video</code> element.\n",
|
|
" </video>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Video object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"%%manim -v WARNING -qh Pendulum\n",
|
|
"\n",
|
|
"\n",
|
|
"# příklad upravený z https://github.com/Matheart/manim-physics\n",
|
|
"# opět používáme SpaceScene, jelikož animujeme fyzikální interakce\n",
|
|
"class Pendulum(SpaceScene):\n",
|
|
" def construct(self):\n",
|
|
" # pozice kuliček pendula\n",
|
|
" bob_positions = [RIGHT * 1.5 + UP, RIGHT * 1.5 + UP * 2]\n",
|
|
" \n",
|
|
" pendulum = MultiPendulum(\n",
|
|
" *bob_positions,\n",
|
|
" pivot_point=UP,\n",
|
|
" bob_style={\"color\": WHITE, \"fill_opacity\": 1, \"radius\": 0.15},\n",
|
|
" )\n",
|
|
" \n",
|
|
" self.make_rigid_body(pendulum.bobs) # kuličky pendula jsou rigidní\n",
|
|
" pendulum.start_swinging() # a spojené\n",
|
|
" \n",
|
|
" self.add(pendulum)\n",
|
|
" \n",
|
|
" # budeme sledovat cestu obou kuliček\n",
|
|
" for i, bob in enumerate(pendulum.bobs):\n",
|
|
" self.bring_to_back(TracedPath(bob.get_center, stroke_color=DARK_GRAY))\n",
|
|
" \n",
|
|
" self.wait(12)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b1c1214e",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Chemie"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "74825cc6",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from chanim import *"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "af492827",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" \r"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<video src=\"media/jupyter/ChanimExample@2022-05-01@15-24-57.mp4\" controls autoplay loop style=\"max-width: 60%;\" >\n",
|
|
" Your browser does not support the <code>video</code> element.\n",
|
|
" </video>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.Video object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"%%manim -v WARNING -qh ChanimExample\n",
|
|
"\n",
|
|
"\n",
|
|
"class ChanimExample(Scene):\n",
|
|
" def construct(self):\n",
|
|
" # chemická sloučenina\n",
|
|
" # interně využívá ChemFigový syntax (https://www.ctan.org/pkg/chemfig)\n",
|
|
" chem = ChemWithName(\n",
|
|
" \"*6((=O)-N(-CH_3)-*5(-N=-N(-CH_3)-=)--(=O)-N(-H_3C)-)\",\n",
|
|
" \"Caffeine\"\n",
|
|
" )\n",
|
|
" \n",
|
|
" chem.move_to(ORIGIN)\n",
|
|
" \n",
|
|
" self.play(chem.creation_anim())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "b2c6e7b5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.10.2"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|
|
|