| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>Pysketcher: Create Principal Sketches of Physics Problems</title>
-
- <link rel="stylesheet" href="_static/default.css" type="text/css" />
- <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: './',
- VERSION: '1.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
- <script type="text/javascript" src="_static/sidebar.js"></script>
- <script src="http://sagecell.sagemath.org/static/jquery.min.js"></script>
- <script src="http://sagecell.sagemath.org/static/embedded_sagecell.js"></script>
- <script>sagecell.makeSagecell({inputLocation: ".sage"});</script>
- <style type="text/css">
- .sagecell .CodeMirror-scroll {
- overflow-y: hidden;
- overflow-x: auto;
- }
- .sagecell .CodeMirror {
- height: auto;
- }
- </style>
-
- <link rel="top" title="Pysketcher: Create Principal Sketches of Physics Problems" href="index.html" />
- <link rel="prev" title="Pysketcher: Create Principal Sketches of Physics Problems" href="index.html" />
-
-
- <style type="text/css">
- div.admonition {
- background-color: whiteSmoke;
- border: 1px solid #bababa;
- }
- </style>
- </head>
-
- <body role="document">
- <div class="related" role="navigation" aria-label="related navigation">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="index.html" title="Pysketcher: Create Principal Sketches of Physics Problems"
- accesskey="P">previous</a> |</li>
- <li class="nav-item nav-item-0"><a href="index.html">Pysketcher: Create Principal Sketches of Physics Problems</a> »</li>
- </ul>
- </div>
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body" role="main">
-
- <div class="section" id="pysketcher-create-principal-sketches-of-physics-problems">
- <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>
- <table class="docutils field-list" frame="void" rules="none">
- <col class="field-name" />
- <col class="field-body" />
- <tbody valign="top">
- <tr class="field-odd field"><th class="field-name">Authors:</th><td class="field-body">Hans Petter Langtangen</td>
- </tr>
- <tr class="field-even field"><th class="field-name">Date:</th><td class="field-body">Jan 22, 2016</td>
- </tr>
- </tbody>
- </table>
- <p>This document is derived from Chapter 9 in the book
- <a class="reference external" href="http://www.amazon.com/Scientific-Programming-Computational-Science-Engineering/dp/3642549586/ref=sr_1_2?s=books&ie=UTF8&qid=1407225588&sr=1-2&keywords=langtangen">A Primer on Scientific Programming with Python</a>, by H. P. Langtangen,
- 4th edition, Springer, 2014.</p>
- <p><em>Abstract.</em> Pysketcher is a Python package which allows principal sketches of
- physics and mechanics problems to be realized through short programs
- instead of interactive (and potentially tedious and inaccurate)
- drawing. Elements of the sketch, such as lines, circles, angles,
- forces, coordinate systems, etc., are realized as objects and
- collected in hierarchical structures. Parts of the hierarchical
- structures can easily change line styles and colors, or be copied,
- scaled, translated, and rotated. These features make it
- straightforward to move parts of the sketch to create animation,
- usually in accordance with the physics of the underlying problem.
- Exact dimensioning of the elements in the sketch is trivial to obtain
- since distances are specified in computer code.</p>
- <p>Pysketcher is easy to learn from a number of examples. Beyond
- essential Python programming and a knowledge about mechanics problems,
- no further background is required.</p>
- <div class="section" id="a-first-glimpse-of-pysketcher">
- <h2>A first glimpse of Pysketcher<a class="headerlink" href="#a-first-glimpse-of-pysketcher" title="Permalink to this headline">¶</a></h2>
- <p>Formulation of physical problems makes heavy use of <em>principal sketches</em>
- 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>.
- This particular sketch illustrates the classical mechanics problem
- of a rolling wheel on an inclined plane.
- The figure
- is made up many individual elements: a rectangle
- filled with a pattern (the inclined plane), a hollow circle with color
- (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>
- axis), an angle with symbol <span class="math">\(\theta\)</span>, and a dashed line indicating the
- starting location of the wheel.</p>
- <p>Drawing software and plotting programs can produce such figures quite
- easily in principle, but the amount of details the user needs to
- control with the mouse can be substantial. Software more tailored to
- producing sketches of this type would work with more convenient
- abstractions, such as circle, wall, angle, force arrow, axis, and so
- forth. And as soon we start <em>programming</em> to construct the figure we
- get a range of other powerful tools at disposal. For example, we can
- easily translate and rotate parts of the figure and make an animation
- that illustrates the physics of the problem.
- Programming as a superior alternative to interactive drawing is
- the mantra of this section.</p>
- <div class="figure" id="id2">
- <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>
- <p class="caption"><span class="caption-text"><em>Sketch of a physics problem</em></span></p>
- </div>
- <div class="section" id="basic-construction-of-sketches">
- <h3>Basic construction of sketches<a class="headerlink" href="#basic-construction-of-sketches" title="Permalink to this headline">¶</a></h3>
- <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>
- we focus on the significantly simpler drawing shown
- 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
- several elements: two circles, two rectangles, and a “ground” element.</p>
- <div class="figure" id="id3">
- <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>
- <p class="caption"><span class="caption-text"><em>Sketch of a simple figure</em></span></p>
- </div>
- <p>When the sketch is defined in terms of computer code, it is natural to
- parameterize geometric features, such as the radius of the wheel (<span class="math">\(R\)</span>),
- the center point of the left wheel (<span class="math">\(w_1\)</span>), as well as the height (<span class="math">\(H\)</span>) and
- length (<span class="math">\(L\)</span>) of the main part. The simple vehicle in
- 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
- tool. However, if we want to change the radius of the wheels, you need a
- sophisticated drawing tool to avoid redrawing the whole figure, while
- in computer code this is a matter of changing the <span class="math">\(R\)</span> parameter and
- rerunning the program.
- 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
- a variation of the drawing in
- 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
- <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
- to quickly change geometric sizes is key to many problem settings in
- physics and engineering, but then a program must define the geometry.</p>
- <div class="figure" id="id4">
- <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>
- <p class="caption"><span class="caption-text"><em>Redrawing a figure with other geometric parameters</em></span></p>
- </div>
- <div class="section" id="basic-drawing">
- <h4>Basic drawing<a class="headerlink" href="#basic-drawing" title="Permalink to this headline">¶</a></h4>
- <p>A typical program creating these five elements is shown next.
- After importing the <code class="docutils literal"><span class="pre">pysketcher</span></code> package, the first task is always to
- define a coordinate system:</p>
- <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>
- <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="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>
- </pre></div>
- </div>
- <p>Instead of working with lengths expressed by specific numbers it is
- highly recommended to use variables to parameterize lengths as
- this makes it easier to change dimensions later.
- Here we introduce some key lengths for the radius of the wheels,
- distance between the wheels, etc.:</p>
- <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>
- <span class="n">L</span> <span class="o">=</span> <span class="mi">4</span> <span class="c"># distance between wheels</span>
- <span class="n">H</span> <span class="o">=</span> <span class="mi">2</span> <span class="c"># height of vehicle body</span>
- <span class="n">w_1</span> <span class="o">=</span> <span class="mi">5</span> <span class="c"># position of front wheel</span>
- <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>
- <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>
- </pre></div>
- </div>
- <p>With the drawing area in place we can make the first <code class="docutils literal"><span class="pre">Circle</span></code> object
- in an intuitive fashion:</p>
- <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>
- </pre></div>
- </div>
- <p>to change dimensions later.</p>
- <p>To translate the geometric information about the <code class="docutils literal"><span class="pre">wheel1</span></code> object to
- instructions for the plotting engine (in this case Matplotlib), one calls the
- <code class="docutils literal"><span class="pre">wheel1.draw()</span></code>. To display all drawn objects, one issues
- <code class="docutils literal"><span class="pre">drawing_tool.display()</span></code>. The typical steps are hence:</p>
- <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>
- <span class="n">wheel1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="c"># Define other objects and call their draw() methods</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">'tmp.png'</span><span class="p">)</span> <span class="c"># store picture</span>
- </pre></div>
- </div>
- <p>The next wheel can be made by taking a copy of <code class="docutils literal"><span class="pre">wheel1</span></code> and
- translating the object to the right according to a
- displacement vector <span class="math">\((L,0)\)</span>:</p>
- <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>
- <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>
- </pre></div>
- </div>
- <p>The two rectangles are also made in an intuitive way:</p>
- <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>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- </div>
- <div class="section" id="groups-of-objects">
- <h4>Groups of objects<a class="headerlink" href="#groups-of-objects" title="Permalink to this headline">¶</a></h4>
- <p>Instead of calling the <code class="docutils literal"><span class="pre">draw</span></code> method of every object, we can
- group objects and call <code class="docutils literal"><span class="pre">draw</span></code>, or perform other operations, for
- the whole group. For example, we may collect the two wheels
- 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
- in a <code class="docutils literal"><span class="pre">body</span></code> group. The whole vehicle is a composition
- 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>
- <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">'wheel1'</span><span class="p">:</span> <span class="n">wheel1</span><span class="p">,</span> <span class="s">'wheel2'</span><span class="p">:</span> <span class="n">wheel2</span><span class="p">})</span>
- <span class="n">body</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">'under'</span><span class="p">:</span> <span class="n">under</span><span class="p">,</span> <span class="s">'over'</span><span class="p">:</span> <span class="n">over</span><span class="p">})</span>
- <span class="n">vehicle</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">'wheels'</span><span class="p">:</span> <span class="n">wheels</span><span class="p">,</span> <span class="s">'body'</span><span class="p">:</span> <span class="n">body</span><span class="p">})</span>
- </pre></div>
- </div>
- <p>The ground is illustrated by an object of type <code class="docutils literal"><span class="pre">Wall</span></code>,
- mostly used to indicate walls in sketches of mechanical systems.
- 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,
- and a <code class="docutils literal"><span class="pre">thickness</span></code> parameter, and creates a thick curve filled
- with a simple pattern. In this case the curve is just a flat
- line so the construction is made of two points on the
- ground line (<span class="math">\((w_1-L,0)\)</span> and <span class="math">\((w_1+3L,0)\)</span>):</p>
- <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>
- </pre></div>
- </div>
- <p>The negative thickness makes the pattern-filled rectangle appear below
- the defined line, otherwise it appears above.</p>
- <p>We may now collect all the objects in a “top” object that contains
- the whole figure:</p>
- <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">'vehicle'</span><span class="p">:</span> <span class="n">vehicle</span><span class="p">,</span> <span class="s">'ground'</span><span class="p">:</span> <span class="n">ground</span><span class="p">})</span>
- <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>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">'tmp.png'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>The <code class="docutils literal"><span class="pre">fig.draw()</span></code> call will visit
- all subgroups, their subgroups,
- and so forth in the hierarchical tree structure of
- figure elements,
- and call <code class="docutils literal"><span class="pre">draw</span></code> for every object.</p>
- </div>
- <div class="section" id="changing-line-styles-and-colors">
- <h4>Changing line styles and colors<a class="headerlink" href="#changing-line-styles-and-colors" title="Permalink to this headline">¶</a></h4>
- <p>Controlling the line style, line color, and line width is
- fundamental when designing figures. The <code class="docutils literal"><span class="pre">pysketcher</span></code>
- package allows the user to control such properties in
- single objects, but also set global properties that are
- used if the object has no particular specification of
- the properties. Setting the global properties are done like</p>
- <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">'dashed'</span><span class="p">)</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'black'</span><span class="p">)</span>
- <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>
- </pre></div>
- </div>
- <p>At the object level the properties are specified in a similar
- way:</p>
- <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">'solid'</span><span class="p">)</span>
- <span class="n">wheels</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'red'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>and so on.</p>
- <p>Geometric figures can be specified as <em>filled</em>, either with a color or with a
- special visual pattern:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="c"># Set filling of all curves</span>
- <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">'blue'</span><span class="p">,</span> <span class="n">pattern</span><span class="o">=</span><span class="s">'/'</span><span class="p">)</span>
- <span class="c"># Turn off filling of all curves</span>
- <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>
- <span class="c"># Fill the wheel with red color</span>
- <span class="n">wheel1</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">'red'</span><span class="p">)</span>
- </pre></div>
- </div>
- </div>
- <div class="section" id="the-figure-composition-as-an-object-hierarchy">
- <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>
- <p>The composition of objects making up the figure
- is hierarchical, similar to a family, where
- each object has a parent and a number of children. Do a
- <code class="docutils literal"><span class="pre">print</span> <span class="pre">fig</span></code> to display the relations:</p>
- <div class="highlight-text"><div class="highlight"><pre>ground
- wall
- vehicle
- body
- over
- rectangle
- under
- rectangle
- wheels
- wheel1
- arc
- wheel2
- arc
- </pre></div>
- </div>
- <p>The indentation reflects how deep down in the hierarchy (family)
- we are.
- This output is to be interpreted as follows:</p>
- <blockquote>
- <div><ul class="simple">
- <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>
- <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>
- <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>
- <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>
- <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>
- </ul>
- </div></blockquote>
- <p>In this listing there are also objects not defined by the
- 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>
- 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>
- <p>More detailed information can be printed by</p>
- <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">'std'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>yielding the output</p>
- <div class="highlight-text"><div class="highlight"><pre>ground (Wall):
- wall (Curve): 4 coords fillcolor='white' fillpattern='/'
- vehicle (Composition):
- body (Composition):
- over (Rectangle):
- rectangle (Curve): 5 coords
- under (Rectangle):
- rectangle (Curve): 5 coords
- wheels (Composition):
- wheel1 (Circle):
- arc (Curve): 181 coords
- wheel2 (Circle):
- arc (Curve): 181 coords
- </pre></div>
- </div>
- <p>Here we can see the class type for each figure object, how many
- coordinates that are involved in basic figures (<code class="docutils literal"><span class="pre">Curve</span></code> objects), and
- special settings of the basic figure (fillcolor, line types, etc.).
- 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>,
- which is a <code class="docutils literal"><span class="pre">Curve</span></code> object consisting of 181 coordinates (the
- points needed to draw a smooth circle). The <code class="docutils literal"><span class="pre">Curve</span></code> objects are the
- only objects that really holds specific coordinates to be drawn.
- The other object types are just compositions used to group
- parts of the complete figure.</p>
- <p>One can also get a graphical overview of the hierarchy of figure objects
- that build up a particular figure <code class="docutils literal"><span class="pre">fig</span></code>.
- 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
- the <em>dot format</em>. This file contains relations between parent and
- child objects in the figure and can be turned into an image,
- 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
- running the <code class="docutils literal"><span class="pre">dot</span></code> program:</p>
- <div class="highlight-text"><div class="highlight"><pre>Terminal> dot -Tpng -o fig.png fig.dot
- </pre></div>
- </div>
- <div class="figure" id="id5">
- <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>
- <p class="caption"><span class="caption-text"><em>Hierarchical relation between figure objects</em></span></p>
- </div>
- <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
- where the class type of each object is also visible, see
- Figure <span class="xref std std-ref">sketcher:fig:vehicle0:hier2</span>. The ability to write out the
- object hierarchy or view it graphically can be of great help when
- working with complex figures that involve layers of subfigures.</p>
- <div class="figure" id="id6">
- <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>
- <p class="caption"><span class="caption-text"><em>Hierarchical relation between figure objects, including their class names</em></span></p>
- </div>
- <p>Any of the objects can in the program be reached through their names, e.g.,</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">]</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">]</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">]</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">][</span><span class="s">'arc'</span><span class="p">]</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">][</span><span class="s">'arc'</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="c"># x coords</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">][</span><span class="s">'arc'</span><span class="p">]</span><span class="o">.</span><span class="n">y</span> <span class="c"># y coords</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">][</span><span class="s">'arc'</span><span class="p">]</span><span class="o">.</span><span class="n">linestyle</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">][</span><span class="s">'arc'</span><span class="p">]</span><span class="o">.</span><span class="n">linetype</span>
- </pre></div>
- </div>
- <p>Grabbing a part of the figure this way is handy for
- changing properties of that part, for example, colors, line styles
- (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>
- <div class="highlight-python"><div class="highlight"><pre><span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">]</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</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>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">]</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'black'</span><span class="p">)</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'body'</span><span class="p">][</span><span class="s">'under'</span><span class="p">]</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">'red'</span><span class="p">)</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'body'</span><span class="p">][</span><span class="s">'over'</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">'/'</span><span class="p">)</span>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'body'</span><span class="p">][</span><span class="s">'over'</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>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'body'</span><span class="p">][</span><span class="s">'over'</span><span class="p">][</span><span class="s">'rectangle'</span><span class="p">]</span><span class="o">.</span><span class="n">linewidth</span> <span class="o">=</span> <span class="mi">4</span>
- </pre></div>
- </div>
- <p>The last line accesses the <code class="docutils literal"><span class="pre">Curve</span></code> object directly, while the line above,
- accesses the <code class="docutils literal"><span class="pre">Rectangle</span></code> object, which will then set the linewidth of
- its <code class="docutils literal"><span class="pre">Curve</span></code> object, and other objects if it had any.
- 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>
- <div class="figure" id="id7">
- <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>
- <p class="caption"><span class="caption-text"><em>Left: Basic line-based drawing. Right: Thicker lines and filled parts</em></span></p>
- </div>
- <p>We can also change position of parts of the figure and thereby make
- animations, as shown next.</p>
- </div>
- <div class="section" id="animation-translating-the-vehicle">
- <h4>Animation: translating the vehicle<a class="headerlink" href="#animation-translating-the-vehicle" title="Permalink to this headline">¶</a></h4>
- <p>Can we make our little vehicle roll? A first attempt will be to
- fake rolling by just displacing all parts of the vehicle.
- The relevant parts constitute the <code class="docutils literal"><span class="pre">fig['vehicle']</span></code> object.
- This part of the figure can be translated, rotated, and scaled.
- A translation along the ground means a translation in <span class="math">\(x\)</span> direction,
- say a length <span class="math">\(L\)</span> to the right:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</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>
- </pre></div>
- </div>
- <p>You need to erase, draw, and display to see the movement:</p>
- <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>
- <span class="n">fig</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- </pre></div>
- </div>
- <p>Without erasing, the old drawing of the vehicle will remain in
- the figure so you get two vehicles. Without <code class="docutils literal"><span class="pre">fig.draw()</span></code> the
- new coordinates of the vehicle will not be communicated to
- the drawing tool, and without calling display the updated
- drawing will not be visible.</p>
- <p>A figure that moves in time is conveniently realized by the
- function <code class="docutils literal"><span class="pre">animate</span></code>:</p>
- <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>
- </pre></div>
- </div>
- <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
- time points, and <code class="docutils literal"><span class="pre">action</span></code> is a user-specified function that changes
- <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
- parts of <code class="docutils literal"><span class="pre">fig</span></code>.</p>
- <p>In the present case we can define the movement through a velocity
- 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
- intervals <code class="docutils literal"><span class="pre">dt</span></code>. A possible velocity function is</p>
- <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>
- <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>
- </pre></div>
- </div>
- <p>Our action function for horizontal displacements <code class="docutils literal"><span class="pre">v(t)*dt</span></code> becomes</p>
- <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>
- <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>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</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>
- </pre></div>
- </div>
- <p>Since our velocity is negative for <span class="math">\(t\in [0,2R]\)</span> the displacement is
- to the left.</p>
- <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
- 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
- <code class="docutils literal"><span class="pre">fig.draw()</span></code> and <code class="docutils literal"><span class="pre">drawing_tool.display()</span></code>.
- Here we choose a resolution of the animation corresponding to
- 25 time points in the time interval <span class="math">\([0,2R]\)</span>:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">numpy</span>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- <p>The <code class="docutils literal"><span class="pre">pause_per_frame</span></code> adds a pause, here 0.2 seconds, between
- each frame in the animation.</p>
- <p>We can also ask <code class="docutils literal"><span class="pre">animate</span></code> to store each frame in a file:</p>
- <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>
- <span class="n">pause_per_frame</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)</span>
- </pre></div>
- </div>
- <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>,
- is the printf-specification used to generate the individual
- plot files. We can use this specification to make a video
- 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
- as Ubuntu). Videos in the Flash and WebM formats can be created
- by</p>
- <div class="highlight-text"><div class="highlight"><pre>Terminal> ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec flv mov.flv
- Terminal> ffmpeg -r 12 -i tmp_frame_%04d.png -vcodec libvpx mov.webm
- </pre></div>
- </div>
- <p>An animated GIF movie can also be made using the <code class="docutils literal"><span class="pre">convert</span></code> program
- from the ImageMagick software suite:</p>
- <div class="highlight-text"><div class="highlight"><pre>Terminal> convert -delay 20 tmp_frame*.png mov.gif
- Terminal> animate mov.gif # play movie
- </pre></div>
- </div>
- <p>The delay between frames, in units of 1/100 s,
- governs the speed of the movie.
- To play the animated GIF file in a web page, simply insert
- <code class="docutils literal"><span class="pre"><img</span> <span class="pre">src="mov.gif"></span></code> in the HTML code.</p>
- <p>The individual PNG frames can be directly played in a web
- browser by running</p>
- <div class="highlight-text"><div class="highlight"><pre>Terminal> scitools movie output_file=mov.html fps=5 tmp_frame*
- </pre></div>
- </div>
- <p>or calling</p>
- <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>
- <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">'html'</span><span class="p">,</span> <span class="n">output_file</span><span class="o">=</span><span class="s">'mov.html'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>in Python. Load the resulting file <code class="docutils literal"><span class="pre">mov.html</span></code> into a web browser
- to play the movie.</p>
- <p>Try to run <a class="reference external" href="http://tinyurl.com/ot733jn/vehicle0.py">vehicle0.py</a> and
- 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>
- 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>
- </div>
- <div class="section" id="animation-rolling-the-wheels">
- <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>
- <p>It is time to show rolling wheels. To this end, we add spokes to the
- 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>.
- The construction of the wheels will now involve a circle and two lines:</p>
- <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>
- <span class="s">'wheel'</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>
- <span class="s">'cross'</span><span class="p">:</span> <span class="n">Composition</span><span class="p">({</span><span class="s">'cross1'</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>
- <span class="s">'cross2'</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>
- <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>
- <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>
- </pre></div>
- </div>
- <p>Observe that <code class="docutils literal"><span class="pre">wheel1.copy()</span></code> copies all the objects that make
- up the first wheel, and <code class="docutils literal"><span class="pre">wheel2.translate</span></code> translates all
- the copied objects.</p>
- <div class="figure" id="id8">
- <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>
- <p class="caption"><span class="caption-text"><em>Wheels with spokes to illustrate rolling</em></span></p>
- </div>
- <p>The <code class="docutils literal"><span class="pre">move</span></code> function now needs to displace all the objects in the
- 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>
- objects in both wheels.
- The rotation angle follows from the fact that the arc length
- of a rolling wheel equals the displacement of the center of
- the wheel, leading to a rotation angle</p>
- <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>
- </pre></div>
- </div>
- <p>With <code class="docutils literal"><span class="pre">w_1</span></code> tracking the <span class="math">\(x\)</span> coordinate of the center
- of the front wheel, we can rotate that wheel by</p>
- <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">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel1'</span><span class="p">]</span>
- <span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">degrees</span>
- <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>
- </pre></div>
- </div>
- <p>The <code class="docutils literal"><span class="pre">rotate</span></code> function takes two parameters: the rotation angle
- (in degrees) and the center point of the rotation, which is the
- center of the wheel in this case. The other wheel is rotated by</p>
- <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">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">]</span>
- <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>
- </pre></div>
- </div>
- <p>That is, the angle is the same, but the rotation point is different.
- 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>.
- The complete <code class="docutils literal"><span class="pre">move</span></code> function with translation of the entire
- vehicle and rotation of the wheels then becomes</p>
- <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>
- <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>
- <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>
- <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</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>
- <span class="c"># Rotate wheels</span>
- <span class="k">global</span> <span class="n">w_1</span>
- <span class="n">w_1</span> <span class="o">+=</span> <span class="n">x_displacement</span>
- <span class="c"># R*angle = -x_displacement</span>
- <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>
- <span class="n">w1</span> <span class="o">=</span> <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel1'</span><span class="p">]</span>
- <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>
- <span class="n">w2</span> <span class="o">=</span> <span class="n">fig</span><span class="p">[</span><span class="s">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">][</span><span class="s">'wheel2'</span><span class="p">]</span>
- <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>
- </pre></div>
- </div>
- <p>The complete example is found in the file
- <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>
- <p>The advantages with making figures this way, through programming
- rather than using interactive drawing programs, are numerous. For
- example, the objects are parameterized by variables so that various
- dimensions can easily be changed. Subparts of the figure, possible
- involving a lot of figure objects, can change color, linetype, filling
- or other properties through a <em>single</em> function call. Subparts of the
- figure can be rotated, translated, or scaled. Subparts of the figure
- can also be copied and moved to other parts of the drawing
- area. However, the single most important feature is probably the
- ability to make animations governed by mathematical formulas or data
- coming from physics simulations of the problem, as shown in the example above.</p>
- </div>
- </div>
- </div>
- <div class="section" id="a-simple-pendulum">
- <span id="sketcher-ex-pendulum"></span><h2>A simple pendulum<a class="headerlink" href="#a-simple-pendulum" title="Permalink to this headline">¶</a></h2>
- <div class="section" id="the-basic-physics-sketch">
- <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>
- <p>We now want to make a sketch of simple pendulum from physics, as shown
- in Figure <a class="reference internal" href="#sketcher-ex-pendulum-fig1"><span class="std std-ref">Sketch of a simple pendulum</span></a>. A suggested work flow is to
- first sketch the figure on a piece of paper and introduce a coordinate
- system. A simple coordinate system is indicated in Figure
- <a class="reference internal" href="#sketcher-ex-pendulum-fig1wgrid"><span class="std std-ref">Sketch of a simple pendulum</span></a>. In a code we introduce variables
- <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
- the coordinate system) and open the program like this:</p>
- <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>
- <span class="n">H</span> <span class="o">=</span> <span class="mf">7.</span>
- <span class="n">W</span> <span class="o">=</span> <span class="mf">6.</span>
- <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>
- <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>
- <span class="n">axis</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
- <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>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>Note that when the sketch is ready for “production”, we will (normally)
- set <code class="docutils literal"><span class="pre">axis=False</span></code> to remove the coordinate system and also remove the
- grid, i.e., delete or
- comment out the line <code class="docutils literal"><span class="pre">drawing_tool.set_grid(True)</span></code>.
- Also note that we in this example let all lines be blue by default.</p>
- <div class="figure" id="id9">
- <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: 400px;" /></a>
- <p class="caption"><span class="caption-text"><em>Sketch of a simple pendulum</em></span></p>
- </div>
- <div class="figure" id="id10">
- <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>
- <p class="caption"><span class="caption-text"><em>Sketch of a simple pendulum</em></span></p>
- </div>
- <p>The next step is to introduce variables for key quantities in the sketch.
- 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
- <code class="docutils literal"><span class="pre">a</span></code> be the angle the pendulum makes with the vertical (measured in degrees).
- We may set</p>
- <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>
- <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>
- <span class="n">a</span> <span class="o">=</span> <span class="mi">40</span> <span class="c"># angle</span>
- </pre></div>
- </div>
- <p>Be careful with integer division if you use Python 2! Fortunately, we
- 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
- are safe.</p>
- <p>What kind of objects do we need in this sketch? Looking at
- 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>
- <ol class="arabic simple">
- <li>a vertical, dashed line</li>
- <li>an arc with no text but dashed line to indicate the <em>path</em> of the
- mass</li>
- <li>an arc with name <span class="math">\(\theta\)</span> to indicate the <em>angle</em></li>
- <li>a line, here called <em>rod</em>, from the rotation point to the mass</li>
- <li>a blue, filled circle representing the <em>mass</em></li>
- <li>a text <span class="math">\(m\)</span> associated with the mass</li>
- <li>an indicator of the pendulum’s <em>length</em> <span class="math">\(L\)</span>, visualized as
- a line with two arrows tips and the text <span class="math">\(L\)</span></li>
- <li>a gravity vector with the text <span class="math">\(g\)</span></li>
- </ol>
- <p>Pysketcher has objects for each of these elements in our sketch.
- We start with the simplest element: the vertical line, going from
- <code class="docutils literal"><span class="pre">P</span></code> to <code class="docutils literal"><span class="pre">P</span></code> minus the length in <span class="math">\(y\)</span> direction:</p>
- <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>
- </pre></div>
- </div>
- <p>The path of the mass is an arc that can be made by
- Pysketcher’s <code class="docutils literal"><span class="pre">Arc</span></code> object:</p>
- <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>
- </pre></div>
- </div>
- <p>The first argument <code class="docutils literal"><span class="pre">P</span></code> is the center point, the second is the
- radius (<code class="docutils literal"><span class="pre">L</span></code> here), the next arguments is the start angle, here
- it starts at -90 degrees, while the next argument is the angle of
- the arc, here <code class="docutils literal"><span class="pre">a</span></code>.
- For the path of the mass, we also need an arc object, but this
- time with an associated text. Pysketcher has a specialized object
- for this purpose, <code class="docutils literal"><span class="pre">Arc_wText</span></code>, since placing the text manually can
- be somewhat cumbersome.</p>
- <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'$\theta$'</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>
- </pre></div>
- </div>
- <p>The arguments are as for <code class="docutils literal"><span class="pre">Arc</span></code> above, but the first one is the desired
- text. Remember to use a raw string since we want a LaTeX greek letter
- that contains a backslash.
- The <code class="docutils literal"><span class="pre">text_spacing</span></code> argument must often be tweaked. It is recommended
- to create only a few objects before rendering the sketch and then
- adjust spacings as one goes along.</p>
- <p>The rod is simply a line from <code class="docutils literal"><span class="pre">P</span></code> to the mass. We can easily
- compute the position of the mass from basic geometry considerations,
- but it is easier and safer to look up this point in other objects
- if it is already computed. The <code class="docutils literal"><span class="pre">path</span></code> object stores its start and
- end points, so <code class="docutils literal"><span class="pre">path.geometric_features()['end']</span></code> is the end point
- of the path, which is the position of the mass. We can therefore
- create the rod simply as a line from <code class="docutils literal"><span class="pre">P</span></code> to this end point:</p>
- <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">'end'</span><span class="p">]</span>
- <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>
- </pre></div>
- </div>
- <p>The mass is a circle filled with color:</p>
- <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>
- <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">'blue'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>To place the <span class="math">\(m\)</span> correctly, we go a small distance in the direction of
- the rod, from the center of the circle. To this end, we need to
- compute the direction. This is easiest done by computing a vector
- 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
- a unit vector in this direction:</p>
- <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">'end'</span><span class="p">]</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">'start'</span><span class="p">]</span>
- <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>
- <span class="n">mass_symbol</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">'$m$'</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>
- </pre></div>
- </div>
- <p>Again, the distance <code class="docutils literal"><span class="pre">L/10</span></code> is something one has to experiment with.</p>
- <p>The next object is the length measure with the text <span class="math">\(L\)</span>. Such length
- measures are represented by Pysketcher’s <code class="docutils literal"><span class="pre">Distance_wText</span></code> object.
- An easy construction is to first place this length measure along the
- rod and then translate it a little distance (<code class="docutils literal"><span class="pre">L/15</span></code>) in the
- normal direction of the rod:</p>
- <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">'$L$'</span><span class="p">)</span>
- <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>
- </pre></div>
- </div>
- <p>For this translation we need a unit vector in the normal direction
- of the rod, which is from geometric considerations given by
- <span class="math">\((\cos a, \sin a)\)</span>, when <span class="math">\(a\)</span> is the angle of the pendulum.</p>
- <p>The final object is the gravity force vector, which is so common
- in physics sketches that Pysketcher has a ready-made object: <code class="docutils literal"><span class="pre">Gravity</span></code>,</p>
- <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>
- </pre></div>
- </div>
- <p>Since blue is the default color for
- lines, we want the dashed lines (<code class="docutils literal"><span class="pre">vertical</span></code> and <code class="docutils literal"><span class="pre">path</span></code>) to be black
- and dashed with linewidth 1. These properties can be set one by one,
- but we can also make a little helper function:</p>
- <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>
- <span class="sd">"""Set linestyle of an object to dashed, black, width=1."""</span>
- <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
- <span class="n">obj</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">'dashed'</span><span class="p">)</span>
- <span class="n">obj</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'black'</span><span class="p">)</span>
- <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>
- <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>
- </pre></div>
- </div>
- <p>Now, all objects are in place, so it remains to compose the final
- figure and draw the composition:</p>
- <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="p">{</span><span class="s">'body'</span><span class="p">:</span> <span class="n">mass</span><span class="p">,</span> <span class="s">'rod'</span><span class="p">:</span> <span class="n">rod</span><span class="p">,</span>
- <span class="s">'vertical'</span><span class="p">:</span> <span class="n">vertical</span><span class="p">,</span> <span class="s">'theta'</span><span class="p">:</span> <span class="n">angle</span><span class="p">,</span> <span class="s">'path'</span><span class="p">:</span> <span class="n">path</span><span class="p">,</span>
- <span class="s">'g'</span><span class="p">:</span> <span class="n">gravity</span><span class="p">,</span> <span class="s">'L'</span><span class="p">:</span> <span class="n">length</span><span class="p">,</span> <span class="s">'m'</span><span class="p">:</span> <span class="n">mass_symbol</span><span class="p">})</span>
- <span class="n">fig</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">'pendulum1'</span><span class="p">)</span>
- </pre></div>
- </div>
- </div>
- <div class="section" id="the-body-diagram">
- <h3>The body diagram<a class="headerlink" href="#the-body-diagram" title="Permalink to this headline">¶</a></h3>
- <p>Now we want to isolate the mass and draw all the forces that act on it.
- 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
- embedded in the coordinate system.
- We consider three types of forces: the gravity force, the force from the
- rod, and air resistance. The body diagram is key for deriving the
- equation of motion, so it is illustrative to add useful mathematical
- quantities needed in the derivation, such as the unit vectors in polar
- coordinates.</p>
- <div class="figure" id="id11">
- <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: 400px;" /></a>
- <p class="caption"><span class="caption-text"><em>Body diagram of a simple pendulum</em></span></p>
- </div>
- <p>We start by listing the objects in the sketch:</p>
- <ol class="arabic simple">
- <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>
- <li>unit vector <span class="math">\(\boldsymbol{i}_r\)</span> with text</li>
- <li>unit vector <span class="math">\(\boldsymbol{i}_\theta\)</span> with text</li>
- <li>a dashed vertical line</li>
- <li>a dashed line along the rod</li>
- <li>an arc with text <span class="math">\(\theta\)</span></li>
- <li>the gravity force with text <span class="math">\(mg\)</span></li>
- <li>the force in the rod with text <span class="math">\(S\)</span></li>
- <li>the air resistance force with text <span class="math">\(\sim |v|v\)</span></li>
- </ol>
- <p>The first object, <span class="math">\((x_0,y_0)\)</span>, is simply a plain text where we have
- to experiment with the position. The unit vectors in polar coordinates
- may be drawn using the Pysketcher’s <code class="docutils literal"><span class="pre">Force</span></code> object since it has an
- arrow with a text. The first three object can then be made as follows:</p>
- <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">'$(x_0,y_0)$'</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>
- <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>
- <span class="s">r'$\boldsymbol{i}_r$'</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">'end'</span><span class="p">,</span>
- <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>
- <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>
- <span class="s">r'$\boldsymbol{i}_{\theta}$'</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">'end'</span><span class="p">,</span>
- <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>
- </pre></div>
- </div>
- <p>Note that tweaking of the position of <code class="docutils literal"><span class="pre">x0y0</span></code> use absolute coordinates, so
- 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
- will most likely not look good. A better solution would be to express
- 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>.
- 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
- coordinates. Very often, this is much more convenient when adjusting
- 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
- seldom changed.</p>
- <p>The vertical, dashed line, the dashed rod, and the arc for <span class="math">\(\theta\)</span>
- are made by</p>
- <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">'start'</span><span class="p">]</span> <span class="c"># Point P</span>
- <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>
- <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">vertical2</span><span class="p">)</span>
- <span class="n">set_dashed_thin_blackline</span><span class="p">(</span><span class="n">rod</span><span class="p">)</span>
- <span class="n">angle2</span> <span class="o">=</span> <span class="n">Arc_wText</span><span class="p">(</span><span class="s">r'$\theta$'</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>
- <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>
- </pre></div>
- </div>
- <p>Note how we reuse the earlier defined object <code class="docutils literal"><span class="pre">rod</span></code>.</p>
- <p>The forces are constructed as shown below.</p>
- <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>
- <span class="s">'$mg$'</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">'end'</span><span class="p">)</span>
- <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>
- <span class="s">'$S$'</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">'end'</span><span class="p">,</span>
- <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>
- <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>
- <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>
- <span class="s">'$\sim|v|v$'</span><span class="p">,</span> <span class="n">text_pos</span><span class="o">=</span><span class="s">'end'</span><span class="p">,</span>
- <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>
- </pre></div>
- </div>
- <p>All objects are in place, and we can compose a figure to be drawn:</p>
- <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>
- <span class="p">{</span><span class="s">'mg'</span><span class="p">:</span> <span class="n">mg_force</span><span class="p">,</span> <span class="s">'S'</span><span class="p">:</span> <span class="n">rod_force</span><span class="p">,</span> <span class="s">'rod'</span><span class="p">:</span> <span class="n">rod</span><span class="p">,</span>
- <span class="s">'vertical'</span><span class="p">:</span> <span class="n">vertical2</span><span class="p">,</span> <span class="s">'theta'</span><span class="p">:</span> <span class="n">angle2</span><span class="p">,</span>
- <span class="s">'body'</span><span class="p">:</span> <span class="n">mass</span><span class="p">,</span> <span class="s">'m'</span><span class="p">:</span> <span class="n">mass_symbol</span><span class="p">})</span>
- <span class="n">body_diagram</span><span class="p">[</span><span class="s">'air'</span><span class="p">]</span> <span class="o">=</span> <span class="n">air_force</span>
- <span class="n">body_diagram</span><span class="p">[</span><span class="s">'ir'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ir</span>
- <span class="n">body_diagram</span><span class="p">[</span><span class="s">'ith'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ith</span>
- <span class="n">body_diagram</span><span class="p">[</span><span class="s">'origin'</span><span class="p">]</span> <span class="o">=</span> <span class="n">x0y0</span>
- </pre></div>
- </div>
- <p>Here, we exemplify that we can start out with a composition as a
- dictionary, but (as in ordinary Python dictionaries) add new
- elements later when desired.</p>
- </div>
- </div>
- <div class="section" id="basic-shapes">
- <h2>Basic shapes<a class="headerlink" href="#basic-shapes" title="Permalink to this headline">¶</a></h2>
- <p>This section presents many of the basic shapes in Pysketcher:
- <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>,
- <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>.
- Each shape is demonstrated with a figure and a
- unit test that shows how the figure is constructed in Python code.
- These demos rely heavily on the method <code class="docutils literal"><span class="pre">draw_dimensions</span></code> in
- the shape classes, which annotates the basic drawing of the shape
- with the various geometric parameters that govern the shape.</p>
- <div class="section" id="axis">
- <h3>Axis<a class="headerlink" href="#axis" title="Permalink to this headline">¶</a></h3>
- <p>The <code class="docutils literal"><span class="pre">Axis</span></code> object gives the possibility draw a single axis to
- notify a coordinate system. Here is an example where we
- draw <span class="math">\(x\)</span> and <span class="math">\(y\)</span> axis of three coordinate systems of different
- rotation:</p>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <div class="figure">
- <a class="reference internal image-reference" href="_images/Axis.png"><img alt="_images/Axis.png" src="_images/Axis.png" style="width: 500px;" /></a>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>The corresponding code looks like this:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Axis</span><span class="p">():</span>
- <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="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>
- <span class="n">instruction_file</span><span class="o">=</span><span class="s">'tmp_Axis.py'</span><span class="p">)</span>
- <span class="c"># Draw normal x and y axis with origin at (7.5, 2)</span>
- <span class="c"># in the coordinate system of the sketch: [0,15]x[-7,8]</span>
- <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">'x'</span><span class="p">,</span> <span class="n">rotation_angle</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
- <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">'y'</span><span class="p">,</span> <span class="n">rotation_angle</span><span class="o">=</span><span class="mi">90</span><span class="p">)</span>
- <span class="n">system</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">'x axis'</span><span class="p">:</span> <span class="n">x_axis</span><span class="p">,</span> <span class="s">'y axis'</span><span class="p">:</span> <span class="n">y_axis</span><span class="p">})</span>
- <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- <span class="c"># Rotate this system 40 degrees counter clockwise</span>
- <span class="c"># and draw it with dashed lines</span>
- <span class="n">system</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">'dashed'</span><span class="p">)</span>
- <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>
- <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- <span class="c"># Rotate this system another 220 degrees and show</span>
- <span class="c"># with dotted lines</span>
- <span class="n">system</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">'dotted'</span><span class="p">)</span>
- <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>
- <span class="n">system</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">'Axis'</span><span class="p">)</span>
- </pre></div>
- </div>
- </div>
- <div class="section" id="distance-with-text">
- <h3>Distance with text<a class="headerlink" href="#distance-with-text" title="Permalink to this headline">¶</a></h3>
- <p>The object <code class="docutils literal"><span class="pre">Distance_wText</span></code> is used to display an arrow, to indicate
- a distance in a sketch, with an additional text in the middle of the arrow.</p>
- <p>The figure</p>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <div class="figure">
- <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>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>was produced by this code:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Distance_wText</span><span class="p">():</span>
- <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="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>
- <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">'tmp_Distance_wText.py'</span><span class="p">)</span>
- <span class="n">fontsize</span><span class="o">=</span><span class="mi">14</span>
- <span class="n">t</span> <span class="o">=</span> <span class="s">r'$ 2\pi R^2 $'</span> <span class="c"># sample text</span>
- <span class="n">examples</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span>
- <span class="s">'a0'</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>
- <span class="s">'a6'</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>
- <span class="s">'a1'</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>
- <span class="s">'a2'</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>
- <span class="s">'a3'</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>
- <span class="s">'a4'</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>
- <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>
- <span class="s">'a5'</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>
- <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">'right'</span><span class="p">),</span>
- <span class="s">'c1'</span><span class="p">:</span> <span class="n">Text_wArrow</span><span class="p">(</span><span class="s">'text_spacing=-1./60'</span><span class="p">,</span>
- <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>
- <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">'left'</span><span class="p">),</span>
- <span class="s">'c2'</span><span class="p">:</span> <span class="n">Text_wArrow</span><span class="p">(</span><span class="s">'text_spacing=-1./40, alignment="right"'</span><span class="p">,</span>
- <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>
- <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">'left'</span><span class="p">),</span>
- <span class="p">})</span>
- <span class="n">examples</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">'Distance_wText and text positioning'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>Note the use of <code class="docutils literal"><span class="pre">Text_wArrow</span></code> to write an explaining text with an
- associated arrow, here used to explain how
- 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
- the appearance of the text that goes with the distance arrow.</p>
- </div>
- <div class="section" id="rectangle">
- <h3>Rectangle<a class="headerlink" href="#rectangle" title="Permalink to this headline">¶</a></h3>
- <div class="figure">
- <a class="reference internal image-reference" href="_images/Rectangle.png"><img alt="_images/Rectangle.png" src="_images/Rectangle.png" style="width: 500px;" /></a>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>The above figure can be produced by the following code.</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Rectangle</span><span class="p">():</span>
- <span class="n">L</span> <span class="o">=</span> <span class="mf">3.0</span>
- <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
- <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="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>
- <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">'tmp_Rectangle.py'</span><span class="p">)</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- <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>
- <span class="n">xpos</span> <span class="o">=</span> <span class="n">W</span><span class="o">/</span><span class="mi">2</span>
- <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>
- <span class="n">r</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">r</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">'Rectangle'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>Note that the <code class="docutils literal"><span class="pre">draw_dimension</span></code> method adds explanation of dimensions and various
- important argument in the construction of a shape. It adapts the annotations
- to the geometry of the current shape.</p>
- </div>
- <div class="section" id="triangle">
- <h3>Triangle<a class="headerlink" href="#triangle" title="Permalink to this headline">¶</a></h3>
- <div class="figure">
- <a class="reference internal image-reference" href="_images/Triangle.png"><img alt="_images/Triangle.png" src="_images/Triangle.png" style="width: 500px;" /></a>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>The code below produces the figure.</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Triangle</span><span class="p">():</span>
- <span class="n">L</span> <span class="o">=</span> <span class="mf">3.0</span>
- <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
- <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="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>
- <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">'tmp_Triangle.py'</span><span class="p">)</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- <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>
- <span class="n">xpos</span> <span class="o">=</span> <span class="mi">1</span>
- <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>
- <span class="n">t</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">t</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">'Triangle'</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>Here, the <code class="docutils literal"><span class="pre">draw_dimension</span></code> method writes the name of the corners at the
- position of the corners, which does not always look nice (the present figure
- is an example). For a high-quality sketch one would add some spacing
- to the location of the p1, p2, and even p3 texts.</p>
- </div>
- <div class="section" id="arc">
- <h3>Arc<a class="headerlink" href="#arc" title="Permalink to this headline">¶</a></h3>
- <div class="figure">
- <a class="reference internal image-reference" href="_images/Arc.png"><img alt="_images/Arc.png" src="_images/Arc.png" style="width: 400px;" /></a>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>An arc like the one above is produced by</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Arc</span><span class="p">():</span>
- <span class="n">L</span> <span class="o">=</span> <span class="mf">4.0</span>
- <span class="n">W</span> <span class="o">=</span> <span class="mf">4.0</span>
- <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="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>
- <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">'tmp_Arc.py'</span><span class="p">)</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- <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>
- <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>
- <span class="n">radius</span> <span class="o">=</span> <span class="n">L</span><span class="o">/</span><span class="mi">2</span>
- <span class="n">start_angle</span> <span class="o">=</span> <span class="mi">60</span>
- <span class="n">arc_angle</span> <span class="o">=</span> <span class="mi">45</span>
- <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>
- <span class="n">a</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">R1</span> <span class="o">=</span> <span class="mf">1.25</span><span class="o">*</span><span class="n">radius</span>
- <span class="n">R2</span> <span class="o">=</span> <span class="mf">1.5</span><span class="o">*</span><span class="n">radius</span>
- <span class="n">R</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">radius</span>
- <span class="n">a</span><span class="o">.</span><span class="n">dimensions</span> <span class="o">=</span> <span class="p">{</span>
- <span class="s">'start_angle'</span><span class="p">:</span>
- <span class="n">Arc_wText</span><span class="p">(</span>
- <span class="s">'start_angle'</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>
- <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>
- <span class="s">'arc_angle'</span><span class="p">:</span>
- <span class="n">Arc_wText</span><span class="p">(</span>
- <span class="s">'arc_angle'</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>
- <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>
- <span class="s">'r=0'</span><span class="p">:</span>
- <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>
- <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>
- <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>
- <span class="s">'r=start_angle'</span><span class="p">:</span>
- <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>
- <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>
- <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>
- <span class="s">'r=start+arc_angle'</span><span class="p">:</span>
- <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>
- <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">'dashed'</span><span class="p">),</span>
- <span class="s">'radius'</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">'radius'</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>
- <span class="s">'center'</span><span class="p">:</span> <span class="n">Text</span><span class="p">(</span><span class="s">'center'</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>
- <span class="p">}</span>
- <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>
- <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">'r='</span><span class="p">):</span>
- <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>
- <span class="n">dim</span><span class="o">.</span><span class="n">set_linestyle</span><span class="p">(</span><span class="s">'dashed'</span><span class="p">)</span>
- <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>
- <span class="n">dim</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'black'</span><span class="p">)</span>
- <span class="n">a</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">'Arc'</span><span class="p">)</span>
- </pre></div>
- </div>
- </div>
- <div class="section" id="spring">
- <h3>Spring<a class="headerlink" href="#spring" title="Permalink to this headline">¶</a></h3>
- <div class="figure">
- <a class="reference internal image-reference" href="_images/Spring.png"><img alt="_images/Spring.png" src="_images/Spring.png" style="width: 800px;" /></a>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>The code for making these two springs goes like this:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Spring</span><span class="p">():</span>
- <span class="n">L</span> <span class="o">=</span> <span class="mf">5.0</span>
- <span class="n">W</span> <span class="o">=</span> <span class="mf">2.0</span>
- <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="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>
- <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">'tmp_Spring.py'</span><span class="p">)</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- <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>
- <span class="n">xpos</span> <span class="o">=</span> <span class="n">W</span>
- <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>
- <span class="n">s1_title</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">'Default Spring'</span><span class="p">,</span>
- <span class="n">s1</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">'end'</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>
- <span class="n">s1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">s1_title</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="c">#s1.draw_dimensions()</span>
- <span class="n">xpos</span> <span class="o">+=</span> <span class="mi">3</span><span class="o">*</span><span class="n">W</span>
- <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>
- <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>
- <span class="n">s2</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">s2</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">'Spring'</span><span class="p">)</span>
- </pre></div>
- </div>
- </div>
- <div class="section" id="dashpot">
- <h3>Dashpot<a class="headerlink" href="#dashpot" title="Permalink to this headline">¶</a></h3>
- <div class="figure">
- <a class="reference internal image-reference" href="_images/Dashpot.png"><img alt="_images/Dashpot.png" src="_images/Dashpot.png" style="width: 600px;" /></a>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>This dashpot is produced by</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">test_Dashpot</span><span class="p">():</span>
- <span class="n">L</span> <span class="o">=</span> <span class="mf">5.0</span>
- <span class="n">W</span> <span class="o">=</span> <span class="mf">2.0</span>
- <span class="n">xpos</span> <span class="o">=</span> <span class="mi">0</span>
- <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="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>
- <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">'tmp_Dashpot.py'</span><span class="p">)</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- <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>
- <span class="c"># Default (simple) dashpot</span>
- <span class="n">xpos</span> <span class="o">=</span> <span class="mf">1.5</span>
- <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>
- <span class="n">d1_title</span> <span class="o">=</span> <span class="n">Text</span><span class="p">(</span><span class="s">'Dashpot (default)'</span><span class="p">,</span>
- <span class="n">d1</span><span class="o">.</span><span class="n">geometric_features</span><span class="p">()[</span><span class="s">'end'</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>
- <span class="n">d1</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">d1_title</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="c"># Dashpot for animation with fixed bar_length, dashpot_length and</span>
- <span class="c"># prescribed piston_pos</span>
- <span class="n">xpos</span> <span class="o">+=</span> <span class="mf">2.5</span><span class="o">*</span><span class="n">W</span>
- <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>
- <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>
- <span class="n">d2</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">d2</span><span class="o">.</span><span class="n">draw_dimensions</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="s">'Dashpot'</span><span class="p">)</span>
- </pre></div>
- </div>
- </div>
- <div class="section" id="wavy">
- <h3>Wavy<a class="headerlink" href="#wavy" title="Permalink to this headline">¶</a></h3>
- <p>Looks strange. Fix x axis.</p>
- </div>
- <div class="section" id="stochastic-curves">
- <h3>Stochastic curves<a class="headerlink" href="#stochastic-curves" title="Permalink to this headline">¶</a></h3>
- <p>The <code class="docutils literal"><span class="pre">StochasticWavyCurve</span></code> object offers three precomputed
- graphics that have a random variation:</p>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <div class="figure">
- <a class="reference internal image-reference" href="_images/StochasticWavyCurve.png"><img alt="_images/StochasticWavyCurve.png" src="_images/StochasticWavyCurve.png" style="width: 600px;" /></a>
- </div>
- <div class="line-block">
- <div class="line"><br /></div>
- <div class="line"><br /></div>
- </div>
- <p>The usage is simple. The construction</p>
- <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>
- </pre></div>
- </div>
- <p>picks the second curve (the three are numbered 0, 1, and 2),
- and the first 40% of that curve. In case one desires another extent
- of the axis, one can just scale the coordinates directly as these
- are stored in the arrays <code class="docutils literal"><span class="pre">curve.x[curve_no]</span></code> and
- <code class="docutils literal"><span class="pre">curve.y[curve_no]</span></code>.</p>
- </div>
- </div>
- <div class="section" id="inner-workings-of-the-pysketcher-tool">
- <h2>Inner workings of the Pysketcher tool<a class="headerlink" href="#inner-workings-of-the-pysketcher-tool" title="Permalink to this headline">¶</a></h2>
- <p>We shall now explain how we can, quite easily, realize software with
- the capabilities demonstrated in the previous examples. Each object in
- the figure is represented as a class in a class hierarchy. Using
- inheritance, classes can inherit properties from parent classes and
- add new geometric features.</p>
- <p id="index-0">Class programming is a key technology for realizing Pysketcher.
- As soon as some classes are established, more are easily
- added. Enhanced functionality for all the classes is also easy to
- implement in common, generic code that can immediately be shared by
- all present and future classes. The fundamental data structure
- involved in the <code class="docutils literal"><span class="pre">pysketcher</span></code> package is a hierarchical tree, and much
- of the material on implementation issues targets how to traverse tree
- structures with recursive function calls in object hierarchies. This
- topic is of key relevance in a wide range of other applications as
- well. In total, the inner workings of Pysketcher constitute an
- excellent example on the power of class programming.</p>
- <div class="section" id="example-of-classes-for-geometric-objects">
- <h3>Example of classes for geometric objects<a class="headerlink" href="#example-of-classes-for-geometric-objects" title="Permalink to this headline">¶</a></h3>
- <p>We introduce class <code class="docutils literal"><span class="pre">Shape</span></code> as superclass for all specialized objects
- in a figure. This class does not store any data, but provides a
- series of functions that add functionality to all the subclasses.
- This will be shown later.</p>
- <div class="section" id="simple-geometric-objects">
- <h4>Simple geometric objects<a class="headerlink" href="#simple-geometric-objects" title="Permalink to this headline">¶</a></h4>
- <p>One simple subclass is <code class="docutils literal"><span class="pre">Rectangle</span></code>, specified by the coordinates of
- the lower left corner and its width and height:</p>
- <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>
- <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>
- <span class="n">p</span> <span class="o">=</span> <span class="n">lower_left_corner</span> <span class="c"># short form</span>
- <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>
- <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>
- <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>
- <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>
- <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">'rectangle'</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>
- </pre></div>
- </div>
- <p>Any subclass of <code class="docutils literal"><span class="pre">Shape</span></code> will have a constructor that takes geometric
- information about the shape of the object and creates a dictionary
- <code class="docutils literal"><span class="pre">self.shapes</span></code> with the shape built of simpler shapes. The most
- 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>
- 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
- 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>
- and <code class="docutils literal"><span class="pre">y</span></code> arrays contain the corner points of the rectangle in
- counterclockwise direction, starting and ending with in the lower left
- corner.</p>
- <p>Class <code class="docutils literal"><span class="pre">Line</span></code> is also a simple class:</p>
- <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>
- <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>
- <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>
- <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>
- <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">'line'</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>
- </pre></div>
- </div>
- <p>Here we only need two points, the start and end point on the line.
- However, we may want to add some useful functionality, e.g., the ability
- to give an <span class="math">\(x\)</span> coordinate and have the class calculate the
- corresponding <span class="math">\(y\)</span> coordinate:</p>
- <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>
- <span class="sd">"""Given x, return y on the line."""</span>
- <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">'line'</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">'line'</span><span class="p">]</span><span class="o">.</span><span class="n">y</span>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- <p>Unfortunately, this is too simplistic because vertical lines cannot be
- 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
- provides a more general solution at the cost of significantly longer
- code with more tests.</p>
- <p>A circle implies a somewhat increased complexity. Again we represent
- 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>
- object needs to store a large number of points on the curve such that
- a plotting program produces a visually smooth curve. The points on
- the circle must be calculated manually in the constructor of class
- <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>
- and center at <span class="math">\((x_0, y_0)\)</span> are given by</p>
- <div class="math">
- \[\begin{split}x &= x_0 + R\cos (t),\\
- y &= y_0 + R\sin (t),\end{split}\]</div>
- <p>where <span class="math">\(t\in [0, 2\pi]\)</span>. A discrete set of <span class="math">\(t\)</span> values in this
- interval gives the corresponding set of <span class="math">\((x,y)\)</span> coordinates on
- the circle. The user must specify the resolution as the number
- of <span class="math">\(t\)</span> values. The circle’s radius and center must of course
- also be specified.</p>
- <p>We can write the <code class="docutils literal"><span class="pre">Circle</span></code> class as</p>
- <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>
- <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>
- <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>
- <span class="bp">self</span><span class="o">.</span><span class="n">resolution</span> <span class="o">=</span> <span class="n">resolution</span>
- <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>
- <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>
- <span class="n">R</span> <span class="o">=</span> <span class="n">radius</span>
- <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>
- <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>
- <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">'circle'</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>
- </pre></div>
- </div>
- <p>As in class <code class="docutils literal"><span class="pre">Line</span></code> we can offer the possibility to give an angle
- <span class="math">\(\theta\)</span> (equivalent to <span class="math">\(t\)</span> in the formulas above)
- and then get the corresponding <span class="math">\(x\)</span> and <span class="math">\(y\)</span> coordinates:</p>
- <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>
- <span class="sd">"""Return (x, y) point corresponding to angle theta."""</span>
- <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> \
- <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>
- </pre></div>
- </div>
- <p>There is one flaw with this method: it yields illegal values after
- a translation, scaling, or rotation of the circle.</p>
- <p>A part of a circle, an arc, is a frequent geometric object when
- drawing mechanical systems. The arc is constructed much like
- a circle, but <span class="math">\(t\)</span> runs in <span class="math">\([\theta_s, \theta_s + \theta_a]\)</span>. Giving
- <span class="math">\(\theta_s\)</span> and <span class="math">\(\theta_a\)</span> the slightly more descriptive names
- <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>
- <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>
- <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">start_angle</span><span class="p">,</span> <span class="n">arc_angle</span><span class="p">,</span>
- <span class="n">resolution</span><span class="o">=</span><span class="mi">180</span><span class="p">):</span>
- <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>
- <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>
- <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>
- <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>
- <span class="n">resolution</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
- <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>
- <span class="n">R</span> <span class="o">=</span> <span class="n">radius</span>
- <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>
- <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>
- <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">'arc'</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>
- </pre></div>
- </div>
- <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
- a subclass specializing the arc to a circle:</p>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- </div>
- <div class="section" id="class-curve">
- <h4>Class curve<a class="headerlink" href="#class-curve" title="Permalink to this headline">¶</a></h4>
- <p>Class <code class="docutils literal"><span class="pre">Curve</span></code> sits on the coordinates to be drawn, but how is that
- done? The constructor of class <code class="docutils literal"><span class="pre">Curve</span></code> just stores the coordinates,
- while a method <code class="docutils literal"><span class="pre">draw</span></code> sends the coordinates to the plotting program to
- make a graph. Or more precisely, to avoid a lot of (e.g.)
- Matplotlib-specific plotting commands in class <code class="docutils literal"><span class="pre">Curve</span></code> we have created
- a small layer with a simple programming interface to plotting
- programs. This makes it straightforward to change from Matplotlib to
- another plotting program. The programming interface is represented by
- the <code class="docutils literal"><span class="pre">drawing_tool</span></code> object and has a few functions:</p>
- <blockquote>
- <div><ul class="simple">
- <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
- to the plotting program,</li>
- <li><code class="docutils literal"><span class="pre">set_coordinate_system</span></code> for specifying the graphics area,</li>
- <li><code class="docutils literal"><span class="pre">erase</span></code> for deleting all elements of the graph,</li>
- <li><code class="docutils literal"><span class="pre">set_grid</span></code> for turning on a grid (convenient while constructing the figure),</li>
- <li><code class="docutils literal"><span class="pre">set_instruction_file</span></code> for creating a separate file with all
- plotting commands (Matplotlib commands in our case),</li>
- <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
- <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>
- </ul>
- </div></blockquote>
- <p>This is basically all we need to communicate to a plotting program.</p>
- <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
- setting properties of curves. This information is propagated to
- all other shape objects in the <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary. Class
- <code class="docutils literal"><span class="pre">Curve</span></code> stores the line properties together with the coordinates
- of its curve and propagates this information to the plotting program.
- When saying <code class="docutils literal"><span class="pre">vehicle.set_linewidth(10)</span></code>, all objects that make
- 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,
- but only the <code class="docutils literal"><span class="pre">Curve</span></code> object at the end of the chain will actually
- store the information and send it to the plotting program.</p>
- <p>A rough sketch of class <code class="docutils literal"><span class="pre">Curve</span></code> reads</p>
- <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>
- <span class="sd">"""General curve as a sequence of (x,y) coordintes."""</span>
- <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>
- <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>
- <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>
- <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">plot_curve</span><span class="p">(</span>
- <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>
- <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>
- <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>
- <span class="bp">self</span><span class="o">.</span><span class="n">linewidth</span> <span class="o">=</span> <span class="n">width</span>
- <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>
- <span class="bp">self</span><span class="o">.</span><span class="n">linestyle</span> <span class="o">=</span> <span class="n">style</span>
- <span class="o">...</span>
- </pre></div>
- </div>
- </div>
- <div class="section" id="compound-geometric-objects">
- <h4>Compound geometric objects<a class="headerlink" href="#compound-geometric-objects" title="Permalink to this headline">¶</a></h4>
- <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
- shape through just one <code class="docutils literal"><span class="pre">Curve</span></code> object. More complicated shapes are
- built from instances of various subclasses of <code class="docutils literal"><span class="pre">Shape</span></code>. Classes used
- for professional drawings soon get quite complex in composition and
- have a lot of geometric details, so here we prefer to make a very
- simple composition: the already drawn vehicle from Figure
- <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
- in a Python program as shown above, we make a subclass <code class="docutils literal"><span class="pre">Vehicle0</span></code> in
- the <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy for doing the same thing.</p>
- <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
- classes or derive a new one, we need to import <code class="docutils literal"><span class="pre">pysketcher</span></code>. The constructor
- of class <code class="docutils literal"><span class="pre">Vehicle0</span></code> performs approximately the same statements as
- in the example program we developed for making the drawing in
- Figure <a class="reference internal" href="#sketcher-fig-vehicle0"><span class="std std-ref">Sketch of a simple figure</span></a>.</p>
- <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>
- <span class="k">class</span> <span class="nc">Vehicle0</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
- <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>
- <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>
- <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>
- <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>
- <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>
- <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>
- <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>
- <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>
- <span class="n">wheels</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
- <span class="p">{</span><span class="s">'wheel1'</span><span class="p">:</span> <span class="n">wheel1</span><span class="p">,</span> <span class="s">'wheel2'</span><span class="p">:</span> <span class="n">wheel2</span><span class="p">})</span>
- <span class="n">body</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">(</span>
- <span class="p">{</span><span class="s">'under'</span><span class="p">:</span> <span class="n">under</span><span class="p">,</span> <span class="s">'over'</span><span class="p">:</span> <span class="n">over</span><span class="p">})</span>
- <span class="n">vehicle</span> <span class="o">=</span> <span class="n">Composition</span><span class="p">({</span><span class="s">'wheels'</span><span class="p">:</span> <span class="n">wheels</span><span class="p">,</span> <span class="s">'body'</span><span class="p">:</span> <span class="n">body</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="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>
- <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">'vehicle'</span><span class="p">:</span> <span class="n">vehicle</span><span class="p">,</span> <span class="s">'ground'</span><span class="p">:</span> <span class="n">ground</span><span class="p">}</span>
- </pre></div>
- </div>
- <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
- the inherited <code class="docutils literal"><span class="pre">draw</span></code> method (and a lot of other methods too) will
- not work.</p>
- <p>The painting of the vehicle, as shown in the right part of
- 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>
- be offered by a method:</p>
- <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>
- <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">'vehicle'</span><span class="p">][</span><span class="s">'wheels'</span><span class="p">]</span>
- <span class="n">wheels</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span>
- <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>
- <span class="n">wheels</span><span class="o">.</span><span class="n">set_linecolor</span><span class="p">(</span><span class="s">'black'</span><span class="p">)</span>
- <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">'vehicle'</span><span class="p">][</span><span class="s">'body'</span><span class="p">][</span><span class="s">'under'</span><span class="p">]</span>
- <span class="n">under</span><span class="o">.</span><span class="n">set_filled_curves</span><span class="p">(</span><span class="s">'red'</span><span class="p">)</span>
- <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">'vehicle'</span><span class="p">][</span><span class="s">'body'</span><span class="p">][</span><span class="s">'over'</span><span class="p">]</span>
- <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">'/'</span><span class="p">)</span>
- <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>
- </pre></div>
- </div>
- <p>The usage of the class is simple: after having set up an appropriate
- coordinate system as previously shown, we can do</p>
- <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>
- <span class="n">vehicle</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- </pre></div>
- </div>
- <p>and go on the make a painted version by</p>
- <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>
- <span class="n">vehicle</span><span class="o">.</span><span class="n">colorful</span><span class="p">()</span>
- <span class="n">vehicle</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">drawing_tool</span><span class="o">.</span><span class="n">display</span><span class="p">()</span>
- </pre></div>
- </div>
- <p>A complete code defining and using class <code class="docutils literal"><span class="pre">Vehicle0</span></code> is found in the file
- <a class="reference external" href="http://tinyurl.com/ot733jn/vehicle2.py">vehicle2.py</a>.</p>
- <p>The <code class="docutils literal"><span class="pre">pysketcher</span></code> package contains a wide range of classes for various
- geometrical objects, particularly those that are frequently used in
- drawings of mechanical systems.</p>
- </div>
- </div>
- <div class="section" id="adding-functionality-via-recursion">
- <h3>Adding functionality via recursion<a class="headerlink" href="#adding-functionality-via-recursion" title="Permalink to this headline">¶</a></h3>
- <p id="index-1">The really powerful feature of our class hierarchy is that we can add
- much functionality to the superclass <code class="docutils literal"><span class="pre">Shape</span></code> and to the “bottom” class
- <code class="docutils literal"><span class="pre">Curve</span></code>, and then all other classes for various types of geometrical shapes
- immediately get the new functionality. To explain the idea we may
- 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>
- hierarchy must have. The inner workings of the <code class="docutils literal"><span class="pre">draw</span></code> method explain
- the secrets of how a series of other useful operations on figures
- can be implemented.</p>
- <div class="section" id="basic-principles-of-recursion">
- <h4>Basic principles of recursion<a class="headerlink" href="#basic-principles-of-recursion" title="Permalink to this headline">¶</a></h4>
- <p>Note that we work with two types of hierarchies in the
- present documentation: one Python <em>class hierarchy</em>,
- with <code class="docutils literal"><span class="pre">Shape</span></code> as superclass, and one <em>object hierarchy</em> of figure elements
- in a specific figure. A subclass of <code class="docutils literal"><span class="pre">Shape</span></code> stores its figure in the
- <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary. This dictionary represents the object hierarchy
- of figure elements for that class. We want to make one <code class="docutils literal"><span class="pre">draw</span></code> call
- for an instance, say our class <code class="docutils literal"><span class="pre">Vehicle0</span></code>, and then we want this call
- to be propagated to <em>all</em> objects that are contained in
- <code class="docutils literal"><span class="pre">self.shapes</span></code> and all is nested subdictionaries. How is this done?</p>
- <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
- in the <code class="docutils literal"><span class="pre">self.shapes</span></code> dictionary:</p>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- <p>This general method can be provided by class <code class="docutils literal"><span class="pre">Shape</span></code> and inherited in
- 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.
- Seemingly, a call <code class="docutils literal"><span class="pre">v.draw()</span></code> just calls</p>
- <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">'vehicle'</span><span class="p">]</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- <span class="n">v</span><span class="o">.</span><span class="n">shapes</span><span class="p">[</span><span class="s">'ground'</span><span class="p">]</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
- </pre></div>
- </div>
- <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
- 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>.
- 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
- 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>.
- 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>
- method, which will run through <code class="docutils literal"><span class="pre">self.shapes</span></code>, now containing
- 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>,
- 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>,
- but this is the same <code class="docutils literal"><span class="pre">draw</span></code> method as shown above. This method will
- therefore traverse the circle’s <code class="docutils literal"><span class="pre">shapes</span></code> dictionary, which we have seen
- consists of one <code class="docutils literal"><span class="pre">Curve</span></code> element.</p>
- <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>
- really needs to do something “physical”, namely send the coordinates to
- the plotting program. The <code class="docutils literal"><span class="pre">draw</span></code> method is outlined in the short listing
- of class <code class="docutils literal"><span class="pre">Curve</span></code> shown previously.</p>
- <p>We can go to any of the other shape objects that appear in the figure
- hierarchy and follow their <code class="docutils literal"><span class="pre">draw</span></code> calls in the similar way. Every time,
- 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
- a <code class="docutils literal"><span class="pre">Curve</span></code> object at the “bottom” of the figure hierarchy, and then that part
- of the figure is really plotted (or more precisely, the coordinates
- are sent to a plotting program).</p>
- <p>When a method calls itself, such as <code class="docutils literal"><span class="pre">draw</span></code> does, the calls are known as
- <em>recursive</em> and the programming principle is referred to as
- <em>recursion</em>. This technique is very often used to traverse hierarchical
- structures like the figure structures we work with here. Even though the
- hierarchy of objects building up a figure are of different types, they
- all inherit the same <code class="docutils literal"><span class="pre">draw</span></code> method and therefore exhibit the same
- behavior with respect to drawing. Only the <code class="docutils literal"><span class="pre">Curve</span></code> object has a different
- <code class="docutils literal"><span class="pre">draw</span></code> method, which does not lead to more recursion.</p>
- </div>
- <div class="section" id="explaining-recursion">
- <h4>Explaining recursion<a class="headerlink" href="#explaining-recursion" title="Permalink to this headline">¶</a></h4>
- <p>Understanding recursion is usually a challenge. To get a better idea of
- 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>
- that just visits all the objects in the <code class="docutils literal"><span class="pre">shapes</span></code> dictionary and prints
- out a message for each object.
- This feature allows us to trace the execution and see exactly where
- we are in the hierarchy and which objects that are visited.</p>
- <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>
- <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>
- <span class="c"># print message where we are (name is where we come from)</span>
- <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>
- <span class="c"># print message about which object to visit</span>
- <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>
- </pre></div>
- </div>
- <p>The <code class="docutils literal"><span class="pre">indent</span></code> parameter governs how much the message from this
- <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
- level in the hierarchy, i.e., every row of objects in Figure
- <span class="xref std std-ref">sketcher:fig:Vehicle0:hier2</span>. This indentation makes it easy to
- see on the printout how far down in the hierarchy we are.</p>
- <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
- 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>,
- will be</p>
- <div class="highlight-text"><div class="highlight"><pre>Composition: body.shapes has entries 'over', 'under'
- call body.shapes["over"].recurse("over", 6)
- </pre></div>
- </div>
- <p>The number of leading blanks on each line corresponds to the value of
- <code class="docutils literal"><span class="pre">indent</span></code>. The code printing out such messages looks like</p>
- <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>
- <span class="n">space</span> <span class="o">=</span> <span class="s">' '</span><span class="o">*</span><span class="n">indent</span>
- <span class="k">print</span> <span class="n">space</span><span class="p">,</span> <span class="s">'</span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">.shapes has entries'</span> <span class="o">%</span> \
- <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> \
- <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>
- <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>
- <span class="k">print</span> <span class="n">space</span><span class="p">,</span>
- <span class="k">print</span> <span class="s">'call </span><span class="si">%s</span><span class="s">.shapes["</span><span class="si">%s</span><span class="s">"].recurse("</span><span class="si">%s</span><span class="s">", </span><span class="si">%d</span><span class="s">)'</span> <span class="o">%</span> \
- <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>
- <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>
- </pre></div>
- </div>
- <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
- 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>,
- let us get an overview of the figure hierarchy in the <code class="docutils literal"><span class="pre">v</span></code> object
- (as produced by <code class="docutils literal"><span class="pre">print</span> <span class="pre">v</span></code>)</p>
- <div class="highlight-text"><div class="highlight"><pre>ground
- wall
- vehicle
- body
- over
- rectangle
- under
- rectangle
- wheels
- wheel1
- arc
- wheel2
- arc
- </pre></div>
- </div>
- <p>The <code class="docutils literal"><span class="pre">recurse</span></code> method performs the same kind of traversal of the
- hierarchy, but writes out and explains a lot more.</p>
- <p>The data structure represented by <code class="docutils literal"><span class="pre">v.shapes</span></code> is known as a <em>tree</em>.
- As in physical trees, there is a <em>root</em>, here the <code class="docutils literal"><span class="pre">v.shapes</span></code>
- dictionary. A graphical illustration of the tree (upside down) is
- shown in Figure <span class="xref std std-ref">sketcher:fig:Vehicle0:hier2</span>.
- From the root there are one or more branches, here two:
- <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
- 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
- are often used to describe the relations in object trees too: we say
- 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
- <code class="docutils literal"><span class="pre">vehicle</span></code>. The term <em>node</em> is also often used to describe an element
- in a tree. A node may have several other nodes as <em>descendants</em>.</p>
- <div class="figure" id="id12">
- <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>
- <p class="caption"><span class="caption-text"><em>Hierarchy of figure elements in an instance of class `Vehicle0`</em></span></p>
- </div>
- <p>Recursion is the principal programming technique to traverse tree structures.
- Any object in the tree can be viewed as a root of a subtree. For
- example, <code class="docutils literal"><span class="pre">wheels</span></code> is the root of a subtree that branches into
- <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,
- we imagine we process the root and then recurse into a subtree, but the
- first object we recurse into can be viewed as the root of the subtree, so the
- processing procedure of the parent object can be repeated.</p>
- <p>A recommended next step is to simulate the <code class="docutils literal"><span class="pre">recurse</span></code> method by hand and
- carefully check that what happens in the visits to <code class="docutils literal"><span class="pre">recurse</span></code> is
- consistent with the output listed below. Although tedious, this is
- a major exercise that guaranteed will help to demystify recursion.</p>
- <p>A part of the printout of <code class="docutils literal"><span class="pre">v.recurse('vehicle')</span></code> looks like</p>
- <div class="highlight-text"><div class="highlight"><pre> Vehicle0: vehicle.shapes has entries 'ground', 'vehicle'
- call vehicle.shapes["ground"].recurse("ground", 2)
- Wall: ground.shapes has entries 'wall'
- call ground.shapes["wall"].recurse("wall", 4)
- reached "bottom" object Curve
- call vehicle.shapes["vehicle"].recurse("vehicle", 2)
- Composition: vehicle.shapes has entries 'body', 'wheels'
- call vehicle.shapes["body"].recurse("body", 4)
- Composition: body.shapes has entries 'over', 'under'
- call body.shapes["over"].recurse("over", 6)
- Rectangle: over.shapes has entries 'rectangle'
- call over.shapes["rectangle"].recurse("rectangle", 8)
- reached "bottom" object Curve
- call body.shapes["under"].recurse("under", 6)
- Rectangle: under.shapes has entries 'rectangle'
- call under.shapes["rectangle"].recurse("rectangle", 8)
- reached "bottom" object Curve
- ...
- </pre></div>
- </div>
- <p>This example should clearly demonstrate the principle that we
- can start at any object in the tree and do a recursive set
- of calls with that object as root.</p>
- </div>
- </div>
- <div class="section" id="scaling-translating-and-rotating-a-figure">
- <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>
- <p>With recursion, as explained in the previous section, we can within
- minutes equip <em>all</em> classes in the <code class="docutils literal"><span class="pre">Shape</span></code> hierarchy, both present and
- future ones, with the ability to scale the figure, translate it,
- or rotate it. This added functionality requires only a few lines
- of code.</p>
- <div class="section" id="scaling">
- <h4>Scaling<a class="headerlink" href="#scaling" title="Permalink to this headline">¶</a></h4>
- <p>We start with the simplest of the three geometric transformations,
- namely scaling. For a <code class="docutils literal"><span class="pre">Curve</span></code> instance containing a set of <span class="math">\(n\)</span>
- coordinates <span class="math">\((x_i,y_i)\)</span> that make up a curve, scaling by a factor <span class="math">\(a\)</span>
- 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>
- <div class="math">
- \[x_i \leftarrow ax_i,\quad y_i\leftarrow ay_i,
- \quad i=0,\ldots,n-1\thinspace .\]</div>
- <p>Here we apply the arrow as an assignment operator.
- The corresponding Python implementation in
- class <code class="docutils literal"><span class="pre">Curve</span></code> reads</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
- <span class="o">...</span>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- <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,
- so that multiplication by a scalar number <code class="docutils literal"><span class="pre">factor</span></code> is
- a vectorized operation.</p>
- <p>An even more efficient implementation is to make use of in-place
- multiplication in the arrays,</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
- <span class="o">...</span>
- <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>
- <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="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">*=</span> <span class="n">factor</span>
- </pre></div>
- </div>
- <p>as this saves the creation of temporary arrays like <code class="docutils literal"><span class="pre">factor*self.x</span></code>.</p>
- <p>In an instance of a subclass of <code class="docutils literal"><span class="pre">Shape</span></code>, the meaning of a method
- <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
- ask each object to scale itself. This is the same delegation of
- 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>)
- method. All objects, except <code class="docutils literal"><span class="pre">Curve</span></code> instances, can share the same
- 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>
- method in the superclass <code class="docutils literal"><span class="pre">Shape</span></code> such that all subclasses inherit the
- 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
- 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
- the <code class="docutils literal"><span class="pre">draw</span></code> method:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
- <span class="o">...</span>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- <p>This is all we have to do in order to equip all subclasses of
- <code class="docutils literal"><span class="pre">Shape</span></code> with scaling functionality!
- Any piece of the figure will scale itself, in the same manner
- as it can draw itself.</p>
- </div>
- <div class="section" id="translation">
- <h4>Translation<a class="headerlink" href="#translation" title="Permalink to this headline">¶</a></h4>
- <p>A set of coordinates <span class="math">\((x_i, y_i)\)</span> can be translated <span class="math">\(v_0\)</span> units in
- 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>
- <div class="math">
- \[x_i\leftarrow x_i+v_0,\quad y_i\leftarrow y_i+v_1,
- \quad i=0,\ldots,n-1\thinspace .\]</div>
- <p>The natural specification of the translation is in terms of the
- vector <span class="math">\(v=(v_0,v_1)\)</span>.
- The corresponding Python implementation in class <code class="docutils literal"><span class="pre">Curve</span></code> becomes</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Curve</span><span class="p">:</span>
- <span class="o">...</span>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- <p>The translation operation for a shape object is very similar to the
- scaling and drawing operations. This means that we can implement a
- 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
- is parallel to the <code class="docutils literal"><span class="pre">scale</span></code> method:</p>
- <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
- <span class="o">....</span>
- <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>
- <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>
- <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>
- </pre></div>
- </div>
- </div>
- <div class="section" id="rotation">
- <h4>Rotation<a class="headerlink" href="#rotation" title="Permalink to this headline">¶</a></h4>
- <p>Rotating a figure is more complicated than scaling and translating.
- A counter clockwise rotation of <span class="math">\(\theta\)</span> degrees for a set of
- coordinates <span class="math">\((x_i,y_i)\)</span> is given by</p>
- <div class="math">
- \[\begin{split}\bar x_i &\leftarrow x_i\cos\theta - y_i\sin\theta,\\
- \bar y_i &\leftarrow x_i\sin\theta + y_i\cos\theta\thinspace .\end{split}\]</div>
- <p>This rotation is performed around the origin. If we want the figure
- to be rotated with respect to a general point <span class="math">\((x,y)\)</span>, we need to
- extend the formulas above:</p>
- <div class="math">
- \[\begin{split}\bar x_i &\leftarrow x + (x_i -x)\cos\theta - (y_i -y)\sin\theta,\\
- \bar y_i &\leftarrow y + (x_i -x)\sin\theta + (y_i -y)\cos\theta\thinspace .\end{split}\]</div>
- <p>The Python implementation in class <code class="docutils literal"><span class="pre">Curve</span></code>, assuming that <span class="math">\(\theta\)</span>
- is given in degrees and not in radians, becomes</p>
- <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>
- <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>
- <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">center</span>
- <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>
- <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>
- <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>
- <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">xnew</span>
- <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">ynew</span>
- </pre></div>
- </div>
- <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
- <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>
- <p>We have already seen the <code class="docutils literal"><span class="pre">rotate</span></code> method in action when animating the
- 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>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
- <div class="sphinxsidebarwrapper">
- <center>
- <p class="logo"><a href="http://cbc.simula.no/" title="Go to Center for Biomedical Computing">
- <img class="logo" src="_static/cbc_logo.png" alt="Logo"/>
- </a></p>
- </center>
- <h3><a href="index.html">Table Of Contents</a></h3>
- <ul>
- <li><a class="reference internal" href="#">Pysketcher: Create Principal Sketches of Physics Problems</a><ul>
- <li><a class="reference internal" href="#a-first-glimpse-of-pysketcher">A first glimpse of Pysketcher</a><ul>
- <li><a class="reference internal" href="#basic-construction-of-sketches">Basic construction of sketches</a><ul>
- <li><a class="reference internal" href="#basic-drawing">Basic drawing</a></li>
- <li><a class="reference internal" href="#groups-of-objects">Groups of objects</a></li>
- <li><a class="reference internal" href="#changing-line-styles-and-colors">Changing line styles and colors</a></li>
- <li><a class="reference internal" href="#the-figure-composition-as-an-object-hierarchy">The figure composition as an object hierarchy</a></li>
- <li><a class="reference internal" href="#animation-translating-the-vehicle">Animation: translating the vehicle</a></li>
- <li><a class="reference internal" href="#animation-rolling-the-wheels">Animation: rolling the wheels</a></li>
- </ul>
- </li>
- </ul>
- </li>
- <li><a class="reference internal" href="#a-simple-pendulum">A simple pendulum</a><ul>
- <li><a class="reference internal" href="#the-basic-physics-sketch">The basic physics sketch</a></li>
- <li><a class="reference internal" href="#the-body-diagram">The body diagram</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#basic-shapes">Basic shapes</a><ul>
- <li><a class="reference internal" href="#axis">Axis</a></li>
- <li><a class="reference internal" href="#distance-with-text">Distance with text</a></li>
- <li><a class="reference internal" href="#rectangle">Rectangle</a></li>
- <li><a class="reference internal" href="#triangle">Triangle</a></li>
- <li><a class="reference internal" href="#arc">Arc</a></li>
- <li><a class="reference internal" href="#spring">Spring</a></li>
- <li><a class="reference internal" href="#dashpot">Dashpot</a></li>
- <li><a class="reference internal" href="#wavy">Wavy</a></li>
- <li><a class="reference internal" href="#stochastic-curves">Stochastic curves</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#inner-workings-of-the-pysketcher-tool">Inner workings of the Pysketcher tool</a><ul>
- <li><a class="reference internal" href="#example-of-classes-for-geometric-objects">Example of classes for geometric objects</a><ul>
- <li><a class="reference internal" href="#simple-geometric-objects">Simple geometric objects</a></li>
- <li><a class="reference internal" href="#class-curve">Class curve</a></li>
- <li><a class="reference internal" href="#compound-geometric-objects">Compound geometric objects</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#adding-functionality-via-recursion">Adding functionality via recursion</a><ul>
- <li><a class="reference internal" href="#basic-principles-of-recursion">Basic principles of recursion</a></li>
- <li><a class="reference internal" href="#explaining-recursion">Explaining recursion</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#scaling-translating-and-rotating-a-figure">Scaling, translating, and rotating a figure</a><ul>
- <li><a class="reference internal" href="#scaling">Scaling</a></li>
- <li><a class="reference internal" href="#translation">Translation</a></li>
- <li><a class="reference internal" href="#rotation">Rotation</a></li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- <h4>Previous topic</h4>
- <p class="topless"><a href="index.html"
- title="previous chapter">Pysketcher: Create Principal Sketches of Physics Problems</a></p>
- <div role="note" aria-label="source link">
- <h3>This Page</h3>
- <ul class="this-page-menu">
- <li><a href="_sources/main_sketcher.txt"
- rel="nofollow">Show Source</a></li>
- </ul>
- </div>
- <div id="searchbox" style="display: none" role="search">
- <h3>Quick search</h3>
- <form class="search" action="search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
- </div>
- <script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related" role="navigation" aria-label="related navigation">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="index.html" title="Pysketcher: Create Principal Sketches of Physics Problems"
- >previous</a> |</li>
- <li class="nav-item nav-item-0"><a href="index.html">Pysketcher: Create Principal Sketches of Physics Problems</a> »</li>
- </ul>
- </div>
- <div class="wrapper">
- <div class="footer">
- <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
- <br />
- <br />
- ©2016, Hans Petter Langtangen.
- </div>
- </div>
- </body>
- </html>
|