#!/usr/bin/env python ''' Copyright (C) 2007 John Beard john.j.beard@gmail.com ##This extension allows you to draw a Cartesian grid in Inkscape. ##There is a wide range of options including subdivision, subsubdivions ## and logarithmic scales. Custom line widths are also possible. ##All elements are grouped with similar elements (eg all x-subdivs) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' import inkex import simplestyle, sys from math import * def draw_SVG_line(x1, y1, x2, y2, width, name, parent): style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' } line_attribs = {'style':simplestyle.formatStyle(style), inkex.addNS('label','inkscape'):name, 'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)} inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) def draw_SVG_rect(x,y,w,h, width, fill, name, parent): style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill':fill} rect_attribs = {'style':simplestyle.formatStyle(style), inkex.addNS('label','inkscape'):name, 'x':str(x), 'y':str(y), 'width':str(w), 'height':str(h)} inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), rect_attribs ) class Grid_Polar(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.OptionParser.add_option("--x_divs", action="store", type="int", dest="x_divs", default=5, help="Major X Divisions") self.OptionParser.add_option("--dx", action="store", type="float", dest="dx", default=100.0, help="Major X divison Spacing") self.OptionParser.add_option("--x_subdivs", action="store", type="int", dest="x_subdivs", default=2, help="Subdivisions per Major X division") self.OptionParser.add_option("--x_log", action="store", type="inkbool", dest="x_log", default=False, help="Logarithmic x subdivisions if true") self.OptionParser.add_option("--x_subsubdivs", action="store", type="int", dest="x_subsubdivs", default=5, help="Subsubdivisions per Minor X division") self.OptionParser.add_option("--x_half_freq", action="store", type="int", dest="x_half_freq", default=4, help="Halve Subsubdiv. Frequency after 'n' Subdivs. (log only)") self.OptionParser.add_option("--x_divs_th", action="store", type="float", dest="x_divs_th", default=2, help="Major X Division Line thickness") self.OptionParser.add_option("--x_subdivs_th", action="store", type="float", dest="x_subdivs_th", default=1, help="Minor X Division Line thickness") self.OptionParser.add_option("--x_subsubdivs_th", action="store", type="float", dest="x_subsubdivs_th", default=1, help="Subminor X Division Line thickness") self.OptionParser.add_option("--y_divs", action="store", type="int", dest="y_divs", default=6, help="Major Y Divisions") self.OptionParser.add_option("--dy", action="store", type="float", dest="dy", default=100.0, help="Major Gridline Increment") self.OptionParser.add_option("--y_subdivs", action="store", type="int", dest="y_subdivs", default=2, help="Minor Divisions per Major Y division") self.OptionParser.add_option("--y_log", action="store", type="inkbool", dest="y_log", default=False, help="Logarithmic y subdivisions if true") self.OptionParser.add_option("--y_subsubdivs", action="store", type="int", dest="y_subsubdivs", default=5, help="Subsubdivisions per Minor Y division") self.OptionParser.add_option("--y_half_freq", action="store", type="int", dest="y_half_freq", default=4, help="Halve Y Subsubdiv. Frequency after 'n' Subdivs. (log only)") self.OptionParser.add_option("--y_divs_th", action="store", type="float", dest="y_divs_th", default=2, help="Major Y Division Line thickness") self.OptionParser.add_option("--y_subdivs_th", action="store", type="float", dest="y_subdivs_th", default=1, help="Minor Y Division Line thickness") self.OptionParser.add_option("--y_subsubdivs_th", action="store", type="float", dest="y_subsubdivs_th", default=1, help="Subminor Y Division Line thickness") self.OptionParser.add_option("--border_th", action="store", type="float", dest="border_th", default=3, help="Border Line thickness") def effect(self): self.options.border_th = self.unittouu(str(self.options.border_th) + 'px') self.options.dx = self.unittouu(str(self.options.dx) + 'px') self.options.x_divs_th = self.unittouu(str(self.options.x_divs_th) + 'px') self.options.x_subdivs_th = self.unittouu(str(self.options.x_subdivs_th) + 'px') self.options.x_subsubdivs_th = self.unittouu(str(self.options.x_subsubdivs_th) + 'px') self.options.dy = self.unittouu(str(self.options.dy) + 'px') self.options.y_divs_th = self.unittouu(str(self.options.y_divs_th) + 'px') self.options.y_subdivs_th = self.unittouu(str(self.options.y_subdivs_th) + 'px') self.options.y_subsubdivs_th = self.unittouu(str(self.options.y_subsubdivs_th) + 'px') #find the pixel dimensions of the overall grid ymax = self.options.dy * self.options.y_divs xmax = self.options.dx * self.options.x_divs # Embed grid in group #Put in in the centre of the current view t = 'translate(' + str( self.view_center[0]- xmax/2.0) + ',' + \ str( self.view_center[1]- ymax/2.0) + ')' g_attribs = {inkex.addNS('label','inkscape'):'Grid_Polar:X' + \ str( self.options.x_divs )+':Y'+str( self.options.y_divs ), 'transform':t } grid = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) #Group for major x gridlines g_attribs = {inkex.addNS('label','inkscape'):'MajorXGridlines'} majglx = inkex.etree.SubElement(grid, 'g', g_attribs) #Group for major y gridlines g_attribs = {inkex.addNS('label','inkscape'):'MajorYGridlines'} majgly = inkex.etree.SubElement(grid, 'g', g_attribs) #Group for minor x gridlines if self.options.x_subdivs > 1:#if there are any minor x gridlines g_attribs = {inkex.addNS('label','inkscape'):'MinorXGridlines'} minglx = inkex.etree.SubElement(grid, 'g', g_attribs) #Group for subminor x gridlines if self.options.x_subsubdivs > 1:#if there are any minor minor x gridlines g_attribs = {inkex.addNS('label','inkscape'):'SubMinorXGridlines'} mminglx = inkex.etree.SubElement(grid, 'g', g_attribs) #Group for minor y gridlines if self.options.y_subdivs > 1:#if there are any minor y gridlines g_attribs = {inkex.addNS('label','inkscape'):'MinorYGridlines'} mingly = inkex.etree.SubElement(grid, 'g', g_attribs) #Group for subminor y gridlines if self.options.y_subsubdivs > 1:#if there are any minor minor x gridlines g_attribs = {inkex.addNS('label','inkscape'):'SubMinorYGridlines'} mmingly = inkex.etree.SubElement(grid, 'g', g_attribs) draw_SVG_rect(0, 0, xmax, ymax, self.options.border_th, 'none', 'Border', grid) #border rectangle #DO THE X DIVISONS====================================== sd = self.options.x_subdivs #sub divs per div ssd = self.options.x_subsubdivs #subsubdivs per subdiv for i in range(0, self.options.x_divs): #Major x divisons if i>0: #dont draw first line (we made a proper border) draw_SVG_line(self.options.dx*i, 0, self.options.dx*i,ymax, self.options.x_divs_th, 'MajorXDiv'+str(i), majglx) if self.options.x_log: #log x subdivs for j in range (1, sd): if j>1: #the first loop is only for subsubdivs draw_SVG_line(self.options.dx*(i+log(j, sd)), 0, self.options.dx*(i+log(j, sd)), ymax, self.options.x_subdivs_th, 'MinorXDiv'+str(i)+':'+str(j), minglx) for k in range (1, ssd): #subsub divs if (j <= self.options.x_half_freq) or (k%2 == 0):#only draw half the subsubdivs past the half-freq point if (ssd%2 > 0) and (j > self.options.y_half_freq): #half frequency won't work with odd numbers of subsubdivs, ssd2 = ssd+1 #make even else: ssd2 = ssd #no change draw_SVG_line(self.options.dx*(i+log(j+k/float(ssd2),sd )), 0, self.options.dx*(i+log(j+k/float(ssd2),sd )), ymax, self.options.x_subsubdivs_th,'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mminglx) else: #linear x subdivs for j in range (0, sd): if j>0: #not for the first loop (this loop is for the subsubdivs before the first subdiv) draw_SVG_line(self.options.dx*(i+j/float(sd)), 0, self.options.dx*(i+j/float(sd)), ymax, self.options.x_subdivs_th, 'MinorXDiv'+str(i)+':'+str(j), minglx) for k in range (1, ssd): #subsub divs draw_SVG_line(self.options.dx*(i+(j*ssd+k)/((float(sd)*ssd))) , 0, self.options.dx*(i+(j*ssd+k)/((float(sd)*ssd))) , ymax, self.options.x_subsubdivs_th, 'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mminglx) #DO THE Y DIVISONS======================================== sd = self.options.y_subdivs #sub divs per div ssd = self.options.y_subsubdivs #subsubdivs per subdiv for i in range(0, self.options.y_divs): #Major y divisons if i>0:#dont draw first line (we will make a border) draw_SVG_line(0, self.options.dy*i, xmax, self.options.dy*i, self.options.y_divs_th, 'MajorYDiv'+str(i), majgly) if self.options.y_log: #log y subdivs for j in range (1, sd): if j>1: #the first loop is only for subsubdivs draw_SVG_line(0, self.options.dy*(i+1-log(j,sd)), xmax, self.options.dy*(i+1-log(j,sd)), self.options.y_subdivs_th, 'MinorXDiv'+str(i)+':'+str(j), mingly) for k in range (1, ssd): #subsub divs if (j <= self.options.y_half_freq) or (k%2 == 0):#only draw half the subsubdivs past the half-freq point if (ssd%2 > 0) and (j > self.options.y_half_freq): #half frequency won't work with odd numbers of subsubdivs, ssd2 = ssd+1 else: ssd2 = ssd #no change draw_SVG_line(0, self.options.dx*(i+1-log(j+k/float(ssd2),sd )), xmax, self.options.dx*(i+1-log(j+k/float(ssd2),sd )), self.options.y_subsubdivs_th, 'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mmingly) else: #linear y subdivs for j in range (0, self.options.y_subdivs): if j>0:#not for the first loop (this loop is for the subsubdivs before the first subdiv) draw_SVG_line(0, self.options.dy*(i+j/float(sd)), xmax, self.options.dy*(i+j/float(sd)), self.options.y_subdivs_th, 'MinorXYiv'+str(i)+':'+str(j), mingly) for k in range (1, ssd): #subsub divs draw_SVG_line(0, self.options.dy*(i+(j*ssd+k)/((float(sd)*ssd))), xmax, self.options.dy*(i+(j*ssd+k)/((float(sd)*ssd))), self.options.y_subsubdivs_th, 'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mmingly) if __name__ == '__main__': e = Grid_Polar() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99