home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / Inkscape / Inkscape-0.48.2-1-win32.exe / share / extensions / funcplot.py < prev    next >
Text File  |  2011-07-08  |  12KB  |  282 lines

  1. #!/usr/bin/env python 
  2. '''
  3. Copyright (C) 2007 Tavmjong Bah, tavmjong@free.fr
  4. Copyright (C) 2006 Georg Wiora, xorx@quarkbox.de
  5. Copyright (C) 2006 Johan Engelen, johan@shouraizou.nl
  6. Copyright (C) 2005 Aaron Spike, aaron@ekips.org
  7.  
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12.  
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with this program; if not, write to the Free Software
  20. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21.  
  22. Changes:
  23.  * This program is a modified version of wavy.py by Aaron Spike.
  24.  * 22-Dec-2006: Wiora : Added axis and isotropic scaling
  25.  * 21-Jun-2007: Tavmjong: Added polar coordinates
  26.  
  27. '''
  28. import inkex, simplepath, simplestyle
  29. from math import *
  30. from random import *
  31.  
  32. def drawfunction(xstart, xend, ybottom, ytop, samples, width, height, left, bottom, 
  33.     fx = "sin(x)", fpx = "cos(x)", fponum = True, times2pi = False, polar = False, isoscale = True, drawaxis = True):
  34.  
  35.     if times2pi == True:
  36.         xstart = 2 * pi * xstart
  37.         xend   = 2 * pi * xend   
  38.       
  39.     # coords and scales based on the source rect
  40.     scalex = width / (xend - xstart)
  41.     xoff = left
  42.     coordx = lambda x: (x - xstart) * scalex + xoff  #convert x-value to coordinate
  43.     if polar :  # Set scale so that left side of rectangle is -1, right side is +1.
  44.                 # (We can't use xscale for both range and scale.)
  45.         centerx = left + width/2.0
  46.         polar_scalex = width/2.0
  47.         coordx = lambda x: x * polar_scalex + centerx  #convert x-value to coordinate
  48.  
  49.     scaley = height / (ytop - ybottom)
  50.     yoff = bottom
  51.     coordy = lambda y: (ybottom - y) * scaley + yoff  #convert y-value to coordinate
  52.  
  53.     # Check for isotropic scaling and use smaller of the two scales, correct ranges
  54.     if isoscale and not polar:
  55.       if scaley<scalex:
  56.         # compute zero location
  57.         xzero = coordx(0)
  58.         # set scale
  59.         scalex = scaley
  60.         # correct x-offset
  61.         xstart = (left-xzero)/scalex
  62.         xend = (left+width-xzero)/scalex
  63.       else :
  64.         # compute zero location
  65.         yzero = coordy(0)
  66.         # set scale
  67.         scaley = scalex
  68.         # correct x-offset
  69.         ybottom = (yzero-bottom)/scaley
  70.         ytop = (bottom+height-yzero)/scaley
  71.  
  72.     # functions specified by the user
  73.     try:
  74.         if fx != "":
  75.             f = eval('lambda x: ' + fx.strip('"'))
  76.         if fpx != "":
  77.             fp = eval('lambda x: ' + fpx.strip('"'))
  78.     # handle incomplete/invalid function gracefully
  79.     except SyntaxError:
  80.         return []
  81.  
  82.     # step is the distance between nodes on x
  83.     step = (xend - xstart) / (samples-1)
  84.     third = step / 3.0
  85.     ds = step * 0.001 # Step used in calculating derivatives
  86.  
  87.     a = [] # path array 
  88.     # add axis
  89.     if drawaxis :
  90.       # check for visibility of x-axis
  91.       if ybottom<=0 and ytop>=0:
  92.         # xaxis
  93.         a.append(['M ',[left, coordy(0)]])
  94.         a.append([' l ',[width, 0]])
  95.       # check for visibility of y-axis
  96.       if xstart<=0 and xend>=0:
  97.         # xaxis
  98.         a.append([' M ',[coordx(0),bottom]])
  99.         a.append([' l ',[0, -height]])
  100.  
  101.     # initialize function and derivative for 0;
  102.     # they are carried over from one iteration to the next, to avoid extra function calculations. 
  103.     x0 =   xstart
  104.     y0 = f(xstart)
  105.     if polar :
  106.         xp0 = y0 * cos( x0 )
  107.         yp0 = y0 * sin( x0 )
  108.         x0 = xp0
  109.         y0 = yp0
  110.     if fponum or polar: # numerical derivative, using 0.001*step as the small differential
  111.         x1 = xstart + ds # Second point AFTER first point (Good for first point)
  112.         y1 = f(x1)
  113.         if polar :
  114.             xp1 = y1 * cos( x1 )
  115.             yp1 = y1 * sin( x1 )
  116.             x1 = xp1
  117.             y1 = yp1
  118.         dx0 = (x1 - x0)/ds 
  119.         dy0 = (y1 - y0)/ds
  120.     else: # derivative given by the user
  121.         dx0 = 1 # Only works for rectangular coordinates
  122.         dy0 = fp(xstart)
  123.  
  124.     # Start curve
  125.     a.append([' M ',[coordx(x0), coordy(y0)]]) # initial moveto
  126.  
  127.     for i in range(int(samples-1)):
  128.         x1 = (i+1) * step + xstart
  129.         x2 = x1 - ds # Second point BEFORE first point (Good for last point)
  130.         y1 = f(x1)
  131.         y2 = f(x2)
  132.         if polar :
  133.             xp1 = y1 * cos( x1 )
  134.             yp1 = y1 * sin( x1 )
  135.             xp2 = y2 * cos( x2 )
  136.             yp2 = y2 * sin( x2 )
  137.             x1 = xp1
  138.             y1 = yp1
  139.             x2 = xp2
  140.             y2 = yp2
  141.         if fponum or polar: # numerical derivative
  142.             dx1 = (x1 - x2)/ds
  143.             dy1 = (y1 - y2)/ds
  144.         else: # derivative given by the user
  145.             dx1 = 1 # Only works for rectangular coordinates
  146.             dy1 = fp(x1)
  147.         # create curve
  148.         a.append([' C ',
  149.                   [coordx(x0 + (dx0 * third)), coordy(y0 + (dy0 * third)), 
  150.                    coordx(x1 - (dx1 * third)), coordy(y1 - (dy1 * third)),
  151.                    coordx(x1),                 coordy(y1)]
  152.                   ])
  153.         x0  = x1  # Next segment's start is this segments end
  154.         y0  = y1
  155.         dx0 = dx1 # Assume the function is smooth everywhere, so carry over the derivative too
  156.         dy0 = dy1    
  157.     return a
  158.  
  159. class FuncPlot(inkex.Effect):
  160.     def __init__(self):
  161.         inkex.Effect.__init__(self)
  162.         self.OptionParser.add_option("--xstart",
  163.                         action="store", type="float", 
  164.                         dest="xstart", default=0.0,
  165.                         help="Start x-value")
  166.         self.OptionParser.add_option("--xend",
  167.                         action="store", type="float", 
  168.                         dest="xend", default=1.0,
  169.                         help="End x-value")
  170.         self.OptionParser.add_option("--times2pi",
  171.                         action="store", type="inkbool", 
  172.                         dest="times2pi", default=True,
  173.                         help="Multiply x-range by 2*pi")    
  174.         self.OptionParser.add_option("--polar",
  175.                         action="store", type="inkbool", 
  176.                         dest="polar", default=False,
  177.                         help="Plot using polar coordinates")    
  178.         self.OptionParser.add_option("--ybottom",
  179.                         action="store", type="float", 
  180.                         dest="ybottom", default=-1.0,
  181.                         help="y-value of rectangle's bottom")
  182.         self.OptionParser.add_option("--ytop",
  183.                         action="store", type="float", 
  184.                         dest="ytop", default=1.0,
  185.                         help="y-value of rectangle's top")
  186.         self.OptionParser.add_option("-s", "--samples",
  187.                         action="store", type="int", 
  188.                         dest="samples", default=8,
  189.                         help="Samples")    
  190.         self.OptionParser.add_option("--fofx",
  191.                         action="store", type="string", 
  192.                         dest="fofx", default="sin(x)",
  193.                         help="f(x) for plotting")    
  194.         self.OptionParser.add_option("--fponum",
  195.                         action="store", type="inkbool", 
  196.                         dest="fponum", default=True,
  197.                         help="Calculate the first derivative numerically")    
  198.         self.OptionParser.add_option("--fpofx",
  199.                         action="store", type="string", 
  200.                         dest="fpofx", default="cos(x)",
  201.                         help="f'(x) for plotting") 
  202.         self.OptionParser.add_option("--remove",
  203.                         action="store", type="inkbool", 
  204.                         dest="remove", default=True,
  205.                         help="If True, source rectangle is removed") 
  206.         self.OptionParser.add_option("--isoscale",
  207.                         action="store", type="inkbool", 
  208.                         dest="isoscale", default=True,
  209.                         help="If True, isotropic scaling is used") 
  210.         self.OptionParser.add_option("--drawaxis",
  211.                         action="store", type="inkbool", 
  212.                         dest="drawaxis", default=True,
  213.                         help="If True, axis are drawn") 
  214.         self.OptionParser.add_option("--tab",
  215.                         action="store", type="string", 
  216.                         dest="tab", default="sampling",
  217.                         help="The selected UI-tab when OK was pressed") 
  218.         self.OptionParser.add_option("--funcplotuse",
  219.                         action="store", type="string", 
  220.                         dest="funcplotuse", default="",
  221.                         help="dummy") 
  222.         self.OptionParser.add_option("--pythonfunctions",
  223.                         action="store", type="string", 
  224.                         dest="pythonfunctions", default="",
  225.                         help="dummy") 
  226.  
  227.     def effect(self):
  228.         for id, node in self.selected.iteritems():
  229.             if node.tag == inkex.addNS('rect','svg'):
  230.                 # create new path with basic dimensions of selected rectangle
  231.                 newpath = inkex.etree.Element(inkex.addNS('path','svg'))
  232.                 x = float(node.get('x'))
  233.                 y = float(node.get('y'))
  234.                 w = float(node.get('width'))
  235.                 h = float(node.get('height'))
  236.  
  237.                 #copy attributes of rect
  238.                 s = node.get('style')
  239.                 if s:
  240.                     newpath.set('style', s)
  241.                 
  242.                 t = node.get('transform')
  243.                 if t:
  244.                     newpath.set('transform', t)
  245.                     
  246.                 # top and bottom were exchanged
  247.                 newpath.set('d', simplepath.formatPath(
  248.                             drawfunction(self.options.xstart,
  249.                                 self.options.xend,
  250.                                 self.options.ybottom,
  251.                                 self.options.ytop,
  252.                                 self.options.samples, 
  253.                                 w,h,x,y+h,
  254.                                 self.options.fofx, 
  255.                                 self.options.fpofx,
  256.                                 self.options.fponum,
  257.                                 self.options.times2pi,
  258.                                 self.options.polar,
  259.                                 self.options.isoscale,
  260.                                 self.options.drawaxis)))
  261.                 newpath.set('title', self.options.fofx)
  262.                 
  263.                 #newpath.setAttribute('desc', '!func;' + self.options.fofx + ';' 
  264.                 #                                      + self.options.fpofx + ';'
  265.                 #                                      + `self.options.fponum` + ';'
  266.                 #                                      + `self.options.xstart` + ';'
  267.                 #                                      + `self.options.xend` + ';'
  268.                 #                                      + `self.options.samples`)
  269.                                 
  270.                 # add path into SVG structure
  271.                 node.getparent().append(newpath)
  272.                 # option wether to remove the rectangle or not.
  273.                 if self.options.remove:
  274.                     node.getparent().remove(node)
  275.                 
  276. if __name__ == '__main__':
  277.     e = FuncPlot()
  278.     e.affect()
  279.  
  280.  
  281. # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
  282.