This repository has been archived on 2023-03-25. You can view files and clone it, but cannot push or open issues or pull requests.

#### 145 lines 5.4 KiB Python Raw Permalink Blame History

 ```#!/usr/bin/env python3 ``` ```""" ``` ```X-agram ``` ```Create n-pointed star polygons (pentagram, hexagram, etc) ``` ```""" ``` ```import inkex ``` ```from math import * ``` ```from lxml import etree ``` ``` ``` ```def addPathCommand(a, cmd): ``` ``` for x in cmd: ``` ``` a.append(str(x)) ``` ``` ``` ```class XAgram(inkex.EffectExtension): ``` ``` ``` ``` def add_arguments(self, pars): ``` ``` pars.add_argument('--tab') ``` ``` pars.add_argument('--points', type=int, default=5, help='Number of points (or sides)') ``` ``` pars.add_argument('--skip', type=int, default=2, help='Vertex increment when connecting points') ``` ``` pars.add_argument('--rotate', type=float, default=0, help='Rotation angle (clockwise, in degrees)') ``` ``` pars.add_argument('--inner_circle', type=inkex.Boolean, default=False, help='Connect points via inner circle') ``` ``` pars.add_argument('--show_inner_circle', type=inkex.Boolean, default=True, help='Show inner circle') ``` ``` pars.add_argument('--inner_ratio', type=int, default=50, help='Inner radius percentage (inner radius as a percentage of the outer radius)') ``` ``` ``` ``` def effect(self): ``` ``` layer = self.svg.get_current_layer(); ``` ``` ``` ``` if len(self.svg.selected) == 0: ``` ``` inkex.errormsg('Please select a circle or ellipse.') ``` ``` exit() ``` ``` ``` ``` numValid = 0 ``` ``` for id, obj in self.svg.selected.items(): ``` ``` cx,cy, rx,ry = 0,0, 0,0 ``` ``` style = '' ``` ``` isValid = False ``` ``` if obj.tag == inkex.addNS('circle','svg'): ``` ``` isValid = True ``` ``` cx = float(obj.get('cx')) ``` ``` cy = float(obj.get('cy')) ``` ``` rx = float(obj.get('r')) ``` ``` ry = rx ``` ``` elif obj.tag == inkex.addNS('ellipse', 'svg'): ``` ``` isValid = True ``` ``` cx = float(obj.get('cx')) ``` ``` cy = float(obj.get('cy')) ``` ``` rx = float(obj.get('rx')) ``` ``` ry = float(obj.get('ry')) ``` ``` elif obj.tag == inkex.addNS('path', 'svg'): ``` ``` if obj.get(inkex.addNS('type', 'sodipodi')) == 'arc': ``` ``` isValid = True ``` ``` cx = float(obj.get(inkex.addNS('cx', 'sodipodi'))) ``` ``` cy = float(obj.get(inkex.addNS('cy', 'sodipodi'))) ``` ``` rx = float(obj.get(inkex.addNS('rx', 'sodipodi'))) ``` ``` ry = float(obj.get(inkex.addNS('ry', 'sodipodi'))) ``` ``` ``` ``` if not isValid: ``` ``` continue; ``` ``` ``` ``` numValid += 1 ``` ``` style = obj.get('style') ``` ``` transform = obj.get('transform') ``` ``` isEllipse = False ``` ``` if rx != ry: ``` ``` isEllipse = True ``` ``` ``` ``` sides = self.options.points ``` ``` skip = self.options.skip ``` ``` rotate = self.options.rotate ``` ``` useInnerCircle = self.options.inner_circle ``` ``` showInnerCircle = self.options.show_inner_circle ``` ``` innerRatio = float(self.options.inner_ratio) / 100.0 ``` ``` ``` ``` if useInnerCircle and showInnerCircle: ``` ``` if not isEllipse: ``` ``` cin = etree.SubElement(layer, inkex.addNS('circle','svg')) ``` ``` cin.set('r', str(rx * innerRatio)) ``` ``` else: ``` ``` cin = etree.SubElement(layer, inkex.addNS('ellipse','svg')) ``` ``` cin.set('rx', str(rx * innerRatio)) ``` ``` cin.set('ry', str(ry * innerRatio)) ``` ``` cin.set('cx', str(cx)) ``` ``` cin.set('cy', str(cy)) ``` ``` cin.set('style', style) ``` ``` if transform: ``` ``` cin.set('transform', transform) ``` ``` ``` ``` tau = 2*pi ``` ``` origin = -(tau / 4) + (rotate * pi / 180) ``` ``` out_pts = [] ``` ``` in_pts = [] ``` ``` for i in range(sides): ``` ``` # Outer points (on outer circle) ``` ``` theta = (i * (tau / sides)) ``` ``` px = cx + rx * cos(origin + theta) ``` ``` py = cy + ry * sin(origin + theta) ``` ``` out_pts.append([px, py]) ``` ``` ``` ``` # Inner points (on inner circle) ``` ``` theta = ((i + (skip / 2.0)) * (tau / sides)) ``` ``` px = cx + rx * innerRatio * cos(origin + theta) ``` ``` py = cy + ry * innerRatio * sin(origin + theta) ``` ``` in_pts.append([px, py]) ``` ``` ``` ``` pts = [] ``` ``` pt_done = {} ``` ``` for i in range(sides): ``` ``` if i in pt_done: ``` ``` continue; ``` ``` ``` ``` p1 = out_pts[i] ``` ``` addPathCommand(pts, ['M', p1[0], p1[1]]) ``` ``` ``` ``` pt_done[i] = True ``` ``` start_index = i ``` ``` curr = start_index ``` ``` next = (curr + skip) % sides ``` ``` while next != start_index: ``` ``` p = out_pts[next] ``` ``` pt_done[next] = True ``` ``` ``` ``` if useInnerCircle: ``` ``` addPathCommand(pts, ['L', in_pts[curr][0], in_pts[curr][1]]) ``` ``` ``` ``` addPathCommand(pts, ['L', p[0], p[1]]) ``` ``` ``` ``` curr = next ``` ``` next = (curr + skip) % sides ``` ``` if useInnerCircle: ``` ``` addPathCommand(pts, ['L', in_pts[curr][0], in_pts[curr][1]]) ``` ``` addPathCommand(pts, ['z']) ``` ``` ``` ``` # Create star polygon as a single path. ``` ``` l1 = etree.SubElement(layer, inkex.addNS('path','svg')) ``` ``` l1.set('style', style) ``` ``` if transform: ``` ``` l1.set('transform', transform) ``` ``` l1.set('d', ' '.join(pts)) ``` ``` ``` ``` if numValid == 0: ``` ``` inkex.errormsg('Selection must contain a circle or ellipse.') ``` ``` ``` ```if __name__ == '__main__': ``` ``` XAgram().run() ```