Bladeren bron

Added shadow effect.

Hans Petter Langtangen 13 jaren geleden
bovenliggende
commit
a1505e1d4a

+ 1 - 1
doc/src/sketcher/clean.sh

@@ -1,4 +1,4 @@
 #!/bin/sh
 
 doconce clean
-rm -rf Shape2.dot *~
+rm -rf Shape2.dot *~ *.p.tex

+ 2 - 2
doc/src/sketcher/make.sh

@@ -3,10 +3,10 @@
 # Run spellcheck
 python ~/hg/programs/spellcheck.py -d dictionary.txt *.do.txt
 if [ $? -ne 0 ]; then
-  exit
+  echo "Misspellings!"  # use mydict.txt~.all~ as new dictionary.txt?
+  exit 1
 fi
 
-
 main=wrap_sketcher
 doconce format html $main
 

+ 6 - 0
doc/src/sketcher/make_primer.sh

@@ -1,5 +1,11 @@
 #!/bin/sh
 
+python ~/hg/programs/spellcheck.py -d dictionary.txt *.do.txt
+if [ $? -ne 0 ]; then
+  echo "Misspellings!"  # use mydict.txt~.all~ as new dictionary.txt?
+  exit 1
+fi
+
 doconce format latex basics -DPRIMER_BOOK
 doconce format latex implementation -DPRIMER_BOOK
 doconce format latex exercises -DPRIMER_BOOK

+ 5 - 2
examples/wheel_on_inclined_plane.py

@@ -1,4 +1,4 @@
-from shapes import *
+from pysketcher import *
 
 def inclined_plane():
     theta = 30.
@@ -10,6 +10,7 @@ def inclined_plane():
     drawing_tool.set_coordinate_system(xmin=xmin, xmax=xmin+1.5*L,
                                        ymin=ymin, ymax=ymin+L,
                                        #axis=True,
+                                       instruction_file='tmp_mpl.py'
                                        )
     #drawing_tool.set_grid(True)
     fontsize = 18
@@ -18,7 +19,8 @@ def inclined_plane():
     B = point(a+L, 0)
     A = point(a, tan(radians(theta))*L)
 
-    wall = Wall(x=[A[0], B[0]], y=[A[1], B[1]], thickness=-0.25)
+    wall = Wall(x=[A[0], B[0]], y=[A[1], B[1]], thickness=-0.25,
+                transparent=False)
 
     angle = Arc_wText(r'$\theta$', center=B, radius=3,
                       start_angle=180-theta, arc_angle=theta,
@@ -45,6 +47,7 @@ def inclined_plane():
     hole.set_filled_curves('white')
 
     wheel = Composition({'outer': outer_wheel, 'inner': hole})
+    wheel.set_shadow(4)
 
     drawing_tool.set_linecolor('black')
     N = Force(contact - 2*r*normal_vec, contact, r'$N$', text_pos='start')

+ 40 - 7
pysketcher/MatplotlibDraw.py

@@ -2,6 +2,7 @@ import os
 import matplotlib
 matplotlib.use('TkAgg')
 import matplotlib.pyplot as mpl
+import matplotlib.transforms as transforms
 import numpy as np
 
 class MatplotlibDraw:
@@ -214,7 +215,8 @@ ax.set_aspect('equal')
     def plot_curve(self, x, y,
                    linestyle=None, linewidth=None,
                    linecolor=None, arrow=None,
-                   fillcolor=None, fillpattern=None):
+                   fillcolor=None, fillpattern=None,
+                   shadow=0):
         """Define a curve with coordinates x and y (arrays)."""
         #if not self.allow_screen_graphics:
         #    mpl.ioff()
@@ -235,6 +237,8 @@ ax.set_aspect('equal')
             fillcolor = self.fillcolor
         if fillpattern is None:
             fillpattern = self.fillpattern
+        if shadow == 1:
+            shadow = 3   # smallest displacement that is visible
 
         if self.instruction_file:
             import pprint
@@ -248,15 +252,44 @@ ax.set_aspect('equal')
             if fillpattern != '':
                 fillcolor = 'white'
             #print '%d coords, fillcolor="%s" linecolor="%s" fillpattern="%s"' % (x.size, fillcolor, linecolor, fillpattern)
-            self.ax.fill(x, y, fillcolor, edgecolor=linecolor,
-                         linewidth=linewidth, hatch=fillpattern)
+            [line] = self.ax.fill(x, y, fillcolor, edgecolor=linecolor,
+                                  linewidth=linewidth, hatch=fillpattern)
             if self.instruction_file:
-                self.instruction_file.write("ax.fill(x, y, '%s', edgecolor='%s', linewidth=%d, hatch='%s')\n" % (fillcolor, linecolor, linewidth, fillpattern))
+                self.instruction_file.write("[line] = ax.fill(x, y, '%s', edgecolor='%s', linewidth=%d, hatch='%s')\n" % (fillcolor, linecolor, linewidth, fillpattern))
         else:
-            self.ax.plot(x, y, linecolor, linewidth=linewidth,
-                         linestyle=linestyle)
+            [line] = self.ax.plot(x, y, linecolor, linewidth=linewidth,
+                                  linestyle=linestyle)
             if self.instruction_file:
-                self.instruction_file.write("ax.plot(x, y, '%s', linewidth=%d, linestyle='%s')\n" % (linecolor, linewidth, linestyle))
+                self.instruction_file.write("[line] = ax.plot(x, y, '%s', linewidth=%d, linestyle='%s')\n" % (linecolor, linewidth, linestyle))
+
+        if shadow:
+            # http://matplotlib.sourceforge.net/users/transforms_tutorial.html#using-offset-transforms-to-create-a-shadow-effect
+            # shift the object over 2 points, and down 2 points
+            dx, dy = shadow/72., -shadow/72.
+            offset = transforms.ScaledTranslation(
+                dx, dy, self.fig.dpi_scale_trans)
+            shadow_transform = self.ax.transData + offset
+            # now plot the same data with our offset transform;
+            # use the zorder to make sure we are below the line
+            if linewidth is None:
+                linewidth = 3
+            self.ax.plot(x, y, linewidth=linewidth, color='gray',
+                         transform=shadow_transform,
+                         zorder=0.5*line.get_zorder())
+
+
+            if self.instruction_file:
+                self.instruction_file.write("""
+# Shadow effect for last ax.plot
+dx, dy = 3/72., -3/72.
+offset = matplotlib.transforms.ScaledTranslation(dx, dy, fig.dpi_scale_trans)
+shadow_transform = ax.transData + offset
+self.ax.plot(x, y, linewidth=%d, color='gray',
+             transform=shadow_transform,
+             zorder=0.5*line.get_zorder())
+""" % linewidth)
+
+
         if arrow:
             if not arrow in ('->', '<-', '<->'):
                 raise ValueError("arrow argument must be '->', '<-', or '<->', not %s" % repr(arrow))

+ 20 - 5
pysketcher/shapes.py

@@ -379,6 +379,10 @@ class Shape:
         self._for_all_shapes('set_filled_curves', color, pattern)
         return self
 
+    def set_shadow(self, pixel_displacement=3):
+        self._for_all_shapes('set_shadow', pixel_displacement)
+        return self
+
     def show_hierarchy(self, indent=0, format='std'):
         """Recursive pretty print of hierarchy of objects."""
         if not isinstance(self.shapes, dict):
@@ -437,6 +441,7 @@ class Curve(Shape):
         self.fillcolor = None
         self.fillpattern = None
         self.arrow = None
+        self.shadow = False
 
     def inside_plot_area(self, verbose=True):
         """Check that all coordinates are within drawing_tool's area."""
@@ -473,7 +478,8 @@ class Curve(Shape):
         drawing_tool.plot_curve(
             self.x, self.y,
             self.linestyle, self.linewidth, self.linecolor,
-            self.arrow, self.fillcolor, self.fillpattern)
+            self.arrow, self.fillcolor, self.fillpattern,
+            self.shadow)
 
     def rotate(self, angle, center):
         """
@@ -549,6 +555,10 @@ class Curve(Shape):
         self.fillpattern = pattern
         return self
 
+    def set_shadow(self, pixel_displacement=3):
+        self.shadow = pixel_displacement
+        return self
+
     def show_hierarchy(self, indent=0, format='std'):
         if format == 'dict':
             return '"%s"' % str(self)
@@ -666,6 +676,10 @@ class Point(Shape):
     def _object_couplings(self, parent, couplings=[], classname=True):
         return
 
+    # No need for set_linecolor etc since self._for_all_shapes, which
+    # is always called for these functions, makes a test and stops
+    # calls if self.shapes is missing and the object is Point or Curve
+
     def show_hierarchy(self, indent=0, format='std'):
         s = '%s at (%g,%g)' % (self.__class__.__name__, self.x, self.y)
         if format == 'dict':
@@ -975,7 +989,7 @@ class Circle(Arc):
 
 
 class Wall(Shape):
-    def __init__(self, x, y, thickness, pattern='/'):
+    def __init__(self, x, y, thickness, pattern='/', transparent=False):
         is_sequence(x, y, length=len(x))
         if isinstance(x[0], (tuple,list,ndarray)):
             # x is list of curves
@@ -1002,12 +1016,13 @@ class Wall(Shape):
         y = [y1[-1]] + y2[-1::-1].tolist() + [y1[0]]
         self.shapes = {'wall': wall}
 
-        white_eraser = Curve(x, y)
-        white_eraser.set_linecolor('white')
         from collections import OrderedDict
         self.shapes = OrderedDict()
         self.shapes['wall'] = wall
-        self.shapes['eraser'] = white_eraser
+        if transparent:
+            white_eraser = Curve(x, y)
+            white_eraser.set_linecolor('white')
+            self.shapes['eraser'] = white_eraser
 
     def geometric_features(self):
         d = {'start': point(self.x1[0], self.y1[0]),