Hans Petter Langtangen 13 jaren geleden
bovenliggende
commit
c6025ebeea

+ 12 - 13
doc/src/sketcher/sketcher.do.txt

@@ -381,18 +381,17 @@ The complete example is found in the file
 "`vehicle1.py`": "http://hplgit.github.com/pysketcher/doc/src/sketcher/src-sketcher/vehicle1.py". You may run this file or watch a "ready-made movie": "http://hplgit.github.com/pysketcher/doc/src/sketcher/src-sketcher/animation_vehicle1/anim.html".
 # #endif
 
-The great advantage with making figures this way through programming,
-rather than using interactive drawing programs, is that the
-accuracy of mathematical drawings is easily reflected, distances
-can be parameterized through variables such that the
-proportions of parts of the figure can be quickly changed,
-groups of objects can easily be manipulated (translated, rotated,
-scaled), objects can be left out while experimenting with the
-figure, to mention some important features. However, the single
-most important feature is the ability to make animations governed
-by mathematical formulas, maybe coming from simulations
-based on solving differential equations reflecting the physics
-of the problem.
+The advantages with making figures this way through programming,
+rather than using interactive drawing programs, are numerous.  For
+example, the objects are parameterized by variables so that various
+dimensions can easily be changed.  Subparts of the figure can change
+color, linetype, filling or other properties through a single function
+call.  Subparts of the figure can be rotated, translated, or scaled.
+Subparts of the figure can be copied and moved to other parts of the
+drawing area. However, the single most important feature is probably
+the ability to make animations governed by mathematical formulas or
+data coming from physics simulations of the problem sketched in
+the drawing.
 
 
 ===== Example of Classes for Geometric Objects =====
@@ -632,7 +631,7 @@ class Curve(Shape):
 === Compound Geometric Objects ===
 
 The sample classes so far has managed to define the geometric shape
-through just one `Curve` object.
+through just one `Curve` object.[[[
 
 
 

+ 7 - 6
doc/src/sketcher/src-sketcher/flow_over_gaussian.py

@@ -42,13 +42,14 @@ fig.draw()  # send all figures to plotting backend
 
 vx, vy = velprofile(H/2.)
 symbols = {
-    'alpha': DistanceSymbol((W,0), (W,alpha), r'$\alpha$'),
-    'W': DistanceSymbol((0,-0.5), (W,-0.5), r'$W$',
-                        symbol_spacing=-1./30),
-    'L': DistanceSymbol((W,-0.5), (W+L,-0.5), r'$L$',
-                        symbol_spacing=-1./30),
+    'alpha': Distance_wSymbol((W,0), (W,alpha), r'$\alpha$'),
+    'W': Distance_wSymbol((0,-0.5), (W,-0.5), r'$W$',
+                          symbol_spacing=-1./30),
+    'L': Distance_wSymbol((W,-0.5), (W+L,-0.5), r'$L$',
+                          symbol_spacing=-1./30),
     'v(y)': Text('$v(y)$', (H/2., vx)),
-    'dashed line': Line((W-2.5*sigma,0), (W+2.5*sigma,0)).set_linestyle('dotted').set_linecolor('black'),
+    'dashed line': Line((W-2.5*sigma,0), (W+2.5*sigma,0)).\
+                   set_linestyle('dotted').set_linecolor('black'),
     }
 symbols = Compose(symbols)
 symbols.draw()

+ 1 - 1
pysketcher/MatplotlibDraw.py

@@ -225,7 +225,7 @@ ax.set_aspect('equal')
         """Save figure in file."""
         self.mpl.savefig(filename)
         if self.instruction_file:
-            self.instruction_file.write('mpl.savefig(%s)\n' % filename)
+            self.instruction_file.write('mpl.savefig("%s")\n' % filename)
 
     def text(self, text, position, alignment='center', fontsize=18,
              arrow_tip=None):

+ 107 - 62
pysketcher/shapes.py

@@ -846,7 +846,7 @@ def test_Axis():
     print repr(system)
 
 
-class DistanceSymbol(Shape):
+class Distance_wSymbol(Shape):
     """
     Arrow with symbol at the midpoint,
     for identifying a distance with a symbol.
@@ -977,87 +977,132 @@ class SineWave(Shape):
 
 
 
-# make a version of Spring using Point class
+class Spring1(Shape):
+    spring_fraction = 1./2  # fraction of total length occupied by spring
 
-
-class Spring(Shape):
-    def __init__(self, bottom_point, length, tooth_spacing, ntooths=4):
+    def __init__(self, start, length, tooth_width, num_teeth=8):
         """
         Specify a vertical spring, starting at bottom_point and
         having a specified lengths. In the middle third of the
         spring there are ntooths saw thooth tips.
         """
-        self.B = bottom_point
-        self.n = ntooths - 1  # n counts tag intervals
+        B = start
+        n = num_teeth - 1  # n counts teeth intervals
         # n must be odd:
-        if self.n % 2 == 0:
-            self.n = self.n+1
-        self.L = length
-        self.w = tooth_spacing
-
-        B, L, n, w = self.B, self.L, self.n, self.w  # short forms
-        t = L/(3.0*n)  # must be better worked out
-        P0 = (B[0], B[1]+L/3.0)
-        P1 = (B[0], B[1]+L/3.0+t/2.0)
-        P2 = (B[0], B[1]+L*2/3.0)
-        P3 = (B[0], B[1]+L)
-        line1 = Line(B, P1)
-        lines = [line1]
-        #line2 = Line(P2, P3)
-        T1 = P1
+        if n % 2 == 0:
+            n = n+1
+        L = length
+        w = tooth_width
+
+        # [0, x, L-x, L], f = (L-2*x)/L
+        # x = L*(1-f)/2.
+        shapes = {}
+        f = Spring1.spring_fraction
+        t = f*L/n      # distance between teeth
+        s = L*(1-f)/2. # start of spring
+        P0 = (B[0], B[1]+s)
+        shapes['line start'] = Line(B, P0)
+        T1 = P0
         T2 = (T1[0] + w, T1[1] + t/2.0)
-        lines.append(Line(T1,T2))
-        T1 = (T2[0], T2[1])
-        for i in range(n):
+        k = 1
+        shapes['line%d' % k] = Line(T1,T2)
+        T1 = T2[:]  # copy
+        for i in range(2*n-3):
             T2 = (T1[0] + (-1)**(i+1)*2*w, T1[1] + t/2.0)
-            lines.append(Line(T1, T2))
+            k += 1
+            shapes['line%d' % k] = Line(T1, T2)
             T1 = (T2[0], T2[1])
         T2 = (T1[0] + w, T1[1] + t/2.0)
-        lines.append(Line(T1,T2))
+        k += 1
+        shapes['line%d' % k] = Line(T1,T2)
+
+        P2 = (B[0], B[1]+L)
+        shapes['line end'] = Line(T2, P2)
+        self.shapes = shapes
 
-        #print P2, T2
-        lines.append(Line(T2, P3))
-        self.shapes = lines
+class Spring2(Shape):
+    spring_fraction = 1./2  # fraction of total length occupied by spring
 
-class Spring(Shape):
-    def __init__(self, bottom_point, length, tooth_spacing, ntooths=4):
+    def __init__(self, start, length, width, num_windings=11):
         """
         Specify a vertical spring, starting at bottom_point and
         having a specified lengths. In the middle third of the
-        spring there are ntooths tags.
+        spring there are ntooths saw thooth tips.
         """
-        self.B = bottom_point
-        self.n = ntooths - 1  # n counts tag intervals
+        B = start
+        n = num_windings - 1  # n counts teeth intervals
+        if n <= 6:
+            n = 7
         # n must be odd:
-        if self.n % 2 == 0:
-            self.n = self.n+1
-        self.L = length
-        self.w = tooth_spacing
-
-        B, L, n, w = self.B, self.L, self.n, self.w  # short forms
-        t = L/(3.0*n)  # must be better worked out
-        P0 = (B[0], B[1]+L/3.0)
-        P1 = (B[0], B[1]+L/3.0+t/2.0)
-        P2 = (B[0], B[1]+L*2/3.0)
-        P3 = (B[0], B[1]+L)
-        line1 = Line(B, P1)
-        lines = [line1]
-        #line2 = Line(P2, P3)
-        T1 = P1
-        T2 = (T1[0] + w, T1[1] + t/2.0)
-        lines.append(Line(T1,T2))
-        T1 = (T2[0], T2[1])
-        for i in range(n):
-            T2 = (T1[0] + (-1)**(i+1)*2*w, T1[1] + t/2.0)
-            lines.append(Line(T1, T2))
-            T1 = (T2[0], T2[1])
-        T2 = (T1[0] + w, T1[1] + t/2.0)
-        lines.append(Line(T1,T2))
+        if n % 2 == 0:
+            n = n+1
+        L = length
+        w = width
 
-        #print P2, T2
-        lines.append(Line(T2, P3))
-        self.shapes = lines
+        # [0, x, L-x, L], f = (L-2*x)/L
+        # x = L*(1-f)/2.
+        shapes = {}
+        f = Spring2.spring_fraction
+        t = f*L/n      # must be better worked out
+        s = L*(1-f)/2. # start of spring
+        P0 = (B[0], B[1]+s)
+        shapes['line start'] = Line(B, P0)
+        q = linspace(0, n, n*180 + 1)
+        x = P0[0] + w*sin(2*pi*q)
+        y = P0[1] + q*t
+        shapes['sprial'] = Curve(x, y)
+        P1 = (B[0], L-s)
+        P2 = (B[0], B[1]+L)
+        shapes['line end'] = Line(P1,P2)
+        self.shapes = shapes
+
+class Dashpot(Shape):
+    dashpot_fraction = 1./2  # fraction of total length occupied by dashpot
+    piston_gap_fraction = 1./6
+    piston_thickness_fraction = 1./8
 
+    def __init__(self, start, length, width, piston_pos=None):
+        """
+        Specify a vertical dashpot of height `length`, width `width`,
+        and `start` as bottom/starting point. The piston position,
+        `piston_pos` can be specified, but default value None places
+        it at 1/3 from the bottom of the dashpot.
+        """
+        B = start
+        L = length
+        w = width
+
+        # [0, x, L-x, L], f = (L-2*x)/L
+        # x = L*(1-f)/2.
+        shapes = {}
+        f = Dashpot.dashpot_fraction
+        s = L*(1-f)/2. # start of dashpot
+        P0 = (B[0], B[1]+s)
+        P1 = (B[0], B[1]+L-s)
+        P2 = (B[0], B[1]+L)
+        shapes['line start'] = Line(B, P0)
+
+        shapes['pot'] = Curve([P1[0]-w, P0[0]-w, P0[0]+w, P1[0]+w],
+                              [P1[1], P0[1], P0[1], P1[1]])
+        piston_thickness = f*L*Dashpot.piston_thickness_fraction
+        if piston_pos is None:
+            piston_pos = P0[1] + 1/3.*f*L
+            print 'Calculated piston position:', piston_pos, P0[1], 1/3.*f*L
+        if piston_pos < P0[1]:
+            piston_pos = P0[1]
+            print 'too small piston position, <', P0[1]
+        if piston_pos > P1[1]-piston_thickness:
+            print 'too large piston position, >', P1[1]-piston_thickness
+            piston_pos = P1[1]-piston_thickness
+        gap = w*Dashpot.piston_gap_fraction
+        shapes['piston'] = Compose(
+            {'line': Line(P2, (B[0], piston_pos + piston_thickness)),
+             'rectangle': Rectangle((B[0] - w+gap, piston_pos),
+                                    2*w-2*gap, piston_thickness),
+             })
+        shapes['piston']['rectangle'].set_filled_curves(pattern='X')
+
+        self.shapes = shapes
 
 # COMPOSITE types:
 # MassSpringForce: Line(horizontal), Spring, Rectangle, Arrow/Line(w/arrow)