reworked unwind_paths
This commit is contained in:
parent
a4513bbe32
commit
165e5b6067
@ -1,146 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# coding=utf-8
|
|
||||||
#
|
|
||||||
# Copyright (C) [2021] [Joseph Zakar], [observing@gmail.com]
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
"""
|
|
||||||
For each selected path element, this extension creates an additional path element
|
|
||||||
consisting of horizontal line segments which are the same size as the original
|
|
||||||
line segments.
|
|
||||||
|
|
||||||
17.05.2021: Mario Voigt: added option to extrude as a band (add height; adds vertical lines and another horizontal path)
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import inkex
|
|
||||||
from lxml import etree
|
|
||||||
import math
|
|
||||||
|
|
||||||
class HLines(inkex.EffectExtension):
|
|
||||||
|
|
||||||
def add_arguments(self, pars):
|
|
||||||
pars.add_argument('--extrude', type=inkex.Boolean, default=False)
|
|
||||||
pars.add_argument('--extrude_height', type=float, default=10.000)
|
|
||||||
pars.add_argument('--unit', default="mm")
|
|
||||||
|
|
||||||
#draw an SVG line segment between the given (raw) points
|
|
||||||
def drawline(self, pathData, name, parent):
|
|
||||||
line_style = {'stroke':'#000000','stroke-width':'1px','fill':'none'}
|
|
||||||
line_attribs = {'style' : str(inkex.Style(line_style)),
|
|
||||||
inkex.addNS('label','inkscape') : name,
|
|
||||||
'd' : pathData}
|
|
||||||
line = etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
|
|
||||||
|
|
||||||
def effect(self):
|
|
||||||
path_num = 0
|
|
||||||
#for elem in self.svg.get_selected(): # for each selected element (Ver. 1.0)
|
|
||||||
for elem in self.svg.selection.filter(inkex.PathElement).values(): # for each selected element (Ver. 1.02+)
|
|
||||||
#inkex.utils.debug(type(elem))
|
|
||||||
#inkex.utils.debug(elem.bounding_box())
|
|
||||||
#inkex.utils.debug(elem.path)
|
|
||||||
elemGroup = self.svg.get_current_layer().add(inkex.Group(id="unwinding-" + elem.get('id'))) #make a new group at root level
|
|
||||||
if elem.typename == 'PathElement': # Only process path elements
|
|
||||||
xbound,ybound = elem.bounding_box() # Get bounds of this element
|
|
||||||
xmin,xmax = xbound
|
|
||||||
ymin,ymax = ybound
|
|
||||||
ntotal = len(elem.path)
|
|
||||||
nodecnt = 0
|
|
||||||
startx = 0
|
|
||||||
starty = ymax + 10
|
|
||||||
endx = 0
|
|
||||||
endy = starty
|
|
||||||
xoffset = 0
|
|
||||||
orig_sx = 0
|
|
||||||
orig_sy = 0
|
|
||||||
orig_ex = 0
|
|
||||||
orig_ey = 0
|
|
||||||
sx1 = 0
|
|
||||||
sy1 = 0
|
|
||||||
orig_length = 0
|
|
||||||
last_letter = 'M'
|
|
||||||
TopCommandSet = ""
|
|
||||||
DownCommandSet = ""
|
|
||||||
shifting = self.svg.unittouu(str(self.options.extrude_height) + self.options.unit)
|
|
||||||
for ptoken in elem.path.to_absolute(): # For each point in the path
|
|
||||||
#inkex.utils.debug(type(ptoken))
|
|
||||||
#inkex.utils.debug(ptoken)
|
|
||||||
startx = xmin + xoffset
|
|
||||||
if ptoken.letter == 'M': # Starting a new line
|
|
||||||
orig_sx = ptoken.x
|
|
||||||
orig_sy = ptoken.y
|
|
||||||
TopCommandSet = 'M {:0.6f},{:0.6f}'.format(startx, starty)
|
|
||||||
DownCommandSet = 'M {:0.6f},{:0.6f}'.format(startx, starty + shifting)
|
|
||||||
sx1 = orig_sx
|
|
||||||
sy1 = orig_sy
|
|
||||||
if self.options.extrude is True:
|
|
||||||
self.drawline("M {:0.6f},{:0.6f} L {:0.6f},{:0.6f}".format(sx1, endy, sx1 , endy + shifting),"vline{0}".format(path_num), elemGroup)
|
|
||||||
else:
|
|
||||||
if last_letter != 'M':
|
|
||||||
orig_sx = orig_ex
|
|
||||||
orig_sy = orig_ey
|
|
||||||
|
|
||||||
if ptoken.letter == 'L':
|
|
||||||
orig_ex = ptoken.x
|
|
||||||
orig_ey = ptoken.y
|
|
||||||
orig_length = math.sqrt((orig_sx-orig_ex)**2 + (orig_sy-orig_ey)**2)
|
|
||||||
endx = startx + orig_length
|
|
||||||
TopCommandSet = TopCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy)
|
|
||||||
DownCommandSet = DownCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy + shifting)
|
|
||||||
elif ptoken.letter == 'H':
|
|
||||||
if last_letter == 'M':
|
|
||||||
orig_ey = orig_sy
|
|
||||||
orig_length = abs(orig_sx - ptoken.x)
|
|
||||||
orig_ex = ptoken.x
|
|
||||||
endx = startx + orig_length
|
|
||||||
TopCommandSet = TopCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy)
|
|
||||||
DownCommandSet = DownCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy + shifting)
|
|
||||||
elif ptoken.letter == 'V':
|
|
||||||
if last_letter == 'M':
|
|
||||||
orig_ex = orig_sx
|
|
||||||
orig_length = abs(orig_sy - ptoken.y)
|
|
||||||
orig_ey = ptoken.y
|
|
||||||
endx = startx + orig_length
|
|
||||||
TopCommandSet = TopCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy)
|
|
||||||
DownCommandSet = DownCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy + shifting)
|
|
||||||
elif ptoken.letter == 'Z':
|
|
||||||
orig_ex = sx1
|
|
||||||
orig_ey = sy1
|
|
||||||
orig_length = math.sqrt((orig_sx-orig_ex)**2 + (orig_sy-orig_ey)**2)
|
|
||||||
endx = startx + orig_length
|
|
||||||
TopCommandSet = TopCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy)
|
|
||||||
DownCommandSet = DownCommandSet + ' L {:0.6f},{:0.6f}'.format(endx, endy + shifting)
|
|
||||||
else:
|
|
||||||
inkex.utils.debug("Unknown letter - {0}".format(ptoken.letter))
|
|
||||||
inkex.utils.debug("Path may not contain bezier type commands. Convert to polyline before!")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if self.options.extrude is True:
|
|
||||||
self.drawline("M {:0.6f},{:0.6f} L {:0.6f},{:0.6f}".format(endx, endy, endx , endy + shifting),"vline{0}".format(path_num), elemGroup)
|
|
||||||
|
|
||||||
nodecnt = nodecnt + 1
|
|
||||||
if ptoken.letter != 'M':
|
|
||||||
if nodecnt == ntotal:
|
|
||||||
self.drawline(TopCommandSet,"hline{0}".format(path_num), elemGroup)
|
|
||||||
if self.options.extrude is True:
|
|
||||||
self.drawline(DownCommandSet,"hline{0}".format(path_num), elemGroup)
|
|
||||||
|
|
||||||
path_num = path_num + 1
|
|
||||||
xoffset = xoffset + orig_length
|
|
||||||
last_letter = ptoken.letter
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
HLines().run()
|
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
<name>Unwind Paths (Hlines)</name>
|
<name>Unwind Paths</name>
|
||||||
<id>fablabchemnitz.de.hlines</id>
|
<id>fablabchemnitz.de.unwind_paths</id>
|
||||||
<param name="extrude" type="bool" gui-text="Extrude">false</param>
|
<param name="extrude" type="bool" gui-text="Extrude">false</param>
|
||||||
<param name="extrude_height" type="float" min="0.000" max="99999.000" precision="3" gui-text="Extrude height">10.000</param>
|
<param name="extrude_height" type="float" min="0.000" max="99999.000" precision="3" gui-text="Extrude height">10.000</param>
|
||||||
<param name="unit" gui-text="Unit" type="optiongroup" appearance="combo">
|
<param name="unit" gui-text="Unit" type="optiongroup" appearance="combo">
|
||||||
@ -21,6 +21,6 @@
|
|||||||
</effects-menu>
|
</effects-menu>
|
||||||
</effect>
|
</effect>
|
||||||
<script>
|
<script>
|
||||||
<command location="inx" interpreter="python">hlines.py</command>
|
<command location="inx" interpreter="python">unwind_paths.py</command>
|
||||||
</script>
|
</script>
|
||||||
</inkscape-extension>
|
</inkscape-extension>
|
77
extensions/fablabchemnitz/unwind_paths/unwind_paths.py
Normal file
77
extensions/fablabchemnitz/unwind_paths/unwind_paths.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
For each selected path element, this extension creates an additional path element
|
||||||
|
consisting of horizontal line segments which are the same size as the original
|
||||||
|
line segments. Has option to extrude as a band (add height; adds vertical lines and another horizontal path)
|
||||||
|
|
||||||
|
ToDo:
|
||||||
|
- option to colorize each line segment of the original curve (we need to split and group the original one to do this). We map the colors to the unwinded paths
|
||||||
|
- handle combined paths correctly
|
||||||
|
- copy style of input paths and only apply new colors
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import inkex
|
||||||
|
from inkex import bezier
|
||||||
|
from lxml import etree
|
||||||
|
import math
|
||||||
|
|
||||||
|
class UnwindPaths(inkex.EffectExtension):
|
||||||
|
|
||||||
|
#draw an SVG line segment between the given (raw) points
|
||||||
|
def drawline(self, pathData, name, parent):
|
||||||
|
line_style = {'stroke':'#000000','stroke-width':'1px','fill':'none'}
|
||||||
|
line_attribs = {'style' : str(inkex.Style(line_style)),
|
||||||
|
inkex.addNS('label','inkscape') : name,
|
||||||
|
'd' : pathData}
|
||||||
|
line = etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
|
||||||
|
|
||||||
|
|
||||||
|
def add_arguments(self, pars):
|
||||||
|
pars.add_argument('--extrude', type=inkex.Boolean, default=False)
|
||||||
|
pars.add_argument('--extrude_height', type=float, default=10.000)
|
||||||
|
pars.add_argument('--unit', default="mm")
|
||||||
|
|
||||||
|
def effect(self):
|
||||||
|
path_num = 0
|
||||||
|
shifting = self.svg.unittouu(str(self.options.extrude_height) + self.options.unit)
|
||||||
|
|
||||||
|
for element in self.svg.selection.filter(inkex.PathElement).values():
|
||||||
|
elemGroup = self.svg.get_current_layer().add(inkex.Group(id="unwinding-" + element.get('id')))
|
||||||
|
|
||||||
|
#beginning point of the unwind band:
|
||||||
|
bbox = element.bounding_box() #shift the element to the bottom of the element
|
||||||
|
xmin = bbox.left
|
||||||
|
ymax = bbox.bottom
|
||||||
|
|
||||||
|
for sub in element.path.to_superpath():
|
||||||
|
new = []
|
||||||
|
new.append([sub[0]])
|
||||||
|
i = 1
|
||||||
|
topPathData = "m {:0.6f},{:0.6f} ".format(xmin, ymax)
|
||||||
|
bottomPathData = "m {:0.6f},{:0.6f} ".format(xmin, ymax + shifting)
|
||||||
|
lengths = []
|
||||||
|
while i <= len(sub) - 1:
|
||||||
|
length = bezier.cspseglength(new[-1][-1], sub[i]) #sub path length
|
||||||
|
lengths.append(length)
|
||||||
|
segment = "l {:0.6f},{:0.0f} ".format(length, 0)
|
||||||
|
topPathData += segment
|
||||||
|
bottomPathData += segment
|
||||||
|
new[-1].append(sub[i])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
self.drawline(topPathData, "hline-top-{0}".format(element.get('id')), elemGroup)
|
||||||
|
if self.options.extrude is True:
|
||||||
|
self.drawline(bottomPathData, "hline-bottom-{0}".format(element.get('id')), elemGroup)
|
||||||
|
|
||||||
|
#draw as much vertical lines as segments in bezier + start + end vertical line
|
||||||
|
self.drawline("m {:0.6f},{:0.6f} v {:0.6f}".format(xmin, ymax, shifting),"vline{0}".format(path_num), elemGroup)
|
||||||
|
self.drawline("m {:0.6f},{:0.6f} v {:0.6f}".format(xmin + sum([length for length in lengths]), ymax, shifting),"vline{0}".format(path_num), elemGroup)
|
||||||
|
x = 0
|
||||||
|
for n in range(0, i-1):
|
||||||
|
x += lengths[n]
|
||||||
|
self.drawline("m {:0.6f},{:0.6f} v {:0.6f}".format(xmin + x, ymax, shifting),"vline{0}".format(path_num), elemGroup)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
UnwindPaths().run()
|
Reference in New Issue
Block a user