This commit is contained in:
Mario Voigt 2021-10-19 02:20:44 +02:00
commit 808e599437
19 changed files with 622 additions and 161 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Convert To Localized Braille</name>
<id>fablabchemnitz.de.braille-l18n</id>
<id>fablabchemnitz.de.braille_l18n</id>
<param name="locale" gui-text="Alphabet:" type="optiongroup" appearance="combo">
<option value="en">English (ASCII)</option>
<option value="es">Spanish</option>
@ -20,6 +20,6 @@
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">braille-l18n.py</command>
<command location="inx" interpreter="python">braille_l18n.py</command>
</script>
</inkscape-extension>

View File

@ -1,8 +1,8 @@
[
{
"name": "Convert To Localized Braille",
"id": "fablabchemnitz.de.braille-l18n",
"path": "braille-l18n",
"id": "fablabchemnitz.de.braille_l18n",
"path": "braille_l18n",
"original_name": "Convert to localized Braille",
"original_id": "org.inkscape.text.braille-l18n",
"license": "BSD-3-Clause License",

View File

@ -111,9 +111,12 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
csp = CubicSuperPath(subPath)
if len(subPath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
replacedelement.path = subPath
replacedelement.set('id', oldId + str(idSuffix))
if len(subPaths) == 1:
replacedelement.set('id', oldId)
else:
replacedelement.set('id', oldId + str(idSuffix))
idSuffix += 1
parent.insert(idx, replacedelement)
idSuffix += 1
breakelements.append(replacedelement)
element.delete()
for child in element.getchildren():

View File

@ -20,7 +20,6 @@
<param name="creationunit" type="optiongroup" appearance="combo" gui-text="Creation Units">
<option value="mm">mm</option>
<option value="cm">cm</option>
<option value="m">m</option>
<option value="in">in</option>
<option value="pt">pt</option>
<option value="px">px</option>
@ -44,7 +43,6 @@
<param name="length_filter_unit" type="optiongroup" appearance="combo" gui-text="Length filter unit">
<option value="mm">mm</option>
<option value="cm">cm</option>
<option value="m">m</option>
<option value="in">in</option>
<option value="pt">pt</option>
<option value="px">px</option>
@ -52,7 +50,7 @@
</param>
<param name="keep_selected" type="bool" gui-text="Keep selected elements">false</param>
<param name="no_convert" type="bool" gui-text="Do not create output path(s) (cosmetic style only)">false</param>
<param name="breakapart" type="bool" gui-text="Break apart output path(s) into segments" gui-description="Performs CTRL + SHIFT + K to break the new output path into it's parts">false</param>
<param name="breakapart" type="bool" gui-text="Break apart output path(s) into segments" gui-description="Performs CTRL + SHIFT + K to break the new output path into it's parts. Recommended to enable because default break apart of Inkscape might produce pointy paths.">true</param>
<param name="show_info" type="bool" gui-text="Print length, pattern and filtering information/errors" gui-description="Warning: might freeze Inkscape forever if you have a lot of nodes because we create too much print output. Use for debugging only!">false</param>
<param name="skip_errors" type="bool" gui-text="Skip errors">false</param>
</vbox>

View File

@ -59,7 +59,7 @@ class LinksCreator(inkex.EffectExtension):
pars.add_argument("--length_filter_unit", default="mm", help="Length filter unit")
pars.add_argument("--keep_selected", type=inkex.Boolean, default=False, help="Keep selected elements")
pars.add_argument("--no_convert", type=inkex.Boolean, default=False, help="Do not create segments (cosmetic gaps only)")
pars.add_argument("--breakapart", type=inkex.Boolean, default=False, help="Performs CTRL + SHIFT + K to break the new output path into it's parts")
pars.add_argument("--breakapart", type=inkex.Boolean, default=True, help="Performs CTRL + SHIFT + K to break the new output path into it's parts. Recommended to enable because default break apart of Inkscape might produce pointy paths.")
pars.add_argument("--show_info", type=inkex.Boolean, default=False, help="Print some length and pattern information")
pars.add_argument("--skip_errors", type=inkex.Boolean, default=False, help="Skip errors")
@ -83,9 +83,12 @@ class LinksCreator(inkex.EffectExtension):
csp = CubicSuperPath(subpath)
if len(subpath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
replacedelement.set('d', csp)
replacedelement.set('id', oldId + str(idSuffix))
if len(subPaths) == 1:
replacedelement.set('id', oldId)
else:
replacedelement.set('id', oldId + str(idSuffix))
idSuffix += 1
parent.insert(idx, replacedelement)
idSuffix += 1
breakelements.append(replacedelement)
parent.remove(element)
for child in element.getchildren():
@ -280,15 +283,12 @@ class LinksCreator(inkex.EffectExtension):
length = length - dash
idash = (idash + 1) % len(dashes)
dash = dashes[idash]
if sub[-1] != sub[i] and sub[i][0] != sub[i][1]: #avoid pointy paths
if idash % 2:
new.append([sub[i]])
else:
new[-1].append(sub[i])
if idash % 2:
new.append([sub[i]])
else:
new[-1].append(sub[i])
i += 1
if new[-1][0] == new[-1][0]: #avoid pointy paths
new.remove(new[-1])
style.pop('stroke-dasharray')
element.pop('sodipodi:type')
csp = CubicSuperPath(new)

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Grey to MonoAlpha</name>
<id>fablabchemnitz.de.grey_to_monoalpha</id>
<param name="tab" type="notebook">
<page name="main_page" gui-text="Settings">
<vbox>
<hbox>
<param name="color_picker_mono" type="color" appearance="colorbutton" gui-text="Mono Colour">0x000000ff</param>
</hbox>
<hbox>
<param name="apply_to_type_radio" type="optiongroup" appearance="radio" gui-text="Apply To">
<option value="fill_and_stroke">Fill and Stroke</option>
<option value="fill">Fill Only</option>
<option value="stroke">Stroke Only</option>
</param>
</hbox>
<hbox>
<label>Opacity Threshold</label>
<param name="opacity_lower_threshold" type="float" min="0" max="0.9" gui-text="Lower" gui-description="opacity_lower_threshold">0</param>
<param name="opacity_upper_threshold" type="float" min="0.05" max="1" gui-text="Upper" gui-description="opacity_upper_threshold">1</param>
</hbox>
</vbox>
</page>
<page name="about_page" gui-text="About">
<label>Grey To MonoAlpha - An Inkscape Extension</label>
<label>Inkscape 1.1 +</label>
<label appearance="url">https://gitlab.com/inklinea/</label>
<label xml:space="preserve">
▶ Converts a Greyscale Image to
Monochrome with variable Opacity.
▶ Threshold setting to avoid solid colour
▶ Can be applied to stroke / fill or both
</label>
</page>
</param>
<effect>
<object-type>path</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Various"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">grey_to_monoalpha.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,99 @@
#!/usr/bin/env python3
#
# Copyright (C) [2021] [Matt Cottam], [mpcottam@raincloud.co.uk]
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
# Grey To Mono Alpha *** Convert Greys to Monochrome with varying Opacity
##############################################################################
import math
import inkex
from inkex import Color
# Python Standard Libary
from statistics import mean
def get_attributes(self):
for att in dir(self):
inkex.errormsg((att, getattr(self, att)))
def rgba_to_bw_rgba(self, my_objects):
apply_to = self.options.apply_to_type_radio
mono_color = self.options.color_picker_mono.to_rgba()
opacity_lower_threshold = self.options.opacity_lower_threshold
opacity_upper_threshold = self.options.opacity_upper_threshold
opacity_range = opacity_upper_threshold - opacity_lower_threshold
for my_object in my_objects:
if 'fill' in apply_to and ('fill:none' not in str(my_object.style)):
my_fill_color = my_object.style.get_color(name='fill').to_rgba()
my_fill_color_red = my_fill_color[0]
my_fill_color_green = my_fill_color[1]
my_fill_color_blue = my_fill_color[2]
mean_fill_component_value = mean([my_fill_color_red, my_fill_color_blue, my_fill_color_green])
if mean_fill_component_value > 0:
mono_opacity = (1 - (mean_fill_component_value / 256)) * opacity_range
mono_opacity = mono_opacity + opacity_lower_threshold
else:
mono_opacity = opacity_upper_threshold
my_object.style['fill'] = str(mono_color)
my_object.style['fill-opacity'] = str(mono_opacity)
if 'stroke' in apply_to and (';stroke:none' not in str(my_object.style)) and ('stroke:' in str(my_object.style)):
my_stroke_color = my_object.style.get_color(name='stroke').to_rgba()
my_stroke_color_red = my_stroke_color[0]
my_stroke_color_green = my_stroke_color[1]
my_stroke_color_blue = my_stroke_color[2]
mean_stroke_component_value = mean([my_stroke_color_red, my_stroke_color_blue, my_stroke_color_green])
if mean_stroke_component_value > 0:
mono_opacity = (1 - (mean_stroke_component_value / 256)) * opacity_range
mono_opacity = mono_opacity + opacity_lower_threshold
else:
mono_opacity = opacity_upper_threshold
my_object.style['stroke'] = str(mono_color)
my_object.style['stroke-opacity'] = str(mono_opacity)
class GreyToMonoAlpha(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--tab")
pars.add_argument("--color_picker_mono", type=inkex.colors.Color, default=0)
pars.add_argument("--apply_to_type_radio", default=None)
pars.add_argument("--opacity_lower_threshold", type=float, default=0)
pars.add_argument("--opacity_upper_threshold", type=float, default=1)
def effect(self):
my_objects = self.svg.selected
if len(my_objects) < 1:
self.msg('Please select some paths first.')
return
rgba_to_bw_rgba(self, my_objects)
if __name__ == '__main__':
GreyToMonoAlpha().run()

View File

@ -0,0 +1,20 @@
[
{
"name": "Grey To MonoAlpha",
"id": "fablabchemnitz.de.grey_to_monoalpha",
"path": "grey_to_monoalpha",
"original_name": "Grey to MonoAlpha",
"original_id": "org.inkscape.grey_to_monoalpha",
"license": "GNU GPL v3",
"license_url": "https://gitlab.com/inklinea/grey-to-mono-alpha/-/blob/main/LICENSE",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/grey_to_monoalpha",
"fork_url": "https://gitlab.com/inklinea/grey-to-mono-alpha",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Grey+to+MonoAlpha",
"inkscape_gallery_url": null,
"main_authors": [
"gitlab.com/inklinea",
"github.com/vmario89"
]
}
]

View File

@ -1,38 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Join Paths / Create Dimples</name>
<name>Join Paths / Create Tabs And Dimples</name>
<id>fablabchemnitz.de.join_paths</id>
<param name="tab" type="notebook">
<page name="subdividePath" gui-text="Join Paths">
<param name="optimized" type="bool" gui-text="Optimized joining">true</param>
<label appearance="header">Create Dimples</label>
<label>Enable to insert dimples (pressfit noses) into the gaps (instead regular straight lines)</label>
<param name="add_dimples" type="bool" gui-text="Create dimples">false</param>
<param name="dimple_type" type="optiongroup" appearance="combo" gui-text="Dimple type">
<option value="lines">lines</option>
<option value="arcs">arcs</option>
</param>
<param name="draw_dimple_centers" type="bool" gui-text="Draw dimple centers">false</param>
<param name="dimple_invert" type="bool" gui-text="Invert dimples">false</param>
<param name="draw_both_sides" type="bool" gui-text="Draw both sides">false</param>
<param name="dimple_height_mode" type="optiongroup" appearance="combo" gui-text="Height by">
<option value="by_height">by height</option>
<option value="by_angle">by angle</option>
</param>
<param name="dimple_angle" type="float" min="0.000" max="360.000" precision="3" gui-text="Angle">45.000</param>
<param name="dimple_height" type="float" min="0.001" max="99999.000" precision="3" gui-text="Height">4.000</param>
<param name="dimple_height_units" gui-text="Height units" type="optiongroup" appearance="combo">
<option value="px">px</option>
<option value="pt">pt</option>
<option value="in">in</option>
<option value="cm">cm</option>
<option value="mm">mm</option>
</param>
<param name="dimples_to_group" type="bool" gui-text="Unify into single group">false</param>
<page name="subdividePath" gui-text="Join Paths / Create Tabs And Dimples">
<hbox>
<vbox>
<label appearance="header">Join Paths</label>
<param name="optimized" type="bool" gui-text="Optimized joining">true</param>
<param name="margin" type="float" min="0.0001" max="99999.0000" precision="4" gui-text="Merge margin">0.0100</param>
<label appearance="header">Tabs And Dimples</label>
<label>Enable to insert dimples (pressfit noses) into</label>
<label>the gaps (instead regular straight lines)</label>
<param name="add_dimples" type="bool" gui-text="Create dimples">false</param>
<param name="dimples_to_group" type="bool" gui-text="Unify into single group">false</param>
<param name="dimple_type" type="optiongroup" appearance="combo" gui-text="Dimple type">
<option value="lines">lines</option>
<option value="peaks">peaks</option>
<option value="arcs">arcs</option>
<option value="tabs">tabs</option>
</param>
<param name="draw_dimple_centers" type="bool" gui-text="Draw dimple centers">false</param>
<param name="dimple_invert" type="bool" gui-text="Invert dimple sides">false</param>
<param name="draw_both_sides" type="bool" gui-text="Draw both sides">false</param>
<param name="draw_arcs_as_paths" type="bool" gui-text="Draw arcs as svg:path" gui-description="If disabled, we get svg:ellipse elements. Only applies for dimple type 'arcs'">true</param>
</vbox>
<separator/>
<vbox>
<label appearance="header">Tab Dimensions</label>
<param name="dimple_height_mode" type="optiongroup" appearance="combo" gui-text="Height by ...">
<option value="by_height">by height</option>
<option value="by_angle">by angle</option>
</param>
<param name="dimple_angle" type="float" min="0.000" max="360.000" precision="3" gui-text="... angle">45.000</param>
<param name="dimple_height" type="float" min="0.001" max="99999.000" precision="3" gui-text="... height">4.000</param>
<param name="dimple_tab_angle" type="float" min="0.000" max="360.000" precision="3" gui-text="Tab angle" gui-description="Only applies for dimple type 'tabs'">45.000</param>
<param name="dimple_height_units" gui-text="Height units" type="optiongroup" appearance="combo">
<option value="mm">mm</option>
<option value="cm">cm</option>
<option value="in">in</option>
<option value="pt">pt</option>
<option value="px">px</option>
</param>
<label appearance="header">Gap filter</label>
<label>Prevents filling all gaps with tabs/dimples.</label>
<param name="dimple_gap_filter" type="bool" gui-text="Apply min/max filter">false</param>
<param name="dimple_min_gap" type="float" min="0.000" max="99999.000" precision="3" gui-text="Min">1</param>
<param name="dimple_max_gap" type="float" min="0.000" max="99999.000" precision="3" gui-text="Max">40</param>
<param name="dimple_gap_filter_units" gui-text="Filter units" type="optiongroup" appearance="combo">
<option value="mm">mm</option>
<option value="cm">cm</option>
<option value="in">in</option>
<option value="pt">pt</option>
<option value="px">px</option>
</param>
</vbox>
</hbox>
</page>
<page name="desc" gui-text="Help">
<label xml:space="preserve">This effect joins the Bezier curves, with straight line segments. If the end nodes are close enough, they are merged into a single one. With the optimized option selected, the new curve starts from the top most curve from the selection. The curves are then joined based on the distance of their closest end point to the previous curve.
</label>
<page name="tab_about" gui-text="About">
<label appearance="header">Join Paths / Create Tabs And Dimples</label>
<label>This effect joins the Bezier curves with straight line segments.
If the end nodes are close enough, they are merged into a single one.
With the optimized option selected, the new curve starts from the top
most curve from the selection. The curves are then joined based on the
distance of their closest end point to the previous curve.
Additionally it allows to create different tabs / dimples for lasercutting.
This extension is originally based on 'Join Paths Optimized' by Shriinivas.</label>
<label>2021 / written by Mario Voigt (Stadtfabrikanten e.V. / FabLab Chemnitz)</label>
<spacer/>
<label appearance="header">Online Documentation</label>
<label appearance="url">https://y.stadtfabrikanten.org/joinpaths</label>
<spacer/>
<label appearance="header">Contributing</label>
<label appearance="url">https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X</label>
<label appearance="url">mailto:mario.voigt@stadtfabrikanten.org</label>
<spacer/>
<label appearance="header">MightyScape Extension Collection</label>
<label>This piece of software is part of the MightyScape for Inkscape Extension Collection and is licensed under GNU GPL v3</label>
<label appearance="url">https://y.stadtfabrikanten.org/mightyscape-overview</label>
</page>
<page name="tab_donate" gui-text="Donate">
<label appearance="header">Coffee + Pizza</label>
<label>We are the Stadtfabrikanten, running the FabLab Chemnitz since 2016. A FabLab is an open workshop that gives people access to machines and digital tools like 3D printers, laser cutters and CNC milling machines.</label>
<spacer/>
<label>You like our work and want to support us? You can donate to our non-profit organization by different ways:</label>
<label appearance="url">https://y.stadtfabrikanten.org/donate</label>
<spacer/>
<label>Thanks for using our extension and helping us!</label>
<image>../000_about_fablabchemnitz.svg</image>
</page>
</param>
<effect>

View File

@ -74,6 +74,9 @@ def getArrangedIds(pathMap, startPathId):
minDist = 9e+100 #A large float
closestId = None
np = pathMap[nextPathId]
if np[-1] == []:
inkex.utils.debug("Warning. Selection seems to contain invalid paths, e.g. pointy paths like M 54,54 Z. Please check and try again!")
exit(1)
npPts = [np[-1][-1][-1]]
if(len(orderPathIds) == 1):#compare both the ends for the first path
npPts.append(np[0][0][0])
@ -123,8 +126,10 @@ class JoinPaths(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--optimized", type=inkex.Boolean, default=True)
pars.add_argument("--margin", type=float, default=0.0100)
pars.add_argument("--add_dimples", type=inkex.Boolean, default=False)
pars.add_argument("--draw_dimple_centers", type=inkex.Boolean, default=False)
pars.add_argument("--draw_arcs_as_paths", type=inkex.Boolean, default=False)
pars.add_argument("--dimple_invert", type=inkex.Boolean, default=False)
pars.add_argument("--dimple_type", default="lines")
pars.add_argument("--dimples_to_group", type=inkex.Boolean, default=False)
@ -132,13 +137,21 @@ class JoinPaths(inkex.EffectExtension):
pars.add_argument("--dimple_height_mode", default="by_height")
pars.add_argument("--dimple_height", type=float, default=4)
pars.add_argument("--dimple_angle", type=float, default=45)
pars.add_argument("--dimple_tab_angle", type=float, default=45)
pars.add_argument("--dimple_gap_filter", type=inkex.Boolean, default=False)
pars.add_argument("--dimple_min_gap", type=float, default=1)
pars.add_argument("--dimple_max_gap", type=float, default=40)
pars.add_argument("--dimple_gap_filter_units", default="mm")
pars.add_argument("--dimple_height_units", default="mm")
pars.add_argument("--tab", default="sampling", help="Tab")
def effect(self):
selections = self.svg.selected
selections = self.svg.selected
if len(self.svg.selected) == 0:
self.msg('Please select some paths first.')
return
pathNodes = self.document.xpath('//svg:path',namespaces=inkex.NSS)
paths = {p.get('id'): getPartsFromCubicSuper(CubicSuperPath(p.get('d'))) for p in pathNodes }
paths = {p.get('id'): getPartsFromCubicSuper(CubicSuperPath(p.get('d'))) for p in pathNodes }
#paths.keys() Order disturbed
pathIds = [p.get('id') for p in pathNodes]
@ -163,7 +176,7 @@ class JoinPaths(inkex.EffectExtension):
newParts += parts[:]
firstElem = elem
else:
if(vectCmpWithMargin(start, newParts[-1][-1][-1], margin = .01)):
if(vectCmpWithMargin(start, newParts[-1][-1][-1], margin = self.options.margin)) and self.options.add_dimples is False:
newParts[-1] += parts[0]
else:
if self.options.add_dimples is True:
@ -179,20 +192,7 @@ class JoinPaths(inkex.EffectExtension):
newParts[-1].append([newParts[-1][-1][-1], newParts[-1][-1][-1], p2, p2])
newParts[-1] += parts[0]
#angle=self.options.dimple_angle
#p3 = rotate(midPoint, p2, math.radians(angle))
#p4 = rotate(midPoint, p2, math.radians(360-angle))
#add a new dimple
#line = self.svg.get_current_layer().add(inkex.PathElement(id=self.svg.get_unique_id('dimple')))
#line.set('d', "m{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], p3[0], p3[1]))
#line.style = {'stroke': '#000000', 'fill': 'none', 'stroke-width': str(self.svg.unittouu('1px'))}
#add a new dimple
#line = self.svg.get_current_layer().add(inkex.PathElement(id=self.svg.get_unique_id('dimple')))
#line.set('d', "m{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], p4[0], p4[1]))
#line.style = {'stroke': '#000000', 'fill': 'none', 'stroke-width': str(self.svg.unittouu('1px'))}
#get slope, distance and norm slope
dx = midPoint[0]-p1[0]
dy = midPoint[1]-p1[1]
dist = math.sqrt(dx*dx + dy*dy)
@ -202,97 +202,162 @@ class JoinPaths(inkex.EffectExtension):
dx2 = p2[0]-p1[0]
dy2 = p2[1]-p1[1]
dist2 = math.sqrt(dx2*dx2 + dy2*dy2)
if dx2 == 0:
slope=sys.float_info.max #vertical
else:
slope=(p2[1] - p1[1]) / dx2
slope_angle = 90 + math.degrees(math.atan(slope))
if self.options.dimple_height_mode == "by_height":
dimple_height = self.svg.unittouu(str(self.options.dimple_height) + self.options.dimple_height_units)
else:
dimple_height = dist * math.sin(math.radians(self.options.dimple_angle))
x3 = midPoint[0] + (dimple_height)*dy
y3 = midPoint[1] - (dimple_height)*dx
x4 = midPoint[0] - (dimple_height)*dy
y4 = midPoint[1] + (dimple_height)*dx
dimple_style = {'stroke': '#0000FF', 'fill': 'none', 'stroke-width': str(self.svg.unittouu('1px'))}
if self.options.draw_dimple_centers is True:
#add a new dimple center cross (4 segments)
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_perp1')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], x3, y3))
line.style = dimple_style
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_perp2')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], x4, y4))
line.style = dimple_style
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_join1')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(p1[0], p1[1], midPoint[0], midPoint[1]))
line.style = dimple_style
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_join1')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], p2[0], p2[1]))
line.style = dimple_style
if (self.options.dimple_gap_filter is True \
and dist2 >= self.svg.unittouu(str(self.options.dimple_min_gap) + self.options.dimple_gap_filter_units) \
and dist2 < self.svg.unittouu(str(self.options.dimple_max_gap) + self.options.dimple_gap_filter_units)
) \
or self.options.dimple_gap_filter is False:
if self.options.dimple_height_mode == "by_height":
dimple_height = self.svg.unittouu(str(self.options.dimple_height) + self.options.dimple_height_units)
else:
dimple_height = dist * math.sin(math.radians(self.options.dimple_angle))
x3 = midPoint[0] + (dimple_height)*dy
y3 = midPoint[1] - (dimple_height)*dx
x4 = midPoint[0] - (dimple_height)*dy
y4 = midPoint[1] + (dimple_height)*dx
dimple_style = {'stroke': '#0000FF', 'fill': 'none', 'stroke-width': str(self.svg.unittouu('1px'))}
if self.options.draw_dimple_centers is True:
#add a new dimple center cross (4 segments)
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_perp1')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], x3, y3))
line.style = dimple_style
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_perp2')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], x4, y4))
line.style = dimple_style
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_join1')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(p1[0], p1[1], midPoint[0], midPoint[1]))
line.style = dimple_style
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_center_join1')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(midPoint[0], midPoint[1], p2[0], p2[1]))
line.style = dimple_style
if self.options.dimple_type == "lines":
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_line')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(p1[0], p1[1], p2[0], p2[1]))
line.style = dimple_style
if self.options.dimple_type == "peaks":
if self.options.dimple_invert is True:
x5 = x3
y5 = y3
x3 = x4
y3 = y4
x4 = x5
y4 = y5
#add a new dimple center
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_peak')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(p1[0], p1[1], x3, y3, p2[0], p2[1]))
line.style = dimple_style
if self.options.draw_both_sides is True:
#add a new opposite dimple center
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_peak')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(p1[0], p1[1], x4, y4, p2[0], p2[1]))
line.style = dimple_style
if self.options.dimple_type == "lines":
if self.options.dimple_invert is True:
x5 = x3
y5 = y3
x3 = x4
y3 = y4
x4 = x5
y4 = y5
#add a new dimple center
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(p1[0], p1[1], x3, y3, p2[0], p2[1]))
line.style = dimple_style
if self.options.draw_both_sides is True:
#add a new opposite dimple center
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(p1[0], p1[1], x4, y4, p2[0], p2[1]))
line.style = dimple_style
else:
ellipse = dimpleGroup.add(inkex.Ellipse(id=self.svg.get_unique_id('dimple')))
ellipse.set('transform', "rotate({:0.6f} {:0.6f} {:0.6f})".format(slope_angle, midPoint[0], midPoint[1]))
ellipse.set('sodipodi:arc-type', "arc")
ellipse.set('sodipodi:type', "arc")
ellipse.set('sodipodi:cx', "{:0.6f}".format(midPoint[0]))
ellipse.set('sodipodi:cy', "{:0.6f}".format(midPoint[1]))
ellipse.set('sodipodi:rx', "{:0.6f}".format(dimple_height))
ellipse.set('sodipodi:ry', "{:0.6f}".format(dist2 / 2))
if self.options.dimple_invert is True:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(90.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(270.0)))
else:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(270.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(90.0)))
ellipse.style = dimple_style
if self.options.draw_both_sides is True:
ellipse = dimpleGroup.add(inkex.Ellipse(id=self.svg.get_unique_id('dimple')))
ellipse.set('transform', "rotate({:0.6f} {:0.6f} {:0.6f})".format(slope_angle, midPoint[0], midPoint[1]))
ellipse.set('sodipodi:arc-type', "arc")
ellipse.set('sodipodi:type', "arc")
ellipse.set('sodipodi:cx', "{:0.6f}".format(midPoint[0]))
ellipse.set('sodipodi:cy', "{:0.6f}".format(midPoint[1]))
ellipse.set('sodipodi:rx', "{:0.6f}".format(dimple_height))
ellipse.set('sodipodi:ry', "{:0.6f}".format(dist2 / 2))
if self.options.dimple_invert is True:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(270.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(90.0)))
else:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(90.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(270.0)))
ellipse.style = dimple_style
#cleanup groups
if len(dimpleGroup) == 1: ##move up child if group has only one child
for child in dimpleGroup:
dimpleGroup.getparent().insert(elem.getparent().index(elem), child)
dimpleGroup.delete() #delete the empty group now
elif self.options.dimple_type == "arcs":
if self.options.draw_arcs_as_paths is False:
ellipse = dimpleGroup.add(inkex.Ellipse(id=self.svg.get_unique_id('dimple_arc')))
ellipse.set('transform', "rotate({:0.6f} {:0.6f} {:0.6f})".format(slope_angle, midPoint[0], midPoint[1]))
ellipse.set('sodipodi:arc-type', "arc")
ellipse.set('sodipodi:type', "arc")
ellipse.set('sodipodi:cx', "{:0.6f}".format(midPoint[0]))
ellipse.set('sodipodi:cy', "{:0.6f}".format(midPoint[1]))
ellipse.set('sodipodi:rx', "{:0.6f}".format(dimple_height))
ellipse.set('sodipodi:ry', "{:0.6f}".format(dist2 / 2))
if self.options.dimple_invert is True:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(90.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(270.0)))
else:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(270.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(90.0)))
ellipse.style = dimple_style
if self.options.draw_both_sides is True:
ellipse = dimpleGroup.add(inkex.Ellipse(id=self.svg.get_unique_id('dimple_arc')))
ellipse.set('transform', "rotate({:0.6f} {:0.6f} {:0.6f})".format(slope_angle, midPoint[0], midPoint[1]))
ellipse.set('sodipodi:arc-type', "arc")
ellipse.set('sodipodi:type', "arc")
ellipse.set('sodipodi:cx', "{:0.6f}".format(midPoint[0]))
ellipse.set('sodipodi:cy', "{:0.6f}".format(midPoint[1]))
ellipse.set('sodipodi:rx', "{:0.6f}".format(dimple_height))
ellipse.set('sodipodi:ry', "{:0.6f}".format(dist2 / 2))
if self.options.dimple_invert is True:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(270.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(90.0)))
else:
ellipse.set('sodipodi:start', "{:0.6f}".format(math.radians(90.0)))
ellipse.set('sodipodi:end', "{:0.6f}".format(math.radians(270.0)))
ellipse.style = dimple_style
else: #if draw_arcs_as_paths is True
# +--- x-end point
# |
# counterclockwise ---+ | +--- y-end point
# | | |
#<path d="M 85 350 A 150 180 0 0 0 280 79" stroke="red" fill="none"/>
# | | | |
# 1 Radius x-Axis ---+ | | +--- 4 short / long way
# | |
# 2 Radius y-Axis ---+ +--- 3 Rotation x
if self.options.dimple_invert is True:
b1 = 1
b2 = 0
else:
b1 = 0
b2 = 1
ellipse = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_arc')))
ellipse.set('d', "M {:0.6f} {:0.6f} A {:0.6f} {:0.6f} {:0.6f} 0 {} {:0.6f} {:0.6f}".format(p1[0], p1[1], dimple_height, dist2 / 2, slope_angle, b1, p2[0], p2[1]))
ellipse.style = dimple_style
if self.options.draw_both_sides is True:
ellipse = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_arc')))
ellipse.set('d', "M {:0.6f} {:0.6f} A {:0.6f} {:0.6f} {:0.6f} 0 {} {:0.6f} {:0.6f}".format(p1[0], p1[1], dimple_height, dist2 / 2, slope_angle, b2, p2[0], p2[1]))
ellipse.style = dimple_style
elif self.options.dimple_type == "tabs":
pbottom1 = [p1[0] + (dimple_height)*dy, p1[1] - (dimple_height)*dx]
pbottom2 = [p2[0] + (dimple_height)*dy, p2[1] - (dimple_height)*dx]
ptop1 = [p1[0] - (dimple_height)*dy, p1[1] + (dimple_height)*dx]
ptop2 = [p2[0] - (dimple_height)*dy, p2[1] + (dimple_height)*dx]
l_hypo = dimple_height / (math.cos(math.radians(90.0 - self.options.dimple_tab_angle)))
pbottom1 = rotate(p1, [p1[0] + l_hypo * dx, p1[1] + l_hypo * dy], math.radians(-self.options.dimple_tab_angle))
pbottom2 = rotate(p2, [p2[0] - l_hypo * dx, p2[1] - l_hypo * dy], math.radians(-360.0 + self.options.dimple_tab_angle))
ptop1 = rotate(p1, [p1[0] + l_hypo * dx, p1[1] + l_hypo * dy], math.radians(self.options.dimple_tab_angle))
ptop2 = rotate(p2, [p2[0] - l_hypo * dx, p2[1] - l_hypo * dy], math.radians(360.0 - self.options.dimple_tab_angle))
if self.options.dimple_invert is True:
ptemp1 = pbottom1
ptemp2 = pbottom2
pbottom1 = ptop1
pbottom2 = ptop2
ptop1 = ptemp1
ptop2 = ptemp2
#add a new tab
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_tab')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(
p1[0], p1[1], pbottom1[0], pbottom1[1], pbottom2[0], pbottom2[1], p2[0], p2[1]))
line.style = dimple_style
if self.options.draw_both_sides is True:
line = dimpleGroup.add(inkex.PathElement(id=self.svg.get_unique_id('dimple_tab')))
line.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(
p1[0], p1[1], ptop1[0], ptop1[1], ptop2[0], ptop2[1], p2[0], p2[1]))
line.style = dimple_style
#cleanup groups
if len(dimpleGroup) == 1: ##move up child if group has only one child
for child in dimpleGroup:
dimpleGroup.getparent().insert(elem.getparent().index(elem), child)
dimpleGroup.delete() #delete the empty group now
else:
newParts[-1].append([newParts[-1][-1][-1], newParts[-1][-1][-1], start, start])

View File

@ -1,6 +1,6 @@
[
{
"name": "Join Paths / Create Dimples",
"name": "Join Paths / Create Tabs And Dimples",
"id": "fablabchemnitz.de.join_paths",
"path": "join_paths",
"original_name": "Join Paths Optimized",

View File

@ -0,0 +1,19 @@
[
{
"name": "Paths To Lowlevel Strokes",
"id": "fablabchemnitz.de.paths_to_lowlevel_strokes",
"path": "paths_to_lowlevel_strokes",
"original_name": "Paths To Lowlevel Strokes",
"original_id": "fablabchemnitz.de.paths_to_lowlevel_strokes",
"license": "GNU GPL v3",
"license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/LICENSE",
"comment": "Created by Mario Voigt",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/paths_to_strokes",
"fork_url": null,
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Paths+To+Lowlevel+Strokes",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/vmario89"
]
}
]

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Paths To Lowlevel Strokes</name>
<id>fablabchemnitz.de.paths_to_lowlevel_strokes</id>
<param name="flattenbezier" type="bool" gui-text="Quantization (flatten bezier curves to polylines)">true</param>
<param name="flatness" type="float" min="0.001" max="99999.000" precision="3" gui-text="Flatness (tolerance)" gui-description="Minimum flatness = 0.001. The smaller the value the more fine segments you will get.">0.100</param>
<param name="decimals" type="int" min="0" max="16" gui-text="Decimals" gui-description="Accuracy">3</param>
<param name="keep_style" type="bool" gui-text="Keep style">true</param>
<effect needs-live-preview="true">
<object-type>path</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Modify existing Path(s)"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">paths_to_lowlevel_strokes.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,118 @@
#!/usr/bin/env python3
from lxml import etree
import inkex
from inkex import bezier, PathElement
from inkex.paths import CubicSuperPath, Path
import copy
class PathsToStrokes(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--flattenbezier", type=inkex.Boolean, default=False, help="Flatten bezier curves to polylines")
pars.add_argument("--flatness", type=float, default=0.1, help="Minimum flatness = 0.1. The smaller the value the more fine segments you will get (quantization).")
pars.add_argument("--decimals", type=int, default=3)
pars.add_argument("--keep_style", type=inkex.Boolean, default=False)
def effect(self):
def flatten(node):
path = node.path.transform(node.composed_transform()).to_superpath()
bezier.cspsubdiv(path, self.options.flatness)
newpath = []
for subpath in path:
first = True
for csp in subpath:
cmd = 'L'
if first:
cmd = 'M'
first = False
newpath.append([cmd, [csp[1][0], csp[1][1]]])
node.path = newpath
def break_contours(element, breakelements = None):
if breakelements == None:
breakelements = []
if element.tag == inkex.addNS('path','svg'):
if self.options.flattenbezier is True:
flatten(element)
parent = element.getparent()
idx = parent.index(element)
idSuffix = 0
raw = element.path.to_arrays()
subPaths = []
prev = 0
for i in range(len(raw)): # Breaks compound paths into simple paths
if raw[i][0] == 'M' and i != 0:
subPath = raw[prev:i]
subPaths.append(Path(subPath))
prev = i
subPaths.append(Path(raw[prev:])) #finally add the last path
for subPath in subPaths:
replacedelement = copy.copy(element)
oldId = replacedelement.get('id')
csp = CubicSuperPath(subPath)
if len(subPath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
replacedelement.path = subPath
if len(subPaths) == 1:
replacedelement.set('id', oldId)
else:
replacedelement.set('id', oldId + str(idSuffix))
idSuffix += 1
parent.insert(idx, replacedelement)
breakelements.append(replacedelement)
element.delete()
for child in element.getchildren():
break_contours(child, breakelements)
return breakelements
if len(self.svg.selected) == 0:
elementsToWork = break_contours(self.document.getroot())
else:
elementsToWork = None
for element in self.svg.selected.values():
elementsToWork = break_contours(element, elementsToWork)
for element in elementsToWork:
oldId = element.get('id')
oldStyle = element.style
path = element.path.to_absolute().to_arrays() #to_arrays() is deprecated. How to make more modern?
pathIsClosed = False
if path[-1][0] == 'Z' or \
(path[-1][0] == 'L' and path[0][1] == path[-1][1]) or \
(path[-1][0] == 'C' and path[0][1] == [path[-1][1][-2], path[-1][1][-1]]) \
: #if first is last point the path is also closed. The "Z" command is not required
pathIsClosed = True
parent = element.getparent()
idx = parent.index(element)
element.delete()
if len(path) == 2 and pathIsClosed is False:
ll = inkex.Line(id=oldId)
ll.set('x1', '{:0.{dec}f}'.format(path[0][1][0], dec=self.options.decimals))
ll.set('y1', '{:0.{dec}f}'.format(path[0][1][1], dec=self.options.decimals))
ll.set('x2', '{:0.{dec}f}'.format(path[1][1][0], dec=self.options.decimals))
ll.set('y2', '{:0.{dec}f}'.format(path[1][1][1], dec=self.options.decimals))
if len(path) > 2 and pathIsClosed is False:
ll = inkex.Polyline(id=oldId)
points = ""
for i in range(0, len(path)):
points += '{:0.{dec}f},{:0.{dec}f} '.format(path[i][1][0], path[i][1][1], dec=self.options.decimals)
ll.set('points', points)
if len(path) > 2 and pathIsClosed is True:
ll = inkex.Polygon(id=oldId)
points = ""
for i in range(0, len(path) - 1):
points += '{:0.{dec}f},{:0.{dec}f} '.format(path[i][1][0], path[i][1][1], dec=self.options.decimals)
ll.set('points', points)
if self.options.keep_style is True:
ll.style = oldStyle
else:
ll.style = "fill:none;stroke:#0000FF;stroke-width:" + str(self.svg.unittouu("1px"))
parent.insert(idx, ll)
if __name__ == '__main__':
PathsToStrokes().run()

View File

@ -5,6 +5,7 @@
<param name="tab" type="notebook">
<page name="tab_settings" gui-text="Settings">
<param name="separateby" gui-text="Separate by" type="optiongroup" appearance="combo">
<option value="element_tag">Element tag</option>
<option value="stroke">Stroke color</option>
<option value="stroke_width">Stroke width</option>
<option value="stroke_hairline">Stroke hairline</option>

View File

@ -8,7 +8,7 @@ Features
Author: Mario Voigt / FabLab Chemnitz
Mail: mario.voigt@stadtfabrikanten.org
Date: 19.08.2020
Last patch: 11.04.2021
Last patch: 17.10.2021
License: GNU GPL v3
"""
import inkex
@ -115,7 +115,11 @@ class StylesToLayers(inkex.EffectExtension):
#the Styles to Layers extension still might brick the gradients (some tests failed)
if style and element.tag != inkex.addNS('stop','svg') and element.tag != inkex.addNS('tspan','svg'):
if self.options.separateby == "stroke":
if self.options.separateby == "element_tag":
neutral_value = 1
layer_name = "element_tag-" + element.tag.replace("{http://www.w3.org/2000/svg}", "")
elif self.options.separateby == "stroke":
stroke = re.search('(;|^)stroke:(.*?)(;|$)', style)
if stroke is not None:
stroke = stroke[0]
@ -287,12 +291,18 @@ class StylesToLayers(inkex.EffectExtension):
for newLayerNode in topLevelLayerNodeList:
newLayerNode[0].append(newLayerNode[1]) #append newlayer to layer
#clean all empty layers from node list. Please note that the following remove_empty_groups
#call does not apply for this so we need to do it as PREVIOUS step before!
for i in range(0, len(layerNodeList)):
if len(layerNodeList[i][0]) == 0:
layerNodeList[i][0].getparent().remove(layerNodeList[i][0])
if self.options.cleanup == True:
try:
import remove_empty_groups
remove_empty_groups.RemoveEmptyGroups.effect(self)
except:
self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...")
if __name__ == '__main__':
StylesToLayers().run()

View File

@ -5,7 +5,7 @@
<param name="tab" type="notebook">
<page name="tab_settings" gui-text="Unwind Paths">
<label appearance="header">General Settings</label>
<param name="keep_original" type="bool" gui-text="Keep original paths" gui-description="If selected, the original paths get deleted">false</param>
<param name="keep_original" type="bool" gui-text="Keep original paths" gui-description="If not selected, the original paths get deleted">false</param>
<param name="break_apart" type="bool" gui-text="Break apart paths" gui-description="Split each path into single curve segments">false</param>
<param name="break_only" type="bool" gui-text="Break apart paths only" gui-description="No unwinding at all">false</param>
<label appearance="header">Color Style</label>

View File

@ -39,7 +39,7 @@ class UnwindPaths(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument('--tab')
pars.add_argument('--keep_original', type=inkex.Boolean, default=False, help="If selected, the original paths get deleted")
pars.add_argument('--keep_original', type=inkex.Boolean, default=False, help="If not selected, the original paths get deleted")
pars.add_argument('--break_apart', type=inkex.Boolean, default=False, help="Split each path into single curve segments")
pars.add_argument('--break_only', type=inkex.Boolean, default=False, help="Only splits root paths into segments (no unwinding)")
pars.add_argument('--colorize', type=inkex.Boolean, default=False, help="Colorize original paths and glue pairs")
@ -73,9 +73,12 @@ class UnwindPaths(inkex.EffectExtension):
csp = CubicSuperPath(subpath)
if len(subpath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
replacedelement.set('d', csp)
replacedelement.set('id', oldId + str(idSuffix))
if len(subPaths) == 1:
replacedelement.set('id', oldId)
else:
replacedelement.set('id', oldId + str(idSuffix))
idSuffix += 1
parent.insert(idx, replacedelement)
idSuffix += 1
breakelements.append(replacedelement)
parent.remove(element)
else:
@ -228,7 +231,7 @@ class UnwindPaths(inkex.EffectExtension):
self.drawline(d, "segmented-" + element.get('id'), newOriginalPathGroup, new_original_line_style)
if self.options.keep_original is False:
element.delete()
element.delete()
else:
self.msg('Please select some paths first.')