add offset thickness, negative segment marking and segment numbering to

unwind paths
This commit is contained in:
Mario Voigt 2022-01-02 13:53:25 +01:00
parent b869e17401
commit 9251d148fa
2 changed files with 51 additions and 18 deletions

View File

@ -8,13 +8,12 @@
<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="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_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> <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> <label appearance="header">Color And Style</label>
<param name="colorize" type="bool" gui-text="Colorize" gui-description="Colorize original paths and glue pairs">false</param> <param name="colorize" type="bool" gui-text="Colorize" gui-description="Colorize original paths and glue pairs">false</param>
<param name="color_increment" type="int" min="1" max="255" gui-text="Color increment" gui-description="For each segment we count up n colors. Does not apply if 'Randomize colors' is enabled.">10000</param> <param name="color_increment" type="int" min="1" max="255" gui-text="Color increment" gui-description="For each segment we count up n colors. Does not apply if 'Randomize colors' is enabled.">10000</param>
<param name="randomize_colors" type="bool" gui-text="Randomize colors">false</param> <param name="randomize_colors" type="bool" gui-text="Randomize colors">false</param>
<label appearance="header">Extrude Options</label> <param name="number" type="bool" gui-text="Number segments">false</param>
<param name="extrude" type="bool" gui-text="Extrude">false</param> <label appearance="header">Offset / Extrude Options</label>
<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">
<option value="mm">mm</option> <option value="mm">mm</option>
<option value="cm">cm</option> <option value="cm">cm</option>
@ -22,12 +21,15 @@
<option value="pt">pt</option> <option value="pt">pt</option>
<option value="px">px</option> <option value="px">px</option>
</param> </param>
<param name="thickness_offset" type="float" min="-99999.000" max="99999.000" precision="3" gui-text="Thickness offset +/-" gui-description="Allows to add/subtract extra offset length for each curve segment.">0.000</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="render_vertical_dividers" type="bool" gui-text="Render vertical dividers">true</param> <param name="render_vertical_dividers" type="bool" gui-text="Render vertical dividers">true</param>
<param name="render_with_dashes" type="bool" gui-text="Use dash style for dividers">true</param> <param name="render_with_dashes" type="bool" gui-text="Use dash style for dividers">true</param>
</page> </page>
<page name="tab_about" gui-text="About"> <page name="tab_about" gui-text="About">
<label appearance="header">Unwind Paths</label> <label appearance="header">Unwind Paths</label>
<label>An extension to wrap off paths to receive horizontal lines or extruded bands. Can be used for paper crafting, analysis and other works. You can also just use it to colorize path segments.</label> <label>An extension to wrap off paths to receive horizontal lines or extruded bands. Can be used for paper crafting, analysis and other works. You can also just use it to colorize path segments. Tip: use "Offset Paths" extension to create offset curves which help to create unwindings with correct material thickness.</label>
<label>2021 / written by Mario Voigt (Stadtfabrikanten e.V. / FabLab Chemnitz)</label> <label>2021 / written by Mario Voigt (Stadtfabrikanten e.V. / FabLab Chemnitz)</label>
<spacer/> <spacer/>
<label appearance="header">Online Documentation</label> <label appearance="header">Online Documentation</label>

View File

@ -25,7 +25,8 @@ ToDos:
""" """
import copy import copy
import inkex import inkex
from inkex import Color, bezier, Path, CubicSuperPath from inkex import Color, bezier, Path, CubicSuperPath, TextElement, Tspan
from inkex.bezier import csplength
from lxml import etree from lxml import etree
import math import math
import random import random
@ -45,9 +46,11 @@ class UnwindPaths(inkex.EffectExtension):
pars.add_argument('--colorize', type=inkex.Boolean, default=False, help="Colorize original paths and glue pairs") pars.add_argument('--colorize', type=inkex.Boolean, default=False, help="Colorize original paths and glue pairs")
pars.add_argument('--color_increment', type=int, default=10000, help="For each segment we count up n colors. Does not apply if 'Randomize colors' is enabled.") pars.add_argument('--color_increment', type=int, default=10000, help="For each segment we count up n colors. Does not apply if 'Randomize colors' is enabled.")
pars.add_argument('--randomize_colors', type=inkex.Boolean, default=False, help="Randomize colors") pars.add_argument('--randomize_colors', type=inkex.Boolean, default=False, help="Randomize colors")
pars.add_argument('--number', type=inkex.Boolean, default=False, help="Number segments")
pars.add_argument('--unit', default="mm")
pars.add_argument('--thickness_offset', type=float, default=0.000, help="Allows to add/subtract extra offset length for each curve segment.")
pars.add_argument('--extrude', type=inkex.Boolean, default=False) pars.add_argument('--extrude', type=inkex.Boolean, default=False)
pars.add_argument('--extrude_height', type=float, default=10.000) pars.add_argument('--extrude_height', type=float, default=10.000)
pars.add_argument('--unit', default="mm")
pars.add_argument('--render_vertical_dividers', type=inkex.Boolean, default=False) pars.add_argument('--render_vertical_dividers', type=inkex.Boolean, default=False)
pars.add_argument('--render_with_dashes', type=inkex.Boolean, default=False) pars.add_argument('--render_with_dashes', type=inkex.Boolean, default=False)
@ -97,6 +100,7 @@ class UnwindPaths(inkex.EffectExtension):
def effect(self): def effect(self):
shifting = self.svg.unittouu(str(self.options.extrude_height) + self.options.unit) shifting = self.svg.unittouu(str(self.options.extrude_height) + self.options.unit)
to = self.svg.unittouu(str(self.options.thickness_offset) + self.options.unit)
#some mode handling #some mode handling
if self.options.colorize is True: if self.options.colorize is True:
@ -133,6 +137,9 @@ class UnwindPaths(inkex.EffectExtension):
for i in range(subCount): for i in range(subCount):
colorSet.append(Color(self.rgb(0, i+self.options.color_increment, 1*i))) colorSet.append(Color(self.rgb(0, i+self.options.color_increment, 1*i)))
slengths, stotal = csplength(csp) #get segment lengths and total length of path in document's internal unit
#self.msg(stotal) #total length of the path
for sub in csp: for sub in csp:
#generate new horizontal line data by measuring each segment #generate new horizontal line data by measuring each segment
new = [] new = []
@ -154,27 +161,51 @@ class UnwindPaths(inkex.EffectExtension):
if self.options.extrude is True: if self.options.extrude is True:
vlinesGroup = self.svg.get_current_layer().add(inkex.Group(id="vlines-" + element.get('id'))) vlinesGroup = self.svg.get_current_layer().add(inkex.Group(id="vlines-" + element.get('id')))
elemGroup.append(vlinesGroup) elemGroup.append(vlinesGroup)
if self.options.break_only is False: if self.options.break_only is False:
while i <= len(sub) - 1: while i <= len(sub) - 1:
stroke_color = '#000000' stroke_color = '#000000'
if self.options.colorize is True and self.options.break_apart is True: if self.options.colorize is True and self.options.break_apart is True:
stroke_color =colorSet[i-1] stroke_color =colorSet[i-1]
horizontal_line_style = {'stroke':stroke_color,'stroke-width':'1px','fill':'none'} horizontal_line_style = {'stroke':stroke_color,'stroke-width':self.svg.unittouu('1px'),'fill':'none'}
length = bezier.cspseglength(new[-1][-1], sub[i]) #sub path length length = bezier.cspseglength(new[-1][-1], sub[i]) + to #sub path length
#if length <= 0:
# inkex.utils.debug("Warning: path id={}, segment={} might overlap with previous and/or next segment. Maybe check for negative thickness offset.".format(element.get('id'), i))
segment = "h {:0.6f} ".format(length) segment = "h {:0.6f} ".format(length)
topPathData += segment topPathData += segment
bottomPathData += segment bottomPathData += segment
new[-1].append(sub[i]) #important line! new[-1].append(sub[i]) #important line!
mid_coord_x = xmin + sum([length for length in lengths]) + length/2
font_size = 5
font_y_offset = font_size + 1
if self.options.number is True:
text = topLineGroup.add(TextElement(id=element.get('id') + "_TextNr{}".format(i)))
text.set("x", "{:0.6f}".format(mid_coord_x))
text.set("y", "{:0.6f}".format(ymax - font_y_offset))
text.set("font-size", "{:0.6f}".format(font_size))
text.set("style", "text-anchor:middle;text-align:center;fill:{}".format(stroke_color))
tspan = text.add(Tspan(id=element.get('id') + "_TSpanNr{}".format(i)))
tspan.set("x", "{:0.6f}".format(mid_coord_x))
if length <= 0:
tspan.set("y", "{:0.6f}".format(ymax - font_y_offset - i))
else:
tspan.set("y", "{:0.6f}".format(ymax - font_y_offset))
tspan.text = str(i)
if self.options.break_apart is True: if self.options.break_apart is True:
self.drawline("m {:0.6f},{:0.0f} ".format(xmin + sum([length for length in lengths]), ymax) + segment, self.drawline("m {:0.6f},{:0.6f} ".format(xmin + sum([length for length in lengths]), ymax) + segment,
"segmented-top-{}-{}".format(element.get('id'), i), topLineGroup, horizontal_line_style) "segmented-top-{}-{}".format(element.get('id'), i), topLineGroup, horizontal_line_style)
if length <= 0:
self.drawline("m {:0.6f},{:0.6f} ".format(mid_coord_x, ymax) + "v {} ".format(-5-i),
"segmented-top-overlap-{}-{}".format(element.get('id'), i), topLineGroup, horizontal_line_style)
if self.options.extrude is True: if self.options.extrude is True:
self.drawline("m {:0.6f},{:0.0f} ".format(xmin + sum([length for length in lengths]), ymax + shifting) + segment, self.drawline("m {:0.6f},{:0.6f} ".format(xmin + sum([length for length in lengths]), ymax + shifting) + segment,
"segmented-bottom-{}-{}".format(element.get('id'), i), bottomLineGroup, horizontal_line_style) "segmented-bottom-{}-{}".format(element.get('id'), i), bottomLineGroup, horizontal_line_style)
lengths.append(length) lengths.append(length)
i += 1 i += 1
@ -184,15 +215,15 @@ class UnwindPaths(inkex.EffectExtension):
self.drawline(bottomPathData, "combined-bottom-{0}".format(element.get('id')), elemGroup, horizontal_line_style) self.drawline(bottomPathData, "combined-bottom-{0}".format(element.get('id')), elemGroup, horizontal_line_style)
#draw as much vertical lines as segments in bezier + start + end vertical line #draw as much vertical lines as segments in bezier + start + end vertical line
vertical_end_lines_style = {'stroke':'#000000','stroke-width':'1px','fill':'none'} vertical_end_lines_style = {'stroke':'#000000','stroke-width':self.svg.unittouu('1px'),'fill':'none'}
if self.options.extrude is True: if self.options.extrude is True:
#render start line #render start line
self.drawline("m {:0.6f},{:0.6f} v {:0.6f}".format(xmin, ymax, shifting),"vline-{}-start".format(element.get('id')), vlinesGroup, vertical_end_lines_style) self.drawline("m {:0.6f},{:0.6f} v {:0.6f}".format(xmin, ymax, shifting),"vline-{}-start".format(element.get('id')), vlinesGroup, vertical_end_lines_style)
#render divider lines #render divider lines
if self.options.render_vertical_dividers is True: if self.options.render_vertical_dividers is True:
vertical_mid_lines_style = {'stroke':'#000000','stroke-width':'1px','fill':'none'} vertical_mid_lines_style = {'stroke':'#000000','stroke-width':self.svg.unittouu('1px'),'fill':'none'}
if self.options.render_with_dashes is True: if self.options.render_with_dashes is True:
vertical_mid_lines_style = {'stroke':'#000000','stroke-width':'1px',"stroke-dasharray":"2 2", 'fill':'none'} vertical_mid_lines_style = {'stroke':'#000000','stroke-width':self.svg.unittouu('1px'),"stroke-dasharray":"2 2", 'fill':'none'}
x = 0 x = 0
for n in range(0, i-2): for n in range(0, i-2):
x += lengths[n] x += lengths[n]
@ -227,7 +258,7 @@ class UnwindPaths(inkex.EffectExtension):
stroke_color = '#000000' stroke_color = '#000000'
if self.options.colorize is True: if self.options.colorize is True:
stroke_color =colorSet[i-1] stroke_color =colorSet[i-1]
new_original_line_style = {'stroke':stroke_color,'stroke-width':'1px','fill':'none'} new_original_line_style = {'stroke':stroke_color,'stroke-width':self.svg.unittouu('1px'),'fill':'none'}
self.drawline(d, "segmented-" + element.get('id'), newOriginalPathGroup, new_original_line_style) self.drawline(d, "segmented-" + element.get('id'), newOriginalPathGroup, new_original_line_style)
if self.options.keep_original is False: if self.options.keep_original is False: