~ubuntu-branches/ubuntu/utopic/inkscape/utopic-proposed

« back to all changes in this revision

Viewing changes to share/extensions/generate_voronoi.py

  • Committer: Bazaar Package Importer
  • Author(s): Alex Valavanis
  • Date: 2010-09-12 19:44:58 UTC
  • mfrom: (1.1.12 upstream) (45.1.3 maverick)
  • Revision ID: james.westby@ubuntu.com-20100912194458-4sjwmbl7dlsrk5dc
Tags: 0.48.0-1ubuntu1
* Merge with Debian unstable (LP: #628048, LP: #401567, LP: #456248, 
  LP: #463602, LP: #591986)
* debian/control: 
  - Ubuntu maintainers
  - Promote python-lxml, python-numpy, python-uniconvertor to Recommends.
  - Demote pstoedit to Suggests (universe package).
  - Suggests ttf-dejavu instead of ttf-bitstream-vera (LP: #513319)
* debian/rules:
  - Run intltool-update on build (Ubuntu-specific).
  - Add translation domain to .desktop files (Ubuntu-specific).
* debian/dirs:
  - Add usr/share/pixmaps.  Allow inkscape.xpm installation
* drop 50-poppler-API.dpatch (now upstream)
* drop 51-paste-in-unwritable-directory.dpatch (now upstream) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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