3
Copyright (C) 2007 John Beard john.j.beard@gmail.com
5
##This extension allows you to draw a Cartesian grid in Inkscape.
6
##There is a wide range of options including subdivision, subsubdivions
7
## and logarithmic scales. Custom line widths are also possible.
8
##All elements are grouped with similar elements (eg all x-subdivs)
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
import simplestyle, sys
29
def draw_SVG_line(x1, y1, x2, y2, width, name, parent):
30
style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' }
31
line_attribs = {'style':simplestyle.formatStyle(style),
32
inkex.addNS('label','inkscape'):name,
33
'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
34
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
36
def draw_SVG_rect(x,y,w,h, width, fill, name, parent):
37
style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill':fill}
38
rect_attribs = {'style':simplestyle.formatStyle(style),
39
inkex.addNS('label','inkscape'):name,
40
'x':str(x), 'y':str(y), 'width':str(w), 'height':str(h)}
41
inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), rect_attribs )
43
class Grid_Polar(inkex.Effect):
45
inkex.Effect.__init__(self)
46
self.OptionParser.add_option("--x_divs",
47
action="store", type="int",
48
dest="x_divs", default=5,
49
help="Major X Divisions")
50
self.OptionParser.add_option("--dx",
51
action="store", type="float",
52
dest="dx", default=100.0,
53
help="Major X divison Spacing")
54
self.OptionParser.add_option("--x_subdivs",
55
action="store", type="int",
56
dest="x_subdivs", default=2,
57
help="Subdivisions per Major X division")
58
self.OptionParser.add_option("--x_log",
59
action="store", type="inkbool",
60
dest="x_log", default=False,
61
help="Logarithmic x subdivisions if true")
62
self.OptionParser.add_option("--x_subsubdivs",
63
action="store", type="int",
64
dest="x_subsubdivs", default=5,
65
help="Subsubdivisions per Minor X division")
66
self.OptionParser.add_option("--x_half_freq",
67
action="store", type="int",
68
dest="x_half_freq", default=4,
69
help="Halve Subsubdiv. Frequency after 'n' Subdivs. (log only)")
70
self.OptionParser.add_option("--x_divs_th",
71
action="store", type="float",
72
dest="x_divs_th", default=2,
73
help="Major X Division Line thickness")
74
self.OptionParser.add_option("--x_subdivs_th",
75
action="store", type="float",
76
dest="x_subdivs_th", default=1,
77
help="Minor X Division Line thickness")
78
self.OptionParser.add_option("--x_subsubdivs_th",
79
action="store", type="float",
80
dest="x_subsubdivs_th", default=1,
81
help="Subminor X Division Line thickness")
82
self.OptionParser.add_option("--y_divs",
83
action="store", type="int",
84
dest="y_divs", default=6,
85
help="Major Y Divisions")
86
self.OptionParser.add_option("--dy",
87
action="store", type="float",
88
dest="dy", default=100.0,
89
help="Major Gridline Increment")
90
self.OptionParser.add_option("--y_subdivs",
91
action="store", type="int",
92
dest="y_subdivs", default=2,
93
help="Minor Divisions per Major Y division")
94
self.OptionParser.add_option("--y_log",
95
action="store", type="inkbool",
96
dest="y_log", default=False,
97
help="Logarithmic y subdivisions if true")
98
self.OptionParser.add_option("--y_subsubdivs",
99
action="store", type="int",
100
dest="y_subsubdivs", default=5,
101
help="Subsubdivisions per Minor Y division")
102
self.OptionParser.add_option("--y_half_freq",
103
action="store", type="int",
104
dest="y_half_freq", default=4,
105
help="Halve Y Subsubdiv. Frequency after 'n' Subdivs. (log only)")
106
self.OptionParser.add_option("--y_divs_th",
107
action="store", type="float",
108
dest="y_divs_th", default=2,
109
help="Major Y Division Line thickness")
110
self.OptionParser.add_option("--y_subdivs_th",
111
action="store", type="float",
112
dest="y_subdivs_th", default=1,
113
help="Minor Y Division Line thickness")
114
self.OptionParser.add_option("--y_subsubdivs_th",
115
action="store", type="float",
116
dest="y_subsubdivs_th", default=1,
117
help="Subminor Y Division Line thickness")
118
self.OptionParser.add_option("--border_th",
119
action="store", type="float",
120
dest="border_th", default=3,
121
help="Border Line thickness")
126
#find the pixel dimensions of the overall grid
127
ymax = self.options.dy * self.options.y_divs
128
xmax = self.options.dx * self.options.x_divs
130
# Embed grid in group
131
#Put in in the centre of the current view
132
t = 'translate(' + str( self.view_center[0]- xmax/2.0) + ',' + \
133
str( self.view_center[1]- ymax/2.0) + ')'
134
g_attribs = {inkex.addNS('label','inkscape'):'Grid_Polar:X' + \
135
str( self.options.x_divs )+':Y'+str( self.options.y_divs ),
137
grid = inkex.etree.SubElement(self.current_layer, 'g', g_attribs)
139
#Group for major x gridlines
140
g_attribs = {inkex.addNS('label','inkscape'):'MajorXGridlines'}
141
majglx = inkex.etree.SubElement(grid, 'g', g_attribs)
143
#Group for major y gridlines
144
g_attribs = {inkex.addNS('label','inkscape'):'MajorYGridlines'}
145
majgly = inkex.etree.SubElement(grid, 'g', g_attribs)
147
#Group for minor x gridlines
148
if self.options.x_subdivs > 1:#if there are any minor x gridlines
149
g_attribs = {inkex.addNS('label','inkscape'):'MinorXGridlines'}
150
minglx = inkex.etree.SubElement(grid, 'g', g_attribs)
152
#Group for subminor x gridlines
153
if self.options.x_subsubdivs > 1:#if there are any minor minor x gridlines
154
g_attribs = {inkex.addNS('label','inkscape'):'SubMinorXGridlines'}
155
mminglx = inkex.etree.SubElement(grid, 'g', g_attribs)
157
#Group for minor y gridlines
158
if self.options.y_subdivs > 1:#if there are any minor y gridlines
159
g_attribs = {inkex.addNS('label','inkscape'):'MinorYGridlines'}
160
mingly = inkex.etree.SubElement(grid, 'g', g_attribs)
162
#Group for subminor y gridlines
163
if self.options.y_subsubdivs > 1:#if there are any minor minor x gridlines
164
g_attribs = {inkex.addNS('label','inkscape'):'SubMinorYGridlines'}
165
mmingly = inkex.etree.SubElement(grid, 'g', g_attribs)
168
draw_SVG_rect(0, 0, xmax, ymax, self.options.border_th,
169
'none', 'Border', grid) #border rectangle
171
#DO THE X DIVISONS======================================
172
sd = self.options.x_subdivs #sub divs per div
173
ssd = self.options.x_subsubdivs #subsubdivs per subdiv
175
for i in range(0, self.options.x_divs): #Major x divisons
176
if i>0: #dont draw first line (we made a proper border)
177
draw_SVG_line(self.options.dx*i, 0,
178
self.options.dx*i,ymax,
179
self.options.x_divs_th,
180
'MajorXDiv'+str(i), majglx)
182
if self.options.x_log: #log x subdivs
183
for j in range (1, sd):
184
if j>1: #the first loop is only for subsubdivs
185
draw_SVG_line(self.options.dx*(i+log(j, sd)), 0,
186
self.options.dx*(i+log(j, sd)), ymax,
187
self.options.x_subdivs_th,
188
'MinorXDiv'+str(i)+':'+str(j), minglx)
190
for k in range (1, ssd): #subsub divs
191
if (j <= self.options.x_half_freq) or (k%2 == 0):#only draw half the subsubdivs past the half-freq point
192
if (ssd%2 > 0) and (j > self.options.y_half_freq): #half frequency won't work with odd numbers of subsubdivs,
193
ssd2 = ssd+1 #make even
195
ssd2 = ssd #no change
196
draw_SVG_line(self.options.dx*(i+log(j+k/float(ssd2),sd )), 0,
197
self.options.dx*(i+log(j+k/float(ssd2),sd )), ymax,
198
self.options.x_subsubdivs_th,'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mminglx)
200
else: #linear x subdivs
201
for j in range (0, sd):
202
if j>0: #not for the first loop (this loop is for the subsubdivs before the first subdiv)
203
draw_SVG_line(self.options.dx*(i+j/float(sd)), 0,
204
self.options.dx*(i+j/float(sd)), ymax,
205
self.options.x_subdivs_th,
206
'MinorXDiv'+str(i)+':'+str(j), minglx)
208
for k in range (1, ssd): #subsub divs
209
draw_SVG_line(self.options.dx*(i+(j*ssd+k)/((float(sd)*ssd))) , 0,
210
self.options.dx*(i+(j*ssd+k)/((float(sd)*ssd))) , ymax,
211
self.options.x_subsubdivs_th,
212
'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mminglx)
214
#DO THE Y DIVISONS========================================
215
sd = self.options.y_subdivs #sub divs per div
216
ssd = self.options.y_subsubdivs #subsubdivs per subdiv
218
for i in range(0, self.options.y_divs): #Major y divisons
219
if i>0:#dont draw first line (we will make a border)
220
draw_SVG_line(0, self.options.dy*i,
221
xmax, self.options.dy*i,
222
self.options.y_divs_th,
223
'MajorYDiv'+str(i), majgly)
225
if self.options.y_log: #log y subdivs
226
for j in range (1, sd):
227
if j>1: #the first loop is only for subsubdivs
228
draw_SVG_line(0, self.options.dy*(i+1-log(j,sd)),
229
xmax, self.options.dy*(i+1-log(j,sd)),
230
self.options.y_subdivs_th,
231
'MinorXDiv'+str(i)+':'+str(j), mingly)
233
for k in range (1, ssd): #subsub divs
234
if (j <= self.options.y_half_freq) or (k%2 == 0):#only draw half the subsubdivs past the half-freq point
235
if (ssd%2 > 0) and (j > self.options.y_half_freq): #half frequency won't work with odd numbers of subsubdivs,
238
ssd2 = ssd #no change
239
draw_SVG_line(0, self.options.dx*(i+1-log(j+k/float(ssd2),sd )),
240
xmax, self.options.dx*(i+1-log(j+k/float(ssd2),sd )),
241
self.options.y_subsubdivs_th,
242
'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mmingly)
243
else: #linear y subdivs
244
for j in range (0, self.options.y_subdivs):
245
if j>0:#not for the first loop (this loop is for the subsubdivs before the first subdiv)
246
draw_SVG_line(0, self.options.dy*(i+j/float(sd)),
247
xmax, self.options.dy*(i+j/float(sd)),
248
self.options.y_subdivs_th,
249
'MinorXYiv'+str(i)+':'+str(j), mingly)
251
for k in range (1, ssd): #subsub divs
252
draw_SVG_line(0, self.options.dy*(i+(j*ssd+k)/((float(sd)*ssd))),
253
xmax, self.options.dy*(i+(j*ssd+k)/((float(sd)*ssd))),
254
self.options.y_subsubdivs_th,
255
'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mmingly)
259
if __name__ == '__main__':
264
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99