From bdf43f912eb0039785532ddee4eca0f83fa70650 Mon Sep 17 00:00:00 2001 From: leyghisbb Date: Sun, 2 Aug 2020 01:31:16 +0200 Subject: [PATCH] Added Affine Spirals --- extensions/fablabchemnitz_affine_spirals.inx | 26 +++++ extensions/fablabchemnitz_affine_spirals.py | 100 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 extensions/fablabchemnitz_affine_spirals.inx create mode 100644 extensions/fablabchemnitz_affine_spirals.py diff --git a/extensions/fablabchemnitz_affine_spirals.inx b/extensions/fablabchemnitz_affine_spirals.inx new file mode 100644 index 00000000..3a8acd28 --- /dev/null +++ b/extensions/fablabchemnitz_affine_spirals.inx @@ -0,0 +1,26 @@ + + + <_name>Affine Spirals + fablabchemnitz.de.affine_torus + + + 3 + 2 + 0.8 + <_param name="help" type="description" xml:space="preserve">------------------------------ + + + + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz_affine_spirals.py b/extensions/fablabchemnitz_affine_spirals.py new file mode 100644 index 00000000..762fe2ca --- /dev/null +++ b/extensions/fablabchemnitz_affine_spirals.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +import inkex +from lxml import etree +from math import cos, sin, pi, exp +__version__ = '0.1' +inkex.localization.localize + +def line(npts=40, x0=0, y0=0, delta=.5, sgn=1): + #returns a list of points on a line (y = +/- x + c) starting at x0,y0 + return [ (x0 + delta*t, y0 + sgn*delta*t) for t in range(npts)] + +def ff(v, ww=.25, ds=.4): + #covering map from R^2 ro punctured plane + x,y = v + r,u = exp(-ds*x), cos(pi*ww*y) + 1J*sin(pi*ww*y) + return r*u + +def mk_plugs(pts): + #returns a list of complex representing a plug type segment + segs = [fit_plug(end_pts) for end_pts in zip(pts,pts[1:]) ] + tmp = [] + for seg in segs: + tmp.extend(seg) + return tmp + +def fit_plug(ss): + a,b = ss + rot = complex(b-a) + pts = [0,.45,.4 + .15*1J, .6 + .15*1J, .55, 1] + return [rot*z + a for z in pts] + +def pts2curve(cplxs): + '''makes a polyline path element from a list of complex + ''' + def cplx2pt(z): + return (z.real,z.imag) + + scale = 200 + data = [cplx2pt( scale*z ) for z in cplxs ] + pth = [ '%.2f, %.2f '%z for z in data] + return 'M '+ ''.join(pth) + +class AffineTorus(inkex.Effect): # choose a better name + + def __init__(self): + inkex.Effect.__init__(self) + self.arg_parser.add_argument("--num_lines", type=int, default=3) + self.arg_parser.add_argument("--num_petals", type=int, default=3) + self.arg_parser.add_argument("--shrink_ratio", type=float, default=3) + #self.arg_parser.add_argument("--mk_filled", type=inkex.Boolean, default=False) + self.arg_parser.add_argument("--mk_full", type=inkex.Boolean, default=False) + self.arg_parser.add_argument("--active-tab", default='title') + + def calc_unit_factor(self): + unit_factor = self.svg.unittouu(str(1.0) + self.options.units) + return unit_factor + + def effect(self): + path_stroke = '#DD0000' # take color from tab3 + path_fill = 'none' # no fill - just a line + path_stroke_width = 1. # can also be in form '0.6mm' + page_id = self.options.active_tab # sometimes wrong the very first time + + styles = [ {'stroke': path_stroke , 'fill': 'none', 'stroke-width': path_stroke_width}, + {'stroke': 'none', 'fill': '#FFFF00', 'stroke-width': 0}] + + styles = [str(inkex.Style(x)) for x in styles] + + # This finds center of current view in inkscape + t = 'translate(%s,%s)' % (self.svg.namedview.center[0], self.svg.namedview.center[1]) + + # Make a nice useful name + g_attribs = {inkex.addNS('label','inkscape'): 'koch', + inkex.addNS('transform-center-x','inkscape'): str(0), + inkex.addNS('transform-center-y','inkscape'): str(0), + 'transform': t, + 'style' : styles[1], + 'info':'N: '+str(self.options.num_lines) } + topgroup = etree.SubElement(self.svg.get_current_layer(), 'g', g_attribs) + + NN = 2*self.options.num_lines + NP = self.options.num_petals + SF = 2*self.options.shrink_ratio + + payload = [] + for y in range(-NP,NP): + mpts = [ff(z,ww=1./NP, ds=SF) for z in line(npts=NN, y0=y)] + payload.append(mk_plugs(mpts)) + mpts = [ff(z,ww=1./NP, ds=SF) for z in line(npts=NN, y0=y,sgn=-1 )] + payload.append(mk_plugs(mpts)) + + payload = [pts2curve(cc) for cc in payload] + payload = ' '.join(payload) + + curve_attribs = { 'style': styles[0], 'd': payload} + etree.SubElement(topgroup, inkex.addNS('path','svg'), curve_attribs) + +if __name__ == '__main__': + AffineTorus().run() \ No newline at end of file