Hans Petter Langtangen vor 13 Jahren
Ursprung
Commit
70eac6e121

BIN
doc/src/sketcher/figs-sketcher/vehicle0.png


BIN
doc/src/sketcher/figs-sketcher/vehicle0v2.png


+ 69 - 4
doc/src/sketcher/sketcher.do.txt

@@ -229,7 +229,7 @@ FIGURE: [figs-sketcher/vehicle0v2.png, width=400] Changed properties of parts of
 We can also change position of parts of the figure and thereby make
 animations, as shown next.
 
-=== Animation ===
+=== Animation: Translating the Vehicle ===
 
 Can we make our little vehicle roll? A first attempt will be to
 fake rolling by just displacing all parts of the vehicle.
@@ -301,11 +301,76 @@ movie(files, encoder='html', output_file='anim')
 !ec
 This command makes a movie that is actually an HTML file `anim.html`,
 which can be loaded into a web browser.
-You can try this by running the present example in
+You can try this by running the present example in the file
 # #ifdef PRIMER_BOOK
-the file `vehicle0.py`.
+`vehicle0.py`.
 # #else
-the file "vehicle0.py":
+"`vehicle0.py`": "http://hplgit.github.com/pysketcher/doc/src/sketcher/sketcher.do.txt".
+# #endif
+
+=== Animation: Rolling the Wheels ===
+
+It is time to show rolling wheels. To this end, we make somewhat
+more complicated wheels with spokes as on a bicyle, formed by
+two crossing lines, see Figure ref{sketcher:fig:vehicle1}.
+The construction of the wheels will now involve a circle
+and two lines:
+!bc pycod
+R = 1.  # radius of wheel
+wheel1 = Compose({'wheel':
+                  Circle(center=(4, R), radius=R),
+                  'cross':
+                  Compose({'cross1': Line((4,0), (4,2*R)),
+                          'cross2': Line((4-R,R), (4+R,R))})})
+wheel2 = wheel1.copy()
+wheel2.translate((4,0))
+!ec
+Observe that `wheel1.copy()` copies all the objects that make
+up the first wheel, and `wheel2.translate` translates all
+the copied objects.
+
+FIGURE: [figs-sketcher/vehicle1.png, width=400] Wheels with spokes to show rotation. label{sketcher:fig:vehicle1}
+
+The `move_vehicle` function need to displace all the objects in the
+entire vehicle and also rotate the crosses in the wheels.
+The rotation angle follows from the fact that the arc length
+of a rolling wheel equals the displacement of the center of
+the wheel, leading to a rotation angle
+!bc pycod
+angle = - displacement[0]/R
+!ec
+With `wheel1_center` tracking the $x$ coordinate of the center
+of the front wheel, we can rotate that wheel by
+!bc pycod
+w1 = fig['vehicle']['wheels']['wheel1']
+from math import degrees
+w1.rotate(degrees(angle), center=(wheel1_center, R))
+!ec
+The `rotate` function takes two parameters: the rotation angle
+(in degrees) and the center point of the rotation, which is the
+center of the wheel in this case. The other wheel is rotated by
+!bc pycod
+w2 = fig['vehicle']['wheels']['wheel2']
+w2.rotate(degrees(angle), center=(wheel1_center+4, R))
+!ec
+That is, the angle is the same, but the rotation point is different.
+The update of the center point is done by `wheel1_center += displacement[0]`.
+The complete `move_vehicle` function then becomes
+!bc pycod
+wheel1_center = 7   # start position
+
+def move_vehicle(t, fig):
+    displacement = dt*v(t)
+    fig['vehicle'].translate(displacement)
+    global wheel1_center
+    wheel1_center += displacement[0]
+    angle = - displacement[0]/R
+    w1 = fig['vehicle']['wheels']['wheel1']
+    w1.rotate(degrees(angle), center=(wheel1_center, R))
+    w2 = fig['vehicle']['wheels']['wheel2']
+    w2.rotate(degrees(angle), center=(wheel1_center+4, R))
+!ec
+
 
 
 The great advantage with making figures this way through programming,

+ 207 - 0
doc/src/sketcher/src-sketcher/vehicle0_animation/anim.html

@@ -0,0 +1,207 @@
+<html>
+<head>
+</head>
+<body>
+
+<script language="Javascript">
+<!---
+var num_images_anim = 35;
+var img_width = 800;
+var img_height = 600;
+var interval = 40;    
+var images_anim = new Array();
+
+function preload_images_anim()
+{
+   t = document.getElementById("progress");
+
+   t.innerHTML = "Preloading image ";
+   images_anim[0] = new Image(img_width, img_height);
+   images_anim[0].src = "tmp_frame_0000.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[1] = new Image(img_width, img_height);
+   images_anim[1].src = "tmp_frame_0001.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[2] = new Image(img_width, img_height);
+   images_anim[2].src = "tmp_frame_0002.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[3] = new Image(img_width, img_height);
+   images_anim[3].src = "tmp_frame_0003.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[4] = new Image(img_width, img_height);
+   images_anim[4].src = "tmp_frame_0004.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[5] = new Image(img_width, img_height);
+   images_anim[5].src = "tmp_frame_0005.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[6] = new Image(img_width, img_height);
+   images_anim[6].src = "tmp_frame_0006.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[7] = new Image(img_width, img_height);
+   images_anim[7].src = "tmp_frame_0007.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[8] = new Image(img_width, img_height);
+   images_anim[8].src = "tmp_frame_0008.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[9] = new Image(img_width, img_height);
+   images_anim[9].src = "tmp_frame_0009.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[10] = new Image(img_width, img_height);
+   images_anim[10].src = "tmp_frame_0010.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[11] = new Image(img_width, img_height);
+   images_anim[11].src = "tmp_frame_0011.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[12] = new Image(img_width, img_height);
+   images_anim[12].src = "tmp_frame_0012.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[13] = new Image(img_width, img_height);
+   images_anim[13].src = "tmp_frame_0013.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[14] = new Image(img_width, img_height);
+   images_anim[14].src = "tmp_frame_0014.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[15] = new Image(img_width, img_height);
+   images_anim[15].src = "tmp_frame_0015.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[16] = new Image(img_width, img_height);
+   images_anim[16].src = "tmp_frame_0016.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[17] = new Image(img_width, img_height);
+   images_anim[17].src = "tmp_frame_0017.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[18] = new Image(img_width, img_height);
+   images_anim[18].src = "tmp_frame_0018.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[19] = new Image(img_width, img_height);
+   images_anim[19].src = "tmp_frame_0019.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[20] = new Image(img_width, img_height);
+   images_anim[20].src = "tmp_frame_0020.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[21] = new Image(img_width, img_height);
+   images_anim[21].src = "tmp_frame_0021.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[22] = new Image(img_width, img_height);
+   images_anim[22].src = "tmp_frame_0022.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[23] = new Image(img_width, img_height);
+   images_anim[23].src = "tmp_frame_0023.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[24] = new Image(img_width, img_height);
+   images_anim[24].src = "tmp_frame_0024.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[25] = new Image(img_width, img_height);
+   images_anim[25].src = "tmp_frame_0025.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[26] = new Image(img_width, img_height);
+   images_anim[26].src = "tmp_frame_0026.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[27] = new Image(img_width, img_height);
+   images_anim[27].src = "tmp_frame_0027.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[28] = new Image(img_width, img_height);
+   images_anim[28].src = "tmp_frame_0028.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[29] = new Image(img_width, img_height);
+   images_anim[29].src = "tmp_frame_0029.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[30] = new Image(img_width, img_height);
+   images_anim[30].src = "tmp_frame_0030.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[31] = new Image(img_width, img_height);
+   images_anim[31].src = "tmp_frame_0031.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[32] = new Image(img_width, img_height);
+   images_anim[32].src = "tmp_frame_0032.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[33] = new Image(img_width, img_height);
+   images_anim[33].src = "tmp_frame_0033.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[34] = new Image(img_width, img_height);
+   images_anim[34].src = "tmp_frame_0034.png";
+        
+   t.innerHTML = "";
+}
+
+function tick_anim()
+{
+   if (frame_anim > num_images_anim - 1)
+       frame_anim = 0;
+
+   document.movie.src = images_anim[frame_anim].src;
+   frame_anim += 1;
+   tt = setTimeout("tick_anim()", interval);
+}
+
+function startup_anim()
+{
+   preload_images_anim();
+   frame_anim = 0;
+   setTimeout("tick_anim()", interval);
+}
+
+function stopit()
+{ clearTimeout(tt); }
+
+function restart_anim()
+{ tt = setTimeout("tick_anim()", interval); }
+
+function slower()
+{ interval = interval/0.7; }
+
+function faster()
+{ interval = interval*0.7; }
+
+// --->
+</script>
+
+<form>
+&nbsp;
+<input type="button" value="Start movie" onClick="startup_anim()">
+<input type="button" value="Pause movie" onClick="stopit()">
+<input type="button" value="Restart movie" onClick="restart_anim()">
+&nbsp;
+<input type="button" value="Slower" onClick="slower()">
+<input type="button" value="Faster" onClick="faster()">
+</form>
+
+<p><div ID="progress"></div></p>
+<img src="tmp_frame_0000.png" name="movie" border=2/>
+
+</body>
+</html>

+ 207 - 0
doc/src/sketcher/src-sketcher/vehicle1_animation/anim.html

@@ -0,0 +1,207 @@
+<html>
+<head>
+</head>
+<body>
+
+<script language="Javascript">
+<!---
+var num_images_anim = 35;
+var img_width = 800;
+var img_height = 600;
+var interval = 40;    
+var images_anim = new Array();
+
+function preload_images_anim()
+{
+   t = document.getElementById("progress");
+
+   t.innerHTML = "Preloading image ";
+   images_anim[0] = new Image(img_width, img_height);
+   images_anim[0].src = "tmp_frame_0000.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[1] = new Image(img_width, img_height);
+   images_anim[1].src = "tmp_frame_0001.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[2] = new Image(img_width, img_height);
+   images_anim[2].src = "tmp_frame_0002.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[3] = new Image(img_width, img_height);
+   images_anim[3].src = "tmp_frame_0003.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[4] = new Image(img_width, img_height);
+   images_anim[4].src = "tmp_frame_0004.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[5] = new Image(img_width, img_height);
+   images_anim[5].src = "tmp_frame_0005.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[6] = new Image(img_width, img_height);
+   images_anim[6].src = "tmp_frame_0006.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[7] = new Image(img_width, img_height);
+   images_anim[7].src = "tmp_frame_0007.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[8] = new Image(img_width, img_height);
+   images_anim[8].src = "tmp_frame_0008.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[9] = new Image(img_width, img_height);
+   images_anim[9].src = "tmp_frame_0009.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[10] = new Image(img_width, img_height);
+   images_anim[10].src = "tmp_frame_0010.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[11] = new Image(img_width, img_height);
+   images_anim[11].src = "tmp_frame_0011.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[12] = new Image(img_width, img_height);
+   images_anim[12].src = "tmp_frame_0012.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[13] = new Image(img_width, img_height);
+   images_anim[13].src = "tmp_frame_0013.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[14] = new Image(img_width, img_height);
+   images_anim[14].src = "tmp_frame_0014.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[15] = new Image(img_width, img_height);
+   images_anim[15].src = "tmp_frame_0015.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[16] = new Image(img_width, img_height);
+   images_anim[16].src = "tmp_frame_0016.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[17] = new Image(img_width, img_height);
+   images_anim[17].src = "tmp_frame_0017.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[18] = new Image(img_width, img_height);
+   images_anim[18].src = "tmp_frame_0018.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[19] = new Image(img_width, img_height);
+   images_anim[19].src = "tmp_frame_0019.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[20] = new Image(img_width, img_height);
+   images_anim[20].src = "tmp_frame_0020.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[21] = new Image(img_width, img_height);
+   images_anim[21].src = "tmp_frame_0021.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[22] = new Image(img_width, img_height);
+   images_anim[22].src = "tmp_frame_0022.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[23] = new Image(img_width, img_height);
+   images_anim[23].src = "tmp_frame_0023.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[24] = new Image(img_width, img_height);
+   images_anim[24].src = "tmp_frame_0024.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[25] = new Image(img_width, img_height);
+   images_anim[25].src = "tmp_frame_0025.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[26] = new Image(img_width, img_height);
+   images_anim[26].src = "tmp_frame_0026.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[27] = new Image(img_width, img_height);
+   images_anim[27].src = "tmp_frame_0027.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[28] = new Image(img_width, img_height);
+   images_anim[28].src = "tmp_frame_0028.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[29] = new Image(img_width, img_height);
+   images_anim[29].src = "tmp_frame_0029.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[30] = new Image(img_width, img_height);
+   images_anim[30].src = "tmp_frame_0030.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[31] = new Image(img_width, img_height);
+   images_anim[31].src = "tmp_frame_0031.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[32] = new Image(img_width, img_height);
+   images_anim[32].src = "tmp_frame_0032.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[33] = new Image(img_width, img_height);
+   images_anim[33].src = "tmp_frame_0033.png";
+        
+   t.innerHTML = "Preloading image ";
+   images_anim[34] = new Image(img_width, img_height);
+   images_anim[34].src = "tmp_frame_0034.png";
+        
+   t.innerHTML = "";
+}
+
+function tick_anim()
+{
+   if (frame_anim > num_images_anim - 1)
+       frame_anim = 0;
+
+   document.movie.src = images_anim[frame_anim].src;
+   frame_anim += 1;
+   tt = setTimeout("tick_anim()", interval);
+}
+
+function startup_anim()
+{
+   preload_images_anim();
+   frame_anim = 0;
+   setTimeout("tick_anim()", interval);
+}
+
+function stopit()
+{ clearTimeout(tt); }
+
+function restart_anim()
+{ tt = setTimeout("tick_anim()", interval); }
+
+function slower()
+{ interval = interval/0.7; }
+
+function faster()
+{ interval = interval*0.7; }
+
+// --->
+</script>
+
+<form>
+&nbsp;
+<input type="button" value="Start movie" onClick="startup_anim()">
+<input type="button" value="Pause movie" onClick="stopit()">
+<input type="button" value="Restart movie" onClick="restart_anim()">
+&nbsp;
+<input type="button" value="Slower" onClick="slower()">
+<input type="button" value="Faster" onClick="faster()">
+</form>
+
+<p><div ID="progress"></div></p>
+<img src="tmp_frame_0000.png" name="movie" border=2/>
+
+</body>
+</html>

+ 32 - 1
pysketcher/shapes.py

@@ -81,9 +81,14 @@ class Shape:
                 return self.shapes[name]
             else:
                 for shape in self.shapes:
+                    if isinstance(self.shapes[shape], (Curve,Point)):
+                        # Indexing of Curve/Point/Text is not possible
+                        raise TypeError(
+                            'Index "%s" is illegal' % name)
                     return self.shapes[shape][name]
         else:
-            return self
+            raise Exception('This is a bug')
+
 
     def for_all_shapes(self, func, *args, **kwargs):
         if not hasattr(self, 'shapes'):
@@ -146,6 +151,9 @@ class Shape:
 
     def show_hierarchy(self, indent=0, format='std'):
         """Recursive pretty print of hierarchy of objects."""
+        if not isinstance(self.shapes, dict):
+            print 'cannot print hierarchy when %s.shapes is not a dict' % \
+                  self.__class__.__name__
         s = ''
         if format == 'dict':
             s += '{'
@@ -405,6 +413,29 @@ class Line(Shape):
             self.c = None
             self.d = None
 
+    def compute_formulas(self):
+        x, y = self.shapes['line'].x, self.shapes['line'].y
+
+        tol = 1E-14
+        # Define equations for line:
+        # y = a*x + b,  x = c*y + d
+        if abs(x[1] - x[0]) > tol:
+            self.a = (y[1] - y[0])/(x[1] - x[0])
+            self.b = y[0] - self.a*x[0]
+        else:
+            # Vertical line, y is not a function of x
+            self.a = None
+            self.b = None
+        if self.a is None:
+            self.c = 0
+        elif abs(self.a) > tol:
+            self.c = 1/float(self.a)
+            self.d = x[1]
+        else:  # self.a is 0
+            # Horizontal line, x is not a function of y
+            self.c = None
+            self.d = None
+
     def __call__(self, x=None, y=None):
         """Given x, return y on the line, or given y, return x."""
         self.compute_formulas()