1#!/usr/local/bin/python3.8 2# coding=utf-8 3# 4# Copyright (C) 2005 Carsten Goetze c.goetze@tu-bs.de 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with this program; if not, write to the Free Software 18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19# 20import math 21import random 22import inkex 23from inkex.paths import Move, Line 24 25def calculate_subdivision(smoothness, x1, y1, x2, y2): 26 # Calculate the vector from (x1,y1) to (x2,y2) 27 x3 = x2 - x1 28 y3 = y2 - y1 29 # Calculate the point half-way between the two points 30 hx = x1 + x3 / 2 31 hy = y1 + y3 / 2 32 # Calculate normalized vector perpendicular to the vector (x3,y3) 33 length = math.sqrt(x3 * x3 + y3 * y3) 34 if length != 0: 35 nx = -y3 / length 36 ny = x3 / length 37 else: 38 nx = 1 39 ny = 0 40 # Scale perpendicular vector by random factor """ 41 r = random.uniform(-length / (1 + smoothness), length / (1 + smoothness)) 42 nx = nx * r 43 ny = ny * r 44 # add scaled perpendicular vector to the half-way point to get the final displaced subdivision point 45 x = hx + nx 46 y = hy + ny 47 return (x, y) 48 49 50class Fractalize(inkex.EffectExtension): 51 def add_arguments(self, pars): 52 pars.add_argument("-s", "--subdivs", type=int, default="6", 53 help="Number of subdivisons") 54 pars.add_argument("-f", "--smooth", type=float, default="4.0", 55 help="Smoothness of the subdivision") 56 57 def effect(self): 58 for node in self.svg.selection.filter(inkex.PathElement): 59 path = node.path.to_absolute() 60 result = [] 61 for cmd_proxy in path.proxy_iterator(): # type: inkex.Path.PathCommandProxy 62 prev = cmd_proxy.previous_end_point 63 end = cmd_proxy.end_point 64 if cmd_proxy.letter == 'M': 65 result.append(Move(*cmd_proxy.args)) 66 else: 67 for seg in self.fractalize((prev.x, prev.y, end.x, end.y), self.options.subdivs, 68 self.options.smooth): 69 result.append(Line(*seg)) 70 result.append(Line(end.x, end.y)) 71 72 node.path = result 73 74 def fractalize(self, coords, subdivs, smooth): 75 """recursively subdivide the segments left and right of the subdivision""" 76 subdiv_point = calculate_subdivision(smooth, *coords) 77 78 if subdivs: 79 # recursively subdivide the segment left of the subdivision point 80 for left_seg in self.fractalize(coords[:2] + subdiv_point[-2:], subdivs - 1, smooth): 81 yield left_seg 82 83 yield subdiv_point 84 85 # recursively subdivide the segment right of the subdivision point 86 for right_seg in self.fractalize(subdiv_point[-2:] + coords[-2:], subdivs - 1, smooth): 87 yield right_seg 88 89if __name__ == '__main__': 90 Fractalize().run() 91