diff --git a/extensions/fablabchemnitz/braille-l18n/braille-l18n.inx b/extensions/fablabchemnitz/braille_l18n/braille_l18n.inx
similarity index 86%
rename from extensions/fablabchemnitz/braille-l18n/braille-l18n.inx
rename to extensions/fablabchemnitz/braille_l18n/braille_l18n.inx
index 92ad17c9..e36574e0 100644
--- a/extensions/fablabchemnitz/braille-l18n/braille-l18n.inx
+++ b/extensions/fablabchemnitz/braille_l18n/braille_l18n.inx
@@ -1,7 +1,7 @@
Convert To Localized Braille
- fablabchemnitz.de.braille-l18n
+ fablabchemnitz.de.braille_l18n
@@ -20,6 +20,6 @@
\ No newline at end of file
diff --git a/extensions/fablabchemnitz/braille-l18n/braille-l18n.py b/extensions/fablabchemnitz/braille_l18n/braille_l18n.py
similarity index 100%
rename from extensions/fablabchemnitz/braille-l18n/braille-l18n.py
rename to extensions/fablabchemnitz/braille_l18n/braille_l18n.py
diff --git a/extensions/fablabchemnitz/braille-l18n/meta.json b/extensions/fablabchemnitz/braille_l18n/meta.json
similarity index 91%
rename from extensions/fablabchemnitz/braille-l18n/meta.json
rename to extensions/fablabchemnitz/braille_l18n/meta.json
index 5a66fb74..57eb291d 100644
--- a/extensions/fablabchemnitz/braille-l18n/meta.json
+++ b/extensions/fablabchemnitz/braille_l18n/meta.json
@@ -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",
diff --git a/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py b/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py
index c19d9fee..e3e45c0a 100644
--- a/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py
+++ b/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py
@@ -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():
diff --git a/extensions/fablabchemnitz/create_links/create_links.inx b/extensions/fablabchemnitz/create_links/create_links.inx
index c17a30f3..85f08dc3 100644
--- a/extensions/fablabchemnitz/create_links/create_links.inx
+++ b/extensions/fablabchemnitz/create_links/create_links.inx
@@ -20,7 +20,6 @@
-
@@ -44,7 +43,6 @@
-
@@ -52,7 +50,7 @@
false
false
- false
+ true
false
false
diff --git a/extensions/fablabchemnitz/create_links/create_links.py b/extensions/fablabchemnitz/create_links/create_links.py
index 351942f5..d432e28f 100644
--- a/extensions/fablabchemnitz/create_links/create_links.py
+++ b/extensions/fablabchemnitz/create_links/create_links.py
@@ -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)
diff --git a/extensions/fablabchemnitz/grey_to_monoalpha/grey_to_monoalpha.inx b/extensions/fablabchemnitz/grey_to_monoalpha/grey_to_monoalpha.inx
new file mode 100644
index 00000000..54d39779
--- /dev/null
+++ b/extensions/fablabchemnitz/grey_to_monoalpha/grey_to_monoalpha.inx
@@ -0,0 +1,48 @@
+
+
+ Grey to MonoAlpha
+ fablabchemnitz.de.grey_to_monoalpha
+
+
+
+
+ 0x000000ff
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ path
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/fablabchemnitz/grey_to_monoalpha/grey_to_monoalpha.py b/extensions/fablabchemnitz/grey_to_monoalpha/grey_to_monoalpha.py
new file mode 100644
index 00000000..1bbe1ae4
--- /dev/null
+++ b/extensions/fablabchemnitz/grey_to_monoalpha/grey_to_monoalpha.py
@@ -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()
diff --git a/extensions/fablabchemnitz/grey_to_monoalpha/meta.json b/extensions/fablabchemnitz/grey_to_monoalpha/meta.json
new file mode 100644
index 00000000..9c32922e
--- /dev/null
+++ b/extensions/fablabchemnitz/grey_to_monoalpha/meta.json
@@ -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"
+ ]
+ }
+]
\ No newline at end of file
diff --git a/extensions/fablabchemnitz/join_paths/join_paths.inx b/extensions/fablabchemnitz/join_paths/join_paths.inx
index 46ec34bb..0e263103 100644
--- a/extensions/fablabchemnitz/join_paths/join_paths.inx
+++ b/extensions/fablabchemnitz/join_paths/join_paths.inx
@@ -1,38 +1,95 @@
- Join Paths / Create Dimples
+ Join Paths / Create Tabs And Dimples
fablabchemnitz.de.join_paths
-
- true
-
-
- false
-
-
-
-
- false
- false
- false
-
-
-
-
- 45.000
- 4.000
-
-
-
-
-
-
-
- false
+
+
+
+
+ true
+ 0.0100
+
+
+
+ false
+ false
+
+
+
+
+
+
+ false
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+ 45.000
+ 4.000
+ 45.000
+
+
+
+
+
+
+
+
+
+ false
+ 1
+ 40
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ../000_about_fablabchemnitz.svg
diff --git a/extensions/fablabchemnitz/join_paths/join_paths.py b/extensions/fablabchemnitz/join_paths/join_paths.py
index d500bb25..087fd7c9 100644
--- a/extensions/fablabchemnitz/join_paths/join_paths.py
+++ b/extensions/fablabchemnitz/join_paths/join_paths.py
@@ -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
+ # | | |
+ #
+ # | | | |
+ # 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])
diff --git a/extensions/fablabchemnitz/join_paths/meta.json b/extensions/fablabchemnitz/join_paths/meta.json
index cf2e3771..8e0e02f0 100644
--- a/extensions/fablabchemnitz/join_paths/meta.json
+++ b/extensions/fablabchemnitz/join_paths/meta.json
@@ -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",
diff --git a/extensions/fablabchemnitz/paths_to_lowlevel_strokes/meta.json b/extensions/fablabchemnitz/paths_to_lowlevel_strokes/meta.json
new file mode 100644
index 00000000..28ca7913
--- /dev/null
+++ b/extensions/fablabchemnitz/paths_to_lowlevel_strokes/meta.json
@@ -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"
+ ]
+ }
+]
\ No newline at end of file
diff --git a/extensions/fablabchemnitz/paths_to_lowlevel_strokes/paths_to_lowlevel_strokes.inx b/extensions/fablabchemnitz/paths_to_lowlevel_strokes/paths_to_lowlevel_strokes.inx
new file mode 100644
index 00000000..1b7ce685
--- /dev/null
+++ b/extensions/fablabchemnitz/paths_to_lowlevel_strokes/paths_to_lowlevel_strokes.inx
@@ -0,0 +1,20 @@
+
+
+ Paths To Lowlevel Strokes
+ fablabchemnitz.de.paths_to_lowlevel_strokes
+ true
+ 0.100
+ 3
+ true
+
+ path
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/fablabchemnitz/paths_to_lowlevel_strokes/paths_to_lowlevel_strokes.py b/extensions/fablabchemnitz/paths_to_lowlevel_strokes/paths_to_lowlevel_strokes.py
new file mode 100644
index 00000000..9d9489ef
--- /dev/null
+++ b/extensions/fablabchemnitz/paths_to_lowlevel_strokes/paths_to_lowlevel_strokes.py
@@ -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()
\ No newline at end of file
diff --git a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx
index c480fe8b..168e516c 100644
--- a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx
+++ b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx
@@ -5,6 +5,7 @@
+
diff --git a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py
index cc055605..ac63536c 100644
--- a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py
+++ b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py
@@ -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()
\ No newline at end of file
diff --git a/extensions/fablabchemnitz/unwind_paths/unwind_paths.inx b/extensions/fablabchemnitz/unwind_paths/unwind_paths.inx
index ad2bc66c..e698177e 100644
--- a/extensions/fablabchemnitz/unwind_paths/unwind_paths.inx
+++ b/extensions/fablabchemnitz/unwind_paths/unwind_paths.inx
@@ -5,7 +5,7 @@
- false
+ false
false
false
diff --git a/extensions/fablabchemnitz/unwind_paths/unwind_paths.py b/extensions/fablabchemnitz/unwind_paths/unwind_paths.py
index 85dfb564..046ed252 100644
--- a/extensions/fablabchemnitz/unwind_paths/unwind_paths.py
+++ b/extensions/fablabchemnitz/unwind_paths/unwind_paths.py
@@ -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.')