Hans Petter Langtangen 11 years ago
parent
commit
28915c8f8c
2 changed files with 59 additions and 28 deletions
  1. 2 0
      doc/src/tut/basics.do.txt
  2. 57 28
      doc/src/tut/implementation.do.txt

+ 2 - 0
doc/src/tut/basics.do.txt

@@ -1,5 +1,7 @@
 
 
 # #ifdef PRIMER_BOOK
 # #ifdef PRIMER_BOOK
+idx{`pysketcher`}
+
 Implementing a drawing program provides a very good example on the
 Implementing a drawing program provides a very good example on the
 usefulness of object-oriented programming. In the following we shall
 usefulness of object-oriented programming. In the following we shall
 develop the simpler parts of a relatively small and compact drawing
 develop the simpler parts of a relatively small and compact drawing

+ 57 - 28
doc/src/tut/implementation.do.txt

@@ -13,6 +13,8 @@ add new geometric features.
 
 
 # #ifndef PRIMER_BOOK
 # #ifndef PRIMER_BOOK
 
 
+idx{tree data structure}
+
 Class programming is a key technology for realizing Pysketcher.
 Class programming is a key technology for realizing Pysketcher.
 As soon as some classes are established, more are easily
 As soon as some classes are established, more are easily
 added. Enhanced functionality for all the classes is also easy to
 added. Enhanced functionality for all the classes is also easy to
@@ -48,15 +50,15 @@ class Rectangle(Shape):
         self.shapes = {'rectangle': Curve(x,y)}
         self.shapes = {'rectangle': Curve(x,y)}
 !ec
 !ec
 
 
-Any subclass of `Shape` will have a constructor which takes
-geometric information about the shape of the object and
-creates a dictionary `self.shapes` with the shape built of
-simpler shapes. The most fundamental shape is `Curve`, which is
-just a collection of $(x,y)$ coordinates in two arrays `x` and `y`.
-Drawing the `Curve` object is a matter of plotting `y` versus `x`.
-For class `Rectangle` the `x` and `y` arrays contain the corner points
-of the rectangle in counterclockwise direction, starting and ending
-with in the lower left corner.
+Any subclass of `Shape` will have a constructor which takes geometric
+information about the shape of the object and creates a dictionary
+`self.shapes` with the shape built of simpler shapes. The most
+fundamental shape is `Curve`, which is just a collection of $(x,y)$
+coordinates in two arrays `x` and `y`.  Drawing the `Curve` object is
+a matter of plotting `y` versus `x`.  For class `Rectangle` the `x`
+and `y` arrays contain the corner points of the rectangle in
+counterclockwise direction, starting and ending with in the lower left
+corner.
 
 
 Class `Line` is also a simple class:
 Class `Line` is also a simple class:
 !bc pycod
 !bc pycod
@@ -70,6 +72,7 @@ Here we only need two points, the start and end point on the line.
 However, we may want to add some useful functionality, e.g., the ability
 However, we may want to add some useful functionality, e.g., the ability
 to give an $x$ coordinate and have the class calculate the
 to give an $x$ coordinate and have the class calculate the
 corresponding $y$ coordinate:
 corresponding $y$ coordinate:
+
 !bc pycod
 !bc pycod
     def __call__(self, x):
     def __call__(self, x):
         """Given x, return y on the line."""
         """Given x, return y on the line."""
@@ -85,11 +88,12 @@ code with more tests.
 
 
 A circle implies a somewhat increased complexity. Again we represent
 A circle implies a somewhat increased complexity. Again we represent
 the geometric object by a `Curve` object, but this time the `Curve`
 the geometric object by a `Curve` object, but this time the `Curve`
-object needs to store a large number of points on the curve such
-that a plotting program produces a visually smooth curve.
-The points on the circle must be calculated manually in the constructor
-of class `Circle`. The formulas for points $(x,y)$ on a curve with radius
-$R$ and center at $(x_0, y_0)$ are given by
+object needs to store a large number of points on the curve such that
+a plotting program produces a visually smooth curve.  The points on
+the circle must be calculated manually in the constructor of class
+`Circle`. The formulas for points $(x,y)$ on a curve with radius $R$
+and center at $(x_0, y_0)$ are given by
+
 !bt
 !bt
 \begin{align*}
 \begin{align*}
 x &= x_0 + R\cos (t),\\
 x &= x_0 + R\cos (t),\\
@@ -103,6 +107,7 @@ of $t$ values. The circle's radius and center must of course
 also be specified.
 also be specified.
 
 
 We can write the `Circle` class as
 We can write the `Circle` class as
+
 !bc pycod
 !bc pycod
 class Circle(Shape):
 class Circle(Shape):
     def __init__(self, center, radius, resolution=180):
     def __init__(self, center, radius, resolution=180):
@@ -119,6 +124,7 @@ class Circle(Shape):
 As in class `Line` we can offer the possibility to give an angle
 As in class `Line` we can offer the possibility to give an angle
 $\theta$ (equivalent to $t$ in the formulas above)
 $\theta$ (equivalent to $t$ in the formulas above)
 and then get the corresponding $x$ and $y$ coordinates:
 and then get the corresponding $x$ and $y$ coordinates:
+
 !bc pycod
 !bc pycod
     def __call__(self, theta):
     def __call__(self, theta):
         """Return (x, y) point corresponding to angle theta."""
         """Return (x, y) point corresponding to angle theta."""
@@ -133,6 +139,7 @@ drawing mechanical systems. The arc is constructed much like
 a circle, but $t$ runs in $[\theta_s, \theta_s + \theta_a]$. Giving
 a circle, but $t$ runs in $[\theta_s, \theta_s + \theta_a]$. Giving
 $\theta_s$ and $\theta_a$ the slightly more descriptive names
 $\theta_s$ and $\theta_a$ the slightly more descriptive names
 `start_angle` and `arc_angle`, the code looks like this:
 `start_angle` and `arc_angle`, the code looks like this:
+
 !bc pycod
 !bc pycod
 class Arc(Shape):
 class Arc(Shape):
     def __init__(self, center, radius,
     def __init__(self, center, radius,
@@ -195,6 +202,7 @@ but only the `Curve` object at the end of the chain will actually
 store the information and send it to the plotting program.
 store the information and send it to the plotting program.
 
 
 A rough sketch of class `Curve` reads
 A rough sketch of class `Curve` reads
+
 !bc pycod
 !bc pycod
 class Curve(Shape):
 class Curve(Shape):
     """General curve as a sequence of (x,y) coordintes."""
     """General curve as a sequence of (x,y) coordintes."""
@@ -232,6 +240,7 @@ classes or derive a new one, we need to import `pysketcher`. The constructor
 of class `Vehicle0` performs approximately the same statements as
 of class `Vehicle0` performs approximately the same statements as
 in the example program we developed for making the drawing in
 in the example program we developed for making the drawing in
 Figure ref{sketcher:fig:vehicle0}.
 Figure ref{sketcher:fig:vehicle0}.
+
 !bc pycod
 !bc pycod
 from pysketcher import *
 from pysketcher import *
 
 
@@ -265,6 +274,7 @@ not work.
 The painting of the vehicle, as shown in the right part of
 The painting of the vehicle, as shown in the right part of
 Figure ref{sketcher:fig:vehicle0:v2}, could in class `Vehicle0`
 Figure ref{sketcher:fig:vehicle0:v2}, could in class `Vehicle0`
 be offered by a method:
 be offered by a method:
+
 !bc pycod
 !bc pycod
     def colorful(self):
     def colorful(self):
         wheels = self.shapes['vehicle']['wheels']
         wheels = self.shapes['vehicle']['wheels']
@@ -280,12 +290,14 @@ be offered by a method:
 
 
 The usage of the class is simple: after having set up an appropriate
 The usage of the class is simple: after having set up an appropriate
 coordinate system as previously shown, we can do
 coordinate system as previously shown, we can do
+
 !bc pycod
 !bc pycod
 vehicle = Vehicle0(w_1, R, L, H)
 vehicle = Vehicle0(w_1, R, L, H)
 vehicle.draw()
 vehicle.draw()
 drawing_tool.display()
 drawing_tool.display()
 !ec
 !ec
 and go on the make a painted version by
 and go on the make a painted version by
+
 !bc pycod
 !bc pycod
 drawing_tool.erase()
 drawing_tool.erase()
 vehicle.colorful()
 vehicle.colorful()
@@ -302,6 +314,8 @@ drawings of mechanical systems.
 
 
 ===== Adding Functionality via Recursion =====
 ===== Adding Functionality via Recursion =====
 
 
+idx{recursive function calls}
+
 The really powerful feature of our class hierarchy is that we can add
 The really powerful feature of our class hierarchy is that we can add
 much functionality to the superclass `Shape` and to the ``bottom'' class
 much functionality to the superclass `Shape` and to the ``bottom'' class
 `Curve`, and then all other classes for various types of geometrical shapes
 `Curve`, and then all other classes for various types of geometrical shapes
@@ -380,6 +394,7 @@ This feature allows us to trace the execution and see exactly where
 we are in the hierarchy and which objects that are visited.
 we are in the hierarchy and which objects that are visited.
 
 
 The `recurse` method is very similar to `draw`:
 The `recurse` method is very similar to `draw`:
+
 !bc pycod
 !bc pycod
     def recurse(self, name, indent=0):
     def recurse(self, name, indent=0):
         # print message where we are (name is where we come from)
         # print message where we are (name is where we come from)
@@ -396,12 +411,14 @@ see on the printout how far down in the hierarchy we are.
 A typical message written by `recurse` when `name` is `'body'` and
 A typical message written by `recurse` when `name` is `'body'` and
 the `shapes` dictionary has the keys `'over'` and `'under'`,
 the `shapes` dictionary has the keys `'over'` and `'under'`,
 will be
 will be
+
 !bc dat
 !bc dat
      Composition: body.shapes has entries 'over', 'under'
      Composition: body.shapes has entries 'over', 'under'
      call body.shapes["over"].recurse("over", 6)
      call body.shapes["over"].recurse("over", 6)
 !ec
 !ec
 The number of leading blanks on each line corresponds to the value of
 The number of leading blanks on each line corresponds to the value of
 `indent`. The code printing out such messages looks like
 `indent`. The code printing out such messages looks like
+
 !bc pycod
 !bc pycod
     def recurse(self, name, indent=0):
     def recurse(self, name, indent=0):
         space = ' '*indent
         space = ' '*indent
@@ -420,6 +437,7 @@ Let us follow a `v.recurse('vehicle')` call in detail, `v` being
 a `Vehicle0` instance. Before looking into the output from `recurse`,
 a `Vehicle0` instance. Before looking into the output from `recurse`,
 let us get an overview of the figure hierarchy in the `v` object
 let us get an overview of the figure hierarchy in the `v` object
 (as produced by `print v`)
 (as produced by `print v`)
+
 !bc dat
 !bc dat
 ground
 ground
     wall
     wall
@@ -466,6 +484,7 @@ consistent with the output listed below. Although tedious, this is
 a major exercise that guaranteed will help to demystify recursion.
 a major exercise that guaranteed will help to demystify recursion.
 
 
 A part of the printout of `v.recurse('vehicle')` looks like
 A part of the printout of `v.recurse('vehicle')` looks like
+
 !bc dat
 !bc dat
  Vehicle0: vehicle.shapes has entries 'ground', 'vehicle'
  Vehicle0: vehicle.shapes has entries 'ground', 'vehicle'
  call vehicle.shapes["ground"].recurse("ground", 2)
  call vehicle.shapes["ground"].recurse("ground", 2)
@@ -503,11 +522,10 @@ of code.
 === Scaling ===
 === Scaling ===
 
 
 We start with the simplest of the three geometric transformations,
 We start with the simplest of the three geometric transformations,
-namely scaling.
-For a `Curve` instance containing a set of $n$ coordinates
-$(x_i,y_i)$ that make up a curve, scaling by
-a factor $a$ means that we multiply all the $x$ and $y$ coordinates
-by $a$:
+namely scaling.  For a `Curve` instance containing a set of $n$
+coordinates $(x_i,y_i)$ that make up a curve, scaling by a factor $a$
+means that we multiply all the $x$ and $y$ coordinates by $a$:
+
 !bt
 !bt
 \[
 \[
 x_i \leftarrow ax_i,\quad y_i\leftarrow ay_i,
 x_i \leftarrow ax_i,\quad y_i\leftarrow ay_i,
@@ -517,7 +535,8 @@ x_i \leftarrow ax_i,\quad y_i\leftarrow ay_i,
 Here we apply the arrow as an assignment operator.
 Here we apply the arrow as an assignment operator.
 The corresponding Python implementation in
 The corresponding Python implementation in
 class `Curve` reads
 class `Curve` reads
-!bc cod
+
+!bc pycod
 class Curve:
 class Curve:
     ...
     ...
     def scale(self, factor):
     def scale(self, factor):
@@ -528,9 +547,10 @@ Note here that `self.x` and `self.y` are Numerical Python arrays,
 so that multiplication by a scalar number `factor` is
 so that multiplication by a scalar number `factor` is
 a vectorized operation.
 a vectorized operation.
 
 
-An even more efficient implementation is
-to make use of in-place multiplication in the arrays,
-!bc cod
+An even more efficient implementation is to make use of in-place
+multiplication in the arrays,
+
+!bc pycod
 class Curve:
 class Curve:
     ...
     ...
     def scale(self, factor):
     def scale(self, factor):
@@ -549,7 +569,8 @@ method in the superclass `Shape` such that all subclasses inherit the
 method.  Since `scale` and `draw` are so similar, we can easily
 method.  Since `scale` and `draw` are so similar, we can easily
 implement the `scale` method in class `Shape` by copying and editing
 implement the `scale` method in class `Shape` by copying and editing
 the `draw` method:
 the `draw` method:
-!bc cod
+
+!bc pycod
 class Shape:
 class Shape:
     ...
     ...
     def scale(self, factor):
     def scale(self, factor):
@@ -566,14 +587,18 @@ as it can draw itself.
 
 
 A set of coordinates $(x_i, y_i)$ can be translated $v_0$ units in
 A set of coordinates $(x_i, y_i)$ can be translated $v_0$ units in
 the $x$ direction and $v_1$ units in the $y$ direction using the formulas
 the $x$ direction and $v_1$ units in the $y$ direction using the formulas
+
 !bt
 !bt
 \begin{equation*}
 \begin{equation*}
-x_i\leftarrow x_i+v_0,\quad y_i\leftarrow y_i+v_1,\quad i=0,\ldots,n-1\thinspace . \end{equation*}
+x_i\leftarrow x_i+v_0,\quad y_i\leftarrow y_i+v_1,
+\quad i=0,\ldots,n-1\thinspace .
+\end{equation*}
 !et
 !et
 The natural specification of the translation is in terms of the
 The natural specification of the translation is in terms of the
 vector $v=(v_0,v_1)$.
 vector $v=(v_0,v_1)$.
 The corresponding Python implementation in class `Curve` becomes
 The corresponding Python implementation in class `Curve` becomes
-!bc cod
+
+!bc pycod
 class Curve:
 class Curve:
     ...
     ...
     def translate(self, v):
     def translate(self, v):
@@ -584,7 +609,8 @@ The translation operation for a shape object is very similar to the
 scaling and drawing operations. This means that we can implement a
 scaling and drawing operations. This means that we can implement a
 common method `translate` in the superclass `Shape`. The code
 common method `translate` in the superclass `Shape`. The code
 is parallel to the `scale` method:
 is parallel to the `scale` method:
-!bc cod
+
+!bc pycod
 class Shape:
 class Shape:
     ....
     ....
     def translate(self, v):
     def translate(self, v):
@@ -597,6 +623,7 @@ class Shape:
 Rotating a figure is more complicated than scaling and translating.
 Rotating a figure is more complicated than scaling and translating.
 A counter clockwise rotation of $\theta$ degrees for a set of
 A counter clockwise rotation of $\theta$ degrees for a set of
 coordinates $(x_i,y_i)$ is given by
 coordinates $(x_i,y_i)$ is given by
+
 !bt
 !bt
 \begin{align*}
 \begin{align*}
  \bar x_i &\leftarrow x_i\cos\theta - y_i\sin\theta,\\
  \bar x_i &\leftarrow x_i\cos\theta - y_i\sin\theta,\\
@@ -606,6 +633,7 @@ coordinates $(x_i,y_i)$ is given by
 This rotation is performed around the origin. If we want the figure
 This rotation is performed around the origin. If we want the figure
 to be rotated with respect to a general point $(x,y)$, we need to
 to be rotated with respect to a general point $(x,y)$, we need to
 extend the formulas above:
 extend the formulas above:
+
 !bt
 !bt
 \begin{align*}
 \begin{align*}
  \bar x_i &\leftarrow x + (x_i -x)\cos\theta - (y_i -y)\sin\theta,\\
  \bar x_i &\leftarrow x + (x_i -x)\cos\theta - (y_i -y)\sin\theta,\\
@@ -614,7 +642,8 @@ extend the formulas above:
 !et
 !et
 The Python implementation in class `Curve`, assuming that $\theta$
 The Python implementation in class `Curve`, assuming that $\theta$
 is given in degrees and not in radians, becomes
 is given in degrees and not in radians, becomes
-!bc cod
+
+!bc pycod
     def rotate(self, angle, center):
     def rotate(self, angle, center):
         angle = radians(angle)
         angle = radians(angle)
         x, y = center
         x, y = center