._pysketcher002.html 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  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. ('Basic shapes', 1, None, '___sec8'),
  43. ('Axis', 2, None, '___sec9'),
  44. ('Distance with text', 2, None, '___sec10'),
  45. ('Rectangle', 2, None, '___sec11'),
  46. ('Triangle', 2, None, '___sec12'),
  47. ('Arc', 2, None, '___sec13'),
  48. ('Spring', 2, None, '___sec14'),
  49. ('Dashpot', 2, None, '___sec15'),
  50. ('Wavy', 2, None, '___sec16'),
  51. ('Stochastic curves', 2, None, '___sec17'),
  52. ('Inner workings of the Pysketcher tool', 1, None, '___sec18'),
  53. ('Example of classes for geometric objects',
  54. 2,
  55. None,
  56. '___sec19'),
  57. ('Simple geometric objects', 3, None, '___sec20'),
  58. ('Class curve', 3, None, '___sec21'),
  59. ('Compound geometric objects', 3, None, '___sec22'),
  60. ('Adding functionality via recursion', 2, None, '___sec23'),
  61. ('Basic principles of recursion', 3, None, '___sec24'),
  62. ('Explaining recursion', 3, None, '___sec25'),
  63. ('Scaling, translating, and rotating a figure',
  64. 2,
  65. 'sketcher:scaling',
  66. 'sketcher:scaling'),
  67. ('Scaling', 3, None, '___sec27'),
  68. ('Translation', 3, None, '___sec28'),
  69. ('Rotation', 3, None, '___sec29')]}
  70. end of tocinfo -->
  71. <body>
  72. <script type="text/x-mathjax-config">
  73. MathJax.Hub.Config({
  74. TeX: {
  75. equationNumbers: { autoNumber: "none" },
  76. extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
  77. }
  78. });
  79. </script>
  80. <script type="text/javascript"
  81. src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
  82. </script>
  83. <!-- Bootstrap navigation bar -->
  84. <div class="navbar navbar-default navbar-fixed-top">
  85. <div class="navbar-header">
  86. <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-responsive-collapse">
  87. <span class="icon-bar"></span>
  88. <span class="icon-bar"></span>
  89. <span class="icon-bar"></span>
  90. </button>
  91. <a class="navbar-brand" href="pysketcher.html">Using Pysketcher to Create Principal Sketches of Physics Problems</a>
  92. </div>
  93. <div class="navbar-collapse collapse navbar-responsive-collapse">
  94. <ul class="nav navbar-nav navbar-right">
  95. <li class="dropdown">
  96. <a href="#" class="dropdown-toggle" data-toggle="dropdown">Contents <b class="caret"></b></a>
  97. <ul class="dropdown-menu">
  98. <!-- navigation toc: --> <li><a href="#___sec0" style="font-size: 80%;"><b>A first glimpse of Pysketcher</b></a></li>
  99. <!-- navigation toc: --> <li><a href="#___sec1" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Basic construction of sketches</a></li>
  100. <!-- navigation toc: --> <li><a href="#___sec2" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic drawing</a></li>
  101. <!-- navigation toc: --> <li><a href="#___sec3" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Groups of objects</a></li>
  102. <!-- navigation toc: --> <li><a href="#___sec4" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Changing line styles and colors</a></li>
  103. <!-- navigation toc: --> <li><a href="#___sec5" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The figure composition as an object hierarchy</a></li>
  104. <!-- navigation toc: --> <li><a href="#___sec6" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: translating the vehicle</a></li>
  105. <!-- navigation toc: --> <li><a href="#sketcher:vehicle1:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: rolling the wheels</a></li>
  106. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec8" style="font-size: 80%;"><b>Basic shapes</b></a></li>
  107. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec9" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
  108. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
  109. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec11" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
  110. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
  111. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
  112. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
  113. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
  114. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
  115. <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
  116. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
  117. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
  118. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
  119. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec21" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
  120. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
  121. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
  122. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
  123. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
  124. <!-- navigation toc: --> <li><a href="._pysketcher004.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
  125. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
  126. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
  127. <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec29" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
  128. </ul>
  129. </li>
  130. </ul>
  131. </div>
  132. </div>
  133. </div> <!-- end of navigation bar -->
  134. <div class="container">
  135. <p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p> <!-- add vertical space -->
  136. <a name="part0002"></a>
  137. <!-- !split -->
  138. <h1 id="___sec0">A first glimpse of Pysketcher </h1>
  139. <p>
  140. Formulation of physical problems makes heavy use of <em>principal sketches</em>
  141. such as the one in Figure <a href="#sketcher:fig:inclinedplane">1</a>.
  142. This particular sketch illustrates the classical mechanics problem
  143. of a rolling wheel on an inclined plane.
  144. The figure
  145. is made up many individual elements: a rectangle
  146. filled with a pattern (the inclined plane), a hollow circle with color
  147. (the wheel), arrows with labels (the \( N \) and \( Mg \) forces, and the \( x \)
  148. axis), an angle with symbol \( \theta \), and a dashed line indicating the
  149. starting location of the wheel.
  150. <p>
  151. Drawing software and plotting programs can produce such figures quite
  152. easily in principle, but the amount of details the user needs to
  153. control with the mouse can be substantial. Software more tailored to
  154. producing sketches of this type would work with more convenient
  155. abstractions, such as circle, wall, angle, force arrow, axis, and so
  156. forth. And as soon we start <em>programming</em> to construct the figure we
  157. get a range of other powerful tools at disposal. For example, we can
  158. easily translate and rotate parts of the figure and make an animation
  159. that illustrates the physics of the problem.
  160. Programming as a superior alternative to interactive drawing is
  161. the mantra of this section.
  162. <p>
  163. <center> <!-- figure -->
  164. <hr class="figure">
  165. <center><p class="caption">Figure 1: Sketch of a physics problem. <div id="sketcher:fig:inclinedplane"></div> </p></center>
  166. <p><img src="fig-tut/wheel_on_inclined_plane.png" align="bottom" width=400></p>
  167. </center>
  168. <h2 id="___sec1">Basic construction of sketches </h2>
  169. <p>
  170. Before attacking real-life sketches as in Figure <a href="#sketcher:fig:inclinedplane">1</a>
  171. we focus on the significantly simpler drawing shown
  172. in Figure <a href="#sketcher:fig:vehicle0">2</a>. This toy sketch consists of
  173. several elements: two circles, two rectangles, and a &quot;ground&quot; element.
  174. <p>
  175. <center> <!-- figure -->
  176. <hr class="figure">
  177. <center><p class="caption">Figure 2: Sketch of a simple figure. <div id="sketcher:fig:vehicle0"></div> </p></center>
  178. <p><img src="fig-tut/vehicle0_dim.png" align="bottom" width=600></p>
  179. </center>
  180. <p>
  181. When the sketch is defined in terms of computer code, it is natural to
  182. parameterize geometric features, such as the radius of the wheel (\( R \)),
  183. the center point of the left wheel (\( w_1 \)), as well as the height (\( H \)) and
  184. length (\( L \)) of the main part. The simple vehicle in
  185. Figure <a href="#sketcher:fig:vehicle0">2</a> is quickly drawn in almost any interactive
  186. tool. However, if we want to change the radius of the wheels, you need a
  187. sophisticated drawing tool to avoid redrawing the whole figure, while
  188. in computer code this is a matter of changing the \( R \) parameter and
  189. rerunning the program.
  190. For example, Figure <a href="#sketcher:fig:vehicle0b">3</a> shows
  191. a variation of the drawing in
  192. Figure <a href="#sketcher:fig:vehicle0">2</a> obtained by just setting
  193. \( R=0.5 \), \( L=5 \), \( H=2 \), and \( R=2 \). Being able
  194. to quickly change geometric sizes is key to many problem settings in
  195. physics and engineering, but then a program must define the geometry.
  196. <p>
  197. <center> <!-- figure -->
  198. <hr class="figure">
  199. <center><p class="caption">Figure 3: Redrawing a figure with other geometric parameters. <div id="sketcher:fig:vehicle0b"></div> </p></center>
  200. <p><img src="fig-tut/vehicle_v2.png" align="bottom" width=500></p>
  201. </center>
  202. <h3 id="___sec2">Basic drawing </h3>
  203. <p>
  204. A typical program creating these five elements is shown next.
  205. After importing the <code>pysketcher</code> package, the first task is always to
  206. define a coordinate system:
  207. <p>
  208. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  209. <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>
  210. drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
  211. xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=10</span>, ymin<span style="color: #666666">=-1</span>, ymax<span style="color: #666666">=8</span>)
  212. </pre></div>
  213. <p>
  214. Instead of working with lengths expressed by specific numbers it is
  215. highly recommended to use variables to parameterize lengths as
  216. this makes it easier to change dimensions later.
  217. Here we introduce some key lengths for the radius of the wheels,
  218. distance between the wheels, etc.:
  219. <p>
  220. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  221. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">R <span style="color: #666666">=</span> <span style="color: #666666">1</span> <span style="color: #408080; font-style: italic"># radius of wheel</span>
  222. L <span style="color: #666666">=</span> <span style="color: #666666">4</span> <span style="color: #408080; font-style: italic"># distance between wheels</span>
  223. H <span style="color: #666666">=</span> <span style="color: #666666">2</span> <span style="color: #408080; font-style: italic"># height of vehicle body</span>
  224. w_1 <span style="color: #666666">=</span> <span style="color: #666666">5</span> <span style="color: #408080; font-style: italic"># position of front wheel</span>
  225. drawing_tool<span style="color: #666666">.</span>set_coordinate_system(xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=</span>w_1 <span style="color: #666666">+</span> <span style="color: #666666">2*</span>L <span style="color: #666666">+</span> <span style="color: #666666">3*</span>R,
  226. ymin<span style="color: #666666">=-1</span>, ymax<span style="color: #666666">=2*</span>R <span style="color: #666666">+</span> <span style="color: #666666">3*</span>H)
  227. </pre></div>
  228. <p>
  229. With the drawing area in place we can make the first <code>Circle</code> object
  230. in an intuitive fashion:
  231. <p>
  232. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  233. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel1 <span style="color: #666666">=</span> Circle(center<span style="color: #666666">=</span>(w_1, R), radius<span style="color: #666666">=</span>R)
  234. </pre></div>
  235. <p>
  236. to change dimensions later.
  237. <p>
  238. To translate the geometric information about the <code>wheel1</code> object to
  239. instructions for the plotting engine (in this case Matplotlib), one calls the
  240. <code>wheel1.draw()</code>. To display all drawn objects, one issues
  241. <code>drawing_tool.display()</code>. The typical steps are hence:
  242. <p>
  243. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  244. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel1 <span style="color: #666666">=</span> Circle(center<span style="color: #666666">=</span>(w_1, R), radius<span style="color: #666666">=</span>R)
  245. wheel1<span style="color: #666666">.</span>draw()
  246. <span style="color: #408080; font-style: italic"># Define other objects and call their draw() methods</span>
  247. drawing_tool<span style="color: #666666">.</span>display()
  248. drawing_tool<span style="color: #666666">.</span>savefig(<span style="color: #BA2121">&#39;tmp.png&#39;</span>) <span style="color: #408080; font-style: italic"># store picture</span>
  249. </pre></div>
  250. <p>
  251. The next wheel can be made by taking a copy of <code>wheel1</code> and
  252. translating the object to the right according to a
  253. displacement vector \( (L,0) \):
  254. <p>
  255. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  256. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel2 <span style="color: #666666">=</span> wheel1<span style="color: #666666">.</span>copy()
  257. wheel2<span style="color: #666666">.</span>translate((L,<span style="color: #666666">0</span>))
  258. </pre></div>
  259. <p>
  260. The two rectangles are also made in an intuitive way:
  261. <p>
  262. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  263. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">under <span style="color: #666666">=</span> Rectangle(lower_left_corner<span style="color: #666666">=</span>(w_1<span style="color: #666666">-2*</span>R, <span style="color: #666666">2*</span>R),
  264. width<span style="color: #666666">=2*</span>R <span style="color: #666666">+</span> L <span style="color: #666666">+</span> <span style="color: #666666">2*</span>R, height<span style="color: #666666">=</span>H)
  265. over <span style="color: #666666">=</span> Rectangle(lower_left_corner<span style="color: #666666">=</span>(w_1, <span style="color: #666666">2*</span>R <span style="color: #666666">+</span> H),
  266. width<span style="color: #666666">=2.5*</span>R, height<span style="color: #666666">=1.25*</span>H)
  267. </pre></div>
  268. <h3 id="___sec3">Groups of objects </h3>
  269. <p>
  270. Instead of calling the <code>draw</code> method of every object, we can
  271. group objects and call <code>draw</code>, or perform other operations, for
  272. the whole group. For example, we may collect the two wheels
  273. in a <code>wheels</code> group and the <code>over</code> and <code>under</code> rectangles
  274. in a <code>body</code> group. The whole vehicle is a composition
  275. of its <code>wheels</code> and <code>body</code> groups. The code goes like
  276. <p>
  277. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  278. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheels <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">&#39;wheel1&#39;</span>: wheel1, <span style="color: #BA2121">&#39;wheel2&#39;</span>: wheel2})
  279. body <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">&#39;under&#39;</span>: under, <span style="color: #BA2121">&#39;over&#39;</span>: over})
  280. vehicle <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">&#39;wheels&#39;</span>: wheels, <span style="color: #BA2121">&#39;body&#39;</span>: body})
  281. </pre></div>
  282. <p>
  283. The ground is illustrated by an object of type <code>Wall</code>,
  284. mostly used to indicate walls in sketches of mechanical systems.
  285. A <code>Wall</code> takes the <code>x</code> and <code>y</code> coordinates of some curve,
  286. and a <code>thickness</code> parameter, and creates a thick curve filled
  287. with a simple pattern. In this case the curve is just a flat
  288. line so the construction is made of two points on the
  289. ground line (\( (w_1-L,0) \) and \( (w_1+3L,0) \)):
  290. <p>
  291. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  292. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">ground <span style="color: #666666">=</span> Wall(x<span style="color: #666666">=</span>[w_1 <span style="color: #666666">-</span> L, w_1 <span style="color: #666666">+</span> <span style="color: #666666">3*</span>L], y<span style="color: #666666">=</span>[<span style="color: #666666">0</span>, <span style="color: #666666">0</span>], thickness<span style="color: #666666">=-0.3*</span>R)
  293. </pre></div>
  294. <p>
  295. The negative thickness makes the pattern-filled rectangle appear below
  296. the defined line, otherwise it appears above.
  297. <p>
  298. We may now collect all the objects in a &quot;top&quot; object that contains
  299. the whole figure:
  300. <p>
  301. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  302. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">&#39;vehicle&#39;</span>: vehicle, <span style="color: #BA2121">&#39;ground&#39;</span>: ground})
  303. fig<span style="color: #666666">.</span>draw() <span style="color: #408080; font-style: italic"># send all figures to plotting backend</span>
  304. drawing_tool<span style="color: #666666">.</span>display()
  305. drawing_tool<span style="color: #666666">.</span>savefig(<span style="color: #BA2121">&#39;tmp.png&#39;</span>)
  306. </pre></div>
  307. <p>
  308. The <code>fig.draw()</code> call will visit
  309. all subgroups, their subgroups,
  310. and so forth in the hierarchical tree structure of
  311. figure elements,
  312. and call <code>draw</code> for every object.
  313. <h3 id="___sec4">Changing line styles and colors </h3>
  314. <p>
  315. Controlling the line style, line color, and line width is
  316. fundamental when designing figures. The <code>pysketcher</code>
  317. package allows the user to control such properties in
  318. single objects, but also set global properties that are
  319. used if the object has no particular specification of
  320. the properties. Setting the global properties are done like
  321. <p>
  322. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  323. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">drawing_tool<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dashed&#39;</span>)
  324. drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;black&#39;</span>)
  325. drawing_tool<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">4</span>)
  326. </pre></div>
  327. <p>
  328. At the object level the properties are specified in a similar
  329. way:
  330. <p>
  331. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  332. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheels<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;solid&#39;</span>)
  333. wheels<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;red&#39;</span>)
  334. </pre></div>
  335. <p>
  336. and so on.
  337. <p>
  338. Geometric figures can be specified as <em>filled</em>, either with a color or with a
  339. special visual pattern:
  340. <p>
  341. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  342. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #408080; font-style: italic"># Set filling of all curves</span>
  343. drawing_tool<span style="color: #666666">.</span>set_filled_curves(color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;blue&#39;</span>, pattern<span style="color: #666666">=</span><span style="color: #BA2121">&#39;/&#39;</span>)
  344. <span style="color: #408080; font-style: italic"># Turn off filling of all curves</span>
  345. drawing_tool<span style="color: #666666">.</span>set_filled_curves(<span style="color: #008000">False</span>)
  346. <span style="color: #408080; font-style: italic"># Fill the wheel with red color</span>
  347. wheel1<span style="color: #666666">.</span>set_filled_curves(<span style="color: #BA2121">&#39;red&#39;</span>)
  348. </pre></div>
  349. <p>
  350. <!-- <a href="http://packages.python.org/ete2/" target="_self"><tt>http://packages.python.org/ete2/</tt></a> for visualizing tree structures! -->
  351. <h3 id="___sec5">The figure composition as an object hierarchy </h3>
  352. <p>
  353. The composition of objects making up the figure
  354. is hierarchical, similar to a family, where
  355. each object has a parent and a number of children. Do a
  356. <code>print fig</code> to display the relations:
  357. <p>
  358. <!-- code=text (!bc dat) typeset with pygments style "default" -->
  359. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">ground
  360. wall
  361. vehicle
  362. body
  363. over
  364. rectangle
  365. under
  366. rectangle
  367. wheels
  368. wheel1
  369. arc
  370. wheel2
  371. arc
  372. </pre></div>
  373. <p>
  374. The indentation reflects how deep down in the hierarchy (family)
  375. we are.
  376. This output is to be interpreted as follows:
  377. <ul>
  378. <li> <code>fig</code> contains two objects, <code>ground</code> and <code>vehicle</code></li>
  379. <li> <code>ground</code> contains an object <code>wall</code></li>
  380. <li> <code>vehicle</code> contains two objects, <code>body</code> and <code>wheels</code></li>
  381. <li> <code>body</code> contains two objects, <code>over</code> and <code>under</code></li>
  382. <li> <code>wheels</code> contains two objects, <code>wheel1</code> and <code>wheel2</code></li>
  383. </ul>
  384. In this listing there are also objects not defined by the
  385. programmer: <code>rectangle</code> and <code>arc</code>. These are of type <code>Curve</code>
  386. and automatically generated by the classes <code>Rectangle</code> and <code>Circle</code>.
  387. <p>
  388. More detailed information can be printed by
  389. <p>
  390. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  391. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">print</span> fig<span style="color: #666666">.</span>show_hierarchy(<span style="color: #BA2121">&#39;std&#39;</span>)
  392. </pre></div>
  393. <p>
  394. yielding the output
  395. <p>
  396. <!-- code=text (!bc dat) typeset with pygments style "default" -->
  397. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">ground (Wall):
  398. wall (Curve): 4 coords fillcolor=&#39;white&#39; fillpattern=&#39;/&#39;
  399. vehicle (Composition):
  400. body (Composition):
  401. over (Rectangle):
  402. rectangle (Curve): 5 coords
  403. under (Rectangle):
  404. rectangle (Curve): 5 coords
  405. wheels (Composition):
  406. wheel1 (Circle):
  407. arc (Curve): 181 coords
  408. wheel2 (Circle):
  409. arc (Curve): 181 coords
  410. </pre></div>
  411. <p>
  412. Here we can see the class type for each figure object, how many
  413. coordinates that are involved in basic figures (<code>Curve</code> objects), and
  414. special settings of the basic figure (fillcolor, line types, etc.).
  415. For example, <code>wheel2</code> is a <code>Circle</code> object consisting of an <code>arc</code>,
  416. which is a <code>Curve</code> object consisting of 181 coordinates (the
  417. points needed to draw a smooth circle). The <code>Curve</code> objects are the
  418. only objects that really holds specific coordinates to be drawn.
  419. The other object types are just compositions used to group
  420. parts of the complete figure.
  421. <p>
  422. One can also get a graphical overview of the hierarchy of figure objects
  423. that build up a particular figure <code>fig</code>.
  424. Just call <code>fig.graphviz_dot('fig')</code> to produce a file <code>fig.dot</code> in
  425. the <em>dot format</em>. This file contains relations between parent and
  426. child objects in the figure and can be turned into an image,
  427. as in Figure <a href="#sketcher:fig:vehicle0:hier1">4</a>, by
  428. running the <code>dot</code> program:
  429. <p>
  430. <!-- code=text (!bc sys) typeset with pygments style "default" -->
  431. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Terminal&gt; dot -Tpng -o fig.png fig.dot
  432. </pre></div>
  433. <p>
  434. <center> <!-- figure -->
  435. <hr class="figure">
  436. <center><p class="caption">Figure 4: Hierarchical relation between figure objects. <div id="sketcher:fig:vehicle0:hier1"></div> </p></center>
  437. <p><img src="fig-tut/vehicle0_hier1.png" align="bottom" width=500></p>
  438. </center>
  439. <p>
  440. The call <code>fig.graphviz_dot('fig', classname=True)</code> makes a <code>fig.dot</code> file
  441. where the class type of each object is also visible, see
  442. Figure <a href="#sketcher:fig:vehicle0:hier2">5</a>. The ability to write out the
  443. object hierarchy or view it graphically can be of great help when
  444. working with complex figures that involve layers of subfigures.
  445. <p>
  446. <center> <!-- figure -->
  447. <hr class="figure">
  448. <center><p class="caption">Figure 5: Hierarchical relation between figure objects, including their class names. <div id="sketcher:fig:vehicle0:hier2"></div> </p></center>
  449. <p><img src="fig-tut/Vehicle0_hier2.png" align="bottom" width=500></p>
  450. </center>
  451. <p>
  452. Any of the objects can in the program be reached through their names, e.g.,
  453. <p>
  454. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  455. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>]
  456. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>]
  457. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>]
  458. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>][<span style="color: #BA2121">&#39;arc&#39;</span>]
  459. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>][<span style="color: #BA2121">&#39;arc&#39;</span>]<span style="color: #666666">.</span>x <span style="color: #408080; font-style: italic"># x coords</span>
  460. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>][<span style="color: #BA2121">&#39;arc&#39;</span>]<span style="color: #666666">.</span>y <span style="color: #408080; font-style: italic"># y coords</span>
  461. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>][<span style="color: #BA2121">&#39;arc&#39;</span>]<span style="color: #666666">.</span>linestyle
  462. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>][<span style="color: #BA2121">&#39;arc&#39;</span>]<span style="color: #666666">.</span>linetype
  463. </pre></div>
  464. <p>
  465. Grabbing a part of the figure this way is handy for
  466. changing properties of that part, for example, colors, line styles
  467. (see Figure <a href="#sketcher:fig:vehicle0:v2">6</a>):
  468. <p>
  469. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  470. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>]<span style="color: #666666">.</span>set_filled_curves(<span style="color: #BA2121">&#39;blue&#39;</span>)
  471. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>]<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">6</span>)
  472. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>]<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;black&#39;</span>)
  473. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;body&#39;</span>][<span style="color: #BA2121">&#39;under&#39;</span>]<span style="color: #666666">.</span>set_filled_curves(<span style="color: #BA2121">&#39;red&#39;</span>)
  474. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;body&#39;</span>][<span style="color: #BA2121">&#39;over&#39;</span>]<span style="color: #666666">.</span>set_filled_curves(pattern<span style="color: #666666">=</span><span style="color: #BA2121">&#39;/&#39;</span>)
  475. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;body&#39;</span>][<span style="color: #BA2121">&#39;over&#39;</span>]<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">14</span>)
  476. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;body&#39;</span>][<span style="color: #BA2121">&#39;over&#39;</span>][<span style="color: #BA2121">&#39;rectangle&#39;</span>]<span style="color: #666666">.</span>linewidth <span style="color: #666666">=</span> <span style="color: #666666">4</span>
  477. </pre></div>
  478. <p>
  479. The last line accesses the <code>Curve</code> object directly, while the line above,
  480. accesses the <code>Rectangle</code> object, which will then set the linewidth of
  481. its <code>Curve</code> object, and other objects if it had any.
  482. The result of the actions above is shown in Figure <a href="#sketcher:fig:vehicle0:v2">6</a>.
  483. <p>
  484. <center> <!-- figure -->
  485. <hr class="figure">
  486. <center><p class="caption">Figure 6: Left: Basic line-based drawing. Right: Thicker lines and filled parts. <div id="sketcher:fig:vehicle0:v2"></div> </p></center>
  487. <p><img src="fig-tut/vehicle0.png" align="bottom" width=700></p>
  488. </center>
  489. <p>
  490. We can also change position of parts of the figure and thereby make
  491. animations, as shown next.
  492. <h3 id="___sec6">Animation: translating the vehicle </h3>
  493. <p>
  494. Can we make our little vehicle roll? A first attempt will be to
  495. fake rolling by just displacing all parts of the vehicle.
  496. The relevant parts constitute the <code>fig['vehicle']</code> object.
  497. This part of the figure can be translated, rotated, and scaled.
  498. A translation along the ground means a translation in \( x \) direction,
  499. say a length \( L \) to the right:
  500. <p>
  501. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  502. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>]<span style="color: #666666">.</span>translate((L,<span style="color: #666666">0</span>))
  503. </pre></div>
  504. <p>
  505. You need to erase, draw, and display to see the movement:
  506. <p>
  507. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  508. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">drawing_tool<span style="color: #666666">.</span>erase()
  509. fig<span style="color: #666666">.</span>draw()
  510. drawing_tool<span style="color: #666666">.</span>display()
  511. </pre></div>
  512. <p>
  513. Without erasing, the old drawing of the vehicle will remain in
  514. the figure so you get two vehicles. Without <code>fig.draw()</code> the
  515. new coordinates of the vehicle will not be communicated to
  516. the drawing tool, and without calling display the updated
  517. drawing will not be visible.
  518. <p>
  519. A figure that moves in time is conveniently realized by the
  520. function <code>animate</code>:
  521. <p>
  522. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  523. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">animate(fig, tp, action)
  524. </pre></div>
  525. <p>
  526. Here, <code>fig</code> is the entire figure, <code>tp</code> is an array of
  527. time points, and <code>action</code> is a user-specified function that changes
  528. <code>fig</code> at a specific time point. Typically, <code>action</code> will move
  529. parts of <code>fig</code>.
  530. <p>
  531. In the present case we can define the movement through a velocity
  532. function <code>v(t)</code> and displace the figure <code>v(t)*dt</code> for small time
  533. intervals <code>dt</code>. A possible velocity function is
  534. <p>
  535. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  536. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">v</span>(t):
  537. <span style="color: #008000; font-weight: bold">return</span> <span style="color: #666666">-8*</span>R<span style="color: #666666">*</span>t<span style="color: #666666">*</span>(<span style="color: #666666">1</span> <span style="color: #666666">-</span> t<span style="color: #666666">/</span>(<span style="color: #666666">2*</span>R))
  538. </pre></div>
  539. <p>
  540. Our action function for horizontal displacements <code>v(t)*dt</code> becomes
  541. <p>
  542. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  543. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">move</span>(t, fig):
  544. x_displacement <span style="color: #666666">=</span> dt<span style="color: #666666">*</span>v(t)
  545. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>]<span style="color: #666666">.</span>translate((x_displacement, <span style="color: #666666">0</span>))
  546. </pre></div>
  547. <p>
  548. Since our velocity is negative for \( t\in [0,2R] \) the displacement is
  549. to the left.
  550. <p>
  551. The <code>animate</code> function will for each time point <code>t</code> in <code>tp</code> erase
  552. the drawing, call <code>action(t, fig)</code>, and show the new figure by
  553. <code>fig.draw()</code> and <code>drawing_tool.display()</code>.
  554. Here we choose a resolution of the animation corresponding to
  555. 25 time points in the time interval \( [0,2R] \):
  556. <p>
  557. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  558. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span>
  559. tp <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>linspace(<span style="color: #666666">0</span>, <span style="color: #666666">2*</span>R, <span style="color: #666666">25</span>)
  560. dt <span style="color: #666666">=</span> tp[<span style="color: #666666">1</span>] <span style="color: #666666">-</span> tp[<span style="color: #666666">0</span>] <span style="color: #408080; font-style: italic"># time step</span>
  561. animate(fig, tp, move, pause_per_frame<span style="color: #666666">=0.2</span>)
  562. </pre></div>
  563. <p>
  564. The <code>pause_per_frame</code> adds a pause, here 0.2 seconds, between
  565. each frame in the animation.
  566. <p>
  567. We can also ask <code>animate</code> to store each frame in a file:
  568. <p>
  569. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  570. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">files <span style="color: #666666">=</span> animate(fig, tp, move_vehicle, moviefiles<span style="color: #666666">=</span><span style="color: #008000">True</span>,
  571. pause_per_frame<span style="color: #666666">=0.2</span>)
  572. </pre></div>
  573. <p>
  574. The <code>files</code> variable, here <code>'tmp_frame_%04d.png'</code>,
  575. is the printf-specification used to generate the individual
  576. plot files. We can use this specification to make a video
  577. file via <code>ffmpeg</code> (or <code>avconv</code> on Debian-based Linux systems such
  578. as Ubuntu). Videos in the Flash and WebM formats can be created
  579. by
  580. <p>
  581. <!-- code=text (!bc sys) typeset with pygments style "default" -->
  582. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Terminal&gt; ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec flv mov.flv
  583. Terminal&gt; ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec libvpx mov.webm
  584. </pre></div>
  585. <p>
  586. An animated GIF movie can also be made using the <code>convert</code> program
  587. from the ImageMagick software suite:
  588. <p>
  589. <!-- code=text (!bc sys) typeset with pygments style "default" -->
  590. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Terminal&gt; convert -delay 20 tmp_frame*.png mov.gif
  591. Terminal&gt; animate mov.gif # play movie
  592. </pre></div>
  593. <p>
  594. The delay between frames, in units of 1/100 s,
  595. governs the speed of the movie.
  596. To play the animated GIF file in a web page, simply insert
  597. <code>&lt;img src=&quot;mov.gif&quot;&gt;</code> in the HTML code.
  598. <p>
  599. The individual PNG frames can be directly played in a web
  600. browser by running
  601. <p>
  602. <!-- code=text (!bc sys) typeset with pygments style "default" -->
  603. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Terminal&gt; scitools movie output_file=mov.html fps=5 tmp_frame*
  604. </pre></div>
  605. <p>
  606. or calling
  607. <p>
  608. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  609. <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">scitools.std</span> <span style="color: #008000; font-weight: bold">import</span> movie
  610. movie(files, encoder<span style="color: #666666">=</span><span style="color: #BA2121">&#39;html&#39;</span>, output_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;mov.html&#39;</span>)
  611. </pre></div>
  612. <p>
  613. in Python. Load the resulting file <code>mov.html</code> into a web browser
  614. to play the movie.
  615. <p>
  616. Try to run <a href="http://tinyurl.com/ot733jn/vehicle0.py" target="_self"><tt>vehicle0.py</tt></a> and
  617. then load <code>mov.html</code> into a browser, or play one of the <code>mov.*</code>
  618. video files. Alternatively, you can view a ready-made <a href="http://tinyurl.com/oou9lp7/mov-tut/vehicle0.html" target="_self">movie</a>.
  619. <h3 id="sketcher:vehicle1:anim">Animation: rolling the wheels</h3>
  620. <p>
  621. It is time to show rolling wheels. To this end, we add spokes to the
  622. wheels, formed by two crossing lines, see Figure <a href="#sketcher:fig:vehicle1">7</a>.
  623. The construction of the wheels will now involve a circle and two lines:
  624. <p>
  625. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  626. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel1 <span style="color: #666666">=</span> Composition({
  627. <span style="color: #BA2121">&#39;wheel&#39;</span>: Circle(center<span style="color: #666666">=</span>(w_1, R), radius<span style="color: #666666">=</span>R),
  628. <span style="color: #BA2121">&#39;cross&#39;</span>: Composition({<span style="color: #BA2121">&#39;cross1&#39;</span>: Line((w_1,<span style="color: #666666">0</span>), (w_1,<span style="color: #666666">2*</span>R)),
  629. <span style="color: #BA2121">&#39;cross2&#39;</span>: Line((w_1<span style="color: #666666">-</span>R,R), (w_1<span style="color: #666666">+</span>R,R))})})
  630. wheel2 <span style="color: #666666">=</span> wheel1<span style="color: #666666">.</span>copy()
  631. wheel2<span style="color: #666666">.</span>translate((L,<span style="color: #666666">0</span>))
  632. </pre></div>
  633. <p>
  634. Observe that <code>wheel1.copy()</code> copies all the objects that make
  635. up the first wheel, and <code>wheel2.translate</code> translates all
  636. the copied objects.
  637. <p>
  638. <center> <!-- figure -->
  639. <hr class="figure">
  640. <center><p class="caption">Figure 7: Wheels with spokes to illustrate rolling. <div id="sketcher:fig:vehicle1"></div> </p></center>
  641. <p><img src="fig-tut/vehicle1.png" align="bottom" width=400></p>
  642. </center>
  643. <p>
  644. The <code>move</code> function now needs to displace all the objects in the
  645. entire vehicle and also rotate the <code>cross1</code> and <code>cross2</code>
  646. objects in both wheels.
  647. The rotation angle follows from the fact that the arc length
  648. of a rolling wheel equals the displacement of the center of
  649. the wheel, leading to a rotation angle
  650. <p>
  651. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  652. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">angle <span style="color: #666666">=</span> <span style="color: #666666">-</span> x_displacement<span style="color: #666666">/</span>R
  653. </pre></div>
  654. <p>
  655. With <code>w_1</code> tracking the \( x \) coordinate of the center
  656. of the front wheel, we can rotate that wheel by
  657. <p>
  658. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  659. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">w1 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel1&#39;</span>]
  660. <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> degrees
  661. w1<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1, R))
  662. </pre></div>
  663. <p>
  664. The <code>rotate</code> function takes two parameters: the rotation angle
  665. (in degrees) and the center point of the rotation, which is the
  666. center of the wheel in this case. The other wheel is rotated by
  667. <p>
  668. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  669. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">w2 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>]
  670. w2<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1 <span style="color: #666666">+</span> L, R))
  671. </pre></div>
  672. <p>
  673. That is, the angle is the same, but the rotation point is different.
  674. The update of the center point is done by <code>w_1 += x_displacement</code>.
  675. The complete <code>move</code> function with translation of the entire
  676. vehicle and rotation of the wheels then becomes
  677. <p>
  678. <!-- code=python (!bc pycod) typeset with pygments style "default" -->
  679. <div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">w_1 <span style="color: #666666">=</span> w_1 <span style="color: #666666">+</span> L <span style="color: #408080; font-style: italic"># start position</span>
  680. <span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">move</span>(t, fig):
  681. x_displacement <span style="color: #666666">=</span> dt<span style="color: #666666">*</span>v(t)
  682. fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>]<span style="color: #666666">.</span>translate((x_displacement, <span style="color: #666666">0</span>))
  683. <span style="color: #408080; font-style: italic"># Rotate wheels</span>
  684. <span style="color: #008000; font-weight: bold">global</span> w_1
  685. w_1 <span style="color: #666666">+=</span> x_displacement
  686. <span style="color: #408080; font-style: italic"># R*angle = -x_displacement</span>
  687. angle <span style="color: #666666">=</span> <span style="color: #666666">-</span> x_displacement<span style="color: #666666">/</span>R
  688. w1 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel1&#39;</span>]
  689. w1<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1, R))
  690. w2 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">&#39;vehicle&#39;</span>][<span style="color: #BA2121">&#39;wheels&#39;</span>][<span style="color: #BA2121">&#39;wheel2&#39;</span>]
  691. w2<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1 <span style="color: #666666">+</span> L, R))
  692. </pre></div>
  693. <p>
  694. The complete example is found in the file
  695. <a href="http://tinyurl.com/ot733jn/vehicle1.py" target="_self"><tt>vehicle1.py</tt></a>. You may run this file or watch a <a href="http://tinyurl.com/oou9lp7/mov-tut/vehicle1.html" target="_self">ready-made movie</a>.
  696. <p>
  697. The advantages with making figures this way, through programming
  698. rather than using interactive drawing programs, are numerous. For
  699. example, the objects are parameterized by variables so that various
  700. dimensions can easily be changed. Subparts of the figure, possible
  701. involving a lot of figure objects, can change color, linetype, filling
  702. or other properties through a <em>single</em> function call. Subparts of the
  703. figure can be rotated, translated, or scaled. Subparts of the figure
  704. can also be copied and moved to other parts of the drawing
  705. area. However, the single most important feature is probably the
  706. ability to make animations governed by mathematical formulas or data
  707. coming from physics simulations of the problem, as shown in the example above.
  708. <p>
  709. <p>
  710. <!-- navigation buttons at the bottom of the page -->
  711. <ul class="pagination">
  712. <li><a href="._pysketcher001.html">&laquo;</a></li>
  713. <li><a href="._pysketcher000.html">1</a></li>
  714. <li><a href="._pysketcher001.html">2</a></li>
  715. <li class="active"><a href="._pysketcher002.html">3</a></li>
  716. <li><a href="._pysketcher003.html">4</a></li>
  717. <li><a href="._pysketcher004.html">5</a></li>
  718. <li><a href="._pysketcher003.html">&raquo;</a></li>
  719. </ul>
  720. <!-- ------------------- end of main content --------------- -->
  721. </div> <!-- end container -->
  722. <!-- include javascript, jQuery *first* -->
  723. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  724. <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
  725. <!-- Bootstrap footer
  726. <footer>
  727. <a href="http://..."><img width="250" align=right src="http://..."></a>
  728. </footer>
  729. -->
  730. </body>
  731. </html>