Hans Petter Langtangen 13 years ago
parent
commit
bdf2f1f7bc

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


+ 3 - 3
doc/src/sketcher/src-sketcher/beam1.py

@@ -10,6 +10,7 @@ drawing_tool.set_coordinate_system(xmin=0, xmax=xpos+1.2*L,
                                    axis=True)
                                    axis=True)
 drawing_tool.set_linecolor('blue')
 drawing_tool.set_linecolor('blue')
 drawing_tool.set_grid(True)
 drawing_tool.set_grid(True)
+drawing_tool.set_fontsize(22)
 
 
 P0 = point(xpos,ypos)
 P0 = point(xpos,ypos)
 main = Rectangle(P0, L, H)
 main = Rectangle(P0, L, H)
@@ -17,9 +18,8 @@ h = L/16  # size of support, clamped wall etc
 support = SimplySupportedBeam(P0, h)
 support = SimplySupportedBeam(P0, h)
 clamped = Rectangle(P0 + point(L, 0) - point(0,2*h), h, 6*h).set_filled_curves(pattern='/')
 clamped = Rectangle(P0 + point(L, 0) - point(0,2*h), h, 6*h).set_filled_curves(pattern='/')
 F_pt = point(P0[0]+L/2, P0[1]+H)
 F_pt = point(P0[0]+L/2, P0[1]+H)
-force = Force(F_pt + point(0,2*H), F_pt, '$F$', fontsize=22).set_linewidth(3)
-L_dim = Distance_wText((xpos,P0[1]-3*h), (xpos+L,P0[1]-3*h), '$L$',
-                       fontsize=22)
+force = Force(F_pt + point(0,2*H), F_pt, '$F$').set_linewidth(3)
+L_dim = Distance_wText((xpos,P0[1]-3*h), (xpos+L,P0[1]-3*h), '$L$')
 beam = Compose({'main': main, 'simply supported end': support,
 beam = Compose({'main': main, 'simply supported end': support,
                 'clamped end': clamped, 'force': force,
                 'clamped end': clamped, 'force': force,
                 'L': L_dim})
                 'L': L_dim})

+ 12 - 18
doc/src/sketcher/src-sketcher/beam2.py

@@ -12,8 +12,8 @@ drawing_tool.set_coordinate_system(xmin=-3, xmax=xpos+1.5*L,
                                    axis=False)
                                    axis=False)
 drawing_tool.set_linecolor('blue')
 drawing_tool.set_linecolor('blue')
 #drawing_tool.set_grid(True)
 #drawing_tool.set_grid(True)
+drawing_tool.set_fontsize(16)
 
 
-fontsize=16
 A = point(xpos,ypos)
 A = point(xpos,ypos)
 
 
 beam = Rectangle(A, L, H)
 beam = Rectangle(A, L, H)
@@ -25,47 +25,41 @@ clamped = Rectangle(A - point(h,0) - point(0,2*h), h,
 
 
 load = ConstantBeamLoad(A + point(0,H), L, H)
 load = ConstantBeamLoad(A + point(0,H), L, H)
 load.set_linewidth(1).set_linecolor('black')
 load.set_linewidth(1).set_linecolor('black')
-load_text = Text('$w$', load.mid_top + point(0,h/2.), fontsize=fontsize)
+load_text = Text('$w$', load.mid_top + point(0,h/2.))
 
 
 B = A + point(a, 0)
 B = A + point(a, 0)
 C = B + point(b, 0)
 C = B + point(b, 0)
 
 
-support = SimplySupportedBeam(B, h)
+support = SimplySupportedBeam(B, h)  # pt B is simply supported
 
 
 
 
-R1 = Force(A-point(0,2*H), A, '$R_1$',
-           fontsize=fontsize, symbol_spacing=1./20)
+R1 = Force(A-point(0,2*H), A, '$R_1$', text_spacing=1./20)
 R1.set_linewidth(3).set_linecolor('black')
 R1.set_linewidth(3).set_linecolor('black')
 R2 = Force(B-point(0,2*H), support.mid_support,
 R2 = Force(B-point(0,2*H), support.mid_support,
-           '$R_2$', fontsize=fontsize, symbol_spacing=1./20)
+           '$R_2$', text_spacing=1./20)
 R2.set_linewidth(3).set_linecolor('black')
 R2.set_linewidth(3).set_linecolor('black')
 M1 = Moment('$M_1$', center=A + point(-H, H/2), radius=H/2,
 M1 = Moment('$M_1$', center=A + point(-H, H/2), radius=H/2,
-            left=True, fontsize=fontsize,
-            symbol_spacing=1/30.)
+            left=True, text_spacing=1/30.)
 M1.set_linecolor('black')
 M1.set_linecolor('black')
 
 
 ab_level = point(0, 3*h)
 ab_level = point(0, 3*h)
-a_dim = Distance_wText(A - ab_level, B - ab_level, '$a$',
-                       fontsize=fontsize)
-b_dim = Distance_wText(B - ab_level, C - ab_level, '$b$',
-                       fontsize=fontsize)
+a_dim = Distance_wText(A - ab_level, B - ab_level, '$a$')
+b_dim = Distance_wText(B - ab_level, C - ab_level, '$b$')
 dims = Compose({'a': a_dim, 'b': b_dim})
 dims = Compose({'a': a_dim, 'b': b_dim})
 symbols = Compose({'R1': R1, 'R2': R2, 'M1': M1,
 symbols = Compose({'R1': R1, 'R2': R2, 'M1': M1,
                    'w': load, 'w text': load_text,
                    'w': load, 'w text': load_text,
-                   'A': Text('$A$', A+point(h/2,-h/2)),
+                   'A': Text('$A$', A+point(0.7*h,-0.9*h)),
                    'B': Text('$B$', support.mid_support-point(h,0)),
                    'B': Text('$B$', support.mid_support-point(h,0)),
                    'C': Text('$C$', C+point(h/2,-h/2))})
                    'C': Text('$C$', C+point(h/2,-h/2))})
 
 
-x_axis = Axis(A + point(L+h, H/2), 2*H, '$x$',
-              fontsize=fontsize).set_linecolor('black')
+x_axis = Axis(A + point(L+h, H/2), 2*H, '$x$',).set_linecolor('black')
 y_axis = Axis(A + point(0,H/2), 3.5*H, '$y$',
 y_axis = Axis(A + point(0,H/2), 3.5*H, '$y$',
-              below=False, rotation_angle=90,
-              fontsize=fontsize).set_linecolor('black')
+              below=False, rotation_angle=90).set_linecolor('black')
 axes = Compose({'x axis': x_axis, 'y axis': y_axis})
 axes = Compose({'x axis': x_axis, 'y axis': y_axis})
 
 
 annotations = Compose({'dims': dims, 'symbols': symbols,
 annotations = Compose({'dims': dims, 'symbols': symbols,
                 'axes': axes})
                 'axes': axes})
-fig = Compose({'main': main, 'support': support,
+fig = Compose({'beam': beam, 'support': support,
                'clamped end': clamped, 'load': load})
                'clamped end': clamped, 'load': load})
 
 
 def deflection(x, a, b, w):
 def deflection(x, a, b, w):

+ 46 - 0
doc/src/sketcher/src-sketcher/osc1.py

@@ -0,0 +1,46 @@
+from pysketcher import *
+
+L = 12.
+H = L/6
+W = L/6
+
+xmax = L
+drawing_tool.set_coordinate_system(xmin=-L, xmax=xmax,
+                                   ymin=-1, ymax=L,
+                                   axis=True,
+                                   instruction_file='tmp_mpl.py')
+x = 0
+
+def make_dashpot(x):
+    d_start = (-L,2*H)
+    d = Dashpot(start=d_start, total_length=L+x, width=W,
+                bar_length=3*H/2, dashpot_length=L/4, piston_pos=H)
+    d.rotate(-90, d_start)
+    return d
+
+def make_spring(x):
+    s_start = (-L,4*H)
+    s = Spring(start=s_start, length=L+x, bar_length=3*H/2, teeth=True)
+    s.rotate(-90, s_start)
+    return s
+
+d = make_dashpot(0)
+s = make_spring(0)
+
+M = Rectangle((0,H), 4*H, 4*H)
+left_wall = Rectangle((-L,0),H/10,4*H).set_filled_curves(pattern='/')
+ground = Wall(x=[-L/2,L], y=[0,0], thickness=-H/10)
+wheel1 = Circle((H,H/2), H/2)
+wheel2 = wheel1.copy()
+wheel2.translate(point(2*H, 0))
+fig = Compose({
+    'dashpot': d, 'spring': s, 'mass': M, 'left wall': left_wall,
+    'ground': ground, 'wheel1': wheel1, 'wheel2': wheel2})
+
+#fig.draw()
+s.draw()
+print s
+print s.shapes['bar1']['line'].x, s.shapes['bar1']['line'].y
+print s.shapes['bar2']['line'].x, s.shapes['bar2']['line'].y
+drawing_tool.display()
+raw_input()

+ 83 - 0
doc/src/sketcher/src-sketcher/pendulum.py

@@ -0,0 +1,83 @@
+from pysketcher import *
+
+H = 7.
+W = 6.
+
+drawing_tool.set_coordinate_system(xmin=0, xmax=W,
+                                   ymin=0, ymax=H,
+                                   axis=True)
+drawing_tool.set_linecolor('blue')
+#drawing_tool.set_grid(True)
+
+def set_dashed_thin_blackline(*objects):
+    """Set linestyle of an object to dashed, black, width=1."""
+    for obj in objects:
+        obj.set_linestyle('dashed')
+        obj.set_linecolor('black')
+        obj.set_linewidth(1)
+
+
+L = 5*H/7          # length
+P = (W/6, 0.85*H)  # rotation point
+a = 40             # angle
+
+path = Arc(P, L, -90, a)
+angle = Arc_wText(r'$\theta$', P, L/4, -90, a, text_spacing=1/30.)
+vertical = Line(P, P-point(0,L))
+
+rod = Line(P, P + L*point(sin(radians(a)), -cos(radians(a))))
+# or shorter (and more reliable)
+mass_pt = path.end
+rod = Line(P, mass_pt)
+
+mass = Circle(center=mass_pt, radius=L/20.)
+mass.set_filled_curves(color='blue')
+mass_symbol = Text('$m$', mass_pt + L/10*unit_vec(rod.end-rod.start))
+
+length = Distance_wText(P, mass_pt, '$L$')
+# Displace length indication
+length.translate(L/15*point(cos(radians(a)), sin(radians(a))))
+gravity = Gravity(start=P+point(0.8*L,0), length=L/3)
+
+set_dashed_thin_blackline(vertical, path)
+
+dims = Compose({'vertical': vertical, 'theta': angle, 'path': path,
+                'g': gravity, 'L': length, 'm': mass_symbol})
+
+fig = Compose({'body': mass, 'rod': rod, 'dims': dims})
+
+#drawing_tool.ax.set_xlim(4,10)
+#drawing_tool.ax.set_ylim(1,8)
+fig.draw()
+drawing_tool.display()
+drawing_tool.savefig('tmp_pendulum1.png')
+
+# Draw body diagram
+#raw_input('Press Return to make body diagram: ')
+import time; time.sleep(2)
+drawing_tool.erase()
+
+drawing_tool.set_linecolor('black')
+mg_force = Force(mass_pt, mass_pt + L/3*point(0,-1), '$mg$', text_pos='end')
+rod_force = Force(mass_pt, mass_pt + L/3*unit_vec(rod.start-rod.end),
+                  '$S$', text_pos='end')
+vertical2 = Line(rod_force.end, rod_force.end + point(0,-L/3))
+set_dashed_thin_blackline(vertical2)
+angle2 = Arc_wText(r'$\theta$', rod_force.end, L/6, -90, a, text_spacing=1/30.)
+path2 = Arc(P, L, -90+a-a/2., a)
+path2.set_arrow('<-')
+path2.set_linestyle('dashed')
+
+body_diagram = Compose({'mg': mg_force, 'S': rod_force,
+                        'vertical': vertical2, 'theta': angle2,
+                        'path': path2, 'body': mass, 'm': mass_symbol})
+body_diagram.draw()
+drawing_tool.display('Body diagram')
+drawing_tool.savefig('tmp_pendulum2.png')
+
+time.sleep(1)
+drawing_tool.adjust_coordinate_system(body_diagram.minmax_coordinates(), 90)
+drawing_tool.display('Body diagram')
+drawing_tool.savefig('tmp_pendulum3.png')
+
+raw_input()

+ 76 - 10
pysketcher/MatplotlibDraw.py

@@ -5,12 +5,29 @@ import matplotlib.pyplot as mpl
 import numpy as np
 import numpy as np
 
 
 class MatplotlibDraw:
 class MatplotlibDraw:
+    """
+    Simple interface for plotting. This interface makes use of
+    Matplotlib for plotting.
+
+    Some attributes that must be controlled directly (no set_* method
+    since these attributes are changed quite seldom).
+
+    ========================== ============================================
+    Attribute                  Description
+    ========================== ============================================
+    allow_screen_graphics      False means that no plot is shown on
+                               the screen. (Does not work yet.)
+    arrow_head_width           Size of arrow head.
+    ========================== ============================================
+    """
+
     line_colors = {'red': 'r', 'green': 'g', 'blue': 'b', 'cyan': 'c',
     line_colors = {'red': 'r', 'green': 'g', 'blue': 'b', 'cyan': 'c',
                    'magenta': 'm', 'purple': 'p',
                    'magenta': 'm', 'purple': 'p',
                    'yellow': 'y', 'black': 'k', 'white': 'w',
                    'yellow': 'y', 'black': 'k', 'white': 'w',
                    'brown': 'brown', '': ''}
                    'brown': 'brown', '': ''}
     def __init__(self):
     def __init__(self):
         self.instruction_file = None
         self.instruction_file = None
+        self.allow_screen_graphics = True  # does not work yet
 
 
     def ok(self):
     def ok(self):
         """
         """
@@ -18,6 +35,21 @@ class MatplotlibDraw:
         objects can be drawn.
         objects can be drawn.
         """
         """
 
 
+    def adjust_coordinate_system(self, minmax, occupation_percent=80):
+        """
+        Given a dict of xmin, xmax, ymin, ymax values, and a desired
+        filling of the plotting area of `occupation_percent` percent,
+        set new axis limits.
+        """
+        x_range = minmax['xmax'] - minmax['xmin']
+        y_range = minmax['ymax'] - minmax['ymin']
+        new_x_range = x_range*100./occupation_percent
+        x_space = new_x_range - x_range
+        new_y_range = y_range*100./occupation_percent
+        y_space = new_y_range - y_range
+        self.ax.set_xlim(minmax['xmin']-x_space/2., minmax['xmax']+x_space/2.)
+        self.ax.set_ylim(minmax['ymin']-y_space/2., minmax['ymax']+y_space/2.)
+
     def set_coordinate_system(self, xmin, xmax, ymin, ymax, axis=False,
     def set_coordinate_system(self, xmin, xmax, ymin, ymax, axis=False,
                               instruction_file=None):
                               instruction_file=None):
         """
         """
@@ -28,6 +60,15 @@ class MatplotlibDraw:
         for the plotting program are stored (useful for debugging
         for the plotting program are stored (useful for debugging
         a figure or tailoring plots).
         a figure or tailoring plots).
         """
         """
+
+        # Close file for previous figure and start new one
+        # if not the figure file is the same
+        if self.instruction_file is not None:
+            if instruction_file == self.instruction_file.name:
+                pass  # continue with same file
+            else:
+                self.instruction_file.close()  # make new py file for commands
+
         self.mpl = mpl
         self.mpl = mpl
         self.xmin, self.xmax, self.ymin, self.ymax = \
         self.xmin, self.xmax, self.ymin, self.ymax = \
              float(xmin), float(xmax), float(ymin), float(ymax)
              float(xmin), float(xmax), float(ymin), float(ymax)
@@ -55,19 +96,19 @@ import matplotlib.pyplot as mpl
 
 
 mpl.ion()  # for interactive drawing
 mpl.ion()  # for interactive drawing
 """)
 """)
-        self._make_axes(new_figure=True)
-
-        manager = self.mpl.get_current_fig_manager()
-        manager.window.wm_geometry(geometry)
-
-
         # Default properties
         # Default properties
         self.set_linecolor('red')
         self.set_linecolor('red')
         self.set_linewidth(2)
         self.set_linewidth(2)
         self.set_linestyle('solid')
         self.set_linestyle('solid')
         self.set_filled_curves()  # no filling
         self.set_filled_curves()  # no filling
+        self.set_fontsize(14)
         self.arrow_head_width = 0.2*self.xrange/16
         self.arrow_head_width = 0.2*self.xrange/16
 
 
+        self._make_axes(new_figure=True)
+
+        manager = self.mpl.get_current_fig_manager()
+        manager.window.wm_geometry(geometry)
+
     def _make_axes(self, new_figure=False):
     def _make_axes(self, new_figure=False):
         if new_figure:
         if new_figure:
             self.fig = self.mpl.figure()
             self.fig = self.mpl.figure()
@@ -150,6 +191,13 @@ ax.set_aspect('equal')
                          MatplotlibDraw.line_colors[color]
                          MatplotlibDraw.line_colors[color]
             self.fillpattern = pattern
             self.fillpattern = pattern
 
 
+    def set_fontsize(self, fontsize=18):
+        """
+        Method for setting a common fontsize for text, unless
+        individually specified when calling ``text``.
+        """
+        self.fontsize = fontsize
+
     def set_grid(self, on=False):
     def set_grid(self, on=False):
         self.mpl.grid(on)
         self.mpl.grid(on)
         if self.instruction_file:
         if self.instruction_file:
@@ -168,6 +216,11 @@ ax.set_aspect('equal')
                    linecolor=None, arrow=None,
                    linecolor=None, arrow=None,
                    fillcolor=None, fillpattern=None):
                    fillcolor=None, fillpattern=None):
         """Define a curve with coordinates x and y (arrays)."""
         """Define a curve with coordinates x and y (arrays)."""
+        #if not self.allow_screen_graphics:
+        #    mpl.ioff()
+        #else:
+        #    mpl.ion()
+
         self.xdata = np.asarray(x, dtype=np.float)
         self.xdata = np.asarray(x, dtype=np.float)
         self.ydata = np.asarray(y, dtype=np.float)
         self.ydata = np.asarray(y, dtype=np.float)
 
 
@@ -228,7 +281,9 @@ ax.set_aspect('equal')
             self.mpl.title(title)
             self.mpl.title(title)
             if self.instruction_file:
             if self.instruction_file:
                 self.instruction_file.write('mpl.title("%s")\n' % title)
                 self.instruction_file.write('mpl.title("%s")\n' % title)
+
         self.mpl.draw()
         self.mpl.draw()
+
         if self.instruction_file:
         if self.instruction_file:
             self.instruction_file.write('mpl.draw()\n')
             self.instruction_file.write('mpl.draw()\n')
 
 
@@ -238,15 +293,26 @@ ax.set_aspect('equal')
         if self.instruction_file:
         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,
+    def text(self, text, position, alignment='center', fontsize=0,
              arrow_tip=None):
              arrow_tip=None):
         """
         """
-        Write text at a position (centered, left, right - according
-        to the alignment string). position is a 2-tuple.
-        arrow+tip != None draws an arrow from the text to a point
+        Write `text` string at a position (centered, left, right - according
+        to the `alignment` string). `position` is a point in the coordinate
+        system.
+        If ``arrow+tip != None``, an arrow is drawn from the text to a point
         (on a curve, for instance). The arrow_tip argument is then
         (on a curve, for instance). The arrow_tip argument is then
         the (x,y) coordinates for the arrow tip.
         the (x,y) coordinates for the arrow tip.
+        fontsize=0 indicates use of the default font as set by
+        ``set_fontsize``.
         """
         """
+        if fontsize == 0:
+            if hasattr(self, 'fontsize'):
+                fontsize = self.fontsize
+            else:
+                raise AttributeError(
+                    'No self.fontsize attribute to be used when text(...)\n'
+                    'is called with fontsize=0. Call set_fontsize method.')
+
         x, y = position
         x, y = position
         if arrow_tip is None:
         if arrow_tip is None:
             self.ax.text(x, y, text, horizontalalignment=alignment,
             self.ax.text(x, y, text, horizontalalignment=alignment,

File diff suppressed because it is too large
+ 482 - 210
pysketcher/shapes.py