Hans Petter Langtangen 10 years ago
parent
commit
db2357f81f
38 changed files with 1426 additions and 586 deletions
  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
 See the `examples` directory for some examples beyond the more basic
 ones in the tutorial.
 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:
 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,
                3,
                'sketcher:vehicle1:anim',
                'sketcher:vehicle1:anim',
                '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',
               ('Example of classes for geometric objects',
                2,
                2,
                None,
                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',
               ('Scaling, translating, and rotating a figure',
                2,
                2,
                'sketcher:scaling',
                'sketcher:scaling',
                '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 -->
 end of tocinfo -->
 
 
 <body>
 <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#___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#___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="._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>
         </ul>
       </li>
       </li>
@@ -175,7 +187,7 @@ MathJax.Hub.Config({
 <center>[2] <b>Department of Informatics, University of Oslo</b></center>
 <center>[2] <b>Department of Informatics, University of Oslo</b></center>
 <br>
 <br>
 <p>
 <p>
-<center><h4>Dec 23, 2015</h4></center> <!-- date -->
+<center><h4>Jan 22, 2016</h4></center> <!-- date -->
 <br>
 <br>
 <p>
 <p>
 
 
@@ -231,6 +243,7 @@ no further background is required.
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</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>
   <li><a href="._pysketcher001.html">&raquo;</a></li>
 </ul>
 </ul>
 <!-- ------------------- end of main content --------------- -->
 <!-- ------------------- end of main content --------------- -->

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

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                3,
                3,
                'sketcher:vehicle1:anim',
                'sketcher:vehicle1:anim',
                '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',
               ('Example of classes for geometric objects',
                2,
                2,
                None,
                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',
               ('Scaling, translating, and rotating a figure',
                2,
                2,
                'sketcher:scaling',
                'sketcher:scaling',
                '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 -->
 end of tocinfo -->
 
 
 <body>
 <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#___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#___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="._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>
         </ul>
       </li>
       </li>
@@ -162,20 +174,23 @@ Table of contents</h2>
 <p>
 <p>
 <a href="._pysketcher002.html#___sec0"> A first glimpse of Pysketcher </a><br>
 <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>
 &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>
 <p>
 <p>
 <p>
@@ -187,6 +202,7 @@ Table of contents</h2>
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</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>
   <li><a href="._pysketcher002.html">&raquo;</a></li>
 </ul>
 </ul>
 <!-- ------------------- end of main content --------------- -->
 <!-- ------------------- end of main content --------------- -->

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

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                3,
                3,
                'sketcher:vehicle1:anim',
                'sketcher:vehicle1:anim',
                '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',
               ('Example of classes for geometric objects',
                2,
                2,
                None,
                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',
               ('Scaling, translating, and rotating a figure',
                2,
                2,
                'sketcher:scaling',
                'sketcher:scaling',
                '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 -->
 end of tocinfo -->
 
 
 <body>
 <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="#___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="#___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="#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>
         </ul>
       </li>
       </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 class="active"><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</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>
   <li><a href="._pysketcher003.html">&raquo;</a></li>
 </ul>
 </ul>
 <!-- ------------------- end of main content --------------- -->
 <!-- ------------------- end of main content --------------- -->

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

@@ -46,34 +46,43 @@ Automatically generated HTML file from DocOnce source
                3,
                3,
                'sketcher:vehicle1:anim',
                'sketcher:vehicle1:anim',
                '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',
               ('Example of classes for geometric objects',
                2,
                2,
                None,
                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',
               ('Scaling, translating, and rotating a figure',
                2,
                2,
                'sketcher:scaling',
                'sketcher:scaling',
                '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 -->
 end of tocinfo -->
 
 
 <body>
 <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#___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#___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="._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>
         </ul>
       </li>
       </li>
@@ -156,394 +168,350 @@ MathJax.Hub.Config({
 <a name="part0003"></a>
 <a name="part0003"></a>
 <!-- !split -->
 <!-- !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>
 <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>
 <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>
 <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>
 <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>
 <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>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
-
-<h2 id="___sec10">Distance with text </h2>
-
 <p>
 <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>
 <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>
 <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>
 <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>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
 <p>
 <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>
 <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>
 <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>
 <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>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
 <p>
 <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>
 <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>
 <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>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
 <p>
 <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>
 <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>
 <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>
 <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>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
-
-<h2 id="___sec14">Spring </h2>
-
 <p>
 <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>
 <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>
 <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>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
 
 
-<h2 id="___sec15">Dashpot </h2>
+<h2 id="___sec10">The body diagram </h2>
 
 
 <p>
 <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>
 <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>
 <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>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
-
-<h2 id="___sec16">Wavy </h2>
-
 <p>
 <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>
 <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>
 <p>
-<br />
-<br />
+Note how we reuse the earlier defined object <code>rod</code>.
 
 
 <p>
 <p>
-<center><p><img src="fig-tut/StochasticWavyCurve.png" align="bottom" width=600></p></center>
+The forces are constructed as shown below.
 
 
 <p>
 <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>
 <p>
-The usage is simple. The construction
+All objects are in place, and we can compose a figure to be drawn:
 
 
 <p>
 <p>
 
 
 <!-- code=python (!bc pycod) typeset with pygments style "default" -->
 <!-- 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>
 </pre></div>
 <p>
 <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>
 <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><a href="._pysketcher002.html">3</a></li>
   <li class="active"><a href="._pysketcher003.html">4</a></li>
   <li class="active"><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</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>
   <li><a href="._pysketcher004.html">&raquo;</a></li>
 </ul>
 </ul>
 <!-- ------------------- end of main content --------------- -->
 <!-- ------------------- end of main content --------------- -->

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

@@ -1,4 +1,4 @@
 # Sphinx build info version 1
 # 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.
 # 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
 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
 :Authors: Hans Petter Langtangen
-:Date: Dec 23, 2015
+:Date: Jan 22, 2016
 
 
 
 
 .. The below box could be typeset as .. admonition: Attention
 .. 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
 .. !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
 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>
     <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
     <br />
     <br />
     <br />
     <br />
-      &copy;2015, Hans Petter Langtangen.
+      &copy;2016, Hans Petter Langtangen.
   </div>
   </div>
 </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>
 <li class="toctree-l3"><a class="reference internal" href="main_sketcher.html#basic-construction-of-sketches">Basic construction of sketches</a></li>
 </ul>
 </ul>
 </li>
 </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-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#axis">Axis</a></li>
 <li class="toctree-l3"><a class="reference internal" href="main_sketcher.html#distance-with-text">Distance with text</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>
     <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
     <br />
     <br />
     <br />
     <br />
-      &copy;2015, Hans Petter Langtangen.
+      &copy;2016, Hans Petter Langtangen.
   </div>
   </div>
 </div>
 </div>
 
 

File diff suppressed because it is too large
+ 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>
     <a href="http://cbc.simula.no"><img src="_static/cbc_banner.png" width="100%"><a>
     <br />
     <br />
     <br />
     <br />
-      &copy;2015, Hans Petter Langtangen.
+      &copy;2016, Hans Petter Langtangen.
   </div>
   </div>
 </div>
 </div>
 
 

File diff suppressed because it is too large
+ 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,
                3,
                'sketcher:vehicle1:anim',
                'sketcher:vehicle1:anim',
                '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',
               ('Example of classes for geometric objects',
                2,
                2,
                None,
                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',
               ('Scaling, translating, and rotating a figure',
                2,
                2,
                'sketcher:scaling',
                'sketcher:scaling',
                '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 -->
 end of tocinfo -->
 
 
 <body>
 <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#___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#___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="._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>
         </ul>
       </li>
       </li>
@@ -175,7 +187,7 @@ MathJax.Hub.Config({
 <center>[2] <b>Department of Informatics, University of Oslo</b></center>
 <center>[2] <b>Department of Informatics, University of Oslo</b></center>
 <br>
 <br>
 <p>
 <p>
-<center><h4>Dec 23, 2015</h4></center> <!-- date -->
+<center><h4>Jan 22, 2016</h4></center> <!-- date -->
 <br>
 <br>
 <p>
 <p>
 
 
@@ -231,6 +243,7 @@ no further background is required.
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher002.html">3</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher003.html">4</a></li>
   <li><a href="._pysketcher004.html">5</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>
   <li><a href="._pysketcher001.html">&raquo;</a></li>
 </ul>
 </ul>
 <!-- ------------------- end of main content --------------- -->
 <!-- ------------------- end of main content --------------- -->

BIN
doc/pub/tutorial/pysketcher.pdf


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

@@ -1,13 +1,17 @@
 
 
+Cromer
 Dashpot
 Dashpot
 ImageMagick
 ImageMagick
 Informatics
 Informatics
 Langtangen
 Langtangen
 MPEG
 MPEG
 Matplotlib
 Matplotlib
+ODEs
 OO
 OO
+Odespy
 Pygame
 Pygame
 Pysketcher
 Pysketcher
+Pysketcher's
 SciTools
 SciTools
 Simula
 Simula
 WebM
 WebM
@@ -27,6 +31,7 @@ fillcolor
 gif
 gif
 github
 github
 graphviz
 graphviz
+greek
 hier
 hier
 hplgit
 hplgit
 html
 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
 !split
 # #include "basics.do.txt"
 # #include "basics.do.txt"
 
 
+!split
+# #include "examples.do.txt"
+
 !split
 !split
 # #include "classes.do.txt"
 # #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 *
 from pysketcher import *
 
 
 L = 8.0
 L = 8.0

+ 4 - 3
examples/beam2.py

@@ -1,3 +1,4 @@
+"""A more sophisticated beam than in beam1.py."""
 from pysketcher import *
 from pysketcher import *
 
 
 def beam():
 def beam():
@@ -93,19 +94,19 @@ def beam():
 
 
     beam.draw()
     beam.draw()
     drawing_tool.display()
     drawing_tool.display()
-    drawing_tool.savefig('tmp_beam2_1.png')
+    drawing_tool.savefig('tmp_beam2_1')
 
 
     import time
     import time
     time.sleep(1.5)
     time.sleep(1.5)
 
 
     annotations.draw()
     annotations.draw()
     drawing_tool.display()
     drawing_tool.display()
-    drawing_tool.savefig('tmp_beam2_2.png')
+    drawing_tool.savefig('tmp_beam2_2')
     time.sleep(1.5)
     time.sleep(1.5)
 
 
     elastic_line.draw()
     elastic_line.draw()
     drawing_tool.display()
     drawing_tool.display()
-    drawing_tool.savefig('tmp_beam2_3.png')
+    drawing_tool.savefig('tmp_beam2_3')
     #beam.draw_dimensions()
     #beam.draw_dimensions()
     #test_Dashpot(xpos+2*W)
     #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,
 drawing_tool.set_coordinate_system(xmin=0, xmax=W,
                                    ymin=0, ymax=H,
                                    ymin=0, ymax=H,
                                    axis=False)
                                    axis=False)
-drawing_tool.set_linecolor('blue')
 #drawing_tool.set_grid(True)
 #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
 L = 5*H/7          # length
 P = (W/6, 0.85*H)  # rotation point
 P = (W/6, 0.85*H)  # rotation point
 a = 40             # angle
 a = 40             # angle
 
 
+vertical = Line(P, P-point(0,L))
 path = Arc(P, L, -90, a)
 path = Arc(P, L, -90, a)
 angle = Arc_wText(r'$\theta$', P, L/4, -90, a, text_spacing=1/30.)
 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))))
 rod = Line(P, P + L*point(sin(radians(a)), -L*cos(radians(a))))
 # or shorter (and more reliable)
 # or shorter (and more reliable)
@@ -32,51 +24,63 @@ rod = Line(P, mass_pt)
 
 
 mass = Circle(center=mass_pt, radius=L/20.)
 mass = Circle(center=mass_pt, radius=L/20.)
 mass.set_filled_curves(color='blue')
 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$')
 length = Distance_wText(P, mass_pt, '$L$')
 # Displace length indication
 # Displace length indication
 length.translate(L/15*point(cos(radians(a)), sin(radians(a))))
 length.translate(L/15*point(cos(radians(a)), sin(radians(a))))
 gravity = Gravity(start=P+point(0.8*L,0), length=L/3)
 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)
 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})
      'g': gravity, 'L': length, 'm': mass_symbol})
 
 
-fig = Composition({'body': mass, 'rod': rod, 'dims': dims})
-
 fig.draw()
 fig.draw()
 drawing_tool.display()
 drawing_tool.display()
 drawing_tool.savefig('tmp_pendulum1')
 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: ')
 input('Press Return to make body diagram: ')
-#import time; time.sleep(3)
+
 drawing_tool.erase()
 drawing_tool.erase()
 
 
 drawing_tool.set_linecolor('black')
 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))
 vertical2 = Line(rod_start, rod_start + point(0,-L/3))
 set_dashed_thin_blackline(vertical2)
 set_dashed_thin_blackline(vertical2)
 set_dashed_thin_blackline(rod)
 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(
 body_diagram = Composition(
     {'mg': mg_force, 'S': rod_force, 'rod': rod,
     {'mg': mg_force, 'S': rod_force, 'rod': rod,
      'vertical': vertical2, 'theta': angle2,
      'vertical': vertical2, 'theta': angle2,
-     #'path': path2,
      'body': mass, 'm': mass_symbol})
      'body': mass, 'm': mass_symbol})
 
 
 body_diagram.draw()
 body_diagram.draw()
@@ -88,23 +92,23 @@ drawing_tool.adjust_coordinate_system(body_diagram.minmax_coordinates(), 90)
 drawing_tool.savefig('tmp_pendulum3')
 drawing_tool.savefig('tmp_pendulum3')
 
 
 drawing_tool.erase()
 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['air'] = air_force
 body_diagram.draw()
 body_diagram.draw()
 #drawing_tool.display('Body diagram')
 #drawing_tool.display('Body diagram')
 drawing_tool.savefig('tmp_pendulum4')
 drawing_tool.savefig('tmp_pendulum4')
 
 
 drawing_tool.erase()
 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),
 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])),
 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['ir'] = ir
 body_diagram['ith'] = ith
 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()
 body_diagram.draw()
 #drawing_tool.display('Body diagram')
 #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 os
 import matplotlib
 import matplotlib
+
 matplotlib.use('TkAgg')
 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.pyplot as mpl
 import matplotlib.transforms as transforms
 import matplotlib.transforms as transforms
 import numpy as np
 import numpy as np
@@ -113,6 +118,11 @@ class MatplotlibDraw(object):
         self.mpl.ion()  # important for interactive drawing and animation
         self.mpl.ion()  # important for interactive drawing and animation
         if self.instruction_file:
         if self.instruction_file:
             self.instruction_file.write("""\
             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.pyplot as mpl
 import matplotlib.transforms as transforms
 import matplotlib.transforms as transforms
 
 
@@ -350,23 +360,24 @@ self.ax.plot(x, y, linewidth=%d, color='gray',
         if self.instruction_file:
         if self.instruction_file:
             self.instruction_file.write('mpl.draw()\n')
             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."""
         """Save figure in file. Set dpi=300 for really high resolution."""
         # If filename is without extension, generate all important formats
         # If filename is without extension, generate all important formats
         ext = os.path.splitext(filename)[1]
         ext = os.path.splitext(filename)[1]
         if not ext:
         if not ext:
             # Create both PNG and PDF file
             # Create both PNG and PDF file
             self.mpl.savefig(filename + '.png', dpi=dpi)
             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')
             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')
             #self.mpl.savefig(filename + '.eps')
             if self.instruction_file:
             if self.instruction_file:
                 self.instruction_file.write('mpl.savefig("%s.png", dpi=%s)\n'
                 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:
         else:
             self.mpl.savefig(filename, dpi=dpi)
             self.mpl.savefig(filename, dpi=dpi)
             if ext == '.png':
             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':
             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:
             if self.instruction_file:
                 self.instruction_file.write('mpl.savefig("%s", dpi=%s)\n'
                 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):
     def _for_all_shapes(self, func, *args, **kwargs):
+        verbose = kwargs.get('verbose', 0)
         if not hasattr(self, 'shapes'):
         if not hasattr(self, 'shapes'):
             # When self.shapes is lacking, we either come to
             # When self.shapes is lacking, we either come to
             # a special implementation of func or we come here
             # a special implementation of func or we come here
             # because Shape.func is just inherited. This is
             # because Shape.func is just inherited. This is
             # an error if the class is not Curve or Point
             # an error if the class is not Curve or Point
             if isinstance(self, (Curve, 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:
             else:
                 raise AttributeError('class %s has no shapes attribute!' %
                 raise AttributeError('class %s has no shapes attribute!' %
                                      self.__class__.__name__)
                                      self.__class__.__name__)
@@ -264,10 +265,12 @@ class Shape(object):
 
 
             if isinstance(shape, Curve):
             if isinstance(shape, Curve):
                 shape.name = shape_name
                 shape.name = shape_name
+            if verbose > 0:
+                print('calling %s.%s' % (shape_name, func))
             getattr(shape, func)(*args, **kwargs)
             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
         return self
 
 
     def draw_dimensions(self):
     def draw_dimensions(self):
@@ -514,7 +517,7 @@ class Curve(Shape):
                 print('y_max=%g > plot area y_max=%g' % (ymax, t.ymax))
                 print('y_max=%g > plot area y_max=%g' % (ymax, t.ymax))
         return inside
         return inside
 
 
-    def draw(self):
+    def draw(self, verbose=0):
         """
         """
         Send the curve to the plotting engine. That is, convert
         Send the curve to the plotting engine. That is, convert
         coordinate information in self.x and self.y, together
         coordinate information in self.x and self.y, together
@@ -527,6 +530,8 @@ class Curve(Shape):
             self.linestyle, self.linewidth, self.linecolor,
             self.linestyle, self.linewidth, self.linecolor,
             self.arrow, self.fillcolor, self.fillpattern,
             self.arrow, self.fillcolor, self.fillpattern,
             self.shadow, self.name)
             self.shadow, self.name)
+        if verbose:
+            print('drawing Curve object with %d points' % len(self.x))
 
 
     def rotate(self, angle, center):
     def rotate(self, angle, center):
         """
         """
@@ -751,7 +756,7 @@ class Point(Shape):
 
 
     # class Point is an abstract class - only subclasses are useful
     # class Point is an abstract class - only subclasses are useful
     # and must implement draw
     # and must implement draw
-    def draw(self):
+    def draw(self, verbose=0):
         raise NotImplementedError(
         raise NotImplementedError(
             'class %s must implement the draw method' %
             'class %s must implement the draw method' %
             self.__class__.__name__)
             self.__class__.__name__)
@@ -904,6 +909,14 @@ class Triangle(Shape):
 class Line(Shape):
 class Line(Shape):
     def __init__(self, start, end):
     def __init__(self, start, end):
         is_sequence(start, end, length=2)
         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]]
         x = [start[0], end[0]]
         y = [start[1], end[1]]
         y = [start[1], end[1]]
         self.shapes = {'line': Curve(x, y)}
         self.shapes = {'line': Curve(x, y)}
@@ -1320,12 +1333,14 @@ class Text(Point):
         Point.__init__(self, position[0], position[1])
         Point.__init__(self, position[0], position[1])
         #no need for self.shapes here
         #no need for self.shapes here
 
 
-    def draw(self):
+    def draw(self, verbose=0):
         drawing_tool.text(
         drawing_tool.text(
             self.text, (self.x, self.y),
             self.text, (self.x, self.y),
             self.alignment, self.fontsize,
             self.alignment, self.fontsize,
             arrow_tip=None, bgcolor=self.bgcolor, fgcolor=self.fgcolor,
             arrow_tip=None, bgcolor=self.bgcolor, fgcolor=self.fgcolor,
             fontfamily=self.fontfamily)
             fontfamily=self.fontfamily)
+        if verbose > 0:
+            print('drawing Text "%s"' % self.text)
 
 
     def __str__(self):
     def __str__(self):
         return 'text "%s" at (%g,%g)' % (self.text, self.x, self.y)
         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
         self.arrow_tip = arrow_tip
         Text.__init__(self, text, position, alignment, fontsize)
         Text.__init__(self, text, position, alignment, fontsize)
 
 
-    def draw(self):
+    def draw(self, verbose=0):
         drawing_tool.text(
         drawing_tool.text(
             self.text, self.position,
             self.text, self.position,
             self.alignment, self.fontsize,
             self.alignment, self.fontsize,
             arrow_tip=self.arrow_tip,
             arrow_tip=self.arrow_tip,
             bgcolor=self.bgcolor, fgcolor=self.fgcolor,
             bgcolor=self.bgcolor, fgcolor=self.fgcolor,
             fontfamily=self.fontfamily)
             fontfamily=self.fontfamily)
+        if verbose > 0:
+            print('drawing Text_wArrow "%s"' % self.text)
 
 
     def __str__(self):
     def __str__(self):
         return 'annotation "%s" at (%g,%g) with arrow to (%g,%g)' % \
         return 'annotation "%s" at (%g,%g) with arrow to (%g,%g)' % \
@@ -1431,7 +1448,7 @@ class Force(Arrow1):
         downward = (end-start)[1] < 0
         downward = (end-start)[1] < 0
         upward = not downward  # for easy code reading
         upward = not downward  # for easy code reading
 
 
-        if isinstance(text_pos, str):
+        if isinstance(text_pos, (str,bytes)):
             if text_pos == 'start':
             if text_pos == 'start':
                 spacing_dir = unit_vec(start - end)
                 spacing_dir = unit_vec(start - end)
                 if upward:
                 if upward: