summaryrefslogtreecommitdiffstats
path: root/share/extensions/grid_polar.py
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions/grid_polar.py')
-rwxr-xr-xshare/extensions/grid_polar.py270
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()