diff options
Diffstat (limited to 'share/extensions/grid_polar.py')
-rwxr-xr-x | share/extensions/grid_polar.py | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/share/extensions/grid_polar.py b/share/extensions/grid_polar.py new file mode 100755 index 0000000..ceefb3d --- /dev/null +++ b/share/extensions/grid_polar.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python +# coding=utf-8 +# +# Copyright (C) 2007 John Beard john.j.beard@gmail.com +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +""" +This extension allows you to draw a polar grid in Inkscape. +There is a wide range of options including subdivision and labels. +""" + +from math import cos, log, pi, sin + +import inkex +from inkex import Group, Circle, TextElement + + +def draw_circle(r, cx, cy, width, fill, name, parent): + """Draw an SVG circle""" + circle = parent.add(Circle(cx=str(cx), cy=str(cy), r=str(r))) + circle.style = {"stroke": "#000000", "stroke-width": str(width), "fill": fill} + circle.label = name + + +def draw_line(x1, y1, x2, y2, width, name, parent): + """Draw an SVG line""" + line = parent.add(inkex.PathElement()) + line.style = {"stroke": "#000000", "stroke-width": str(width), "fill": "none"} + line.path = "M {},{} L {},{}".format(x1, y1, x2, y2) + line.label = name + + +def draw_label(x, y, string, font_size, name, parent): + """Draw a centered label""" + label = parent.add(TextElement(x=str(x), y=str(y))) + label.style = { + "text-align": "center", + "vertical-align": "top", + "text-anchor": "middle", + "font-size": str(font_size) + "px", + "fill-opacity": "1.0", + "stroke": "none", + "font-weight": "normal", + "font-style": "normal", + "fill": "#000000", + } + label.text = string + label.label = name + + +class GridPolar(inkex.GenerateExtension): + def add_arguments(self, pars): + pars.add_argument("--tab") + pars.add_argument("--r_divs", type=int, default=5, help="Circular Divisions") + pars.add_argument( + "--dr", type=float, default=50, help="Circular Division Spacing" + ) + pars.add_argument( + "--r_subdivs", type=int, default=3, help="Subdivisions per Major div" + ) + pars.add_argument( + "--r_log", type=inkex.Boolean, default=False, help="Logarithmic subdiv" + ) + pars.add_argument( + "--r_divs_th", type=float, default=2, help="Major Line thickness" + ) + pars.add_argument( + "--r_subdivs_th", type=float, default=1, help="Minor Line thickness" + ) + pars.add_argument("--a_divs", type=int, default=24, help="Angle Divisions") + pars.add_argument( + "--a_divs_cent", type=int, default=4, help="Angle Divisions at Centre" + ) + pars.add_argument( + "--a_subdivs", type=int, default=1, help="Angcular Subdivisions" + ) + pars.add_argument( + "--a_subdivs_cent", type=int, default=2, help="Angular Subdivisions end" + ) + pars.add_argument( + "--a_divs_th", type=float, default=2, help="Major Angular thickness" + ) + pars.add_argument( + "--a_subdivs_th", type=float, default=1, help="Minor Angular thickness" + ) + pars.add_argument( + "--c_dot_dia", type=float, default=5.0, help="Diameter of Centre Dot" + ) + pars.add_argument( + "--a_labels", default="none", help="The kind of labels to apply" + ) + pars.add_argument( + "--a_label_size", type=int, default=18, help="Pixel size of the labels" + ) + pars.add_argument( + "--a_label_outset", type=float, default=24, help="Label Radial outset" + ) + + def generate(self): + self.options.dr = self.svg.unittouu(str(self.options.dr) + "px") + self.options.r_divs_th = self.svg.unittouu(str(self.options.r_divs_th) + "px") + self.options.r_subdivs_th = self.svg.unittouu( + str(self.options.r_subdivs_th) + "px" + ) + self.options.a_divs_th = self.svg.unittouu(str(self.options.a_divs_th) + "px") + self.options.a_subdivs_th = self.svg.unittouu( + str(self.options.a_subdivs_th) + "px" + ) + self.options.c_dot_dia = self.svg.unittouu(str(self.options.c_dot_dia) + "px") + self.options.a_label_size = self.svg.unittouu( + str(self.options.a_label_size) + "px" + ) + self.options.a_label_outset = self.svg.unittouu( + str(self.options.a_label_outset) + "px" + ) + + # Embed grid in group + grid = Group.new("GridPolar:R{0.r_divs}:A{0.a_divs}".format(self.options)) + + (pos_x, pos_y) = self.svg.namedview.center + grid.transform.add_translate(pos_x, pos_y) + + dr = self.options.dr # Distance between neighbouring circles + dtheta = ( + 2 * pi / self.options.a_divs_cent + ) # Angular change between adjacent radial lines at centre + rmax = self.options.r_divs * dr + + # Create SVG circles + for i in range(1, self.options.r_divs + 1): + draw_circle( + i * dr, + 0, + 0, # major div circles + self.options.r_divs_th, + "none", + "MajorDivCircle" + str(i) + ":R" + str(i * dr), + grid, + ) + + if self.options.r_log: # logarithmic subdivisions + for j in range(2, self.options.r_subdivs): + draw_circle( + i * dr + - (1 - log(j, self.options.r_subdivs)) + * dr, # minor div circles + 0, + 0, + self.options.r_subdivs_th, + "none", + "MinorDivCircle" + str(i) + ":Log" + str(j), + grid, + ) + else: # linear subdivs + for j in range(1, self.options.r_subdivs): + draw_circle( + i * dr - j * dr / self.options.r_subdivs, # minor div circles + 0, + 0, + self.options.r_subdivs_th, + "none", + "MinorDivCircle" + str(i) + ":R" + str(i * dr), + grid, + ) + + if ( + self.options.a_divs == self.options.a_divs_cent + ): # the lines can go from the centre to the edge + for i in range(0, self.options.a_divs): + draw_line( + 0, + 0, + rmax * sin(i * dtheta), + rmax * cos(i * dtheta), + self.options.a_divs_th, + "RadialGridline" + str(i), + grid, + ) + + else: # we need separate lines + for i in range( + 0, self.options.a_divs_cent + ): # lines that go to the first circle + draw_line( + 0, + 0, + dr * sin(i * dtheta), + dr * cos(i * dtheta), + self.options.a_divs_th, + "RadialGridline" + str(i), + grid, + ) + + dtheta = ( + 2 * pi / self.options.a_divs + ) # work out the angle change for outer lines + + for i in range( + 0, self.options.a_divs + ): # lines that go from there to the edge + draw_line( + dr * sin(i * dtheta + pi / 2.0), + dr * cos(i * dtheta + pi / 2.0), + rmax * sin(i * dtheta + pi / 2.0), + rmax * cos(i * dtheta + pi / 2.0), + self.options.a_divs_th, + "RadialGridline" + str(i), + grid, + ) + + if self.options.a_subdivs > 1: # draw angular subdivs + for i in range(0, self.options.a_divs): # for each major division + for j in range(1, self.options.a_subdivs): # draw the subdivisions + angle = ( + i * dtheta - j * dtheta / self.options.a_subdivs + pi / 2.0 + ) # the angle of the subdivion line + draw_line( + dr * self.options.a_subdivs_cent * sin(angle), + dr * self.options.a_subdivs_cent * cos(angle), + rmax * sin(angle), + rmax * cos(angle), + self.options.a_subdivs_th, + "RadialMinorGridline" + str(i), + grid, + ) + + if self.options.c_dot_dia != 0: # if a non-zero diameter, draw the centre dot + draw_circle( + self.options.c_dot_dia / 2.0, 0, 0, 0, "#000000", "CentreDot", grid + ) + + if self.options.a_labels == "deg": + label_radius = rmax + self.options.a_label_outset # radius of label centres + label_size = self.options.a_label_size + numeral_size = ( + 0.73 * label_size + ) # numerals appear to be 0.73 the height of the nominal pixel size of the font in "Sans" + + for i in range( + 0, self.options.a_divs + ): # self.options.a_divs): #radial line labels + draw_label( + sin(i * dtheta + pi / 2.0) + * label_radius, # 0 at the RHS, mathematical style + cos(i * dtheta + pi / 2.0) * label_radius + + numeral_size / 2.0, # centre the text vertically + str(i * 360 / self.options.a_divs), + label_size, + "Label" + str(i), + grid, + ) + + return grid + + +if __name__ == "__main__": + GridPolar().run() |