main_sketcher.html 177 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml">
  4. <head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  6. <title>Pysketcher: Create Principal Sketches of Physics Problems</title>
  7. <link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
  8. <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
  9. <script type="text/javascript">
  10. var DOCUMENTATION_OPTIONS = {
  11. URL_ROOT: './',
  12. VERSION: '1.0',
  13. COLLAPSE_INDEX: false,
  14. FILE_SUFFIX: '.html',
  15. HAS_SOURCE: true
  16. };
  17. </script>
  18. <script type="text/javascript" src="_static/jquery.js"></script>
  19. <script type="text/javascript" src="_static/underscore.js"></script>
  20. <script type="text/javascript" src="_static/doctools.js"></script>
  21. <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  22. <script src="http://sagecell.sagemath.org/static/jquery.min.js"></script>
  23. <script src="http://sagecell.sagemath.org/static/embedded_sagecell.js"></script>
  24. <script>sagecell.makeSagecell({inputLocation: ".sage"});</script>
  25. <style type="text/css">
  26. .sagecell .CodeMirror-scroll {
  27. overflow-y: hidden;
  28. overflow-x: auto;
  29. }
  30. .sagecell .CodeMirror {
  31. height: auto;
  32. }
  33. </style>
  34. <link rel="top" title="Pysketcher: Create Principal Sketches of Physics Problems" href="index.html" />
  35. <link rel="prev" title="Pysketcher: Create Principal Sketches of Physics Problems" href="index.html" />
  36. <meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9">
  37. <style type="text/css">
  38. div.admonition {
  39. background-color: whiteSmoke;
  40. border: 1px solid #bababa;
  41. }
  42. </style>
  43. </head>
  44. <body role="document">
  45. <div class="document">
  46. <div class="documentwrapper">
  47. <div class="bodywrapper">
  48. <div class="body" role="main">
  49. <div class="section" id="pysketcher-create-principal-sketches-of-physics-problems">
  50. <h1>Pysketcher: Create Principal Sketches of Physics Problems<a class="headerlink" href="#pysketcher-create-principal-sketches-of-physics-problems" title="Permalink to this headline">¶</a></h1>
  51. <table class="docutils field-list" frame="void" rules="none">
  52. <col class="field-name" />
  53. <col class="field-body" />
  54. <tbody valign="top">
  55. <tr class="field-odd field"><th class="field-name">Authors:</th><td class="field-body">Hans Petter Langtangen</td>
  56. </tr>
  57. <tr class="field-even field"><th class="field-name">Date:</th><td class="field-body">Dec 22, 2015</td>
  58. </tr>
  59. </tbody>
  60. </table>
  61. <p>This document is derived from Chapter 9 in the book
  62. <a class="reference external" href="http://www.amazon.com/Scientific-Programming-Computational-Science-Engineering/dp/3642549586/ref=sr_1_2?s=books&amp;ie=UTF8&amp;qid=1407225588&amp;sr=1-2&amp;keywords=langtangen">A Primer on Scientific Programming with Python</a>, by H. P. Langtangen,
  63. 4th edition, Springer, 2014.</p>
  64. <p><em>Abstract.</em> Pysketcher is a Python package which allows principal sketches of
  65. physics and mechanics problems to be realized through short programs
  66. instead of interactive (and potentially tedious and inaccurate)
  67. drawing. Elements of the sketch, such as lines, circles, angles,
  68. forces, coordinate systems, etc., are realized as objects and
  69. collected in hierarchical structures. Parts of the hierarchical
  70. structures can easily change line styles and colors, or be copied,
  71. scaled, translated, and rotated. These features make it
  72. straightforward to move parts of the sketch to create animation,
  73. usually in accordance with the physics of the underlying problem.
  74. Exact dimensioning of the elements in the sketch is trivial to obtain
  75. since distances are specified in computer code.</p>
  76. <p>Pysketcher is easy to learn from a number of examples. Beyond
  77. essential Python programming and a knowledge about mechanics problems,
  78. no further background is required.</p>
  79. <div class="section" id="a-first-glimpse-of-pysketcher">
  80. <h2>A First Glimpse of Pysketcher<a class="headerlink" href="#a-first-glimpse-of-pysketcher" title="Permalink to this headline">¶</a></h2>
  81. <p>Formulation of physical problems makes heavy use of <em>principal sketches</em>
  82. such as the one in Figure <a class="reference internal" href="#sketcher-fig-inclinedplane"><span class="std std-ref">Sketch of a physics problem</span></a>.
  83. This particular sketch illustrates the classical mechanics problem
  84. of a rolling wheel on an inclined plane.
  85. The figure
  86. is made up many individual elements: a rectangle
  87. filled with a pattern (the inclined plane), a hollow circle with color
  88. (the wheel), arrows with labels (the <span class="math">\(N\)</span> and <span class="math">\(Mg\)</span> forces, and the <span class="math">\(x\)</span>
  89. axis), an angle with symbol <span class="math">\(\theta\)</span>, and a dashed line indicating the
  90. starting location of the wheel.</p>
  91. <p>Drawing software and plotting programs can produce such figures quite
  92. easily in principle, but the amount of details the user needs to
  93. control with the mouse can be substantial. Software more tailored to
  94. producing sketches of this type would work with more convenient
  95. abstractions, such as circle, wall, angle, force arrow, axis, and so
  96. forth. And as soon we start <em>programming</em> to construct the figure we
  97. get a range of other powerful tools at disposal. For example, we can
  98. easily translate and rotate parts of the figure and make an animation
  99. that illustrates the physics of the problem.
  100. Programming as a superior alternative to interactive drawing is
  101. the mantra of this section.</p>
  102. <div class="figure" id="id2">
  103. <span id="sketcher-fig-inclinedplane"></span><a class="reference internal image-reference" href="_images/wheel_on_inclined_plane.png"><img alt="_images/wheel_on_inclined_plane.png" src="_images/wheel_on_inclined_plane.png" style="width: 400px;" /></a>
  104. <p class="caption"><span class="caption-text"><em>Sketch of a physics problem</em></span></p>
  105. </div>
  106. <div class="section" id="basic-construction-of-sketches">
  107. <h3>Basic Construction of Sketches<a class="headerlink" href="#basic-construction-of-sketches" title="Permalink to this headline">¶</a></h3>
  108. <p>Before attacking real-life sketches as in Figure <a class="reference internal" href="#sketcher-fig-inclinedplane"><span class="std std-ref">Sketch of a physics problem</span></a>
  109. we focus on the significantly simpler drawing shown
  110. in Figure <a class="reference internal" href="#sketcher-fig-vehicle0"><span class="std std-ref">Sketch of a simple figure</span></a>. This toy sketch consists of
  111. several elements: two circles, two rectangles, and a &#8220;ground&#8221; element.</p>
  112. <div class="figure" id="id3">
  113. <span id="sketcher-fig-vehicle0"></span><a class="reference internal image-reference" href="_images/vehicle0_dim.png"><img alt="_images/vehicle0_dim.png" src="_images/vehicle0_dim.png" style="width: 600px;" /></a>
  114. <p class="caption"><span class="caption-text"><em>Sketch of a simple figure</em></span></p>
  115. </div>
  116. <p>When the sketch is defined in terms of computer code, it is natural to
  117. parameterize geometric features, such as the radius of the wheel (<span class="math">\(R\)</span>),
  118. the center point of the left wheel (<span class="math">\(w_1\)</span>), as well as the height (<span class="math">\(H\)</span>) and
  119. length (<span class="math">\(L\)</span>) of the main part. The simple vehicle in
  120. Figure <a class="reference internal" href="#sketcher-fig-vehicle0"><span class="std std-ref">Sketch of a simple figure</span></a> is quickly drawn in almost any interactive
  121. tool. However, if we want to change the radius of the wheels, you need a
  122. sophisticated drawing tool to avoid redrawing the whole figure, while
  123. in computer code this is a matter of changing the <span class="math">\(R\)</span> parameter and
  124. rerunning the program.
  125. For example, Figure <a class="reference internal" href="#sketcher-fig-vehicle0b"><span class="std std-ref">Redrawing a figure with other geometric parameters</span></a> shows
  126. a variation of the drawing in
  127. Figure <a class="reference internal" href="#sketcher-fig-vehicle0"><span class="std std-ref">Sketch of a simple figure</span></a> obtained by just setting
  128. <span class="math">\(R=0.5\)</span>, <span class="math">\(L=5\)</span>, <span class="math">\(H=2\)</span>, and <span class="math">\(R=2\)</span>. Being able
  129. to quickly change geometric sizes is key to many problem settings in
  130. physics and engineering, but then a program must define the geometry.</p>
  131. <div class="figure" id="id4">
  132. <span id="sketcher-fig-vehicle0b"></span><a class="reference internal image-reference" href="_images/vehicle_v2.png"><img alt="_images/vehicle_v2.png" src="_images/vehicle_v2.png" style="width: 500px;" /></a>
  133. <p class="caption"><span class="caption-text"><em>Redrawing a figure with other geometric parameters</em></span></p>
  134. </div>
  135. <div class="section" id="basic-drawing">
  136. <h4>Basic Drawing<a class="headerlink" href="#basic-drawing" title="Permalink to this headline">¶</a></h4>
  137. <p>A typical program creating these five elements is shown next.
  138. After importing the <code class="docutils literal"><span class="pre">pysketcher</span></code> package, the first task is always to
  139. define a coordinate system:</p>
  140. <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">pysketcher</span> <span class="kn">import</span> <span class="o">*</span>
  141. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  142. <span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span> <span class="n">ymax</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
  143. </pre></div>
  144. </div>
  145. <p>Instead of working with lengths expressed by specific numbers it is
  146. highly recommended to use variables to parameterize lengths as
  147. this makes it easier to change dimensions later.
  148. Here we introduce some key lengths for the radius of the wheels,
  149. distance between the wheels, etc.:</p>
  150. <div class="highlight-python"><div class="highlight"><pre><span class="n">R</span> <span class="o">=</span> <span class="mi">1</span> <span class="c"># radius of wheel</span>
  151. <span class="n">L</span> <span class="o">=</span> <span class="mi">4</span> <span class="c"># distance between wheels</span>
  152. <span class="n">H</span> <span class="o">=</span> <span class="mi">2</span> <span class="c"># height of vehicle body</span>
  153. <span class="n">w_1</span> <span class="o">=</span> <span class="mi">5</span> <span class="c"># position of front wheel</span>
  154. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span><span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="n">w_1</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">L</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">R</span><span class="p">,</span>
  155. <span class="n">ymin</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span> <span class="n">ymax</span><span class="o">=</span><span class="mi">2</span><span class="o">*</span><span class="n">R</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">H</span><span class="p">)</span>
  156. </pre></div>
  157. </div>
  158. <p>With the drawing area in place we can make the first <code class="docutils literal"><span class="pre">Circle</span></code> object
  159. in an intuitive fashion:</p>
  160. <div class="highlight-python"><div class="highlight"><pre><span class="n">wheel1</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="n">R</span><span class="p">)</span>
  161. </pre></div>
  162. </div>
  163. <p>to change dimensions later.</p>
  164. <p>To translate the geometric information about the <code class="docutils literal"><span class="pre">wheel1</span></code> object to
  165. instructions for the plotting engine (in this case Matplotlib), one calls the
  166. <code class="docutils literal"><span class="pre">wheel1.draw()</span></code>. To display all drawn objects, one issues
  167. <code class="docutils literal"><span class="pre">drawing_tool.display()</span></code>. The typical steps are hence:</p>
  168. <div class="highlight-python"><div class="highlight"><pre><span class="n">wheel1</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="n">R</span><span class="p">)</span>
  169. <span class="n">wheel1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  170. <span class="c"># Define other objects and call their draw() methods</span>
  171. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  172. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">&#39;tmp.png&#39;</span><span class="p">)</span> <span class="c"># store picture</span>
  173. </pre></div>
  174. </div>
  175. <p>The next wheel can be made by taking a copy of <code class="docutils literal"><span class="pre">wheel1</span></code> and
  176. translating the object to the right according to a
  177. displacement vector <span class="math">\((L,0)\)</span>:</p>
  178. <div class="highlight-python"><div class="highlight"><pre><span class="n">wheel2</span> <span class="o">=</span> <span class="n">wheel1</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
  179. <span class="n">wheel2</span><span class="o">.</span><span class="n">translate</span><span class="p">((</span><span class="n">L</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
  180. </pre></div>
  181. </div>
  182. <p>The two rectangles are also made in an intuitive way:</p>
  183. <div class="highlight-python"><div class="highlight"><pre><span class="n">under</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">lower_left_corner</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="o">-</span><span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">),</span>
  184. <span class="n">width</span><span class="o">=</span><span class="mi">2</span><span class="o">*</span><span class="n">R</span> <span class="o">+</span> <span class="n">L</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="n">H</span><span class="p">)</span>
  185. <span class="n">over</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">lower_left_corner</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">R</span> <span class="o">+</span> <span class="n">H</span><span class="p">),</span>
  186. <span class="n">width</span><span class="o">=</span><span class="mf">2.5</span><span class="o">*</span><span class="n">R</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mf">1.25</span><span class="o">*</span><span class="n">H</span><span class="p">)</span>
  187. </pre></div>
  188. </div>
  189. </div>
  190. <div class="section" id="groups-of-objects">
  191. <h4>Groups of Objects<a class="headerlink" href="#groups-of-objects" title="Permalink to this headline">¶</a></h4>
  192. <p>Instead of calling the <code class="docutils literal"><span class="pre">draw</span></code> method of every object, we can
  193. group objects and call <code class="docutils literal"><span class="pre">draw</span></code>, or perform other operations, for
  194. the whole group. For example, we may collect the two wheels
  195. in a <code class="docutils literal"><span class="pre">wheels</span></code> group and the <code class="docutils literal"><span class="pre">over</span></code> and <code class="docutils literal"><span class="pre">under</span></code> rectangles
  196. in a <code class="docutils literal"><span class="pre">body</span></code> group. The whole vehicle is a composition
  197. of its <code class="docutils literal"><span class="pre">wheels</span></code> and <code class="docutils literal"><span class="pre">body</span></code> groups. The code goes like</p>
  198. <div class="highlight-python"><div class="highlight"><pre><span class="n">wheels</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">&#39;wheel1&#39;</span><span class="p">:</span> <span class="n">wheel1</span><span class="p">,</span> <span class="s">&#39;wheel2&#39;</span><span class="p">:</span> <span class="n">wheel2</span><span class="p">})</span>
  199. <span class="n">body</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">&#39;under&#39;</span><span class="p">:</span> <span class="n">under</span><span class="p">,</span> <span class="s">&#39;over&#39;</span><span class="p">:</span> <span class="n">over</span><span class="p">})</span>
  200. <span class="n">vehicle</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">&#39;wheels&#39;</span><span class="p">:</span> <span class="n">wheels</span><span class="p">,</span> <span class="s">&#39;body&#39;</span><span class="p">:</span> <span class="n">body</span><span class="p">})</span>
  201. </pre></div>
  202. </div>
  203. <p>The ground is illustrated by an object of type <code class="docutils literal"><span class="pre">Wall</span></code>,
  204. mostly used to indicate walls in sketches of mechanical systems.
  205. A <code class="docutils literal"><span class="pre">Wall</span></code> takes the <code class="docutils literal"><span class="pre">x</span></code> and <code class="docutils literal"><span class="pre">y</span></code> coordinates of some curve,
  206. and a <code class="docutils literal"><span class="pre">thickness</span></code> parameter, and creates a thick curve filled
  207. with a simple pattern. In this case the curve is just a flat
  208. line so the construction is made of two points on the
  209. ground line (<span class="math">\((w_1-L,0)\)</span> and <span class="math">\((w_1+3L,0)\)</span>):</p>
  210. <div class="highlight-python"><div class="highlight"><pre><span class="n">ground</span> <span class="o">=</span> <span class="n">Wall</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="p">[</span><span class="n">w_1</span> <span class="o">-</span> <span class="n">L</span><span class="p">,</span> <span class="n">w_1</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">L</span><span class="p">],</span> <span class="n">y</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">thickness</span><span class="o">=-</span><span class="mf">0.3</span><span class="o">*</span><span class="n">R</span><span class="p">)</span>
  211. </pre></div>
  212. </div>
  213. <p>The negative thickness makes the pattern-filled rectangle appear below
  214. the defined line, otherwise it appears above.</p>
  215. <p>We may now collect all the objects in a &#8220;top&#8221; object that contains
  216. the whole figure:</p>
  217. <div class="highlight-python"><div class="highlight"><pre><span class="n">fig</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">&#39;vehicle&#39;</span><span class="p">:</span> <span class="n">vehicle</span><span class="p">,</span> <span class="s">&#39;ground&#39;</span><span class="p">:</span> <span class="n">ground</span><span class="p">})</span>
  218. <span class="n">fig</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span> <span class="c"># send all figures to plotting backend</span>
  219. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  220. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">&#39;tmp.png&#39;</span><span class="p">)</span>
  221. </pre></div>
  222. </div>
  223. <p>The <code class="docutils literal"><span class="pre">fig.draw()</span></code> call will visit
  224. all subgroups, their subgroups,
  225. and so forth in the hierarchical tree structure of
  226. figure elements,
  227. and call <code class="docutils literal"><span class="pre">draw</span></code> for every object.</p>
  228. </div>
  229. <div class="section" id="changing-line-styles-and-colors">
  230. <h4>Changing Line Styles and Colors<a class="headerlink" href="#changing-line-styles-and-colors" title="Permalink to this headline">¶</a></h4>
  231. <p>Controlling the line style, line color, and line width is
  232. fundamental when designing figures. The <code class="docutils literal"><span class="pre">pysketcher</span></code>
  233. package allows the user to control such properties in
  234. single objects, but also set global properties that are
  235. used if the object has no particular specification of
  236. the properties. Setting the global properties are done like</p>
  237. <div class="highlight-python"><div class="highlight"><pre><span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">&#39;dashed&#39;</span><span class="p">)</span>
  238. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;black&#39;</span><span class="p">)</span>
  239. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  240. </pre></div>
  241. </div>
  242. <p>At the object level the properties are specified in a similar
  243. way:</p>
  244. <div class="highlight-python"><div class="highlight"><pre><span class="n">wheels</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">&#39;solid&#39;</span><span class="p">)</span>
  245. <span class="n">wheels</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;red&#39;</span><span class="p">)</span>
  246. </pre></div>
  247. </div>
  248. <p>and so on.</p>
  249. <p>Geometric figures can be specified as <em>filled</em>, either with a color or with a
  250. special visual pattern:</p>
  251. <div class="highlight-python"><div class="highlight"><pre><span class="c"># Set filling of all curves</span>
  252. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="n">color</span><span class="o">=</span><span class="s">&#39;blue&#39;</span><span class="p">,</span> <span class="n">pattern</span><span class="o">=</span><span class="s">&#39;/&#39;</span><span class="p">)</span>
  253. <span class="c"># Turn off filling of all curves</span>
  254. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span>
  255. <span class="c"># Fill the wheel with red color</span>
  256. <span class="n">wheel1</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">&#39;red&#39;</span><span class="p">)</span>
  257. </pre></div>
  258. </div>
  259. </div>
  260. <div class="section" id="the-figure-composition-as-an-object-hierarchy">
  261. <h4>The Figure Composition as an Object Hierarchy<a class="headerlink" href="#the-figure-composition-as-an-object-hierarchy" title="Permalink to this headline">¶</a></h4>
  262. <p>The composition of objects making up the figure
  263. is hierarchical, similar to a family, where
  264. each object has a parent and a number of children. Do a
  265. <code class="docutils literal"><span class="pre">print</span> <span class="pre">fig</span></code> to display the relations:</p>
  266. <div class="highlight-text"><div class="highlight"><pre>ground
  267. wall
  268. vehicle
  269. body
  270. over
  271. rectangle
  272. under
  273. rectangle
  274. wheels
  275. wheel1
  276. arc
  277. wheel2
  278. arc
  279. </pre></div>
  280. </div>
  281. <p>The indentation reflects how deep down in the hierarchy (family)
  282. we are.
  283. This output is to be interpreted as follows:</p>
  284. <blockquote>
  285. <div><ul class="simple">
  286. <li><code class="docutils literal"><span class="pre">fig</span></code> contains two objects, <code class="docutils literal"><span class="pre">ground</span></code> and <code class="docutils literal"><span class="pre">vehicle</span></code></li>
  287. <li><code class="docutils literal"><span class="pre">ground</span></code> contains an object <code class="docutils literal"><span class="pre">wall</span></code></li>
  288. <li><code class="docutils literal"><span class="pre">vehicle</span></code> contains two objects, <code class="docutils literal"><span class="pre">body</span></code> and <code class="docutils literal"><span class="pre">wheels</span></code></li>
  289. <li><code class="docutils literal"><span class="pre">body</span></code> contains two objects, <code class="docutils literal"><span class="pre">over</span></code> and <code class="docutils literal"><span class="pre">under</span></code></li>
  290. <li><code class="docutils literal"><span class="pre">wheels</span></code> contains two objects, <code class="docutils literal"><span class="pre">wheel1</span></code> and <code class="docutils literal"><span class="pre">wheel2</span></code></li>
  291. </ul>
  292. </div></blockquote>
  293. <p>In this listing there are also objects not defined by the
  294. programmer: <code class="docutils literal"><span class="pre">rectangle</span></code> and <code class="docutils literal"><span class="pre">arc</span></code>. These are of type <code class="docutils literal"><span class="pre">Curve</span></code>
  295. and automatically generated by the classes <code class="docutils literal"><span class="pre">Rectangle</span></code> and <code class="docutils literal"><span class="pre">Circle</span></code>.</p>
  296. <p>More detailed information can be printed by</p>
  297. <div class="highlight-python"><div class="highlight"><pre><span class="k">print</span> <span class="n">fig</span><span class="o">.</span><span class="n">show_hierarchy</span><span class="p">(</span><span class="s">&#39;std&#39;</span><span class="p">)</span>
  298. </pre></div>
  299. </div>
  300. <p>yielding the output</p>
  301. <div class="highlight-text"><div class="highlight"><pre>ground (Wall):
  302. wall (Curve): 4 coords fillcolor=&#39;white&#39; fillpattern=&#39;/&#39;
  303. vehicle (Composition):
  304. body (Composition):
  305. over (Rectangle):
  306. rectangle (Curve): 5 coords
  307. under (Rectangle):
  308. rectangle (Curve): 5 coords
  309. wheels (Composition):
  310. wheel1 (Circle):
  311. arc (Curve): 181 coords
  312. wheel2 (Circle):
  313. arc (Curve): 181 coords
  314. </pre></div>
  315. </div>
  316. <p>Here we can see the class type for each figure object, how many
  317. coordinates that are involved in basic figures (<code class="docutils literal"><span class="pre">Curve</span></code> objects), and
  318. special settings of the basic figure (fillcolor, line types, etc.).
  319. For example, <code class="docutils literal"><span class="pre">wheel2</span></code> is a <code class="docutils literal"><span class="pre">Circle</span></code> object consisting of an <code class="docutils literal"><span class="pre">arc</span></code>,
  320. which is a <code class="docutils literal"><span class="pre">Curve</span></code> object consisting of 181 coordinates (the
  321. points needed to draw a smooth circle). The <code class="docutils literal"><span class="pre">Curve</span></code> objects are the
  322. only objects that really holds specific coordinates to be drawn.
  323. The other object types are just compositions used to group
  324. parts of the complete figure.</p>
  325. <p>One can also get a graphical overview of the hierarchy of figure objects
  326. that build up a particular figure <code class="docutils literal"><span class="pre">fig</span></code>.
  327. Just call <code class="docutils literal"><span class="pre">fig.graphviz_dot('fig')</span></code> to produce a file <code class="docutils literal"><span class="pre">fig.dot</span></code> in
  328. the <em>dot format</em>. This file contains relations between parent and
  329. child objects in the figure and can be turned into an image,
  330. as in Figure <a class="reference internal" href="#sketcher-fig-vehicle0-hier1"><span class="std std-ref">Hierarchical relation between figure objects</span></a>, by
  331. running the <code class="docutils literal"><span class="pre">dot</span></code> program:</p>
  332. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; dot -Tpng -o fig.png fig.dot
  333. </pre></div>
  334. </div>
  335. <div class="figure" id="id5">
  336. <span id="sketcher-fig-vehicle0-hier1"></span><a class="reference internal image-reference" href="_images/vehicle0_hier1.png"><img alt="_images/vehicle0_hier1.png" src="_images/vehicle0_hier1.png" style="width: 500px;" /></a>
  337. <p class="caption"><span class="caption-text"><em>Hierarchical relation between figure objects</em></span></p>
  338. </div>
  339. <p>The call <code class="docutils literal"><span class="pre">fig.graphviz_dot('fig',</span> <span class="pre">classname=True)</span></code> makes a <code class="docutils literal"><span class="pre">fig.dot</span></code> file
  340. where the class type of each object is also visible, see
  341. Figure <span class="xref std std-ref">sketcher:fig:vehicle0:hier2</span>. The ability to write out the
  342. object hierarchy or view it graphically can be of great help when
  343. working with complex figures that involve layers of subfigures.</p>
  344. <div class="figure" id="id6">
  345. <span id="sketcher-fig-vehicle0-hier2"></span><a class="reference internal image-reference" href="_images/Vehicle0_hier2.png"><img alt="_images/Vehicle0_hier2.png" src="_images/Vehicle0_hier2.png" style="width: 500px;" /></a>
  346. <p class="caption"><span class="caption-text"><em>Hierarchical relation between figure objects, including their class names</em></span></p>
  347. </div>
  348. <p>Any of the objects can in the program be reached through their names, e.g.,</p>
  349. <div class="highlight-python"><div class="highlight"><pre><span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">]</span>
  350. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">]</span>
  351. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">]</span>
  352. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">][</span><span class="s">&#39;arc&#39;</span><span class="p">]</span>
  353. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">][</span><span class="s">&#39;arc&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="c"># x coords</span>
  354. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">][</span><span class="s">&#39;arc&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">y</span> <span class="c"># y coords</span>
  355. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">][</span><span class="s">&#39;arc&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">linestyle</span>
  356. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">][</span><span class="s">&#39;arc&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">linetype</span>
  357. </pre></div>
  358. </div>
  359. <p>Grabbing a part of the figure this way is handy for
  360. changing properties of that part, for example, colors, line styles
  361. (see Figure <a class="reference internal" href="#sketcher-fig-vehicle0-v2"><span class="std std-ref">Left: Basic line-based drawing. Right: Thicker lines and filled parts</span></a>):</p>
  362. <div class="highlight-python"><div class="highlight"><pre><span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">&#39;blue&#39;</span><span class="p">)</span>
  363. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
  364. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;black&#39;</span><span class="p">)</span>
  365. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;body&#39;</span><span class="p">][</span><span class="s">&#39;under&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">&#39;red&#39;</span><span class="p">)</span>
  366. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;body&#39;</span><span class="p">][</span><span class="s">&#39;over&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s">&#39;/&#39;</span><span class="p">)</span>
  367. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;body&#39;</span><span class="p">][</span><span class="s">&#39;over&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">14</span><span class="p">)</span>
  368. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;body&#39;</span><span class="p">][</span><span class="s">&#39;over&#39;</span><span class="p">][</span><span class="s">&#39;rectangle&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">linewidth</span> <span class="o">=</span> <span class="mi">4</span>
  369. </pre></div>
  370. </div>
  371. <p>The last line accesses the <code class="docutils literal"><span class="pre">Curve</span></code> object directly, while the line above,
  372. accesses the <code class="docutils literal"><span class="pre">Rectangle</span></code> object, which will then set the linewidth of
  373. its <code class="docutils literal"><span class="pre">Curve</span></code> object, and other objects if it had any.
  374. The result of the actions above is shown in Figure <a class="reference internal" href="#sketcher-fig-vehicle0-v2"><span class="std std-ref">Left: Basic line-based drawing. Right: Thicker lines and filled parts</span></a>.</p>
  375. <div class="figure" id="id7">
  376. <span id="sketcher-fig-vehicle0-v2"></span><a class="reference internal image-reference" href="_images/vehicle0.png"><img alt="_images/vehicle0.png" src="_images/vehicle0.png" style="width: 700px;" /></a>
  377. <p class="caption"><span class="caption-text"><em>Left: Basic line-based drawing. Right: Thicker lines and filled parts</em></span></p>
  378. </div>
  379. <p>We can also change position of parts of the figure and thereby make
  380. animations, as shown next.</p>
  381. </div>
  382. <div class="section" id="animation-translating-the-vehicle">
  383. <h4>Animation: Translating the Vehicle<a class="headerlink" href="#animation-translating-the-vehicle" title="Permalink to this headline">¶</a></h4>
  384. <p>Can we make our little vehicle roll? A first attempt will be to
  385. fake rolling by just displacing all parts of the vehicle.
  386. The relevant parts constitute the <code class="docutils literal"><span class="pre">fig['vehicle']</span></code> object.
  387. This part of the figure can be translated, rotated, and scaled.
  388. A translation along the ground means a translation in <span class="math">\(x\)</span> direction,
  389. say a length <span class="math">\(L\)</span> to the right:</p>
  390. <div class="highlight-python"><div class="highlight"><pre><span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">translate</span><span class="p">((</span><span class="n">L</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
  391. </pre></div>
  392. </div>
  393. <p>You need to erase, draw, and display to see the movement:</p>
  394. <div class="highlight-python"><div class="highlight"><pre><span class="n">drawing_tool</span><span class="o">.</span><span class="n">erase</span><span class="p">()</span>
  395. <span class="n">fig</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  396. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  397. </pre></div>
  398. </div>
  399. <p>Without erasing, the old drawing of the vehicle will remain in
  400. the figure so you get two vehicles. Without <code class="docutils literal"><span class="pre">fig.draw()</span></code> the
  401. new coordinates of the vehicle will not be communicated to
  402. the drawing tool, and without calling display the updated
  403. drawing will not be visible.</p>
  404. <p>A figure that moves in time is conveniently realized by the
  405. function <code class="docutils literal"><span class="pre">animate</span></code>:</p>
  406. <div class="highlight-python"><div class="highlight"><pre><span class="n">animate</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">tp</span><span class="p">,</span> <span class="n">action</span><span class="p">)</span>
  407. </pre></div>
  408. </div>
  409. <p>Here, <code class="docutils literal"><span class="pre">fig</span></code> is the entire figure, <code class="docutils literal"><span class="pre">tp</span></code> is an array of
  410. time points, and <code class="docutils literal"><span class="pre">action</span></code> is a user-specified function that changes
  411. <code class="docutils literal"><span class="pre">fig</span></code> at a specific time point. Typically, <code class="docutils literal"><span class="pre">action</span></code> will move
  412. parts of <code class="docutils literal"><span class="pre">fig</span></code>.</p>
  413. <p>In the present case we can define the movement through a velocity
  414. function <code class="docutils literal"><span class="pre">v(t)</span></code> and displace the figure <code class="docutils literal"><span class="pre">v(t)*dt</span></code> for small time
  415. intervals <code class="docutils literal"><span class="pre">dt</span></code>. A possible velocity function is</p>
  416. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">v</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
  417. <span class="k">return</span> <span class="o">-</span><span class="mi">8</span><span class="o">*</span><span class="n">R</span><span class="o">*</span><span class="n">t</span><span class="o">*</span><span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">t</span><span class="o">/</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">))</span>
  418. </pre></div>
  419. </div>
  420. <p>Our action function for horizontal displacements <code class="docutils literal"><span class="pre">v(t)*dt</span></code> becomes</p>
  421. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">fig</span><span class="p">):</span>
  422. <span class="n">x_displacement</span> <span class="o">=</span> <span class="n">dt</span><span class="o">*</span><span class="n">v</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
  423. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">translate</span><span class="p">((</span><span class="n">x_displacement</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
  424. </pre></div>
  425. </div>
  426. <p>Since our velocity is negative for <span class="math">\(t\in [0,2R]\)</span> the displacement is
  427. to the left.</p>
  428. <p>The <code class="docutils literal"><span class="pre">animate</span></code> function will for each time point <code class="docutils literal"><span class="pre">t</span></code> in <code class="docutils literal"><span class="pre">tp</span></code> erase
  429. the drawing, call <code class="docutils literal"><span class="pre">action(t,</span> <span class="pre">fig)</span></code>, and show the new figure by
  430. <code class="docutils literal"><span class="pre">fig.draw()</span></code> and <code class="docutils literal"><span class="pre">drawing_tool.display()</span></code>.
  431. Here we choose a resolution of the animation corresponding to
  432. 25 time points in the time interval <span class="math">\([0,2R]\)</span>:</p>
  433. <div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">numpy</span>
  434. <span class="n">tp</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span>
  435. <span class="n">dt</span> <span class="o">=</span> <span class="n">tp</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">tp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c"># time step</span>
  436. <span class="n">animate</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">tp</span><span class="p">,</span> <span class="n">move</span><span class="p">,</span> <span class="n">pause_per_frame</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)</span>
  437. </pre></div>
  438. </div>
  439. <p>The <code class="docutils literal"><span class="pre">pause_per_frame</span></code> adds a pause, here 0.2 seconds, between
  440. each frame in the animation.</p>
  441. <p>We can also ask <code class="docutils literal"><span class="pre">animate</span></code> to store each frame in a file:</p>
  442. <div class="highlight-python"><div class="highlight"><pre><span class="n">files</span> <span class="o">=</span> <span class="n">animate</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">tp</span><span class="p">,</span> <span class="n">move_vehicle</span><span class="p">,</span> <span class="n">moviefiles</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
  443. <span class="n">pause_per_frame</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)</span>
  444. </pre></div>
  445. </div>
  446. <p>The <code class="docutils literal"><span class="pre">files</span></code> variable, here <code class="docutils literal"><span class="pre">'tmp_frame_%04d.png'</span></code>,
  447. is the printf-specification used to generate the individual
  448. plot files. We can use this specification to make a video
  449. file via <code class="docutils literal"><span class="pre">ffmpeg</span></code> (or <code class="docutils literal"><span class="pre">avconv</span></code> on Debian-based Linux systems such
  450. as Ubuntu). Videos in the Flash and WebM formats can be created
  451. by</p>
  452. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec flv mov.flv
  453. Terminal&gt; ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec libvpx mov.webm
  454. </pre></div>
  455. </div>
  456. <p>An animated GIF movie can also be made using the <code class="docutils literal"><span class="pre">convert</span></code> program
  457. from the ImageMagick software suite:</p>
  458. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; convert -delay 20 tmp_frame*.png mov.gif
  459. Terminal&gt; animate mov.gif # play movie
  460. </pre></div>
  461. </div>
  462. <p>The delay between frames, in units of 1/100 s,
  463. governs the speed of the movie.
  464. To play the animated GIF file in a web page, simply insert
  465. <code class="docutils literal"><span class="pre">&lt;img</span> <span class="pre">src=&quot;mov.gif&quot;&gt;</span></code> in the HTML code.</p>
  466. <p>The individual PNG frames can be directly played in a web
  467. browser by running</p>
  468. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; scitools movie output_file=mov.html fps=5 tmp_frame*
  469. </pre></div>
  470. </div>
  471. <p>or calling</p>
  472. <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">scitools.std</span> <span class="kn">import</span> <span class="n">movie</span>
  473. <span class="n">movie</span><span class="p">(</span><span class="n">files</span><span class="p">,</span> <span class="n">encoder</span><span class="o">=</span><span class="s">&#39;html&#39;</span><span class="p">,</span> <span class="n">output_file</span><span class="o">=</span><span class="s">&#39;mov.html&#39;</span><span class="p">)</span>
  474. </pre></div>
  475. </div>
  476. <p>in Python. Load the resulting file <code class="docutils literal"><span class="pre">mov.html</span></code> into a web browser
  477. to play the movie.</p>
  478. <p>Try to run <a class="reference external" href="http://tinyurl.com/ot733jn/vehicle0.py">vehicle0.py</a> and
  479. then load <code class="docutils literal"><span class="pre">mov.html</span></code> into a browser, or play one of the <code class="docutils literal"><span class="pre">mov.*</span></code>
  480. video files. Alternatively, you can view a ready-made <a class="reference external" href="http://tinyurl.com/oou9lp7/mov-tut/vehicle0.html">movie</a>.</p>
  481. </div>
  482. <div class="section" id="animation-rolling-the-wheels">
  483. <span id="sketcher-vehicle1-anim"></span><h4>Animation: Rolling the Wheels<a class="headerlink" href="#animation-rolling-the-wheels" title="Permalink to this headline">¶</a></h4>
  484. <p>It is time to show rolling wheels. To this end, we add spokes to the
  485. wheels, formed by two crossing lines, see Figure <a class="reference internal" href="#sketcher-fig-vehicle1"><span class="std std-ref">Wheels with spokes to illustrate rolling</span></a>.
  486. The construction of the wheels will now involve a circle and two lines:</p>
  487. <div class="highlight-python"><div class="highlight"><pre><span class="n">wheel1</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span>
  488. <span class="s">&#39;wheel&#39;</span><span class="p">:</span> <span class="n">Circle</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="n">R</span><span class="p">),</span>
  489. <span class="s">&#39;cross&#39;</span><span class="p">:</span> <span class="n">Composition</span><span class="p">({</span><span class="s">&#39;cross1&#39;</span><span class="p">:</span> <span class="n">Line</span><span class="p">((</span><span class="n">w_1</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="n">w_1</span><span class="p">,</span><span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">)),</span>
  490. <span class="s">&#39;cross2&#39;</span><span class="p">:</span> <span class="n">Line</span><span class="p">((</span><span class="n">w_1</span><span class="o">-</span><span class="n">R</span><span class="p">,</span><span class="n">R</span><span class="p">),</span> <span class="p">(</span><span class="n">w_1</span><span class="o">+</span><span class="n">R</span><span class="p">,</span><span class="n">R</span><span class="p">))})})</span>
  491. <span class="n">wheel2</span> <span class="o">=</span> <span class="n">wheel1</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
  492. <span class="n">wheel2</span><span class="o">.</span><span class="n">translate</span><span class="p">((</span><span class="n">L</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
  493. </pre></div>
  494. </div>
  495. <p>Observe that <code class="docutils literal"><span class="pre">wheel1.copy()</span></code> copies all the objects that make
  496. up the first wheel, and <code class="docutils literal"><span class="pre">wheel2.translate</span></code> translates all
  497. the copied objects.</p>
  498. <div class="figure" id="id8">
  499. <span id="sketcher-fig-vehicle1"></span><a class="reference internal image-reference" href="_images/vehicle1.png"><img alt="_images/vehicle1.png" src="_images/vehicle1.png" style="width: 400px;" /></a>
  500. <p class="caption"><span class="caption-text"><em>Wheels with spokes to illustrate rolling</em></span></p>
  501. </div>
  502. <p>The <code class="docutils literal"><span class="pre">move</span></code> function now needs to displace all the objects in the
  503. entire vehicle and also rotate the <code class="docutils literal"><span class="pre">cross1</span></code> and <code class="docutils literal"><span class="pre">cross2</span></code>
  504. objects in both wheels.
  505. The rotation angle follows from the fact that the arc length
  506. of a rolling wheel equals the displacement of the center of
  507. the wheel, leading to a rotation angle</p>
  508. <div class="highlight-python"><div class="highlight"><pre><span class="n">angle</span> <span class="o">=</span> <span class="o">-</span> <span class="n">x_displacement</span><span class="o">/</span><span class="n">R</span>
  509. </pre></div>
  510. </div>
  511. <p>With <code class="docutils literal"><span class="pre">w_1</span></code> tracking the <span class="math">\(x\)</span> coordinate of the center
  512. of the front wheel, we can rotate that wheel by</p>
  513. <div class="highlight-python"><div class="highlight"><pre><span class="n">w1</span> <span class="o">=</span> <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel1&#39;</span><span class="p">]</span>
  514. <span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">degrees</span>
  515. <span class="n">w1</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="n">degrees</span><span class="p">(</span><span class="n">angle</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">))</span>
  516. </pre></div>
  517. </div>
  518. <p>The <code class="docutils literal"><span class="pre">rotate</span></code> function takes two parameters: the rotation angle
  519. (in degrees) and the center point of the rotation, which is the
  520. center of the wheel in this case. The other wheel is rotated by</p>
  521. <div class="highlight-python"><div class="highlight"><pre><span class="n">w2</span> <span class="o">=</span> <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">]</span>
  522. <span class="n">w2</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="n">degrees</span><span class="p">(</span><span class="n">angle</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span> <span class="o">+</span> <span class="n">L</span><span class="p">,</span> <span class="n">R</span><span class="p">))</span>
  523. </pre></div>
  524. </div>
  525. <p>That is, the angle is the same, but the rotation point is different.
  526. The update of the center point is done by <code class="docutils literal"><span class="pre">w_1</span> <span class="pre">+=</span> <span class="pre">x_displacement</span></code>.
  527. The complete <code class="docutils literal"><span class="pre">move</span></code> function with translation of the entire
  528. vehicle and rotation of the wheels then becomes</p>
  529. <div class="highlight-python"><div class="highlight"><pre><span class="n">w_1</span> <span class="o">=</span> <span class="n">w_1</span> <span class="o">+</span> <span class="n">L</span> <span class="c"># start position</span>
  530. <span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">fig</span><span class="p">):</span>
  531. <span class="n">x_displacement</span> <span class="o">=</span> <span class="n">dt</span><span class="o">*</span><span class="n">v</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
  532. <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">translate</span><span class="p">((</span><span class="n">x_displacement</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
  533. <span class="c"># Rotate wheels</span>
  534. <span class="k">global</span> <span class="n">w_1</span>
  535. <span class="n">w_1</span> <span class="o">+=</span> <span class="n">x_displacement</span>
  536. <span class="c"># R*angle = -x_displacement</span>
  537. <span class="n">angle</span> <span class="o">=</span> <span class="o">-</span> <span class="n">x_displacement</span><span class="o">/</span><span class="n">R</span>
  538. <span class="n">w1</span> <span class="o">=</span> <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel1&#39;</span><span class="p">]</span>
  539. <span class="n">w1</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="n">degrees</span><span class="p">(</span><span class="n">angle</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">))</span>
  540. <span class="n">w2</span> <span class="o">=</span> <span class="n">fig</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">][</span><span class="s">&#39;wheel2&#39;</span><span class="p">]</span>
  541. <span class="n">w2</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="n">degrees</span><span class="p">(</span><span class="n">angle</span><span class="p">),</span> <span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span> <span class="o">+</span> <span class="n">L</span><span class="p">,</span> <span class="n">R</span><span class="p">))</span>
  542. </pre></div>
  543. </div>
  544. <p>The complete example is found in the file
  545. <a class="reference external" href="http://tinyurl.com/ot733jn/vehicle1.py">vehicle1.py</a>. You may run this file or watch a <a class="reference external" href="http://tinyurl.com/oou9lp7/mov-tut/vehicle1.html">ready-made movie</a>.</p>
  546. <p>The advantages with making figures this way, through programming
  547. rather than using interactive drawing programs, are numerous. For
  548. example, the objects are parameterized by variables so that various
  549. dimensions can easily be changed. Subparts of the figure, possible
  550. involving a lot of figure objects, can change color, linetype, filling
  551. or other properties through a <em>single</em> function call. Subparts of the
  552. figure can be rotated, translated, or scaled. Subparts of the figure
  553. can also be copied and moved to other parts of the drawing
  554. area. However, the single most important feature is probably the
  555. ability to make animations governed by mathematical formulas or data
  556. coming from physics simulations of the problem, as shown in the example above.</p>
  557. </div>
  558. </div>
  559. </div>
  560. <div class="section" id="basic-shapes">
  561. <h2>Basic Shapes<a class="headerlink" href="#basic-shapes" title="Permalink to this headline">¶</a></h2>
  562. <p>This section presents many of the basic shapes in Pysketcher:
  563. <code class="docutils literal"><span class="pre">Axis</span></code>, <code class="docutils literal"><span class="pre">Distance_wText</span></code>, <code class="docutils literal"><span class="pre">Rectangle</span></code>, <code class="docutils literal"><span class="pre">Triangle</span></code>, <code class="docutils literal"><span class="pre">Arc</span></code>,
  564. <code class="docutils literal"><span class="pre">Spring</span></code>, <code class="docutils literal"><span class="pre">Dashpot</span></code>, and <code class="docutils literal"><span class="pre">Wavy</span></code>.
  565. Each shape is demonstrated with a figure and a
  566. unit test that shows how the figure is constructed in Python code.
  567. These demos rely heavily on the method <code class="docutils literal"><span class="pre">draw_dimensions</span></code> in
  568. the shape classes, which annotates the basic drawing of the shape
  569. with the various geometric parameters that govern the shape.</p>
  570. <div class="section" id="axis">
  571. <h3>Axis<a class="headerlink" href="#axis" title="Permalink to this headline">¶</a></h3>
  572. <p>The <code class="docutils literal"><span class="pre">Axis</span></code> object gives the possibility draw a single axis to
  573. notify a coordinate system. Here is an example where we
  574. draw <span class="math">\(x\)</span> and <span class="math">\(y\)</span> axis of three coordinate systems of different
  575. rotation:</p>
  576. <div class="line-block">
  577. <div class="line"><br /></div>
  578. <div class="line"><br /></div>
  579. </div>
  580. <div class="figure">
  581. <a class="reference internal image-reference" href="_images/Axis.png"><img alt="_images/Axis.png" src="_images/Axis.png" style="width: 500px;" /></a>
  582. </div>
  583. <div class="line-block">
  584. <div class="line"><br /></div>
  585. <div class="line"><br /></div>
  586. </div>
  587. <p>The corresponding code looks like this:</p>
  588. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Axis</span><span class="p">():</span>
  589. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  590. <span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=-</span><span class="mi">7</span><span class="p">,</span> <span class="n">ymax</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
  591. <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Axis.py&#39;</span><span class="p">)</span>
  592. <span class="c"># Draw normal x and y axis with origin at (7.5, 2)</span>
  593. <span class="c"># in the coordinate system of the sketch: [0,15]x[-7,8]</span>
  594. <span class="n">x_axis</span> <span class="o">=</span> <span class="n">Axis</span><span class="p">((</span><span class="mf">7.5</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="mi">5</span><span class="p">,</span> <span class="s">&#39;x&#39;</span><span class="p">,</span> <span class="n">rotation_angle</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
  595. <span class="n">y_axis</span> <span class="o">=</span> <span class="n">Axis</span><span class="p">((</span><span class="mf">7.5</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="mi">5</span><span class="p">,</span> <span class="s">&#39;y&#39;</span><span class="p">,</span> <span class="n">rotation_angle</span><span class="o">=</span><span class="mi">90</span><span class="p">)</span>
  596. <span class="n">system</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">&#39;x axis&#39;</span><span class="p">:</span> <span class="n">x_axis</span><span class="p">,</span> <span class="s">&#39;y axis&#39;</span><span class="p">:</span> <span class="n">y_axis</span><span class="p">})</span>
  597. <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  598. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  599. <span class="c"># Rotate this system 40 degrees counter clockwise</span>
  600. <span class="c"># and draw it with dashed lines</span>
  601. <span class="n">system</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">&#39;dashed&#39;</span><span class="p">)</span>
  602. <span class="n">system</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="mi">40</span><span class="p">,</span> <span class="p">(</span><span class="mf">7.5</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
  603. <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  604. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  605. <span class="c"># Rotate this system another 220 degrees and show</span>
  606. <span class="c"># with dotted lines</span>
  607. <span class="n">system</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">&#39;dotted&#39;</span><span class="p">)</span>
  608. <span class="n">system</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="mi">220</span><span class="p">,</span> <span class="p">(</span><span class="mf">7.5</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
  609. <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  610. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  611. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">&#39;Axis&#39;</span><span class="p">)</span>
  612. </pre></div>
  613. </div>
  614. </div>
  615. <div class="section" id="distance-with-text">
  616. <h3>Distance with Text<a class="headerlink" href="#distance-with-text" title="Permalink to this headline">¶</a></h3>
  617. <p>The object <code class="docutils literal"><span class="pre">Distance_wText</span></code> is used to display an arrow, to indicate
  618. a distance in a sketch, with an additional text in the middle of the arrow.</p>
  619. <p>The figure</p>
  620. <div class="line-block">
  621. <div class="line"><br /></div>
  622. <div class="line"><br /></div>
  623. </div>
  624. <div class="figure">
  625. <a class="reference internal image-reference" href="_images/Distance_wText.png"><img alt="_images/Distance_wText.png" src="_images/Distance_wText.png" style="width: 500px;" /></a>
  626. </div>
  627. <div class="line-block">
  628. <div class="line"><br /></div>
  629. <div class="line"><br /></div>
  630. </div>
  631. <p>was produced by this code:</p>
  632. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Distance_wText</span><span class="p">():</span>
  633. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  634. <span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">ymax</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span>
  635. <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Distance_wText.py&#39;</span><span class="p">)</span>
  636. <span class="n">fontsize</span><span class="o">=</span><span class="mi">14</span>
  637. <span class="n">t</span> <span class="o">=</span> <span class="s">r&#39;$ 2\pi R^2 $&#39;</span> <span class="c"># sample text</span>
  638. <span class="n">examples</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span>
  639. <span class="s">&#39;a0&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">((</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="n">t</span><span class="p">,</span> <span class="n">fontsize</span><span class="p">),</span>
  640. <span class="s">&#39;a6&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">((</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="n">t</span><span class="p">,</span> <span class="n">fontsize</span><span class="p">),</span>
  641. <span class="s">&#39;a1&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mf">4.5</span><span class="p">),</span> <span class="n">t</span><span class="p">,</span> <span class="n">fontsize</span><span class="p">),</span>
  642. <span class="s">&#39;a2&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">t</span><span class="p">,</span> <span class="n">fontsize</span><span class="p">),</span>
  643. <span class="s">&#39;a3&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mf">4.5</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">5.5</span><span class="p">),</span> <span class="n">t</span><span class="p">,</span> <span class="n">fontsize</span><span class="p">),</span>
  644. <span class="s">&#39;a4&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">((</span><span class="mi">8</span><span class="p">,</span><span class="mi">4</span><span class="p">),</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">t</span><span class="p">,</span> <span class="n">fontsize</span><span class="p">,</span>
  645. <span class="n">text_spacing</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="mf">1.</span><span class="p">,</span><span class="mi">60</span><span class="p">)),</span>
  646. <span class="s">&#39;a5&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">((</span><span class="mi">8</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">t</span><span class="p">,</span> <span class="n">fontsize</span><span class="p">,</span>
  647. <span class="n">text_spacing</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="mf">1.</span><span class="p">,</span><span class="mi">40</span><span class="p">),</span> <span class="n">alignment</span><span class="o">=</span><span class="s">&#39;right&#39;</span><span class="p">),</span>
  648. <span class="s">&#39;c1&#39;</span><span class="p">:</span> <span class="n">Text_wArrow</span><span class="p">(</span><span class="s">&#39;text_spacing=-1./60&#39;</span><span class="p">,</span>
  649. <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mf">3.5</span><span class="p">),</span> <span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mf">3.2</span><span class="p">),</span>
  650. <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">alignment</span><span class="o">=</span><span class="s">&#39;left&#39;</span><span class="p">),</span>
  651. <span class="s">&#39;c2&#39;</span><span class="p">:</span> <span class="n">Text_wArrow</span><span class="p">(</span><span class="s">&#39;text_spacing=-1./40, alignment=&quot;right&quot;&#39;</span><span class="p">,</span>
  652. <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">),</span> <span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">),</span>
  653. <span class="n">fontsize</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">alignment</span><span class="o">=</span><span class="s">&#39;left&#39;</span><span class="p">),</span>
  654. <span class="p">})</span>
  655. <span class="n">examples</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  656. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">&#39;Distance_wText and text positioning&#39;</span><span class="p">)</span>
  657. </pre></div>
  658. </div>
  659. <p>Note the use of <code class="docutils literal"><span class="pre">Text_wArrow</span></code> to write an explaining text with an
  660. associated arrow, here used to explain how
  661. the <code class="docutils literal"><span class="pre">text_spacing</span></code> and <code class="docutils literal"><span class="pre">alignment</span></code> arguments can be used to adjust
  662. the appearance of the text that goes with the distance arrow.</p>
  663. </div>
  664. <div class="section" id="rectangle">
  665. <h3>Rectangle<a class="headerlink" href="#rectangle" title="Permalink to this headline">¶</a></h3>
  666. <div class="figure">
  667. <a class="reference internal image-reference" href="_images/Rectangle.png"><img alt="_images/Rectangle.png" src="_images/Rectangle.png" style="width: 500px;" /></a>
  668. </div>
  669. <div class="line-block">
  670. <div class="line"><br /></div>
  671. <div class="line"><br /></div>
  672. </div>
  673. <p>The above figure can be produced by the following code.</p>
  674. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Rectangle</span><span class="p">():</span>
  675. <span class="n">L</span> <span class="o">=</span> <span class="mf">3.0</span>
  676. <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
  677. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  678. <span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="mi">2</span><span class="o">*</span><span class="n">W</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="n">L</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">ymax</span><span class="o">=</span><span class="mi">2</span><span class="o">*</span><span class="n">L</span><span class="p">,</span>
  679. <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Rectangle.py&#39;</span><span class="p">)</span>
  680. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;blue&#39;</span><span class="p">)</span>
  681. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_grid</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
  682. <span class="n">xpos</span> <span class="o">=</span> <span class="n">old_div</span><span class="p">(</span><span class="n">W</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span>
  683. <span class="n">r</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">lower_left_corner</span><span class="o">=</span><span class="p">(</span><span class="n">xpos</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="n">width</span><span class="o">=</span><span class="n">W</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="n">L</span><span class="p">)</span>
  684. <span class="n">r</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  685. <span class="n">r</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  686. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">&#39;Rectangle&#39;</span><span class="p">)</span>
  687. </pre></div>
  688. </div>
  689. <p>Note that the <code class="docutils literal"><span class="pre">draw_dimension</span></code> method adds explanation of dimensions and various
  690. important argument in the construction of a shape. It adapts the annotations
  691. to the geometry of the current shape.</p>
  692. </div>
  693. <div class="section" id="triangle">
  694. <h3>Triangle<a class="headerlink" href="#triangle" title="Permalink to this headline">¶</a></h3>
  695. <div class="figure">
  696. <a class="reference internal image-reference" href="_images/Triangle.png"><img alt="_images/Triangle.png" src="_images/Triangle.png" style="width: 500px;" /></a>
  697. </div>
  698. <div class="line-block">
  699. <div class="line"><br /></div>
  700. <div class="line"><br /></div>
  701. </div>
  702. <p>The code below produces the figure.</p>
  703. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Triangle</span><span class="p">():</span>
  704. <span class="n">L</span> <span class="o">=</span> <span class="mf">3.0</span>
  705. <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
  706. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  707. <span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="mi">2</span><span class="o">*</span><span class="n">W</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="n">L</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">ymax</span><span class="o">=</span><span class="mf">1.2</span><span class="o">*</span><span class="n">L</span><span class="p">,</span>
  708. <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Triangle.py&#39;</span><span class="p">)</span>
  709. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;blue&#39;</span><span class="p">)</span>
  710. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_grid</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
  711. <span class="n">xpos</span> <span class="o">=</span> <span class="mi">1</span>
  712. <span class="n">t</span> <span class="o">=</span> <span class="n">Triangle</span><span class="p">(</span><span class="n">p1</span><span class="o">=</span><span class="p">(</span><span class="n">old_div</span><span class="p">(</span><span class="n">W</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span><span class="mi">0</span><span class="p">),</span> <span class="n">p2</span><span class="o">=</span><span class="p">(</span><span class="mi">3</span><span class="o">*</span><span class="n">W</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="n">old_div</span><span class="p">(</span><span class="n">W</span><span class="p">,</span><span class="mi">2</span><span class="p">)),</span> <span class="n">p3</span><span class="o">=</span><span class="p">(</span><span class="mi">4</span><span class="o">*</span><span class="n">W</span><span class="o">/</span><span class="mf">5.</span><span class="p">,</span><span class="n">L</span><span class="p">))</span>
  713. <span class="n">t</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  714. <span class="n">t</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  715. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">&#39;Triangle&#39;</span><span class="p">)</span>
  716. </pre></div>
  717. </div>
  718. <p>Here, the <code class="docutils literal"><span class="pre">draw_dimension</span></code> method writes the name of the corners at the
  719. position of the corners, which does not always look nice (the present figure
  720. is an example). For a high-quality sketch one would add some spacing
  721. to the location of the p1, p2, and even p3 texts.</p>
  722. </div>
  723. <div class="section" id="arc">
  724. <h3>Arc<a class="headerlink" href="#arc" title="Permalink to this headline">¶</a></h3>
  725. <div class="figure">
  726. <a class="reference internal image-reference" href="_images/Arc.png"><img alt="_images/Arc.png" src="_images/Arc.png" style="width: 400px;" /></a>
  727. </div>
  728. <div class="line-block">
  729. <div class="line"><br /></div>
  730. <div class="line"><br /></div>
  731. </div>
  732. <p>An arc like the one above is produced by</p>
  733. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Arc</span><span class="p">():</span>
  734. <span class="n">L</span> <span class="o">=</span> <span class="mf">4.0</span>
  735. <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
  736. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  737. <span class="n">xmin</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="n">W</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">xmax</span><span class="o">=</span><span class="n">W</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="n">L</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">ymax</span><span class="o">=</span><span class="mf">1.5</span><span class="o">*</span><span class="n">L</span><span class="p">,</span>
  738. <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Arc.py&#39;</span><span class="p">)</span>
  739. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;blue&#39;</span><span class="p">)</span>
  740. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_grid</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
  741. <span class="n">center</span> <span class="o">=</span> <span class="n">point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span>
  742. <span class="n">radius</span> <span class="o">=</span> <span class="n">old_div</span><span class="p">(</span><span class="n">L</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span>
  743. <span class="n">start_angle</span> <span class="o">=</span> <span class="mi">60</span>
  744. <span class="n">arc_angle</span> <span class="o">=</span> <span class="mi">45</span>
  745. <span class="n">a</span> <span class="o">=</span> <span class="n">Arc</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">radius</span><span class="p">,</span> <span class="n">start_angle</span><span class="p">,</span> <span class="n">arc_angle</span><span class="p">)</span>
  746. <span class="n">a</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  747. <span class="n">R1</span> <span class="o">=</span> <span class="mf">1.25</span><span class="o">*</span><span class="n">radius</span>
  748. <span class="n">R2</span> <span class="o">=</span> <span class="mf">1.5</span><span class="o">*</span><span class="n">radius</span>
  749. <span class="n">R</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">radius</span>
  750. <span class="n">a</span><span class="o">.</span><span class="n">dimensions</span> <span class="o">=</span> <span class="p">{</span>
  751. <span class="s">&#39;start_angle&#39;</span><span class="p">:</span>
  752. <span class="n">Arc_wText</span><span class="p">(</span>
  753. <span class="s">&#39;start_angle&#39;</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">R1</span><span class="p">,</span> <span class="n">start_angle</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
  754. <span class="n">arc_angle</span><span class="o">=</span><span class="n">start_angle</span><span class="p">,</span> <span class="n">text_spacing</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mf">10.</span><span class="p">)),</span>
  755. <span class="s">&#39;arc_angle&#39;</span><span class="p">:</span>
  756. <span class="n">Arc_wText</span><span class="p">(</span>
  757. <span class="s">&#39;arc_angle&#39;</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">R2</span><span class="p">,</span> <span class="n">start_angle</span><span class="o">=</span><span class="n">start_angle</span><span class="p">,</span>
  758. <span class="n">arc_angle</span><span class="o">=</span><span class="n">arc_angle</span><span class="p">,</span> <span class="n">text_spacing</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mf">20.</span><span class="p">)),</span>
  759. <span class="s">&#39;r=0&#39;</span><span class="p">:</span>
  760. <span class="n">Line</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">center</span> <span class="o">+</span>
  761. <span class="n">point</span><span class="p">(</span><span class="n">R</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">start_angle</span><span class="p">)),</span>
  762. <span class="n">R</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">start_angle</span><span class="p">)))),</span>
  763. <span class="s">&#39;r=start_angle&#39;</span><span class="p">:</span>
  764. <span class="n">Line</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">center</span> <span class="o">+</span>
  765. <span class="n">point</span><span class="p">(</span><span class="n">R</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">start_angle</span><span class="o">+</span><span class="n">arc_angle</span><span class="p">)),</span>
  766. <span class="n">R</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">start_angle</span><span class="o">+</span><span class="n">arc_angle</span><span class="p">)))),</span>
  767. <span class="s">&#39;r=start+arc_angle&#39;</span><span class="p">:</span>
  768. <span class="n">Line</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">center</span> <span class="o">+</span>
  769. <span class="n">point</span><span class="p">(</span><span class="n">R</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">&#39;dashed&#39;</span><span class="p">),</span>
  770. <span class="s">&#39;radius&#39;</span><span class="p">:</span> <span class="n">Distance_wText</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">a</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="s">&#39;radius&#39;</span><span class="p">,</span> <span class="n">text_spacing</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mf">40.</span><span class="p">)),</span>
  771. <span class="s">&#39;center&#39;</span><span class="p">:</span> <span class="n">Text</span><span class="p">(</span><span class="s">&#39;center&#39;</span><span class="p">,</span> <span class="n">center</span><span class="o">-</span><span class="n">point</span><span class="p">(</span><span class="n">old_div</span><span class="p">(</span><span class="n">radius</span><span class="p">,</span><span class="mf">10.</span><span class="p">),</span> <span class="n">old_div</span><span class="p">(</span><span class="n">radius</span><span class="p">,</span><span class="mf">10.</span><span class="p">))),</span>
  772. <span class="p">}</span>
  773. <span class="k">for</span> <span class="n">dimension</span> <span class="ow">in</span> <span class="n">a</span><span class="o">.</span><span class="n">dimensions</span><span class="p">:</span>
  774. <span class="k">if</span> <span class="n">dimension</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&#39;r=&#39;</span><span class="p">):</span>
  775. <span class="n">dim</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">dimensions</span><span class="p">[</span><span class="n">dimension</span><span class="p">]</span>
  776. <span class="n">dim</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">&#39;dashed&#39;</span><span class="p">)</span>
  777. <span class="n">dim</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  778. <span class="n">dim</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;black&#39;</span><span class="p">)</span>
  779. <span class="n">a</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  780. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">&#39;Arc&#39;</span><span class="p">)</span>
  781. </pre></div>
  782. </div>
  783. </div>
  784. <div class="section" id="spring">
  785. <h3>Spring<a class="headerlink" href="#spring" title="Permalink to this headline">¶</a></h3>
  786. <div class="figure">
  787. <a class="reference internal image-reference" href="_images/Spring.png"><img alt="_images/Spring.png" src="_images/Spring.png" style="width: 800px;" /></a>
  788. </div>
  789. <div class="line-block">
  790. <div class="line"><br /></div>
  791. <div class="line"><br /></div>
  792. </div>
  793. <p>The code for making these two springs goes like this:</p>
  794. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Spring</span><span class="p">():</span>
  795. <span class="n">L</span> <span class="o">=</span> <span class="mf">5.0</span>
  796. <span class="n">W</span> <span class="o">=</span> <span class="mf">2.0</span>
  797. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  798. <span class="n">xmin</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="mi">7</span><span class="o">*</span><span class="n">W</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="n">L</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">ymax</span><span class="o">=</span><span class="mf">1.5</span><span class="o">*</span><span class="n">L</span><span class="p">,</span>
  799. <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Spring.py&#39;</span><span class="p">)</span>
  800. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;blue&#39;</span><span class="p">)</span>
  801. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_grid</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
  802. <span class="n">xpos</span> <span class="o">=</span> <span class="n">W</span>
  803. <span class="n">s1</span> <span class="o">=</span> <span class="n">Spring</span><span class="p">((</span><span class="n">W</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="n">L</span><span class="p">,</span> <span class="n">teeth</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
  804. <span class="n">s1_title</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">&#39;Default Spring&#39;</span><span class="p">,</span>
  805. <span class="n">s1</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">&#39;end&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">old_div</span><span class="p">(</span><span class="n">L</span><span class="p">,</span><span class="mi">10</span><span class="p">)))</span>
  806. <span class="n">s1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  807. <span class="n">s1_title</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  808. <span class="c">#s1.draw_dimensions()</span>
  809. <span class="n">xpos</span> <span class="o">+=</span> <span class="mi">3</span><span class="o">*</span><span class="n">W</span>
  810. <span class="n">s2</span> <span class="o">=</span> <span class="n">Spring</span><span class="p">(</span><span class="n">start</span><span class="o">=</span><span class="p">(</span><span class="n">xpos</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="n">length</span><span class="o">=</span><span class="n">L</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="n">W</span><span class="p">,</span><span class="mf">2.</span><span class="p">),</span>
  811. <span class="n">bar_length</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="n">L</span><span class="p">,</span><span class="mf">6.</span><span class="p">),</span> <span class="n">teeth</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
  812. <span class="n">s2</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  813. <span class="n">s2</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  814. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">&#39;Spring&#39;</span><span class="p">)</span>
  815. </pre></div>
  816. </div>
  817. </div>
  818. <div class="section" id="dashpot">
  819. <h3>Dashpot<a class="headerlink" href="#dashpot" title="Permalink to this headline">¶</a></h3>
  820. <div class="figure">
  821. <a class="reference internal image-reference" href="_images/Dashpot.png"><img alt="_images/Dashpot.png" src="_images/Dashpot.png" style="width: 600px;" /></a>
  822. </div>
  823. <div class="line-block">
  824. <div class="line"><br /></div>
  825. <div class="line"><br /></div>
  826. </div>
  827. <p>This dashpot is produced by</p>
  828. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Dashpot</span><span class="p">():</span>
  829. <span class="n">L</span> <span class="o">=</span> <span class="mf">5.0</span>
  830. <span class="n">W</span> <span class="o">=</span> <span class="mf">2.0</span>
  831. <span class="n">xpos</span> <span class="o">=</span> <span class="mi">0</span>
  832. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  833. <span class="n">xmin</span><span class="o">=</span><span class="n">xpos</span><span class="p">,</span> <span class="n">xmax</span><span class="o">=</span><span class="n">xpos</span><span class="o">+</span><span class="mf">5.5</span><span class="o">*</span><span class="n">W</span><span class="p">,</span> <span class="n">ymin</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="o">-</span><span class="n">L</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">ymax</span><span class="o">=</span><span class="mf">1.5</span><span class="o">*</span><span class="n">L</span><span class="p">,</span>
  834. <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Dashpot.py&#39;</span><span class="p">)</span>
  835. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;blue&#39;</span><span class="p">)</span>
  836. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_grid</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
  837. <span class="c"># Default (simple) dashpot</span>
  838. <span class="n">xpos</span> <span class="o">=</span> <span class="mf">1.5</span>
  839. <span class="n">d1</span> <span class="o">=</span> <span class="n">Dashpot</span><span class="p">(</span><span class="n">start</span><span class="o">=</span><span class="p">(</span><span class="n">xpos</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="n">total_length</span><span class="o">=</span><span class="n">L</span><span class="p">)</span>
  840. <span class="n">d1_title</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">&#39;Dashpot (default)&#39;</span><span class="p">,</span>
  841. <span class="n">d1</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">&#39;end&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="n">point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">old_div</span><span class="p">(</span><span class="n">L</span><span class="p">,</span><span class="mi">10</span><span class="p">)))</span>
  842. <span class="n">d1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  843. <span class="n">d1_title</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  844. <span class="c"># Dashpot for animation with fixed bar_length, dashpot_length and</span>
  845. <span class="c"># prescribed piston_pos</span>
  846. <span class="n">xpos</span> <span class="o">+=</span> <span class="mf">2.5</span><span class="o">*</span><span class="n">W</span>
  847. <span class="n">d2</span> <span class="o">=</span> <span class="n">Dashpot</span><span class="p">(</span><span class="n">start</span><span class="o">=</span><span class="p">(</span><span class="n">xpos</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="n">total_length</span><span class="o">=</span><span class="mf">1.2</span><span class="o">*</span><span class="n">L</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="n">W</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span>
  848. <span class="n">bar_length</span><span class="o">=</span><span class="n">W</span><span class="p">,</span> <span class="n">dashpot_length</span><span class="o">=</span><span class="n">old_div</span><span class="p">(</span><span class="n">L</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">piston_pos</span><span class="o">=</span><span class="mi">2</span><span class="o">*</span><span class="n">W</span><span class="p">)</span>
  849. <span class="n">d2</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  850. <span class="n">d2</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  851. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">&#39;Dashpot&#39;</span><span class="p">)</span>
  852. </pre></div>
  853. </div>
  854. </div>
  855. <div class="section" id="wavy">
  856. <h3>Wavy<a class="headerlink" href="#wavy" title="Permalink to this headline">¶</a></h3>
  857. <p>Looks strange. Fix x axis.</p>
  858. </div>
  859. <div class="section" id="stochastic-curves">
  860. <h3>Stochastic curves<a class="headerlink" href="#stochastic-curves" title="Permalink to this headline">¶</a></h3>
  861. <p>The <code class="docutils literal"><span class="pre">StochasticWavyCurve</span></code> object offers three precomputed
  862. graphics that have a random variation:</p>
  863. <div class="line-block">
  864. <div class="line"><br /></div>
  865. <div class="line"><br /></div>
  866. </div>
  867. <div class="figure">
  868. <a class="reference internal image-reference" href="_images/StochasticWavyCurve.png"><img alt="_images/StochasticWavyCurve.png" src="_images/StochasticWavyCurve.png" style="width: 600px;" /></a>
  869. </div>
  870. <div class="line-block">
  871. <div class="line"><br /></div>
  872. <div class="line"><br /></div>
  873. </div>
  874. <p>The usage is simple. The construction</p>
  875. <div class="highlight-python"><div class="highlight"><pre><span class="n">curve</span> <span class="o">=</span> <span class="n">StochasticWavyCurve</span><span class="p">(</span><span class="n">curve_no</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">percentage</span><span class="o">=</span><span class="mi">40</span><span class="p">)</span>
  876. </pre></div>
  877. </div>
  878. <p>picks the second curve (the three are numbered 0, 1, and 2),
  879. and the first 40% of that curve. In case one desires another extent
  880. of the axis, one can just scale the coordinates directly as these
  881. are stored in the arrays <code class="docutils literal"><span class="pre">curve.x[curve_no]</span></code> and
  882. <code class="docutils literal"><span class="pre">curve.y[curve_no]</span></code>.</p>
  883. </div>
  884. </div>
  885. <div class="section" id="inner-workings-of-the-pysketcher-tool">
  886. <h2>Inner Workings of the Pysketcher Tool<a class="headerlink" href="#inner-workings-of-the-pysketcher-tool" title="Permalink to this headline">¶</a></h2>
  887. <p>We shall now explain how we can, quite easily, realize software with
  888. the capabilities demonstrated in the previous examples. Each object in
  889. the figure is represented as a class in a class hierarchy. Using
  890. inheritance, classes can inherit properties from parent classes and
  891. add new geometric features.</p>
  892. <p id="index-0">Class programming is a key technology for realizing Pysketcher.
  893. As soon as some classes are established, more are easily
  894. added. Enhanced functionality for all the classes is also easy to
  895. implement in common, generic code that can immediately be shared by
  896. all present and future classes. The fundamental data structure
  897. involved in the <code class="docutils literal"><span class="pre">pysketcher</span></code> package is a hierarchical tree, and much
  898. of the material on implementation issues targets how to traverse tree
  899. structures with recursive function calls in object hierarchies. This
  900. topic is of key relevance in a wide range of other applications as
  901. well. In total, the inner workings of Pysketcher constitute an
  902. excellent example on the power of class programming.</p>
  903. <div class="section" id="example-of-classes-for-geometric-objects">
  904. <h3>Example of Classes for Geometric Objects<a class="headerlink" href="#example-of-classes-for-geometric-objects" title="Permalink to this headline">¶</a></h3>
  905. <p>We introduce class <code class="docutils literal"><span class="pre">Shape</span></code> as superclass for all specialized objects
  906. in a figure. This class does not store any data, but provides a
  907. series of functions that add functionality to all the subclasses.
  908. This will be shown later.</p>
  909. <div class="section" id="simple-geometric-objects">
  910. <h4>Simple Geometric Objects<a class="headerlink" href="#simple-geometric-objects" title="Permalink to this headline">¶</a></h4>
  911. <p>One simple subclass is <code class="docutils literal"><span class="pre">Rectangle</span></code>, specified by the coordinates of
  912. the lower left corner and its width and height:</p>
  913. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Rectangle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
  914. <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lower_left_corner</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">):</span>
  915. <span class="n">p</span> <span class="o">=</span> <span class="n">lower_left_corner</span> <span class="c"># short form</span>
  916. <span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">width</span><span class="p">,</span>
  917. <span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">width</span><span class="p">,</span> <span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
  918. <span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">p</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">p</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">height</span><span class="p">,</span>
  919. <span class="n">p</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">height</span><span class="p">,</span> <span class="n">p</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
  920. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;rectangle&#39;</span><span class="p">:</span> <span class="n">Curve</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)}</span>
  921. </pre></div>
  922. </div>
  923. <p>Any subclass of <code class="docutils literal"><span class="pre">Shape</span></code> will have a constructor that takes geometric
  924. information about the shape of the object and creates a dictionary
  925. <code class="docutils literal"><span class="pre">self.shapes</span></code> with the shape built of simpler shapes. The most
  926. fundamental shape is <code class="docutils literal"><span class="pre">Curve</span></code>, which is just a collection of <span class="math">\((x,y)\)</span>
  927. coordinates in two arrays <code class="docutils literal"><span class="pre">x</span></code> and <code class="docutils literal"><span class="pre">y</span></code>. Drawing the <code class="docutils literal"><span class="pre">Curve</span></code> object is
  928. a matter of plotting <code class="docutils literal"><span class="pre">y</span></code> versus <code class="docutils literal"><span class="pre">x</span></code>. For class <code class="docutils literal"><span class="pre">Rectangle</span></code> the <code class="docutils literal"><span class="pre">x</span></code>
  929. and <code class="docutils literal"><span class="pre">y</span></code> arrays contain the corner points of the rectangle in
  930. counterclockwise direction, starting and ending with in the lower left
  931. corner.</p>
  932. <p>Class <code class="docutils literal"><span class="pre">Line</span></code> is also a simple class:</p>
  933. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Line</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
  934. <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">):</span>
  935. <span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="n">start</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">end</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
  936. <span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="n">start</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">end</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
  937. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;line&#39;</span><span class="p">:</span> <span class="n">Curve</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)}</span>
  938. </pre></div>
  939. </div>
  940. <p>Here we only need two points, the start and end point on the line.
  941. However, we may want to add some useful functionality, e.g., the ability
  942. to give an <span class="math">\(x\)</span> coordinate and have the class calculate the
  943. corresponding <span class="math">\(y\)</span> coordinate:</p>
  944. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
  945. <span class="sd">&quot;&quot;&quot;Given x, return y on the line.&quot;&quot;&quot;</span>
  946. <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">&#39;line&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">&#39;line&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">y</span>
  947. <span class="bp">self</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">y</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="o">/</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
  948. <span class="bp">self</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="n">y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="o">*</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
  949. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span>
  950. </pre></div>
  951. </div>
  952. <p>Unfortunately, this is too simplistic because vertical lines cannot be
  953. handled (infinite <code class="docutils literal"><span class="pre">self.a</span></code>). The true source code of <code class="docutils literal"><span class="pre">Line</span></code> therefore
  954. provides a more general solution at the cost of significantly longer
  955. code with more tests.</p>
  956. <p>A circle implies a somewhat increased complexity. Again we represent
  957. the geometric object by a <code class="docutils literal"><span class="pre">Curve</span></code> object, but this time the <code class="docutils literal"><span class="pre">Curve</span></code>
  958. object needs to store a large number of points on the curve such that
  959. a plotting program produces a visually smooth curve. The points on
  960. the circle must be calculated manually in the constructor of class
  961. <code class="docutils literal"><span class="pre">Circle</span></code>. The formulas for points <span class="math">\((x,y)\)</span> on a curve with radius <span class="math">\(R\)</span>
  962. and center at <span class="math">\((x_0, y_0)\)</span> are given by</p>
  963. <div class="math">
  964. \[\begin{split}x &amp;= x_0 + R\cos (t),\\
  965. y &amp;= y_0 + R\sin (t),\end{split}\]</div>
  966. <p>where <span class="math">\(t\in [0, 2\pi]\)</span>. A discrete set of <span class="math">\(t\)</span> values in this
  967. interval gives the corresponding set of <span class="math">\((x,y)\)</span> coordinates on
  968. the circle. The user must specify the resolution as the number
  969. of <span class="math">\(t\)</span> values. The circle&#8217;s radius and center must of course
  970. also be specified.</p>
  971. <p>We can write the <code class="docutils literal"><span class="pre">Circle</span></code> class as</p>
  972. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
  973. <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">radius</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="mi">180</span><span class="p">):</span>
  974. <span class="bp">self</span><span class="o">.</span><span class="n">center</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">center</span><span class="p">,</span> <span class="n">radius</span>
  975. <span class="bp">self</span><span class="o">.</span><span class="n">resolution</span> <span class="o">=</span> <span class="n">resolution</span>
  976. <span class="n">t</span> <span class="o">=</span> <span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">pi</span><span class="p">,</span> <span class="n">resolution</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
  977. <span class="n">x0</span> <span class="o">=</span> <span class="n">center</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="n">y0</span> <span class="o">=</span> <span class="n">center</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
  978. <span class="n">R</span> <span class="o">=</span> <span class="n">radius</span>
  979. <span class="n">x</span> <span class="o">=</span> <span class="n">x0</span> <span class="o">+</span> <span class="n">R</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
  980. <span class="n">y</span> <span class="o">=</span> <span class="n">y0</span> <span class="o">+</span> <span class="n">R</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
  981. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;circle&#39;</span><span class="p">:</span> <span class="n">Curve</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)}</span>
  982. </pre></div>
  983. </div>
  984. <p>As in class <code class="docutils literal"><span class="pre">Line</span></code> we can offer the possibility to give an angle
  985. <span class="math">\(\theta\)</span> (equivalent to <span class="math">\(t\)</span> in the formulas above)
  986. and then get the corresponding <span class="math">\(x\)</span> and <span class="math">\(y\)</span> coordinates:</p>
  987. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">theta</span><span class="p">):</span>
  988. <span class="sd">&quot;&quot;&quot;Return (x, y) point corresponding to angle theta.&quot;&quot;&quot;</span>
  989. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">center</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">radius</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> \
  990. <span class="bp">self</span><span class="o">.</span><span class="n">center</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">radius</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span>
  991. </pre></div>
  992. </div>
  993. <p>There is one flaw with this method: it yields illegal values after
  994. a translation, scaling, or rotation of the circle.</p>
  995. <p>A part of a circle, an arc, is a frequent geometric object when
  996. drawing mechanical systems. The arc is constructed much like
  997. a circle, but <span class="math">\(t\)</span> runs in <span class="math">\([\theta_s, \theta_s + \theta_a]\)</span>. Giving
  998. <span class="math">\(\theta_s\)</span> and <span class="math">\(\theta_a\)</span> the slightly more descriptive names
  999. <code class="docutils literal"><span class="pre">start_angle</span></code> and <code class="docutils literal"><span class="pre">arc_angle</span></code>, the code looks like this:</p>
  1000. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Arc</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
  1001. <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">radius</span><span class="p">,</span>
  1002. <span class="n">start_angle</span><span class="p">,</span> <span class="n">arc_angle</span><span class="p">,</span>
  1003. <span class="n">resolution</span><span class="o">=</span><span class="mi">180</span><span class="p">):</span>
  1004. <span class="bp">self</span><span class="o">.</span><span class="n">start_angle</span> <span class="o">=</span> <span class="n">radians</span><span class="p">(</span><span class="n">start_angle</span><span class="p">)</span>
  1005. <span class="bp">self</span><span class="o">.</span><span class="n">arc_angle</span> <span class="o">=</span> <span class="n">radians</span><span class="p">(</span><span class="n">arc_angle</span><span class="p">)</span>
  1006. <span class="n">t</span> <span class="o">=</span> <span class="n">linspace</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">start_angle</span><span class="p">,</span>
  1007. <span class="bp">self</span><span class="o">.</span><span class="n">start_angle</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">arc_angle</span><span class="p">,</span>
  1008. <span class="n">resolution</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
  1009. <span class="n">x0</span> <span class="o">=</span> <span class="n">center</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="n">y0</span> <span class="o">=</span> <span class="n">center</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
  1010. <span class="n">R</span> <span class="o">=</span> <span class="n">radius</span>
  1011. <span class="n">x</span> <span class="o">=</span> <span class="n">x0</span> <span class="o">+</span> <span class="n">R</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
  1012. <span class="n">y</span> <span class="o">=</span> <span class="n">y0</span> <span class="o">+</span> <span class="n">R</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
  1013. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;arc&#39;</span><span class="p">:</span> <span class="n">Curve</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)}</span>
  1014. </pre></div>
  1015. </div>
  1016. <p>Having the <code class="docutils literal"><span class="pre">Arc</span></code> class, a <code class="docutils literal"><span class="pre">Circle</span></code> can alternatively be defined as
  1017. a subclass specializing the arc to a circle:</p>
  1018. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Arc</span><span class="p">):</span>
  1019. <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">radius</span><span class="p">,</span> <span class="n">resolution</span><span class="o">=</span><span class="mi">180</span><span class="p">):</span>
  1020. <span class="n">Arc</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">radius</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">360</span><span class="p">,</span> <span class="n">resolution</span><span class="p">)</span>
  1021. </pre></div>
  1022. </div>
  1023. </div>
  1024. <div class="section" id="class-curve">
  1025. <h4>Class Curve<a class="headerlink" href="#class-curve" title="Permalink to this headline">¶</a></h4>
  1026. <p>Class <code class="docutils literal"><span class="pre">Curve</span></code> sits on the coordinates to be drawn, but how is that
  1027. done? The constructor of class <code class="docutils literal"><span class="pre">Curve</span></code> just stores the coordinates,
  1028. while a method <code class="docutils literal"><span class="pre">draw</span></code> sends the coordinates to the plotting program to
  1029. make a graph. Or more precisely, to avoid a lot of (e.g.)
  1030. Matplotlib-specific plotting commands in class <code class="docutils literal"><span class="pre">Curve</span></code> we have created
  1031. a small layer with a simple programming interface to plotting
  1032. programs. This makes it straightforward to change from Matplotlib to
  1033. another plotting program. The programming interface is represented by
  1034. the <code class="docutils literal"><span class="pre">drawing_tool</span></code> object and has a few functions:</p>
  1035. <blockquote>
  1036. <div><ul class="simple">
  1037. <li><code class="docutils literal"><span class="pre">plot_curve</span></code> for sending a curve in terms of <span class="math">\(x\)</span> and <span class="math">\(y\)</span> coordinates
  1038. to the plotting program,</li>
  1039. <li><code class="docutils literal"><span class="pre">set_coordinate_system</span></code> for specifying the graphics area,</li>
  1040. <li><code class="docutils literal"><span class="pre">erase</span></code> for deleting all elements of the graph,</li>
  1041. <li><code class="docutils literal"><span class="pre">set_grid</span></code> for turning on a grid (convenient while constructing the figure),</li>
  1042. <li><code class="docutils literal"><span class="pre">set_instruction_file</span></code> for creating a separate file with all
  1043. plotting commands (Matplotlib commands in our case),</li>
  1044. <li>a series of <code class="docutils literal"><span class="pre">set_X</span></code> functions where <code class="docutils literal"><span class="pre">X</span></code> is some property like
  1045. <code class="docutils literal"><span class="pre">linecolor</span></code>, <code class="docutils literal"><span class="pre">linestyle</span></code>, <code class="docutils literal"><span class="pre">linewidth</span></code>, <code class="docutils literal"><span class="pre">filled_curves</span></code>.</li>
  1046. </ul>
  1047. </div></blockquote>
  1048. <p>This is basically all we need to communicate to a plotting program.</p>
  1049. <p>Any class in the <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy inherits <code class="docutils literal"><span class="pre">set_X</span></code> functions for
  1050. setting properties of curves. This information is propagated to
  1051. all other shape objects in the <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary. Class
  1052. <code class="docutils literal"><span class="pre">Curve</span></code> stores the line properties together with the coordinates
  1053. of its curve and propagates this information to the plotting program.
  1054. When saying <code class="docutils literal"><span class="pre">vehicle.set_linewidth(10)</span></code>, all objects that make
  1055. up the <code class="docutils literal"><span class="pre">vehicle</span></code> object will get a <code class="docutils literal"><span class="pre">set_linewidth(10)</span></code> call,
  1056. but only the <code class="docutils literal"><span class="pre">Curve</span></code> object at the end of the chain will actually
  1057. store the information and send it to the plotting program.</p>
  1058. <p>A rough sketch of class <code class="docutils literal"><span class="pre">Curve</span></code> reads</p>
  1059. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
  1060. <span class="sd">&quot;&quot;&quot;General curve as a sequence of (x,y) coordintes.&quot;&quot;&quot;</span>
  1061. <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
  1062. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">asarray</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span>
  1063. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">asarray</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span>
  1064. <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  1065. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">plot_curve</span><span class="p">(</span>
  1066. <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="p">,</span>
  1067. <span class="bp">self</span><span class="o">.</span><span class="n">linestyle</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">linewidth</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">linecolor</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
  1068. <span class="k">def</span> <span class="nf">set_linewidth</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">width</span><span class="p">):</span>
  1069. <span class="bp">self</span><span class="o">.</span><span class="n">linewidth</span> <span class="o">=</span> <span class="n">width</span>
  1070. <span class="n">det</span> <span class="n">set_linestyle</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">style</span><span class="p">):</span>
  1071. <span class="bp">self</span><span class="o">.</span><span class="n">linestyle</span> <span class="o">=</span> <span class="n">style</span>
  1072. <span class="o">...</span>
  1073. </pre></div>
  1074. </div>
  1075. </div>
  1076. <div class="section" id="compound-geometric-objects">
  1077. <h4>Compound Geometric Objects<a class="headerlink" href="#compound-geometric-objects" title="Permalink to this headline">¶</a></h4>
  1078. <p>The simple classes <code class="docutils literal"><span class="pre">Line</span></code>, <code class="docutils literal"><span class="pre">Arc</span></code>, and <code class="docutils literal"><span class="pre">Circle</span></code> could can the geometric
  1079. shape through just one <code class="docutils literal"><span class="pre">Curve</span></code> object. More complicated shapes are
  1080. built from instances of various subclasses of <code class="docutils literal"><span class="pre">Shape</span></code>. Classes used
  1081. for professional drawings soon get quite complex in composition and
  1082. have a lot of geometric details, so here we prefer to make a very
  1083. simple composition: the already drawn vehicle from Figure
  1084. <a class="reference internal" href="#sketcher-fig-vehicle0"><span class="std std-ref">Sketch of a simple figure</span></a>. That is, instead of composing the drawing
  1085. in a Python program as shown above, we make a subclass <code class="docutils literal"><span class="pre">Vehicle0</span></code> in
  1086. the <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy for doing the same thing.</p>
  1087. <p>The <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy is found in the <code class="docutils literal"><span class="pre">pysketcher</span></code> package, so to use these
  1088. classes or derive a new one, we need to import <code class="docutils literal"><span class="pre">pysketcher</span></code>. The constructor
  1089. of class <code class="docutils literal"><span class="pre">Vehicle0</span></code> performs approximately the same statements as
  1090. in the example program we developed for making the drawing in
  1091. Figure <a class="reference internal" href="#sketcher-fig-vehicle0"><span class="std std-ref">Sketch of a simple figure</span></a>.</p>
  1092. <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">pysketcher</span> <span class="kn">import</span> <span class="o">*</span>
  1093. <span class="k">class</span> <span class="nc">Vehicle0</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
  1094. <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="n">H</span><span class="p">):</span>
  1095. <span class="n">wheel1</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="n">R</span><span class="p">)</span>
  1096. <span class="n">wheel2</span> <span class="o">=</span> <span class="n">wheel1</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
  1097. <span class="n">wheel2</span><span class="o">.</span><span class="n">translate</span><span class="p">((</span><span class="n">L</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
  1098. <span class="n">under</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">lower_left_corner</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="o">-</span><span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">),</span>
  1099. <span class="n">width</span><span class="o">=</span><span class="mi">2</span><span class="o">*</span><span class="n">R</span> <span class="o">+</span> <span class="n">L</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">R</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="n">H</span><span class="p">)</span>
  1100. <span class="n">over</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">lower_left_corner</span><span class="o">=</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">R</span> <span class="o">+</span> <span class="n">H</span><span class="p">),</span>
  1101. <span class="n">width</span><span class="o">=</span><span class="mf">2.5</span><span class="o">*</span><span class="n">R</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mf">1.25</span><span class="o">*</span><span class="n">H</span><span class="p">)</span>
  1102. <span class="n">wheels</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
  1103. <span class="p">{</span><span class="s">&#39;wheel1&#39;</span><span class="p">:</span> <span class="n">wheel1</span><span class="p">,</span> <span class="s">&#39;wheel2&#39;</span><span class="p">:</span> <span class="n">wheel2</span><span class="p">})</span>
  1104. <span class="n">body</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
  1105. <span class="p">{</span><span class="s">&#39;under&#39;</span><span class="p">:</span> <span class="n">under</span><span class="p">,</span> <span class="s">&#39;over&#39;</span><span class="p">:</span> <span class="n">over</span><span class="p">})</span>
  1106. <span class="n">vehicle</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">&#39;wheels&#39;</span><span class="p">:</span> <span class="n">wheels</span><span class="p">,</span> <span class="s">&#39;body&#39;</span><span class="p">:</span> <span class="n">body</span><span class="p">})</span>
  1107. <span class="n">xmax</span> <span class="o">=</span> <span class="n">w_1</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">L</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">R</span>
  1108. <span class="n">ground</span> <span class="o">=</span> <span class="n">Wall</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="p">[</span><span class="n">R</span><span class="p">,</span> <span class="n">xmax</span><span class="p">],</span> <span class="n">y</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">thickness</span><span class="o">=-</span><span class="mf">0.3</span><span class="o">*</span><span class="n">R</span><span class="p">)</span>
  1109. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;vehicle&#39;</span><span class="p">:</span> <span class="n">vehicle</span><span class="p">,</span> <span class="s">&#39;ground&#39;</span><span class="p">:</span> <span class="n">ground</span><span class="p">}</span>
  1110. </pre></div>
  1111. </div>
  1112. <p>Any subclass of <code class="docutils literal"><span class="pre">Shape</span></code> <em>must</em> define the <code class="docutils literal"><span class="pre">shapes</span></code> attribute, otherwise
  1113. the inherited <code class="docutils literal"><span class="pre">draw</span></code> method (and a lot of other methods too) will
  1114. not work.</p>
  1115. <p>The painting of the vehicle, as shown in the right part of
  1116. Figure <a class="reference internal" href="#sketcher-fig-vehicle0-v2"><span class="std std-ref">Left: Basic line-based drawing. Right: Thicker lines and filled parts</span></a>, could in class <code class="docutils literal"><span class="pre">Vehicle0</span></code>
  1117. be offered by a method:</p>
  1118. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">colorful</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  1119. <span class="n">wheels</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;wheels&#39;</span><span class="p">]</span>
  1120. <span class="n">wheels</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">&#39;blue&#39;</span><span class="p">)</span>
  1121. <span class="n">wheels</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
  1122. <span class="n">wheels</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">&#39;black&#39;</span><span class="p">)</span>
  1123. <span class="n">under</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;body&#39;</span><span class="p">][</span><span class="s">&#39;under&#39;</span><span class="p">]</span>
  1124. <span class="n">under</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">&#39;red&#39;</span><span class="p">)</span>
  1125. <span class="n">over</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">][</span><span class="s">&#39;body&#39;</span><span class="p">][</span><span class="s">&#39;over&#39;</span><span class="p">]</span>
  1126. <span class="n">over</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s">&#39;/&#39;</span><span class="p">)</span>
  1127. <span class="n">over</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">14</span><span class="p">)</span>
  1128. </pre></div>
  1129. </div>
  1130. <p>The usage of the class is simple: after having set up an appropriate
  1131. coordinate system as previously shown, we can do</p>
  1132. <div class="highlight-python"><div class="highlight"><pre><span class="n">vehicle</span> <span class="o">=</span> <span class="n">Vehicle0</span><span class="p">(</span><span class="n">w_1</span><span class="p">,</span> <span class="n">R</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="n">H</span><span class="p">)</span>
  1133. <span class="n">vehicle</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1134. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  1135. </pre></div>
  1136. </div>
  1137. <p>and go on the make a painted version by</p>
  1138. <div class="highlight-python"><div class="highlight"><pre><span class="n">drawing_tool</span><span class="o">.</span><span class="n">erase</span><span class="p">()</span>
  1139. <span class="n">vehicle</span><span class="o">.</span><span class="n">colorful</span><span class="p">()</span>
  1140. <span class="n">vehicle</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1141. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  1142. </pre></div>
  1143. </div>
  1144. <p>A complete code defining and using class <code class="docutils literal"><span class="pre">Vehicle0</span></code> is found in the file
  1145. <a class="reference external" href="http://tinyurl.com/ot733jn/vehicle2.py">vehicle2.py</a>.</p>
  1146. <p>The <code class="docutils literal"><span class="pre">pysketcher</span></code> package contains a wide range of classes for various
  1147. geometrical objects, particularly those that are frequently used in
  1148. drawings of mechanical systems.</p>
  1149. </div>
  1150. </div>
  1151. <div class="section" id="adding-functionality-via-recursion">
  1152. <h3>Adding Functionality via Recursion<a class="headerlink" href="#adding-functionality-via-recursion" title="Permalink to this headline">¶</a></h3>
  1153. <p id="index-1">The really powerful feature of our class hierarchy is that we can add
  1154. much functionality to the superclass <code class="docutils literal"><span class="pre">Shape</span></code> and to the &#8220;bottom&#8221; class
  1155. <code class="docutils literal"><span class="pre">Curve</span></code>, and then all other classes for various types of geometrical shapes
  1156. immediately get the new functionality. To explain the idea we may
  1157. look at the <code class="docutils literal"><span class="pre">draw</span></code> method, which all classes in the <code class="docutils literal"><span class="pre">Shape</span></code>
  1158. hierarchy must have. The inner workings of the <code class="docutils literal"><span class="pre">draw</span></code> method explain
  1159. the secrets of how a series of other useful operations on figures
  1160. can be implemented.</p>
  1161. <div class="section" id="basic-principles-of-recursion">
  1162. <h4>Basic Principles of Recursion<a class="headerlink" href="#basic-principles-of-recursion" title="Permalink to this headline">¶</a></h4>
  1163. <p>Note that we work with two types of hierarchies in the
  1164. present documentation: one Python <em>class hierarchy</em>,
  1165. with <code class="docutils literal"><span class="pre">Shape</span></code> as superclass, and one <em>object hierarchy</em> of figure elements
  1166. in a specific figure. A subclass of <code class="docutils literal"><span class="pre">Shape</span></code> stores its figure in the
  1167. <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary. This dictionary represents the object hierarchy
  1168. of figure elements for that class. We want to make one <code class="docutils literal"><span class="pre">draw</span></code> call
  1169. for an instance, say our class <code class="docutils literal"><span class="pre">Vehicle0</span></code>, and then we want this call
  1170. to be propagated to <em>all</em> objects that are contained in
  1171. <code class="docutils literal"><span class="pre">self.shapes</span></code> and all is nested subdictionaries. How is this done?</p>
  1172. <p>The natural starting point is to call <code class="docutils literal"><span class="pre">draw</span></code> for each <code class="docutils literal"><span class="pre">Shape</span></code> object
  1173. in the <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary:</p>
  1174. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  1175. <span class="k">for</span> <span class="n">shape</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">:</span>
  1176. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="n">shape</span><span class="p">]</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1177. </pre></div>
  1178. </div>
  1179. <p>This general method can be provided by class <code class="docutils literal"><span class="pre">Shape</span></code> and inherited in
  1180. subclasses like <code class="docutils literal"><span class="pre">Vehicle0</span></code>. Let <code class="docutils literal"><span class="pre">v</span></code> be a <code class="docutils literal"><span class="pre">Vehicle0</span></code> instance.
  1181. Seemingly, a call <code class="docutils literal"><span class="pre">v.draw()</span></code> just calls</p>
  1182. <div class="highlight-python"><div class="highlight"><pre><span class="n">v</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">&#39;vehicle&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1183. <span class="n">v</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">&#39;ground&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1184. </pre></div>
  1185. </div>
  1186. <p>However, in the former call we call the <code class="docutils literal"><span class="pre">draw</span></code> method of a <code class="docutils literal"><span class="pre">Composition</span></code> object
  1187. whose <code class="docutils literal"><span class="pre">self.shapes</span></code> attributed has two elements: <code class="docutils literal"><span class="pre">wheels</span></code> and <code class="docutils literal"><span class="pre">body</span></code>.
  1188. Since class <code class="docutils literal"><span class="pre">Composition</span></code> inherits the same <code class="docutils literal"><span class="pre">draw</span></code> method, this method will
  1189. run through <code class="docutils literal"><span class="pre">self.shapes</span></code> and call <code class="docutils literal"><span class="pre">wheels.draw()</span></code> and <code class="docutils literal"><span class="pre">body.draw()</span></code>.
  1190. Now, the <code class="docutils literal"><span class="pre">wheels</span></code> object is also a <code class="docutils literal"><span class="pre">Composition</span></code> with the same <code class="docutils literal"><span class="pre">draw</span></code>
  1191. method, which will run through <code class="docutils literal"><span class="pre">self.shapes</span></code>, now containing
  1192. the <code class="docutils literal"><span class="pre">wheel1</span></code> and <code class="docutils literal"><span class="pre">wheel2</span></code> objects. The <code class="docutils literal"><span class="pre">wheel1</span></code> object is a <code class="docutils literal"><span class="pre">Circle</span></code>,
  1193. so calling <code class="docutils literal"><span class="pre">wheel1.draw()</span></code> calls the <code class="docutils literal"><span class="pre">draw</span></code> method in class <code class="docutils literal"><span class="pre">Circle</span></code>,
  1194. but this is the same <code class="docutils literal"><span class="pre">draw</span></code> method as shown above. This method will
  1195. therefore traverse the circle&#8217;s <code class="docutils literal"><span class="pre">shapes</span></code> dictionary, which we have seen
  1196. consists of one <code class="docutils literal"><span class="pre">Curve</span></code> element.</p>
  1197. <p>The <code class="docutils literal"><span class="pre">Curve</span></code> object holds the coordinates to be plotted so here <code class="docutils literal"><span class="pre">draw</span></code>
  1198. really needs to do something &#8220;physical&#8221;, namely send the coordinates to
  1199. the plotting program. The <code class="docutils literal"><span class="pre">draw</span></code> method is outlined in the short listing
  1200. of class <code class="docutils literal"><span class="pre">Curve</span></code> shown previously.</p>
  1201. <p>We can go to any of the other shape objects that appear in the figure
  1202. hierarchy and follow their <code class="docutils literal"><span class="pre">draw</span></code> calls in the similar way. Every time,
  1203. a <code class="docutils literal"><span class="pre">draw</span></code> call will invoke a new <code class="docutils literal"><span class="pre">draw</span></code> call, until we eventually hit
  1204. a <code class="docutils literal"><span class="pre">Curve</span></code> object at the &#8220;bottom&#8221; of the figure hierarchy, and then that part
  1205. of the figure is really plotted (or more precisely, the coordinates
  1206. are sent to a plotting program).</p>
  1207. <p>When a method calls itself, such as <code class="docutils literal"><span class="pre">draw</span></code> does, the calls are known as
  1208. <em>recursive</em> and the programming principle is referred to as
  1209. <em>recursion</em>. This technique is very often used to traverse hierarchical
  1210. structures like the figure structures we work with here. Even though the
  1211. hierarchy of objects building up a figure are of different types, they
  1212. all inherit the same <code class="docutils literal"><span class="pre">draw</span></code> method and therefore exhibit the same
  1213. behavior with respect to drawing. Only the <code class="docutils literal"><span class="pre">Curve</span></code> object has a different
  1214. <code class="docutils literal"><span class="pre">draw</span></code> method, which does not lead to more recursion.</p>
  1215. </div>
  1216. <div class="section" id="explaining-recursion">
  1217. <h4>Explaining Recursion<a class="headerlink" href="#explaining-recursion" title="Permalink to this headline">¶</a></h4>
  1218. <p>Understanding recursion is usually a challenge. To get a better idea of
  1219. how recursion works, we have equipped class <code class="docutils literal"><span class="pre">Shape</span></code> with a method <code class="docutils literal"><span class="pre">recurse</span></code>
  1220. that just visits all the objects in the <code class="docutils literal"><span class="pre">shapes</span></code> dictionary and prints
  1221. out a message for each object.
  1222. This feature allows us to trace the execution and see exactly where
  1223. we are in the hierarchy and which objects that are visited.</p>
  1224. <p>The <code class="docutils literal"><span class="pre">recurse</span></code> method is very similar to <code class="docutils literal"><span class="pre">draw</span></code>:</p>
  1225. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">recurse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
  1226. <span class="c"># print message where we are (name is where we come from)</span>
  1227. <span class="k">for</span> <span class="n">shape</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">:</span>
  1228. <span class="c"># print message about which object to visit</span>
  1229. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="n">shape</span><span class="p">]</span><span class="o">.</span><span class="n">recurse</span><span class="p">(</span><span class="n">indent</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="n">shape</span><span class="p">)</span>
  1230. </pre></div>
  1231. </div>
  1232. <p>The <code class="docutils literal"><span class="pre">indent</span></code> parameter governs how much the message from this
  1233. <code class="docutils literal"><span class="pre">recurse</span></code> method is intended. We increase <code class="docutils literal"><span class="pre">indent</span></code> by 2 for every
  1234. level in the hierarchy, i.e., every row of objects in Figure
  1235. <span class="xref std std-ref">sketcher:fig:Vehicle0:hier2</span>. This indentation makes it easy to
  1236. see on the printout how far down in the hierarchy we are.</p>
  1237. <p>A typical message written by <code class="docutils literal"><span class="pre">recurse</span></code> when <code class="docutils literal"><span class="pre">name</span></code> is <code class="docutils literal"><span class="pre">'body'</span></code> and
  1238. the <code class="docutils literal"><span class="pre">shapes</span></code> dictionary has the keys <code class="docutils literal"><span class="pre">'over'</span></code> and <code class="docutils literal"><span class="pre">'under'</span></code>,
  1239. will be</p>
  1240. <div class="highlight-text"><div class="highlight"><pre>Composition: body.shapes has entries &#39;over&#39;, &#39;under&#39;
  1241. call body.shapes[&quot;over&quot;].recurse(&quot;over&quot;, 6)
  1242. </pre></div>
  1243. </div>
  1244. <p>The number of leading blanks on each line corresponds to the value of
  1245. <code class="docutils literal"><span class="pre">indent</span></code>. The code printing out such messages looks like</p>
  1246. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">recurse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
  1247. <span class="n">space</span> <span class="o">=</span> <span class="s">&#39; &#39;</span><span class="o">*</span><span class="n">indent</span>
  1248. <span class="k">print</span> <span class="n">space</span><span class="p">,</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">.shapes has entries&#39;</span> <span class="o">%</span> \
  1249. <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">name</span><span class="p">),</span> \
  1250. <span class="nb">str</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="o">.</span><span class="n">keys</span><span class="p">()))[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
  1251. <span class="k">for</span> <span class="n">shape</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">:</span>
  1252. <span class="k">print</span> <span class="n">space</span><span class="p">,</span>
  1253. <span class="k">print</span> <span class="s">&#39;call </span><span class="si">%s</span><span class="s">.shapes[&quot;</span><span class="si">%s</span><span class="s">&quot;].recurse(&quot;</span><span class="si">%s</span><span class="s">&quot;, </span><span class="si">%d</span><span class="s">)&#39;</span> <span class="o">%</span> \
  1254. <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">shape</span><span class="p">,</span> <span class="n">shape</span><span class="p">,</span> <span class="n">indent</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span>
  1255. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="n">shape</span><span class="p">]</span><span class="o">.</span><span class="n">recurse</span><span class="p">(</span><span class="n">shape</span><span class="p">,</span> <span class="n">indent</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span>
  1256. </pre></div>
  1257. </div>
  1258. <p>Let us follow a <code class="docutils literal"><span class="pre">v.recurse('vehicle')</span></code> call in detail, <code class="docutils literal"><span class="pre">v</span></code> being
  1259. a <code class="docutils literal"><span class="pre">Vehicle0</span></code> instance. Before looking into the output from <code class="docutils literal"><span class="pre">recurse</span></code>,
  1260. let us get an overview of the figure hierarchy in the <code class="docutils literal"><span class="pre">v</span></code> object
  1261. (as produced by <code class="docutils literal"><span class="pre">print</span> <span class="pre">v</span></code>)</p>
  1262. <div class="highlight-text"><div class="highlight"><pre>ground
  1263. wall
  1264. vehicle
  1265. body
  1266. over
  1267. rectangle
  1268. under
  1269. rectangle
  1270. wheels
  1271. wheel1
  1272. arc
  1273. wheel2
  1274. arc
  1275. </pre></div>
  1276. </div>
  1277. <p>The <code class="docutils literal"><span class="pre">recurse</span></code> method performs the same kind of traversal of the
  1278. hierarchy, but writes out and explains a lot more.</p>
  1279. <p>The data structure represented by <code class="docutils literal"><span class="pre">v.shapes</span></code> is known as a <em>tree</em>.
  1280. As in physical trees, there is a <em>root</em>, here the <code class="docutils literal"><span class="pre">v.shapes</span></code>
  1281. dictionary. A graphical illustration of the tree (upside down) is
  1282. shown in Figure <span class="xref std std-ref">sketcher:fig:Vehicle0:hier2</span>.
  1283. From the root there are one or more branches, here two:
  1284. <code class="docutils literal"><span class="pre">ground</span></code> and <code class="docutils literal"><span class="pre">vehicle</span></code>. Following the <code class="docutils literal"><span class="pre">vehicle</span></code> branch, it has two new
  1285. branches, <code class="docutils literal"><span class="pre">body</span></code> and <code class="docutils literal"><span class="pre">wheels</span></code>. Relationships as in family trees
  1286. are often used to describe the relations in object trees too: we say
  1287. that <code class="docutils literal"><span class="pre">vehicle</span></code> is the parent of <code class="docutils literal"><span class="pre">body</span></code> and that <code class="docutils literal"><span class="pre">body</span></code> is a child of
  1288. <code class="docutils literal"><span class="pre">vehicle</span></code>. The term <em>node</em> is also often used to describe an element
  1289. in a tree. A node may have several other nodes as <em>descendants</em>.</p>
  1290. <div class="figure" id="id9">
  1291. <span id="id1"></span><a class="reference internal image-reference" href="_images/Vehicle0_hier2.png"><img alt="_images/Vehicle0_hier2.png" src="_images/Vehicle0_hier2.png" style="width: 600px;" /></a>
  1292. <p class="caption"><span class="caption-text"><em>Hierarchy of figure elements in an instance of class `Vehicle0`</em></span></p>
  1293. </div>
  1294. <p>Recursion is the principal programming technique to traverse tree structures.
  1295. Any object in the tree can be viewed as a root of a subtree. For
  1296. example, <code class="docutils literal"><span class="pre">wheels</span></code> is the root of a subtree that branches into
  1297. <code class="docutils literal"><span class="pre">wheel1</span></code> and <code class="docutils literal"><span class="pre">wheel2</span></code>. So when processing an object in the tree,
  1298. we imagine we process the root and then recurse into a subtree, but the
  1299. first object we recurse into can be viewed as the root of the subtree, so the
  1300. processing procedure of the parent object can be repeated.</p>
  1301. <p>A recommended next step is to simulate the <code class="docutils literal"><span class="pre">recurse</span></code> method by hand and
  1302. carefully check that what happens in the visits to <code class="docutils literal"><span class="pre">recurse</span></code> is
  1303. consistent with the output listed below. Although tedious, this is
  1304. a major exercise that guaranteed will help to demystify recursion.</p>
  1305. <p>A part of the printout of <code class="docutils literal"><span class="pre">v.recurse('vehicle')</span></code> looks like</p>
  1306. <div class="highlight-text"><div class="highlight"><pre> Vehicle0: vehicle.shapes has entries &#39;ground&#39;, &#39;vehicle&#39;
  1307. call vehicle.shapes[&quot;ground&quot;].recurse(&quot;ground&quot;, 2)
  1308. Wall: ground.shapes has entries &#39;wall&#39;
  1309. call ground.shapes[&quot;wall&quot;].recurse(&quot;wall&quot;, 4)
  1310. reached &quot;bottom&quot; object Curve
  1311. call vehicle.shapes[&quot;vehicle&quot;].recurse(&quot;vehicle&quot;, 2)
  1312. Composition: vehicle.shapes has entries &#39;body&#39;, &#39;wheels&#39;
  1313. call vehicle.shapes[&quot;body&quot;].recurse(&quot;body&quot;, 4)
  1314. Composition: body.shapes has entries &#39;over&#39;, &#39;under&#39;
  1315. call body.shapes[&quot;over&quot;].recurse(&quot;over&quot;, 6)
  1316. Rectangle: over.shapes has entries &#39;rectangle&#39;
  1317. call over.shapes[&quot;rectangle&quot;].recurse(&quot;rectangle&quot;, 8)
  1318. reached &quot;bottom&quot; object Curve
  1319. call body.shapes[&quot;under&quot;].recurse(&quot;under&quot;, 6)
  1320. Rectangle: under.shapes has entries &#39;rectangle&#39;
  1321. call under.shapes[&quot;rectangle&quot;].recurse(&quot;rectangle&quot;, 8)
  1322. reached &quot;bottom&quot; object Curve
  1323. ...
  1324. </pre></div>
  1325. </div>
  1326. <p>This example should clearly demonstrate the principle that we
  1327. can start at any object in the tree and do a recursive set
  1328. of calls with that object as root.</p>
  1329. </div>
  1330. </div>
  1331. <div class="section" id="scaling-translating-and-rotating-a-figure">
  1332. <span id="sketcher-scaling"></span><h3>Scaling, Translating, and Rotating a Figure<a class="headerlink" href="#scaling-translating-and-rotating-a-figure" title="Permalink to this headline">¶</a></h3>
  1333. <p>With recursion, as explained in the previous section, we can within
  1334. minutes equip <em>all</em> classes in the <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy, both present and
  1335. future ones, with the ability to scale the figure, translate it,
  1336. or rotate it. This added functionality requires only a few lines
  1337. of code.</p>
  1338. <div class="section" id="scaling">
  1339. <h4>Scaling<a class="headerlink" href="#scaling" title="Permalink to this headline">¶</a></h4>
  1340. <p>We start with the simplest of the three geometric transformations,
  1341. namely scaling. For a <code class="docutils literal"><span class="pre">Curve</span></code> instance containing a set of <span class="math">\(n\)</span>
  1342. coordinates <span class="math">\((x_i,y_i)\)</span> that make up a curve, scaling by a factor <span class="math">\(a\)</span>
  1343. means that we multiply all the <span class="math">\(x\)</span> and <span class="math">\(y\)</span> coordinates by <span class="math">\(a\)</span>:</p>
  1344. <div class="math">
  1345. \[x_i \leftarrow ax_i,\quad y_i\leftarrow ay_i,
  1346. \quad i=0,\ldots,n-1\thinspace .\]</div>
  1347. <p>Here we apply the arrow as an assignment operator.
  1348. The corresponding Python implementation in
  1349. class <code class="docutils literal"><span class="pre">Curve</span></code> reads</p>
  1350. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
  1351. <span class="o">...</span>
  1352. <span class="k">def</span> <span class="nf">scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">factor</span><span class="p">):</span>
  1353. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">factor</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span>
  1354. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">factor</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">y</span>
  1355. </pre></div>
  1356. </div>
  1357. <p>Note here that <code class="docutils literal"><span class="pre">self.x</span></code> and <code class="docutils literal"><span class="pre">self.y</span></code> are Numerical Python arrays,
  1358. so that multiplication by a scalar number <code class="docutils literal"><span class="pre">factor</span></code> is
  1359. a vectorized operation.</p>
  1360. <p>An even more efficient implementation is to make use of in-place
  1361. multiplication in the arrays,</p>
  1362. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
  1363. <span class="o">...</span>
  1364. <span class="k">def</span> <span class="nf">scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">factor</span><span class="p">):</span>
  1365. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">*=</span> <span class="n">factor</span>
  1366. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">*=</span> <span class="n">factor</span>
  1367. </pre></div>
  1368. </div>
  1369. <p>as this saves the creation of temporary arrays like <code class="docutils literal"><span class="pre">factor*self.x</span></code>.</p>
  1370. <p>In an instance of a subclass of <code class="docutils literal"><span class="pre">Shape</span></code>, the meaning of a method
  1371. <code class="docutils literal"><span class="pre">scale</span></code> is to run through all objects in the dictionary <code class="docutils literal"><span class="pre">shapes</span></code> and
  1372. ask each object to scale itself. This is the same delegation of
  1373. actions to subclass instances as we do in the <code class="docutils literal"><span class="pre">draw</span></code> (or <code class="docutils literal"><span class="pre">recurse</span></code>)
  1374. method. All objects, except <code class="docutils literal"><span class="pre">Curve</span></code> instances, can share the same
  1375. implementation of the <code class="docutils literal"><span class="pre">scale</span></code> method. Therefore, we place the <code class="docutils literal"><span class="pre">scale</span></code>
  1376. method in the superclass <code class="docutils literal"><span class="pre">Shape</span></code> such that all subclasses inherit the
  1377. method. Since <code class="docutils literal"><span class="pre">scale</span></code> and <code class="docutils literal"><span class="pre">draw</span></code> are so similar, we can easily
  1378. implement the <code class="docutils literal"><span class="pre">scale</span></code> method in class <code class="docutils literal"><span class="pre">Shape</span></code> by copying and editing
  1379. the <code class="docutils literal"><span class="pre">draw</span></code> method:</p>
  1380. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
  1381. <span class="o">...</span>
  1382. <span class="k">def</span> <span class="nf">scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">factor</span><span class="p">):</span>
  1383. <span class="k">for</span> <span class="n">shape</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">:</span>
  1384. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="n">shape</span><span class="p">]</span><span class="o">.</span><span class="n">scale</span><span class="p">(</span><span class="n">factor</span><span class="p">)</span>
  1385. </pre></div>
  1386. </div>
  1387. <p>This is all we have to do in order to equip all subclasses of
  1388. <code class="docutils literal"><span class="pre">Shape</span></code> with scaling functionality!
  1389. Any piece of the figure will scale itself, in the same manner
  1390. as it can draw itself.</p>
  1391. </div>
  1392. <div class="section" id="translation">
  1393. <h4>Translation<a class="headerlink" href="#translation" title="Permalink to this headline">¶</a></h4>
  1394. <p>A set of coordinates <span class="math">\((x_i, y_i)\)</span> can be translated <span class="math">\(v_0\)</span> units in
  1395. the <span class="math">\(x\)</span> direction and <span class="math">\(v_1\)</span> units in the <span class="math">\(y\)</span> direction using the formulas</p>
  1396. <div class="math">
  1397. \[x_i\leftarrow x_i+v_0,\quad y_i\leftarrow y_i+v_1,
  1398. \quad i=0,\ldots,n-1\thinspace .\]</div>
  1399. <p>The natural specification of the translation is in terms of the
  1400. vector <span class="math">\(v=(v_0,v_1)\)</span>.
  1401. The corresponding Python implementation in class <code class="docutils literal"><span class="pre">Curve</span></code> becomes</p>
  1402. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
  1403. <span class="o">...</span>
  1404. <span class="k">def</span> <span class="nf">translate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
  1405. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">+=</span> <span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
  1406. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">+=</span> <span class="n">v</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
  1407. </pre></div>
  1408. </div>
  1409. <p>The translation operation for a shape object is very similar to the
  1410. scaling and drawing operations. This means that we can implement a
  1411. common method <code class="docutils literal"><span class="pre">translate</span></code> in the superclass <code class="docutils literal"><span class="pre">Shape</span></code>. The code
  1412. is parallel to the <code class="docutils literal"><span class="pre">scale</span></code> method:</p>
  1413. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
  1414. <span class="o">....</span>
  1415. <span class="k">def</span> <span class="nf">translate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
  1416. <span class="k">for</span> <span class="n">shape</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">:</span>
  1417. <span class="bp">self</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="n">shape</span><span class="p">]</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
  1418. </pre></div>
  1419. </div>
  1420. </div>
  1421. <div class="section" id="rotation">
  1422. <h4>Rotation<a class="headerlink" href="#rotation" title="Permalink to this headline">¶</a></h4>
  1423. <p>Rotating a figure is more complicated than scaling and translating.
  1424. A counter clockwise rotation of <span class="math">\(\theta\)</span> degrees for a set of
  1425. coordinates <span class="math">\((x_i,y_i)\)</span> is given by</p>
  1426. <div class="math">
  1427. \[\begin{split}\bar x_i &amp;\leftarrow x_i\cos\theta - y_i\sin\theta,\\
  1428. \bar y_i &amp;\leftarrow x_i\sin\theta + y_i\cos\theta\thinspace .\end{split}\]</div>
  1429. <p>This rotation is performed around the origin. If we want the figure
  1430. to be rotated with respect to a general point <span class="math">\((x,y)\)</span>, we need to
  1431. extend the formulas above:</p>
  1432. <div class="math">
  1433. \[\begin{split}\bar x_i &amp;\leftarrow x + (x_i -x)\cos\theta - (y_i -y)\sin\theta,\\
  1434. \bar y_i &amp;\leftarrow y + (x_i -x)\sin\theta + (y_i -y)\cos\theta\thinspace .\end{split}\]</div>
  1435. <p>The Python implementation in class <code class="docutils literal"><span class="pre">Curve</span></code>, assuming that <span class="math">\(\theta\)</span>
  1436. is given in degrees and not in radians, becomes</p>
  1437. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">rotate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">angle</span><span class="p">,</span> <span class="n">center</span><span class="p">):</span>
  1438. <span class="n">angle</span> <span class="o">=</span> <span class="n">radians</span><span class="p">(</span><span class="n">angle</span><span class="p">)</span>
  1439. <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">center</span>
  1440. <span class="n">c</span> <span class="o">=</span> <span class="n">cos</span><span class="p">(</span><span class="n">angle</span><span class="p">);</span> <span class="n">s</span> <span class="o">=</span> <span class="n">sin</span><span class="p">(</span><span class="n">angle</span><span class="p">)</span>
  1441. <span class="n">xnew</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">x</span><span class="p">)</span><span class="o">*</span><span class="n">c</span> <span class="o">-</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">y</span><span class="p">)</span><span class="o">*</span><span class="n">s</span>
  1442. <span class="n">ynew</span> <span class="o">=</span> <span class="n">y</span> <span class="o">+</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">x</span><span class="p">)</span><span class="o">*</span><span class="n">s</span> <span class="o">+</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">y</span><span class="p">)</span><span class="o">*</span><span class="n">c</span>
  1443. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">xnew</span>
  1444. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">ynew</span>
  1445. </pre></div>
  1446. </div>
  1447. <p>The <code class="docutils literal"><span class="pre">rotate</span></code> method in class <code class="docutils literal"><span class="pre">Shape</span></code> follows the principle of the
  1448. <code class="docutils literal"><span class="pre">draw</span></code>, <code class="docutils literal"><span class="pre">scale</span></code>, and <code class="docutils literal"><span class="pre">translate</span></code> methods.</p>
  1449. <p>We have already seen the <code class="docutils literal"><span class="pre">rotate</span></code> method in action when animating the
  1450. rolling wheel at the end of the section <a class="reference internal" href="#sketcher-vehicle1-anim"><span class="std std-ref">Animation: Rolling the Wheels</span></a>.</p>
  1451. </div>
  1452. </div>
  1453. </div>
  1454. </div>
  1455. </div>
  1456. </div>
  1457. </div>
  1458. <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
  1459. <div class="sphinxsidebarwrapper">
  1460. <h3><a href="index.html">Table Of Contents</a></h3>
  1461. <ul>
  1462. <li><a class="reference internal" href="#">Pysketcher: Create Principal Sketches of Physics Problems</a><ul>
  1463. <li><a class="reference internal" href="#a-first-glimpse-of-pysketcher">A First Glimpse of Pysketcher</a><ul>
  1464. <li><a class="reference internal" href="#basic-construction-of-sketches">Basic Construction of Sketches</a><ul>
  1465. <li><a class="reference internal" href="#basic-drawing">Basic Drawing</a></li>
  1466. <li><a class="reference internal" href="#groups-of-objects">Groups of Objects</a></li>
  1467. <li><a class="reference internal" href="#changing-line-styles-and-colors">Changing Line Styles and Colors</a></li>
  1468. <li><a class="reference internal" href="#the-figure-composition-as-an-object-hierarchy">The Figure Composition as an Object Hierarchy</a></li>
  1469. <li><a class="reference internal" href="#animation-translating-the-vehicle">Animation: Translating the Vehicle</a></li>
  1470. <li><a class="reference internal" href="#animation-rolling-the-wheels">Animation: Rolling the Wheels</a></li>
  1471. </ul>
  1472. </li>
  1473. </ul>
  1474. </li>
  1475. <li><a class="reference internal" href="#basic-shapes">Basic Shapes</a><ul>
  1476. <li><a class="reference internal" href="#axis">Axis</a></li>
  1477. <li><a class="reference internal" href="#distance-with-text">Distance with Text</a></li>
  1478. <li><a class="reference internal" href="#rectangle">Rectangle</a></li>
  1479. <li><a class="reference internal" href="#triangle">Triangle</a></li>
  1480. <li><a class="reference internal" href="#arc">Arc</a></li>
  1481. <li><a class="reference internal" href="#spring">Spring</a></li>
  1482. <li><a class="reference internal" href="#dashpot">Dashpot</a></li>
  1483. <li><a class="reference internal" href="#wavy">Wavy</a></li>
  1484. <li><a class="reference internal" href="#stochastic-curves">Stochastic curves</a></li>
  1485. </ul>
  1486. </li>
  1487. <li><a class="reference internal" href="#inner-workings-of-the-pysketcher-tool">Inner Workings of the Pysketcher Tool</a><ul>
  1488. <li><a class="reference internal" href="#example-of-classes-for-geometric-objects">Example of Classes for Geometric Objects</a><ul>
  1489. <li><a class="reference internal" href="#simple-geometric-objects">Simple Geometric Objects</a></li>
  1490. <li><a class="reference internal" href="#class-curve">Class Curve</a></li>
  1491. <li><a class="reference internal" href="#compound-geometric-objects">Compound Geometric Objects</a></li>
  1492. </ul>
  1493. </li>
  1494. <li><a class="reference internal" href="#adding-functionality-via-recursion">Adding Functionality via Recursion</a><ul>
  1495. <li><a class="reference internal" href="#basic-principles-of-recursion">Basic Principles of Recursion</a></li>
  1496. <li><a class="reference internal" href="#explaining-recursion">Explaining Recursion</a></li>
  1497. </ul>
  1498. </li>
  1499. <li><a class="reference internal" href="#scaling-translating-and-rotating-a-figure">Scaling, Translating, and Rotating a Figure</a><ul>
  1500. <li><a class="reference internal" href="#scaling">Scaling</a></li>
  1501. <li><a class="reference internal" href="#translation">Translation</a></li>
  1502. <li><a class="reference internal" href="#rotation">Rotation</a></li>
  1503. </ul>
  1504. </li>
  1505. </ul>
  1506. </li>
  1507. </ul>
  1508. </li>
  1509. </ul>
  1510. <div class="relations">
  1511. <h3>Related Topics</h3>
  1512. <ul>
  1513. <li><a href="index.html">Documentation overview</a><ul>
  1514. <li>Previous: <a href="index.html" title="previous chapter">Pysketcher: Create Principal Sketches of Physics Problems</a></li>
  1515. </ul></li>
  1516. </ul>
  1517. </div>
  1518. <div role="note" aria-label="source link">
  1519. <h3>This Page</h3>
  1520. <ul class="this-page-menu">
  1521. <li><a href="_sources/main_sketcher.txt"
  1522. rel="nofollow">Show Source</a></li>
  1523. </ul>
  1524. </div>
  1525. <div id="searchbox" style="display: none" role="search">
  1526. <h3>Quick search</h3>
  1527. <form class="search" action="search.html" method="get">
  1528. <input type="text" name="q" />
  1529. <input type="submit" value="Go" />
  1530. <input type="hidden" name="check_keywords" value="yes" />
  1531. <input type="hidden" name="area" value="default" />
  1532. </form>
  1533. <p class="searchtip" style="font-size: 90%">
  1534. Enter search terms or a module, class or function name.
  1535. </p>
  1536. </div>
  1537. <script type="text/javascript">$('#searchbox').show(0);</script>
  1538. </div>
  1539. </div>
  1540. <div class="clearer"></div>
  1541. </div>
  1542. <div class="footer">
  1543. &copy;2015, Hans Petter Langtangen.
  1544. |
  1545. Powered by <a href="http://sphinx-doc.org/">Sphinx 1.4a0+</a>
  1546. &amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.6</a>
  1547. |
  1548. <a href="_sources/main_sketcher.txt"
  1549. rel="nofollow">Page source</a>
  1550. </div>
  1551. </body>
  1552. </html>