more options to handle offset paths

This commit is contained in:
Mario Voigt 2021-06-10 00:31:53 +02:00
parent 50f891d9ba
commit 2071c0227f
2 changed files with 82 additions and 64 deletions

View File

@ -31,6 +31,8 @@
<option value="4">Open Round</option> <option value="4">Open Round</option>
</param> </param>
<param name="copy_org" type="bool" gui-text="Keep original path" gui-description="If enabled, keeps original path as a copy">false</param> <param name="copy_org" type="bool" gui-text="Keep original path" gui-description="If enabled, keeps original path as a copy">false</param>
<param name="individual" type="bool" gui-text="Separate into individual paths" gui-description="If enabled, each offset curve will be an individual svg element">false</param>
</page> </page>
<page name="tab_about" gui-text="About"> <page name="tab_about" gui-text="About">
<label appearance="header">Offset Paths</label> <label appearance="header">Offset Paths</label>

View File

@ -15,6 +15,7 @@ import inkex
import math import math
from inkex.paths import CubicSuperPath from inkex.paths import CubicSuperPath
import re import re
import copy
import pyclipper import pyclipper
class OffsetPaths(inkex.EffectExtension): class OffsetPaths(inkex.EffectExtension):
@ -25,24 +26,26 @@ class OffsetPaths(inkex.EffectExtension):
pars.add_argument("--offset_count", type=int, default=1, help="Number of offset paths") 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("--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("--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("--offset_increase", type=float, default=0.000, help="Offset increase between iterations")
pars.add_argument("--jointype", default="2", help="Join type") pars.add_argument("--jointype", default="2", help="Join type")
pars.add_argument("--endtype", default="3", help="End 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("--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("--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): def effect(self):
unit_factor = 1.0 / self.svg.uutounit(1.0, self.options.unit) unit_factor = 1.0 / self.svg.uutounit(1.0, self.options.unit)
paths = self.svg.selection.filter(inkex.PathElement).values() pathElements = self.svg.selection.filter(inkex.PathElement).values()
count = sum(1 for path in paths) count = sum(1 for pathElement in pathElements)
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() #we need to call this twice because the sum function consumes the generator
if count == 0: if count == 0:
inkex.errormsg("No paths selected.") inkex.errormsg("No paths selected.")
exit() exit()
for path in paths: for pathElement in pathElements:
if path.tag == inkex.addNS('path','svg'): csp = CubicSuperPath(pathElement.get('d'))
p = CubicSuperPath(path.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
@ -68,12 +71,12 @@ class OffsetPaths(inkex.EffectExtension):
elif self.options.endtype == "4": elif self.options.endtype == "4":
ET = pyclipper.ET_OPENROUND ET = pyclipper.ET_OPENROUND
new = [] newPaths = []
# load in initial paths # load in initial paths
for sub in p: for subPath in csp:
sub_simple = [] sub_simple = []
for item in sub: for item in subPath:
itemx = [float(z) * scale_factor for z in item[1]] itemx = [float(z) * scale_factor for z in item[1]]
sub_simple.append(itemx) sub_simple.append(itemx)
pco.AddPath(sub_simple, JT, ET) pco.AddPath(sub_simple, JT, ET)
@ -100,14 +103,27 @@ class OffsetPaths(inkex.EffectExtension):
solx = [[float(s[0]) / scale_factor, float(s[1]) / scale_factor] for s in sol] 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 = [[a, a, a] for a in solx]
sol_p.append(sol_p[0][:]) sol_p.append(sol_p[0][:])
new.append(sol_p) if sol_p not in newPaths:
newPaths.append(sol_p)
# add old, just to keep (make optional!) if self.options.individual is True:
if self.options.copy_org: parent = pathElement.getparent()
for sub in p: idx = parent.index(pathElement)
new.append(sub) idSuffix = 0
for newPath in newPaths:
path.set('d', CubicSuperPath(new)) 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__': if __name__ == '__main__':
OffsetPaths().run() OffsetPaths().run()