|
@@ -0,0 +1,813 @@
|
|
|
|
|
+<!--
|
|
|
|
|
+Automatically generated HTML file from DocOnce source
|
|
|
|
|
+(https://github.com/hplgit/doconce/)
|
|
|
|
|
+-->
|
|
|
|
|
+<html>
|
|
|
|
|
+<head>
|
|
|
|
|
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
|
|
|
+<meta name="generator" content="DocOnce: https://github.com/hplgit/doconce/" />
|
|
|
|
|
+<meta name="description" content="Using Pysketcher to Create Principal Sketches of Physics Problems">
|
|
|
|
|
+<meta name="keywords" content="tree data structure,recursive function calls">
|
|
|
|
|
+
|
|
|
|
|
+<title>Using Pysketcher to Create Principal Sketches of Physics Problems</title>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+<style type="text/css">
|
|
|
|
|
+/* blueish style */
|
|
|
|
|
+
|
|
|
|
|
+/* Color definitions: http://www.december.com/html/spec/color0.html
|
|
|
|
|
+ CSS examples: http://www.w3schools.com/css/css_examples.asp */
|
|
|
|
|
+
|
|
|
|
|
+body {
|
|
|
|
|
+ margin-top: 1.0em;
|
|
|
|
|
+ background-color: #ffffff;
|
|
|
|
|
+ font-family: Helvetica, Arial, FreeSans, san-serif;
|
|
|
|
|
+ color: #000000;
|
|
|
|
|
+}
|
|
|
|
|
+h1 { font-size: 1.8em; color: #1e36ce; }
|
|
|
|
|
+h2 { font-size: 1.6em; color: #1e36ce; }
|
|
|
|
|
+h3 { font-size: 1.4em; color: #1e36ce; }
|
|
|
|
|
+a { color: #1e36ce; text-decoration:none; }
|
|
|
|
|
+tt { font-family: "Courier New", Courier; }
|
|
|
|
|
+/* pre style removed because it will interfer with pygments */
|
|
|
|
|
+p { text-indent: 0px; }
|
|
|
|
|
+hr { border: 0; width: 80%; border-bottom: 1px solid #aaa}
|
|
|
|
|
+p.caption { width: 80%; font-style: normal; text-align: left; }
|
|
|
|
|
+hr.figure { border: 0; width: 80%; border-bottom: 1px solid #aaa}
|
|
|
|
|
+
|
|
|
|
|
+div { text-align: justify; text-justify: inter-word; }
|
|
|
|
|
+</style>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+</head>
|
|
|
|
|
+
|
|
|
|
|
+<!-- tocinfo
|
|
|
|
|
+{'highest level': 1,
|
|
|
|
|
+ 'sections': [(' A First Glimpse of Pysketcher ', 1, None, '___sec0'),
|
|
|
|
|
+ (' Basic Construction of Sketches ', 2, None, '___sec1'),
|
|
|
|
|
+ (' Basic Drawing ', 3, None, '___sec2'),
|
|
|
|
|
+ (' Groups of Objects ', 3, None, '___sec3'),
|
|
|
|
|
+ (' Changing Line Styles and Colors ', 3, None, '___sec4'),
|
|
|
|
|
+ (' The Figure Composition as an Object Hierarchy ',
|
|
|
|
|
+ 3,
|
|
|
|
|
+ None,
|
|
|
|
|
+ '___sec5'),
|
|
|
|
|
+ (' Animation: Translating the Vehicle ', 3, None, '___sec6'),
|
|
|
|
|
+ (' Animation: Rolling the Wheels ',
|
|
|
|
|
+ 3,
|
|
|
|
|
+ 'sketcher:vehicle1:anim',
|
|
|
|
|
+ 'sketcher:vehicle1:anim'),
|
|
|
|
|
+ (' Basic Shapes ', 1, None, '___sec8'),
|
|
|
|
|
+ (' Axis ', 2, None, '___sec9'),
|
|
|
|
|
+ (' Distance with Text ', 2, None, '___sec10'),
|
|
|
|
|
+ (' Rectangle ', 2, None, '___sec11'),
|
|
|
|
|
+ (' Triangle ', 2, None, '___sec12'),
|
|
|
|
|
+ (' Arc ', 2, None, '___sec13'),
|
|
|
|
|
+ (' Spring ', 2, None, '___sec14'),
|
|
|
|
|
+ (' Dashpot ', 2, None, '___sec15'),
|
|
|
|
|
+ (' Wavy ', 2, None, '___sec16'),
|
|
|
|
|
+ (' Stochastic curves ', 2, None, '___sec17'),
|
|
|
|
|
+ (' Inner Workings of the Pysketcher Tool ',
|
|
|
|
|
+ 1,
|
|
|
|
|
+ None,
|
|
|
|
|
+ '___sec18'),
|
|
|
|
|
+ (' Example of Classes for Geometric Objects ',
|
|
|
|
|
+ 2,
|
|
|
|
|
+ None,
|
|
|
|
|
+ '___sec19'),
|
|
|
|
|
+ (' Simple Geometric Objects ', 3, None, '___sec20'),
|
|
|
|
|
+ (' Class Curve ', 3, None, '___sec21'),
|
|
|
|
|
+ (' Compound Geometric Objects ', 3, None, '___sec22'),
|
|
|
|
|
+ (' Adding Functionality via Recursion ', 2, None, '___sec23'),
|
|
|
|
|
+ (' Basic Principles of Recursion ', 3, None, '___sec24'),
|
|
|
|
|
+ (' Explaining Recursion ', 3, None, '___sec25'),
|
|
|
|
|
+ (' Scaling, Translating, and Rotating a Figure ',
|
|
|
|
|
+ 2,
|
|
|
|
|
+ 'sketcher:scaling',
|
|
|
|
|
+ 'sketcher:scaling'),
|
|
|
|
|
+ (' Scaling ', 3, None, '___sec27'),
|
|
|
|
|
+ (' Translation ', 3, None, '___sec28'),
|
|
|
|
|
+ (' Rotation ', 3, None, '___sec29')]}
|
|
|
|
|
+end of tocinfo -->
|
|
|
|
|
+
|
|
|
|
|
+<body>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+<script type="text/x-mathjax-config">
|
|
|
|
|
+MathJax.Hub.Config({
|
|
|
|
|
+ TeX: {
|
|
|
|
|
+ equationNumbers: { autoNumber: "none" },
|
|
|
|
|
+ extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|
|
|
|
|
+<script type="text/javascript"
|
|
|
|
|
+ src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+<a name="part0001"></a>
|
|
|
|
|
+<p>
|
|
|
|
|
+<!-- begin top navigation -->
|
|
|
|
|
+<table style="width: 100%"><tr><td>
|
|
|
|
|
+<div style="text-align: left;"><a href="._pysketcher000.html"><img src="http://hplgit.github.io/doconce/bundled/html_images/prev1.png" border=0 alt="« Previous"></a></div>
|
|
|
|
|
+</td><td>
|
|
|
|
|
+<div style="text-align: right;"><a href="._pysketcher002.html"><img src="http://hplgit.github.io/doconce/bundled/html_images/next1.png" border=0 alt="Next »"></a></div>
|
|
|
|
|
+</td></tr></table>
|
|
|
|
|
+<!-- end top navigation -->
|
|
|
|
|
+</p>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+<!-- !split -->
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+2DO:
|
|
|
|
|
+
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li> two wheels of different radii on inclined plane coupled to
|
|
|
|
|
+ correct solution</li>
|
|
|
|
|
+ <li> <a href="http://inventwithpython.com/chapter17.html" target="_self">Pygame backend</a></li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h1 id="___sec0">A First Glimpse of Pysketcher </h1>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+Formulation of physical problems makes heavy use of <em>principal sketches</em>
|
|
|
|
|
+such as the one in Figure <a href="#sketcher:fig:inclinedplane">1</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 \( N \) and \( Mg \) forces, and the \( x \)
|
|
|
|
|
+axis), an angle with symbol \( \theta \), and a dashed line indicating the
|
|
|
|
|
+starting location of the wheel.
|
|
|
|
|
+
|
|
|
|
|
+<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>
|
|
|
|
|
+<center> <!-- figure -->
|
|
|
|
|
+<hr class="figure">
|
|
|
|
|
+<center><p class="caption">Figure 1: Sketch of a physics problem. <div id="sketcher:fig:inclinedplane"></div> </p></center>
|
|
|
|
|
+<p><img src="fig-tut/wheel_on_inclined_plane.png" align="bottom" width=400></p>
|
|
|
|
|
+</center>
|
|
|
|
|
+
|
|
|
|
|
+<h2 id="___sec1">Basic Construction of Sketches </h2>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+Before attacking real-life sketches as in Figure <a href="#sketcher:fig:inclinedplane">1</a>
|
|
|
|
|
+we focus on the significantly simpler drawing shown
|
|
|
|
|
+in Figure <a href="#sketcher:fig:vehicle0">2</a>. This toy sketch consists of
|
|
|
|
|
+several elements: two circles, two rectangles, and a "ground" element.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+<center> <!-- figure -->
|
|
|
|
|
+<hr class="figure">
|
|
|
|
|
+<center><p class="caption">Figure 2: Sketch of a simple figure. <div id="sketcher:fig:vehicle0"></div> </p></center>
|
|
|
|
|
+<p><img src="fig-tut/vehicle0_dim.png" align="bottom" width=600></p>
|
|
|
|
|
+</center>
|
|
|
|
|
+
|
|
|
|
|
+<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 (\( R \)),
|
|
|
|
|
+the center point of the left wheel (\( w_1 \)), as well as the height (\( H \)) and
|
|
|
|
|
+length (\( L \)) of the main part. The simple vehicle in
|
|
|
|
|
+Figure <a href="#sketcher:fig:vehicle0">2</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 \( R \) parameter and
|
|
|
|
|
+rerunning the program.
|
|
|
|
|
+For example, Figure <a href="#sketcher:fig:vehicle0b">3</a> shows
|
|
|
|
|
+a variation of the drawing in
|
|
|
|
|
+Figure <a href="#sketcher:fig:vehicle0">2</a> obtained by just setting
|
|
|
|
|
+\( R=0.5 \), \( L=5 \), \( H=2 \), and \( R=2 \). 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>
|
|
|
|
|
+<center> <!-- figure -->
|
|
|
|
|
+<hr class="figure">
|
|
|
|
|
+<center><p class="caption">Figure 3: Redrawing a figure with other geometric parameters. <div id="sketcher:fig:vehicle0b"></div> </p></center>
|
|
|
|
|
+<p><img src="fig-tut/vehicle_v2.png" align="bottom" width=500></p>
|
|
|
|
|
+</center>
|
|
|
|
|
+
|
|
|
|
|
+<h3 id="___sec2">Basic Drawing </h3>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+A typical program creating these five elements is shown next.
|
|
|
|
|
+After importing the <code>pysketcher</code> package, the first task is always to
|
|
|
|
|
+define a coordinate system:
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">pysketcher</span> <span style="color: #008000; font-weight: bold">import</span> <span style="color: #666666">*</span>
|
|
|
|
|
+
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
|
|
|
|
|
+ xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=10</span>, ymin<span style="color: #666666">=-1</span>, ymax<span style="color: #666666">=8</span>)
|
|
|
|
|
+</pre></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>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">R <span style="color: #666666">=</span> <span style="color: #666666">1</span> <span style="color: #408080; font-style: italic"># radius of wheel</span>
|
|
|
|
|
+L <span style="color: #666666">=</span> <span style="color: #666666">4</span> <span style="color: #408080; font-style: italic"># distance between wheels</span>
|
|
|
|
|
+H <span style="color: #666666">=</span> <span style="color: #666666">2</span> <span style="color: #408080; font-style: italic"># height of vehicle body</span>
|
|
|
|
|
+w_1 <span style="color: #666666">=</span> <span style="color: #666666">5</span> <span style="color: #408080; font-style: italic"># position of front wheel</span>
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>set_coordinate_system(xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=</span>w_1 <span style="color: #666666">+</span> <span style="color: #666666">2*</span>L <span style="color: #666666">+</span> <span style="color: #666666">3*</span>R,
|
|
|
|
|
+ ymin<span style="color: #666666">=-1</span>, ymax<span style="color: #666666">=2*</span>R <span style="color: #666666">+</span> <span style="color: #666666">3*</span>H)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+With the drawing area in place we can make the first <code>Circle</code> object
|
|
|
|
|
+in an intuitive fashion:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel1 <span style="color: #666666">=</span> Circle(center<span style="color: #666666">=</span>(w_1, R), radius<span style="color: #666666">=</span>R)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+to change dimensions later.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+To translate the geometric information about the <code>wheel1</code> object to
|
|
|
|
|
+instructions for the plotting engine (in this case Matplotlib), one calls the
|
|
|
|
|
+<code>wheel1.draw()</code>. To display all drawn objects, one issues
|
|
|
|
|
+<code>drawing_tool.display()</code>. The typical steps are hence:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel1 <span style="color: #666666">=</span> Circle(center<span style="color: #666666">=</span>(w_1, R), radius<span style="color: #666666">=</span>R)
|
|
|
|
|
+wheel1<span style="color: #666666">.</span>draw()
|
|
|
|
|
+
|
|
|
|
|
+<span style="color: #408080; font-style: italic"># Define other objects and call their draw() methods</span>
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>display()
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>savefig(<span style="color: #BA2121">'tmp.png'</span>) <span style="color: #408080; font-style: italic"># store picture</span>
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The next wheel can be made by taking a copy of <code>wheel1</code> and
|
|
|
|
|
+translating the object to the right according to a
|
|
|
|
|
+displacement vector \( (L,0) \):
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel2 <span style="color: #666666">=</span> wheel1<span style="color: #666666">.</span>copy()
|
|
|
|
|
+wheel2<span style="color: #666666">.</span>translate((L,<span style="color: #666666">0</span>))
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The two rectangles are also made in an intuitive way:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">under <span style="color: #666666">=</span> Rectangle(lower_left_corner<span style="color: #666666">=</span>(w_1<span style="color: #666666">-2*</span>R, <span style="color: #666666">2*</span>R),
|
|
|
|
|
+ width<span style="color: #666666">=2*</span>R <span style="color: #666666">+</span> L <span style="color: #666666">+</span> <span style="color: #666666">2*</span>R, height<span style="color: #666666">=</span>H)
|
|
|
|
|
+over <span style="color: #666666">=</span> Rectangle(lower_left_corner<span style="color: #666666">=</span>(w_1, <span style="color: #666666">2*</span>R <span style="color: #666666">+</span> H),
|
|
|
|
|
+ width<span style="color: #666666">=2.5*</span>R, height<span style="color: #666666">=1.25*</span>H)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+
|
|
|
|
|
+<h3 id="___sec3">Groups of Objects </h3>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+Instead of calling the <code>draw</code> method of every object, we can
|
|
|
|
|
+group objects and call <code>draw</code>, or perform other operations, for
|
|
|
|
|
+the whole group. For example, we may collect the two wheels
|
|
|
|
|
+in a <code>wheels</code> group and the <code>over</code> and <code>under</code> rectangles
|
|
|
|
|
+in a <code>body</code> group. The whole vehicle is a composition
|
|
|
|
|
+of its <code>wheels</code> and <code>body</code> groups. The code goes like
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheels <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">'wheel1'</span>: wheel1, <span style="color: #BA2121">'wheel2'</span>: wheel2})
|
|
|
|
|
+body <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">'under'</span>: under, <span style="color: #BA2121">'over'</span>: over})
|
|
|
|
|
+
|
|
|
|
|
+vehicle <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">'wheels'</span>: wheels, <span style="color: #BA2121">'body'</span>: body})
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The ground is illustrated by an object of type <code>Wall</code>,
|
|
|
|
|
+mostly used to indicate walls in sketches of mechanical systems.
|
|
|
|
|
+A <code>Wall</code> takes the <code>x</code> and <code>y</code> coordinates of some curve,
|
|
|
|
|
+and a <code>thickness</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 (\( (w_1-L,0) \) and \( (w_1+3L,0) \)):
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">ground <span style="color: #666666">=</span> Wall(x<span style="color: #666666">=</span>[w_1 <span style="color: #666666">-</span> L, w_1 <span style="color: #666666">+</span> <span style="color: #666666">3*</span>L], y<span style="color: #666666">=</span>[<span style="color: #666666">0</span>, <span style="color: #666666">0</span>], thickness<span style="color: #666666">=-0.3*</span>R)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The negative thickness makes the pattern-filled rectangle appear below
|
|
|
|
|
+the defined line, otherwise it appears above.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+We may now collect all the objects in a "top" object that contains
|
|
|
|
|
+the whole figure:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">'vehicle'</span>: vehicle, <span style="color: #BA2121">'ground'</span>: ground})
|
|
|
|
|
+fig<span style="color: #666666">.</span>draw() <span style="color: #408080; font-style: italic"># send all figures to plotting backend</span>
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>display()
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>savefig(<span style="color: #BA2121">'tmp.png'</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The <code>fig.draw()</code> call will visit
|
|
|
|
|
+all subgroups, their subgroups,
|
|
|
|
|
+and so forth in the hierarchical tree structure of
|
|
|
|
|
+figure elements,
|
|
|
|
|
+and call <code>draw</code> for every object.
|
|
|
|
|
+
|
|
|
|
|
+<h3 id="___sec4">Changing Line Styles and Colors </h3>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+Controlling the line style, line color, and line width is
|
|
|
|
|
+fundamental when designing figures. The <code>pysketcher</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>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">drawing_tool<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">'dashed'</span>)
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">'black'</span>)
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">4</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+At the object level the properties are specified in a similar
|
|
|
|
|
+way:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheels<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">'solid'</span>)
|
|
|
|
|
+wheels<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">'red'</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+and so on.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+Geometric figures can be specified as <em>filled</em>, either with a color or with a
|
|
|
|
|
+special visual pattern:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #408080; font-style: italic"># Set filling of all curves</span>
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>set_filled_curves(color<span style="color: #666666">=</span><span style="color: #BA2121">'blue'</span>, pattern<span style="color: #666666">=</span><span style="color: #BA2121">'/'</span>)
|
|
|
|
|
+
|
|
|
|
|
+<span style="color: #408080; font-style: italic"># Turn off filling of all curves</span>
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>set_filled_curves(<span style="color: #008000">False</span>)
|
|
|
|
|
+
|
|
|
|
|
+<span style="color: #408080; font-style: italic"># Fill the wheel with red color</span>
|
|
|
|
|
+wheel1<span style="color: #666666">.</span>set_filled_curves(<span style="color: #BA2121">'red'</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+<!-- <a href="http://packages.python.org/ete2/" target="_self"><tt>http://packages.python.org/ete2/</tt></a> for visualizing tree structures! -->
|
|
|
|
|
+
|
|
|
|
|
+<h3 id="___sec5">The Figure Composition as an Object Hierarchy </h3>
|
|
|
|
|
+
|
|
|
|
|
+<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>print fig</code> to display the relations:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=text (!bc dat) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">ground
|
|
|
|
|
+ wall
|
|
|
|
|
+vehicle
|
|
|
|
|
+ body
|
|
|
|
|
+ over
|
|
|
|
|
+ rectangle
|
|
|
|
|
+ under
|
|
|
|
|
+ rectangle
|
|
|
|
|
+ wheels
|
|
|
|
|
+ wheel1
|
|
|
|
|
+ arc
|
|
|
|
|
+ wheel2
|
|
|
|
|
+ arc
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The indentation reflects how deep down in the hierarchy (family)
|
|
|
|
|
+we are.
|
|
|
|
|
+This output is to be interpreted as follows:
|
|
|
|
|
+
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li> <code>fig</code> contains two objects, <code>ground</code> and <code>vehicle</code></li>
|
|
|
|
|
+ <li> <code>ground</code> contains an object <code>wall</code></li>
|
|
|
|
|
+ <li> <code>vehicle</code> contains two objects, <code>body</code> and <code>wheels</code></li>
|
|
|
|
|
+ <li> <code>body</code> contains two objects, <code>over</code> and <code>under</code></li>
|
|
|
|
|
+ <li> <code>wheels</code> contains two objects, <code>wheel1</code> and <code>wheel2</code></li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+In this listing there are also objects not defined by the
|
|
|
|
|
+programmer: <code>rectangle</code> and <code>arc</code>. These are of type <code>Curve</code>
|
|
|
|
|
+and automatically generated by the classes <code>Rectangle</code> and <code>Circle</code>.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+More detailed information can be printed by
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">print</span> fig<span style="color: #666666">.</span>show_hierarchy(<span style="color: #BA2121">'std'</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+yielding the output
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=text (!bc dat) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">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>
|
|
|
|
|
+<p>
|
|
|
|
|
+Here we can see the class type for each figure object, how many
|
|
|
|
|
+coordinates that are involved in basic figures (<code>Curve</code> objects), and
|
|
|
|
|
+special settings of the basic figure (fillcolor, line types, etc.).
|
|
|
|
|
+For example, <code>wheel2</code> is a <code>Circle</code> object consisting of an <code>arc</code>,
|
|
|
|
|
+which is a <code>Curve</code> object consisting of 181 coordinates (the
|
|
|
|
|
+points needed to draw a smooth circle). The <code>Curve</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>
|
|
|
|
|
+One can also get a graphical overview of the hierarchy of figure objects
|
|
|
|
|
+that build up a particular figure <code>fig</code>.
|
|
|
|
|
+Just call <code>fig.graphviz_dot('fig')</code> to produce a file <code>fig.dot</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 href="#sketcher:fig:vehicle0:hier1">4</a>, by
|
|
|
|
|
+running the <code>dot</code> program:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=text (!bc sys) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Terminal> dot -Tpng -o fig.png fig.dot
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+<center> <!-- figure -->
|
|
|
|
|
+<hr class="figure">
|
|
|
|
|
+<center><p class="caption">Figure 4: Hierarchical relation between figure objects. <div id="sketcher:fig:vehicle0:hier1"></div> </p></center>
|
|
|
|
|
+<p><img src="fig-tut/vehicle0_hier1.png" align="bottom" width=500></p>
|
|
|
|
|
+</center>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+The call <code>fig.graphviz_dot('fig', classname=True)</code> makes a <code>fig.dot</code> file
|
|
|
|
|
+where the class type of each object is also visible, see
|
|
|
|
|
+Figure <a href="#sketcher:fig:vehicle0:hier2">5</a>. 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>
|
|
|
|
|
+<center> <!-- figure -->
|
|
|
|
|
+<hr class="figure">
|
|
|
|
|
+<center><p class="caption">Figure 5: Hierarchical relation between figure objects, including their class names. <div id="sketcher:fig:vehicle0:hier2"></div> </p></center>
|
|
|
|
|
+<p><img src="fig-tut/Vehicle0_hier2.png" align="bottom" width=500></p>
|
|
|
|
|
+</center>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+Any of the objects can in the program be reached through their names, e.g.,
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig[<span style="color: #BA2121">'vehicle'</span>]
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>]
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>]
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>][<span style="color: #BA2121">'arc'</span>]
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>][<span style="color: #BA2121">'arc'</span>]<span style="color: #666666">.</span>x <span style="color: #408080; font-style: italic"># x coords</span>
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>][<span style="color: #BA2121">'arc'</span>]<span style="color: #666666">.</span>y <span style="color: #408080; font-style: italic"># y coords</span>
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>][<span style="color: #BA2121">'arc'</span>]<span style="color: #666666">.</span>linestyle
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>][<span style="color: #BA2121">'arc'</span>]<span style="color: #666666">.</span>linetype
|
|
|
|
|
+</pre></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 href="#sketcher:fig:vehicle0:v2">6</a>):
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>]<span style="color: #666666">.</span>set_filled_curves(<span style="color: #BA2121">'blue'</span>)
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>]<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">6</span>)
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>]<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">'black'</span>)
|
|
|
|
|
+
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'body'</span>][<span style="color: #BA2121">'under'</span>]<span style="color: #666666">.</span>set_filled_curves(<span style="color: #BA2121">'red'</span>)
|
|
|
|
|
+
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'body'</span>][<span style="color: #BA2121">'over'</span>]<span style="color: #666666">.</span>set_filled_curves(pattern<span style="color: #666666">=</span><span style="color: #BA2121">'/'</span>)
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'body'</span>][<span style="color: #BA2121">'over'</span>]<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">14</span>)
|
|
|
|
|
+fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'body'</span>][<span style="color: #BA2121">'over'</span>][<span style="color: #BA2121">'rectangle'</span>]<span style="color: #666666">.</span>linewidth <span style="color: #666666">=</span> <span style="color: #666666">4</span>
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The last line accesses the <code>Curve</code> object directly, while the line above,
|
|
|
|
|
+accesses the <code>Rectangle</code> object, which will then set the linewidth of
|
|
|
|
|
+its <code>Curve</code> object, and other objects if it had any.
|
|
|
|
|
+The result of the actions above is shown in Figure <a href="#sketcher:fig:vehicle0:v2">6</a>.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+<center> <!-- figure -->
|
|
|
|
|
+<hr class="figure">
|
|
|
|
|
+<center><p class="caption">Figure 6: Left: Basic line-based drawing. Right: Thicker lines and filled parts. <div id="sketcher:fig:vehicle0:v2"></div> </p></center>
|
|
|
|
|
+<p><img src="fig-tut/vehicle0.png" align="bottom" width=700></p>
|
|
|
|
|
+</center>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+We can also change position of parts of the figure and thereby make
|
|
|
|
|
+animations, as shown next.
|
|
|
|
|
+
|
|
|
|
|
+<h3 id="___sec6">Animation: Translating the Vehicle </h3>
|
|
|
|
|
+
|
|
|
|
|
+<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>fig['vehicle']</code> object.
|
|
|
|
|
+This part of the figure can be translated, rotated, and scaled.
|
|
|
|
|
+A translation along the ground means a translation in \( x \) direction,
|
|
|
|
|
+say a length \( L \) to the right:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig[<span style="color: #BA2121">'vehicle'</span>]<span style="color: #666666">.</span>translate((L,<span style="color: #666666">0</span>))
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+You need to erase, draw, and display to see the movement:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">drawing_tool<span style="color: #666666">.</span>erase()
|
|
|
|
|
+fig<span style="color: #666666">.</span>draw()
|
|
|
|
|
+drawing_tool<span style="color: #666666">.</span>display()
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+Without erasing, the old drawing of the vehicle will remain in
|
|
|
|
|
+the figure so you get two vehicles. Without <code>fig.draw()</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>
|
|
|
|
|
+A figure that moves in time is conveniently realized by the
|
|
|
|
|
+function <code>animate</code>:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">animate(fig, tp, action)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+Here, <code>fig</code> is the entire figure, <code>tp</code> is an array of
|
|
|
|
|
+time points, and <code>action</code> is a user-specified function that changes
|
|
|
|
|
+<code>fig</code> at a specific time point. Typically, <code>action</code> will move
|
|
|
|
|
+parts of <code>fig</code>.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+In the present case we can define the movement through a velocity
|
|
|
|
|
+function <code>v(t)</code> and displace the figure <code>v(t)*dt</code> for small time
|
|
|
|
|
+intervals <code>dt</code>. A possible velocity function is
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">v</span>(t):
|
|
|
|
|
+ <span style="color: #008000; font-weight: bold">return</span> <span style="color: #666666">-8*</span>R<span style="color: #666666">*</span>t<span style="color: #666666">*</span>(<span style="color: #666666">1</span> <span style="color: #666666">-</span> t<span style="color: #666666">/</span>(<span style="color: #666666">2*</span>R))
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+Our action function for horizontal displacements <code>v(t)*dt</code> becomes
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">move</span>(t, fig):
|
|
|
|
|
+ x_displacement <span style="color: #666666">=</span> dt<span style="color: #666666">*</span>v(t)
|
|
|
|
|
+ fig[<span style="color: #BA2121">'vehicle'</span>]<span style="color: #666666">.</span>translate((x_displacement, <span style="color: #666666">0</span>))
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+Since our velocity is negative for \( t\in [0,2R] \) the displacement is
|
|
|
|
|
+to the left.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+The <code>animate</code> function will for each time point <code>t</code> in <code>tp</code> erase
|
|
|
|
|
+the drawing, call <code>action(t, fig)</code>, and show the new figure by
|
|
|
|
|
+<code>fig.draw()</code> and <code>drawing_tool.display()</code>.
|
|
|
|
|
+Here we choose a resolution of the animation corresponding to
|
|
|
|
|
+25 time points in the time interval \( [0,2R] \):
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span>
|
|
|
|
|
+tp <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>linspace(<span style="color: #666666">0</span>, <span style="color: #666666">2*</span>R, <span style="color: #666666">25</span>)
|
|
|
|
|
+dt <span style="color: #666666">=</span> tp[<span style="color: #666666">1</span>] <span style="color: #666666">-</span> tp[<span style="color: #666666">0</span>] <span style="color: #408080; font-style: italic"># time step</span>
|
|
|
|
|
+
|
|
|
|
|
+animate(fig, tp, move, pause_per_frame<span style="color: #666666">=0.2</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The <code>pause_per_frame</code> adds a pause, here 0.2 seconds, between
|
|
|
|
|
+each frame in the animation.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+We can also ask <code>animate</code> to store each frame in a file:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">files <span style="color: #666666">=</span> animate(fig, tp, move_vehicle, moviefiles<span style="color: #666666">=</span><span style="color: #008000">True</span>,
|
|
|
|
|
+ pause_per_frame<span style="color: #666666">=0.2</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The <code>files</code> variable, here <code>'tmp_frame_%04d.png'</code>,
|
|
|
|
|
+is the printf-specification used to generate the individual
|
|
|
|
|
+plot files. We can use this specification to make a video
|
|
|
|
|
+file via <code>ffmpeg</code> (or <code>avconv</code> on Debian-based Linux systems such
|
|
|
|
|
+as Ubuntu). Videos in the Flash and WebM formats can be created
|
|
|
|
|
+by
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=text (!bc sys) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">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>
|
|
|
|
|
+<p>
|
|
|
|
|
+An animated GIF movie can also be made using the <code>convert</code> program
|
|
|
|
|
+from the ImageMagick software suite:
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=text (!bc sys) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Terminal> convert -delay 20 tmp_frame*.png mov.gif
|
|
|
|
|
+Terminal> animate mov.gif # play movie
|
|
|
|
|
+</pre></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><img src="mov.gif"></code> in the HTML code.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+The individual PNG frames can be directly played in a web
|
|
|
|
|
+browser by running
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=text (!bc sys) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">Terminal> scitools movie output_file=mov.html fps=5 tmp_frame*
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+or calling
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">scitools.std</span> <span style="color: #008000; font-weight: bold">import</span> movie
|
|
|
|
|
+movie(files, encoder<span style="color: #666666">=</span><span style="color: #BA2121">'html'</span>, output_file<span style="color: #666666">=</span><span style="color: #BA2121">'mov.html'</span>)
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+in Python. Load the resulting file <code>mov.html</code> into a web browser
|
|
|
|
|
+to play the movie.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+Try to run <a href="http://tinyurl.com/ot733jn/vehicle0.py" target="_self"><tt>vehicle0.py</tt></a> and
|
|
|
|
|
+then load <code>mov.html</code> into a browser, or play one of the <code>mov.*</code>
|
|
|
|
|
+video files. Alternatively, you can view a ready-made <a href="http://tinyurl.com/oou9lp7/mov-tut/vehicle0.html" target="_self">movie</a>.
|
|
|
|
|
+
|
|
|
|
|
+<h3 id="sketcher:vehicle1:anim">Animation: Rolling the Wheels</h3>
|
|
|
|
|
+
|
|
|
|
|
+<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 href="#sketcher:fig:vehicle1">7</a>.
|
|
|
|
|
+The construction of the wheels will now involve a circle and two lines:
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">wheel1 <span style="color: #666666">=</span> Composition({
|
|
|
|
|
+ <span style="color: #BA2121">'wheel'</span>: Circle(center<span style="color: #666666">=</span>(w_1, R), radius<span style="color: #666666">=</span>R),
|
|
|
|
|
+ <span style="color: #BA2121">'cross'</span>: Composition({<span style="color: #BA2121">'cross1'</span>: Line((w_1,<span style="color: #666666">0</span>), (w_1,<span style="color: #666666">2*</span>R)),
|
|
|
|
|
+ <span style="color: #BA2121">'cross2'</span>: Line((w_1<span style="color: #666666">-</span>R,R), (w_1<span style="color: #666666">+</span>R,R))})})
|
|
|
|
|
+wheel2 <span style="color: #666666">=</span> wheel1<span style="color: #666666">.</span>copy()
|
|
|
|
|
+wheel2<span style="color: #666666">.</span>translate((L,<span style="color: #666666">0</span>))
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+Observe that <code>wheel1.copy()</code> copies all the objects that make
|
|
|
|
|
+up the first wheel, and <code>wheel2.translate</code> translates all
|
|
|
|
|
+the copied objects.
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+<center> <!-- figure -->
|
|
|
|
|
+<hr class="figure">
|
|
|
|
|
+<center><p class="caption">Figure 7: Wheels with spokes to illustrate rolling. <div id="sketcher:fig:vehicle1"></div> </p></center>
|
|
|
|
|
+<p><img src="fig-tut/vehicle1.png" align="bottom" width=400></p>
|
|
|
|
|
+</center>
|
|
|
|
|
+
|
|
|
|
|
+<p>
|
|
|
|
|
+The <code>move</code> function now needs to displace all the objects in the
|
|
|
|
|
+entire vehicle and also rotate the <code>cross1</code> and <code>cross2</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>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">angle <span style="color: #666666">=</span> <span style="color: #666666">-</span> x_displacement<span style="color: #666666">/</span>R
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+With <code>w_1</code> tracking the \( x \) coordinate of the center
|
|
|
|
|
+of the front wheel, we can rotate that wheel by
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">w1 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel1'</span>]
|
|
|
|
|
+<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">math</span> <span style="color: #008000; font-weight: bold">import</span> degrees
|
|
|
|
|
+w1<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1, R))
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The <code>rotate</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>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">w2 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>]
|
|
|
|
|
+w2<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1 <span style="color: #666666">+</span> L, R))
|
|
|
|
|
+</pre></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>w_1 += x_displacement</code>.
|
|
|
|
|
+The complete <code>move</code> function with translation of the entire
|
|
|
|
|
+vehicle and rotation of the wheels then becomes
|
|
|
|
|
+<p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
|
|
|
|
|
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">w_1 <span style="color: #666666">=</span> w_1 <span style="color: #666666">+</span> L <span style="color: #408080; font-style: italic"># start position</span>
|
|
|
|
|
+
|
|
|
|
|
+<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">move</span>(t, fig):
|
|
|
|
|
+ x_displacement <span style="color: #666666">=</span> dt<span style="color: #666666">*</span>v(t)
|
|
|
|
|
+ fig[<span style="color: #BA2121">'vehicle'</span>]<span style="color: #666666">.</span>translate((x_displacement, <span style="color: #666666">0</span>))
|
|
|
|
|
+
|
|
|
|
|
+ <span style="color: #408080; font-style: italic"># Rotate wheels</span>
|
|
|
|
|
+ <span style="color: #008000; font-weight: bold">global</span> w_1
|
|
|
|
|
+ w_1 <span style="color: #666666">+=</span> x_displacement
|
|
|
|
|
+ <span style="color: #408080; font-style: italic"># R*angle = -x_displacement</span>
|
|
|
|
|
+ angle <span style="color: #666666">=</span> <span style="color: #666666">-</span> x_displacement<span style="color: #666666">/</span>R
|
|
|
|
|
+ w1 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel1'</span>]
|
|
|
|
|
+ w1<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1, R))
|
|
|
|
|
+ w2 <span style="color: #666666">=</span> fig[<span style="color: #BA2121">'vehicle'</span>][<span style="color: #BA2121">'wheels'</span>][<span style="color: #BA2121">'wheel2'</span>]
|
|
|
|
|
+ w2<span style="color: #666666">.</span>rotate(degrees(angle), center<span style="color: #666666">=</span>(w_1 <span style="color: #666666">+</span> L, R))
|
|
|
|
|
+</pre></div>
|
|
|
|
|
+<p>
|
|
|
|
|
+The complete example is found in the file
|
|
|
|
|
+<a href="http://tinyurl.com/ot733jn/vehicle1.py" target="_self"><tt>vehicle1.py</tt></a>. You may run this file or watch a <a href="http://tinyurl.com/oou9lp7/mov-tut/vehicle1.html" target="_self">ready-made movie</a>.
|
|
|
|
|
+
|
|
|
|
|
+<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>
|
|
|
|
|
+<p>
|
|
|
|
|
+<!-- begin bottom navigation -->
|
|
|
|
|
+<table style="width: 100%"><tr><td>
|
|
|
|
|
+<div style="text-align: left;"><a href="._pysketcher000.html"><img src="http://hplgit.github.io/doconce/bundled/html_images/prev1.png" border=0 alt="« Previous"></a></div>
|
|
|
|
|
+</td><td>
|
|
|
|
|
+<div style="text-align: right;"><a href="._pysketcher002.html"><img src="http://hplgit.github.io/doconce/bundled/html_images/next1.png" border=0 alt="Next »"></a></div>
|
|
|
|
|
+</td></tr></table>
|
|
|
|
|
+<!-- end bottom navigation -->
|
|
|
|
|
+</p>
|
|
|
|
|
+
|
|
|
|
|
+<!-- ------------------- end of main content --------------- -->
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+</body>
|
|
|
|
|
+</html>
|
|
|
|
|
+
|
|
|
|
|
+
|