Hans Petter Langtangen 10 年 前
コミット
db2357f81f
38 ファイル変更1426 行追加586 行削除
  1. 3 3
      README.do.txt
  2. 57 44
      doc/pub/tutorial/._pysketcher000.html
  3. 73 57
      doc/pub/tutorial/._pysketcher001.html
  4. 56 43
      doc/pub/tutorial/._pysketcher002.html
  5. 294 325
      doc/pub/tutorial/._pysketcher003.html
  6. 1 1
      doc/pub/tutorial/html/.buildinfo
  7. 323 1
      doc/pub/tutorial/html/_sources/main_sketcher.txt
  8. 1 1
      doc/pub/tutorial/html/genindex.html
  9. 6 1
      doc/pub/tutorial/html/index.html
  10. 257 3
      doc/pub/tutorial/html/main_sketcher.html
  11. BIN
      doc/pub/tutorial/html/objects.inv
  12. 1 1
      doc/pub/tutorial/html/search.html
  13. 1 1
      doc/pub/tutorial/html/searchindex.js
  14. BIN
      doc/pub/tutorial/mov-tut/pendulum/movie.flv
  15. BIN
      doc/pub/tutorial/mov-tut/pendulum/movie.mp4
  16. BIN
      doc/pub/tutorial/mov-tut/pendulum/movie.ogg
  17. BIN
      doc/pub/tutorial/mov-tut/pendulum/movie.webm
  18. 57 44
      doc/pub/tutorial/pysketcher.html
  19. BIN
      doc/pub/tutorial/pysketcher.pdf
  20. 5 0
      doc/src/tut/.dict4spell.txt
  21. BIN
      doc/src/tut/fig-tut/pendulum1.pdf
  22. BIN
      doc/src/tut/fig-tut/pendulum1.png
  23. BIN
      doc/src/tut/fig-tut/pendulum1_wgrid.pdf
  24. BIN
      doc/src/tut/fig-tut/pendulum1_wgrid.png
  25. BIN
      doc/src/tut/fig-tut/pendulum5.pdf
  26. BIN
      doc/src/tut/fig-tut/pendulum5.png
  27. BIN
      doc/src/tut/fig-tut/pendulum5_wgrid.pdf
  28. BIN
      doc/src/tut/fig-tut/pendulum5_wgrid.png
  29. 3 0
      doc/src/tut/main_sketcher.do.txt
  30. 18 0
      doc/src/tut/newcommands.tex
  31. 1 0
      examples/beam1.py
  32. 4 3
      examples/beam2.py
  33. 38 34
      examples/pendulum.py
  34. 173 0
      examples/pendulum2.py
  35. BIN
      fig/beam2_3.pdf
  36. BIN
      fig/beam2_3.png
  37. 29 16
      pysketcher/MatplotlibDraw.py
  38. 25 8
      pysketcher/shapes.py

+ 3 - 3
README.do.txt

@@ -47,11 +47,11 @@ the tutorial in Chapter 9 in "A Primer on Scientific Programming with Python": "
 
 See the `examples` directory for some examples beyond the more basic
 ones in the tutorial.
-For example, a pendulum and its body diagram,
+For example, an elastic beam can be sketched as
 
-FIGURE: [fig/pendulum2, width=800 frac=1]
+FIGURE: [fig/beam2_3, width=600 frac=0.8]
 
-can be created by the program "`examples/pendulum.py`": "https://github.com/hplgit/pysketcher/tree/master/examples/pendulum.py".
+The sketch was created by the program "`examples/beam2.py`": "https://github.com/hplgit/pysketcher/tree/master/examples/beam2.py".
 
 Here is an illustration of the idea of numerical integration:
 

+ 57 - 44
doc/pub/tutorial/._pysketcher000.html

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                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'),
+              ('A simple pendulum',
+               1,
+               'sketcher:ex:pendulum',
+               'sketcher:ex:pendulum'),
+              ('The basic physics sketch',
+               2,
+               'sketcher:ex:pendulum:basic',
+               'sketcher:ex:pendulum:basic'),
+              ('The body diagram', 2, None, '___sec10'),
+              ('Basic shapes', 1, None, '___sec11'),
+              ('Axis', 2, None, '___sec12'),
+              ('Distance with text', 2, None, '___sec13'),
+              ('Rectangle', 2, None, '___sec14'),
+              ('Triangle', 2, None, '___sec15'),
+              ('Arc', 2, None, '___sec16'),
+              ('Spring', 2, None, '___sec17'),
+              ('Dashpot', 2, None, '___sec18'),
+              ('Wavy', 2, None, '___sec19'),
+              ('Stochastic curves', 2, None, '___sec20'),
+              ('Inner workings of the Pysketcher tool', 1, None, '___sec21'),
               ('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'),
+               '___sec22'),
+              ('Simple geometric objects', 3, None, '___sec23'),
+              ('Class curve', 3, None, '___sec24'),
+              ('Compound geometric objects', 3, None, '___sec25'),
+              ('Adding functionality via recursion', 2, None, '___sec26'),
+              ('Basic principles of recursion', 3, None, '___sec27'),
+              ('Explaining recursion', 3, None, '___sec28'),
               ('Scaling, translating, and rotating a figure',
                2,
                'sketcher:scaling',
                'sketcher:scaling'),
-              ('Scaling', 3, None, '___sec27'),
-              ('Translation', 3, None, '___sec28'),
-              ('Rotation', 3, None, '___sec29')]}
+              ('Scaling', 3, None, '___sec30'),
+              ('Translation', 3, None, '___sec31'),
+              ('Rotation', 3, None, '___sec32')]}
 end of tocinfo -->
 
 <body>
@@ -119,28 +128,31 @@ MathJax.Hub.Config({
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec5" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The figure composition as an object hierarchy</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec6" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: translating the vehicle</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#sketcher:vehicle1:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: rolling the wheels</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec8" style="font-size: 80%;"><b>Basic shapes</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec9" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec11" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec21" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec29" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum" style="font-size: 80%;"><b>A simple pendulum</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum:basic" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The basic physics sketch</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The body diagram</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec11" style="font-size: 80%;"><b>Basic shapes</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec21" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec26" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec30" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec31" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec32" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
 
         </ul>
       </li>
@@ -175,7 +187,7 @@ MathJax.Hub.Config({
 <center>[2] <b>Department of Informatics, University of Oslo</b></center>
 <br>
 <p>
-<center><h4>Dec 23, 2015</h4></center> <!-- date -->
+<center><h4>Jan 22, 2016</h4></center> <!-- date -->
 <br>
 <p>
 
@@ -231,6 +243,7 @@ no further background is required.
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</a></li>
+  <li><a href="._pysketcher005.html">6</a></li>
   <li><a href="._pysketcher001.html">&raquo;</a></li>
 </ul>
 <!-- ------------------- end of main content --------------- -->

+ 73 - 57
doc/pub/tutorial/._pysketcher001.html

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                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'),
+              ('A simple pendulum',
+               1,
+               'sketcher:ex:pendulum',
+               'sketcher:ex:pendulum'),
+              ('The basic physics sketch',
+               2,
+               'sketcher:ex:pendulum:basic',
+               'sketcher:ex:pendulum:basic'),
+              ('The body diagram', 2, None, '___sec10'),
+              ('Basic shapes', 1, None, '___sec11'),
+              ('Axis', 2, None, '___sec12'),
+              ('Distance with text', 2, None, '___sec13'),
+              ('Rectangle', 2, None, '___sec14'),
+              ('Triangle', 2, None, '___sec15'),
+              ('Arc', 2, None, '___sec16'),
+              ('Spring', 2, None, '___sec17'),
+              ('Dashpot', 2, None, '___sec18'),
+              ('Wavy', 2, None, '___sec19'),
+              ('Stochastic curves', 2, None, '___sec20'),
+              ('Inner workings of the Pysketcher tool', 1, None, '___sec21'),
               ('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'),
+               '___sec22'),
+              ('Simple geometric objects', 3, None, '___sec23'),
+              ('Class curve', 3, None, '___sec24'),
+              ('Compound geometric objects', 3, None, '___sec25'),
+              ('Adding functionality via recursion', 2, None, '___sec26'),
+              ('Basic principles of recursion', 3, None, '___sec27'),
+              ('Explaining recursion', 3, None, '___sec28'),
               ('Scaling, translating, and rotating a figure',
                2,
                'sketcher:scaling',
                'sketcher:scaling'),
-              ('Scaling', 3, None, '___sec27'),
-              ('Translation', 3, None, '___sec28'),
-              ('Rotation', 3, None, '___sec29')]}
+              ('Scaling', 3, None, '___sec30'),
+              ('Translation', 3, None, '___sec31'),
+              ('Rotation', 3, None, '___sec32')]}
 end of tocinfo -->
 
 <body>
@@ -119,28 +128,31 @@ MathJax.Hub.Config({
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec5" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The figure composition as an object hierarchy</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec6" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: translating the vehicle</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#sketcher:vehicle1:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: rolling the wheels</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec8" style="font-size: 80%;"><b>Basic shapes</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec9" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec11" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec21" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec29" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum" style="font-size: 80%;"><b>A simple pendulum</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum:basic" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The basic physics sketch</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The body diagram</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec11" style="font-size: 80%;"><b>Basic shapes</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec21" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec26" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec30" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec31" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec32" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
 
         </ul>
       </li>
@@ -162,20 +174,23 @@ Table of contents</h2>
 <p>
 <a href="._pysketcher002.html#___sec0"> A first glimpse of Pysketcher </a><br>
 &nbsp; &nbsp; &nbsp; <a href="._pysketcher002.html#___sec1"> Basic construction of sketches </a><br>
-<a href="._pysketcher003.html#___sec8"> Basic shapes </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec9"> Axis </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec10"> Distance with text </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec11"> Rectangle </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec12"> Triangle </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec13"> Arc </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec14"> Spring </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec15"> Dashpot </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec16"> Wavy </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec17"> Stochastic curves </a><br>
-<a href="._pysketcher004.html#___sec18"> Inner workings of the Pysketcher tool </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec19"> Example of classes for geometric objects </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec23"> Adding functionality via recursion </a><br>
-&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#sketcher:scaling"> Scaling, translating, and rotating a figure </a><br>
+<a href="._pysketcher003.html#sketcher:ex:pendulum"> A simple pendulum </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#sketcher:ex:pendulum:basic"> The basic physics sketch </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher003.html#___sec10"> The body diagram </a><br>
+<a href="._pysketcher004.html#___sec11"> Basic shapes </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec12"> Axis </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec13"> Distance with text </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec14"> Rectangle </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec15"> Triangle </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec16"> Arc </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec17"> Spring </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec18"> Dashpot </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec19"> Wavy </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher004.html#___sec20"> Stochastic curves </a><br>
+<a href="._pysketcher005.html#___sec21"> Inner workings of the Pysketcher tool </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher005.html#___sec22"> Example of classes for geometric objects </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher005.html#___sec26"> Adding functionality via recursion </a><br>
+&nbsp; &nbsp; &nbsp; <a href="._pysketcher005.html#sketcher:scaling"> Scaling, translating, and rotating a figure </a><br>
 </p>
 <p>
 <p>
@@ -187,6 +202,7 @@ Table of contents</h2>
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</a></li>
+  <li><a href="._pysketcher005.html">6</a></li>
   <li><a href="._pysketcher002.html">&raquo;</a></li>
 </ul>
 <!-- ------------------- end of main content --------------- -->

+ 56 - 43
doc/pub/tutorial/._pysketcher002.html

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                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'),
+              ('A simple pendulum',
+               1,
+               'sketcher:ex:pendulum',
+               'sketcher:ex:pendulum'),
+              ('The basic physics sketch',
+               2,
+               'sketcher:ex:pendulum:basic',
+               'sketcher:ex:pendulum:basic'),
+              ('The body diagram', 2, None, '___sec10'),
+              ('Basic shapes', 1, None, '___sec11'),
+              ('Axis', 2, None, '___sec12'),
+              ('Distance with text', 2, None, '___sec13'),
+              ('Rectangle', 2, None, '___sec14'),
+              ('Triangle', 2, None, '___sec15'),
+              ('Arc', 2, None, '___sec16'),
+              ('Spring', 2, None, '___sec17'),
+              ('Dashpot', 2, None, '___sec18'),
+              ('Wavy', 2, None, '___sec19'),
+              ('Stochastic curves', 2, None, '___sec20'),
+              ('Inner workings of the Pysketcher tool', 1, None, '___sec21'),
               ('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'),
+               '___sec22'),
+              ('Simple geometric objects', 3, None, '___sec23'),
+              ('Class curve', 3, None, '___sec24'),
+              ('Compound geometric objects', 3, None, '___sec25'),
+              ('Adding functionality via recursion', 2, None, '___sec26'),
+              ('Basic principles of recursion', 3, None, '___sec27'),
+              ('Explaining recursion', 3, None, '___sec28'),
               ('Scaling, translating, and rotating a figure',
                2,
                'sketcher:scaling',
                'sketcher:scaling'),
-              ('Scaling', 3, None, '___sec27'),
-              ('Translation', 3, None, '___sec28'),
-              ('Rotation', 3, None, '___sec29')]}
+              ('Scaling', 3, None, '___sec30'),
+              ('Translation', 3, None, '___sec31'),
+              ('Rotation', 3, None, '___sec32')]}
 end of tocinfo -->
 
 <body>
@@ -119,28 +128,31 @@ MathJax.Hub.Config({
      <!-- navigation toc: --> <li><a href="#___sec5" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The figure composition as an object hierarchy</a></li>
      <!-- navigation toc: --> <li><a href="#___sec6" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: translating the vehicle</a></li>
      <!-- navigation toc: --> <li><a href="#sketcher:vehicle1:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: rolling the wheels</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec8" style="font-size: 80%;"><b>Basic shapes</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec9" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec11" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec21" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec29" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum" style="font-size: 80%;"><b>A simple pendulum</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum:basic" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The basic physics sketch</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The body diagram</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec11" style="font-size: 80%;"><b>Basic shapes</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec21" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec26" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec30" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec31" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec32" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
 
         </ul>
       </li>
@@ -827,6 +839,7 @@ coming from physics simulations of the problem, as shown in the example above.
   <li class="active"><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</a></li>
+  <li><a href="._pysketcher005.html">6</a></li>
   <li><a href="._pysketcher003.html">&raquo;</a></li>
 </ul>
 <!-- ------------------- end of main content --------------- -->

+ 294 - 325
doc/pub/tutorial/._pysketcher003.html

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                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'),
+              ('A simple pendulum',
+               1,
+               'sketcher:ex:pendulum',
+               'sketcher:ex:pendulum'),
+              ('The basic physics sketch',
+               2,
+               'sketcher:ex:pendulum:basic',
+               'sketcher:ex:pendulum:basic'),
+              ('The body diagram', 2, None, '___sec10'),
+              ('Basic shapes', 1, None, '___sec11'),
+              ('Axis', 2, None, '___sec12'),
+              ('Distance with text', 2, None, '___sec13'),
+              ('Rectangle', 2, None, '___sec14'),
+              ('Triangle', 2, None, '___sec15'),
+              ('Arc', 2, None, '___sec16'),
+              ('Spring', 2, None, '___sec17'),
+              ('Dashpot', 2, None, '___sec18'),
+              ('Wavy', 2, None, '___sec19'),
+              ('Stochastic curves', 2, None, '___sec20'),
+              ('Inner workings of the Pysketcher tool', 1, None, '___sec21'),
               ('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'),
+               '___sec22'),
+              ('Simple geometric objects', 3, None, '___sec23'),
+              ('Class curve', 3, None, '___sec24'),
+              ('Compound geometric objects', 3, None, '___sec25'),
+              ('Adding functionality via recursion', 2, None, '___sec26'),
+              ('Basic principles of recursion', 3, None, '___sec27'),
+              ('Explaining recursion', 3, None, '___sec28'),
               ('Scaling, translating, and rotating a figure',
                2,
                'sketcher:scaling',
                'sketcher:scaling'),
-              ('Scaling', 3, None, '___sec27'),
-              ('Translation', 3, None, '___sec28'),
-              ('Rotation', 3, None, '___sec29')]}
+              ('Scaling', 3, None, '___sec30'),
+              ('Translation', 3, None, '___sec31'),
+              ('Rotation', 3, None, '___sec32')]}
 end of tocinfo -->
 
 <body>
@@ -119,28 +128,31 @@ MathJax.Hub.Config({
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec5" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The figure composition as an object hierarchy</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec6" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: translating the vehicle</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#sketcher:vehicle1:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: rolling the wheels</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec8" style="font-size: 80%;"><b>Basic shapes</b></a></li>
-     <!-- navigation toc: --> <li><a href="#___sec9" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec11" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
-     <!-- navigation toc: --> <li><a href="#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec21" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec29" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
+     <!-- navigation toc: --> <li><a href="#sketcher:ex:pendulum" style="font-size: 80%;"><b>A simple pendulum</b></a></li>
+     <!-- navigation toc: --> <li><a href="#sketcher:ex:pendulum:basic" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The basic physics sketch</a></li>
+     <!-- navigation toc: --> <li><a href="#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The body diagram</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec11" style="font-size: 80%;"><b>Basic shapes</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec21" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec26" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec30" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec31" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec32" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
 
         </ul>
       </li>
@@ -156,394 +168,350 @@ MathJax.Hub.Config({
 <a name="part0003"></a>
 <!-- !split -->
 
-<h1 id="___sec8">Basic shapes </h1>
+<h1 id="sketcher:ex:pendulum">A simple pendulum</h1>
 
-<p>
-This section presents many of the basic shapes in Pysketcher:
-<code>Axis</code>, <code>Distance_wText</code>, <code>Rectangle</code>, 	<code>Triangle</code>, <code>Arc</code>,
-<code>Spring</code>, <code>Dashpot</code>, and <code>Wavy</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>draw_dimensions</code> in
-the shape classes, which annotates the basic drawing of the shape
-with the various geometric parameters that govern the shape.
+<h2 id="sketcher:ex:pendulum:basic">The basic physics sketch</h2>
 
-<h2 id="___sec9">Axis </h2>
+<p>
+We now want to make a sketch of simple pendulum from physics, as shown
+in Figure <a href="#sketcher:ex:pendulum:fig1">8</a>. A suggested work flow is to
+first sketch the figure on a piece of paper and introduce a coordinate
+system. A simple coordinate system is indicated in Figure
+<a href="#sketcher:ex:pendulum:fig1wgrid">9</a>. In a code we introduce variables
+<code>W</code> and <code>H</code> for the width and height of the figure (i.e., extent of
+the coordinate system) and open the program like this:
 
 <p>
-The <code>Axis</code> object gives the possibility draw a single axis to
-notify a coordinate system. Here is an example where we
-draw \( x \) and \( y \) axis of three coordinate systems of different
-rotation:
 
+<!-- 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>
+
+H <span style="color: #666666">=</span> <span style="color: #666666">7.</span>
+W <span style="color: #666666">=</span> <span style="color: #666666">6.</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,
+                                   ymin<span style="color: #666666">=0</span>, ymax<span style="color: #666666">=</span>H,
+                                   axis<span style="color: #666666">=</span><span style="color: #008000">True</span>)
+drawing_tool<span style="color: #666666">.</span>set_grid(<span style="color: #008000">True</span>)
+drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
+</pre></div>
 <p>
-<br />
-<br />
+Note that when the sketch is ready for &quot;production&quot;, we will (normally)
+set <code>axis=False</code> to remove the coordinate system and also remove the
+grid, i.e., delete or
+comment out the line <code>drawing_tool.set_grid(True)</code>.
+Also note that we in this example let all lines be blue by default.
 
 <p>
-<center><p><img src="fig-tut/Axis.png" align="bottom" width=500></p></center>
+<center> <!-- figure -->
+<hr class="figure">
+<center><p class="caption">Figure 8:  Sketch of a simple pendulum. <div id="sketcher:ex:pendulum:fig1"></div> </p></center>
+<p><img src="fig-tut/pendulum1.png" align="bottom" width=400></p>
+</center>
 
 <p>
-<br />
-<br />
+<center> <!-- figure -->
+<hr class="figure">
+<center><p class="caption">Figure 9:  Sketch of a simple pendulum. <div id="sketcher:ex:pendulum:fig1wgrid"></div> </p></center>
+<p><img src="fig-tut/pendulum1_wgrid.png" align="bottom" width=400></p>
+</center>
 
 <p>
-The corresponding code looks like this:
+The next step is to introduce variables for key quantities in the sketch.
+Let <code>L</code> be the length of the pendulum, <code>P</code> the rotation point, and let
+<code>a</code> be the angle the pendulum makes with the vertical (measured in degrees).
+We may set
 
 <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">test_Axis</span>():
-    drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
-        xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=15</span>, ymin<span style="color: #666666">=-7</span>, ymax<span style="color: #666666">=8</span>, axis<span style="color: #666666">=</span><span style="color: #008000">True</span>,
-        instruction_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;tmp_Axis.py&#39;</span>)
-    <span style="color: #408080; font-style: italic"># Draw normal x and y axis with origin at (7.5, 2)</span>
-    <span style="color: #408080; font-style: italic"># in the coordinate system of the sketch: [0,15]x[-7,8]</span>
-    x_axis <span style="color: #666666">=</span> Axis((<span style="color: #666666">7.5</span>,<span style="color: #666666">2</span>), <span style="color: #666666">5</span>, <span style="color: #BA2121">&#39;x&#39;</span>, rotation_angle<span style="color: #666666">=0</span>)
-    y_axis <span style="color: #666666">=</span> Axis((<span style="color: #666666">7.5</span>,<span style="color: #666666">2</span>), <span style="color: #666666">5</span>, <span style="color: #BA2121">&#39;y&#39;</span>, rotation_angle<span style="color: #666666">=90</span>)
-    system <span style="color: #666666">=</span> Composition({<span style="color: #BA2121">&#39;x axis&#39;</span>: x_axis, <span style="color: #BA2121">&#39;y axis&#39;</span>: y_axis})
-    system<span style="color: #666666">.</span>draw()
-    drawing_tool<span style="color: #666666">.</span>display()
-
-    <span style="color: #408080; font-style: italic"># Rotate this system 40 degrees counter clockwise</span>
-    <span style="color: #408080; font-style: italic"># and draw it with dashed lines</span>
-    system<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dashed&#39;</span>)
-    system<span style="color: #666666">.</span>rotate(<span style="color: #666666">40</span>, (<span style="color: #666666">7.5</span>,<span style="color: #666666">2</span>))
-    system<span style="color: #666666">.</span>draw()
-    drawing_tool<span style="color: #666666">.</span>display()
-
-    <span style="color: #408080; font-style: italic"># Rotate this system another 220 degrees and show</span>
-    <span style="color: #408080; font-style: italic"># with dotted lines</span>
-    system<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dotted&#39;</span>)
-    system<span style="color: #666666">.</span>rotate(<span style="color: #666666">220</span>, (<span style="color: #666666">7.5</span>,<span style="color: #666666">2</span>))
-    system<span style="color: #666666">.</span>draw()
-    drawing_tool<span style="color: #666666">.</span>display()
-
-    drawing_tool<span style="color: #666666">.</span>display(<span style="color: #BA2121">&#39;Axis&#39;</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">L <span style="color: #666666">=</span> <span style="color: #666666">5*</span>H<span style="color: #666666">/7</span>          <span style="color: #408080; font-style: italic"># length</span>
+P <span style="color: #666666">=</span> (W<span style="color: #666666">/6</span>, <span style="color: #666666">0.85*</span>H)  <span style="color: #408080; font-style: italic"># rotation point</span>
+a <span style="color: #666666">=</span> <span style="color: #666666">40</span>             <span style="color: #408080; font-style: italic"># angle</span>
 </pre></div>
-
-<h2 id="___sec10">Distance with text </h2>
-
 <p>
-The object <code>Distance_wText</code> is used to display an arrow, to indicate
-a distance in a sketch, with an additional text in the middle of the arrow.
+Be careful with integer division if you use Python 2! Fortunately, we
+started out with <code>float</code> objects for <code>W</code> and <code>H</code> so the expressions above
+are safe.
 
 <p>
-The figure
+What kind of objects do we need in this sketch? Looking at
+Figure <a href="#sketcher:ex:pendulum:fig1">8</a> we see that we need
 
-<p>
-<br />
-<br />
+<ol>
+<li> a vertical, dashed line</li>
+<li> an arc with no text but dashed line to indicate the <em>path</em> of the
+   mass</li>
+<li> an arc with name \( \theta \) to indicate the <em>angle</em></li>
+<li> a line, here called <em>rod</em>, from the rotation point to the mass</li>
+<li> a blue, filled circle representing the <em>mass</em></li>
+<li> a text \( m \) associated with the mass</li>
+<li> an indicator of the pendulum's <em>length</em> \( L \), visualized as
+   a line with two arrows tips and the text \( L \)</li>
+<li> a gravity vector with the text \( g \)</li>
+</ol>
 
-<p>
-<center><p><img src="fig-tut/Distance_wText.png" align="bottom" width=500></p></center>
+Pysketcher has objects for each of these elements in our sketch.
+We start with the simplest element: the vertical line, going from
+<code>P</code> to <code>P</code> minus the length in \( y \) direction:
 
 <p>
-<br />
-<br />
 
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">vertical <span style="color: #666666">=</span> Line(P, P<span style="color: #666666">-</span>point(<span style="color: #666666">0</span>,L))
+</pre></div>
 <p>
-was produced by this code:
+The path of the mass is an arc that can be made by
+Pysketcher's <code>Arc</code> object:
 
 <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">test_Distance_wText</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">=0</span>, ymax<span style="color: #666666">=6</span>,
-        axis<span style="color: #666666">=</span><span style="color: #008000">True</span>, instruction_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;tmp_Distance_wText.py&#39;</span>)
-
-    fontsize<span style="color: #666666">=14</span>
-    t <span style="color: #666666">=</span> <span style="color: #BA2121">r&#39;$ 2\pi R^2 $&#39;</span>  <span style="color: #408080; font-style: italic"># sample text</span>
-    examples <span style="color: #666666">=</span> Composition({
-        <span style="color: #BA2121">&#39;a0&#39;</span>: Distance_wText((<span style="color: #666666">4</span>,<span style="color: #666666">5</span>), (<span style="color: #666666">8</span>, <span style="color: #666666">5</span>), t, fontsize),
-        <span style="color: #BA2121">&#39;a6&#39;</span>: Distance_wText((<span style="color: #666666">4</span>,<span style="color: #666666">5</span>), (<span style="color: #666666">4</span>, <span style="color: #666666">4</span>), t, fontsize),
-        <span style="color: #BA2121">&#39;a1&#39;</span>: Distance_wText((<span style="color: #666666">0</span>,<span style="color: #666666">2</span>), (<span style="color: #666666">2</span>, <span style="color: #666666">4.5</span>), t, fontsize),
-        <span style="color: #BA2121">&#39;a2&#39;</span>: Distance_wText((<span style="color: #666666">0</span>,<span style="color: #666666">2</span>), (<span style="color: #666666">2</span>, <span style="color: #666666">0</span>), t, fontsize),
-        <span style="color: #BA2121">&#39;a3&#39;</span>: Distance_wText((<span style="color: #666666">2</span>,<span style="color: #666666">4.5</span>), (<span style="color: #666666">0</span>, <span style="color: #666666">5.5</span>), t, fontsize),
-        <span style="color: #BA2121">&#39;a4&#39;</span>: Distance_wText((<span style="color: #666666">8</span>,<span style="color: #666666">4</span>), (<span style="color: #666666">10</span>, <span style="color: #666666">3</span>), t, fontsize,
-                             text_spacing<span style="color: #666666">=-1./60</span>),
-        <span style="color: #BA2121">&#39;a5&#39;</span>: Distance_wText((<span style="color: #666666">8</span>,<span style="color: #666666">2</span>), (<span style="color: #666666">10</span>, <span style="color: #666666">1</span>), t, fontsize,
-                             text_spacing<span style="color: #666666">=-1./40</span>, alignment<span style="color: #666666">=</span><span style="color: #BA2121">&#39;right&#39;</span>),
-        <span style="color: #BA2121">&#39;c1&#39;</span>: Text_wArrow(<span style="color: #BA2121">&#39;text_spacing=-1./60&#39;</span>,
-                          (<span style="color: #666666">4</span>, <span style="color: #666666">3.5</span>), (<span style="color: #666666">9</span>, <span style="color: #666666">3.2</span>),
-                          fontsize<span style="color: #666666">=10</span>, alignment<span style="color: #666666">=</span><span style="color: #BA2121">&#39;left&#39;</span>),
-        <span style="color: #BA2121">&#39;c2&#39;</span>: Text_wArrow(<span style="color: #BA2121">&#39;text_spacing=-1./40, alignment=&quot;right&quot;&#39;</span>,
-                          (<span style="color: #666666">4</span>, <span style="color: #666666">0.5</span>), (<span style="color: #666666">9</span>, <span style="color: #666666">1.2</span>),
-                          fontsize<span style="color: #666666">=10</span>, alignment<span style="color: #666666">=</span><span style="color: #BA2121">&#39;left&#39;</span>),
-        })
-    examples<span style="color: #666666">.</span>draw()
-    drawing_tool<span style="color: #666666">.</span>display(<span style="color: #BA2121">&#39;Distance_wText and text positioning&#39;</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">path <span style="color: #666666">=</span> Arc(P, L, <span style="color: #666666">-90</span>, a)
 </pre></div>
 <p>
-Note the use of <code>Text_wArrow</code> to write an explaining text with an
-associated arrow, here used to explain how
-the <code>text_spacing</code> and <code>alignment</code> arguments can be used to adjust
-the appearance of the text that goes with the distance arrow.
-
-<h2 id="___sec11">Rectangle </h2>
+The first argument <code>P</code> is the center point, the second is the
+radius (<code>L</code> here), the next arguments is the start angle, here
+it starts at -90 degrees, while the next argument is the angle of
+the arc, here <code>a</code>.
+For the path of the mass, we also need an arc object, but this
+time with an associated text. Pysketcher has a specialized object
+for this purpose, <code>Arc_wText</code>, since placing the text manually can
+be somewhat cumbersome.
 
 <p>
-<center><p><img src="fig-tut/Rectangle.png" align="bottom" width=500></p></center>
 
+<!-- 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> Arc_wText(<span style="color: #BA2121">r&#39;$\theta$&#39;</span>, P, L<span style="color: #666666">/4</span>, <span style="color: #666666">-90</span>, a, text_spacing<span style="color: #666666">=1/30.</span>)
+</pre></div>
 <p>
-<br />
-<br />
+The arguments are as for <code>Arc</code> above, but the first one is the desired
+text. Remember to use a raw string since we want a LaTeX greek letter
+that contains a backslash.
+The <code>text_spacing</code> argument must often be tweaked. It is recommended
+to create only a few objects before rendering the sketch and then
+adjust spacings as one goes along.
 
 <p>
-The above figure can be produced by the following code.
+The rod is simply a line from <code>P</code> to the mass. We can easily
+compute the position of the mass from basic geometry considerations,
+but it is easier and safer to look up this point in other objects
+if it is already computed. The <code>path</code> object stores its start and
+end points, so <code>path.geometric_features()['end']</code> is the end point
+of the path, which is the position of the mass. We can therefore
+create the rod simply as a line from <code>P</code> to this end point:
 
 <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">test_Rectangle</span>():
-    L <span style="color: #666666">=</span> <span style="color: #666666">3.0</span>
-    W <span style="color: #666666">=</span> <span style="color: #666666">4.0</span>
-
-    drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
-        xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=2*</span>W, ymin<span style="color: #666666">=-</span>L<span style="color: #666666">/2</span>, ymax<span style="color: #666666">=2*</span>L,
-        axis<span style="color: #666666">=</span><span style="color: #008000">True</span>, instruction_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;tmp_Rectangle.py&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_grid(<span style="color: #008000">True</span>)
-
-    xpos <span style="color: #666666">=</span> W<span style="color: #666666">/2</span>
-    r <span style="color: #666666">=</span> Rectangle(lower_left_corner<span style="color: #666666">=</span>(xpos,<span style="color: #666666">0</span>), width<span style="color: #666666">=</span>W, height<span style="color: #666666">=</span>L)
-    r<span style="color: #666666">.</span>draw()
-    r<span style="color: #666666">.</span>draw_dimensions()
-    drawing_tool<span style="color: #666666">.</span>display(<span style="color: #BA2121">&#39;Rectangle&#39;</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">mass_pt <span style="color: #666666">=</span> path<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>]
+rod <span style="color: #666666">=</span> Line(P, mass_pt)
 </pre></div>
 <p>
-Note that the <code>draw_dimension</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.
-
-<h2 id="___sec12">Triangle </h2>
+The mass is a circle filled with color:
 
 <p>
-<center><p><img src="fig-tut/Triangle.png" align="bottom" width=500></p></center>
-
-<p>
-<br />
-<br />
 
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">mass <span style="color: #666666">=</span> Circle(center<span style="color: #666666">=</span>mass_pt, radius<span style="color: #666666">=</span>L<span style="color: #666666">/20.</span>)
+mass<span style="color: #666666">.</span>set_filled_curves(color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;blue&#39;</span>)
+</pre></div>
 <p>
-The code below produces the figure.
+To place the \( m \) correctly, we go a small distance in the direction of
+the rod, from the center of the circle. To this end, we need to
+compute the direction. This is easiest done by computing a vector
+from <code>P</code> to the center of the circle and calling <code>unit_vec</code> to make
+a unit vector in this direction:
 
 <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">test_Triangle</span>():
-    L <span style="color: #666666">=</span> <span style="color: #666666">3.0</span>
-    W <span style="color: #666666">=</span> <span style="color: #666666">4.0</span>
-
-    drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
-        xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=2*</span>W, ymin<span style="color: #666666">=-</span>L<span style="color: #666666">/2</span>, ymax<span style="color: #666666">=1.2*</span>L,
-        axis<span style="color: #666666">=</span><span style="color: #008000">True</span>, instruction_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;tmp_Triangle.py&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_grid(<span style="color: #008000">True</span>)
-
-    xpos <span style="color: #666666">=</span> <span style="color: #666666">1</span>
-    t <span style="color: #666666">=</span> Triangle(p1<span style="color: #666666">=</span>(W<span style="color: #666666">/2</span>,<span style="color: #666666">0</span>), p2<span style="color: #666666">=</span>(<span style="color: #666666">3*</span>W<span style="color: #666666">/2</span>,W<span style="color: #666666">/2</span>), p3<span style="color: #666666">=</span>(<span style="color: #666666">4*</span>W<span style="color: #666666">/5.</span>,L))
-    t<span style="color: #666666">.</span>draw()
-    t<span style="color: #666666">.</span>draw_dimensions()
-    drawing_tool<span style="color: #666666">.</span>display(<span style="color: #BA2121">&#39;Triangle&#39;</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">rod_vec <span style="color: #666666">=</span> rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>] <span style="color: #666666">-</span> \ 
+          rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;start&#39;</span>]
+unit_rod_vec <span style="color: #666666">=</span> unit_vec(rod_vec)
+mass_symbol <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;$m$&#39;</span>, mass_pt <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_rod_vec)
 </pre></div>
 <p>
-Here, the <code>draw_dimension</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.
+Again, the distance <code>L/10</code> is something one has to experiment with.
 
-<h2 id="___sec13">Arc </h2>
+<p>
+The next object is the length measure with the text \( L \). Such length
+measures are represented by Pysketcher's <code>Distance_wText</code> object.
+An easy construction is to first place this length measure along the
+rod and then translate it a little distance (<code>L/15</code>) in the
+normal direction of the rod:
 
 <p>
-<center><p><img src="fig-tut/Arc.png" align="bottom" width=400></p></center>
 
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">length <span style="color: #666666">=</span> Distance_wText(P, mass_pt, <span style="color: #BA2121">&#39;$L$&#39;</span>)
+length<span style="color: #666666">.</span>translate(L<span style="color: #666666">/15*</span>point(cos(radians(a)), sin(radians(a))))
+</pre></div>
 <p>
-<br />
-<br />
+For this translation we need a unit vector in the normal direction
+of the rod, which is from geometric considerations given by
+\( (\cos a, \sin a) \), when \( a \) is the angle of the pendulum.
 
 <p>
-An arc like the one above is produced by
+The final object is the gravity force vector, which is so common
+in physics sketches that Pysketcher has a ready-made object: <code>Gravity</code>,
 
 <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">test_Arc</span>():
-    L <span style="color: #666666">=</span> <span style="color: #666666">4.0</span>
-    W <span style="color: #666666">=</span> <span style="color: #666666">4.0</span>
-
-    drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
-        xmin<span style="color: #666666">=-</span>W<span style="color: #666666">/2</span>, xmax<span style="color: #666666">=</span>W, ymin<span style="color: #666666">=-</span>L<span style="color: #666666">/2</span>, ymax<span style="color: #666666">=1.5*</span>L,
-        axis<span style="color: #666666">=</span><span style="color: #008000">True</span>, instruction_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;tmp_Arc.py&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_grid(<span style="color: #008000">True</span>)
-
-    center <span style="color: #666666">=</span> point(<span style="color: #666666">0</span>,<span style="color: #666666">0</span>)
-    radius <span style="color: #666666">=</span> L<span style="color: #666666">/2</span>
-    start_angle <span style="color: #666666">=</span> <span style="color: #666666">60</span>
-    arc_angle <span style="color: #666666">=</span> <span style="color: #666666">45</span>
-    a <span style="color: #666666">=</span> Arc(center, radius, start_angle, arc_angle)
-    a<span style="color: #666666">.</span>draw()
-
-    R1 <span style="color: #666666">=</span> <span style="color: #666666">1.25*</span>radius
-    R2 <span style="color: #666666">=</span> <span style="color: #666666">1.5*</span>radius
-    R <span style="color: #666666">=</span> <span style="color: #666666">2*</span>radius
-    a<span style="color: #666666">.</span>dimensions <span style="color: #666666">=</span> {
-        <span style="color: #BA2121">&#39;start_angle&#39;</span>:
-        Arc_wText(
-            <span style="color: #BA2121">&#39;start_angle&#39;</span>, center, R1, start_angle<span style="color: #666666">=0</span>,
-            arc_angle<span style="color: #666666">=</span>start_angle, text_spacing<span style="color: #666666">=1/10.</span>),
-        <span style="color: #BA2121">&#39;arc_angle&#39;</span>:
-        Arc_wText(
-            <span style="color: #BA2121">&#39;arc_angle&#39;</span>, center, R2, start_angle<span style="color: #666666">=</span>start_angle,
-            arc_angle<span style="color: #666666">=</span>arc_angle, text_spacing<span style="color: #666666">=1/20.</span>),
-        <span style="color: #BA2121">&#39;r=0&#39;</span>:
-        Line(center, center <span style="color: #666666">+</span>
-             point(R<span style="color: #666666">*</span>cos(radians(start_angle)),
-                   R<span style="color: #666666">*</span>sin(radians(start_angle)))),
-        <span style="color: #BA2121">&#39;r=start_angle&#39;</span>:
-        Line(center, center <span style="color: #666666">+</span>
-             point(R<span style="color: #666666">*</span>cos(radians(start_angle<span style="color: #666666">+</span>arc_angle)),
-                   R<span style="color: #666666">*</span>sin(radians(start_angle<span style="color: #666666">+</span>arc_angle)))),
-        <span style="color: #BA2121">&#39;r=start+arc_angle&#39;</span>:
-        Line(center, center <span style="color: #666666">+</span>
-             point(R, <span style="color: #666666">0</span>))<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dashed&#39;</span>),
-        <span style="color: #BA2121">&#39;radius&#39;</span>: Distance_wText(center, a(<span style="color: #666666">0</span>), <span style="color: #BA2121">&#39;radius&#39;</span>, text_spacing<span style="color: #666666">=1/40.</span>),
-        <span style="color: #BA2121">&#39;center&#39;</span>: Text(<span style="color: #BA2121">&#39;center&#39;</span>, center<span style="color: #666666">-</span>point(radius<span style="color: #666666">/10.</span>, radius<span style="color: #666666">/10.</span>)),
-        }
-    <span style="color: #008000; font-weight: bold">for</span> dimension <span style="color: #AA22FF; font-weight: bold">in</span> a<span style="color: #666666">.</span>dimensions:
-        <span style="color: #008000; font-weight: bold">if</span> dimension<span style="color: #666666">.</span>startswith(<span style="color: #BA2121">&#39;r=&#39;</span>):
-            dim <span style="color: #666666">=</span> a<span style="color: #666666">.</span>dimensions[dimension]
-            dim<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dashed&#39;</span>)
-            dim<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">1</span>)
-            dim<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;black&#39;</span>)
-
-    a<span style="color: #666666">.</span>draw_dimensions()
-    drawing_tool<span style="color: #666666">.</span>display(<span style="color: #BA2121">&#39;Arc&#39;</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">gravity <span style="color: #666666">=</span> Gravity(start<span style="color: #666666">=</span>P<span style="color: #666666">+</span>point(<span style="color: #666666">0.8*</span>L,<span style="color: #666666">0</span>), length<span style="color: #666666">=</span>L<span style="color: #666666">/3</span>)
 </pre></div>
-
-<h2 id="___sec14">Spring </h2>
-
 <p>
-<center><p><img src="fig-tut/Spring.png" align="bottom" width=800></p></center>
+Since blue is the default color for
+lines, we want the dashed lines (<code>vertical</code> and <code>path</code>) to be black
+and dashed with linewidth 1. These properties can be set one by one,
+but we can also make a little helper function:
 
 <p>
-<br />
-<br />
 
+<!-- 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">set_dashed_thin_blackline</span>(<span style="color: #666666">*</span>objects):
+    <span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Set linestyle of an object to dashed, black, width=1.&quot;&quot;&quot;</span>
+    <span style="color: #008000; font-weight: bold">for</span> obj <span style="color: #AA22FF; font-weight: bold">in</span> objects:
+        obj<span style="color: #666666">.</span>set_linestyle(<span style="color: #BA2121">&#39;dashed&#39;</span>)
+        obj<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;black&#39;</span>)
+        obj<span style="color: #666666">.</span>set_linewidth(<span style="color: #666666">1</span>)
+
+set_dashed_thin_blackline(vertical, path)
+</pre></div>
 <p>
-The code for making these two springs goes like this:
+Now, all objects are in place, so it remains to compose the final
+figure and draw the composition:
 
 <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">test_Spring</span>():
-    L <span style="color: #666666">=</span> <span style="color: #666666">5.0</span>
-    W <span style="color: #666666">=</span> <span style="color: #666666">2.0</span>
-
-    drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
-        xmin<span style="color: #666666">=0</span>, xmax<span style="color: #666666">=7*</span>W, ymin<span style="color: #666666">=-</span>L<span style="color: #666666">/2</span>, ymax<span style="color: #666666">=1.5*</span>L,
-        axis<span style="color: #666666">=</span><span style="color: #008000">True</span>, instruction_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;tmp_Spring.py&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_grid(<span style="color: #008000">True</span>)
-
-    xpos <span style="color: #666666">=</span> W
-    s1 <span style="color: #666666">=</span> Spring((W,<span style="color: #666666">0</span>), L, teeth<span style="color: #666666">=</span><span style="color: #008000">True</span>)
-    s1_title <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;Default Spring&#39;</span>,
-                    s1<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>] <span style="color: #666666">+</span> point(<span style="color: #666666">0</span>,L<span style="color: #666666">/10</span>))
-    s1<span style="color: #666666">.</span>draw()
-    s1_title<span style="color: #666666">.</span>draw()
-    <span style="color: #408080; font-style: italic">#s1.draw_dimensions()</span>
-    xpos <span style="color: #666666">+=</span> <span style="color: #666666">3*</span>W
-    s2 <span style="color: #666666">=</span> Spring(start<span style="color: #666666">=</span>(xpos,<span style="color: #666666">0</span>), length<span style="color: #666666">=</span>L, width<span style="color: #666666">=</span>W<span style="color: #666666">/2.</span>,
-                bar_length<span style="color: #666666">=</span>L<span style="color: #666666">/6.</span>, teeth<span style="color: #666666">=</span><span style="color: #008000">False</span>)
-    s2<span style="color: #666666">.</span>draw()
-    s2<span style="color: #666666">.</span>draw_dimensions()
-    drawing_tool<span style="color: #666666">.</span>display(<span style="color: #BA2121">&#39;Spring&#39;</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">fig <span style="color: #666666">=</span> Composition(
+    {<span style="color: #BA2121">&#39;body&#39;</span>: mass, <span style="color: #BA2121">&#39;rod&#39;</span>: rod,
+     <span style="color: #BA2121">&#39;vertical&#39;</span>: vertical, <span style="color: #BA2121">&#39;theta&#39;</span>: angle, <span style="color: #BA2121">&#39;path&#39;</span>: path,
+     <span style="color: #BA2121">&#39;g&#39;</span>: gravity, <span style="color: #BA2121">&#39;L&#39;</span>: length, <span style="color: #BA2121">&#39;m&#39;</span>: mass_symbol})
+
+fig<span style="color: #666666">.</span>draw()
+drawing_tool<span style="color: #666666">.</span>display()
+drawing_tool<span style="color: #666666">.</span>savefig(<span style="color: #BA2121">&#39;pendulum1&#39;</span>)
 </pre></div>
 
-<h2 id="___sec15">Dashpot </h2>
+<h2 id="___sec10">The body diagram </h2>
 
 <p>
-<center><p><img src="fig-tut/Dashpot.png" align="bottom" width=600></p></center>
+Now we want to isolate the mass and draw all the forces that act on it.
+Figure <a href="#sketcher:ex:pendulum:fig2wgrid">10</a> shows the desired result, but
+embedded in the coordinate system.
+We consider three types of forces: the gravity force, the force from the
+rod, and air resistance. The body diagram is key for deriving the
+equation of motion, so it is illustrative to add useful mathematical
+quantities needed in the derivation, such as the unit vectors in polar
+coordinates.
 
 <p>
-<br />
-<br />
+<center> <!-- figure -->
+<hr class="figure">
+<center><p class="caption">Figure 10:  Body diagram of a simple pendulum. <div id="sketcher:ex:pendulum:fig2wgrid"></div> </p></center>
+<p><img src="fig-tut/pendulum5_wgrid.png" align="bottom" width=400></p>
+</center>
 
 <p>
-This dashpot is produced by
+We start by listing the objects in the sketch:
+
+<ol>
+<li> a text \( (x_0,y_0) \) representing the rotation  point <code>P</code></li>
+<li> unit vector \( \boldsymbol{i}_r \) with text</li>
+<li> unit vector \( \boldsymbol{i}_\theta \) with text</li>
+<li> a dashed vertical line</li>
+<li> a dashed line along the rod</li>
+<li> an arc with text \( \theta \)</li>
+<li> the gravity force with text \( mg \)</li>
+<li> the force in the rod with text \( S \)</li>
+<li> the air resistance force with text \( \sim |v|v \)</li>
+</ol>
+
+The first object, \( (x_0,y_0) \), is simply a plain text where we have
+to experiment with the position. The unit vectors in polar coordinates
+may be drawn using the Pysketcher's <code>Force</code> object since it has an
+arrow with a text. The first three object can then be made as follows:
 
 <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">test_Dashpot</span>():
-    L <span style="color: #666666">=</span> <span style="color: #666666">5.0</span>
-    W <span style="color: #666666">=</span> <span style="color: #666666">2.0</span>
-    xpos <span style="color: #666666">=</span> <span style="color: #666666">0</span>
-
-    drawing_tool<span style="color: #666666">.</span>set_coordinate_system(
-        xmin<span style="color: #666666">=</span>xpos, xmax<span style="color: #666666">=</span>xpos<span style="color: #666666">+5.5*</span>W, ymin<span style="color: #666666">=-</span>L<span style="color: #666666">/2</span>, ymax<span style="color: #666666">=1.5*</span>L,
-        axis<span style="color: #666666">=</span><span style="color: #008000">True</span>, instruction_file<span style="color: #666666">=</span><span style="color: #BA2121">&#39;tmp_Dashpot.py&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_linecolor(<span style="color: #BA2121">&#39;blue&#39;</span>)
-    drawing_tool<span style="color: #666666">.</span>set_grid(<span style="color: #008000">True</span>)
-
-    <span style="color: #408080; font-style: italic"># Default (simple) dashpot</span>
-    xpos <span style="color: #666666">=</span> <span style="color: #666666">1.5</span>
-    d1 <span style="color: #666666">=</span> Dashpot(start<span style="color: #666666">=</span>(xpos,<span style="color: #666666">0</span>), total_length<span style="color: #666666">=</span>L)
-    d1_title <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;Dashpot (default)&#39;</span>,
-                    d1<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;end&#39;</span>] <span style="color: #666666">+</span> point(<span style="color: #666666">0</span>,L<span style="color: #666666">/10</span>))
-    d1<span style="color: #666666">.</span>draw()
-    d1_title<span style="color: #666666">.</span>draw()
-
-    <span style="color: #408080; font-style: italic"># Dashpot for animation with fixed bar_length, dashpot_length and</span>
-    <span style="color: #408080; font-style: italic"># prescribed piston_pos</span>
-    xpos <span style="color: #666666">+=</span> <span style="color: #666666">2.5*</span>W
-    d2 <span style="color: #666666">=</span> Dashpot(start<span style="color: #666666">=</span>(xpos,<span style="color: #666666">0</span>), total_length<span style="color: #666666">=1.2*</span>L, width<span style="color: #666666">=</span>W<span style="color: #666666">/2</span>,
-                 bar_length<span style="color: #666666">=</span>W, dashpot_length<span style="color: #666666">=</span>L<span style="color: #666666">/2</span>, piston_pos<span style="color: #666666">=2*</span>W)
-    d2<span style="color: #666666">.</span>draw()
-    d2<span style="color: #666666">.</span>draw_dimensions()
-
-    drawing_tool<span style="color: #666666">.</span>display(<span style="color: #BA2121">&#39;Dashpot&#39;</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">x0y0 <span style="color: #666666">=</span> Text(<span style="color: #BA2121">&#39;$(x_0,y_0)$&#39;</span>, P <span style="color: #666666">+</span> point(<span style="color: #666666">-0.4</span>,<span style="color: #666666">-0.1</span>))
+ir <span style="color: #666666">=</span> Force(P, P <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_vec(rod_vec),
+           <span style="color: #BA2121">r&#39;$\boldsymbol{i}_r$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
+           text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.015</span>,<span style="color: #666666">0</span>))
+ith <span style="color: #666666">=</span> Force(P, P <span style="color: #666666">+</span> L<span style="color: #666666">/10*</span>unit_vec((<span style="color: #666666">-</span>rod_vec[<span style="color: #666666">1</span>], rod_vec[<span style="color: #666666">0</span>])),
+           <span style="color: #BA2121">r&#39;$\boldsymbol{i}_{\theta}$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
+            text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.02</span>,<span style="color: #666666">0.005</span>))
 </pre></div>
-
-<h2 id="___sec16">Wavy </h2>
-
 <p>
-Looks strange. Fix x axis.
+Note that tweaking of the position of <code>x0y0</code> use absolute coordinates, so
+if <code>W</code> or <code>H</code> is changed in the beginning of the figure, the tweaked position
+will most likely not look good. A better solution would be to express
+the tweaked displacement <code>point(-0.4,-0.1)</code> in terms of <code>W</code> and <code>H</code>.
+The <code>text_spacing</code> values in the <code>Force</code> objects also use absolute
+coordinates. Very often, this is much more convenient when adjusting
+the objects, and global size parameters like <code>W</code> and <code>H</code> are in practice
+seldom changed.
 
-<h2 id="___sec17">Stochastic curves </h2>
+<p>
+The vertical, dashed line, the dashed rod, and the arc for \( \theta \)
+are made by
 
 <p>
-The <code>StochasticWavyCurve</code> object offers three precomputed
-graphics that have a random variation:
 
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">rod_start <span style="color: #666666">=</span> rod<span style="color: #666666">.</span>geometric_features()[<span style="color: #BA2121">&#39;start&#39;</span>]  <span style="color: #408080; font-style: italic"># Point P</span>
+vertical2 <span style="color: #666666">=</span> Line(rod_start, rod_start <span style="color: #666666">+</span> point(<span style="color: #666666">0</span>,<span style="color: #666666">-</span>L<span style="color: #666666">/3</span>))
+set_dashed_thin_blackline(vertical2)
+set_dashed_thin_blackline(rod)
+angle2 <span style="color: #666666">=</span> Arc_wText(<span style="color: #BA2121">r&#39;$\theta$&#39;</span>, rod_start, L<span style="color: #666666">/6</span>, <span style="color: #666666">-90</span>, a,
+                   text_spacing<span style="color: #666666">=1/30.</span>)
+</pre></div>
 <p>
-<br />
-<br />
+Note how we reuse the earlier defined object <code>rod</code>.
 
 <p>
-<center><p><img src="fig-tut/StochasticWavyCurve.png" align="bottom" width=600></p></center>
+The forces are constructed as shown below.
 
 <p>
-<br />
-<br />
 
+<!-- code=python (!bc pycod) typeset with pygments style "default" -->
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">mg_force  <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">+</span> L<span style="color: #666666">/5*</span>point(<span style="color: #666666">0</span>,<span style="color: #666666">-1</span>),
+                  <span style="color: #BA2121">&#39;$mg$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>)
+rod_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">-</span> L<span style="color: #666666">/3*</span>unit_vec(rod_vec),
+                  <span style="color: #BA2121">&#39;$S$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
+                  text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.03</span>, <span style="color: #666666">0.01</span>))
+air_force <span style="color: #666666">=</span> Force(mass_pt, mass_pt <span style="color: #666666">-</span>
+                  L<span style="color: #666666">/6*</span>unit_vec((rod_vec[<span style="color: #666666">1</span>], <span style="color: #666666">-</span>rod_vec[<span style="color: #666666">0</span>])),
+                  <span style="color: #BA2121">&#39;$\sim|v|v$&#39;</span>, text_pos<span style="color: #666666">=</span><span style="color: #BA2121">&#39;end&#39;</span>,
+                  text_spacing<span style="color: #666666">=</span>(<span style="color: #666666">0.04</span>,<span style="color: #666666">0.005</span>))
+</pre></div>
 <p>
-The usage is simple. The construction
+All objects are in place, and we can compose a figure to be drawn:
 
 <p>
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
-<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">curve <span style="color: #666666">=</span> StochasticWavyCurve(curve_no<span style="color: #666666">=1</span>, percentage<span style="color: #666666">=40</span>)
+<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">body_diagram <span style="color: #666666">=</span> Composition(
+    {<span style="color: #BA2121">&#39;mg&#39;</span>: mg_force, <span style="color: #BA2121">&#39;S&#39;</span>: rod_force, <span style="color: #BA2121">&#39;rod&#39;</span>: rod,
+     <span style="color: #BA2121">&#39;vertical&#39;</span>: vertical2, <span style="color: #BA2121">&#39;theta&#39;</span>: angle2,
+     <span style="color: #BA2121">&#39;body&#39;</span>: mass, <span style="color: #BA2121">&#39;m&#39;</span>: mass_symbol})
+
+body_diagram[<span style="color: #BA2121">&#39;air&#39;</span>] <span style="color: #666666">=</span> air_force
+body_diagram[<span style="color: #BA2121">&#39;ir&#39;</span>] <span style="color: #666666">=</span> ir
+body_diagram[<span style="color: #BA2121">&#39;ith&#39;</span>] <span style="color: #666666">=</span> ith
+body_diagram[<span style="color: #BA2121">&#39;origin&#39;</span>] <span style="color: #666666">=</span> x0y0
 </pre></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>curve.x[curve_no]</code> and
-<code>curve.y[curve_no]</code>.
+Here, we exemplify that we can start out with a composition as a
+dictionary, but (as in ordinary Python dictionaries) add new
+elements later when desired.
+
+<p>
+<!-- FIGURE: [fig-tut/pendulum1.png, width=400 frac=0.5] Sketch of a simple pendulum. <div id="sketcher:ex:pendulum:fig2"></div> -->
 
 <p>
 <p>
@@ -555,6 +523,7 @@ are stored in the arrays <code>curve.x[curve_no]</code> and
   <li><a href="._pysketcher002.html">3</a></li>
   <li class="active"><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</a></li>
+  <li><a href="._pysketcher005.html">6</a></li>
   <li><a href="._pysketcher004.html">&raquo;</a></li>
 </ul>
 <!-- ------------------- end of main content --------------- -->

+ 1 - 1
doc/pub/tutorial/html/.buildinfo

@@ -1,4 +1,4 @@
 # Sphinx build info version 1
 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: b7768360f818b5d2d2965679d67c458a
+config: 8268ab8f943669e8e06fc313365ba29a
 tags: 645f666f9bcd5a90fca523b33c5a78b7

+ 323 - 1
doc/pub/tutorial/html/_sources/main_sketcher.txt

@@ -9,7 +9,7 @@ Pysketcher: Create Principal Sketches of Physics Problems
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 :Authors: Hans Petter Langtangen
-:Date: Dec 23, 2015
+:Date: Jan 22, 2016
 
 
 .. The below box could be typeset as .. admonition: Attention
@@ -664,6 +664,328 @@ coming from physics simulations of the problem, as shown in the example above.
 
 .. !split
 
+.. _sketcher:ex:pendulum:
+
+A simple pendulum
+=================
+
+.. _sketcher:ex:pendulum:basic:
+
+The basic physics sketch
+------------------------
+
+We now want to make a sketch of simple pendulum from physics, as shown
+in Figure :ref:`sketcher:ex:pendulum:fig1`. A suggested work flow is to
+first sketch the figure on a piece of paper and introduce a coordinate
+system. A simple coordinate system is indicated in Figure
+:ref:`sketcher:ex:pendulum:fig1wgrid`. In a code we introduce variables
+``W`` and ``H`` for the width and height of the figure (i.e., extent of
+the coordinate system) and open the program like this:
+
+.. code-block:: python
+
+        from pysketcher import *
+        
+        H = 7.
+        W = 6.
+        
+        drawing_tool.set_coordinate_system(xmin=0, xmax=W,
+                                           ymin=0, ymax=H,
+                                           axis=True)
+        drawing_tool.set_grid(True)
+        drawing_tool.set_linecolor('blue')
+
+Note that when the sketch is ready for "production", we will (normally)
+set ``axis=False`` to remove the coordinate system and also remove the
+grid, i.e., delete or
+comment out the line ``drawing_tool.set_grid(True)``.
+Also note that we in this example let all lines be blue by default.
+
+.. _sketcher:ex:pendulum:fig1:
+
+.. figure:: pendulum1.png
+   :width: 400
+
+   *Sketch of a simple pendulum*
+
+.. _sketcher:ex:pendulum:fig1wgrid:
+
+.. figure:: pendulum1_wgrid.png
+   :width: 400
+
+   *Sketch of a simple pendulum*
+
+The next step is to introduce variables for key quantities in the sketch.
+Let ``L`` be the length of the pendulum, ``P`` the rotation point, and let
+``a`` be the angle the pendulum makes with the vertical (measured in degrees).
+We may set
+
+.. code-block:: python
+
+        L = 5*H/7          # length
+        P = (W/6, 0.85*H)  # rotation point
+        a = 40             # angle
+
+Be careful with integer division if you use Python 2! Fortunately, we
+started out with ``float`` objects for ``W`` and ``H`` so the expressions above
+are safe.
+
+What kind of objects do we need in this sketch? Looking at
+Figure :ref:`sketcher:ex:pendulum:fig1` we see that we need
+
+1. a vertical, dashed line
+
+2. an arc with no text but dashed line to indicate the *path* of the
+   mass
+
+3. an arc with name :math:`\theta` to indicate the *angle*
+
+4. a line, here called *rod*, from the rotation point to the mass
+
+5. a blue, filled circle representing the *mass*
+
+6. a text :math:`m` associated with the mass
+
+7. an indicator of the pendulum's *length* :math:`L`, visualized as
+   a line with two arrows tips and the text :math:`L`
+
+8. a gravity vector with the text :math:`g`
+
+Pysketcher has objects for each of these elements in our sketch.
+We start with the simplest element: the vertical line, going from
+``P`` to ``P`` minus the length in :math:`y` direction:
+
+.. code-block:: python
+
+        vertical = Line(P, P-point(0,L))
+
+The path of the mass is an arc that can be made by
+Pysketcher's ``Arc`` object:
+
+.. code-block:: python
+
+        path = Arc(P, L, -90, a)
+
+The first argument ``P`` is the center point, the second is the
+radius (``L`` here), the next arguments is the start angle, here
+it starts at -90 degrees, while the next argument is the angle of
+the arc, here ``a``.
+For the path of the mass, we also need an arc object, but this
+time with an associated text. Pysketcher has a specialized object
+for this purpose, ``Arc_wText``, since placing the text manually can
+be somewhat cumbersome.
+
+.. code-block:: python
+
+        angle = Arc_wText(r'$\theta$', P, L/4, -90, a, text_spacing=1/30.)
+
+The arguments are as for ``Arc`` above, but the first one is the desired
+text. Remember to use a raw string since we want a LaTeX greek letter
+that contains a backslash.
+The ``text_spacing`` argument must often be tweaked. It is recommended
+to create only a few objects before rendering the sketch and then
+adjust spacings as one goes along.
+
+The rod is simply a line from ``P`` to the mass. We can easily
+compute the position of the mass from basic geometry considerations,
+but it is easier and safer to look up this point in other objects
+if it is already computed. The ``path`` object stores its start and
+end points, so ``path.geometric_features()['end']`` is the end point
+of the path, which is the position of the mass. We can therefore
+create the rod simply as a line from ``P`` to this end point:
+
+.. code-block:: python
+
+        mass_pt = path.geometric_features()['end']
+        rod = Line(P, mass_pt)
+
+The mass is a circle filled with color:
+
+.. code-block:: python
+
+        mass = Circle(center=mass_pt, radius=L/20.)
+        mass.set_filled_curves(color='blue')
+
+To place the :math:`m` correctly, we go a small distance in the direction of
+the rod, from the center of the circle. To this end, we need to
+compute the direction. This is easiest done by computing a vector
+from ``P`` to the center of the circle and calling ``unit_vec`` to make
+a unit vector in this direction:
+
+.. code-block:: python
+
+        rod_vec = rod.geometric_features()['end'] - \ 
+                  rod.geometric_features()['start']
+        unit_rod_vec = unit_vec(rod_vec)
+        mass_symbol = Text('$m$', mass_pt + L/10*unit_rod_vec)
+
+Again, the distance ``L/10`` is something one has to experiment with.
+
+The next object is the length measure with the text :math:`L`. Such length
+measures are represented by Pysketcher's ``Distance_wText`` object.
+An easy construction is to first place this length measure along the
+rod and then translate it a little distance (``L/15``) in the
+normal direction of the rod:
+
+.. code-block:: python
+
+        length = Distance_wText(P, mass_pt, '$L$')
+        length.translate(L/15*point(cos(radians(a)), sin(radians(a))))
+
+For this translation we need a unit vector in the normal direction
+of the rod, which is from geometric considerations given by
+:math:`(\cos a, \sin a)`, when :math:`a` is the angle of the pendulum.
+
+The final object is the gravity force vector, which is so common
+in physics sketches that Pysketcher has a ready-made object: ``Gravity``,
+
+.. code-block:: python
+
+        gravity = Gravity(start=P+point(0.8*L,0), length=L/3)
+
+Since blue is the default color for
+lines, we want the dashed lines (``vertical`` and ``path``) to be black
+and dashed with linewidth 1. These properties can be set one by one,
+but we can also make a little helper function:
+
+.. code-block:: python
+
+        def set_dashed_thin_blackline(*objects):
+            """Set linestyle of an object to dashed, black, width=1."""
+            for obj in objects:
+                obj.set_linestyle('dashed')
+                obj.set_linecolor('black')
+                obj.set_linewidth(1)
+        
+        set_dashed_thin_blackline(vertical, path)
+
+Now, all objects are in place, so it remains to compose the final
+figure and draw the composition:
+
+.. code-block:: python
+
+        fig = Composition(
+            {'body': mass, 'rod': rod,
+             'vertical': vertical, 'theta': angle, 'path': path,
+             'g': gravity, 'L': length, 'm': mass_symbol})
+        
+        fig.draw()
+        drawing_tool.display()
+        drawing_tool.savefig('pendulum1')
+
+The body diagram
+----------------
+
+Now we want to isolate the mass and draw all the forces that act on it.
+Figure :ref:`sketcher:ex:pendulum:fig2wgrid` shows the desired result, but
+embedded in the coordinate system.
+We consider three types of forces: the gravity force, the force from the
+rod, and air resistance. The body diagram is key for deriving the
+equation of motion, so it is illustrative to add useful mathematical
+quantities needed in the derivation, such as the unit vectors in polar
+coordinates.
+
+.. _sketcher:ex:pendulum:fig2wgrid:
+
+.. figure:: pendulum5_wgrid.png
+   :width: 400
+
+   *Body diagram of a simple pendulum*
+
+We start by listing the objects in the sketch:
+
+1. a text :math:`(x_0,y_0)` representing the rotation  point ``P``
+
+2. unit vector :math:`\boldsymbol{i}_r` with text
+
+3. unit vector :math:`\boldsymbol{i}_\theta` with text
+
+4. a dashed vertical line
+
+5. a dashed line along the rod
+
+6. an arc with text :math:`\theta`
+
+7. the gravity force with text :math:`mg`
+
+8. the force in the rod with text :math:`S`
+
+9. the air resistance force with text :math:`\sim |v|v`
+
+The first object, :math:`(x_0,y_0)`, is simply a plain text where we have
+to experiment with the position. The unit vectors in polar coordinates
+may be drawn using the Pysketcher's ``Force`` object since it has an
+arrow with a text. The first three object can then be made as follows:
+
+.. code-block:: python
+
+        x0y0 = Text('$(x_0,y_0)$', P + point(-0.4,-0.1))
+        ir = Force(P, P + L/10*unit_vec(rod_vec),
+                   r'$\boldsymbol{i}_r$', text_pos='end',
+                   text_spacing=(0.015,0))
+        ith = Force(P, P + L/10*unit_vec((-rod_vec[1], rod_vec[0])),
+                   r'$\boldsymbol{i}_{\theta}$', text_pos='end',
+                    text_spacing=(0.02,0.005))
+
+Note that tweaking of the position of ``x0y0`` use absolute coordinates, so
+if ``W`` or ``H`` is changed in the beginning of the figure, the tweaked position
+will most likely not look good. A better solution would be to express
+the tweaked displacement ``point(-0.4,-0.1)`` in terms of ``W`` and ``H``.
+The ``text_spacing`` values in the ``Force`` objects also use absolute
+coordinates. Very often, this is much more convenient when adjusting
+the objects, and global size parameters like ``W`` and ``H`` are in practice
+seldom changed.
+
+The vertical, dashed line, the dashed rod, and the arc for :math:`\theta`
+are made by
+
+.. code-block:: python
+
+        rod_start = rod.geometric_features()['start']  # Point P
+        vertical2 = Line(rod_start, rod_start + point(0,-L/3))
+        set_dashed_thin_blackline(vertical2)
+        set_dashed_thin_blackline(rod)
+        angle2 = Arc_wText(r'$\theta$', rod_start, L/6, -90, a,
+                           text_spacing=1/30.)
+
+Note how we reuse the earlier defined object ``rod``.
+
+The forces are constructed as shown below.
+
+.. code-block:: python
+
+        mg_force  = Force(mass_pt, mass_pt + L/5*point(0,-1),
+                          '$mg$', text_pos='end')
+        rod_force = Force(mass_pt, mass_pt - L/3*unit_vec(rod_vec),
+                          '$S$', text_pos='end',
+                          text_spacing=(0.03, 0.01))
+        air_force = Force(mass_pt, mass_pt -
+                          L/6*unit_vec((rod_vec[1], -rod_vec[0])),
+                          '$\sim|v|v$', text_pos='end',
+                          text_spacing=(0.04,0.005))
+
+All objects are in place, and we can compose a figure to be drawn:
+
+.. code-block:: python
+
+        body_diagram = Composition(
+            {'mg': mg_force, 'S': rod_force, 'rod': rod,
+             'vertical': vertical2, 'theta': angle2,
+             'body': mass, 'm': mass_symbol})
+        
+        body_diagram['air'] = air_force
+        body_diagram['ir'] = ir
+        body_diagram['ith'] = ith
+        body_diagram['origin'] = x0y0
+
+Here, we exemplify that we can start out with a composition as a
+dictionary, but (as in ordinary Python dictionaries) add new
+elements later when desired.
+
+.. FIGURE: [fig-tut/pendulum1.png, width=400 frac=0.5] Sketch of a simple pendulum.
+
+.. !split
+
 Basic shapes
 ============
 

+ 1 - 1
doc/pub/tutorial/html/genindex.html

@@ -145,7 +145,7 @@
     <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
     <br />
     <br />
-      &copy;2015, Hans Petter Langtangen.
+      &copy;2016, Hans Petter Langtangen.
   </div>
 </div>
 

+ 6 - 1
doc/pub/tutorial/html/index.html

@@ -84,6 +84,11 @@
 <li class="toctree-l3"><a class="reference internal" href="main_sketcher.html#basic-construction-of-sketches">Basic construction of sketches</a></li>
 </ul>
 </li>
+<li class="toctree-l2"><a class="reference internal" href="main_sketcher.html#a-simple-pendulum">A simple pendulum</a><ul>
+<li class="toctree-l3"><a class="reference internal" href="main_sketcher.html#the-basic-physics-sketch">The basic physics sketch</a></li>
+<li class="toctree-l3"><a class="reference internal" href="main_sketcher.html#the-body-diagram">The body diagram</a></li>
+</ul>
+</li>
 <li class="toctree-l2"><a class="reference internal" href="main_sketcher.html#basic-shapes">Basic shapes</a><ul>
 <li class="toctree-l3"><a class="reference internal" href="main_sketcher.html#axis">Axis</a></li>
 <li class="toctree-l3"><a class="reference internal" href="main_sketcher.html#distance-with-text">Distance with text</a></li>
@@ -175,7 +180,7 @@
     <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
     <br />
     <br />
-      &copy;2015, Hans Petter Langtangen.
+      &copy;2016, Hans Petter Langtangen.
   </div>
 </div>
 

ファイルの差分が大きいため隠しています
+ 257 - 3
doc/pub/tutorial/html/main_sketcher.html


BIN
doc/pub/tutorial/html/objects.inv


+ 1 - 1
doc/pub/tutorial/html/search.html

@@ -130,7 +130,7 @@
     <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
     <br />
     <br />
-      &copy;2015, Hans Petter Langtangen.
+      &copy;2016, Hans Petter Langtangen.
   </div>
 </div>
 

ファイルの差分が大きいため隠しています
+ 1 - 1
doc/pub/tutorial/html/searchindex.js


BIN
doc/pub/tutorial/mov-tut/pendulum/movie.flv


BIN
doc/pub/tutorial/mov-tut/pendulum/movie.mp4


BIN
doc/pub/tutorial/mov-tut/pendulum/movie.ogg


BIN
doc/pub/tutorial/mov-tut/pendulum/movie.webm


+ 57 - 44
doc/pub/tutorial/pysketcher.html

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                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'),
+              ('A simple pendulum',
+               1,
+               'sketcher:ex:pendulum',
+               'sketcher:ex:pendulum'),
+              ('The basic physics sketch',
+               2,
+               'sketcher:ex:pendulum:basic',
+               'sketcher:ex:pendulum:basic'),
+              ('The body diagram', 2, None, '___sec10'),
+              ('Basic shapes', 1, None, '___sec11'),
+              ('Axis', 2, None, '___sec12'),
+              ('Distance with text', 2, None, '___sec13'),
+              ('Rectangle', 2, None, '___sec14'),
+              ('Triangle', 2, None, '___sec15'),
+              ('Arc', 2, None, '___sec16'),
+              ('Spring', 2, None, '___sec17'),
+              ('Dashpot', 2, None, '___sec18'),
+              ('Wavy', 2, None, '___sec19'),
+              ('Stochastic curves', 2, None, '___sec20'),
+              ('Inner workings of the Pysketcher tool', 1, None, '___sec21'),
               ('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'),
+               '___sec22'),
+              ('Simple geometric objects', 3, None, '___sec23'),
+              ('Class curve', 3, None, '___sec24'),
+              ('Compound geometric objects', 3, None, '___sec25'),
+              ('Adding functionality via recursion', 2, None, '___sec26'),
+              ('Basic principles of recursion', 3, None, '___sec27'),
+              ('Explaining recursion', 3, None, '___sec28'),
               ('Scaling, translating, and rotating a figure',
                2,
                'sketcher:scaling',
                'sketcher:scaling'),
-              ('Scaling', 3, None, '___sec27'),
-              ('Translation', 3, None, '___sec28'),
-              ('Rotation', 3, None, '___sec29')]}
+              ('Scaling', 3, None, '___sec30'),
+              ('Translation', 3, None, '___sec31'),
+              ('Rotation', 3, None, '___sec32')]}
 end of tocinfo -->
 
 <body>
@@ -119,28 +128,31 @@ MathJax.Hub.Config({
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec5" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The figure composition as an object hierarchy</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#___sec6" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: translating the vehicle</a></li>
      <!-- navigation toc: --> <li><a href="._pysketcher002.html#sketcher:vehicle1:anim" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animation: rolling the wheels</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec8" style="font-size: 80%;"><b>Basic shapes</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec9" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec11" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec21" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
-     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec29" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum" style="font-size: 80%;"><b>A simple pendulum</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#sketcher:ex:pendulum:basic" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The basic physics sketch</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher003.html#___sec10" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;The body diagram</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec11" style="font-size: 80%;"><b>Basic shapes</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec12" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Axis</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec13" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Distance with text</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec14" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Rectangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec15" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Triangle</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec16" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Arc</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec17" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Spring</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec18" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Dashpot</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec19" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Wavy</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher004.html#___sec20" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Stochastic curves</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec21" style="font-size: 80%;"><b>Inner workings of the Pysketcher tool</b></a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec22" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Example of classes for geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec23" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simple geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec24" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class curve</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec25" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compound geometric objects</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec26" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Adding functionality via recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec27" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Basic principles of recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec28" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Explaining recursion</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#sketcher:scaling" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;Scaling, translating, and rotating a figure</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec30" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scaling</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec31" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Translation</a></li>
+     <!-- navigation toc: --> <li><a href="._pysketcher005.html#___sec32" style="font-size: 80%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rotation</a></li>
 
         </ul>
       </li>
@@ -175,7 +187,7 @@ MathJax.Hub.Config({
 <center>[2] <b>Department of Informatics, University of Oslo</b></center>
 <br>
 <p>
-<center><h4>Dec 23, 2015</h4></center> <!-- date -->
+<center><h4>Jan 22, 2016</h4></center> <!-- date -->
 <br>
 <p>
 
@@ -231,6 +243,7 @@ no further background is required.
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</a></li>
+  <li><a href="._pysketcher005.html">6</a></li>
   <li><a href="._pysketcher001.html">&raquo;</a></li>
 </ul>
 <!-- ------------------- end of main content --------------- -->

BIN
doc/pub/tutorial/pysketcher.pdf


+ 5 - 0
doc/src/tut/.dict4spell.txt

@@ -1,13 +1,17 @@
 
+Cromer
 Dashpot
 ImageMagick
 Informatics
 Langtangen
 MPEG
 Matplotlib
+ODEs
 OO
+Odespy
 Pygame
 Pysketcher
+Pysketcher's
 SciTools
 Simula
 WebM
@@ -27,6 +31,7 @@ fillcolor
 gif
 github
 graphviz
+greek
 hier
 hplgit
 html

BIN
doc/src/tut/fig-tut/pendulum1.pdf


BIN
doc/src/tut/fig-tut/pendulum1.png


BIN
doc/src/tut/fig-tut/pendulum1_wgrid.pdf


BIN
doc/src/tut/fig-tut/pendulum1_wgrid.png


BIN
doc/src/tut/fig-tut/pendulum5.pdf


BIN
doc/src/tut/fig-tut/pendulum5.png


BIN
doc/src/tut/fig-tut/pendulum5_wgrid.pdf


BIN
doc/src/tut/fig-tut/pendulum5_wgrid.png


+ 3 - 0
doc/src/tut/main_sketcher.do.txt

@@ -52,6 +52,9 @@ TOC: on
 !split
 # #include "basics.do.txt"
 
+!split
+# #include "examples.do.txt"
+
 !split
 # #include "classes.do.txt"
 

+ 18 - 0
doc/src/tut/newcommands.tex

@@ -0,0 +1,18 @@
+\newcommand{\half}{\frac{1}{2}}
+\newcommand{\tp}{\thinspace .}
+
+\newcommand{\xpoint}{\bm{x}}
+\newcommand{\normalvec}{\bm{n}}
+\newcommand{\Oof}[1]{\mathcal{O}(#1)}
+
+% Boldface vectors/tensors
+\newcommand{\x}{\bm{x}}
+\renewcommand{\v}{\bm{v}}
+\newcommand{\rpos}{\bm{r}}
+% Unit vectors
+\newcommand{\ii}{\bm{i}}
+\newcommand{\jj}{\bm{j}}
+\newcommand{\kk}{\bm{k}}
+\newcommand{\ir}{\bm{i}_r}
+\newcommand{\ith}{\bm{i}_{\theta}}
+\newcommand{\iz}{\bm{i}_z}

+ 1 - 0
examples/beam1.py

@@ -1,3 +1,4 @@
+"""A very simple beam."""
 from pysketcher import *
 
 L = 8.0

+ 4 - 3
examples/beam2.py

@@ -1,3 +1,4 @@
+"""A more sophisticated beam than in beam1.py."""
 from pysketcher import *
 
 def beam():
@@ -93,19 +94,19 @@ def beam():
 
     beam.draw()
     drawing_tool.display()
-    drawing_tool.savefig('tmp_beam2_1.png')
+    drawing_tool.savefig('tmp_beam2_1')
 
     import time
     time.sleep(1.5)
 
     annotations.draw()
     drawing_tool.display()
-    drawing_tool.savefig('tmp_beam2_2.png')
+    drawing_tool.savefig('tmp_beam2_2')
     time.sleep(1.5)
 
     elastic_line.draw()
     drawing_tool.display()
-    drawing_tool.savefig('tmp_beam2_3.png')
+    drawing_tool.savefig('tmp_beam2_3')
     #beam.draw_dimensions()
     #test_Dashpot(xpos+2*W)
 

+ 38 - 34
examples/pendulum.py

@@ -6,24 +6,16 @@ W = 6.
 drawing_tool.set_coordinate_system(xmin=0, xmax=W,
                                    ymin=0, ymax=H,
                                    axis=False)
-drawing_tool.set_linecolor('blue')
 #drawing_tool.set_grid(True)
-
-def set_dashed_thin_blackline(*objects):
-    """Set linestyle of an object to dashed, black, width=1."""
-    for obj in objects:
-        obj.set_linestyle('dashed')
-        obj.set_linecolor('black')
-        obj.set_linewidth(1)
-
+drawing_tool.set_linecolor('blue')
 
 L = 5*H/7          # length
 P = (W/6, 0.85*H)  # rotation point
 a = 40             # angle
 
+vertical = Line(P, P-point(0,L))
 path = Arc(P, L, -90, a)
 angle = Arc_wText(r'$\theta$', P, L/4, -90, a, text_spacing=1/30.)
-vertical = Line(P, P-point(0,L))
 
 rod = Line(P, P + L*point(sin(radians(a)), -L*cos(radians(a))))
 # or shorter (and more reliable)
@@ -32,51 +24,63 @@ rod = Line(P, mass_pt)
 
 mass = Circle(center=mass_pt, radius=L/20.)
 mass.set_filled_curves(color='blue')
-rod_vec = rod.geometric_features()['end'] - rod.geometric_features()['start']
-mass_symbol = Text('$m$', mass_pt + L/10*unit_vec(rod_vec))
+rod_vec = rod.geometric_features()['end'] - \
+          rod.geometric_features()['start']
+unit_rod_vec = unit_vec(rod_vec)
+mass_symbol = Text('$m$', mass_pt + L/10*unit_rod_vec)
 
 length = Distance_wText(P, mass_pt, '$L$')
 # Displace length indication
 length.translate(L/15*point(cos(radians(a)), sin(radians(a))))
 gravity = Gravity(start=P+point(0.8*L,0), length=L/3)
 
+def set_dashed_thin_blackline(*objects):
+    """Set linestyle of objects to dashed, black, width=1."""
+    for obj in objects:
+        obj.set_linestyle('dashed')
+        obj.set_linecolor('black')
+        obj.set_linewidth(1)
+
 set_dashed_thin_blackline(vertical, path)
 
-dims = Composition(
-    {'vertical': vertical, 'theta': angle, 'path': path,
+fig = Composition(
+    {'body': mass, 'rod': rod,
+     'vertical': vertical, 'theta': angle, 'path': path,
      'g': gravity, 'L': length, 'm': mass_symbol})
 
-fig = Composition({'body': mass, 'rod': rod, 'dims': dims})
-
 fig.draw()
 drawing_tool.display()
 drawing_tool.savefig('tmp_pendulum1')
 
-# Draw body diagram
+# Draw body diagram in several different versions
+# (note that we build body_diagram, erase and draw,
+# add elements to body_diagram, erase and draw, and so on)
 input('Press Return to make body diagram: ')
-#import time; time.sleep(3)
+
 drawing_tool.erase()
 
 drawing_tool.set_linecolor('black')
-mg_force = Force(mass_pt, mass_pt + L/5*point(0,-1), '$mg$', text_pos='end')
-rod_force = Force(mass_pt, mass_pt - L/3*unit_vec(rod_vec),
-                  '$S$', text_pos='end', text_spacing=(0.03, 0.01))
 
-rod_start = rod.geometric_features()['start']
+rod_start = rod.geometric_features()['start']  # Point P
 vertical2 = Line(rod_start, rod_start + point(0,-L/3))
 set_dashed_thin_blackline(vertical2)
 set_dashed_thin_blackline(rod)
-angle2 = Arc_wText(r'$\theta$', rod_start, L/6, -90, a, text_spacing=1/30.)
+angle2 = Arc_wText(r'$\theta$', rod_start, L/6, -90, a,
+                   text_spacing=1/30.)
 
-# Cannot understand this one:
-#path2 = Arc(P, L, -90+a-a/2., a)
-#path2.set_arrow('<-')
-#path2.set_linestyle('dashed')
+mg_force  = Force(mass_pt, mass_pt + L/5*point(0,-1),
+                  '$mg$', text_pos='end')
+rod_force = Force(mass_pt, mass_pt - L/3*unit_vec(rod_vec),
+                  '$S$', text_pos='end',
+                  text_spacing=(0.03, 0.01))
+air_force = Force(mass_pt, mass_pt -
+                  L/6*unit_vec((rod_vec[1], -rod_vec[0])),
+                  '$\sim|v|v$', text_pos='end',
+                  text_spacing=(0.04,0.005))
 
 body_diagram = Composition(
     {'mg': mg_force, 'S': rod_force, 'rod': rod,
      'vertical': vertical2, 'theta': angle2,
-     #'path': path2,
      'body': mass, 'm': mass_symbol})
 
 body_diagram.draw()
@@ -88,23 +92,23 @@ drawing_tool.adjust_coordinate_system(body_diagram.minmax_coordinates(), 90)
 drawing_tool.savefig('tmp_pendulum3')
 
 drawing_tool.erase()
-air_force = Force(mass_pt, mass_pt - L/6*unit_vec((rod_vec[1], -rod_vec[0])),
-                  '$\sim|v|v$', text_pos='end', text_spacing=(0.04,0.005))
-
 body_diagram['air'] = air_force
 body_diagram.draw()
 #drawing_tool.display('Body diagram')
 drawing_tool.savefig('tmp_pendulum4')
 
 drawing_tool.erase()
+x0y0 = Text('$(x_0,y_0)$', P + point(-0.4,-0.1))
 ir = Force(P, P + L/10*unit_vec(rod_vec),
-           r'${\bf i}_r$', text_pos='end', text_spacing=(0.015,0))
+           r'$\boldsymbol{i}_r$', text_pos='end',
+           text_spacing=(0.015,0))
 ith = Force(P, P + L/10*unit_vec((-rod_vec[1], rod_vec[0])),
-           r'${\bf i}_{\theta}$', text_pos='end', text_spacing=(0.02,0.005))
+           r'$\boldsymbol{i}_{\theta}$', text_pos='end',
+            text_spacing=(0.02,0.005))
 
 body_diagram['ir'] = ir
 body_diagram['ith'] = ith
-body_diagram['origin'] = Text('$(x_0,y_0)$', P + point(-0.4,-0.1))
+body_diagram['origin'] = x0y0
 
 body_diagram.draw()
 #drawing_tool.display('Body diagram')

+ 173 - 0
examples/pendulum2.py

@@ -0,0 +1,173 @@
+"""
+Modified version of pendulum1.py:
+A function draws the body diagram, given the angle.
+This function can be coupled to a numerical solver
+for the motion. Videos of the motion are made.
+"""
+from pysketcher import *
+
+H = 15.
+W = 17.
+
+drawing_tool.set_coordinate_system(xmin=0, xmax=W,
+                                   ymin=0, ymax=H,
+                                   axis=False)
+
+def pendulum(theta, S, mg, drag, t, time_level):
+
+    drawing_tool.set_linecolor('blue')
+    import math
+    a = math.degrees(theta[time_level])
+    L = 0.4*H         # length
+    P = (W/2, 0.8*H)  # rotation point
+
+    vertical = Line(P, P-point(0,L))
+    path = Arc(P, L, -90, a)
+    angle = Arc_wText(r'$\theta$', P, L/4, -90, a, text_spacing=1/30.)
+
+    mass_pt = path.geometric_features()['end']
+    rod = Line(P, mass_pt)
+
+    mass = Circle(center=mass_pt, radius=L/20.)
+    mass.set_filled_curves(color='blue')
+    rod_vec = rod.geometric_features()['end'] - \
+              rod.geometric_features()['start']
+    unit_rod_vec = unit_vec(rod_vec)
+    mass_symbol = Text('$m$', mass_pt + L/10*unit_rod_vec)
+
+    length = Distance_wText(P, mass_pt, '$L$')
+    # Displace length indication
+    length.translate(L/15*point(cos(radians(a)), sin(radians(a))))
+    gravity = Gravity(start=P+point(0.8*L,0), length=L/3)
+
+    def set_dashed_thin_blackline(*objects):
+        """Set linestyle of objects to dashed, black, width=1."""
+        for obj in objects:
+            obj.set_linestyle('dashed')
+            obj.set_linecolor('black')
+            obj.set_linewidth(1)
+
+    set_dashed_thin_blackline(vertical, path)
+
+    fig = Composition(
+        {'body': mass, 'rod': rod,
+         'vertical': vertical, 'theta': angle, 'path': path,
+         'g': gravity, 'L': length})
+
+    #fig.draw()
+    #drawing_tool.display()
+    #drawing_tool.savefig('tmp_pendulum1')
+
+    drawing_tool.set_linecolor('black')
+
+    rod_start = rod.geometric_features()['start']  # Point P
+    vertical2 = Line(rod_start, rod_start + point(0,-L/3))
+    set_dashed_thin_blackline(vertical2)
+    set_dashed_thin_blackline(rod)
+    angle2 = Arc_wText(r'$\theta$', rod_start, L/6, -90, a,
+                       text_spacing=1/30.)
+
+    magnitude = 1.2*L/2   # length of a unit force in figure
+    force = mg[time_level]  # constant (scaled eq: about 1)
+    force *= magnitude
+    mg_force  = Force(mass_pt, mass_pt + force*point(0,-1),
+                      '', text_pos='end')
+    force = S[time_level]
+    force *= magnitude
+    rod_force = Force(mass_pt, mass_pt - force*unit_vec(rod_vec),
+                      '', text_pos='end',
+                      text_spacing=(0.03, 0.01))
+    force = drag[time_level]
+    force *= magnitude
+    #print('drag(%g)=%g' % (t, drag[time_level]))
+    air_force = Force(mass_pt, mass_pt -
+                      force*unit_vec((rod_vec[1], -rod_vec[0])),
+                      '', text_pos='end',
+                      text_spacing=(0.04,0.005))
+
+    body_diagram = Composition(
+        {'mg': mg_force, 'S': rod_force, 'air': air_force,
+         'rod': rod,
+         'vertical': vertical2, 'theta': angle2,
+         'body': mass})
+
+    x0y0 = Text('$(x_0,y_0)$', P + point(-0.4,-0.1))
+    ir = Force(P, P + L/10*unit_vec(rod_vec),
+               r'$\boldsymbol{i}_r$', text_pos='end',
+               text_spacing=(0.015,0))
+    ith = Force(P, P + L/10*unit_vec((-rod_vec[1], rod_vec[0])),
+               r'$\boldsymbol{i}_{\theta}$', text_pos='end',
+                text_spacing=(0.02,0.005))
+
+    #body_diagram['ir'] = ir
+    #body_diagram['ith'] = ith
+    #body_diagram['origin'] = x0y0
+
+    drawing_tool.erase()
+    body_diagram.draw(verbose=0)
+    #drawing_tool.display('Body diagram')
+    drawing_tool.savefig('tmp_%04d.png' % time_level, crop=False)
+    # No cropping: otherwise movies will be very strange
+
+def simulate_pendulum(alpha, theta0, dt, T):
+    import odespy
+
+    def f(u, t, alpha):
+        omega, theta = u
+        return [-alpha*omega*abs(omega) - sin(theta),
+                omega]
+
+    import numpy as np
+    Nt = int(round(T/float(dt)))
+    t = np.linspace(0, Nt*dt, Nt+1)
+    solver = odespy.RK4(f, f_args=[alpha])
+    solver.set_initial_condition([0, theta0])
+    u, t = solver.solve(t,
+                        terminate=lambda u, t, n: abs(u[n,1]) < 1E-3)
+    omega = u[:,0]
+    theta = u[:,1]
+    S = omega**2 + np.cos(theta)
+    drag = -alpha*np.abs(omega)*omega
+    return t, theta, omega, S, drag
+
+def animate():
+    # Clean up old plot files
+    import os, glob
+    for filename in glob.glob('tmp_*.png') + glob.glob('movie.*'):
+        os.remove(filename)
+    # Solve problem
+    from math import pi, radians, degrees
+    import numpy as np
+    alpha = 0.4
+    period = 2*pi
+    T = 12*period
+    dt = period/40
+    a = 70
+    theta0 = radians(a)
+    t, theta, omega, S, drag = simulate_pendulum(alpha, theta0, dt, T)
+    mg = np.ones(S.size)
+    # Visualize drag force 5 times as large
+    drag *= 5
+    print('NOTE: drag force magnified 5 times!!')
+
+    # Draw animation
+    import time
+    for time_level, t_ in enumerate(t):
+        pendulum(theta, S, mg, drag, t_, time_level)
+        time.sleep(0.2)
+
+    # Make videos
+    prog = 'ffmpeg'
+    filename = 'tmp_%04d.png'
+    fps = 6
+    codecs = {'flv': 'flv', 'mp4': 'libx264',
+              'webm': 'libvpx', 'ogg': 'libtheora'}
+    for ext in codecs:
+        lib = codecs[ext]
+        cmd = '%(prog)s -i %(filename)s -r %(fps)s ' % vars()
+        cmd += '-vcodec %(lib)s movie.%(ext)s' % vars()
+        print(cmd)
+        os.system(cmd)
+
+if __name__ == '__main__':
+    animate()

BIN
fig/beam2_3.pdf


BIN
fig/beam2_3.png


+ 29 - 16
pysketcher/MatplotlibDraw.py

@@ -11,7 +11,12 @@ from builtins import object
 
 import os
 import matplotlib
+
 matplotlib.use('TkAgg')
+# Allow \boldsymbol{} etc in title, labels, etc
+matplotlib.rc('text', usetex=True)
+matplotlib.rcParams['text.latex.preamble'] = '\\usepackage{amsmath}'
+
 import matplotlib.pyplot as mpl
 import matplotlib.transforms as transforms
 import numpy as np
@@ -113,6 +118,11 @@ class MatplotlibDraw(object):
         self.mpl.ion()  # important for interactive drawing and animation
         if self.instruction_file:
             self.instruction_file.write("""\
+import matplotlib
+matplotlib.use('TkAgg')
+# Allow \boldsymbol{} etc in title, labels, etc
+matplotlib.rc('text', usetex=True)
+matplotlib.rcParams['text.latex.preamble'] = '\\usepackage{amsmath}'
 import matplotlib.pyplot as mpl
 import matplotlib.transforms as transforms
 
@@ -350,23 +360,24 @@ self.ax.plot(x, y, linewidth=%d, color='gray',
         if self.instruction_file:
             self.instruction_file.write('mpl.draw()\n')
 
-    def savefig(self, filename, dpi=None):
+    def savefig(self, filename, dpi=None, crop=True):
         """Save figure in file. Set dpi=300 for really high resolution."""
         # If filename is without extension, generate all important formats
         ext = os.path.splitext(filename)[1]
         if not ext:
             # Create both PNG and PDF file
             self.mpl.savefig(filename + '.png', dpi=dpi)
-            # Crop the PNG file
-            failure = os.system('convert -trim %s.png %s.png' %
-                                (filename, filename))
-            if failure:
-                print('convert from ImageMagick is not installed - needed for cropping PNG files')
             self.mpl.savefig(filename + '.pdf')
-            failure = os.system('pdfcrop %s.pdf %s.pdf' %
-                                (filename, filename))
-            if failure:
-                print('pdfcrop is not installed - needed for cropping PDF files')
+            if crop:
+                # Crop the PNG file
+                failure = os.system('convert -trim %s.png %s.png' %
+                                    (filename, filename))
+                if failure:
+                    print('convert from ImageMagick is not installed - needed for cropping PNG files')
+                failure = os.system('pdfcrop %s.pdf %s.pdf' %
+                                    (filename, filename))
+                if failure:
+                    print('pdfcrop is not installed - needed for cropping PDF files')
             #self.mpl.savefig(filename + '.eps')
             if self.instruction_file:
                 self.instruction_file.write('mpl.savefig("%s.png", dpi=%s)\n'
@@ -376,13 +387,15 @@ self.ax.plot(x, y, linewidth=%d, color='gray',
         else:
             self.mpl.savefig(filename, dpi=dpi)
             if ext == '.png':
-                failure = os.system('convert -trim %s %s' % (filename, filename))
-                if failure:
-                    print('convert from ImageMagick is not installed - needed for cropping PNG files')
+                if crop:
+                    failure = os.system('convert -trim %s %s' % (filename, filename))
+                    if failure:
+                        print('convert from ImageMagick is not installed - needed for cropping PNG files')
             elif ext == '.pdf':
-                failure = os.system('pdfcrop %s %s' % (filename, filename))
-                if failure:
-                    print('pdfcrop is not installed - needed for cropping PDF files')
+                if crop:
+                    failure = os.system('pdfcrop %s %s' % (filename, filename))
+                    if failure:
+                        print('pdfcrop is not installed - needed for cropping PDF files')
 
             if self.instruction_file:
                 self.instruction_file.write('mpl.savefig("%s", dpi=%s)\n'

+ 25 - 8
pysketcher/shapes.py

@@ -215,13 +215,14 @@ class Shape(object):
 
 
     def _for_all_shapes(self, func, *args, **kwargs):
+        verbose = kwargs.get('verbose', 0)
         if not hasattr(self, 'shapes'):
             # When self.shapes is lacking, we either come to
             # a special implementation of func or we come here
             # because Shape.func is just inherited. This is
             # an error if the class is not Curve or Point
             if isinstance(self, (Curve, Point)):
-                return  # ok: no shapes and no func
+                return  # ok: no shapes, but object is a curve or point end leaf
             else:
                 raise AttributeError('class %s has no shapes attribute!' %
                                      self.__class__.__name__)
@@ -264,10 +265,12 @@ class Shape(object):
 
             if isinstance(shape, Curve):
                 shape.name = shape_name
+            if verbose > 0:
+                print('calling %s.%s' % (shape_name, func))
             getattr(shape, func)(*args, **kwargs)
 
-    def draw(self):
-        self._for_all_shapes('draw')
+    def draw(self, verbose=0):
+        self._for_all_shapes('draw', verbose=verbose)
         return self
 
     def draw_dimensions(self):
@@ -514,7 +517,7 @@ class Curve(Shape):
                 print('y_max=%g > plot area y_max=%g' % (ymax, t.ymax))
         return inside
 
-    def draw(self):
+    def draw(self, verbose=0):
         """
         Send the curve to the plotting engine. That is, convert
         coordinate information in self.x and self.y, together
@@ -527,6 +530,8 @@ class Curve(Shape):
             self.linestyle, self.linewidth, self.linecolor,
             self.arrow, self.fillcolor, self.fillpattern,
             self.shadow, self.name)
+        if verbose:
+            print('drawing Curve object with %d points' % len(self.x))
 
     def rotate(self, angle, center):
         """
@@ -751,7 +756,7 @@ class Point(Shape):
 
     # class Point is an abstract class - only subclasses are useful
     # and must implement draw
-    def draw(self):
+    def draw(self, verbose=0):
         raise NotImplementedError(
             'class %s must implement the draw method' %
             self.__class__.__name__)
@@ -904,6 +909,14 @@ class Triangle(Shape):
 class Line(Shape):
     def __init__(self, start, end):
         is_sequence(start, end, length=2)
+        if isinstance(start, (list,tuple)):
+            start = array(start)
+        if isinstance(end, (list,tuple)):
+            end = array(end)
+        if (start == end).all():
+            # Introduce a very small perturbation since identical points
+            # give drawing error
+            end[0] = start[0] + 1E-10
         x = [start[0], end[0]]
         y = [start[1], end[1]]
         self.shapes = {'line': Curve(x, y)}
@@ -1320,12 +1333,14 @@ class Text(Point):
         Point.__init__(self, position[0], position[1])
         #no need for self.shapes here
 
-    def draw(self):
+    def draw(self, verbose=0):
         drawing_tool.text(
             self.text, (self.x, self.y),
             self.alignment, self.fontsize,
             arrow_tip=None, bgcolor=self.bgcolor, fgcolor=self.fgcolor,
             fontfamily=self.fontfamily)
+        if verbose > 0:
+            print('drawing Text "%s"' % self.text)
 
     def __str__(self):
         return 'text "%s" at (%g,%g)' % (self.text, self.x, self.y)
@@ -1346,13 +1361,15 @@ class Text_wArrow(Text):
         self.arrow_tip = arrow_tip
         Text.__init__(self, text, position, alignment, fontsize)
 
-    def draw(self):
+    def draw(self, verbose=0):
         drawing_tool.text(
             self.text, self.position,
             self.alignment, self.fontsize,
             arrow_tip=self.arrow_tip,
             bgcolor=self.bgcolor, fgcolor=self.fgcolor,
             fontfamily=self.fontfamily)
+        if verbose > 0:
+            print('drawing Text_wArrow "%s"' % self.text)
 
     def __str__(self):
         return 'annotation "%s" at (%g,%g) with arrow to (%g,%g)' % \
@@ -1431,7 +1448,7 @@ class Force(Arrow1):
         downward = (end-start)[1] < 0
         upward = not downward  # for easy code reading
 
-        if isinstance(text_pos, str):
+        if isinstance(text_pos, (str,bytes)):
             if text_pos == 'start':
                 spacing_dir = unit_vec(start - end)
                 if upward: