{ "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": [ "
Manim Community v0.15.0\n",
       "\n",
       "
\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": [ "" ], "text/plain": [ "" ] }, "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": [ "" ], "text/plain": [ "" ] }, "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": [ "" ], "text/plain": [ "" ] }, "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": [ "" ], "text/plain": [ "" ] }, "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": [ "" ], "text/plain": [ "" ] }, "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": [ "" ], "text/plain": [ "" ] }, "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 }