diff --git a/extensions/fablabchemnitz/offset_paths/offset_paths.inx b/extensions/fablabchemnitz/offset_paths/offset_paths.inx
index 61fae9bb..2e0a8168 100644
--- a/extensions/fablabchemnitz/offset_paths/offset_paths.inx
+++ b/extensions/fablabchemnitz/offset_paths/offset_paths.inx
@@ -31,6 +31,8 @@
false
+ false
+
diff --git a/extensions/fablabchemnitz/offset_paths/offset_paths.py b/extensions/fablabchemnitz/offset_paths/offset_paths.py
index 5aa59ea8..52e25796 100644
--- a/extensions/fablabchemnitz/offset_paths/offset_paths.py
+++ b/extensions/fablabchemnitz/offset_paths/offset_paths.py
@@ -15,6 +15,7 @@ import inkex
import math
from inkex.paths import CubicSuperPath
import re
+import copy
import pyclipper
class OffsetPaths(inkex.EffectExtension):
@@ -25,89 +26,104 @@ class OffsetPaths(inkex.EffectExtension):
pars.add_argument("--offset_count", type=int, default=1, help="Number of offset paths")
pars.add_argument("--offset", type=float, default=1.000, help="Offset amount")
pars.add_argument("--init_offset", type=float, default=0.000, help="Initial Offset Amount")
- pars.add_argument("--copy_org", type=inkex.Boolean, default=True, help="copy original path")
pars.add_argument("--offset_increase", type=float, default=0.000, help="Offset increase between iterations")
pars.add_argument("--jointype", default="2", help="Join type")
pars.add_argument("--endtype", default="3", help="End type")
pars.add_argument("--miterlimit", type=float, default=3.0, help="Miter limit")
pars.add_argument("--clipperscale", type=int, default=1024, help="Scaling factor. Should be a multiplicator of 2, like 2^4=16 or 2^10=1024. The higher the scale factor the higher the quality.")
+ pars.add_argument("--copy_org", type=inkex.Boolean, default=True, help="copy original path")
+ pars.add_argument("--individual", type=inkex.Boolean, default=True, help="Separate into individual paths")
+
+
def effect(self):
unit_factor = 1.0 / self.svg.uutounit(1.0, self.options.unit)
- paths = self.svg.selection.filter(inkex.PathElement).values()
- count = sum(1 for path in paths)
- paths = self.svg.selection.filter(inkex.PathElement).values() #we need to call this twice because the sum function consumes the generator
+ pathElements = self.svg.selection.filter(inkex.PathElement).values()
+ count = sum(1 for pathElement in pathElements)
+ pathElements = self.svg.selection.filter(inkex.PathElement).values() #we need to call this twice because the sum function consumes the generator
if count == 0:
inkex.errormsg("No paths selected.")
exit()
- for path in paths:
- if path.tag == inkex.addNS('path','svg'):
- p = CubicSuperPath(path.get('d'))
+ for pathElement in pathElements:
+ csp = CubicSuperPath(pathElement.get('d'))
- scale_factor = self.options.clipperscale # 2 ** 32 = 1024 - see also https://github.com/fonttools/pyclipper/wiki/Deprecating-SCALING_FACTOR
+ scale_factor = self.options.clipperscale # 2 ** 32 = 1024 - see also https://github.com/fonttools/pyclipper/wiki/Deprecating-SCALING_FACTOR
- pco = pyclipper.PyclipperOffset(self.options.miterlimit)
+ pco = pyclipper.PyclipperOffset(self.options.miterlimit)
+
+ JT = None
+ if self.options.jointype == "0":
+ JT = pyclipper.JT_SQUARE
+ elif self.options.jointype == "1":
+ JT = pyclipper.JT_ROUND
+ elif self.options.jointype == "2":
+ JT = pyclipper.JT_MITER
- JT = None
- if self.options.jointype == "0":
- JT = pyclipper.JT_SQUARE
- elif self.options.jointype == "1":
- JT = pyclipper.JT_ROUND
- elif self.options.jointype == "2":
- JT = pyclipper.JT_MITER
-
- ET = None
- if self.options.endtype == "0":
- ET = pyclipper.ET_CLOSEDPOLYGON
- elif self.options.endtype == "1":
- ET = pyclipper.ET_CLOSEDLINE
- elif self.options.endtype == "2":
- ET = pyclipper.ET_OPENBUTT
- elif self.options.endtype == "3":
- ET = pyclipper.ET_OPENSQUARE
- elif self.options.endtype == "4":
- ET = pyclipper.ET_OPENROUND
-
- new = []
+ ET = None
+ if self.options.endtype == "0":
+ ET = pyclipper.ET_CLOSEDPOLYGON
+ elif self.options.endtype == "1":
+ ET = pyclipper.ET_CLOSEDLINE
+ elif self.options.endtype == "2":
+ ET = pyclipper.ET_OPENBUTT
+ elif self.options.endtype == "3":
+ ET = pyclipper.ET_OPENSQUARE
+ elif self.options.endtype == "4":
+ ET = pyclipper.ET_OPENROUND
+
+ newPaths = []
- # load in initial paths
- for sub in p:
- sub_simple = []
- for item in sub:
- itemx = [float(z) * scale_factor for z in item[1]]
- sub_simple.append(itemx)
- pco.AddPath(sub_simple, JT, ET)
+ # load in initial paths
+ for subPath in csp:
+ sub_simple = []
+ for item in subPath:
+ itemx = [float(z) * scale_factor for z in item[1]]
+ sub_simple.append(itemx)
+ pco.AddPath(sub_simple, JT, ET)
- # calculate offset paths for different offset amounts
- offset_list = []
- offset_list.append(self.options.init_offset * unit_factor)
- for i in range(0, self.options.offset_count):
- ofs_increase = +math.pow(float(i) * self.options.offset_increase * unit_factor, 2)
- if self.options.offset_increase < 0:
- ofs_increase = -ofs_increase
- offset_list.append(offset_list[0] + float(i) * self.options.offset * unit_factor + ofs_increase * unit_factor)
+ # calculate offset paths for different offset amounts
+ offset_list = []
+ offset_list.append(self.options.init_offset * unit_factor)
+ for i in range(0, self.options.offset_count):
+ ofs_increase = +math.pow(float(i) * self.options.offset_increase * unit_factor, 2)
+ if self.options.offset_increase < 0:
+ ofs_increase = -ofs_increase
+ offset_list.append(offset_list[0] + float(i) * self.options.offset * unit_factor + ofs_increase * unit_factor)
- solutions = []
- for offset in offset_list:
- solution = pco.Execute(offset * scale_factor)
- solutions.append(solution)
- if len(solution)<=0:
- continue # no more loops to go, will provide no results.
+ solutions = []
+ for offset in offset_list:
+ solution = pco.Execute(offset * scale_factor)
+ solutions.append(solution)
+ if len(solution)<=0:
+ continue # no more loops to go, will provide no results.
- # re-arrange solutions to fit expected format & add to array
- for solution in solutions:
- for sol in solution:
- solx = [[float(s[0]) / scale_factor, float(s[1]) / scale_factor] for s in sol]
- sol_p = [[a, a, a] for a in solx]
- sol_p.append(sol_p[0][:])
- new.append(sol_p)
+ # re-arrange solutions to fit expected format & add to array
+ for solution in solutions:
+ for sol in solution:
+ solx = [[float(s[0]) / scale_factor, float(s[1]) / scale_factor] for s in sol]
+ sol_p = [[a, a, a] for a in solx]
+ sol_p.append(sol_p[0][:])
+ if sol_p not in newPaths:
+ newPaths.append(sol_p)
- # add old, just to keep (make optional!)
- if self.options.copy_org:
- for sub in p:
- new.append(sub)
-
- path.set('d', CubicSuperPath(new))
+ if self.options.individual is True:
+ parent = pathElement.getparent()
+ idx = parent.index(pathElement)
+ idSuffix = 0
+ for newPath in newPaths:
+ copyElement = copy.copy(pathElement)
+ elementId = copyElement.get('id')
+ copyElement.path = CubicSuperPath(newPath)
+ copyElement.set('id', elementId + str(idSuffix))
+ parent.insert(idx, copyElement)
+ idSuffix += 1
+ if self.options.copy_org is False:
+ pathElement.delete()
+ else:
+ if self.options.copy_org is True:
+ for subPath in csp:
+ newPaths.append(subPath)
+ pathElement.set('d', CubicSuperPath(newPaths))
if __name__ == '__main__':
OffsetPaths().run()
\ No newline at end of file