added purge pointy paths extension
This commit is contained in:
parent
1264a864bc
commit
8fcc0cbf64
@ -36,8 +36,8 @@ class DrawBBoxes(inkex.EffectExtension):
|
|||||||
def effect(self):
|
def effect(self):
|
||||||
if len(self.svg.selected) > 0:
|
if len(self.svg.selected) > 0:
|
||||||
if self.options.split is False:
|
if self.options.split is False:
|
||||||
for id, item in self.svg.selected.items():
|
for element in self.svg.selected.values():
|
||||||
self.drawBBox(item.bounding_box())
|
self.drawBBox(element.bounding_box())
|
||||||
else:
|
else:
|
||||||
#self.drawBBox(self.svg.get_selected_bbox()) #works for InkScape (1:1.0+devel+202008292235+eff2292935) @ Linux and for Windows (but with deprecation)
|
#self.drawBBox(self.svg.get_selected_bbox()) #works for InkScape (1:1.0+devel+202008292235+eff2292935) @ Linux and for Windows (but with deprecation)
|
||||||
self.drawBBox(self.svg.selection.bounding_box()) #works for InkScape 1.1dev (9b1fc87, 2020-08-27)) @ Windows
|
self.drawBBox(self.svg.selection.bounding_box()) #works for InkScape 1.1dev (9b1fc87, 2020-08-27)) @ Windows
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
#
|
#
|
||||||
# Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org
|
# Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org
|
||||||
@ -139,7 +139,7 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
if self.options.switch_pattern is True:
|
if self.options.switch_pattern is True:
|
||||||
dashes = dashes[::-1] #reverse the array
|
dashes = dashes[::-1] #reverse the array
|
||||||
|
|
||||||
#validate dashes. May not be negative. Otherwise Inkscape will freeze forever. Reason: rendering issue
|
#validate dashes. May not be negative (dash or gap cannot be longer than the path itself). Otherwise Inkscape will freeze forever. Reason: rendering issue
|
||||||
if any(dash <= 0.0 for dash in dashes) == True:
|
if any(dash <= 0.0 for dash in dashes) == True:
|
||||||
if self.options.show_info is True: self.msg("node " + node.get('id') + ": Error! Dash array may not contain negative numbers: " + ' '.join(format(dash, "1.3f") for dash in dashes) + ". Path skipped. Maybe it's too short. Adjust your link count, multiplicator and length accordingly, or set to unit '%'")
|
if self.options.show_info is True: self.msg("node " + node.get('id') + ": Error! Dash array may not contain negative numbers: " + ' '.join(format(dash, "1.3f") for dash in dashes) + ". Path skipped. Maybe it's too short. Adjust your link count, multiplicator and length accordingly, or set to unit '%'")
|
||||||
return False if self.options.skip_errors is True else exit(1)
|
return False if self.options.skip_errors is True else exit(1)
|
||||||
@ -267,8 +267,7 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
dash = dash - length
|
dash = dash - length
|
||||||
length = bezier.cspseglength(new[-1][-1], sub[i])
|
length = bezier.cspseglength(new[-1][-1], sub[i])
|
||||||
while dash < length:
|
while dash < length:
|
||||||
new[-1][-1], nxt, sub[i] = \
|
new[-1][-1], nxt, sub[i] = bezier.cspbezsplitatlength(new[-1][-1], sub[i], dash/length)
|
||||||
bezier.cspbezsplitatlength(new[-1][-1], sub[i], dash/length)
|
|
||||||
if idash % 2: # create a gap
|
if idash % 2: # create a gap
|
||||||
new.append([nxt[:]])
|
new.append([nxt[:]])
|
||||||
else: # splice the curve
|
else: # splice the curve
|
||||||
@ -283,22 +282,44 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
i += 1
|
i += 1
|
||||||
style.pop('stroke-dasharray')
|
style.pop('stroke-dasharray')
|
||||||
node.pop('sodipodi:type')
|
node.pop('sodipodi:type')
|
||||||
|
csp = CubicSuperPath(new)
|
||||||
node.path = CubicSuperPath(new)
|
node.path = CubicSuperPath(new)
|
||||||
node.style = style
|
node.style = style
|
||||||
|
|
||||||
# break apart the combined path to have multiple elements
|
# break apart the combined path to have multiple elements
|
||||||
if self.options.breakapart is True:
|
if self.options.breakapart is True:
|
||||||
breakOutputNodes = self.breakContours(node)
|
breakOutputNodes = None
|
||||||
|
breakOutputNodes = self.breakContours(node, breakOutputNodes)
|
||||||
breakApartGroup = nodeParent.add(inkex.Group())
|
breakApartGroup = nodeParent.add(inkex.Group())
|
||||||
for breakOutputNode in breakOutputNodes:
|
for breakOutputNode in breakOutputNodes:
|
||||||
breakApartGroup.append(breakOutputNode)
|
breakApartGroup.append(breakOutputNode)
|
||||||
#self.msg(replacedNode.get('id'))
|
#self.msg(replacedNode.get('id'))
|
||||||
#self.svg.selection.set(replacedNode.get('id')) #update selection to split paths segments (does not work, so commented out)
|
#self.svg.selection.set(replacedNode.get('id')) #update selection to split paths segments (does not work, so commented out)
|
||||||
|
|
||||||
|
#cleanup useless points
|
||||||
|
p = breakOutputNode.path
|
||||||
|
commandsCoords = p.to_arrays()
|
||||||
|
# "m 45.250809,91.692739" - this path contains onyl one command - a single point
|
||||||
|
if len(commandsCoords) == 1:
|
||||||
|
breakOutputNode.delete()
|
||||||
|
# "m 45.250809,91.692739 z" - this path contains two commands, but only one coordinate.
|
||||||
|
# It's a single point, the path is closed by a Z command
|
||||||
|
elif len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]:
|
||||||
|
breakOutputNode.delete()
|
||||||
|
# "m 45.250809,91.692739 l 45.250809,91.692739" - this path contains two commands,
|
||||||
|
# but the first and second coordinate are the same. It will render als point
|
||||||
|
elif len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z':
|
||||||
|
breakOutputNode.delete()
|
||||||
|
# "m 45.250809,91.692739 l 45.250809,91.692739 z" - this path contains three commands,
|
||||||
|
# but the first and second coordinate are the same. It will render als point, the path is closed by a Z command
|
||||||
|
elif len(commandsCoords) == 3 and commandsCoords[0][1] == commandsCoords[1][1] and commandsCoords[2][1] == 'Z':
|
||||||
|
breakOutputNode.delete()
|
||||||
|
|
||||||
if len(self.svg.selected) > 0:
|
if len(self.svg.selected) > 0:
|
||||||
for node in self.svg.selection.values():
|
for node in self.svg.selection.values():
|
||||||
#at first we need to break down combined nodes to single path, otherwise dasharray cannot properly be applied
|
#at first we need to break down combined nodes to single path, otherwise dasharray cannot properly be applied
|
||||||
breakInputNodes = self.breakContours(node)
|
breakInputNodes = None
|
||||||
|
breakInputNodes = self.breakContours(node, breakInputNodes)
|
||||||
for breakInputNode in breakInputNodes:
|
for breakInputNode in breakInputNodes:
|
||||||
createLinks(breakInputNode)
|
createLinks(breakInputNode)
|
||||||
else:
|
else:
|
||||||
|
16
extensions/fablabchemnitz/purge_pointy_paths.inx
Normal file
16
extensions/fablabchemnitz/purge_pointy_paths.inx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<name>Purge Pointy Paths</name>
|
||||||
|
<id>fablabchemnitz.de.purge_pointy_paths</id>
|
||||||
|
<effect>
|
||||||
|
<object-type>path</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu name="FabLab Chemnitz">
|
||||||
|
<submenu name="Nesting/Cut Optimization"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command location="inx" interpreter="python">purge_pointy_paths.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
49
extensions/fablabchemnitz/purge_pointy_paths.py
Normal file
49
extensions/fablabchemnitz/purge_pointy_paths.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
This filter deletes paths which render as point only
|
||||||
|
|
||||||
|
More usesless and/or redundant filters for removing duplicate nodes and segments are provided by the following extension:
|
||||||
|
- https://stadtfabrikanten.org/display/IFM/Purge+Duplicate+Path+Segments
|
||||||
|
- https://stadtfabrikanten.org/display/IFM/Purge+Duplicate+Path+Nodes
|
||||||
|
|
||||||
|
Extension for InkScape 1.X
|
||||||
|
Author: Mario Voigt / FabLab Chemnitz
|
||||||
|
Mail: mario.voigt@stadtfabrikanten.org
|
||||||
|
Date: 21.04.2021
|
||||||
|
Last patch: 21.04.2021
|
||||||
|
License: GNU GPL v3
|
||||||
|
"""
|
||||||
|
|
||||||
|
import inkex
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
class PurgeInvalidPaths(inkex.EffectExtension):
|
||||||
|
|
||||||
|
def effect(self):
|
||||||
|
if len(self.svg.selected) > 0:
|
||||||
|
for element in self.svg.selected.values():
|
||||||
|
if isinstance(element, inkex.PathElement):
|
||||||
|
p = element.path
|
||||||
|
commandsCoords = p.to_arrays()
|
||||||
|
# "m 45.250809,91.692739" - this path contains onyl one command - a single point
|
||||||
|
if len(commandsCoords) == 1:
|
||||||
|
element.delete()
|
||||||
|
# "m 45.250809,91.692739 z" - this path contains two commands, but only one coordinate.
|
||||||
|
# It's a single point, the path is closed by a Z command
|
||||||
|
elif len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]:
|
||||||
|
element.delete()
|
||||||
|
# "m 45.250809,91.692739 l 45.250809,91.692739" - this path contains two commands,
|
||||||
|
# but the first and second coordinate are the same. It will render als point
|
||||||
|
elif len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z':
|
||||||
|
element.delete()
|
||||||
|
# "m 45.250809,91.692739 l 45.250809,91.692739 z" - this path contains three commands,
|
||||||
|
# but the first and second coordinate are the same. It will render als point, the path is closed by a Z command
|
||||||
|
elif len(commandsCoords) == 3 and commandsCoords[0][1] == commandsCoords[1][1] and commandsCoords[2][1] == 'Z':
|
||||||
|
element.delete()
|
||||||
|
else:
|
||||||
|
inkex.errormsg('Please select some objects first.')
|
||||||
|
return
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
PurgeInvalidPaths().run()
|
@ -59,9 +59,9 @@ class RemoveRedundant(inkex.EffectExtension):
|
|||||||
seenSegments = set()
|
seenSegments = set()
|
||||||
coordsCache = FixedRadiusSearch()
|
coordsCache = FixedRadiusSearch()
|
||||||
|
|
||||||
for id, node in self.svg.selected.items():
|
for element in self.svg.selected.values():
|
||||||
if node.tag == inkex.addNS('path','svg'):
|
if element.tag == inkex.addNS('path','svg'):
|
||||||
d = node.get('d')
|
d = element.get('d')
|
||||||
path = paths.CubicSuperPath(d).to_path().to_arrays()
|
path = paths.CubicSuperPath(d).to_path().to_arrays()
|
||||||
newPath = []
|
newPath = []
|
||||||
start = prev = None
|
start = prev = None
|
||||||
@ -117,7 +117,7 @@ class RemoveRedundant(inkex.EffectExtension):
|
|||||||
newPath.append([command, coords])
|
newPath.append([command, coords])
|
||||||
while len(newPath) and newPath[-1][0] == 'M':
|
while len(newPath) and newPath[-1][0] == 'M':
|
||||||
newPath = newPath[:-1]
|
newPath = newPath[:-1]
|
||||||
node.set('d',str(paths.Path(newPath)))
|
element.set('d',str(paths.Path(newPath)))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
RemoveRedundant().run()
|
RemoveRedundant().run()
|
Reference in New Issue
Block a user