A random link Home Compute Inkscape Contact   
   
   
   

Kochify

" RFE #1118728: fractal lines" was one of the reasons I thought it would be fun to work on extensions. This script is my implementation of a Koch's snowflake tool for Inkscape. The tool is built with two scripts. The first script loads the first selected path into a temporary file. The second script replaces each segment of the selected paths with a scaled and rotated copy of the path from the temporary file.

Loader script:

#!/usr/bin/env python 
import math, tempfile, cPickle, inkex

def findend(d):
	end = []
	subPathStart = []
	for cmd,params in d:
		if cmd == 'M':
			subPathStart = params[-2:]
		if cmd == 'Z':
			end = subPathStart[:]
		else:
			end = params[-2:]
	return end

class LoadKochify(inkex.Effect):
	def effect(self):
		for id, node in self.selected.iteritems():
			if node.tagName == 'path':
				d = inkex.parsePath(node.attributes.getNamedItem('d').value)
				start = d[0][1][-2:]
				end = findend(d)
				while start == end and len(d):
					d = d[:-1]
					end = findend(d)
				if not end: 
					break
				dx = end[0]-start[0]
				dy = end[1]-start[1]
				length = math.sqrt((dx**2) + (dy**2))
				angle = math.atan2(dy,dx)
				path = {'start': start, 'end': end, 
					'length': length, 'angle': angle, 'path': d}
				f = open(tempfile.gettempdir() + '/kochify.bin', 'w')
				cPickle.dump(path, f)
				f.close()				
				break

e = LoadKochify()
e.affect()
Replacer script:
#!/usr/bin/env python 
import math, tempfile, copy, cPickle, inkex

def findend(d):
	end = []
	subPathStart = []
	for cmd,params in d:
		if cmd == 'M':
			subPathStart = params[-2:]
		if cmd == 'Z':
			end = subPathStart[:]
		else:
			end = params[-2:]
	return end

class Kochify(inkex.Effect):
	def effect(self):
		try:
			f = open(tempfile.gettempdir() + '/kochify.bin', 'r')
			proto = cPickle.load(f)
			f.close()				
		except:
			return False
		
		for id, node in self.selected.iteritems():
			if node.tagName == 'path':
				d = node.attributes.getNamedItem('d')
				p = inkex.parsePath(d.value)
				last = p[0][1][-2:]
				subPathStart = []
				cur = []
				new = []
				for i in range(len(p)):
					rep = copy.deepcopy(proto['path'])
					cmd, params = p[i]
					if cmd == 'M':
						subPathStart = params[-2:]
						new.append(copy.deepcopy(p[i]))
						continue
					if cmd == 'Z':
						cur = subPathStart[:]
					else:
						cur = params[-2:]

					if last == cur:
						continue

					dx = cur[0]-last[0]
					dy = cur[1]-last[1]
					length = math.sqrt((dx**2) + (dy**2))
					angle = math.atan2(dy,dx)
		
					scale = length / proto['length']
					rotate = angle - proto['angle']
					inkex.scalePath(rep,scale,scale)
					inkex.rotatePath(rep, rotate)
					repend = findend(rep)
					transx = cur[0] - repend[0]
					transy = cur[1] - repend[1]
					inkex.translatePath(rep, transx, transy)
					
					new.extend(rep[1:])
					last = cur[:]
				d.value = inkex.formatPath(new)
e = Kochify()
e.affect()

Files:

     
   
   
Home Compute Inkscape Contact