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 / generate_voronoi.py < prev    next >
Text File  |  2011-07-08  |  8KB  |  188 lines

  1. #!/usr/bin/env python
  2. """
  3. Copyright (C) 2010 Alvin Penner, penner@vaxxine.com
  4.  
  5. - Voronoi Diagram algorithm and C code by Steven Fortune, 1987, http://ect.bell-labs.com/who/sjf/
  6. - Python translation to file voronoi.py by Bill Simons, 2005, http://www.oxfish.com/
  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. """
  23. import random, inkex, simplestyle, gettext, voronoi
  24. _ = gettext.gettext
  25.  
  26. try:
  27.     from subprocess import Popen, PIPE
  28. except:
  29.     inkex.errormsg(_("Failed to import the subprocess module. Please report this as a bug at : https://bugs.launchpad.net/inkscape."))
  30.     inkex.errormsg("Python version is : " + str(inkex.sys.version_info))
  31.     exit()
  32.  
  33. def clip_line(x1, y1, x2, y2, w, h):
  34.     if x1 < 0 and x2 < 0:
  35.         return [0, 0, 0, 0]
  36.     if x1 > w and x2 > w:
  37.         return [0, 0, 0, 0]
  38.     if x1 < 0:
  39.         y1 = (y1*x2 - y2*x1)/(x2 - x1)
  40.         x1 = 0
  41.     if x2 < 0:
  42.         y2 = (y1*x2 - y2*x1)/(x2 - x1)
  43.         x2 = 0
  44.     if x1 > w:
  45.         y1 = y1 + (w - x1)*(y2 - y1)/(x2 - x1)
  46.         x1 = w
  47.     if x2 > w:
  48.         y2 = y1 + (w - x1)*(y2 - y1)/(x2 - x1)
  49.         x2 = w
  50.     if y1 < 0 and y2 < 0:
  51.         return [0, 0, 0, 0]
  52.     if y1 > h and y2 > h:
  53.         return [0, 0, 0, 0]
  54.     if x1 == x2 and y1 == y2:
  55.         return [0, 0, 0, 0]
  56.     if y1 < 0:
  57.         x1 = (x1*y2 - x2*y1)/(y2 - y1)
  58.         y1 = 0
  59.     if y2 < 0:
  60.         x2 = (x1*y2 - x2*y1)/(y2 - y1)
  61.         y2 = 0
  62.     if y1 > h:
  63.         x1 = x1 + (h - y1)*(x2 - x1)/(y2 - y1)
  64.         y1 = h
  65.     if y2 > h:
  66.         x2 = x1 + (h - y1)*(x2 - x1)/(y2 - y1)
  67.         y2 = h
  68.     return [x1, y1, x2, y2]
  69.  
  70. class Pattern(inkex.Effect):
  71.     def __init__(self):
  72.         inkex.Effect.__init__(self)
  73.         self.OptionParser.add_option("--size",
  74.                         action="store", type="int", 
  75.                         dest="size", default=10,
  76.                         help="Average size of cell (px)")
  77.         self.OptionParser.add_option("--border",
  78.                         action="store", type="int", 
  79.                         dest="border", default=0,
  80.                         help="Size of Border (px)")
  81.  
  82.     def effect(self):
  83.         if not self.options.ids:
  84.             inkex.errormsg(_("Please select an object"))
  85.             exit()
  86.         q = {'x':0,'y':0,'width':0,'height':0}  # query the bounding box of ids[0]
  87.         for query in q.keys():
  88.             p = Popen('inkscape --query-%s --query-id=%s "%s"' % (query, self.options.ids[0], self.args[-1]), shell=True, stdout=PIPE, stderr=PIPE)
  89.             rc = p.wait()
  90.             q[query] = float(p.stdout.read())
  91.         defs = self.xpathSingle('/svg:svg//svg:defs')
  92.         pattern = inkex.etree.SubElement(defs ,inkex.addNS('pattern','svg'))
  93.         pattern.set('id', 'Voronoi' + str(random.randint(1, 9999)))
  94.         pattern.set('width', str(q['width']))
  95.         pattern.set('height', str(q['height']))
  96.         pattern.set('patternTransform', 'translate(%s,%s)' % (q['x'], q['y']))
  97.         pattern.set('patternUnits', 'userSpaceOnUse')
  98.  
  99.         # generate random pattern of points
  100.         c = voronoi.Context()
  101.         pts = []
  102.         b = float(self.options.border)          # width of border
  103.         for i in range(int(q['width']*q['height']/self.options.size/self.options.size)):
  104.             x = random.random()*q['width']
  105.             y = random.random()*q['height']
  106.             if b > 0:                           # duplicate border area
  107.                 pts.append(voronoi.Site(x, y))
  108.                 if x < b:
  109.                     pts.append(voronoi.Site(x + q['width'], y))
  110.                     if y < b:
  111.                         pts.append(voronoi.Site(x + q['width'], y + q['height']))
  112.                     if y > q['height'] - b:
  113.                         pts.append(voronoi.Site(x + q['width'], y - q['height']))
  114.                 if x > q['width'] - b:
  115.                     pts.append(voronoi.Site(x - q['width'], y))
  116.                     if y < b:
  117.                         pts.append(voronoi.Site(x - q['width'], y + q['height']))
  118.                     if y > q['height'] - b:
  119.                         pts.append(voronoi.Site(x - q['width'], y - q['height']))
  120.                 if y < b:
  121.                     pts.append(voronoi.Site(x, y + q['height']))
  122.                 if y > q['height'] - b:
  123.                     pts.append(voronoi.Site(x, y - q['height']))
  124.             elif x > -b and y > -b and x < q['width'] + b and y < q['height'] + b:
  125.                 pts.append(voronoi.Site(x, y))  # leave border area blank
  126.             # dot = inkex.etree.SubElement(pattern, inkex.addNS('rect','svg'))
  127.             # dot.set('x', str(x-1))
  128.             # dot.set('y', str(y-1))
  129.             # dot.set('width', '2')
  130.             # dot.set('height', '2')
  131.         if len(pts) < 3:
  132.             inkex.errormsg("Please choose a larger object, or smaller cell size")
  133.             exit()
  134.  
  135.         # plot Voronoi diagram
  136.         sl = voronoi.SiteList(pts)
  137.         voronoi.voronoi(sl, c)
  138.         for edge in c.edges:
  139.             if edge[1] >= 0 and edge[2] >= 0:       # two vertices
  140.                 [x1, y1, x2, y2] = clip_line(c.vertices[edge[1]][0], c.vertices[edge[1]][1], c.vertices[edge[2]][0], c.vertices[edge[2]][1], q['width'], q['height'])
  141.             elif edge[1] >= 0:                      # only one vertex
  142.                 if c.lines[edge[0]][1] == 0:        # vertical line
  143.                     xtemp = c.lines[edge[0]][2]/c.lines[edge[0]][0]
  144.                     if c.vertices[edge[1]][1] > q['height']/2:
  145.                         ytemp = q['height']
  146.                     else:
  147.                         ytemp = 0
  148.                 else:
  149.                     xtemp = q['width']
  150.                     ytemp = (c.lines[edge[0]][2] - q['width']*c.lines[edge[0]][0])/c.lines[edge[0]][1]
  151.                 [x1, y1, x2, y2] = clip_line(c.vertices[edge[1]][0], c.vertices[edge[1]][1], xtemp, ytemp, q['width'], q['height'])
  152.             elif edge[2] >= 0:                      # only one vertex
  153.                 if c.lines[edge[0]][1] == 0:        # vertical line
  154.                     xtemp = c.lines[edge[0]][2]/c.lines[edge[0]][0]
  155.                     if c.vertices[edge[2]][1] > q['height']/2:
  156.                         ytemp = q['height']
  157.                     else:
  158.                         ytemp = 0
  159.                 else:
  160.                     xtemp = 0
  161.                     ytemp = c.lines[edge[0]][2]/c.lines[edge[0]][1]
  162.                 [x1, y1, x2, y2] = clip_line(xtemp, ytemp, c.vertices[edge[2]][0], c.vertices[edge[2]][1], q['width'], q['height'])
  163.             if x1 or x2 or y1 or y2:
  164.                 path = 'M %f,%f %f,%f' % (x1, y1, x2, y2)
  165.                 attribs = {'d': path, 'style': 'stroke:#000000'}
  166.                 inkex.etree.SubElement(pattern, inkex.addNS('path', 'svg'), attribs)
  167.  
  168.         # link selected object to pattern
  169.         obj = self.selected[self.options.ids[0]]
  170.         style = {}
  171.         if obj.attrib.has_key('style'):
  172.             style = simplestyle.parseStyle(obj.attrib['style'])
  173.         style['fill'] = 'url(#%s)' % pattern.get('id')
  174.         obj.attrib['style'] = simplestyle.formatStyle(style)
  175.         if obj.tag == inkex.addNS('g', 'svg'):
  176.             for node in obj:
  177.                 style = {}
  178.                 if node.attrib.has_key('style'):
  179.                     style = simplestyle.parseStyle(node.attrib['style'])
  180.                 style['fill'] = 'url(#%s)' % pattern.get('id')
  181.                 node.attrib['style'] = simplestyle.formatStyle(style)
  182.  
  183. if __name__ == '__main__':
  184.     e = Pattern()
  185.     e.affect()
  186.  
  187. # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
  188.