._pysketcher003.html 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. <!--
  2. Automatically generated HTML file from DocOnce source
  3. (https://github.com/hplgit/doconce/)
  4. -->
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  8. <meta name="generator" content="DocOnce: https://github.com/hplgit/doconce/" />
  9. <meta name="description" content="Using Pysketcher to Create Principal Sketches of Physics Problems">
  10. <meta name="keywords" content="tree data structure,recursive function calls">
  11. <title>Using Pysketcher to Create Principal Sketches of Physics Problems</title>
  12. <!-- Bootstrap style: bootswatch_readable -->
  13. <link href="http://netdna.bootstrapcdn.com/bootswatch/3.1.1/readable/bootstrap.min.css" rel="stylesheet">
  14. <!-- not necessary
  15. <link href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
  16. -->
  17. <style type="text/css">
  18. /* Add scrollbar to dropdown menus in bootstrap navigation bar */
  19. .dropdown-menu {
  20. height: auto;
  21. max-height: 400px;
  22. overflow-x: hidden;
  23. }
  24. </style>
  25. </head>
  26. <!-- tocinfo
  27. {'highest level': 1,
  28. 'sections': [('A first glimpse of Pysketcher', 1, None, '___sec0'),
  29. ('Basic construction of sketches', 2, None, '___sec1'),
  30. ('Basic drawing', 3, None, '___sec2'),
  31. ('Groups of objects', 3, None, '___sec3'),
  32. ('Changing line styles and colors', 3, None, '___sec4'),
  33. ('The figure composition as an object hierarchy',
  34. 3,
  35. None,
  36. '___sec5'),
  37. ('Animation: translating the vehicle', 3, None, '___sec6'),
  38. ('Animation: rolling the wheels',
  39. 3,
  40. 'sketcher:vehicle1:anim',
  41. 'sketcher:vehicle1:anim'),
  42. ('A simple pendulum',
  43. 1,
  44. 'sketcher:ex:pendulum',
  45. 'sketcher:ex:pendulum'),
  46. ('The basic physics sketch',
  47. 2,
  48. 'sketcher:ex:pendulum:basic',
  49. 'sketcher:ex:pendulum:basic'),
  50. ('The body diagram', 2, None, '___sec10'),
  51. ('Animated body diagram',
  52. 2,
  53. 'sketcher:ex:pendulum:anim',
  54. 'sketcher:ex:pendulum:anim'),
  55. ('Function for drawing the body diagram', 3, None, '___sec12'),
  56. ('Equations for the motion and forces', 3, None, '___sec13'),
  57. ('Numerical solution', 3, None, '___sec14'),
  58. ('Animation', 3, None, '___sec15'),
  59. ('Basic shapes', 1, None, '___sec16'),
  60. ('Axis', 2, None, '___sec17'),
  61. ('Distance with text', 2, None, '___sec18'),
  62. ('Rectangle', 2, None, '___sec19'),
  63. ('Triangle', 2, None, '___sec20'),
  64. ('Arc', 2, None, '___sec21'),
  65. ('Spring', 2, None, '___sec22'),
  66. ('Dashpot', 2, None, '___sec23'),
  67. ('Wavy', 2, None, '___sec24'),
  68. ('Stochastic curves', 2, None, '___sec25'),
  69. ('Inner workings of the Pysketcher tool', 1, None, '___sec26'),
  70. ('Example of classes for geometric objects',
  71. 2,
  72. None,
  73. '___sec27'),
  74. ('Simple geometric objects', 3, None, '___sec28'),
  75. ('Class curve', 3, None, '___sec29'),
  76. ('Compound geometric objects', 3, None, '___sec30'),
  77. ('Adding functionality via recursion', 2, None, '___sec31'),
  78. ('Basic principles of recursion', 3, None, '___sec32'),
  79. ('Explaining recursion', 3, None, '___sec33'),
  80. ('Scaling, translating, and rotating a figure',
  81. 2,
  82. 'sketcher:scaling',
  83. 'sketcher:scaling'),
  84. ('Scaling', 3, None, '___sec35'),
  85. ('Translation', 3, None, '___sec36'),
  86. ('Rotation', 3, None, '___sec37')]}
  87. end of tocinfo -->
  88. <body>
  89. <script type="text/x-mathjax-config">
  90. MathJax.Hub.Config({
  91. TeX: {
  92. equationNumbers: { autoNumber: "none" },
  93. extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
  94. }
  95. });
  96. </script>
  97. <script type="text/javascript"
  98. src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
  99. </script>
  100. <!-- newcommands.tex -->
  101. $$
  102. \newcommand{\half}{\frac{1}{2}}
  103. \newcommand{\tp}{\thinspace .}
  104. \newcommand{\rpos}{\boldsymbol{r}}
  105. \newcommand{\ii}{\boldsymbol{i}}
  106. \newcommand{\jj}{\boldsymbol{j}}
  107. \newcommand{\ir}{\boldsymbol{i}_r}
  108. \newcommand{\ith}{\boldsymbol{i}_{\theta}}
  109. $$
  110. <!-- Bootstrap navigation bar -->
  111. <div class="navbar navbar-default navbar-fixed-top">
  112. <div class="navbar-header">
  113. <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-responsive-collapse">
  114. <span class="icon-bar"></span>
  115. <span class="icon-bar"></span>
  116. <span class="icon-bar"></span>
  117. </button>
  118. <a class="navbar-brand" href="pysketcher.html">Using Pysketcher to Create Principal Sketches of Physics Problems</a>
  119. </div>
  120. <div class="navbar-collapse collapse navbar-responsive-collapse">
  121. <ul class="nav navbar-nav navbar-right">
  122. <li class="dropdown">
  123. <a href="#" class="dropdown-toggle" data-toggle="dropdown">Contents <b class="caret"></b></a>
  124. <ul class="dropdown-menu">
  125. <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec0" style="font-size: 80%;"><b>A first glimpse of Pysketcher</b></a></li>
  126. <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec1" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Basic construction of sketches</a></li>
  127. <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec2" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic drawing</a></li>
  128. <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec3" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Groups of objects</a></li>
  129. <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec4" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Changing line styles and colors</a></li>
  130. <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec5" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The figure composition as an object hierarchy</a></li>
  131. <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec6" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: translating the vehicle</a></li>
  132. <!-- navigation toc: --> <li><a href="._pysketcher002.html#sketcher:vehicle1:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: rolling the wheels</a></li>
  133. <!-- navigation toc: --> <li><a href="#sketcher:ex:pendulum" style="font-size: 80%;"><b>A simple pendulum</b></a></li>
  134. <!-- navigation toc: --> <li><a href="#sketcher:ex:pendulum:basic" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The basic physics sketch</a></li>
  135. <!-- navigation toc: --> <li><a href="#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The body diagram</a></li>
  136. <!-- navigation toc: --> <li><a href="#sketcher:ex:pendulum:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Animated body diagram</a></li>
  137. <!-- navigation toc: --> <li><a href="#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Function for drawing the body diagram</a></li>
  138. <!-- navigation toc: --> <li><a href="#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Equations for the motion and forces</a></li>
  139. <!-- navigation toc: --> <li><a href="#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Numerical solution</a></li>
  140. <!-- navigation toc: --> <li><a href="#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation</a></li>
  141. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec16" style="font-size: 80%;"><b>Basic shapes</b></a></li>
  142. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
  143. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
  144. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
  145. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
  146. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec21" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
  147. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
  148. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
  149. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
  150. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
  151. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec26" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
  152. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
  153. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
  154. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec29" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
  155. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec30" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
  156. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec31" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
  157. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec32" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
  158. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec33" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
  159. <!-- navigation toc: --> <li><a href="._pysketcher005.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
  160. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec35" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
  161. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec36" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
  162. <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec37" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
  163. </ul>
  164. </li>
  165. </ul>
  166. </div>
  167. </div>
  168. </div> <!-- end of navigation bar -->
  169. <div class="container">
  170. <p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p> <!-- add vertical space -->
  171. <a name="part0003"></a>
  172. <!-- !split -->
  173. <h1 id="sketcher:ex:pendulum">A simple pendulum</h1>
  174. <h2 id="sketcher:ex:pendulum:basic">The basic physics sketch</h2>
  175. <p>
  176. We now want to make a sketch of simple pendulum from physics, as shown
  177. in Figure <a href="#sketcher:ex:pendulum:fig1">8</a>. A body with mass \( m \) is attached
  178. to a massless, stiff rod, which can rotate about a point, causing the
  179. pendulum to oscillate.
  180. <p>
  181. A suggested work flow is to
  182. first sketch the figure on a piece of paper and introduce a coordinate
  183. system. A simple coordinate system is indicated in Figure
  184. <a href="#sketcher:ex:pendulum:fig1wgrid">9</a>. In a code we introduce variables
  185. <code>W</code> and <code>H</code> for the width and height of the figure (i.e., extent of
  186. the coordinate system) and open the program like this:
  187. <p>
  188. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  189. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">pysketcher</span> <span style="color: #008000; font-weight: bold">import</span> <span style="color: #666666">*</span>
  190. H <span style="color: #666666">=</span> <span style="color: #666666">7.</span>
  191. W <span style="color: #666666">=</span> <span style="color: #666666">6.</span>
  192. drawing_tool<span style="color: #666666">.</span>set_coordinate_system(xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=</span>W,
  193. ymin<span style="color: #666666">=0</span>, ymax<span style="color: #666666">=</span>H,
  194. axis<span style="color: #666666">=</span><span style="color: #008000">True</span>)
  195. drawing_tool<span style="color: #666666">.</span>set_grid(<span style="color: #008000">True</span>)
  196. drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
  197. </pre></div>
  198. <p>
  199. Note that when the sketch is ready for &quot;production&quot;, we will (normally)
  200. set <code>axis=False</code> to remove the coordinate system and also remove the
  201. grid, i.e., delete or
  202. comment out the line <code>drawing_tool.set_grid(True)</code>.
  203. Also note that we in this example let all lines be blue by default.
  204. <p>
  205. <center> <!-- figure -->
  206. <hr class="figure">
  207. <center><p class="caption">Figure 8: Sketch of a simple pendulum. <div id="sketcher:ex:pendulum:fig1"></div> </p></center>
  208. <p><img src="fig-tut/pendulum1.png" align="bottom" width=300></p>
  209. </center>
  210. <p>
  211. <center> <!-- figure -->
  212. <hr class="figure">
  213. <center><p class="caption">Figure 9: Sketch with assisting coordinate system. <div id="sketcher:ex:pendulum:fig1wgrid"></div> </p></center>
  214. <p><img src="fig-tut/pendulum1_wgrid.png" align="bottom" width=400></p>
  215. </center>
  216. <p>
  217. The next step is to introduce variables for key quantities in the sketch.
  218. Let <code>L</code> be the length of the pendulum, <code>P</code> the rotation point, and let
  219. <code>a</code> be the angle the pendulum makes with the vertical (measured in degrees).
  220. We may set
  221. <p>
  222. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  223. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">L <span style="color: #666666">=</span> <span style="color: #666666">5*</span>H<span style="color: #666666">/7</span> <span style="color: #408080; font-style: italic"># length</span>
  224. P <span style="color: #666666">=</span> (W<span style="color: #666666">/6</span>, <span style="color: #666666">0.85*</span>H) <span style="color: #408080; font-style: italic"># rotation point</span>
  225. a <span style="color: #666666">=</span> <span style="color: #666666">40</span> <span style="color: #408080; font-style: italic"># angle</span>
  226. </pre></div>
  227. <p>
  228. Be careful with integer division if you use Python 2! Fortunately, we
  229. started out with <code>float</code> objects for <code>W</code> and <code>H</code> so the expressions above
  230. are safe.
  231. <p>
  232. What kind of objects do we need in this sketch? Looking at
  233. Figure <a href="#sketcher:ex:pendulum:fig1">8</a> we see that we need
  234. <ol>
  235. <li> a vertical, dashed line</li>
  236. <li> an arc with no text but dashed line to indicate the <em>path</em> of the
  237. mass</li>
  238. <li> an arc with name \( \theta \) to indicate the <em>angle</em></li>
  239. <li> a line, here called <em>rod</em>, from the rotation point to the mass</li>
  240. <li> a blue, filled circle representing the <em>mass</em></li>
  241. <li> a text \( m \) associated with the mass</li>
  242. <li> an indicator of the pendulum's <em>length</em> \( L \), visualized as
  243. a line with two arrows tips and the text \( L \)</li>
  244. <li> a gravity vector with the text \( g \)</li>
  245. </ol>
  246. Pysketcher has objects for each of these elements in our sketch.
  247. We start with the simplest element: the vertical line, going from
  248. <code>P</code> to <code>P</code> minus the length \( L \) in \( y \) direction:
  249. <p>
  250. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  251. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">vertical <span style="color: #666666">=</span> Line(P, P<span style="color: #666666">-</span>point(<span style="color: #666666">0</span>,L))
  252. </pre></div>
  253. <p>
  254. The class <code>point</code> is very convenient: it turns its two coordinates into
  255. a vector with which we can compute, and is therefore one of the most
  256. widely used Pysketcher objects.
  257. <p>
  258. The path of the mass is an arc that can be made by
  259. Pysketcher's <code>Arc</code> object:
  260. <p>
  261. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  262. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">path <span style="color: #666666">=</span> Arc(P, L, <span style="color: #666666">-90</span>, a)
  263. </pre></div>
  264. <p>
  265. The first argument <code>P</code> is the center point, the second is the
  266. radius (<code>L</code> here), the next argument is the start angle, here
  267. it starts at -90 degrees, while the next argument is the angle of
  268. the arc, here <code>a</code>.
  269. For the path of the mass, we also need an arc object, but this
  270. time with an associated text. Pysketcher has a specialized object
  271. for this purpose, <code>Arc_wText</code>, since placing the text manually can
  272. be somewhat cumbersome.
  273. <p>
  274. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  275. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">angle <span style="color: #666666">=</span> Arc_wText(<span style="color: #BA2121">r&#39;$\theta$&#39;</span>, P, L<span style="color: #666666">/4</span>, <span style="color: #666666">-90</span>, a, text_spacing<span style="color: #666666">=1/30.</span>)
  276. </pre></div>
  277. <p>
  278. The arguments are as for <code>Arc</code> above, but the first one is the desired
  279. text. Remember to use a raw string since we want a LaTeX greek letter
  280. that contains a backslash.
  281. The <code>text_spacing</code> argument must often be tweaked. It is recommended
  282. to create only a few objects before rendering the sketch and then
  283. adjust spacings as one goes along.
  284. <p>
  285. The rod is simply a line from <code>P</code> to the mass. We can easily
  286. compute the position of the mass from basic geometry considerations,
  287. but it is easier and safer to look up this point in other objects
  288. if it is already computed. In the present case,
  289. the <code>path</code> object stored its start and
  290. end points, so <code>path.geometric_features()['end']</code> is the end point
  291. of the path, which is the position of the mass. We can therefore
  292. create the rod simply as a line from <code>P</code> to this already computed end point:
  293. <p>
  294. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  295. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">mass_pt <span style="color: #666666">=</span> path<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>]
  296. rod <span style="color: #666666">=</span> Line(P, mass_pt)
  297. </pre></div>
  298. <p>
  299. The mass is a circle filled with color:
  300. <p>
  301. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  302. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">mass <span style="color: #666666">=</span> Circle(center<span style="color: #666666">=</span>mass_pt, radius<span style="color: #666666">=</span>L<span style="color: #666666">/20.</span>)
  303. mass<span style="color: #666666">.</span>set_filled_curves(color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;blue&#39;</span>)
  304. </pre></div>
  305. <p>
  306. To place the \( m \) correctly, we go a small distance in the direction of
  307. the rod, from the center of the circle. To this end, we need to
  308. compute the direction. This is easiest done by computing a vector
  309. from <code>P</code> to the center of the circle and calling <code>unit_vec</code> to make
  310. a unit vector in this direction:
  311. <p>
  312. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  313. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">rod_vec <span style="color: #666666">=</span> rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>] <span style="color: #666666">-</span> \
  314. rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;start&#39;</span>]
  315. unit_rod_vec <span style="color: #666666">=</span> unit_vec(rod_vec)
  316. mass_symbol <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;$m$&#39;</span>, mass_pt <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_rod_vec)
  317. </pre></div>
  318. <p>
  319. Again, the distance <code>L/10</code> is something one has to experiment with.
  320. <p>
  321. The next object is the length measure with the text \( L \). Such length
  322. measures are represented by Pysketcher's <code>Distance_wText</code> object.
  323. An easy construction is to first place this length measure along the
  324. rod and then translate it a little distance (<code>L/15</code>) in the
  325. normal direction of the rod:
  326. <p>
  327. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  328. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">length <span style="color: #666666">=</span> Distance_wText(P, mass_pt, <span style="color: #BA2121">&#39;$L$&#39;</span>)
  329. length<span style="color: #666666">.</span>translate(L<span style="color: #666666">/15*</span>point(cos(radians(a)), sin(radians(a))))
  330. </pre></div>
  331. <p>
  332. For this translation we need a unit vector in the normal direction
  333. of the rod, which is from geometric considerations given by
  334. \( (\cos a, \sin a) \), when \( a \) is the angle of the pendulum.
  335. Alternatively, we could have found the normal vector as a vector that
  336. is normal to <code>unit_rod_vec</code>: <code>point(-unit_rod_vec[1],unit_rod_vec[0])</code>.
  337. <p>
  338. The final object is the gravity force vector, which is so common
  339. in physics sketches that Pysketcher has a ready-made object: <code>Gravity</code>,
  340. <p>
  341. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  342. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">gravity <span style="color: #666666">=</span> Gravity(start<span style="color: #666666">=</span>P<span style="color: #666666">+</span>point(<span style="color: #666666">0.8*</span>L,<span style="color: #666666">0</span>), length<span style="color: #666666">=</span>L<span style="color: #666666">/3</span>)
  343. </pre></div>
  344. <p>
  345. Since blue is the default color for
  346. lines, we want the dashed lines (for <code>vertical</code> and <code>path</code>) to be black
  347. and with linewidth 1. These properties can be set one by one for each
  348. object, but we can also make a little helper function:
  349. <p>
  350. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  351. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">set_dashed_thin_blackline</span>(<span style="color: #666666">*</span>objects):
  352. <span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Set linestyle of objects to dashed, black, width=1.&quot;&quot;&quot;</span>
  353. <span style="color: #008000; font-weight: bold">for</span> obj <span style="color: #AA22FF; font-weight: bold">in</span> objects:
  354. obj<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dashed&#39;</span>)
  355. obj<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;black&#39;</span>)
  356. obj<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">1</span>)
  357. set_dashed_thin_blackline(vertical, path)
  358. </pre></div>
  359. <p>
  360. Now, all objects are in place, so it remains to compose the final
  361. figure and draw the composition:
  362. <p>
  363. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  364. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig <span style="color: #666666">=</span> Composition(
  365. {<span style="color: #BA2121">&#39;body&#39;</span>: mass, <span style="color: #BA2121">&#39;rod&#39;</span>: rod,
  366. <span style="color: #BA2121">&#39;vertical&#39;</span>: vertical, <span style="color: #BA2121">&#39;theta&#39;</span>: angle, <span style="color: #BA2121">&#39;path&#39;</span>: path,
  367. <span style="color: #BA2121">&#39;g&#39;</span>: gravity, <span style="color: #BA2121">&#39;L&#39;</span>: length, <span style="color: #BA2121">&#39;m&#39;</span>: mass_symbol})
  368. fig<span style="color: #666666">.</span>draw()
  369. drawing_tool<span style="color: #666666">.</span>display()
  370. drawing_tool<span style="color: #666666">.</span>savefig(<span style="color: #BA2121">&#39;pendulum1&#39;</span>)
  371. </pre></div>
  372. <h2 id="___sec10">The body diagram </h2>
  373. <p>
  374. Now we want to isolate the mass and draw all the forces that act on it.
  375. Figure <a href="#sketcher:ex:pendulum:fig2wgrid">10</a> shows the desired result, but
  376. embedded in the coordinate system.
  377. We consider three types of forces: the gravity force, the force from the
  378. rod, and air resistance. The body diagram is key for deriving the
  379. equation of motion, so it is illustrative to add useful mathematical
  380. quantities needed in the derivation, such as the unit vectors in polar
  381. coordinates.
  382. <p>
  383. <center> <!-- figure -->
  384. <hr class="figure">
  385. <center><p class="caption">Figure 10: Body diagram of a simple pendulum. <div id="sketcher:ex:pendulum:fig2wgrid"></div> </p></center>
  386. <p><img src="fig-tut/pendulum5_wgrid.png" align="bottom" width=300></p>
  387. </center>
  388. <p>
  389. We start by listing the objects in the sketch:
  390. <ol>
  391. <li> a text \( (x_0,y_0) \) representing the rotation point <code>P</code></li>
  392. <li> unit vector \( \boldsymbol{i}_r \) with text</li>
  393. <li> unit vector \( \boldsymbol{i}_\theta \) with text</li>
  394. <li> a dashed vertical line</li>
  395. <li> a dashed line along the rod</li>
  396. <li> an arc with text \( \theta \)</li>
  397. <li> the gravity force with text \( mg \)</li>
  398. <li> the force in the rod with text \( S \)</li>
  399. <li> the air resistance force with text \( \sim |v|v \)</li>
  400. </ol>
  401. The first object, \( (x_0,y_0) \), is simply a plain text where we have
  402. to experiment with its position. The unit vectors in polar coordinates
  403. may be drawn using the Pysketcher's <code>Force</code> object since it has an
  404. arrow with a text. The first three objects can then be made as follows:
  405. <p>
  406. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  407. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">x0y0 <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;$(x_0,y_0)$&#39;</span>, P <span style="color: #666666">+</span> point(<span style="color: #666666">-0.4</span>,<span style="color: #666666">-0.1</span>))
  408. ir <span style="color: #666666">=</span> Force(P, P <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_vec(rod_vec),
  409. <span style="color: #BA2121">r&#39;$\boldsymbol{i}_r$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  410. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.015</span>,<span style="color: #666666">0</span>))
  411. ith <span style="color: #666666">=</span> Force(P, P <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_vec((<span style="color: #666666">-</span>rod_vec[<span style="color: #666666">1</span>], rod_vec[<span style="color: #666666">0</span>])),
  412. <span style="color: #BA2121">r&#39;$\boldsymbol{i}_{\theta}$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  413. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.02</span>,<span style="color: #666666">0.005</span>))
  414. </pre></div>
  415. <p>
  416. Note that tweaking of the position of <code>x0y0</code> use absolute coordinates, so
  417. if <code>W</code> or <code>H</code> is changed in the beginning of the figure, the tweaked position
  418. will most likely not look good. A better solution would be to express
  419. the tweaked displacement <code>point(-0.4,-0.1)</code> in terms of <code>W</code> and <code>H</code>.
  420. The <code>text_spacing</code> values in the <code>Force</code> objects also use absolute
  421. coordinates. Very often, this is much more convenient when adjusting
  422. the objects, and global size parameters like <code>W</code> and <code>H</code> are in practice
  423. seldom changed, so the solution above is quite typical.
  424. <p>
  425. The vertical, dashed line, the dashed rod, and the arc for \( \theta \)
  426. are made by
  427. <p>
  428. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  429. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">rod_start <span style="color: #666666">=</span> rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;start&#39;</span>] <span style="color: #408080; font-style: italic"># Point P</span>
  430. vertical2 <span style="color: #666666">=</span> Line(rod_start, rod_start <span style="color: #666666">+</span> point(<span style="color: #666666">0</span>,<span style="color: #666666">-</span>L<span style="color: #666666">/3</span>))
  431. set_dashed_thin_blackline(vertical2)
  432. set_dashed_thin_blackline(rod)
  433. angle2 <span style="color: #666666">=</span> Arc_wText(<span style="color: #BA2121">r&#39;$\theta$&#39;</span>, rod_start, L<span style="color: #666666">/6</span>, <span style="color: #666666">-90</span>, a,
  434. text_spacing<span style="color: #666666">=1/30.</span>)
  435. </pre></div>
  436. <p>
  437. Note how we reuse the earlier defined object <code>rod</code>.
  438. <p>
  439. The forces are constructed as shown below.
  440. <p>
  441. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  442. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">mg_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">+</span> L<span style="color: #666666">/5*</span>point(<span style="color: #666666">0</span>,<span style="color: #666666">-1</span>),
  443. <span style="color: #BA2121">&#39;$mg$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>)
  444. rod_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">-</span> L<span style="color: #666666">/3*</span>unit_vec(rod_vec),
  445. <span style="color: #BA2121">&#39;$S$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  446. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.03</span>, <span style="color: #666666">0.01</span>))
  447. air_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">-</span>
  448. L<span style="color: #666666">/6*</span>unit_vec((rod_vec[<span style="color: #666666">1</span>], <span style="color: #666666">-</span>rod_vec[<span style="color: #666666">0</span>])),
  449. <span style="color: #BA2121">&#39;$\sim|v|v$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  450. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.04</span>,<span style="color: #666666">0.005</span>))
  451. </pre></div>
  452. <p>
  453. Note that the drag force from the air is directed perpendicular to
  454. the rod, so we construct a unit vector in this direction directly from
  455. the <code>rod_vec</code> vector.
  456. <p>
  457. All objects are in place, and we can compose a figure to be drawn:
  458. <p>
  459. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  460. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">body_diagram <span style="color: #666666">=</span> Composition(
  461. {<span style="color: #BA2121">&#39;mg&#39;</span>: mg_force, <span style="color: #BA2121">&#39;S&#39;</span>: rod_force, <span style="color: #BA2121">&#39;rod&#39;</span>: rod,
  462. <span style="color: #BA2121">&#39;vertical&#39;</span>: vertical2, <span style="color: #BA2121">&#39;theta&#39;</span>: angle2,
  463. <span style="color: #BA2121">&#39;body&#39;</span>: mass, <span style="color: #BA2121">&#39;m&#39;</span>: mass_symbol})
  464. body_diagram[<span style="color: #BA2121">&#39;air&#39;</span>] <span style="color: #666666">=</span> air_force
  465. body_diagram[<span style="color: #BA2121">&#39;ir&#39;</span>] <span style="color: #666666">=</span> ir
  466. body_diagram[<span style="color: #BA2121">&#39;ith&#39;</span>] <span style="color: #666666">=</span> ith
  467. body_diagram[<span style="color: #BA2121">&#39;origin&#39;</span>] <span style="color: #666666">=</span> x0y0
  468. </pre></div>
  469. <p>
  470. Here, we exemplify that we can start out with a composition as a
  471. dictionary, but (as in ordinary Python dictionaries) add new
  472. elements later when desired.
  473. <p>
  474. <!-- FIGURE: [fig-tut/pendulum1.png, width=300 frac=0.5] Sketch of a simple pendulum. <div id="sketcher:ex:pendulum:fig2"></div> -->
  475. <h2 id="sketcher:ex:pendulum:anim">Animated body diagram</h2>
  476. <p>
  477. We want to make an animated body diagram so that we can see how forces
  478. develop in time according to the motion. This means that we must
  479. couple the sketch at each time level to a numerical solution for
  480. the motion of the pendulum.
  481. <h3 id="___sec12">Function for drawing the body diagram </h3>
  482. <p>
  483. The previous flat program for making sketches of the pendulum is not
  484. suitable when we want to make a sketch at a lot of different points
  485. in time, i.e., for a lot of different angles that the pendulum makes
  486. with the vertical. We therefore need to draw the body diagram in
  487. a function where the angle is a parameter. We also supply arrays
  488. containing the (numerically computed) values of the angle \( \theta \) and
  489. the forces at various time levels, plus the desired time point and level
  490. for this particular sketch:
  491. <p>
  492. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  493. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">pysketcher</span> <span style="color: #008000; font-weight: bold">import</span> <span style="color: #666666">*</span>
  494. H <span style="color: #666666">=</span> <span style="color: #666666">15.</span>
  495. W <span style="color: #666666">=</span> <span style="color: #666666">17.</span>
  496. drawing_tool<span style="color: #666666">.</span>set_coordinate_system(xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=</span>W,
  497. ymin<span style="color: #666666">=0</span>, ymax<span style="color: #666666">=</span>H,
  498. axis<span style="color: #666666">=</span><span style="color: #008000">False</span>)
  499. <span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">pendulum</span>(theta, S, mg, drag, t, time_level):
  500. drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
  501. <span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">math</span>
  502. a <span style="color: #666666">=</span> math<span style="color: #666666">.</span>degrees(theta[time_level])
  503. L <span style="color: #666666">=</span> <span style="color: #666666">0.4*</span>H <span style="color: #408080; font-style: italic"># length</span>
  504. P <span style="color: #666666">=</span> (W<span style="color: #666666">/2</span>, <span style="color: #666666">0.8*</span>H) <span style="color: #408080; font-style: italic"># rotation point</span>
  505. vertical <span style="color: #666666">=</span> Line(P, P<span style="color: #666666">-</span>point(<span style="color: #666666">0</span>,L))
  506. path <span style="color: #666666">=</span> Arc(P, L, <span style="color: #666666">-90</span>, a)
  507. angle <span style="color: #666666">=</span> Arc_wText(<span style="color: #BA2121">r&#39;$\theta$&#39;</span>, P, L<span style="color: #666666">/4</span>, <span style="color: #666666">-90</span>, a, text_spacing<span style="color: #666666">=1/30.</span>)
  508. mass_pt <span style="color: #666666">=</span> path<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>]
  509. rod <span style="color: #666666">=</span> Line(P, mass_pt)
  510. mass <span style="color: #666666">=</span> Circle(center<span style="color: #666666">=</span>mass_pt, radius<span style="color: #666666">=</span>L<span style="color: #666666">/20.</span>)
  511. mass<span style="color: #666666">.</span>set_filled_curves(color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;blue&#39;</span>)
  512. rod_vec <span style="color: #666666">=</span> rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>] <span style="color: #666666">-</span> \
  513. rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;start&#39;</span>]
  514. unit_rod_vec <span style="color: #666666">=</span> unit_vec(rod_vec)
  515. mass_symbol <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;$m$&#39;</span>, mass_pt <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_rod_vec)
  516. length <span style="color: #666666">=</span> Distance_wText(P, mass_pt, <span style="color: #BA2121">&#39;$L$&#39;</span>)
  517. <span style="color: #408080; font-style: italic"># Displace length indication</span>
  518. length<span style="color: #666666">.</span>translate(L<span style="color: #666666">/15*</span>point(cos(radians(a)), sin(radians(a))))
  519. gravity <span style="color: #666666">=</span> Gravity(start<span style="color: #666666">=</span>P<span style="color: #666666">+</span>point(<span style="color: #666666">0.8*</span>L,<span style="color: #666666">0</span>), length<span style="color: #666666">=</span>L<span style="color: #666666">/3</span>)
  520. <span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">set_dashed_thin_blackline</span>(<span style="color: #666666">*</span>objects):
  521. <span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Set linestyle of objects to dashed, black, width=1.&quot;&quot;&quot;</span>
  522. <span style="color: #008000; font-weight: bold">for</span> obj <span style="color: #AA22FF; font-weight: bold">in</span> objects:
  523. obj<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dashed&#39;</span>)
  524. obj<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;black&#39;</span>)
  525. obj<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">1</span>)
  526. set_dashed_thin_blackline(vertical, path)
  527. fig <span style="color: #666666">=</span> Composition(
  528. {<span style="color: #BA2121">&#39;body&#39;</span>: mass, <span style="color: #BA2121">&#39;rod&#39;</span>: rod,
  529. <span style="color: #BA2121">&#39;vertical&#39;</span>: vertical, <span style="color: #BA2121">&#39;theta&#39;</span>: angle, <span style="color: #BA2121">&#39;path&#39;</span>: path,
  530. <span style="color: #BA2121">&#39;g&#39;</span>: gravity, <span style="color: #BA2121">&#39;L&#39;</span>: length})
  531. <span style="color: #408080; font-style: italic">#fig.draw()</span>
  532. <span style="color: #408080; font-style: italic">#drawing_tool.display()</span>
  533. <span style="color: #408080; font-style: italic">#drawing_tool.savefig(&#39;tmp_pendulum1&#39;)</span>
  534. drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;black&#39;</span>)
  535. rod_start <span style="color: #666666">=</span> rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;start&#39;</span>] <span style="color: #408080; font-style: italic"># Point P</span>
  536. vertical2 <span style="color: #666666">=</span> Line(rod_start, rod_start <span style="color: #666666">+</span> point(<span style="color: #666666">0</span>,<span style="color: #666666">-</span>L<span style="color: #666666">/3</span>))
  537. set_dashed_thin_blackline(vertical2)
  538. set_dashed_thin_blackline(rod)
  539. angle2 <span style="color: #666666">=</span> Arc_wText(<span style="color: #BA2121">r&#39;$\theta$&#39;</span>, rod_start, L<span style="color: #666666">/6</span>, <span style="color: #666666">-90</span>, a,
  540. text_spacing<span style="color: #666666">=1/30.</span>)
  541. magnitude <span style="color: #666666">=</span> <span style="color: #666666">1.2*</span>L<span style="color: #666666">/2</span> <span style="color: #408080; font-style: italic"># length of a unit force in figure</span>
  542. force <span style="color: #666666">=</span> mg[time_level] <span style="color: #408080; font-style: italic"># constant (scaled eq: about 1)</span>
  543. force <span style="color: #666666">*=</span> magnitude
  544. mg_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">+</span> force<span style="color: #666666">*</span>point(<span style="color: #666666">0</span>,<span style="color: #666666">-1</span>),
  545. <span style="color: #BA2121">&#39;&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>)
  546. force <span style="color: #666666">=</span> S[time_level]
  547. force <span style="color: #666666">*=</span> magnitude
  548. rod_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">-</span> force<span style="color: #666666">*</span>unit_vec(rod_vec),
  549. <span style="color: #BA2121">&#39;&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  550. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.03</span>, <span style="color: #666666">0.01</span>))
  551. force <span style="color: #666666">=</span> drag[time_level]
  552. force <span style="color: #666666">*=</span> magnitude
  553. <span style="color: #408080; font-style: italic">#print(&#39;drag(%g)=%g&#39; % (t, drag[time_level]))</span>
  554. air_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">-</span>
  555. force<span style="color: #666666">*</span>unit_vec((rod_vec[<span style="color: #666666">1</span>], <span style="color: #666666">-</span>rod_vec[<span style="color: #666666">0</span>])),
  556. <span style="color: #BA2121">&#39;&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  557. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.04</span>,<span style="color: #666666">0.005</span>))
  558. body_diagram <span style="color: #666666">=</span> Composition(
  559. {<span style="color: #BA2121">&#39;mg&#39;</span>: mg_force, <span style="color: #BA2121">&#39;S&#39;</span>: rod_force, <span style="color: #BA2121">&#39;air&#39;</span>: air_force,
  560. <span style="color: #BA2121">&#39;rod&#39;</span>: rod,
  561. <span style="color: #BA2121">&#39;vertical&#39;</span>: vertical2, <span style="color: #BA2121">&#39;theta&#39;</span>: angle2,
  562. <span style="color: #BA2121">&#39;body&#39;</span>: mass})
  563. x0y0 <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;$(x_0,y_0)$&#39;</span>, P <span style="color: #666666">+</span> point(<span style="color: #666666">-0.4</span>,<span style="color: #666666">-0.1</span>))
  564. ir <span style="color: #666666">=</span> Force(P, P <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_vec(rod_vec),
  565. <span style="color: #BA2121">r&#39;$\boldsymbol{i}_r$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  566. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.015</span>,<span style="color: #666666">0</span>))
  567. ith <span style="color: #666666">=</span> Force(P, P <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_vec((<span style="color: #666666">-</span>rod_vec[<span style="color: #666666">1</span>], rod_vec[<span style="color: #666666">0</span>])),
  568. <span style="color: #BA2121">r&#39;$\boldsymbol{i}_{\theta}$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
  569. text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.02</span>,<span style="color: #666666">0.005</span>))
  570. <span style="color: #408080; font-style: italic">#body_diagram[&#39;ir&#39;] = ir</span>
  571. <span style="color: #408080; font-style: italic">#body_diagram[&#39;ith&#39;] = ith</span>
  572. <span style="color: #408080; font-style: italic">#body_diagram[&#39;origin&#39;] = x0y0</span>
  573. drawing_tool<span style="color: #666666">.</span>erase()
  574. body_diagram<span style="color: #666666">.</span>draw(verbose<span style="color: #666666">=0</span>)
  575. <span style="color: #408080; font-style: italic">#drawing_tool.display(&#39;Body diagram&#39;)</span>
  576. drawing_tool<span style="color: #666666">.</span>savefig(<span style="color: #BA2121">&#39;tmp_</span><span style="color: #BB6688; font-weight: bold">%04d</span><span style="color: #BA2121">.png&#39;</span> <span style="color: #666666">%</span> time_level, crop<span style="color: #666666">=</span><span style="color: #008000">False</span>)
  577. <span style="color: #408080; font-style: italic"># No cropping: otherwise movies will be very strange</span>
  578. </pre></div>
  579. <h3 id="___sec13">Equations for the motion and forces </h3>
  580. <p>
  581. The modeling of the motion of a pendulum is most conveniently done in
  582. polar coordinates since then the unknown force in the rod is separated
  583. from the equation determining the motion \( \theta(t) \).
  584. The position vector for the mass is
  585. $$ \rpos = x_0\ii + y_0\jj + L\ir\tp$$
  586. The corresponding acceleration becomes
  587. $$ \ddot{\rpos} = L\ddot{\theta}{\ith} - L\dot{\theta^2}{\ir}\tp$$
  588. <!-- Note: the extra braces help to render the equation correctly in sphinx! -->
  589. <p>
  590. There are three forces on the mass: the gravity force
  591. \( mg\jj = mg(-\cos\theta\,\ir + \sin\theta\,\ith) \), the force in the rod
  592. \( -S\ir \), and the drag force because of air resistance:
  593. $$ -\half C_D \varrho \pi R^2 |v|v\,\ith,$$
  594. where \( C_D\approx 0.4 \) is the drag coefficient for a sphere, \( \varrho \)
  595. is the density of air, \( R \) is the radius of the mass, and \( v \) is the
  596. velocity (\( v=L\dot\theta \)). The drag force acts in \( -\ith \) direction
  597. when \( v>0 \).
  598. <p>
  599. Newton's second law of motion for the pendulum now becomes
  600. $$ mL\ddot\theta\ith - mL\dot\theta^2\ir = -mg(-\cos\theta\,\ir +
  601. \sin\theta\,\ith)
  602. -S\ir - \half C_D \varrho \pi R^2 L^2|\dot\theta|\dot\theta\ith,$$
  603. which gives two component equations
  604. $$
  605. \begin{align}
  606. mL\ddot\theta + \half C_D \varrho \pi R^2 L^2|\dot\theta|\dot\theta +
  607. mg\sin\theta &= 0,
  608. \tag{1}\\
  609. S &= mL\dot\theta^2 + mg\cos\theta
  610. \tag{2}\tp
  611. \end{align}
  612. $$
  613. <p>
  614. It is almost always convenient to scale such equations. Introducing
  615. the dimensionless time
  616. $$ \bar t = \frac{t}{t_c},\quad t_c = \sqrt{\frac{L}{g}},$$
  617. leads to
  618. $$
  619. \begin{align}
  620. \frac{d^2\theta}{d\bar t^2} +
  621. \alpha\left\vert\frac{d\theta}{d\bar t}\right\vert\frac{d\theta}{d\bar t} +
  622. \sin\theta &= 0,
  623. \tag{3}\\
  624. \bar S &= \left(\frac{d\theta}{d\bar t}\right)^2
  625. + \cos\theta,
  626. \tag{4}
  627. \end{align}
  628. $$
  629. where \( \alpha \) is a dimensionless drag coefficient
  630. $$ \alpha = \frac{C_D\varrho\pi R^2L}{2m},$$
  631. and \( \bar S \) is the scaled force
  632. $$ \bar S = \frac{S}{mg}\tp$$
  633. We see that \( \bar S = 1 \) for the equilibrium position \( \theta=0 \), so this
  634. scaling of \( S \) seems appropriate.
  635. <p>
  636. The parameter \( \alpha \) is about
  637. the ratio of the drag force and the gravity force:
  638. $$ \frac{|\half C_D\varrho \pi R^2 |v|v|}{|mg|}\sim
  639. \frac{C_D\varrho \pi R^2 L^2 t_c^{-2}}{mg}
  640. \left|\frac{d\bar\theta}{d\bar t}\right|\frac{d\bar\theta}{d\bar t}
  641. \sim \frac{C_D\varrho \pi R^2 L}{2m}\theta_0^2 = \alpha \theta_0^2\tp$$
  642. (We have that \( \theta(t)/d\theta_0 \) is in \( [-1,1] \), so we expect
  643. since \( \theta_0^{-1}d\bar\theta/d\bar t \) to be around unity.)
  644. <p>
  645. The next step is to write a numerical solver for
  646. <a href="#mjx-eqn-3">(3)</a>-<a href="#mjx-eqn-4">(4)</a>. To
  647. this end, we use the <a href="https://github.com/hplgit/odespy" target="_self">Odespy</a>
  648. package. The system of second-order ODEs must be expressed as a system
  649. of first-order ODEs. We realize that the unknown \( \bar S \) is decoupled
  650. from \( \theta \) in the sense that we can first use
  651. <a href="#mjx-eqn-3">(3)</a> to solve for \( \theta \) and
  652. then compute \( \bar S \) from <a href="#mjx-eqn-4">(4)</a>.
  653. The first-order ODEs become
  654. $$
  655. \begin{align}
  656. \frac{d\omega}{d\bar t} &= -\alpha\left\vert\omega\right\vert\omega
  657. - \sin\theta,
  658. \tag{5}\\
  659. \frac{d\theta}{d\bar t} &= \omega\tp
  660. \tag{6}
  661. \end{align}
  662. $$
  663. Then we compute
  664. $$
  665. \begin{equation}
  666. \bar S = \omega^2 + \cos\theta\tp
  667. \tag{7}
  668. \end{equation}
  669. $$
  670. The dimensionless air resistance force can also be computed:
  671. $$
  672. \begin{equation}
  673. -\alpha|\omega|\omega\tp
  674. \tag{8}
  675. \end{equation}
  676. $$
  677. Since we scaled the force \( S \) by \( mg \), \( mg \) is the natural force scale,
  678. and the \( mg \) force itself is then unity.
  679. <p>
  680. By updating \( \omega \) in the first equation, we can use an Euler-Cromer
  681. scheme on Odespy (all other schemes are independent of whether the
  682. \( \theta \) or \( \omega \) equation comes first).
  683. <h3 id="___sec14">Numerical solution </h3>
  684. <p>
  685. An appropriate solver is
  686. <p>
  687. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  688. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">simulate_pendulum</span>(alpha, theta0, dt, T):
  689. <span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">odespy</span>
  690. <span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">f</span>(u, t, alpha):
  691. omega, theta <span style="color: #666666">=</span> u
  692. <span style="color: #008000; font-weight: bold">return</span> [<span style="color: #666666">-</span>alpha<span style="color: #666666">*</span>omega<span style="color: #666666">*</span><span style="color: #008000">abs</span>(omega) <span style="color: #666666">-</span> sin(theta),
  693. omega]
  694. <span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
  695. Nt <span style="color: #666666">=</span> <span style="color: #008000">int</span>(<span style="color: #008000">round</span>(T<span style="color: #666666">/</span><span style="color: #008000">float</span>(dt)))
  696. t <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linspace(<span style="color: #666666">0</span>, Nt<span style="color: #666666">*</span>dt, Nt<span style="color: #666666">+1</span>)
  697. solver <span style="color: #666666">=</span> odespy<span style="color: #666666">.</span>RK4(f, f_args<span style="color: #666666">=</span>[alpha])
  698. solver<span style="color: #666666">.</span>set_initial_condition([<span style="color: #666666">0</span>, theta0])
  699. u, t <span style="color: #666666">=</span> solver<span style="color: #666666">.</span>solve(t,
  700. terminate<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">lambda</span> u, t, n: <span style="color: #008000">abs</span>(u[n,<span style="color: #666666">1</span>]) <span style="color: #666666">&lt;</span> <span style="color: #666666">1E-3</span>)
  701. omega <span style="color: #666666">=</span> u[:,<span style="color: #666666">0</span>]
  702. theta <span style="color: #666666">=</span> u[:,<span style="color: #666666">1</span>]
  703. S <span style="color: #666666">=</span> omega<span style="color: #666666">**2</span> <span style="color: #666666">+</span> np<span style="color: #666666">.</span>cos(theta)
  704. drag <span style="color: #666666">=</span> <span style="color: #666666">-</span>alpha<span style="color: #666666">*</span>np<span style="color: #666666">.</span>abs(omega)<span style="color: #666666">*</span>omega
  705. <span style="color: #008000; font-weight: bold">return</span> t, theta, omega, S, drag
  706. </pre></div>
  707. <h3 id="___sec15">Animation </h3>
  708. <p>
  709. We can finally traverse the time array and draw a body diagram
  710. at each time level. The resulting sketches are saved to files
  711. <code>tmp_%04d.png</code>, and these files can be combined to videos:
  712. <p>
  713. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  714. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">animate</span>():
  715. <span style="color: #408080; font-style: italic"># Clean up old plot files</span>
  716. <span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">os</span><span style="color: #666666">,</span> <span style="color: #0000FF; font-weight: bold">glob</span>
  717. <span style="color: #008000; font-weight: bold">for</span> filename <span style="color: #AA22FF; font-weight: bold">in</span> glob<span style="color: #666666">.</span>glob(<span style="color: #BA2121">&#39;tmp_*.png&#39;</span>) <span style="color: #666666">+</span> glob<span style="color: #666666">.</span>glob(<span style="color: #BA2121">&#39;movie.*&#39;</span>):
  718. os<span style="color: #666666">.</span>remove(filename)
  719. <span style="color: #408080; font-style: italic"># Solve problem</span>
  720. <span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">math</span> <span style="color: #008000; font-weight: bold">import</span> pi, radians, degrees
  721. <span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
  722. alpha <span style="color: #666666">=</span> <span style="color: #666666">0.4</span>
  723. period <span style="color: #666666">=</span> <span style="color: #666666">2*</span>pi
  724. T <span style="color: #666666">=</span> <span style="color: #666666">12*</span>period
  725. dt <span style="color: #666666">=</span> period<span style="color: #666666">/40</span>
  726. a <span style="color: #666666">=</span> <span style="color: #666666">70</span>
  727. theta0 <span style="color: #666666">=</span> radians(a)
  728. t, theta, omega, S, drag <span style="color: #666666">=</span> simulate_pendulum(alpha, theta0, dt, T)
  729. mg <span style="color: #666666">=</span> np<span style="color: #666666">.</span>ones(S<span style="color: #666666">.</span>size)
  730. <span style="color: #408080; font-style: italic"># Visualize drag force 5 times as large</span>
  731. drag <span style="color: #666666">*=</span> <span style="color: #666666">5</span>
  732. <span style="color: #008000; font-weight: bold">print</span>(<span style="color: #BA2121">&#39;NOTE: drag force magnified 5 times!!&#39;</span>)
  733. <span style="color: #408080; font-style: italic"># Draw animation</span>
  734. <span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">time</span>
  735. <span style="color: #008000; font-weight: bold">for</span> time_level, t_ <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">enumerate</span>(t):
  736. pendulum(theta, S, mg, drag, t_, time_level)
  737. time<span style="color: #666666">.</span>sleep(<span style="color: #666666">0.2</span>)
  738. <span style="color: #408080; font-style: italic"># Make videos</span>
  739. prog <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;ffmpeg&#39;</span>
  740. filename <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;tmp_</span><span style="color: #BB6688; font-weight: bold">%04d</span><span style="color: #BA2121">.png&#39;</span>
  741. fps <span style="color: #666666">=</span> <span style="color: #666666">6</span>
  742. codecs <span style="color: #666666">=</span> {<span style="color: #BA2121">&#39;flv&#39;</span>: <span style="color: #BA2121">&#39;flv&#39;</span>, <span style="color: #BA2121">&#39;mp4&#39;</span>: <span style="color: #BA2121">&#39;libx264&#39;</span>,
  743. <span style="color: #BA2121">&#39;webm&#39;</span>: <span style="color: #BA2121">&#39;libvpx&#39;</span>, <span style="color: #BA2121">&#39;ogg&#39;</span>: <span style="color: #BA2121">&#39;libtheora&#39;</span>}
  744. <span style="color: #008000; font-weight: bold">for</span> ext <span style="color: #AA22FF; font-weight: bold">in</span> codecs:
  745. lib <span style="color: #666666">=</span> codecs[ext]
  746. cmd <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;</span><span style="color: #BB6688; font-weight: bold">%(prog)s</span><span style="color: #BA2121"> -i </span><span style="color: #BB6688; font-weight: bold">%(filename)s</span><span style="color: #BA2121"> -r </span><span style="color: #BB6688; font-weight: bold">%(fps)s</span><span style="color: #BA2121"> &#39;</span> <span style="color: #666666">%</span> <span style="color: #008000">vars</span>()
  747. cmd <span style="color: #666666">+=</span> <span style="color: #BA2121">&#39;-vcodec </span><span style="color: #BB6688; font-weight: bold">%(lib)s</span><span style="color: #BA2121"> movie.</span><span style="color: #BB6688; font-weight: bold">%(ext)s</span><span style="color: #BA2121">&#39;</span> <span style="color: #666666">%</span> <span style="color: #008000">vars</span>()
  748. <span style="color: #008000; font-weight: bold">print</span>(cmd)
  749. os<span style="color: #666666">.</span>system(cmd)
  750. </pre></div>
  751. <p>
  752. This time we did not use the <code>animate</code> function from Pysketcher, but
  753. stored each sketch in a file with <code>drawing_tool.savefig</code>. Note that
  754. the argument <code>crop=False</code> is key: otherwise each figure is cropped and
  755. it makes to sense to combine the images to a video. By default,
  756. Pysketcher crops (removes all exterior whitespace) from figures saved
  757. to file.
  758. <p>
  759. <div>
  760. <video loop controls width='640' height='365' preload='none'>
  761. <source src='https://github.com/hplgit/pysketcher/raw/master/doc/pub/tutorial/mov-tut/pendulum/movie.mp4' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
  762. <source src='https://github.com/hplgit/pysketcher/raw/master/doc/pub/tutorial/mov-tut/pendulum/movie.webm' type='video/webm; codecs="vp8, vorbis"'>
  763. <source src='https://github.com/hplgit/pysketcher/raw/master/doc/pub/tutorial/mov-tut/pendulum/movie.ogg' type='video/ogg; codecs="theora, vorbis"'>
  764. </video>
  765. </div>
  766. <p><em>The drag force is magnified 5 times (compared to \( mg \) and \( S \)!</em></p>
  767. <!-- Issue warning if in a Safari browser -->
  768. <script language="javascript">
  769. if (!!(window.safari)) {
  770. document.write("<div style=\"width: 95%%; padding: 10px; border: 1px solid #100; border-radius: 4px;\"><p><font color=\"red\">The above movie will not play in Safari - use Chrome, Firefox, or Opera.</font></p></div>")}
  771. </script>
  772. <p>
  773. <p>
  774. <!-- navigation buttons at the bottom of the page -->
  775. <ul class="pagination">
  776. <li><a href="._pysketcher002.html">&laquo;</a></li>
  777. <li><a href="._pysketcher000.html">1</a></li>
  778. <li><a href="._pysketcher001.html">2</a></li>
  779. <li><a href="._pysketcher002.html">3</a></li>
  780. <li class="active"><a href="._pysketcher003.html">4</a></li>
  781. <li><a href="._pysketcher004.html">5</a></li>
  782. <li><a href="._pysketcher005.html">6</a></li>
  783. <li><a href="._pysketcher004.html">&raquo;</a></li>
  784. </ul>
  785. <!-- ------------------- end of main content --------------- -->
  786. </div> <!-- end container -->
  787. <!-- include javascript, jQuery *first* -->
  788. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  789. <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
  790. <!-- Bootstrap footer
  791. <footer>
  792. <a href="http://..."><img width="250" align=right src="http://..."></a>
  793. </footer>
  794. -->
  795. </body>
  796. </html>