Hans Petter Langtangen 13 vuotta sitten
vanhempi
commit
5ca0224c6b

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

@@ -2,3 +2,4 @@
 
 doconce clean
 rm -rf Shape2.dot *~ *.p.tex
+rm -f src-sketcher/*.png

+ 0 - 51
doc/src/sketcher/src-sketcher/fd_demo.py

@@ -1,51 +0,0 @@
-from pysketcher import *
-
-#test_test()
-drawing_tool.set_coordinate_system(0, 7, 2, 6, axis=False)
-
-f = SketchyFunc1('$f(x)$')
-x = 3                 # center point where we want the derivative
-xb = 2                # x point used for backward difference
-xf = 4                # x point used for forward difference
-p = (x, f(x))         # center point
-pf = (xf, f(xf))      # forward point
-pb = (xb, f(xb))      # backward point
-r = 0.1               # radius of circles placed at key points
-c = Circle(p, r).set_linecolor('blue')
-cf = Circle(pf, r).set_linecolor('red')
-cb = Circle(pb, r).set_linecolor('green')
-domain = [1, 5]
-domain2 = [2, 5]
-lf = Line(p, pf).new_interval(x=domain2).set_linestyle('dashed').set_linecolor('red')
-lb = Line(pb, p).new_interval(x=domain).set_linestyle('dashed').set_linecolor('green')
-lc = Line(pb, pf).new_interval(x=domain).set_linestyle('dashed').set_linecolor('blue')
-h = 1E-3
-le = Line((x+h, f(x+h)), (x-h, f(x-h))).new_interval(x=domain).set_linestyle('dotted').set_linecolor('black')
-
-forward = Composition(dict(tangent=lf, point1=c, point2=cf,
-                      name=Text('forward',
-                                lf.geometric_features()['end'] + point(0.1,0),
-                                alignment='left')))
-backward = Composition(dict(tangent=lb, point1=c, point2=cb,
-                      name=Text('backward',
-                                lb.geometric_features()['end'] + point(0.1,0),
-                                alignment='left')))
-centered = Composition(dict(tangent=lc, point1=cb, point2=cf,
-                       name=Text('centered',
-                                 lc.geometric_features()['end'] + point(0.1,0),
-                                 alignment='left')))
-
-exact = Composition(dict(graph=f, tangent=le))
-forward = Composition(dict(difference=forward, exact=exact)).set_name('forward')
-backward = Composition(dict(difference=backward, exact=exact)).set_name('backward')
-centered = Composition(dict(difference=centered, exact=exact)).set_name('centered')
-all = Composition(dict(exact=exact, forward=forward, backward=backward,
-                       centered=centered)).set_name('all')
-
-for fig in all, forward, backward, centered:
-    drawing_tool.erase()
-    fig.draw()
-    drawing_tool.display()
-    drawing_tool.savefig(fig.get_name())
-raw_input()
-

+ 0 - 39
doc/src/sketcher/src-sketcher/fd_func.py

@@ -1,39 +0,0 @@
-from pysketcher import *
-
-u = SketchyFunc1('$u(t)$', name_pos='end')
-t_mesh = [0, 2, 4, 6, 8]
-
-u = SketchyFunc2('$u(t)$', name_pos='end')
-n = 7
-t_mesh = [i*2.25/(n-1) for i in range(n)]
-
-t_min1 = t_mesh[0] - 0.2*(t_mesh[-1] - t_mesh[0])
-t_max1 = t_mesh[-1] + 0.2*(t_mesh[-1] - t_mesh[0])
-t_min2 = t_mesh[0] - 0.3*(t_mesh[-1] - t_mesh[0])
-t_max2 = t_mesh[-1] + 0.3*(t_mesh[-1] - t_mesh[0])
-u_max = 1.3*max([u(t) for t in t_mesh])
-u_min = -0.2*u_max
-
-drawing_tool.set_coordinate_system(t_min2, t_max2, u_min, u_max, axis=False)
-drawing_tool.set_linecolor('black')
-
-r = 0.005*(t_max2-t_min2)     # radius of circles placed at mesh points
-discrete_u = Composition({i: Circle(point(t, u(t)), r).\
-                          set_filled_curves('black')
-                          for i, t in enumerate(t_mesh)})
-print repr(discrete_u)
-axes = Composition(dict(x=Axis(point(0,0), t_max2, '$t$'),
-                        y=Axis(point(0,0), 0.8*u_max, '$u$',
-                               rotation_angle=90)))
-h = 0.03*u_max  # tickmarks height
-nodes = Composition({i: Composition(dict(
-    node=Line(point(t,h), point(t,-h)),
-    name=Text('$t_%d$' % i, point(t,-3.5*h))))
-                     for i, t in enumerate(t_mesh)})
-fig = Composition(dict(u=discrete_u, mesh=nodes, axes=axes)).set_name('fdm_u')
-drawing_tool.erase()
-fig.draw()
-drawing_tool.display()
-drawing_tool.savefig(fig.get_name())
-raw_input()
-

+ 112 - 0
doc/src/sketcher/src-sketcher/finite_differences.py

@@ -0,0 +1,112 @@
+"""
+Illustrate forward, backward and centered finite differences
+in four figures.
+"""
+
+from pysketcher import *
+
+#test_test()
+xaxis = 2
+drawing_tool.set_coordinate_system(0, 7, 1, 6, axis=False)
+
+f = SketchyFunc1('$u(t)$')
+x = 3                 # center point where we want the derivative
+xb = 2                # x point used for backward difference
+xf = 4                # x point used for forward difference
+p = (x, f(x))         # center point
+pf = (xf, f(xf))      # forward point
+pb = (xb, f(xb))      # backward point
+r = 0.1               # radius of circles placed at key points
+c = Circle(p, r).set_linecolor('blue')
+cf = Circle(pf, r).set_linecolor('red')
+cb = Circle(pb, r).set_linecolor('green')
+
+# Points in the mesh
+p0 = point(x, xaxis)        # center point
+pf0 = point(xf, xaxis)      # forward point
+pb0 = point(xb, xaxis)      # backward point
+tick = 0.05
+
+# 1D mesh with three points
+mesh = Composition({
+    'tnm1': Text('$t_{n-1}$', pb0 - point(0, 0.3)),
+    'tn': Text('$t_{n}$', p0 - point(0, 0.3)),
+    'tnp1': Text('$t_{n+1}$', pf0 - point(0, 0.3)),
+    'axis': Composition({
+        'hline': Line(pf0-point(3,0), pb0+point(3,0)).\
+        set_linecolor('black').set_linewidth(1),
+        'tick_m1': Line(pf0+point(0,tick), pf0-point(0,tick)).\
+        set_linecolor('black').set_linewidth(1),
+        'tick_n':  Line(p0+point(0,tick), p0-point(0,tick)).\
+        set_linecolor('black').set_linewidth(1),
+        'tick_p1': Line(pb0+point(0,tick), pb0-point(0,tick)).\
+        set_linecolor('black').set_linewidth(1)}),
+    })
+
+# Vertical dotted lines at each mesh point
+vlinec = Line(p, p0).set_linestyle('dotted').\
+         set_linecolor('blue').set_linewidth(1)
+vlinef = Line(pf, pf0).set_linestyle('dotted').\
+         set_linecolor('red').set_linewidth(1)
+vlineb = Line(pb, pb0).set_linestyle('dotted').\
+         set_linecolor('green').set_linewidth(1)
+
+# Compose vertical lines for each type of difference
+forward_lines = Composition({'center': vlinec, 'right': vlinef})
+backward_lines = Composition({'center': vlinec, 'left': vlineb})
+centered_lines = Composition({'left': vlineb, 'right': vlinef})
+centered_lines2 = Composition({'left': vlineb, 'right': vlinef,
+                               'center': vlinec})
+
+# Tangents illustrating the derivative
+domain = [1, 5]
+domain2 = [2, 5]
+forward_tangent = Line(p, pf).new_interval(x=domain2).\
+                  set_linestyle('dashed').set_linecolor('red')
+backward_tangent = Line(pb, p).new_interval(x=domain).\
+                   set_linestyle('dashed').set_linecolor('green')
+centered_tangent = Line(pb, pf).new_interval(x=domain).\
+                   set_linestyle('dashed').set_linecolor('blue')
+h = 1E-3  # h in finite difference approx used to compute the exact tangent
+exact_tangent = Line((x+h, f(x+h)), (x-h, f(x-h))).\
+                new_interval(x=domain).\
+                set_linestyle('dotted').set_linecolor('black')
+
+forward = Composition(
+    dict(tangent=forward_tangent,
+         point1=c, point2=cf, coor=forward_lines,
+         name=Text('forward',
+                   forward_tangent.geometric_features()['end'] + \
+                   point(0.1,0), alignment='left')))
+backward = Composition(
+    dict(tangent=backward_tangent,
+         point1=c, point2=cb, coor=backward_lines,
+         name=Text('backward',
+                   backward_tangent.geometric_features()['end'] + \
+                   point(0.1,0), alignment='left')))
+centered = Composition(
+    dict(tangent=centered_tangent,
+         point1=cb, point2=cf, point=c, coor=centered_lines2,
+         name=Text('centered',
+                   centered_tangent.geometric_features()['end'] + \
+                   point(0.1,0), alignment='left')))
+
+exact = Composition(dict(graph=f, tangent=exact_tangent))
+forward = Composition(dict(difference=forward, exact=exact)).\
+          set_name('forward')
+backward = Composition(dict(difference=backward, exact=exact)).\
+           set_name('backward')
+centered = Composition(dict(difference=centered, exact=exact)).\
+           set_name('centered')
+all = Composition(
+    dict(exact=exact, forward=forward, backward=backward,
+         centered=centered)).set_name('all')
+
+for fig in forward, backward, centered, all:
+    drawing_tool.erase()
+    fig.draw()
+    mesh.draw()
+    drawing_tool.display()
+    drawing_tool.savefig('fd_'+fig.get_name())
+raw_input()
+

+ 65 - 0
doc/src/sketcher/src-sketcher/mesh_function.py

@@ -0,0 +1,65 @@
+from pysketcher import *
+
+u = SketchyFunc2('$u(t)$', name_pos='end')
+n = 7
+t_mesh = [i*2.25/(n-1) for i in range(n)]
+
+u = SketchyFunc2('$u(t)$', name_pos='end')
+t_mesh = [0, 2, 4, 6, 8]
+
+u = SketchyFunc3()
+t_mesh = linspace(0, 6, 8)  # bra
+t_mesh = linspace(0, 6, 6)
+
+
+t_min1 = t_mesh[0] - 0.1*(t_mesh[-1] - t_mesh[0])
+t_max1 = t_mesh[-1] + 0.2*(t_mesh[-1] - t_mesh[0])
+t_min2 = t_mesh[0] - 0.2*(t_mesh[-1] - t_mesh[0])
+t_max2 = t_mesh[-1] + 0.3*(t_mesh[-1] - t_mesh[0])
+u_max = 1.3*max([u(t) for t in t_mesh])
+u_min = -0.2*u_max
+
+drawing_tool.set_coordinate_system(t_min2, t_max2, u_min, u_max, axis=False)
+drawing_tool.set_linecolor('black')
+
+r = 0.005*(t_max2-t_min2)     # radius of circles placed at mesh points
+discrete_u = Composition({i: Composition(dict(
+    circle=Circle(point(t, u(t)), r).set_filled_curves('black'),
+    u_point=Text('$u_%d$' % i,
+                 point(t, u(t)) + (point(0,5*r)
+                                   if i > 0 else point(-5*r,0))),
+    )) for i, t in enumerate(t_mesh)})
+
+interpolant = Composition({
+    i: Line(point(t_mesh[i-1], u(t_mesh[i-1])),
+            point(t_mesh[i], u(t_mesh[i]))).set_linewidth(1)
+    for i in range(1, len(t_mesh))})
+
+axes = Composition(dict(x=Axis(point(0,0), t_max1, '$t$',
+                               label_spacing=(1/45.,-1/30.)),
+                        y=Axis(point(0,0), 0.8*u_max, '$u$',
+                               rotation_angle=90)))
+h = 0.03*u_max  # tickmarks height
+nodes = Composition({i: Composition(dict(
+    node=Line(point(t,h), point(t,-h)),
+    name=Text('$t_%d$' % i, point(t,-3.5*h))))
+                     for i, t in enumerate(t_mesh)})
+illustration = Composition(dict(u=discrete_u,
+                                mesh=nodes,
+                                axes=axes)).set_name('fdm_u')
+drawing_tool.erase()
+illustration.draw()
+drawing_tool.display()
+drawing_tool.savefig(illustration.get_name())
+
+exact = u.set_linestyle('dashed').set_linewidth(1)
+exact.draw()
+drawing_tool.display()
+drawing_tool.savefig('%s_ue' % illustration.get_name())
+
+interpolant.draw()
+drawing_tool.display()
+drawing_tool.savefig('%s_uei' % illustration.get_name())
+
+raw_input()
+

+ 23 - 3
pysketcher/shapes.py

@@ -144,7 +144,7 @@ class Shape:
         return self
 
     def get_name(self):
-        return self.name if hasattr(self, 'name') else None
+        return self.name if hasattr(self, 'name') else 'no_name'
 
     def __iter__(self):
         # We iterate over self.shapes many places, and will
@@ -618,6 +618,20 @@ class SketchyFunc1(Spline):
         if name is not None:
             self.shapes['name'] = Text(name, self.geometric_features()[name_pos] + point(0,0.1))
 
+class SketchyFunc3(Spline):
+    """
+    A typical function curve used to illustrate an "arbitrary" function.
+    """
+    domain = [0, 6]
+    def __init__(self, name=None, name_pos='start'):
+        x = [0, 2,   3,   4, 5,   6]
+        y = [2, 3.5, 3.8, 2, 2.5, 2.6]
+        y = [0.5, 3.5, 3.8, 2, 2.5, 3.5]
+        Spline.__init__(self, x, y)
+        self.shapes['smooth'].set_linecolor('black')
+        if name is not None:
+            self.shapes['name'] = Text(name, self.geometric_features()[name_pos] + point(0,0.1))
+
 
 class SketchyFunc2(Shape):
     """
@@ -1269,9 +1283,15 @@ class Axis(Shape):
         # Arrow is vertical arrow, make it horizontal
         arrow = Arrow3(start, length, rotation_angle=-90)
         arrow.rotate(rotation_angle, start)
-        spacing = drawing_tool.xrange*label_spacing
+        if isinstance(label_spacing, (list,tuple)) and len(label_spacing) == 2:
+            x_spacing = drawing_tool.xrange*label_spacing[0]
+            y_spacing = drawing_tool.yrange*label_spacing[1]
+        elif isinstance(label_spacing, (int,float)):
+            # just x spacing
+            x_spacing = drawing_tool.xrange*label_spacing
+            y_spacing = 0
         # should increase spacing for downward pointing axis
-        label_pos = [start[0] + length + spacing, start[1]]
+        label_pos = [start[0] + length + x_spacing, start[1] + y_spacing]
         label = Text(label, position=label_pos, fontsize=fontsize)
         label.rotate(rotation_angle, start)
         self.shapes = {'arrow': arrow, 'label': label}