main_sketcher.html 248 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210
  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/default.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 type="text/javascript" src="_static/sidebar.js"></script>
  23. <script src="http://sagecell.sagemath.org/static/jquery.min.js"></script>
  24. <script src="http://sagecell.sagemath.org/static/embedded_sagecell.js"></script>
  25. <script>sagecell.makeSagecell({inputLocation: ".sage"});</script>
  26. <style type="text/css">
  27. .sagecell .CodeMirror-scroll {
  28. overflow-y: hidden;
  29. overflow-x: auto;
  30. }
  31. .sagecell .CodeMirror {
  32. height: auto;
  33. }
  34. </style>
  35. <link rel="top" title="Pysketcher: Create Principal Sketches of Physics Problems" href="index.html" />
  36. <link rel="prev" title="Pysketcher: Create Principal Sketches of Physics Problems" href="index.html" />
  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="related" role="navigation" aria-label="related navigation">
  46. <h3>Navigation</h3>
  47. <ul>
  48. <li class="right" style="margin-right: 10px">
  49. <a href="genindex.html" title="General Index"
  50. accesskey="I">index</a></li>
  51. <li class="right" >
  52. <a href="index.html" title="Pysketcher: Create Principal Sketches of Physics Problems"
  53. accesskey="P">previous</a> |</li>
  54. <li class="nav-item nav-item-0"><a href="index.html">Pysketcher: Create Principal Sketches of Physics Problems</a> &raquo;</li>
  55. </ul>
  56. </div>
  57. <div class="document">
  58. <div class="documentwrapper">
  59. <div class="bodywrapper">
  60. <div class="body" role="main">
  61. <div class="section" id="pysketcher-create-principal-sketches-of-physics-problems">
  62. <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>
  63. <table class="docutils field-list" frame="void" rules="none">
  64. <col class="field-name" />
  65. <col class="field-body" />
  66. <tbody valign="top">
  67. <tr class="field-odd field"><th class="field-name">Authors:</th><td class="field-body">Hans Petter Langtangen</td>
  68. </tr>
  69. <tr class="field-even field"><th class="field-name">Date:</th><td class="field-body">Jan 22, 2016</td>
  70. </tr>
  71. </tbody>
  72. </table>
  73. <p>This document is derived from Chapter 9 in the book
  74. <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,
  75. 4th edition, Springer, 2014.</p>
  76. <p><em>Abstract.</em> Pysketcher is a Python package which allows principal sketches of
  77. physics and mechanics problems to be realized through short programs
  78. instead of interactive (and potentially tedious and inaccurate)
  79. drawing. Elements of the sketch, such as lines, circles, angles,
  80. forces, coordinate systems, etc., are realized as objects and
  81. collected in hierarchical structures. Parts of the hierarchical
  82. structures can easily change line styles and colors, or be copied,
  83. scaled, translated, and rotated. These features make it
  84. straightforward to move parts of the sketch to create animation,
  85. usually in accordance with the physics of the underlying problem.
  86. Exact dimensioning of the elements in the sketch is trivial to obtain
  87. since distances are specified in computer code.</p>
  88. <p>Pysketcher is easy to learn from a number of examples. Beyond
  89. essential Python programming and a knowledge about mechanics problems,
  90. no further background is required.</p>
  91. <div class="section" id="a-first-glimpse-of-pysketcher">
  92. <h2>A first glimpse of Pysketcher<a class="headerlink" href="#a-first-glimpse-of-pysketcher" title="Permalink to this headline">¶</a></h2>
  93. <p>Formulation of physical problems makes heavy use of <em>principal sketches</em>
  94. 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>.
  95. This particular sketch illustrates the classical mechanics problem
  96. of a rolling wheel on an inclined plane.
  97. The figure
  98. is made up many individual elements: a rectangle
  99. filled with a pattern (the inclined plane), a hollow circle with color
  100. (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>
  101. axis), an angle with symbol <span class="math">\(\theta\)</span>, and a dashed line indicating the
  102. starting location of the wheel.</p>
  103. <p>Drawing software and plotting programs can produce such figures quite
  104. easily in principle, but the amount of details the user needs to
  105. control with the mouse can be substantial. Software more tailored to
  106. producing sketches of this type would work with more convenient
  107. abstractions, such as circle, wall, angle, force arrow, axis, and so
  108. forth. And as soon we start <em>programming</em> to construct the figure we
  109. get a range of other powerful tools at disposal. For example, we can
  110. easily translate and rotate parts of the figure and make an animation
  111. that illustrates the physics of the problem.
  112. Programming as a superior alternative to interactive drawing is
  113. the mantra of this section.</p>
  114. <div class="figure" id="id2">
  115. <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>
  116. <p class="caption"><span class="caption-text"><em>Sketch of a physics problem</em></span></p>
  117. </div>
  118. <div class="section" id="basic-construction-of-sketches">
  119. <h3>Basic construction of sketches<a class="headerlink" href="#basic-construction-of-sketches" title="Permalink to this headline">¶</a></h3>
  120. <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>
  121. we focus on the significantly simpler drawing shown
  122. 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
  123. several elements: two circles, two rectangles, and a &#8220;ground&#8221; element.</p>
  124. <div class="figure" id="id3">
  125. <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>
  126. <p class="caption"><span class="caption-text"><em>Sketch of a simple figure</em></span></p>
  127. </div>
  128. <p>When the sketch is defined in terms of computer code, it is natural to
  129. parameterize geometric features, such as the radius of the wheel (<span class="math">\(R\)</span>),
  130. the center point of the left wheel (<span class="math">\(w_1\)</span>), as well as the height (<span class="math">\(H\)</span>) and
  131. length (<span class="math">\(L\)</span>) of the main part. The simple vehicle in
  132. 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
  133. tool. However, if we want to change the radius of the wheels, you need a
  134. sophisticated drawing tool to avoid redrawing the whole figure, while
  135. in computer code this is a matter of changing the <span class="math">\(R\)</span> parameter and
  136. rerunning the program.
  137. 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
  138. a variation of the drawing in
  139. 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
  140. <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
  141. to quickly change geometric sizes is key to many problem settings in
  142. physics and engineering, but then a program must define the geometry.</p>
  143. <div class="figure" id="id4">
  144. <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>
  145. <p class="caption"><span class="caption-text"><em>Redrawing a figure with other geometric parameters</em></span></p>
  146. </div>
  147. <div class="section" id="basic-drawing">
  148. <h4>Basic drawing<a class="headerlink" href="#basic-drawing" title="Permalink to this headline">¶</a></h4>
  149. <p>A typical program creating these five elements is shown next.
  150. After importing the <code class="docutils literal"><span class="pre">pysketcher</span></code> package, the first task is always to
  151. define a coordinate system:</p>
  152. <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>
  153. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  154. <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>
  155. </pre></div>
  156. </div>
  157. <p>Instead of working with lengths expressed by specific numbers it is
  158. highly recommended to use variables to parameterize lengths as
  159. this makes it easier to change dimensions later.
  160. Here we introduce some key lengths for the radius of the wheels,
  161. distance between the wheels, etc.:</p>
  162. <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>
  163. <span class="n">L</span> <span class="o">=</span> <span class="mi">4</span> <span class="c"># distance between wheels</span>
  164. <span class="n">H</span> <span class="o">=</span> <span class="mi">2</span> <span class="c"># height of vehicle body</span>
  165. <span class="n">w_1</span> <span class="o">=</span> <span class="mi">5</span> <span class="c"># position of front wheel</span>
  166. <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>
  167. <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>
  168. </pre></div>
  169. </div>
  170. <p>With the drawing area in place we can make the first <code class="docutils literal"><span class="pre">Circle</span></code> object
  171. in an intuitive fashion:</p>
  172. <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>
  173. </pre></div>
  174. </div>
  175. <p>to change dimensions later.</p>
  176. <p>To translate the geometric information about the <code class="docutils literal"><span class="pre">wheel1</span></code> object to
  177. instructions for the plotting engine (in this case Matplotlib), one calls the
  178. <code class="docutils literal"><span class="pre">wheel1.draw()</span></code>. To display all drawn objects, one issues
  179. <code class="docutils literal"><span class="pre">drawing_tool.display()</span></code>. The typical steps are hence:</p>
  180. <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>
  181. <span class="n">wheel1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  182. <span class="c"># Define other objects and call their draw() methods</span>
  183. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  184. <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>
  185. </pre></div>
  186. </div>
  187. <p>The next wheel can be made by taking a copy of <code class="docutils literal"><span class="pre">wheel1</span></code> and
  188. translating the object to the right according to a
  189. displacement vector <span class="math">\((L,0)\)</span>:</p>
  190. <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>
  191. <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>
  192. </pre></div>
  193. </div>
  194. <p>The two rectangles are also made in an intuitive way:</p>
  195. <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>
  196. <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>
  197. <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>
  198. <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>
  199. </pre></div>
  200. </div>
  201. </div>
  202. <div class="section" id="groups-of-objects">
  203. <h4>Groups of objects<a class="headerlink" href="#groups-of-objects" title="Permalink to this headline">¶</a></h4>
  204. <p>Instead of calling the <code class="docutils literal"><span class="pre">draw</span></code> method of every object, we can
  205. group objects and call <code class="docutils literal"><span class="pre">draw</span></code>, or perform other operations, for
  206. the whole group. For example, we may collect the two wheels
  207. 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
  208. in a <code class="docutils literal"><span class="pre">body</span></code> group. The whole vehicle is a composition
  209. 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>
  210. <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>
  211. <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>
  212. <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>
  213. </pre></div>
  214. </div>
  215. <p>The ground is illustrated by an object of type <code class="docutils literal"><span class="pre">Wall</span></code>,
  216. mostly used to indicate walls in sketches of mechanical systems.
  217. 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,
  218. and a <code class="docutils literal"><span class="pre">thickness</span></code> parameter, and creates a thick curve filled
  219. with a simple pattern. In this case the curve is just a flat
  220. line so the construction is made of two points on the
  221. ground line (<span class="math">\((w_1-L,0)\)</span> and <span class="math">\((w_1+3L,0)\)</span>):</p>
  222. <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>
  223. </pre></div>
  224. </div>
  225. <p>The negative thickness makes the pattern-filled rectangle appear below
  226. the defined line, otherwise it appears above.</p>
  227. <p>We may now collect all the objects in a &#8220;top&#8221; object that contains
  228. the whole figure:</p>
  229. <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>
  230. <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>
  231. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  232. <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>
  233. </pre></div>
  234. </div>
  235. <p>The <code class="docutils literal"><span class="pre">fig.draw()</span></code> call will visit
  236. all subgroups, their subgroups,
  237. and so forth in the hierarchical tree structure of
  238. figure elements,
  239. and call <code class="docutils literal"><span class="pre">draw</span></code> for every object.</p>
  240. </div>
  241. <div class="section" id="changing-line-styles-and-colors">
  242. <h4>Changing line styles and colors<a class="headerlink" href="#changing-line-styles-and-colors" title="Permalink to this headline">¶</a></h4>
  243. <p>Controlling the line style, line color, and line width is
  244. fundamental when designing figures. The <code class="docutils literal"><span class="pre">pysketcher</span></code>
  245. package allows the user to control such properties in
  246. single objects, but also set global properties that are
  247. used if the object has no particular specification of
  248. the properties. Setting the global properties are done like</p>
  249. <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>
  250. <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>
  251. <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>
  252. </pre></div>
  253. </div>
  254. <p>At the object level the properties are specified in a similar
  255. way:</p>
  256. <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>
  257. <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>
  258. </pre></div>
  259. </div>
  260. <p>and so on.</p>
  261. <p>Geometric figures can be specified as <em>filled</em>, either with a color or with a
  262. special visual pattern:</p>
  263. <div class="highlight-python"><div class="highlight"><pre><span class="c"># Set filling of all curves</span>
  264. <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>
  265. <span class="c"># Turn off filling of all curves</span>
  266. <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>
  267. <span class="c"># Fill the wheel with red color</span>
  268. <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>
  269. </pre></div>
  270. </div>
  271. </div>
  272. <div class="section" id="the-figure-composition-as-an-object-hierarchy">
  273. <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>
  274. <p>The composition of objects making up the figure
  275. is hierarchical, similar to a family, where
  276. each object has a parent and a number of children. Do a
  277. <code class="docutils literal"><span class="pre">print</span> <span class="pre">fig</span></code> to display the relations:</p>
  278. <div class="highlight-text"><div class="highlight"><pre>ground
  279. wall
  280. vehicle
  281. body
  282. over
  283. rectangle
  284. under
  285. rectangle
  286. wheels
  287. wheel1
  288. arc
  289. wheel2
  290. arc
  291. </pre></div>
  292. </div>
  293. <p>The indentation reflects how deep down in the hierarchy (family)
  294. we are.
  295. This output is to be interpreted as follows:</p>
  296. <blockquote>
  297. <div><ul class="simple">
  298. <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>
  299. <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>
  300. <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>
  301. <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>
  302. <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>
  303. </ul>
  304. </div></blockquote>
  305. <p>In this listing there are also objects not defined by the
  306. 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>
  307. 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>
  308. <p>More detailed information can be printed by</p>
  309. <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>
  310. </pre></div>
  311. </div>
  312. <p>yielding the output</p>
  313. <div class="highlight-text"><div class="highlight"><pre>ground (Wall):
  314. wall (Curve): 4 coords fillcolor=&#39;white&#39; fillpattern=&#39;/&#39;
  315. vehicle (Composition):
  316. body (Composition):
  317. over (Rectangle):
  318. rectangle (Curve): 5 coords
  319. under (Rectangle):
  320. rectangle (Curve): 5 coords
  321. wheels (Composition):
  322. wheel1 (Circle):
  323. arc (Curve): 181 coords
  324. wheel2 (Circle):
  325. arc (Curve): 181 coords
  326. </pre></div>
  327. </div>
  328. <p>Here we can see the class type for each figure object, how many
  329. coordinates that are involved in basic figures (<code class="docutils literal"><span class="pre">Curve</span></code> objects), and
  330. special settings of the basic figure (fillcolor, line types, etc.).
  331. 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>,
  332. which is a <code class="docutils literal"><span class="pre">Curve</span></code> object consisting of 181 coordinates (the
  333. points needed to draw a smooth circle). The <code class="docutils literal"><span class="pre">Curve</span></code> objects are the
  334. only objects that really holds specific coordinates to be drawn.
  335. The other object types are just compositions used to group
  336. parts of the complete figure.</p>
  337. <p>One can also get a graphical overview of the hierarchy of figure objects
  338. that build up a particular figure <code class="docutils literal"><span class="pre">fig</span></code>.
  339. 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
  340. the <em>dot format</em>. This file contains relations between parent and
  341. child objects in the figure and can be turned into an image,
  342. 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
  343. running the <code class="docutils literal"><span class="pre">dot</span></code> program:</p>
  344. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; dot -Tpng -o fig.png fig.dot
  345. </pre></div>
  346. </div>
  347. <div class="figure" id="id5">
  348. <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>
  349. <p class="caption"><span class="caption-text"><em>Hierarchical relation between figure objects</em></span></p>
  350. </div>
  351. <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
  352. where the class type of each object is also visible, see
  353. Figure <span class="xref std std-ref">sketcher:fig:vehicle0:hier2</span>. The ability to write out the
  354. object hierarchy or view it graphically can be of great help when
  355. working with complex figures that involve layers of subfigures.</p>
  356. <div class="figure" id="id6">
  357. <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>
  358. <p class="caption"><span class="caption-text"><em>Hierarchical relation between figure objects, including their class names</em></span></p>
  359. </div>
  360. <p>Any of the objects can in the program be reached through their names, e.g.,</p>
  361. <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>
  362. <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>
  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="s">&#39;wheel2&#39;</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="s">&#39;wheel2&#39;</span><span class="p">][</span><span class="s">&#39;arc&#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;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>
  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;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>
  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;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>
  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;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>
  369. </pre></div>
  370. </div>
  371. <p>Grabbing a part of the figure this way is handy for
  372. changing properties of that part, for example, colors, line styles
  373. (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>
  374. <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>
  375. <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>
  376. <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>
  377. <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>
  378. <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>
  379. <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>
  380. <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>
  381. </pre></div>
  382. </div>
  383. <p>The last line accesses the <code class="docutils literal"><span class="pre">Curve</span></code> object directly, while the line above,
  384. accesses the <code class="docutils literal"><span class="pre">Rectangle</span></code> object, which will then set the linewidth of
  385. its <code class="docutils literal"><span class="pre">Curve</span></code> object, and other objects if it had any.
  386. 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>
  387. <div class="figure" id="id7">
  388. <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>
  389. <p class="caption"><span class="caption-text"><em>Left: Basic line-based drawing. Right: Thicker lines and filled parts</em></span></p>
  390. </div>
  391. <p>We can also change position of parts of the figure and thereby make
  392. animations, as shown next.</p>
  393. </div>
  394. <div class="section" id="animation-translating-the-vehicle">
  395. <h4>Animation: translating the vehicle<a class="headerlink" href="#animation-translating-the-vehicle" title="Permalink to this headline">¶</a></h4>
  396. <p>Can we make our little vehicle roll? A first attempt will be to
  397. fake rolling by just displacing all parts of the vehicle.
  398. The relevant parts constitute the <code class="docutils literal"><span class="pre">fig['vehicle']</span></code> object.
  399. This part of the figure can be translated, rotated, and scaled.
  400. A translation along the ground means a translation in <span class="math">\(x\)</span> direction,
  401. say a length <span class="math">\(L\)</span> to the right:</p>
  402. <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>
  403. </pre></div>
  404. </div>
  405. <p>You need to erase, draw, and display to see the movement:</p>
  406. <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>
  407. <span class="n">fig</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  408. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  409. </pre></div>
  410. </div>
  411. <p>Without erasing, the old drawing of the vehicle will remain in
  412. the figure so you get two vehicles. Without <code class="docutils literal"><span class="pre">fig.draw()</span></code> the
  413. new coordinates of the vehicle will not be communicated to
  414. the drawing tool, and without calling display the updated
  415. drawing will not be visible.</p>
  416. <p>A figure that moves in time is conveniently realized by the
  417. function <code class="docutils literal"><span class="pre">animate</span></code>:</p>
  418. <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>
  419. </pre></div>
  420. </div>
  421. <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
  422. time points, and <code class="docutils literal"><span class="pre">action</span></code> is a user-specified function that changes
  423. <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
  424. parts of <code class="docutils literal"><span class="pre">fig</span></code>.</p>
  425. <p>In the present case we can define the movement through a velocity
  426. 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
  427. intervals <code class="docutils literal"><span class="pre">dt</span></code>. A possible velocity function is</p>
  428. <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>
  429. <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>
  430. </pre></div>
  431. </div>
  432. <p>Our action function for horizontal displacements <code class="docutils literal"><span class="pre">v(t)*dt</span></code> becomes</p>
  433. <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>
  434. <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>
  435. <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>
  436. </pre></div>
  437. </div>
  438. <p>Since our velocity is negative for <span class="math">\(t\in [0,2R]\)</span> the displacement is
  439. to the left.</p>
  440. <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
  441. 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
  442. <code class="docutils literal"><span class="pre">fig.draw()</span></code> and <code class="docutils literal"><span class="pre">drawing_tool.display()</span></code>.
  443. Here we choose a resolution of the animation corresponding to
  444. 25 time points in the time interval <span class="math">\([0,2R]\)</span>:</p>
  445. <div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">numpy</span>
  446. <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>
  447. <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>
  448. <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>
  449. </pre></div>
  450. </div>
  451. <p>The <code class="docutils literal"><span class="pre">pause_per_frame</span></code> adds a pause, here 0.2 seconds, between
  452. each frame in the animation.</p>
  453. <p>We can also ask <code class="docutils literal"><span class="pre">animate</span></code> to store each frame in a file:</p>
  454. <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>
  455. <span class="n">pause_per_frame</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)</span>
  456. </pre></div>
  457. </div>
  458. <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>,
  459. is the printf-specification used to generate the individual
  460. plot files. We can use this specification to make a video
  461. 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
  462. as Ubuntu). Videos in the Flash and WebM formats can be created
  463. by</p>
  464. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec flv mov.flv
  465. Terminal&gt; ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec libvpx mov.webm
  466. </pre></div>
  467. </div>
  468. <p>An animated GIF movie can also be made using the <code class="docutils literal"><span class="pre">convert</span></code> program
  469. from the ImageMagick software suite:</p>
  470. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; convert -delay 20 tmp_frame*.png mov.gif
  471. Terminal&gt; animate mov.gif # play movie
  472. </pre></div>
  473. </div>
  474. <p>The delay between frames, in units of 1/100 s,
  475. governs the speed of the movie.
  476. To play the animated GIF file in a web page, simply insert
  477. <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>
  478. <p>The individual PNG frames can be directly played in a web
  479. browser by running</p>
  480. <div class="highlight-text"><div class="highlight"><pre>Terminal&gt; scitools movie output_file=mov.html fps=5 tmp_frame*
  481. </pre></div>
  482. </div>
  483. <p>or calling</p>
  484. <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>
  485. <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>
  486. </pre></div>
  487. </div>
  488. <p>in Python. Load the resulting file <code class="docutils literal"><span class="pre">mov.html</span></code> into a web browser
  489. to play the movie.</p>
  490. <p>Try to run <a class="reference external" href="http://tinyurl.com/ot733jn/vehicle0.py">vehicle0.py</a> and
  491. 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>
  492. 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>
  493. </div>
  494. <div class="section" id="animation-rolling-the-wheels">
  495. <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>
  496. <p>It is time to show rolling wheels. To this end, we add spokes to the
  497. 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>.
  498. The construction of the wheels will now involve a circle and two lines:</p>
  499. <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>
  500. <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>
  501. <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>
  502. <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>
  503. <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>
  504. <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>
  505. </pre></div>
  506. </div>
  507. <p>Observe that <code class="docutils literal"><span class="pre">wheel1.copy()</span></code> copies all the objects that make
  508. up the first wheel, and <code class="docutils literal"><span class="pre">wheel2.translate</span></code> translates all
  509. the copied objects.</p>
  510. <div class="figure" id="id8">
  511. <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>
  512. <p class="caption"><span class="caption-text"><em>Wheels with spokes to illustrate rolling</em></span></p>
  513. </div>
  514. <p>The <code class="docutils literal"><span class="pre">move</span></code> function now needs to displace all the objects in the
  515. 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>
  516. objects in both wheels.
  517. The rotation angle follows from the fact that the arc length
  518. of a rolling wheel equals the displacement of the center of
  519. the wheel, leading to a rotation angle</p>
  520. <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>
  521. </pre></div>
  522. </div>
  523. <p>With <code class="docutils literal"><span class="pre">w_1</span></code> tracking the <span class="math">\(x\)</span> coordinate of the center
  524. of the front wheel, we can rotate that wheel by</p>
  525. <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>
  526. <span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">degrees</span>
  527. <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>
  528. </pre></div>
  529. </div>
  530. <p>The <code class="docutils literal"><span class="pre">rotate</span></code> function takes two parameters: the rotation angle
  531. (in degrees) and the center point of the rotation, which is the
  532. center of the wheel in this case. The other wheel is rotated by</p>
  533. <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>
  534. <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>
  535. </pre></div>
  536. </div>
  537. <p>That is, the angle is the same, but the rotation point is different.
  538. 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>.
  539. The complete <code class="docutils literal"><span class="pre">move</span></code> function with translation of the entire
  540. vehicle and rotation of the wheels then becomes</p>
  541. <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>
  542. <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>
  543. <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>
  544. <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>
  545. <span class="c"># Rotate wheels</span>
  546. <span class="k">global</span> <span class="n">w_1</span>
  547. <span class="n">w_1</span> <span class="o">+=</span> <span class="n">x_displacement</span>
  548. <span class="c"># R*angle = -x_displacement</span>
  549. <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>
  550. <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>
  551. <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>
  552. <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>
  553. <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>
  554. </pre></div>
  555. </div>
  556. <p>The complete example is found in the file
  557. <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>
  558. <p>The advantages with making figures this way, through programming
  559. rather than using interactive drawing programs, are numerous. For
  560. example, the objects are parameterized by variables so that various
  561. dimensions can easily be changed. Subparts of the figure, possible
  562. involving a lot of figure objects, can change color, linetype, filling
  563. or other properties through a <em>single</em> function call. Subparts of the
  564. figure can be rotated, translated, or scaled. Subparts of the figure
  565. can also be copied and moved to other parts of the drawing
  566. area. However, the single most important feature is probably the
  567. ability to make animations governed by mathematical formulas or data
  568. coming from physics simulations of the problem, as shown in the example above.</p>
  569. </div>
  570. </div>
  571. </div>
  572. <div class="section" id="a-simple-pendulum">
  573. <span id="sketcher-ex-pendulum"></span><h2>A simple pendulum<a class="headerlink" href="#a-simple-pendulum" title="Permalink to this headline">¶</a></h2>
  574. <div class="section" id="the-basic-physics-sketch">
  575. <span id="sketcher-ex-pendulum-basic"></span><h3>The basic physics sketch<a class="headerlink" href="#the-basic-physics-sketch" title="Permalink to this headline">¶</a></h3>
  576. <p>We now want to make a sketch of simple pendulum from physics, as shown
  577. in Figure <a class="reference internal" href="#sketcher-ex-pendulum-fig1"><span class="std std-ref">Sketch of a simple pendulum</span></a>. A body with mass <span class="math">\(m\)</span> is attached
  578. to a massless, stiff rod, which can rotate about a point, causing the
  579. pendulum to oscillate.</p>
  580. <p>A suggested work flow is to
  581. first sketch the figure on a piece of paper and introduce a coordinate
  582. system. A simple coordinate system is indicated in Figure
  583. <a class="reference internal" href="#sketcher-ex-pendulum-fig1wgrid"><span class="std std-ref">Sketch with assisting coordinate system</span></a>. In a code we introduce variables
  584. <code class="docutils literal"><span class="pre">W</span></code> and <code class="docutils literal"><span class="pre">H</span></code> for the width and height of the figure (i.e., extent of
  585. the coordinate system) and open the program like this:</p>
  586. <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>
  587. <span class="n">H</span> <span class="o">=</span> <span class="mf">7.</span>
  588. <span class="n">W</span> <span class="o">=</span> <span class="mf">6.</span>
  589. <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</span><span class="p">,</span>
  590. <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="n">H</span><span class="p">,</span>
  591. <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
  592. <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>
  593. <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>
  594. </pre></div>
  595. </div>
  596. <p>Note that when the sketch is ready for &#8220;production&#8221;, we will (normally)
  597. set <code class="docutils literal"><span class="pre">axis=False</span></code> to remove the coordinate system and also remove the
  598. grid, i.e., delete or
  599. comment out the line <code class="docutils literal"><span class="pre">drawing_tool.set_grid(True)</span></code>.
  600. Also note that we in this example let all lines be blue by default.</p>
  601. <div class="figure" id="id9">
  602. <span id="sketcher-ex-pendulum-fig1"></span><a class="reference internal image-reference" href="_images/pendulum1.png"><img alt="_images/pendulum1.png" src="_images/pendulum1.png" style="width: 300px;" /></a>
  603. <p class="caption"><span class="caption-text"><em>Sketch of a simple pendulum</em></span></p>
  604. </div>
  605. <div class="figure" id="id10">
  606. <span id="sketcher-ex-pendulum-fig1wgrid"></span><a class="reference internal image-reference" href="_images/pendulum1_wgrid.png"><img alt="_images/pendulum1_wgrid.png" src="_images/pendulum1_wgrid.png" style="width: 400px;" /></a>
  607. <p class="caption"><span class="caption-text"><em>Sketch with assisting coordinate system</em></span></p>
  608. </div>
  609. <p>The next step is to introduce variables for key quantities in the sketch.
  610. Let <code class="docutils literal"><span class="pre">L</span></code> be the length of the pendulum, <code class="docutils literal"><span class="pre">P</span></code> the rotation point, and let
  611. <code class="docutils literal"><span class="pre">a</span></code> be the angle the pendulum makes with the vertical (measured in degrees).
  612. We may set</p>
  613. <div class="highlight-python"><div class="highlight"><pre><span class="n">L</span> <span class="o">=</span> <span class="mi">5</span><span class="o">*</span><span class="n">H</span><span class="o">/</span><span class="mi">7</span> <span class="c"># length</span>
  614. <span class="n">P</span> <span class="o">=</span> <span class="p">(</span><span class="n">W</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="mf">0.85</span><span class="o">*</span><span class="n">H</span><span class="p">)</span> <span class="c"># rotation point</span>
  615. <span class="n">a</span> <span class="o">=</span> <span class="mi">40</span> <span class="c"># angle</span>
  616. </pre></div>
  617. </div>
  618. <p>Be careful with integer division if you use Python 2! Fortunately, we
  619. started out with <code class="docutils literal"><span class="pre">float</span></code> objects for <code class="docutils literal"><span class="pre">W</span></code> and <code class="docutils literal"><span class="pre">H</span></code> so the expressions above
  620. are safe.</p>
  621. <p>What kind of objects do we need in this sketch? Looking at
  622. Figure <a class="reference internal" href="#sketcher-ex-pendulum-fig1"><span class="std std-ref">Sketch of a simple pendulum</span></a> we see that we need</p>
  623. <ol class="arabic simple">
  624. <li>a vertical, dashed line</li>
  625. <li>an arc with no text but dashed line to indicate the <em>path</em> of the
  626. mass</li>
  627. <li>an arc with name <span class="math">\(\theta\)</span> to indicate the <em>angle</em></li>
  628. <li>a line, here called <em>rod</em>, from the rotation point to the mass</li>
  629. <li>a blue, filled circle representing the <em>mass</em></li>
  630. <li>a text <span class="math">\(m\)</span> associated with the mass</li>
  631. <li>an indicator of the pendulum&#8217;s <em>length</em> <span class="math">\(L\)</span>, visualized as
  632. a line with two arrows tips and the text <span class="math">\(L\)</span></li>
  633. <li>a gravity vector with the text <span class="math">\(g\)</span></li>
  634. </ol>
  635. <p>Pysketcher has objects for each of these elements in our sketch.
  636. We start with the simplest element: the vertical line, going from
  637. <code class="docutils literal"><span class="pre">P</span></code> to <code class="docutils literal"><span class="pre">P</span></code> minus the length <span class="math">\(L\)</span> in <span class="math">\(y\)</span> direction:</p>
  638. <div class="highlight-python"><div class="highlight"><pre><span class="n">vertical</span> <span class="o">=</span> <span class="n">Line</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">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">L</span><span class="p">))</span>
  639. </pre></div>
  640. </div>
  641. <p>The class <code class="docutils literal"><span class="pre">point</span></code> is very convenient: it turns its two coordinates into
  642. a vector with which we can compute, and is therefore one of the most
  643. widely used Pysketcher objects.</p>
  644. <p>The path of the mass is an arc that can be made by
  645. Pysketcher&#8217;s <code class="docutils literal"><span class="pre">Arc</span></code> object:</p>
  646. <div class="highlight-python"><div class="highlight"><pre><span class="n">path</span> <span class="o">=</span> <span class="n">Arc</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="o">-</span><span class="mi">90</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span>
  647. </pre></div>
  648. </div>
  649. <p>The first argument <code class="docutils literal"><span class="pre">P</span></code> is the center point, the second is the
  650. radius (<code class="docutils literal"><span class="pre">L</span></code> here), the next argument is the start angle, here
  651. it starts at -90 degrees, while the next argument is the angle of
  652. the arc, here <code class="docutils literal"><span class="pre">a</span></code>.
  653. For the path of the mass, we also need an arc object, but this
  654. time with an associated text. Pysketcher has a specialized object
  655. for this purpose, <code class="docutils literal"><span class="pre">Arc_wText</span></code>, since placing the text manually can
  656. be somewhat cumbersome.</p>
  657. <div class="highlight-python"><div class="highlight"><pre><span class="n">angle</span> <span class="o">=</span> <span class="n">Arc_wText</span><span class="p">(</span><span class="s">r&#39;$\theta$&#39;</span><span class="p">,</span> <span class="n">P</span><span class="p">,</span> <span class="n">L</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="o">-</span><span class="mi">90</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">text_spacing</span><span class="o">=</span><span class="mi">1</span><span class="o">/</span><span class="mf">30.</span><span class="p">)</span>
  658. </pre></div>
  659. </div>
  660. <p>The arguments are as for <code class="docutils literal"><span class="pre">Arc</span></code> above, but the first one is the desired
  661. text. Remember to use a raw string since we want a LaTeX greek letter
  662. that contains a backslash.
  663. The <code class="docutils literal"><span class="pre">text_spacing</span></code> argument must often be tweaked. It is recommended
  664. to create only a few objects before rendering the sketch and then
  665. adjust spacings as one goes along.</p>
  666. <p>The rod is simply a line from <code class="docutils literal"><span class="pre">P</span></code> to the mass. We can easily
  667. compute the position of the mass from basic geometry considerations,
  668. but it is easier and safer to look up this point in other objects
  669. if it is already computed. In the present case,
  670. the <code class="docutils literal"><span class="pre">path</span></code> object stored its start and
  671. end points, so <code class="docutils literal"><span class="pre">path.geometric_features()['end']</span></code> is the end point
  672. of the path, which is the position of the mass. We can therefore
  673. create the rod simply as a line from <code class="docutils literal"><span class="pre">P</span></code> to this already computed end point:</p>
  674. <div class="highlight-python"><div class="highlight"><pre><span class="n">mass_pt</span> <span class="o">=</span> <span class="n">path</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>
  675. <span class="n">rod</span> <span class="o">=</span> <span class="n">Line</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">mass_pt</span><span class="p">)</span>
  676. </pre></div>
  677. </div>
  678. <p>The mass is a circle filled with color:</p>
  679. <div class="highlight-python"><div class="highlight"><pre><span class="n">mass</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="n">mass_pt</span><span class="p">,</span> <span class="n">radius</span><span class="o">=</span><span class="n">L</span><span class="o">/</span><span class="mf">20.</span><span class="p">)</span>
  680. <span class="n">mass</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>
  681. </pre></div>
  682. </div>
  683. <p>To place the <span class="math">\(m\)</span> correctly, we go a small distance in the direction of
  684. the rod, from the center of the circle. To this end, we need to
  685. compute the direction. This is easiest done by computing a vector
  686. from <code class="docutils literal"><span class="pre">P</span></code> to the center of the circle and calling <code class="docutils literal"><span class="pre">unit_vec</span></code> to make
  687. a unit vector in this direction:</p>
  688. <div class="highlight-python"><div class="highlight"><pre><span class="n">rod_vec</span> <span class="o">=</span> <span class="n">rod</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> \
  689. <span class="n">rod</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">&#39;start&#39;</span><span class="p">]</span>
  690. <span class="n">unit_rod_vec</span> <span class="o">=</span> <span class="n">unit_vec</span><span class="p">(</span><span class="n">rod_vec</span><span class="p">)</span>
  691. <span class="n">mass_symbol</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">&#39;$m$&#39;</span><span class="p">,</span> <span class="n">mass_pt</span> <span class="o">+</span> <span class="n">L</span><span class="o">/</span><span class="mi">10</span><span class="o">*</span><span class="n">unit_rod_vec</span><span class="p">)</span>
  692. </pre></div>
  693. </div>
  694. <p>Again, the distance <code class="docutils literal"><span class="pre">L/10</span></code> is something one has to experiment with.</p>
  695. <p>The next object is the length measure with the text <span class="math">\(L\)</span>. Such length
  696. measures are represented by Pysketcher&#8217;s <code class="docutils literal"><span class="pre">Distance_wText</span></code> object.
  697. An easy construction is to first place this length measure along the
  698. rod and then translate it a little distance (<code class="docutils literal"><span class="pre">L/15</span></code>) in the
  699. normal direction of the rod:</p>
  700. <div class="highlight-python"><div class="highlight"><pre><span class="n">length</span> <span class="o">=</span> <span class="n">Distance_wText</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">mass_pt</span><span class="p">,</span> <span class="s">&#39;$L$&#39;</span><span class="p">)</span>
  701. <span class="n">length</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">L</span><span class="o">/</span><span class="mi">15</span><span class="o">*</span><span class="n">point</span><span class="p">(</span><span class="n">cos</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">)),</span> <span class="n">sin</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">))))</span>
  702. </pre></div>
  703. </div>
  704. <p>For this translation we need a unit vector in the normal direction
  705. of the rod, which is from geometric considerations given by
  706. <span class="math">\((\cos a, \sin a)\)</span>, when <span class="math">\(a\)</span> is the angle of the pendulum.
  707. Alternatively, we could have found the normal vector as a vector that
  708. is normal to <code class="docutils literal"><span class="pre">unit_rod_vec</span></code>: <code class="docutils literal"><span class="pre">point(-unit_rod_vec[1],unit_rod_vec[0])</span></code>.</p>
  709. <p>The final object is the gravity force vector, which is so common
  710. in physics sketches that Pysketcher has a ready-made object: <code class="docutils literal"><span class="pre">Gravity</span></code>,</p>
  711. <div class="highlight-python"><div class="highlight"><pre><span class="n">gravity</span> <span class="o">=</span> <span class="n">Gravity</span><span class="p">(</span><span class="n">start</span><span class="o">=</span><span class="n">P</span><span class="o">+</span><span class="n">point</span><span class="p">(</span><span class="mf">0.8</span><span class="o">*</span><span class="n">L</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="o">/</span><span class="mi">3</span><span class="p">)</span>
  712. </pre></div>
  713. </div>
  714. <p>Since blue is the default color for
  715. lines, we want the dashed lines (for <code class="docutils literal"><span class="pre">vertical</span></code> and <code class="docutils literal"><span class="pre">path</span></code>) to be black
  716. and with linewidth 1. These properties can be set one by one for each
  717. object, but we can also make a little helper function:</p>
  718. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">set_dashed_thin_blackline</span><span class="p">(</span><span class="o">*</span><span class="n">objects</span><span class="p">):</span>
  719. <span class="sd">&quot;&quot;&quot;Set linestyle of objects to dashed, black, width=1.&quot;&quot;&quot;</span>
  720. <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
  721. <span class="n">obj</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>
  722. <span class="n">obj</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>
  723. <span class="n">obj</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  724. <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">vertical</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
  725. </pre></div>
  726. </div>
  727. <p>Now, all objects are in place, so it remains to compose the final
  728. figure and draw the composition:</p>
  729. <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>
  730. <span class="p">{</span><span class="s">&#39;body&#39;</span><span class="p">:</span> <span class="n">mass</span><span class="p">,</span> <span class="s">&#39;rod&#39;</span><span class="p">:</span> <span class="n">rod</span><span class="p">,</span>
  731. <span class="s">&#39;vertical&#39;</span><span class="p">:</span> <span class="n">vertical</span><span class="p">,</span> <span class="s">&#39;theta&#39;</span><span class="p">:</span> <span class="n">angle</span><span class="p">,</span> <span class="s">&#39;path&#39;</span><span class="p">:</span> <span class="n">path</span><span class="p">,</span>
  732. <span class="s">&#39;g&#39;</span><span class="p">:</span> <span class="n">gravity</span><span class="p">,</span> <span class="s">&#39;L&#39;</span><span class="p">:</span> <span class="n">length</span><span class="p">,</span> <span class="s">&#39;m&#39;</span><span class="p">:</span> <span class="n">mass_symbol</span><span class="p">})</span>
  733. <span class="n">fig</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  734. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  735. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">&#39;pendulum1&#39;</span><span class="p">)</span>
  736. </pre></div>
  737. </div>
  738. </div>
  739. <div class="section" id="the-body-diagram">
  740. <h3>The body diagram<a class="headerlink" href="#the-body-diagram" title="Permalink to this headline">¶</a></h3>
  741. <p>Now we want to isolate the mass and draw all the forces that act on it.
  742. Figure <a class="reference internal" href="#sketcher-ex-pendulum-fig2wgrid"><span class="std std-ref">Body diagram of a simple pendulum</span></a> shows the desired result, but
  743. embedded in the coordinate system.
  744. We consider three types of forces: the gravity force, the force from the
  745. rod, and air resistance. The body diagram is key for deriving the
  746. equation of motion, so it is illustrative to add useful mathematical
  747. quantities needed in the derivation, such as the unit vectors in polar
  748. coordinates.</p>
  749. <div class="figure" id="id11">
  750. <span id="sketcher-ex-pendulum-fig2wgrid"></span><a class="reference internal image-reference" href="_images/pendulum5_wgrid.png"><img alt="_images/pendulum5_wgrid.png" src="_images/pendulum5_wgrid.png" style="width: 300px;" /></a>
  751. <p class="caption"><span class="caption-text"><em>Body diagram of a simple pendulum</em></span></p>
  752. </div>
  753. <p>We start by listing the objects in the sketch:</p>
  754. <ol class="arabic simple">
  755. <li>a text <span class="math">\((x_0,y_0)\)</span> representing the rotation point <code class="docutils literal"><span class="pre">P</span></code></li>
  756. <li>unit vector <span class="math">\(\boldsymbol{i}_r\)</span> with text</li>
  757. <li>unit vector <span class="math">\(\boldsymbol{i}_\theta\)</span> with text</li>
  758. <li>a dashed vertical line</li>
  759. <li>a dashed line along the rod</li>
  760. <li>an arc with text <span class="math">\(\theta\)</span></li>
  761. <li>the gravity force with text <span class="math">\(mg\)</span></li>
  762. <li>the force in the rod with text <span class="math">\(S\)</span></li>
  763. <li>the air resistance force with text <span class="math">\(\sim |v|v\)</span></li>
  764. </ol>
  765. <p>The first object, <span class="math">\((x_0,y_0)\)</span>, is simply a plain text where we have
  766. to experiment with its position. The unit vectors in polar coordinates
  767. may be drawn using the Pysketcher&#8217;s <code class="docutils literal"><span class="pre">Force</span></code> object since it has an
  768. arrow with a text. The first three objects can then be made as follows:</p>
  769. <div class="highlight-python"><div class="highlight"><pre><span class="n">x0y0</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">&#39;$(x_0,y_0)$&#39;</span><span class="p">,</span> <span class="n">P</span> <span class="o">+</span> <span class="n">point</span><span class="p">(</span><span class="o">-</span><span class="mf">0.4</span><span class="p">,</span><span class="o">-</span><span class="mf">0.1</span><span class="p">))</span>
  770. <span class="n">ir</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">P</span> <span class="o">+</span> <span class="n">L</span><span class="o">/</span><span class="mi">10</span><span class="o">*</span><span class="n">unit_vec</span><span class="p">(</span><span class="n">rod_vec</span><span class="p">),</span>
  771. <span class="s">r&#39;$\boldsymbol{i}_r$&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  772. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.015</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
  773. <span class="n">ith</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">P</span> <span class="o">+</span> <span class="n">L</span><span class="o">/</span><span class="mi">10</span><span class="o">*</span><span class="n">unit_vec</span><span class="p">((</span><span class="o">-</span><span class="n">rod_vec</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">rod_vec</span><span class="p">[</span><span class="mi">0</span><span class="p">])),</span>
  774. <span class="s">r&#39;$\boldsymbol{i}_{\theta}$&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  775. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.02</span><span class="p">,</span><span class="mf">0.005</span><span class="p">))</span>
  776. </pre></div>
  777. </div>
  778. <p>Note that tweaking of the position of <code class="docutils literal"><span class="pre">x0y0</span></code> use absolute coordinates, so
  779. if <code class="docutils literal"><span class="pre">W</span></code> or <code class="docutils literal"><span class="pre">H</span></code> is changed in the beginning of the figure, the tweaked position
  780. will most likely not look good. A better solution would be to express
  781. the tweaked displacement <code class="docutils literal"><span class="pre">point(-0.4,-0.1)</span></code> in terms of <code class="docutils literal"><span class="pre">W</span></code> and <code class="docutils literal"><span class="pre">H</span></code>.
  782. The <code class="docutils literal"><span class="pre">text_spacing</span></code> values in the <code class="docutils literal"><span class="pre">Force</span></code> objects also use absolute
  783. coordinates. Very often, this is much more convenient when adjusting
  784. the objects, and global size parameters like <code class="docutils literal"><span class="pre">W</span></code> and <code class="docutils literal"><span class="pre">H</span></code> are in practice
  785. seldom changed, so the solution above is quite typical.</p>
  786. <p>The vertical, dashed line, the dashed rod, and the arc for <span class="math">\(\theta\)</span>
  787. are made by</p>
  788. <div class="highlight-python"><div class="highlight"><pre><span class="n">rod_start</span> <span class="o">=</span> <span class="n">rod</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">&#39;start&#39;</span><span class="p">]</span> <span class="c"># Point P</span>
  789. <span class="n">vertical2</span> <span class="o">=</span> <span class="n">Line</span><span class="p">(</span><span class="n">rod_start</span><span class="p">,</span> <span class="n">rod_start</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="o">-</span><span class="n">L</span><span class="o">/</span><span class="mi">3</span><span class="p">))</span>
  790. <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">vertical2</span><span class="p">)</span>
  791. <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">rod</span><span class="p">)</span>
  792. <span class="n">angle2</span> <span class="o">=</span> <span class="n">Arc_wText</span><span class="p">(</span><span class="s">r&#39;$\theta$&#39;</span><span class="p">,</span> <span class="n">rod_start</span><span class="p">,</span> <span class="n">L</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="o">-</span><span class="mi">90</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span>
  793. <span class="n">text_spacing</span><span class="o">=</span><span class="mi">1</span><span class="o">/</span><span class="mf">30.</span><span class="p">)</span>
  794. </pre></div>
  795. </div>
  796. <p>Note how we reuse the earlier defined object <code class="docutils literal"><span class="pre">rod</span></code>.</p>
  797. <p>The forces are constructed as shown below.</p>
  798. <div class="highlight-python"><div class="highlight"><pre><span class="n">mg_force</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">mass_pt</span><span class="p">,</span> <span class="n">mass_pt</span> <span class="o">+</span> <span class="n">L</span><span class="o">/</span><span class="mi">5</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="o">-</span><span class="mi">1</span><span class="p">),</span>
  799. <span class="s">&#39;$mg$&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">)</span>
  800. <span class="n">rod_force</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">mass_pt</span><span class="p">,</span> <span class="n">mass_pt</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">unit_vec</span><span class="p">(</span><span class="n">rod_vec</span><span class="p">),</span>
  801. <span class="s">&#39;$S$&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  802. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.03</span><span class="p">,</span> <span class="mf">0.01</span><span class="p">))</span>
  803. <span class="n">air_force</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">mass_pt</span><span class="p">,</span> <span class="n">mass_pt</span> <span class="o">-</span>
  804. <span class="n">L</span><span class="o">/</span><span class="mi">6</span><span class="o">*</span><span class="n">unit_vec</span><span class="p">((</span><span class="n">rod_vec</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">-</span><span class="n">rod_vec</span><span class="p">[</span><span class="mi">0</span><span class="p">])),</span>
  805. <span class="s">&#39;$\sim|v|v$&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  806. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.04</span><span class="p">,</span><span class="mf">0.005</span><span class="p">))</span>
  807. </pre></div>
  808. </div>
  809. <p>Note that the drag force from the air is directed perpendicular to
  810. the rod, so we construct a unit vector in this direction directly from
  811. the <code class="docutils literal"><span class="pre">rod_vec</span></code> vector.</p>
  812. <p>All objects are in place, and we can compose a figure to be drawn:</p>
  813. <div class="highlight-python"><div class="highlight"><pre><span class="n">body_diagram</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
  814. <span class="p">{</span><span class="s">&#39;mg&#39;</span><span class="p">:</span> <span class="n">mg_force</span><span class="p">,</span> <span class="s">&#39;S&#39;</span><span class="p">:</span> <span class="n">rod_force</span><span class="p">,</span> <span class="s">&#39;rod&#39;</span><span class="p">:</span> <span class="n">rod</span><span class="p">,</span>
  815. <span class="s">&#39;vertical&#39;</span><span class="p">:</span> <span class="n">vertical2</span><span class="p">,</span> <span class="s">&#39;theta&#39;</span><span class="p">:</span> <span class="n">angle2</span><span class="p">,</span>
  816. <span class="s">&#39;body&#39;</span><span class="p">:</span> <span class="n">mass</span><span class="p">,</span> <span class="s">&#39;m&#39;</span><span class="p">:</span> <span class="n">mass_symbol</span><span class="p">})</span>
  817. <span class="n">body_diagram</span><span class="p">[</span><span class="s">&#39;air&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">air_force</span>
  818. <span class="n">body_diagram</span><span class="p">[</span><span class="s">&#39;ir&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ir</span>
  819. <span class="n">body_diagram</span><span class="p">[</span><span class="s">&#39;ith&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ith</span>
  820. <span class="n">body_diagram</span><span class="p">[</span><span class="s">&#39;origin&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">x0y0</span>
  821. </pre></div>
  822. </div>
  823. <p>Here, we exemplify that we can start out with a composition as a
  824. dictionary, but (as in ordinary Python dictionaries) add new
  825. elements later when desired.</p>
  826. </div>
  827. <div class="section" id="animated-body-diagram">
  828. <span id="sketcher-ex-pendulum-anim"></span><h3>Animated body diagram<a class="headerlink" href="#animated-body-diagram" title="Permalink to this headline">¶</a></h3>
  829. <p>We want to make an animated body diagram so that we can see how forces
  830. develop in time according to the motion. This means that we must
  831. couple the sketch at each time level to a numerical solution for
  832. the motion of the pendulum.</p>
  833. <div class="section" id="function-for-drawing-the-body-diagram">
  834. <h4>Function for drawing the body diagram<a class="headerlink" href="#function-for-drawing-the-body-diagram" title="Permalink to this headline">¶</a></h4>
  835. <p>The previous flat program for making sketches of the pendulum is not
  836. suitable when we want to make a sketch at a lot of different points
  837. in time, i.e., for a lot of different angles that the pendulum makes
  838. with the vertical. We therefore need to draw the body diagram in
  839. a function where the angle is a parameter. We also supply arrays
  840. containing the (numerically computed) values of the angle <span class="math">\(\theta\)</span> and
  841. the forces at various time levels, plus the desired time point and level
  842. for this particular sketch:</p>
  843. <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>
  844. <span class="n">H</span> <span class="o">=</span> <span class="mf">15.</span>
  845. <span class="n">W</span> <span class="o">=</span> <span class="mf">17.</span>
  846. <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</span><span class="p">,</span>
  847. <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="n">H</span><span class="p">,</span>
  848. <span class="n">axis</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
  849. <span class="k">def</span> <span class="nf">pendulum</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">mg</span><span class="p">,</span> <span class="n">drag</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">time_level</span><span class="p">):</span>
  850. <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>
  851. <span class="kn">import</span> <span class="nn">math</span>
  852. <span class="n">a</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">theta</span><span class="p">[</span><span class="n">time_level</span><span class="p">])</span>
  853. <span class="n">L</span> <span class="o">=</span> <span class="mf">0.4</span><span class="o">*</span><span class="n">H</span> <span class="c"># length</span>
  854. <span class="n">P</span> <span class="o">=</span> <span class="p">(</span><span class="n">W</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="mf">0.8</span><span class="o">*</span><span class="n">H</span><span class="p">)</span> <span class="c"># rotation point</span>
  855. <span class="n">vertical</span> <span class="o">=</span> <span class="n">Line</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">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">L</span><span class="p">))</span>
  856. <span class="n">path</span> <span class="o">=</span> <span class="n">Arc</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="o">-</span><span class="mi">90</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span>
  857. <span class="n">angle</span> <span class="o">=</span> <span class="n">Arc_wText</span><span class="p">(</span><span class="s">r&#39;$\theta$&#39;</span><span class="p">,</span> <span class="n">P</span><span class="p">,</span> <span class="n">L</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="o">-</span><span class="mi">90</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">text_spacing</span><span class="o">=</span><span class="mi">1</span><span class="o">/</span><span class="mf">30.</span><span class="p">)</span>
  858. <span class="n">mass_pt</span> <span class="o">=</span> <span class="n">path</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>
  859. <span class="n">rod</span> <span class="o">=</span> <span class="n">Line</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">mass_pt</span><span class="p">)</span>
  860. <span class="n">mass</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="n">mass_pt</span><span class="p">,</span> <span class="n">radius</span><span class="o">=</span><span class="n">L</span><span class="o">/</span><span class="mf">20.</span><span class="p">)</span>
  861. <span class="n">mass</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>
  862. <span class="n">rod_vec</span> <span class="o">=</span> <span class="n">rod</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> \
  863. <span class="n">rod</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">&#39;start&#39;</span><span class="p">]</span>
  864. <span class="n">unit_rod_vec</span> <span class="o">=</span> <span class="n">unit_vec</span><span class="p">(</span><span class="n">rod_vec</span><span class="p">)</span>
  865. <span class="n">mass_symbol</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">&#39;$m$&#39;</span><span class="p">,</span> <span class="n">mass_pt</span> <span class="o">+</span> <span class="n">L</span><span class="o">/</span><span class="mi">10</span><span class="o">*</span><span class="n">unit_rod_vec</span><span class="p">)</span>
  866. <span class="n">length</span> <span class="o">=</span> <span class="n">Distance_wText</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">mass_pt</span><span class="p">,</span> <span class="s">&#39;$L$&#39;</span><span class="p">)</span>
  867. <span class="c"># Displace length indication</span>
  868. <span class="n">length</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">L</span><span class="o">/</span><span class="mi">15</span><span class="o">*</span><span class="n">point</span><span class="p">(</span><span class="n">cos</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">)),</span> <span class="n">sin</span><span class="p">(</span><span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">))))</span>
  869. <span class="n">gravity</span> <span class="o">=</span> <span class="n">Gravity</span><span class="p">(</span><span class="n">start</span><span class="o">=</span><span class="n">P</span><span class="o">+</span><span class="n">point</span><span class="p">(</span><span class="mf">0.8</span><span class="o">*</span><span class="n">L</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="o">/</span><span class="mi">3</span><span class="p">)</span>
  870. <span class="k">def</span> <span class="nf">set_dashed_thin_blackline</span><span class="p">(</span><span class="o">*</span><span class="n">objects</span><span class="p">):</span>
  871. <span class="sd">&quot;&quot;&quot;Set linestyle of objects to dashed, black, width=1.&quot;&quot;&quot;</span>
  872. <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
  873. <span class="n">obj</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>
  874. <span class="n">obj</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>
  875. <span class="n">obj</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  876. <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">vertical</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
  877. <span class="n">fig</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
  878. <span class="p">{</span><span class="s">&#39;body&#39;</span><span class="p">:</span> <span class="n">mass</span><span class="p">,</span> <span class="s">&#39;rod&#39;</span><span class="p">:</span> <span class="n">rod</span><span class="p">,</span>
  879. <span class="s">&#39;vertical&#39;</span><span class="p">:</span> <span class="n">vertical</span><span class="p">,</span> <span class="s">&#39;theta&#39;</span><span class="p">:</span> <span class="n">angle</span><span class="p">,</span> <span class="s">&#39;path&#39;</span><span class="p">:</span> <span class="n">path</span><span class="p">,</span>
  880. <span class="s">&#39;g&#39;</span><span class="p">:</span> <span class="n">gravity</span><span class="p">,</span> <span class="s">&#39;L&#39;</span><span class="p">:</span> <span class="n">length</span><span class="p">})</span>
  881. <span class="c">#fig.draw()</span>
  882. <span class="c">#drawing_tool.display()</span>
  883. <span class="c">#drawing_tool.savefig(&#39;tmp_pendulum1&#39;)</span>
  884. <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>
  885. <span class="n">rod_start</span> <span class="o">=</span> <span class="n">rod</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">&#39;start&#39;</span><span class="p">]</span> <span class="c"># Point P</span>
  886. <span class="n">vertical2</span> <span class="o">=</span> <span class="n">Line</span><span class="p">(</span><span class="n">rod_start</span><span class="p">,</span> <span class="n">rod_start</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="o">-</span><span class="n">L</span><span class="o">/</span><span class="mi">3</span><span class="p">))</span>
  887. <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">vertical2</span><span class="p">)</span>
  888. <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">rod</span><span class="p">)</span>
  889. <span class="n">angle2</span> <span class="o">=</span> <span class="n">Arc_wText</span><span class="p">(</span><span class="s">r&#39;$\theta$&#39;</span><span class="p">,</span> <span class="n">rod_start</span><span class="p">,</span> <span class="n">L</span><span class="o">/</span><span class="mi">6</span><span class="p">,</span> <span class="o">-</span><span class="mi">90</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span>
  890. <span class="n">text_spacing</span><span class="o">=</span><span class="mi">1</span><span class="o">/</span><span class="mf">30.</span><span class="p">)</span>
  891. <span class="n">magnitude</span> <span class="o">=</span> <span class="mf">1.2</span><span class="o">*</span><span class="n">L</span><span class="o">/</span><span class="mi">2</span> <span class="c"># length of a unit force in figure</span>
  892. <span class="n">force</span> <span class="o">=</span> <span class="n">mg</span><span class="p">[</span><span class="n">time_level</span><span class="p">]</span> <span class="c"># constant (scaled eq: about 1)</span>
  893. <span class="n">force</span> <span class="o">*=</span> <span class="n">magnitude</span>
  894. <span class="n">mg_force</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">mass_pt</span><span class="p">,</span> <span class="n">mass_pt</span> <span class="o">+</span> <span class="n">force</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="o">-</span><span class="mi">1</span><span class="p">),</span>
  895. <span class="s">&#39;&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">)</span>
  896. <span class="n">force</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="n">time_level</span><span class="p">]</span>
  897. <span class="n">force</span> <span class="o">*=</span> <span class="n">magnitude</span>
  898. <span class="n">rod_force</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">mass_pt</span><span class="p">,</span> <span class="n">mass_pt</span> <span class="o">-</span> <span class="n">force</span><span class="o">*</span><span class="n">unit_vec</span><span class="p">(</span><span class="n">rod_vec</span><span class="p">),</span>
  899. <span class="s">&#39;&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  900. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.03</span><span class="p">,</span> <span class="mf">0.01</span><span class="p">))</span>
  901. <span class="n">force</span> <span class="o">=</span> <span class="n">drag</span><span class="p">[</span><span class="n">time_level</span><span class="p">]</span>
  902. <span class="n">force</span> <span class="o">*=</span> <span class="n">magnitude</span>
  903. <span class="c">#print(&#39;drag(%g)=%g&#39; % (t, drag[time_level]))</span>
  904. <span class="n">air_force</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">mass_pt</span><span class="p">,</span> <span class="n">mass_pt</span> <span class="o">-</span>
  905. <span class="n">force</span><span class="o">*</span><span class="n">unit_vec</span><span class="p">((</span><span class="n">rod_vec</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">-</span><span class="n">rod_vec</span><span class="p">[</span><span class="mi">0</span><span class="p">])),</span>
  906. <span class="s">&#39;&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  907. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.04</span><span class="p">,</span><span class="mf">0.005</span><span class="p">))</span>
  908. <span class="n">body_diagram</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
  909. <span class="p">{</span><span class="s">&#39;mg&#39;</span><span class="p">:</span> <span class="n">mg_force</span><span class="p">,</span> <span class="s">&#39;S&#39;</span><span class="p">:</span> <span class="n">rod_force</span><span class="p">,</span> <span class="s">&#39;air&#39;</span><span class="p">:</span> <span class="n">air_force</span><span class="p">,</span>
  910. <span class="s">&#39;rod&#39;</span><span class="p">:</span> <span class="n">rod</span><span class="p">,</span>
  911. <span class="s">&#39;vertical&#39;</span><span class="p">:</span> <span class="n">vertical2</span><span class="p">,</span> <span class="s">&#39;theta&#39;</span><span class="p">:</span> <span class="n">angle2</span><span class="p">,</span>
  912. <span class="s">&#39;body&#39;</span><span class="p">:</span> <span class="n">mass</span><span class="p">})</span>
  913. <span class="n">x0y0</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">&#39;$(x_0,y_0)$&#39;</span><span class="p">,</span> <span class="n">P</span> <span class="o">+</span> <span class="n">point</span><span class="p">(</span><span class="o">-</span><span class="mf">0.4</span><span class="p">,</span><span class="o">-</span><span class="mf">0.1</span><span class="p">))</span>
  914. <span class="n">ir</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">P</span> <span class="o">+</span> <span class="n">L</span><span class="o">/</span><span class="mi">10</span><span class="o">*</span><span class="n">unit_vec</span><span class="p">(</span><span class="n">rod_vec</span><span class="p">),</span>
  915. <span class="s">r&#39;$\boldsymbol{i}_r$&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  916. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.015</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
  917. <span class="n">ith</span> <span class="o">=</span> <span class="n">Force</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">P</span> <span class="o">+</span> <span class="n">L</span><span class="o">/</span><span class="mi">10</span><span class="o">*</span><span class="n">unit_vec</span><span class="p">((</span><span class="o">-</span><span class="n">rod_vec</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">rod_vec</span><span class="p">[</span><span class="mi">0</span><span class="p">])),</span>
  918. <span class="s">r&#39;$\boldsymbol{i}_{\theta}$&#39;</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">&#39;end&#39;</span><span class="p">,</span>
  919. <span class="n">text_spacing</span><span class="o">=</span><span class="p">(</span><span class="mf">0.02</span><span class="p">,</span><span class="mf">0.005</span><span class="p">))</span>
  920. <span class="c">#body_diagram[&#39;ir&#39;] = ir</span>
  921. <span class="c">#body_diagram[&#39;ith&#39;] = ith</span>
  922. <span class="c">#body_diagram[&#39;origin&#39;] = x0y0</span>
  923. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">erase</span><span class="p">()</span>
  924. <span class="n">body_diagram</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">verbose</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
  925. <span class="c">#drawing_tool.display(&#39;Body diagram&#39;)</span>
  926. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">&#39;tmp_</span><span class="si">%04d</span><span class="s">.png&#39;</span> <span class="o">%</span> <span class="n">time_level</span><span class="p">,</span> <span class="n">crop</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
  927. <span class="c"># No cropping: otherwise movies will be very strange</span>
  928. </pre></div>
  929. </div>
  930. </div>
  931. <div class="section" id="equations-for-the-motion-and-forces">
  932. <h4>Equations for the motion and forces<a class="headerlink" href="#equations-for-the-motion-and-forces" title="Permalink to this headline">¶</a></h4>
  933. <p>The modeling of the motion of a pendulum is most conveniently done in
  934. polar coordinates since then the unknown force in the rod is separated
  935. from the equation determining the motion <span class="math">\(\theta(t)\)</span>.
  936. The position vector for the mass is</p>
  937. <div class="math">
  938. \[\boldsymbol{r} = x_0\boldsymbol{i} + y_0\boldsymbol{j} + L{\boldsymbol{i}_r}{\thinspace .}\]</div>
  939. <p>The corresponding acceleration becomes</p>
  940. <div class="math">
  941. \[\ddot{\boldsymbol{r}} = L\ddot{\theta}{\boldsymbol{i}_{\theta}} - L\dot{\theta^2}{{\boldsymbol{i}_r}}{\thinspace .}\]</div>
  942. <p>There are three forces on the mass: the gravity force
  943. <span class="math">\(mg\boldsymbol{j} = mg(-\cos\theta\,{\boldsymbol{i}_r} + \sin\theta\,\boldsymbol{i}_{\theta})\)</span>, the force in the rod
  944. <span class="math">\(-S{\boldsymbol{i}_r}\)</span>, and the drag force because of air resistance:</p>
  945. <div class="math">
  946. \[-\frac{1}{2} C_D \varrho \pi R^2 |v|v\,\boldsymbol{i}_{\theta},\]</div>
  947. <p>where <span class="math">\(C_D\approx 0.4\)</span> is the drag coefficient for a sphere, <span class="math">\(\varrho\)</span>
  948. is the density of air, <span class="math">\(R\)</span> is the radius of the mass, and <span class="math">\(v\)</span> is the
  949. velocity (<span class="math">\(v=L\dot\theta\)</span>). The drag force acts in <span class="math">\(-\boldsymbol{i}_{\theta}\)</span> direction
  950. when <span class="math">\(v&gt;0\)</span>.</p>
  951. <p>Newton&#8217;s second law of motion for the pendulum now becomes</p>
  952. <div class="math">
  953. \[mL\ddot\theta\boldsymbol{i}_{\theta} - mL\dot\theta^2{\boldsymbol{i}_r} = -mg(-\cos\theta\,{\boldsymbol{i}_r} +
  954. \sin\theta\,\boldsymbol{i}_{\theta})
  955. -S{\boldsymbol{i}_r} - \frac{1}{2} C_D \varrho \pi R^2 L^2|\dot\theta|\dot\theta\boldsymbol{i}_{\theta},\]</div>
  956. <p>which gives two component equations</p>
  957. <div class="math" id="equation-sketcher:ex:pendulum:anim:eq:ith">
  958. <span class="eqno">(1)</span>\[ mL\ddot\theta + \frac{1}{2} C_D \varrho \pi R^2 L^2|\dot\theta|\dot\theta +
  959. mg\sin\theta = 0,\]</div>
  960. <div class="math" id="equation-sketcher:ex:pendulum:anim:eq:ir">
  961. <span class="eqno">(2)</span>\[ S = mL\dot\theta^2 + mg\cos\theta
  962. {\thinspace .}\]</div>
  963. <p>It is almost always convenient to scale such equations. Introducing
  964. the dimensionless time</p>
  965. <div class="math">
  966. \[\bar t = \frac{t}{t_c},\quad t_c = \sqrt{\frac{L}{g}},\]</div>
  967. <p>leads to</p>
  968. <div class="math" id="equation-sketcher:ex:pendulum:anim:eq:ith:s">
  969. <span class="eqno">(3)</span>\[ \frac{d^2\theta}{d\bar t^2} +
  970. \alpha\left\vert\frac{d\theta}{d\bar t}\right\vert\frac{d\theta}{d\bar t} +
  971. \sin\theta = 0,\]</div>
  972. <div class="math" id="equation-sketcher:ex:pendulum:anim:eq:ir:s">
  973. <span class="eqno">(4)</span>\[ \bar S = \left(\frac{d\theta}{d\bar t}\right)^2
  974. + \cos\theta,\]</div>
  975. <p>where <span class="math">\(\alpha\)</span> is a dimensionless drag coefficient</p>
  976. <div class="math">
  977. \[\alpha = \frac{C_D\varrho\pi R^2L}{2m},\]</div>
  978. <p>and <span class="math">\(\bar S\)</span> is the scaled force</p>
  979. <div class="math">
  980. \[\bar S = \frac{S}{mg}{\thinspace .}\]</div>
  981. <p>We see that <span class="math">\(\bar S = 1\)</span> for the equilibrium position <span class="math">\(\theta=0\)</span>, so this
  982. scaling of <span class="math">\(S\)</span> seems appropriate.</p>
  983. <p>The parameter <span class="math">\(\alpha\)</span> is about
  984. the ratio of the drag force and the gravity force:</p>
  985. <div class="math">
  986. \[\frac{|\frac{1}{2} C_D\varrho \pi R^2 |v|v|}{|mg|}\sim
  987. \frac{C_D\varrho \pi R^2 L^2 t_c^{-2}}{mg}
  988. \left|\frac{d\bar\theta}{d\bar t}\right|\frac{d\bar\theta}{d\bar t}
  989. \sim \frac{C_D\varrho \pi R^2 L}{2m}\theta_0^2 = \alpha \theta_0^2{\thinspace .}\]</div>
  990. <p>(We have that <span class="math">\(\theta(t)/d\theta_0\)</span> is in <span class="math">\([-1,1]\)</span>, so we expect
  991. since <span class="math">\(\theta_0^{-1}d\bar\theta/d\bar t\)</span> to be around unity. Here,
  992. <span class="math">\(\theta_0=\theta(0)\)</span>.)</p>
  993. <p>The next step is to write a numerical solver for
  994. <a href="#equation-sketcher:ex:pendulum:anim:eq:ith:s">(3)</a>-<a href="#equation-sketcher:ex:pendulum:anim:eq:ir:s">(4)</a>. To
  995. this end, we use the <a class="reference external" href="https://github.com/hplgit/odespy">Odespy</a>
  996. package. The system of second-order ODEs must be expressed as a system
  997. of first-order ODEs. We realize that the unknown <span class="math">\(\bar S\)</span> is decoupled
  998. from <span class="math">\(\theta\)</span> in the sense that we can first use
  999. <a href="#equation-sketcher:ex:pendulum:anim:eq:ith:s">(3)</a> to solve for <span class="math">\(\theta\)</span> and
  1000. then compute <span class="math">\(\bar S\)</span> from <a href="#equation-sketcher:ex:pendulum:anim:eq:ir:s">(4)</a>.
  1001. The first-order ODEs become</p>
  1002. <div class="math" id="equation-_auto1">
  1003. <span class="eqno">(5)</span>\[ \frac{d\omega}{d\bar t} = -\alpha\left\vert\omega\right\vert\omega
  1004. - \sin\theta,\]</div>
  1005. <div class="math" id="equation-_auto2">
  1006. <span class="eqno">(6)</span>\[ \frac{d\theta}{d\bar t} = \omega{\thinspace .}\]</div>
  1007. <p>Then we compute</p>
  1008. <div class="math" id="equation-_auto3">
  1009. <span class="eqno">(7)</span>\[ \bar S = \omega^2 + \cos\theta{\thinspace .}\]</div>
  1010. <p>The dimensionless air resistance force can also be computed:</p>
  1011. <div class="math" id="equation-_auto4">
  1012. <span class="eqno">(8)</span>\[ -\alpha|\omega|\omega{\thinspace .}\]</div>
  1013. <p>Since we scaled the force <span class="math">\(S\)</span> by <span class="math">\(mg\)</span>, <span class="math">\(mg\)</span> is the natural force scale,
  1014. and the <span class="math">\(mg\)</span> force itself is then unity.</p>
  1015. <p>By updating <span class="math">\(\omega\)</span> in the first equation, we can use an Euler-Cromer
  1016. scheme on Odespy (all other schemes are independent of whether the
  1017. <span class="math">\(\theta\)</span> or <span class="math">\(\omega\)</span> equation comes first).</p>
  1018. </div>
  1019. <div class="section" id="numerical-solution">
  1020. <h4>Numerical solution<a class="headerlink" href="#numerical-solution" title="Permalink to this headline">¶</a></h4>
  1021. <p>An appropriate solver is</p>
  1022. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">simulate_pendulum</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">theta0</span><span class="p">,</span> <span class="n">dt</span><span class="p">,</span> <span class="n">T</span><span class="p">):</span>
  1023. <span class="kn">import</span> <span class="nn">odespy</span>
  1024. <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">alpha</span><span class="p">):</span>
  1025. <span class="n">omega</span><span class="p">,</span> <span class="n">theta</span> <span class="o">=</span> <span class="n">u</span>
  1026. <span class="k">return</span> <span class="p">[</span><span class="o">-</span><span class="n">alpha</span><span class="o">*</span><span class="n">omega</span><span class="o">*</span><span class="nb">abs</span><span class="p">(</span><span class="n">omega</span><span class="p">)</span> <span class="o">-</span> <span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span>
  1027. <span class="n">omega</span><span class="p">]</span>
  1028. <span class="kn">import</span> <span class="nn">numpy</span> <span class="kn">as</span> <span class="nn">np</span>
  1029. <span class="n">Nt</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">round</span><span class="p">(</span><span class="n">T</span><span class="o">/</span><span class="nb">float</span><span class="p">(</span><span class="n">dt</span><span class="p">)))</span>
  1030. <span class="n">t</span> <span class="o">=</span> <span class="n">np</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="n">Nt</span><span class="o">*</span><span class="n">dt</span><span class="p">,</span> <span class="n">Nt</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
  1031. <span class="n">solver</span> <span class="o">=</span> <span class="n">odespy</span><span class="o">.</span><span class="n">RK4</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">f_args</span><span class="o">=</span><span class="p">[</span><span class="n">alpha</span><span class="p">])</span>
  1032. <span class="n">solver</span><span class="o">.</span><span class="n">set_initial_condition</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">theta0</span><span class="p">])</span>
  1033. <span class="n">u</span><span class="p">,</span> <span class="n">t</span> <span class="o">=</span> <span class="n">solver</span><span class="o">.</span><span class="n">solve</span><span class="p">(</span><span class="n">t</span><span class="p">,</span>
  1034. <span class="n">terminate</span><span class="o">=</span><span class="k">lambda</span> <span class="n">u</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="nb">abs</span><span class="p">(</span><span class="n">u</span><span class="p">[</span><span class="n">n</span><span class="p">,</span><span class="mi">1</span><span class="p">])</span> <span class="o">&lt;</span> <span class="mf">1E-3</span><span class="p">)</span>
  1035. <span class="n">omega</span> <span class="o">=</span> <span class="n">u</span><span class="p">[:,</span><span class="mi">0</span><span class="p">]</span>
  1036. <span class="n">theta</span> <span class="o">=</span> <span class="n">u</span><span class="p">[:,</span><span class="mi">1</span><span class="p">]</span>
  1037. <span class="n">S</span> <span class="o">=</span> <span class="n">omega</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span>
  1038. <span class="n">drag</span> <span class="o">=</span> <span class="o">-</span><span class="n">alpha</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">abs</span><span class="p">(</span><span class="n">omega</span><span class="p">)</span><span class="o">*</span><span class="n">omega</span>
  1039. <span class="k">return</span> <span class="n">t</span><span class="p">,</span> <span class="n">theta</span><span class="p">,</span> <span class="n">omega</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">drag</span>
  1040. </pre></div>
  1041. </div>
  1042. </div>
  1043. <div class="section" id="animation">
  1044. <h4>Animation<a class="headerlink" href="#animation" title="Permalink to this headline">¶</a></h4>
  1045. <p>We can finally traverse the time array and draw a body diagram
  1046. at each time level. The resulting sketches are saved to files
  1047. <code class="docutils literal"><span class="pre">tmp_%04d.png</span></code>, and these files can be combined to videos:</p>
  1048. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">animate</span><span class="p">():</span>
  1049. <span class="c"># Clean up old plot files</span>
  1050. <span class="kn">import</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">glob</span>
  1051. <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;tmp_*.png&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;movie.*&#39;</span><span class="p">):</span>
  1052. <span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
  1053. <span class="c"># Solve problem</span>
  1054. <span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">pi</span><span class="p">,</span> <span class="n">radians</span><span class="p">,</span> <span class="n">degrees</span>
  1055. <span class="kn">import</span> <span class="nn">numpy</span> <span class="kn">as</span> <span class="nn">np</span>
  1056. <span class="n">alpha</span> <span class="o">=</span> <span class="mf">0.4</span>
  1057. <span class="n">period</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">pi</span>
  1058. <span class="n">T</span> <span class="o">=</span> <span class="mi">12</span><span class="o">*</span><span class="n">period</span>
  1059. <span class="n">dt</span> <span class="o">=</span> <span class="n">period</span><span class="o">/</span><span class="mi">40</span>
  1060. <span class="n">a</span> <span class="o">=</span> <span class="mi">70</span>
  1061. <span class="n">theta0</span> <span class="o">=</span> <span class="n">radians</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
  1062. <span class="n">t</span><span class="p">,</span> <span class="n">theta</span><span class="p">,</span> <span class="n">omega</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">drag</span> <span class="o">=</span> <span class="n">simulate_pendulum</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">theta0</span><span class="p">,</span> <span class="n">dt</span><span class="p">,</span> <span class="n">T</span><span class="p">)</span>
  1063. <span class="n">mg</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">ones</span><span class="p">(</span><span class="n">S</span><span class="o">.</span><span class="n">size</span><span class="p">)</span>
  1064. <span class="c"># Visualize drag force 5 times as large</span>
  1065. <span class="n">drag</span> <span class="o">*=</span> <span class="mi">5</span>
  1066. <span class="k">print</span><span class="p">(</span><span class="s">&#39;NOTE: drag force magnified 5 times!!&#39;</span><span class="p">)</span>
  1067. <span class="c"># Draw animation</span>
  1068. <span class="kn">import</span> <span class="nn">time</span>
  1069. <span class="k">for</span> <span class="n">time_level</span><span class="p">,</span> <span class="n">t_</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
  1070. <span class="n">pendulum</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">mg</span><span class="p">,</span> <span class="n">drag</span><span class="p">,</span> <span class="n">t_</span><span class="p">,</span> <span class="n">time_level</span><span class="p">)</span>
  1071. <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span>
  1072. <span class="c"># Make videos</span>
  1073. <span class="n">prog</span> <span class="o">=</span> <span class="s">&#39;ffmpeg&#39;</span>
  1074. <span class="n">filename</span> <span class="o">=</span> <span class="s">&#39;tmp_</span><span class="si">%04d</span><span class="s">.png&#39;</span>
  1075. <span class="n">fps</span> <span class="o">=</span> <span class="mi">6</span>
  1076. <span class="n">codecs</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;flv&#39;</span><span class="p">:</span> <span class="s">&#39;flv&#39;</span><span class="p">,</span> <span class="s">&#39;mp4&#39;</span><span class="p">:</span> <span class="s">&#39;libx264&#39;</span><span class="p">,</span>
  1077. <span class="s">&#39;webm&#39;</span><span class="p">:</span> <span class="s">&#39;libvpx&#39;</span><span class="p">,</span> <span class="s">&#39;ogg&#39;</span><span class="p">:</span> <span class="s">&#39;libtheora&#39;</span><span class="p">}</span>
  1078. <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="n">codecs</span><span class="p">:</span>
  1079. <span class="n">lib</span> <span class="o">=</span> <span class="n">codecs</span><span class="p">[</span><span class="n">ext</span><span class="p">]</span>
  1080. <span class="n">cmd</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%(prog)s</span><span class="s"> -i </span><span class="si">%(filename)s</span><span class="s"> -r </span><span class="si">%(fps)s</span><span class="s"> &#39;</span> <span class="o">%</span> <span class="nb">vars</span><span class="p">()</span>
  1081. <span class="n">cmd</span> <span class="o">+=</span> <span class="s">&#39;-vcodec </span><span class="si">%(lib)s</span><span class="s"> movie.</span><span class="si">%(ext)s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="nb">vars</span><span class="p">()</span>
  1082. <span class="k">print</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
  1083. <span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
  1084. </pre></div>
  1085. </div>
  1086. <p>This time we did not use the <code class="docutils literal"><span class="pre">animate</span></code> function from Pysketcher, but
  1087. stored each sketch in a file with <code class="docutils literal"><span class="pre">drawing_tool.savefig</span></code>. Note that
  1088. the argument <code class="docutils literal"><span class="pre">crop=False</span></code> is key: otherwise each figure is cropped and
  1089. it makes to sense to combine the images to a video. By default,
  1090. Pysketcher crops (removes all exterior whitespace) from figures saved
  1091. to file.</p>
  1092. <div>
  1093. <video loop controls width='640' height='365' preload='none'>
  1094. <source src='https://github.com/hplgit/pysketcher/raw/master/doc/pub/tutorial/mov-tut/pendulum/movie.mp4' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
  1095. <source src='https://github.com/hplgit/pysketcher/raw/master/doc/pub/tutorial/mov-tut/pendulum/movie.webm' type='video/webm; codecs="vp8, vorbis"'>
  1096. <source src='https://github.com/hplgit/pysketcher/raw/master/doc/pub/tutorial/mov-tut/pendulum/movie.ogg' type='video/ogg; codecs="theora, vorbis"'>
  1097. </video>
  1098. </div>
  1099. <p><em>The drag force is magnified 5 times (compared to \( mg \) and \( S \) !</em></p>
  1100. <!-- Issue warning if in a Safari browser -->
  1101. <script language="javascript">
  1102. if (!!(window.safari)) {
  1103. document.write("<div style=\"width: 95%%; padding: 10px; border: 1px solid #100; border-radius: 4px;\"><p><font color=\"red\">The above movie will not play in Safari - use Chrome, Firefox, or Opera.</font></p></div>")}
  1104. </script></div>
  1105. </div>
  1106. </div>
  1107. <div class="section" id="basic-shapes">
  1108. <h2>Basic shapes<a class="headerlink" href="#basic-shapes" title="Permalink to this headline">¶</a></h2>
  1109. <p>This section presents many of the basic shapes in Pysketcher:
  1110. <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>,
  1111. <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>.
  1112. Each shape is demonstrated with a figure and a
  1113. unit test that shows how the figure is constructed in Python code.
  1114. These demos rely heavily on the method <code class="docutils literal"><span class="pre">draw_dimensions</span></code> in
  1115. the shape classes, which annotates the basic drawing of the shape
  1116. with the various geometric parameters that govern the shape.</p>
  1117. <div class="section" id="axis">
  1118. <h3>Axis<a class="headerlink" href="#axis" title="Permalink to this headline">¶</a></h3>
  1119. <p>The <code class="docutils literal"><span class="pre">Axis</span></code> object gives the possibility draw a single axis to
  1120. notify a coordinate system. Here is an example where we
  1121. draw <span class="math">\(x\)</span> and <span class="math">\(y\)</span> axis of three coordinate systems of different
  1122. rotation:</p>
  1123. <div class="line-block">
  1124. <div class="line"><br /></div>
  1125. <div class="line"><br /></div>
  1126. </div>
  1127. <div class="figure">
  1128. <a class="reference internal image-reference" href="_images/Axis.png"><img alt="_images/Axis.png" src="_images/Axis.png" style="width: 500px;" /></a>
  1129. </div>
  1130. <div class="line-block">
  1131. <div class="line"><br /></div>
  1132. <div class="line"><br /></div>
  1133. </div>
  1134. <p>The corresponding code looks like this:</p>
  1135. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Axis</span><span class="p">():</span>
  1136. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  1137. <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>
  1138. <span class="n">instruction_file</span><span class="o">=</span><span class="s">&#39;tmp_Axis.py&#39;</span><span class="p">)</span>
  1139. <span class="c"># Draw normal x and y axis with origin at (7.5, 2)</span>
  1140. <span class="c"># in the coordinate system of the sketch: [0,15]x[-7,8]</span>
  1141. <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>
  1142. <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>
  1143. <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>
  1144. <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1145. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  1146. <span class="c"># Rotate this system 40 degrees counter clockwise</span>
  1147. <span class="c"># and draw it with dashed lines</span>
  1148. <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>
  1149. <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>
  1150. <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1151. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  1152. <span class="c"># Rotate this system another 220 degrees and show</span>
  1153. <span class="c"># with dotted lines</span>
  1154. <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>
  1155. <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>
  1156. <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1157. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  1158. <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>
  1159. </pre></div>
  1160. </div>
  1161. </div>
  1162. <div class="section" id="distance-with-text">
  1163. <h3>Distance with text<a class="headerlink" href="#distance-with-text" title="Permalink to this headline">¶</a></h3>
  1164. <p>The object <code class="docutils literal"><span class="pre">Distance_wText</span></code> is used to display an arrow, to indicate
  1165. a distance in a sketch, with an additional text in the middle of the arrow.</p>
  1166. <p>The figure</p>
  1167. <div class="line-block">
  1168. <div class="line"><br /></div>
  1169. <div class="line"><br /></div>
  1170. </div>
  1171. <div class="figure">
  1172. <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>
  1173. </div>
  1174. <div class="line-block">
  1175. <div class="line"><br /></div>
  1176. <div class="line"><br /></div>
  1177. </div>
  1178. <p>was produced by this code:</p>
  1179. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Distance_wText</span><span class="p">():</span>
  1180. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  1181. <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>
  1182. <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>
  1183. <span class="n">fontsize</span><span class="o">=</span><span class="mi">14</span>
  1184. <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>
  1185. <span class="n">examples</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span>
  1186. <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>
  1187. <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>
  1188. <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>
  1189. <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>
  1190. <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>
  1191. <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>
  1192. <span class="n">text_spacing</span><span class="o">=-</span><span class="mf">1.</span><span class="o">/</span><span class="mi">60</span><span class="p">),</span>
  1193. <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>
  1194. <span class="n">text_spacing</span><span class="o">=-</span><span class="mf">1.</span><span class="o">/</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>
  1195. <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>
  1196. <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>
  1197. <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>
  1198. <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>
  1199. <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>
  1200. <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>
  1201. <span class="p">})</span>
  1202. <span class="n">examples</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1203. <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>
  1204. </pre></div>
  1205. </div>
  1206. <p>Note the use of <code class="docutils literal"><span class="pre">Text_wArrow</span></code> to write an explaining text with an
  1207. associated arrow, here used to explain how
  1208. 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
  1209. the appearance of the text that goes with the distance arrow.</p>
  1210. </div>
  1211. <div class="section" id="rectangle">
  1212. <h3>Rectangle<a class="headerlink" href="#rectangle" title="Permalink to this headline">¶</a></h3>
  1213. <div class="figure">
  1214. <a class="reference internal image-reference" href="_images/Rectangle.png"><img alt="_images/Rectangle.png" src="_images/Rectangle.png" style="width: 500px;" /></a>
  1215. </div>
  1216. <div class="line-block">
  1217. <div class="line"><br /></div>
  1218. <div class="line"><br /></div>
  1219. </div>
  1220. <p>The above figure can be produced by the following code.</p>
  1221. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Rectangle</span><span class="p">():</span>
  1222. <span class="n">L</span> <span class="o">=</span> <span class="mf">3.0</span>
  1223. <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
  1224. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  1225. <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">L</span><span class="o">/</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>
  1226. <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>
  1227. <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>
  1228. <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>
  1229. <span class="n">xpos</span> <span class="o">=</span> <span class="n">W</span><span class="o">/</span><span class="mi">2</span>
  1230. <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>
  1231. <span class="n">r</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1232. <span class="n">r</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  1233. <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>
  1234. </pre></div>
  1235. </div>
  1236. <p>Note that the <code class="docutils literal"><span class="pre">draw_dimension</span></code> method adds explanation of dimensions and various
  1237. important argument in the construction of a shape. It adapts the annotations
  1238. to the geometry of the current shape.</p>
  1239. </div>
  1240. <div class="section" id="triangle">
  1241. <h3>Triangle<a class="headerlink" href="#triangle" title="Permalink to this headline">¶</a></h3>
  1242. <div class="figure">
  1243. <a class="reference internal image-reference" href="_images/Triangle.png"><img alt="_images/Triangle.png" src="_images/Triangle.png" style="width: 500px;" /></a>
  1244. </div>
  1245. <div class="line-block">
  1246. <div class="line"><br /></div>
  1247. <div class="line"><br /></div>
  1248. </div>
  1249. <p>The code below produces the figure.</p>
  1250. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Triangle</span><span class="p">():</span>
  1251. <span class="n">L</span> <span class="o">=</span> <span class="mf">3.0</span>
  1252. <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
  1253. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  1254. <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">L</span><span class="o">/</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>
  1255. <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>
  1256. <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>
  1257. <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>
  1258. <span class="n">xpos</span> <span class="o">=</span> <span class="mi">1</span>
  1259. <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">W</span><span class="o">/</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">W</span><span class="o">/</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>
  1260. <span class="n">t</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1261. <span class="n">t</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  1262. <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>
  1263. </pre></div>
  1264. </div>
  1265. <p>Here, the <code class="docutils literal"><span class="pre">draw_dimension</span></code> method writes the name of the corners at the
  1266. position of the corners, which does not always look nice (the present figure
  1267. is an example). For a high-quality sketch one would add some spacing
  1268. to the location of the p1, p2, and even p3 texts.</p>
  1269. </div>
  1270. <div class="section" id="arc">
  1271. <h3>Arc<a class="headerlink" href="#arc" title="Permalink to this headline">¶</a></h3>
  1272. <div class="figure">
  1273. <a class="reference internal image-reference" href="_images/Arc.png"><img alt="_images/Arc.png" src="_images/Arc.png" style="width: 400px;" /></a>
  1274. </div>
  1275. <div class="line-block">
  1276. <div class="line"><br /></div>
  1277. <div class="line"><br /></div>
  1278. </div>
  1279. <p>An arc like the one above is produced by</p>
  1280. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Arc</span><span class="p">():</span>
  1281. <span class="n">L</span> <span class="o">=</span> <span class="mf">4.0</span>
  1282. <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
  1283. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  1284. <span class="n">xmin</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">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">L</span><span class="o">/</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>
  1285. <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>
  1286. <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>
  1287. <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>
  1288. <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>
  1289. <span class="n">radius</span> <span class="o">=</span> <span class="n">L</span><span class="o">/</span><span class="mi">2</span>
  1290. <span class="n">start_angle</span> <span class="o">=</span> <span class="mi">60</span>
  1291. <span class="n">arc_angle</span> <span class="o">=</span> <span class="mi">45</span>
  1292. <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>
  1293. <span class="n">a</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1294. <span class="n">R1</span> <span class="o">=</span> <span class="mf">1.25</span><span class="o">*</span><span class="n">radius</span>
  1295. <span class="n">R2</span> <span class="o">=</span> <span class="mf">1.5</span><span class="o">*</span><span class="n">radius</span>
  1296. <span class="n">R</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">radius</span>
  1297. <span class="n">a</span><span class="o">.</span><span class="n">dimensions</span> <span class="o">=</span> <span class="p">{</span>
  1298. <span class="s">&#39;start_angle&#39;</span><span class="p">:</span>
  1299. <span class="n">Arc_wText</span><span class="p">(</span>
  1300. <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>
  1301. <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="mi">1</span><span class="o">/</span><span class="mf">10.</span><span class="p">),</span>
  1302. <span class="s">&#39;arc_angle&#39;</span><span class="p">:</span>
  1303. <span class="n">Arc_wText</span><span class="p">(</span>
  1304. <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>
  1305. <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="mi">1</span><span class="o">/</span><span class="mf">20.</span><span class="p">),</span>
  1306. <span class="s">&#39;r=0&#39;</span><span class="p">:</span>
  1307. <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>
  1308. <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>
  1309. <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>
  1310. <span class="s">&#39;r=start_angle&#39;</span><span class="p">:</span>
  1311. <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>
  1312. <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>
  1313. <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>
  1314. <span class="s">&#39;r=start+arc_angle&#39;</span><span class="p">:</span>
  1315. <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>
  1316. <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>
  1317. <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="mi">1</span><span class="o">/</span><span class="mf">40.</span><span class="p">),</span>
  1318. <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">radius</span><span class="o">/</span><span class="mf">10.</span><span class="p">,</span> <span class="n">radius</span><span class="o">/</span><span class="mf">10.</span><span class="p">)),</span>
  1319. <span class="p">}</span>
  1320. <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>
  1321. <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>
  1322. <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>
  1323. <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>
  1324. <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>
  1325. <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>
  1326. <span class="n">a</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  1327. <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>
  1328. </pre></div>
  1329. </div>
  1330. </div>
  1331. <div class="section" id="spring">
  1332. <h3>Spring<a class="headerlink" href="#spring" title="Permalink to this headline">¶</a></h3>
  1333. <div class="figure">
  1334. <a class="reference internal image-reference" href="_images/Spring.png"><img alt="_images/Spring.png" src="_images/Spring.png" style="width: 800px;" /></a>
  1335. </div>
  1336. <div class="line-block">
  1337. <div class="line"><br /></div>
  1338. <div class="line"><br /></div>
  1339. </div>
  1340. <p>The code for making these two springs goes like this:</p>
  1341. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Spring</span><span class="p">():</span>
  1342. <span class="n">L</span> <span class="o">=</span> <span class="mf">5.0</span>
  1343. <span class="n">W</span> <span class="o">=</span> <span class="mf">2.0</span>
  1344. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  1345. <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">L</span><span class="o">/</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>
  1346. <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>
  1347. <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>
  1348. <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>
  1349. <span class="n">xpos</span> <span class="o">=</span> <span class="n">W</span>
  1350. <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>
  1351. <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>
  1352. <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">L</span><span class="o">/</span><span class="mi">10</span><span class="p">))</span>
  1353. <span class="n">s1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1354. <span class="n">s1_title</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1355. <span class="c">#s1.draw_dimensions()</span>
  1356. <span class="n">xpos</span> <span class="o">+=</span> <span class="mi">3</span><span class="o">*</span><span class="n">W</span>
  1357. <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">W</span><span class="o">/</span><span class="mf">2.</span><span class="p">,</span>
  1358. <span class="n">bar_length</span><span class="o">=</span><span class="n">L</span><span class="o">/</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>
  1359. <span class="n">s2</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1360. <span class="n">s2</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  1361. <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>
  1362. </pre></div>
  1363. </div>
  1364. </div>
  1365. <div class="section" id="dashpot">
  1366. <h3>Dashpot<a class="headerlink" href="#dashpot" title="Permalink to this headline">¶</a></h3>
  1367. <div class="figure">
  1368. <a class="reference internal image-reference" href="_images/Dashpot.png"><img alt="_images/Dashpot.png" src="_images/Dashpot.png" style="width: 600px;" /></a>
  1369. </div>
  1370. <div class="line-block">
  1371. <div class="line"><br /></div>
  1372. <div class="line"><br /></div>
  1373. </div>
  1374. <p>This dashpot is produced by</p>
  1375. <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Dashpot</span><span class="p">():</span>
  1376. <span class="n">L</span> <span class="o">=</span> <span class="mf">5.0</span>
  1377. <span class="n">W</span> <span class="o">=</span> <span class="mf">2.0</span>
  1378. <span class="n">xpos</span> <span class="o">=</span> <span class="mi">0</span>
  1379. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_coordinate_system</span><span class="p">(</span>
  1380. <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">L</span><span class="o">/</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>
  1381. <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>
  1382. <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>
  1383. <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>
  1384. <span class="c"># Default (simple) dashpot</span>
  1385. <span class="n">xpos</span> <span class="o">=</span> <span class="mf">1.5</span>
  1386. <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>
  1387. <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>
  1388. <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">L</span><span class="o">/</span><span class="mi">10</span><span class="p">))</span>
  1389. <span class="n">d1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1390. <span class="n">d1_title</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1391. <span class="c"># Dashpot for animation with fixed bar_length, dashpot_length and</span>
  1392. <span class="c"># prescribed piston_pos</span>
  1393. <span class="n">xpos</span> <span class="o">+=</span> <span class="mf">2.5</span><span class="o">*</span><span class="n">W</span>
  1394. <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">W</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span>
  1395. <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">L</span><span class="o">/</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>
  1396. <span class="n">d2</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1397. <span class="n">d2</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
  1398. <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>
  1399. </pre></div>
  1400. </div>
  1401. </div>
  1402. <div class="section" id="wavy">
  1403. <h3>Wavy<a class="headerlink" href="#wavy" title="Permalink to this headline">¶</a></h3>
  1404. <p>Looks strange. Fix x axis.</p>
  1405. </div>
  1406. <div class="section" id="stochastic-curves">
  1407. <h3>Stochastic curves<a class="headerlink" href="#stochastic-curves" title="Permalink to this headline">¶</a></h3>
  1408. <p>The <code class="docutils literal"><span class="pre">StochasticWavyCurve</span></code> object offers three precomputed
  1409. graphics that have a random variation:</p>
  1410. <div class="line-block">
  1411. <div class="line"><br /></div>
  1412. <div class="line"><br /></div>
  1413. </div>
  1414. <div class="figure">
  1415. <a class="reference internal image-reference" href="_images/StochasticWavyCurve.png"><img alt="_images/StochasticWavyCurve.png" src="_images/StochasticWavyCurve.png" style="width: 600px;" /></a>
  1416. </div>
  1417. <div class="line-block">
  1418. <div class="line"><br /></div>
  1419. <div class="line"><br /></div>
  1420. </div>
  1421. <p>The usage is simple. The construction</p>
  1422. <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>
  1423. </pre></div>
  1424. </div>
  1425. <p>picks the second curve (the three are numbered 0, 1, and 2),
  1426. and the first 40% of that curve. In case one desires another extent
  1427. of the axis, one can just scale the coordinates directly as these
  1428. are stored in the arrays <code class="docutils literal"><span class="pre">curve.x[curve_no]</span></code> and
  1429. <code class="docutils literal"><span class="pre">curve.y[curve_no]</span></code>.</p>
  1430. </div>
  1431. </div>
  1432. <div class="section" id="inner-workings-of-the-pysketcher-tool">
  1433. <h2>Inner workings of the Pysketcher tool<a class="headerlink" href="#inner-workings-of-the-pysketcher-tool" title="Permalink to this headline">¶</a></h2>
  1434. <p>We shall now explain how we can, quite easily, realize software with
  1435. the capabilities demonstrated in the previous examples. Each object in
  1436. the figure is represented as a class in a class hierarchy. Using
  1437. inheritance, classes can inherit properties from parent classes and
  1438. add new geometric features.</p>
  1439. <p id="index-0">Class programming is a key technology for realizing Pysketcher.
  1440. As soon as some classes are established, more are easily
  1441. added. Enhanced functionality for all the classes is also easy to
  1442. implement in common, generic code that can immediately be shared by
  1443. all present and future classes. The fundamental data structure
  1444. involved in the <code class="docutils literal"><span class="pre">pysketcher</span></code> package is a hierarchical tree, and much
  1445. of the material on implementation issues targets how to traverse tree
  1446. structures with recursive function calls in object hierarchies. This
  1447. topic is of key relevance in a wide range of other applications as
  1448. well. In total, the inner workings of Pysketcher constitute an
  1449. excellent example on the power of class programming.</p>
  1450. <div class="section" id="example-of-classes-for-geometric-objects">
  1451. <h3>Example of classes for geometric objects<a class="headerlink" href="#example-of-classes-for-geometric-objects" title="Permalink to this headline">¶</a></h3>
  1452. <p>We introduce class <code class="docutils literal"><span class="pre">Shape</span></code> as superclass for all specialized objects
  1453. in a figure. This class does not store any data, but provides a
  1454. series of functions that add functionality to all the subclasses.
  1455. This will be shown later.</p>
  1456. <div class="section" id="simple-geometric-objects">
  1457. <h4>Simple geometric objects<a class="headerlink" href="#simple-geometric-objects" title="Permalink to this headline">¶</a></h4>
  1458. <p>One simple subclass is <code class="docutils literal"><span class="pre">Rectangle</span></code>, specified by the coordinates of
  1459. the lower left corner and its width and height:</p>
  1460. <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>
  1461. <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>
  1462. <span class="n">p</span> <span class="o">=</span> <span class="n">lower_left_corner</span> <span class="c"># short form</span>
  1463. <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>
  1464. <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>
  1465. <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>
  1466. <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>
  1467. <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>
  1468. </pre></div>
  1469. </div>
  1470. <p>Any subclass of <code class="docutils literal"><span class="pre">Shape</span></code> will have a constructor that takes geometric
  1471. information about the shape of the object and creates a dictionary
  1472. <code class="docutils literal"><span class="pre">self.shapes</span></code> with the shape built of simpler shapes. The most
  1473. 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>
  1474. 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
  1475. 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>
  1476. and <code class="docutils literal"><span class="pre">y</span></code> arrays contain the corner points of the rectangle in
  1477. counterclockwise direction, starting and ending with in the lower left
  1478. corner.</p>
  1479. <p>Class <code class="docutils literal"><span class="pre">Line</span></code> is also a simple class:</p>
  1480. <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>
  1481. <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>
  1482. <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>
  1483. <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>
  1484. <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>
  1485. </pre></div>
  1486. </div>
  1487. <p>Here we only need two points, the start and end point on the line.
  1488. However, we may want to add some useful functionality, e.g., the ability
  1489. to give an <span class="math">\(x\)</span> coordinate and have the class calculate the
  1490. corresponding <span class="math">\(y\)</span> coordinate:</p>
  1491. <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>
  1492. <span class="sd">&quot;&quot;&quot;Given x, return y on the line.&quot;&quot;&quot;</span>
  1493. <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>
  1494. <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>
  1495. <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>
  1496. <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>
  1497. </pre></div>
  1498. </div>
  1499. <p>Unfortunately, this is too simplistic because vertical lines cannot be
  1500. 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
  1501. provides a more general solution at the cost of significantly longer
  1502. code with more tests.</p>
  1503. <p>A circle implies a somewhat increased complexity. Again we represent
  1504. 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>
  1505. object needs to store a large number of points on the curve such that
  1506. a plotting program produces a visually smooth curve. The points on
  1507. the circle must be calculated manually in the constructor of class
  1508. <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>
  1509. and center at <span class="math">\((x_0, y_0)\)</span> are given by</p>
  1510. <div class="math">
  1511. \[\begin{split}x &amp;= x_0 + R\cos (t),\\
  1512. y &amp;= y_0 + R\sin (t),\end{split}\]</div>
  1513. <p>where <span class="math">\(t\in [0, 2\pi]\)</span>. A discrete set of <span class="math">\(t\)</span> values in this
  1514. interval gives the corresponding set of <span class="math">\((x,y)\)</span> coordinates on
  1515. the circle. The user must specify the resolution as the number
  1516. of <span class="math">\(t\)</span> values. The circle&#8217;s radius and center must of course
  1517. also be specified.</p>
  1518. <p>We can write the <code class="docutils literal"><span class="pre">Circle</span></code> class as</p>
  1519. <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>
  1520. <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>
  1521. <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>
  1522. <span class="bp">self</span><span class="o">.</span><span class="n">resolution</span> <span class="o">=</span> <span class="n">resolution</span>
  1523. <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>
  1524. <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>
  1525. <span class="n">R</span> <span class="o">=</span> <span class="n">radius</span>
  1526. <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>
  1527. <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>
  1528. <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>
  1529. </pre></div>
  1530. </div>
  1531. <p>As in class <code class="docutils literal"><span class="pre">Line</span></code> we can offer the possibility to give an angle
  1532. <span class="math">\(\theta\)</span> (equivalent to <span class="math">\(t\)</span> in the formulas above)
  1533. and then get the corresponding <span class="math">\(x\)</span> and <span class="math">\(y\)</span> coordinates:</p>
  1534. <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>
  1535. <span class="sd">&quot;&quot;&quot;Return (x, y) point corresponding to angle theta.&quot;&quot;&quot;</span>
  1536. <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> \
  1537. <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>
  1538. </pre></div>
  1539. </div>
  1540. <p>There is one flaw with this method: it yields illegal values after
  1541. a translation, scaling, or rotation of the circle.</p>
  1542. <p>A part of a circle, an arc, is a frequent geometric object when
  1543. drawing mechanical systems. The arc is constructed much like
  1544. a circle, but <span class="math">\(t\)</span> runs in <span class="math">\([\theta_s, \theta_s + \theta_a]\)</span>. Giving
  1545. <span class="math">\(\theta_s\)</span> and <span class="math">\(\theta_a\)</span> the slightly more descriptive names
  1546. <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>
  1547. <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>
  1548. <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>
  1549. <span class="n">start_angle</span><span class="p">,</span> <span class="n">arc_angle</span><span class="p">,</span>
  1550. <span class="n">resolution</span><span class="o">=</span><span class="mi">180</span><span class="p">):</span>
  1551. <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>
  1552. <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>
  1553. <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>
  1554. <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>
  1555. <span class="n">resolution</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
  1556. <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>
  1557. <span class="n">R</span> <span class="o">=</span> <span class="n">radius</span>
  1558. <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>
  1559. <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>
  1560. <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>
  1561. </pre></div>
  1562. </div>
  1563. <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
  1564. a subclass specializing the arc to a circle:</p>
  1565. <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>
  1566. <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>
  1567. <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>
  1568. </pre></div>
  1569. </div>
  1570. </div>
  1571. <div class="section" id="class-curve">
  1572. <h4>Class curve<a class="headerlink" href="#class-curve" title="Permalink to this headline">¶</a></h4>
  1573. <p>Class <code class="docutils literal"><span class="pre">Curve</span></code> sits on the coordinates to be drawn, but how is that
  1574. done? The constructor of class <code class="docutils literal"><span class="pre">Curve</span></code> just stores the coordinates,
  1575. while a method <code class="docutils literal"><span class="pre">draw</span></code> sends the coordinates to the plotting program to
  1576. make a graph. Or more precisely, to avoid a lot of (e.g.)
  1577. Matplotlib-specific plotting commands in class <code class="docutils literal"><span class="pre">Curve</span></code> we have created
  1578. a small layer with a simple programming interface to plotting
  1579. programs. This makes it straightforward to change from Matplotlib to
  1580. another plotting program. The programming interface is represented by
  1581. the <code class="docutils literal"><span class="pre">drawing_tool</span></code> object and has a few functions:</p>
  1582. <blockquote>
  1583. <div><ul class="simple">
  1584. <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
  1585. to the plotting program,</li>
  1586. <li><code class="docutils literal"><span class="pre">set_coordinate_system</span></code> for specifying the graphics area,</li>
  1587. <li><code class="docutils literal"><span class="pre">erase</span></code> for deleting all elements of the graph,</li>
  1588. <li><code class="docutils literal"><span class="pre">set_grid</span></code> for turning on a grid (convenient while constructing the figure),</li>
  1589. <li><code class="docutils literal"><span class="pre">set_instruction_file</span></code> for creating a separate file with all
  1590. plotting commands (Matplotlib commands in our case),</li>
  1591. <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
  1592. <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>
  1593. </ul>
  1594. </div></blockquote>
  1595. <p>This is basically all we need to communicate to a plotting program.</p>
  1596. <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
  1597. setting properties of curves. This information is propagated to
  1598. all other shape objects in the <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary. Class
  1599. <code class="docutils literal"><span class="pre">Curve</span></code> stores the line properties together with the coordinates
  1600. of its curve and propagates this information to the plotting program.
  1601. When saying <code class="docutils literal"><span class="pre">vehicle.set_linewidth(10)</span></code>, all objects that make
  1602. 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,
  1603. but only the <code class="docutils literal"><span class="pre">Curve</span></code> object at the end of the chain will actually
  1604. store the information and send it to the plotting program.</p>
  1605. <p>A rough sketch of class <code class="docutils literal"><span class="pre">Curve</span></code> reads</p>
  1606. <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>
  1607. <span class="sd">&quot;&quot;&quot;General curve as a sequence of (x,y) coordintes.&quot;&quot;&quot;</span>
  1608. <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>
  1609. <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>
  1610. <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>
  1611. <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  1612. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">plot_curve</span><span class="p">(</span>
  1613. <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>
  1614. <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>
  1615. <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>
  1616. <span class="bp">self</span><span class="o">.</span><span class="n">linewidth</span> <span class="o">=</span> <span class="n">width</span>
  1617. <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>
  1618. <span class="bp">self</span><span class="o">.</span><span class="n">linestyle</span> <span class="o">=</span> <span class="n">style</span>
  1619. <span class="o">...</span>
  1620. </pre></div>
  1621. </div>
  1622. </div>
  1623. <div class="section" id="compound-geometric-objects">
  1624. <h4>Compound geometric objects<a class="headerlink" href="#compound-geometric-objects" title="Permalink to this headline">¶</a></h4>
  1625. <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
  1626. shape through just one <code class="docutils literal"><span class="pre">Curve</span></code> object. More complicated shapes are
  1627. built from instances of various subclasses of <code class="docutils literal"><span class="pre">Shape</span></code>. Classes used
  1628. for professional drawings soon get quite complex in composition and
  1629. have a lot of geometric details, so here we prefer to make a very
  1630. simple composition: the already drawn vehicle from Figure
  1631. <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
  1632. in a Python program as shown above, we make a subclass <code class="docutils literal"><span class="pre">Vehicle0</span></code> in
  1633. the <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy for doing the same thing.</p>
  1634. <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
  1635. classes or derive a new one, we need to import <code class="docutils literal"><span class="pre">pysketcher</span></code>. The constructor
  1636. of class <code class="docutils literal"><span class="pre">Vehicle0</span></code> performs approximately the same statements as
  1637. in the example program we developed for making the drawing in
  1638. Figure <a class="reference internal" href="#sketcher-fig-vehicle0"><span class="std std-ref">Sketch of a simple figure</span></a>.</p>
  1639. <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>
  1640. <span class="k">class</span> <span class="nc">Vehicle0</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
  1641. <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>
  1642. <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>
  1643. <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>
  1644. <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>
  1645. <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>
  1646. <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>
  1647. <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>
  1648. <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>
  1649. <span class="n">wheels</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
  1650. <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>
  1651. <span class="n">body</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
  1652. <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>
  1653. <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>
  1654. <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>
  1655. <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>
  1656. <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>
  1657. </pre></div>
  1658. </div>
  1659. <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
  1660. the inherited <code class="docutils literal"><span class="pre">draw</span></code> method (and a lot of other methods too) will
  1661. not work.</p>
  1662. <p>The painting of the vehicle, as shown in the right part of
  1663. 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>
  1664. be offered by a method:</p>
  1665. <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>
  1666. <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>
  1667. <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>
  1668. <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>
  1669. <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>
  1670. <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>
  1671. <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>
  1672. <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>
  1673. <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>
  1674. <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>
  1675. </pre></div>
  1676. </div>
  1677. <p>The usage of the class is simple: after having set up an appropriate
  1678. coordinate system as previously shown, we can do</p>
  1679. <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>
  1680. <span class="n">vehicle</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1681. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  1682. </pre></div>
  1683. </div>
  1684. <p>and go on the make a painted version by</p>
  1685. <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>
  1686. <span class="n">vehicle</span><span class="o">.</span><span class="n">colorful</span><span class="p">()</span>
  1687. <span class="n">vehicle</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
  1688. <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
  1689. </pre></div>
  1690. </div>
  1691. <p>A complete code defining and using class <code class="docutils literal"><span class="pre">Vehicle0</span></code> is found in the file
  1692. <a class="reference external" href="http://tinyurl.com/ot733jn/vehicle2.py">vehicle2.py</a>.</p>
  1693. <p>The <code class="docutils literal"><span class="pre">pysketcher</span></code> package contains a wide range of classes for various
  1694. geometrical objects, particularly those that are frequently used in
  1695. drawings of mechanical systems.</p>
  1696. </div>
  1697. </div>
  1698. <div class="section" id="adding-functionality-via-recursion">
  1699. <h3>Adding functionality via recursion<a class="headerlink" href="#adding-functionality-via-recursion" title="Permalink to this headline">¶</a></h3>
  1700. <p id="index-1">The really powerful feature of our class hierarchy is that we can add
  1701. much functionality to the superclass <code class="docutils literal"><span class="pre">Shape</span></code> and to the &#8220;bottom&#8221; class
  1702. <code class="docutils literal"><span class="pre">Curve</span></code>, and then all other classes for various types of geometrical shapes
  1703. immediately get the new functionality. To explain the idea we may
  1704. 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>
  1705. hierarchy must have. The inner workings of the <code class="docutils literal"><span class="pre">draw</span></code> method explain
  1706. the secrets of how a series of other useful operations on figures
  1707. can be implemented.</p>
  1708. <div class="section" id="basic-principles-of-recursion">
  1709. <h4>Basic principles of recursion<a class="headerlink" href="#basic-principles-of-recursion" title="Permalink to this headline">¶</a></h4>
  1710. <p>Note that we work with two types of hierarchies in the
  1711. present documentation: one Python <em>class hierarchy</em>,
  1712. with <code class="docutils literal"><span class="pre">Shape</span></code> as superclass, and one <em>object hierarchy</em> of figure elements
  1713. in a specific figure. A subclass of <code class="docutils literal"><span class="pre">Shape</span></code> stores its figure in the
  1714. <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary. This dictionary represents the object hierarchy
  1715. of figure elements for that class. We want to make one <code class="docutils literal"><span class="pre">draw</span></code> call
  1716. for an instance, say our class <code class="docutils literal"><span class="pre">Vehicle0</span></code>, and then we want this call
  1717. to be propagated to <em>all</em> objects that are contained in
  1718. <code class="docutils literal"><span class="pre">self.shapes</span></code> and all is nested subdictionaries. How is this done?</p>
  1719. <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
  1720. in the <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary:</p>
  1721. <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>
  1722. <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>
  1723. <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>
  1724. </pre></div>
  1725. </div>
  1726. <p>This general method can be provided by class <code class="docutils literal"><span class="pre">Shape</span></code> and inherited in
  1727. 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.
  1728. Seemingly, a call <code class="docutils literal"><span class="pre">v.draw()</span></code> just calls</p>
  1729. <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>
  1730. <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>
  1731. </pre></div>
  1732. </div>
  1733. <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
  1734. 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>.
  1735. 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
  1736. 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>.
  1737. 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>
  1738. method, which will run through <code class="docutils literal"><span class="pre">self.shapes</span></code>, now containing
  1739. 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>,
  1740. 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>,
  1741. but this is the same <code class="docutils literal"><span class="pre">draw</span></code> method as shown above. This method will
  1742. therefore traverse the circle&#8217;s <code class="docutils literal"><span class="pre">shapes</span></code> dictionary, which we have seen
  1743. consists of one <code class="docutils literal"><span class="pre">Curve</span></code> element.</p>
  1744. <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>
  1745. really needs to do something &#8220;physical&#8221;, namely send the coordinates to
  1746. the plotting program. The <code class="docutils literal"><span class="pre">draw</span></code> method is outlined in the short listing
  1747. of class <code class="docutils literal"><span class="pre">Curve</span></code> shown previously.</p>
  1748. <p>We can go to any of the other shape objects that appear in the figure
  1749. hierarchy and follow their <code class="docutils literal"><span class="pre">draw</span></code> calls in the similar way. Every time,
  1750. 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
  1751. 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
  1752. of the figure is really plotted (or more precisely, the coordinates
  1753. are sent to a plotting program).</p>
  1754. <p>When a method calls itself, such as <code class="docutils literal"><span class="pre">draw</span></code> does, the calls are known as
  1755. <em>recursive</em> and the programming principle is referred to as
  1756. <em>recursion</em>. This technique is very often used to traverse hierarchical
  1757. structures like the figure structures we work with here. Even though the
  1758. hierarchy of objects building up a figure are of different types, they
  1759. all inherit the same <code class="docutils literal"><span class="pre">draw</span></code> method and therefore exhibit the same
  1760. behavior with respect to drawing. Only the <code class="docutils literal"><span class="pre">Curve</span></code> object has a different
  1761. <code class="docutils literal"><span class="pre">draw</span></code> method, which does not lead to more recursion.</p>
  1762. </div>
  1763. <div class="section" id="explaining-recursion">
  1764. <h4>Explaining recursion<a class="headerlink" href="#explaining-recursion" title="Permalink to this headline">¶</a></h4>
  1765. <p>Understanding recursion is usually a challenge. To get a better idea of
  1766. 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>
  1767. that just visits all the objects in the <code class="docutils literal"><span class="pre">shapes</span></code> dictionary and prints
  1768. out a message for each object.
  1769. This feature allows us to trace the execution and see exactly where
  1770. we are in the hierarchy and which objects that are visited.</p>
  1771. <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>
  1772. <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>
  1773. <span class="c"># print message where we are (name is where we come from)</span>
  1774. <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>
  1775. <span class="c"># print message about which object to visit</span>
  1776. <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>
  1777. </pre></div>
  1778. </div>
  1779. <p>The <code class="docutils literal"><span class="pre">indent</span></code> parameter governs how much the message from this
  1780. <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
  1781. level in the hierarchy, i.e., every row of objects in Figure
  1782. <span class="xref std std-ref">sketcher:fig:Vehicle0:hier2</span>. This indentation makes it easy to
  1783. see on the printout how far down in the hierarchy we are.</p>
  1784. <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
  1785. 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>,
  1786. will be</p>
  1787. <div class="highlight-text"><div class="highlight"><pre>Composition: body.shapes has entries &#39;over&#39;, &#39;under&#39;
  1788. call body.shapes[&quot;over&quot;].recurse(&quot;over&quot;, 6)
  1789. </pre></div>
  1790. </div>
  1791. <p>The number of leading blanks on each line corresponds to the value of
  1792. <code class="docutils literal"><span class="pre">indent</span></code>. The code printing out such messages looks like</p>
  1793. <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>
  1794. <span class="n">space</span> <span class="o">=</span> <span class="s">&#39; &#39;</span><span class="o">*</span><span class="n">indent</span>
  1795. <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> \
  1796. <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> \
  1797. <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>
  1798. <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>
  1799. <span class="k">print</span> <span class="n">space</span><span class="p">,</span>
  1800. <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> \
  1801. <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>
  1802. <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>
  1803. </pre></div>
  1804. </div>
  1805. <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
  1806. 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>,
  1807. let us get an overview of the figure hierarchy in the <code class="docutils literal"><span class="pre">v</span></code> object
  1808. (as produced by <code class="docutils literal"><span class="pre">print</span> <span class="pre">v</span></code>)</p>
  1809. <div class="highlight-text"><div class="highlight"><pre>ground
  1810. wall
  1811. vehicle
  1812. body
  1813. over
  1814. rectangle
  1815. under
  1816. rectangle
  1817. wheels
  1818. wheel1
  1819. arc
  1820. wheel2
  1821. arc
  1822. </pre></div>
  1823. </div>
  1824. <p>The <code class="docutils literal"><span class="pre">recurse</span></code> method performs the same kind of traversal of the
  1825. hierarchy, but writes out and explains a lot more.</p>
  1826. <p>The data structure represented by <code class="docutils literal"><span class="pre">v.shapes</span></code> is known as a <em>tree</em>.
  1827. As in physical trees, there is a <em>root</em>, here the <code class="docutils literal"><span class="pre">v.shapes</span></code>
  1828. dictionary. A graphical illustration of the tree (upside down) is
  1829. shown in Figure <span class="xref std std-ref">sketcher:fig:Vehicle0:hier2</span>.
  1830. From the root there are one or more branches, here two:
  1831. <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
  1832. 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
  1833. are often used to describe the relations in object trees too: we say
  1834. 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
  1835. <code class="docutils literal"><span class="pre">vehicle</span></code>. The term <em>node</em> is also often used to describe an element
  1836. in a tree. A node may have several other nodes as <em>descendants</em>.</p>
  1837. <div class="figure" id="id12">
  1838. <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>
  1839. <p class="caption"><span class="caption-text"><em>Hierarchy of figure elements in an instance of class `Vehicle0`</em></span></p>
  1840. </div>
  1841. <p>Recursion is the principal programming technique to traverse tree structures.
  1842. Any object in the tree can be viewed as a root of a subtree. For
  1843. example, <code class="docutils literal"><span class="pre">wheels</span></code> is the root of a subtree that branches into
  1844. <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,
  1845. we imagine we process the root and then recurse into a subtree, but the
  1846. first object we recurse into can be viewed as the root of the subtree, so the
  1847. processing procedure of the parent object can be repeated.</p>
  1848. <p>A recommended next step is to simulate the <code class="docutils literal"><span class="pre">recurse</span></code> method by hand and
  1849. carefully check that what happens in the visits to <code class="docutils literal"><span class="pre">recurse</span></code> is
  1850. consistent with the output listed below. Although tedious, this is
  1851. a major exercise that guaranteed will help to demystify recursion.</p>
  1852. <p>A part of the printout of <code class="docutils literal"><span class="pre">v.recurse('vehicle')</span></code> looks like</p>
  1853. <div class="highlight-text"><div class="highlight"><pre> Vehicle0: vehicle.shapes has entries &#39;ground&#39;, &#39;vehicle&#39;
  1854. call vehicle.shapes[&quot;ground&quot;].recurse(&quot;ground&quot;, 2)
  1855. Wall: ground.shapes has entries &#39;wall&#39;
  1856. call ground.shapes[&quot;wall&quot;].recurse(&quot;wall&quot;, 4)
  1857. reached &quot;bottom&quot; object Curve
  1858. call vehicle.shapes[&quot;vehicle&quot;].recurse(&quot;vehicle&quot;, 2)
  1859. Composition: vehicle.shapes has entries &#39;body&#39;, &#39;wheels&#39;
  1860. call vehicle.shapes[&quot;body&quot;].recurse(&quot;body&quot;, 4)
  1861. Composition: body.shapes has entries &#39;over&#39;, &#39;under&#39;
  1862. call body.shapes[&quot;over&quot;].recurse(&quot;over&quot;, 6)
  1863. Rectangle: over.shapes has entries &#39;rectangle&#39;
  1864. call over.shapes[&quot;rectangle&quot;].recurse(&quot;rectangle&quot;, 8)
  1865. reached &quot;bottom&quot; object Curve
  1866. call body.shapes[&quot;under&quot;].recurse(&quot;under&quot;, 6)
  1867. Rectangle: under.shapes has entries &#39;rectangle&#39;
  1868. call under.shapes[&quot;rectangle&quot;].recurse(&quot;rectangle&quot;, 8)
  1869. reached &quot;bottom&quot; object Curve
  1870. ...
  1871. </pre></div>
  1872. </div>
  1873. <p>This example should clearly demonstrate the principle that we
  1874. can start at any object in the tree and do a recursive set
  1875. of calls with that object as root.</p>
  1876. </div>
  1877. </div>
  1878. <div class="section" id="scaling-translating-and-rotating-a-figure">
  1879. <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>
  1880. <p>With recursion, as explained in the previous section, we can within
  1881. minutes equip <em>all</em> classes in the <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy, both present and
  1882. future ones, with the ability to scale the figure, translate it,
  1883. or rotate it. This added functionality requires only a few lines
  1884. of code.</p>
  1885. <div class="section" id="scaling">
  1886. <h4>Scaling<a class="headerlink" href="#scaling" title="Permalink to this headline">¶</a></h4>
  1887. <p>We start with the simplest of the three geometric transformations,
  1888. namely scaling. For a <code class="docutils literal"><span class="pre">Curve</span></code> instance containing a set of <span class="math">\(n\)</span>
  1889. coordinates <span class="math">\((x_i,y_i)\)</span> that make up a curve, scaling by a factor <span class="math">\(a\)</span>
  1890. 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>
  1891. <div class="math">
  1892. \[x_i \leftarrow ax_i,\quad y_i\leftarrow ay_i,
  1893. \quad i=0,\ldots,n-1\thinspace .\]</div>
  1894. <p>Here we apply the arrow as an assignment operator.
  1895. The corresponding Python implementation in
  1896. class <code class="docutils literal"><span class="pre">Curve</span></code> reads</p>
  1897. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
  1898. <span class="o">...</span>
  1899. <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>
  1900. <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>
  1901. <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>
  1902. </pre></div>
  1903. </div>
  1904. <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,
  1905. so that multiplication by a scalar number <code class="docutils literal"><span class="pre">factor</span></code> is
  1906. a vectorized operation.</p>
  1907. <p>An even more efficient implementation is to make use of in-place
  1908. multiplication in the arrays,</p>
  1909. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
  1910. <span class="o">...</span>
  1911. <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>
  1912. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">*=</span> <span class="n">factor</span>
  1913. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">*=</span> <span class="n">factor</span>
  1914. </pre></div>
  1915. </div>
  1916. <p>as this saves the creation of temporary arrays like <code class="docutils literal"><span class="pre">factor*self.x</span></code>.</p>
  1917. <p>In an instance of a subclass of <code class="docutils literal"><span class="pre">Shape</span></code>, the meaning of a method
  1918. <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
  1919. ask each object to scale itself. This is the same delegation of
  1920. 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>)
  1921. method. All objects, except <code class="docutils literal"><span class="pre">Curve</span></code> instances, can share the same
  1922. 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>
  1923. method in the superclass <code class="docutils literal"><span class="pre">Shape</span></code> such that all subclasses inherit the
  1924. 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
  1925. 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
  1926. the <code class="docutils literal"><span class="pre">draw</span></code> method:</p>
  1927. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
  1928. <span class="o">...</span>
  1929. <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>
  1930. <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>
  1931. <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>
  1932. </pre></div>
  1933. </div>
  1934. <p>This is all we have to do in order to equip all subclasses of
  1935. <code class="docutils literal"><span class="pre">Shape</span></code> with scaling functionality!
  1936. Any piece of the figure will scale itself, in the same manner
  1937. as it can draw itself.</p>
  1938. </div>
  1939. <div class="section" id="translation">
  1940. <h4>Translation<a class="headerlink" href="#translation" title="Permalink to this headline">¶</a></h4>
  1941. <p>A set of coordinates <span class="math">\((x_i, y_i)\)</span> can be translated <span class="math">\(v_0\)</span> units in
  1942. 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>
  1943. <div class="math">
  1944. \[x_i\leftarrow x_i+v_0,\quad y_i\leftarrow y_i+v_1,
  1945. \quad i=0,\ldots,n-1\thinspace .\]</div>
  1946. <p>The natural specification of the translation is in terms of the
  1947. vector <span class="math">\(v=(v_0,v_1)\)</span>.
  1948. The corresponding Python implementation in class <code class="docutils literal"><span class="pre">Curve</span></code> becomes</p>
  1949. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
  1950. <span class="o">...</span>
  1951. <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>
  1952. <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>
  1953. <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>
  1954. </pre></div>
  1955. </div>
  1956. <p>The translation operation for a shape object is very similar to the
  1957. scaling and drawing operations. This means that we can implement a
  1958. 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
  1959. is parallel to the <code class="docutils literal"><span class="pre">scale</span></code> method:</p>
  1960. <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
  1961. <span class="o">....</span>
  1962. <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>
  1963. <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>
  1964. <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>
  1965. </pre></div>
  1966. </div>
  1967. </div>
  1968. <div class="section" id="rotation">
  1969. <h4>Rotation<a class="headerlink" href="#rotation" title="Permalink to this headline">¶</a></h4>
  1970. <p>Rotating a figure is more complicated than scaling and translating.
  1971. A counter clockwise rotation of <span class="math">\(\theta\)</span> degrees for a set of
  1972. coordinates <span class="math">\((x_i,y_i)\)</span> is given by</p>
  1973. <div class="math">
  1974. \[\begin{split}\bar x_i &amp;\leftarrow x_i\cos\theta - y_i\sin\theta,\\
  1975. \bar y_i &amp;\leftarrow x_i\sin\theta + y_i\cos\theta\thinspace .\end{split}\]</div>
  1976. <p>This rotation is performed around the origin. If we want the figure
  1977. to be rotated with respect to a general point <span class="math">\((x,y)\)</span>, we need to
  1978. extend the formulas above:</p>
  1979. <div class="math">
  1980. \[\begin{split}\bar x_i &amp;\leftarrow x + (x_i -x)\cos\theta - (y_i -y)\sin\theta,\\
  1981. \bar y_i &amp;\leftarrow y + (x_i -x)\sin\theta + (y_i -y)\cos\theta\thinspace .\end{split}\]</div>
  1982. <p>The Python implementation in class <code class="docutils literal"><span class="pre">Curve</span></code>, assuming that <span class="math">\(\theta\)</span>
  1983. is given in degrees and not in radians, becomes</p>
  1984. <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>
  1985. <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>
  1986. <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">center</span>
  1987. <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>
  1988. <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>
  1989. <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>
  1990. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">xnew</span>
  1991. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">ynew</span>
  1992. </pre></div>
  1993. </div>
  1994. <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
  1995. <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>
  1996. <p>We have already seen the <code class="docutils literal"><span class="pre">rotate</span></code> method in action when animating the
  1997. 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>
  1998. </div>
  1999. </div>
  2000. </div>
  2001. </div>
  2002. </div>
  2003. </div>
  2004. </div>
  2005. <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
  2006. <div class="sphinxsidebarwrapper">
  2007. <center>
  2008. <p class="logo"><a href="http://cbc.simula.no/" title="Go to Center for Biomedical Computing">
  2009. <img class="logo" src="_static/cbc_logo.png" alt="Logo"/>
  2010. </a></p>
  2011. </center>
  2012. <h3><a href="index.html">Table Of Contents</a></h3>
  2013. <ul>
  2014. <li><a class="reference internal" href="#">Pysketcher: Create Principal Sketches of Physics Problems</a><ul>
  2015. <li><a class="reference internal" href="#a-first-glimpse-of-pysketcher">A first glimpse of Pysketcher</a><ul>
  2016. <li><a class="reference internal" href="#basic-construction-of-sketches">Basic construction of sketches</a><ul>
  2017. <li><a class="reference internal" href="#basic-drawing">Basic drawing</a></li>
  2018. <li><a class="reference internal" href="#groups-of-objects">Groups of objects</a></li>
  2019. <li><a class="reference internal" href="#changing-line-styles-and-colors">Changing line styles and colors</a></li>
  2020. <li><a class="reference internal" href="#the-figure-composition-as-an-object-hierarchy">The figure composition as an object hierarchy</a></li>
  2021. <li><a class="reference internal" href="#animation-translating-the-vehicle">Animation: translating the vehicle</a></li>
  2022. <li><a class="reference internal" href="#animation-rolling-the-wheels">Animation: rolling the wheels</a></li>
  2023. </ul>
  2024. </li>
  2025. </ul>
  2026. </li>
  2027. <li><a class="reference internal" href="#a-simple-pendulum">A simple pendulum</a><ul>
  2028. <li><a class="reference internal" href="#the-basic-physics-sketch">The basic physics sketch</a></li>
  2029. <li><a class="reference internal" href="#the-body-diagram">The body diagram</a></li>
  2030. <li><a class="reference internal" href="#animated-body-diagram">Animated body diagram</a><ul>
  2031. <li><a class="reference internal" href="#function-for-drawing-the-body-diagram">Function for drawing the body diagram</a></li>
  2032. <li><a class="reference internal" href="#equations-for-the-motion-and-forces">Equations for the motion and forces</a></li>
  2033. <li><a class="reference internal" href="#numerical-solution">Numerical solution</a></li>
  2034. <li><a class="reference internal" href="#animation">Animation</a></li>
  2035. </ul>
  2036. </li>
  2037. </ul>
  2038. </li>
  2039. <li><a class="reference internal" href="#basic-shapes">Basic shapes</a><ul>
  2040. <li><a class="reference internal" href="#axis">Axis</a></li>
  2041. <li><a class="reference internal" href="#distance-with-text">Distance with text</a></li>
  2042. <li><a class="reference internal" href="#rectangle">Rectangle</a></li>
  2043. <li><a class="reference internal" href="#triangle">Triangle</a></li>
  2044. <li><a class="reference internal" href="#arc">Arc</a></li>
  2045. <li><a class="reference internal" href="#spring">Spring</a></li>
  2046. <li><a class="reference internal" href="#dashpot">Dashpot</a></li>
  2047. <li><a class="reference internal" href="#wavy">Wavy</a></li>
  2048. <li><a class="reference internal" href="#stochastic-curves">Stochastic curves</a></li>
  2049. </ul>
  2050. </li>
  2051. <li><a class="reference internal" href="#inner-workings-of-the-pysketcher-tool">Inner workings of the Pysketcher tool</a><ul>
  2052. <li><a class="reference internal" href="#example-of-classes-for-geometric-objects">Example of classes for geometric objects</a><ul>
  2053. <li><a class="reference internal" href="#simple-geometric-objects">Simple geometric objects</a></li>
  2054. <li><a class="reference internal" href="#class-curve">Class curve</a></li>
  2055. <li><a class="reference internal" href="#compound-geometric-objects">Compound geometric objects</a></li>
  2056. </ul>
  2057. </li>
  2058. <li><a class="reference internal" href="#adding-functionality-via-recursion">Adding functionality via recursion</a><ul>
  2059. <li><a class="reference internal" href="#basic-principles-of-recursion">Basic principles of recursion</a></li>
  2060. <li><a class="reference internal" href="#explaining-recursion">Explaining recursion</a></li>
  2061. </ul>
  2062. </li>
  2063. <li><a class="reference internal" href="#scaling-translating-and-rotating-a-figure">Scaling, translating, and rotating a figure</a><ul>
  2064. <li><a class="reference internal" href="#scaling">Scaling</a></li>
  2065. <li><a class="reference internal" href="#translation">Translation</a></li>
  2066. <li><a class="reference internal" href="#rotation">Rotation</a></li>
  2067. </ul>
  2068. </li>
  2069. </ul>
  2070. </li>
  2071. </ul>
  2072. </li>
  2073. </ul>
  2074. <h4>Previous topic</h4>
  2075. <p class="topless"><a href="index.html"
  2076. title="previous chapter">Pysketcher: Create Principal Sketches of Physics Problems</a></p>
  2077. <div role="note" aria-label="source link">
  2078. <h3>This Page</h3>
  2079. <ul class="this-page-menu">
  2080. <li><a href="_sources/main_sketcher.txt"
  2081. rel="nofollow">Show Source</a></li>
  2082. </ul>
  2083. </div>
  2084. <div id="searchbox" style="display: none" role="search">
  2085. <h3>Quick search</h3>
  2086. <form class="search" action="search.html" method="get">
  2087. <input type="text" name="q" />
  2088. <input type="submit" value="Go" />
  2089. <input type="hidden" name="check_keywords" value="yes" />
  2090. <input type="hidden" name="area" value="default" />
  2091. </form>
  2092. <p class="searchtip" style="font-size: 90%">
  2093. Enter search terms or a module, class or function name.
  2094. </p>
  2095. </div>
  2096. <script type="text/javascript">$('#searchbox').show(0);</script>
  2097. </div>
  2098. </div>
  2099. <div class="clearer"></div>
  2100. </div>
  2101. <div class="related" role="navigation" aria-label="related navigation">
  2102. <h3>Navigation</h3>
  2103. <ul>
  2104. <li class="right" style="margin-right: 10px">
  2105. <a href="genindex.html" title="General Index"
  2106. >index</a></li>
  2107. <li class="right" >
  2108. <a href="index.html" title="Pysketcher: Create Principal Sketches of Physics Problems"
  2109. >previous</a> |</li>
  2110. <li class="nav-item nav-item-0"><a href="index.html">Pysketcher: Create Principal Sketches of Physics Problems</a> &raquo;</li>
  2111. </ul>
  2112. </div>
  2113. <div class="wrapper">
  2114. <div class="footer">
  2115. <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
  2116. <br />
  2117. <br />
  2118. &copy;2016, Hans Petter Langtangen.
  2119. </div>
  2120. </div>
  2121. </body>
  2122. </html>