| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634 |
- <!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">Dec 23, 2015</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="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="id9">
- <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="#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 />
- ©2015, Hans Petter Langtangen.
- </div>
- </div>
- </body>
- </html>
|