Patched Create Links extension
This commit is contained in:
parent
965f5dbb0a
commit
3fb3a020f8
@ -14,9 +14,10 @@
|
|||||||
<option value="custom_dasharray">Custom dash pattern</option>
|
<option value="custom_dasharray">Custom dash pattern</option>
|
||||||
<option value="entered_values">Render by unit and link settings</option>
|
<option value="entered_values">Render by unit and link settings</option>
|
||||||
</param>
|
</param>
|
||||||
<param name="unit" type="optiongroup" appearance="combo" gui-text="Units">
|
<param name="creationunit" type="optiongroup" appearance="combo" gui-text="Creation Units">
|
||||||
<option value="mm">mm</option>
|
<option value="mm">mm</option>
|
||||||
<option value="cm">cm</option>
|
<option value="cm">cm</option>
|
||||||
|
<option value="m">m</option>
|
||||||
<option value="in">in</option>
|
<option value="in">in</option>
|
||||||
<option value="pt">pt</option>
|
<option value="pt">pt</option>
|
||||||
<option value="px">px</option>
|
<option value="px">px</option>
|
||||||
@ -26,20 +27,30 @@
|
|||||||
<label appearance="header">Creation: Link Settings</label>
|
<label appearance="header">Creation: Link Settings</label>
|
||||||
<param name="link_count" type="int" min="1" max="9999" gui-text="Link count">1</param>
|
<param name="link_count" type="int" min="1" max="9999" gui-text="Link count">1</param>
|
||||||
<param name="length_link" type="float" min="0.000" max="9999.000" precision="3" gui-text="Link length (the length of the gap)">1.000</param>
|
<param name="length_link" type="float" min="0.000" max="9999.000" precision="3" gui-text="Link length (the length of the gap)">1.000</param>
|
||||||
<param name="link_multiplicator" type="int" min="0" max="9999" gui-text="Link multiplicator (experimental)" gui-description="If set, we create a set of multiple gaps of same size next to the main gap">0</param>
|
<param name="link_multiplicator" type="int" min="0" max="9999" gui-text="Link multiplicator" gui-description="If set, we create a set of multiple gaps of same size next to the main gap">0</param>
|
||||||
<param name="link_offset" type="float" min="-9999.000.000" max="9999.000" precision="3" gui-text="Link offset (+/-)">0.000</param>
|
<param name="link_offset" type="float" min="-9999.000.000" max="9999.000" precision="3" gui-text="Link offset (+/-)">0.000</param>
|
||||||
<label appearance="header">Creation: Custom Dash Pattern Settings</label>
|
<label appearance="header">Creation: Custom Dash Pattern Settings</label>
|
||||||
<param name="custom_dasharray_value" type="string" gui-text="Dash pattern" gui-description="A list of separated lengths that specify the lengths of alternating dashes and gaps. Input only accepts numbers. It ignores percentages or other characters.">10 5</param>
|
<param name="custom_dasharray_value" type="string" gui-text="Dash pattern" gui-description="A list of separated lengths that specify the lengths of alternating dashes and gaps. Input only accepts numbers. It ignores percentages or other characters.">10 5.5 2.0 2.0</param>
|
||||||
<label appearance="header">Other Settings</label>
|
<label appearance="header">Other Settings</label>
|
||||||
<param name="length_filter" type="bool" gui-text="Enable path length filtering (uses always document's unit)">false</param>
|
<param name="length_filter" type="bool" gui-text="Enable path length filtering">false</param>
|
||||||
<param name="length_filter_value" type="float" min="0.000" max="9999.000" precision="3" gui-text="Paths with length more than">0.000</param>
|
<param name="length_filter_value" type="float" min="0.000" max="9999.000" precision="3" gui-text="Paths with length more than">0.000</param>
|
||||||
|
<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>
|
||||||
|
<option value="pc">pc</option>
|
||||||
|
</param>
|
||||||
<param name="keep_selected" type="bool" gui-text="Keep selected elements">false</param>
|
<param name="keep_selected" type="bool" gui-text="Keep selected elements">false</param>
|
||||||
<param name="breakapart" type="bool" gui-text="Break apart output paths" gui-description="Performs CTRL + SHIFT + K to break the new output path into it's parts">false</param>
|
<param name="no_convert" type="bool" gui-text="Do not create output path(s) (cosmetic style only)">false</param>
|
||||||
<param name="show_info" type="bool" gui-text="Print some length and pattern information" 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="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="show_info" type="bool" gui-text="Print some length, pattern and filtering information" 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>
|
||||||
</page>
|
</page>
|
||||||
<page name="about" gui-text="About">
|
<page name="about" gui-text="About">
|
||||||
<label appearance="header">Create Links</label>
|
<label appearance="header">Create Links</label>
|
||||||
<label>Stadtfabrikanten e.V. (2021)</label>
|
<label>by Mario Voigt / Stadtfabrikanten e.V. (2021)</label>
|
||||||
<spacer/>
|
<spacer/>
|
||||||
<label>This piece of software is part of the MightyScape for InkScape 1.0/1.1dev Extension Collection.</label>
|
<label>This piece of software is part of the MightyScape for InkScape 1.0/1.1dev Extension Collection.</label>
|
||||||
<label>You found a bug or got some fresh code? Just report to mario.voigt@stadtfabrikanten.org. Thanks!</label>
|
<label>You found a bug or got some fresh code? Just report to mario.voigt@stadtfabrikanten.org. Thanks!</label>
|
||||||
|
@ -43,8 +43,8 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
super(LinksCreator, self).__init__()
|
super(LinksCreator, self).__init__()
|
||||||
self.arg_parser.add_argument("--main_tabs")
|
self.arg_parser.add_argument("--main_tabs")
|
||||||
self.arg_parser.add_argument("--path_types", default="closed_paths", help="Apply for closed paths, open paths or both")
|
self.arg_parser.add_argument("--path_types", default="closed_paths", help="Apply for closed paths, open paths or both")
|
||||||
|
self.arg_parser.add_argument("--creationunit", default="mm", help="Creation Units")
|
||||||
self.arg_parser.add_argument("--creationtype", default="entered_values", help="Creation")
|
self.arg_parser.add_argument("--creationtype", default="entered_values", help="Creation")
|
||||||
self.arg_parser.add_argument("--unit", default="mm", help="Units")
|
|
||||||
self.arg_parser.add_argument("--link_count", type=int, default=1, help="Link count")
|
self.arg_parser.add_argument("--link_count", type=int, default=1, help="Link count")
|
||||||
self.arg_parser.add_argument("--length_link", type=float, default=1.000, help="Link length")
|
self.arg_parser.add_argument("--length_link", type=float, default=1.000, help="Link length")
|
||||||
self.arg_parser.add_argument("--link_multiplicator", type=int, default=1, help="If set, we create a set of multiple gaps of same size next to the main gap")
|
self.arg_parser.add_argument("--link_multiplicator", type=int, default=1, help="If set, we create a set of multiple gaps of same size next to the main gap")
|
||||||
@ -52,7 +52,9 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
self.arg_parser.add_argument("--custom_dasharray_value", default="", help="A list of separated lengths that specify the lengths of alternating dashes and gaps. Input only accepts numbers. It ignores percentages or other characters.")
|
self.arg_parser.add_argument("--custom_dasharray_value", default="", help="A list of separated lengths that specify the lengths of alternating dashes and gaps. Input only accepts numbers. It ignores percentages or other characters.")
|
||||||
self.arg_parser.add_argument("--length_filter", type=inkex.Boolean, default=False, help="Enable path length filtering")
|
self.arg_parser.add_argument("--length_filter", type=inkex.Boolean, default=False, help="Enable path length filtering")
|
||||||
self.arg_parser.add_argument("--length_filter_value", type=float, default=0.000, help="Paths with length more than")
|
self.arg_parser.add_argument("--length_filter_value", type=float, default=0.000, help="Paths with length more than")
|
||||||
|
self.arg_parser.add_argument("--length_filter_unit", default="mm", help="Length filter unit")
|
||||||
self.arg_parser.add_argument("--keep_selected", type=inkex.Boolean, default=False, help="Keep selected elements")
|
self.arg_parser.add_argument("--keep_selected", type=inkex.Boolean, default=False, help="Keep selected elements")
|
||||||
|
self.arg_parser.add_argument("--no_convert", type=inkex.Boolean, default=False, help="Do not create segments (cosmetic gaps only)")
|
||||||
self.arg_parser.add_argument("--breakapart", type=inkex.Boolean, default=False, help="Performs CTRL + SHIFT + K to break the new output path into it's parts")
|
self.arg_parser.add_argument("--breakapart", type=inkex.Boolean, default=False, help="Performs CTRL + SHIFT + K to break the new output path into it's parts")
|
||||||
self.arg_parser.add_argument("--show_info", type=inkex.Boolean, default=False, help="Print some length and pattern information")
|
self.arg_parser.add_argument("--show_info", type=inkex.Boolean, default=False, help="Print some length and pattern information")
|
||||||
|
|
||||||
@ -106,41 +108,44 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
csp = node.path.transform(node.composed_transform()).to_superpath()
|
csp = node.path.transform(node.composed_transform()).to_superpath()
|
||||||
slengths, stotal = csplength(csp) #get segment lengths and total length of path in document's internal unit
|
slengths, stotal = csplength(csp) #get segment lengths and total length of path in document's internal unit
|
||||||
|
|
||||||
if self.options.unit == "percent":
|
|
||||||
length_link = (self.options.length_link / 100.0) * stotal
|
|
||||||
else:
|
|
||||||
length_link = self.svg.unittouu(str(self.options.length_link) + self.options.unit)
|
|
||||||
|
|
||||||
if self.options.length_filter is True:
|
if self.options.length_filter is True:
|
||||||
if stotal < self.options.length_filter_value:
|
if stotal < self.svg.unittouu(str(self.options.length_filter_value) + self.options.length_filter_unit):
|
||||||
if self.options.show_info is True:
|
if self.options.show_info is True:
|
||||||
inkex.utils.debug("node " + node.get('id') + " is shorter than minimum allowed length of {:1.3f}. Path length is {:1.3f}".format(self.options.length_filter_value, stotal))
|
inkex.utils.debug("node " + node.get('id') + " is shorter than minimum allowed length of {:1.3f} {}. Path length is {:1.3f} {}".format(self.options.length_filter_value, self.options.length_filter_unit, stotal, self.options.creationunit))
|
||||||
return #skip this loop iteration
|
return #skip this loop iteration
|
||||||
|
|
||||||
'''
|
if self.options.creationunit == "percent":
|
||||||
<dasharray>
|
length_link = (self.options.length_link / 100.0) * stotal
|
||||||
A list of comma and/or white space separated <length>s and <percentage>s that specify the lengths of alternating dashes and gaps.
|
else:
|
||||||
If an odd number of values is provided, then the list of values is repeated to yield an even number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2.
|
length_link = self.svg.unittouu(str(self.options.length_link) + self.options.creationunit)
|
||||||
|
|
||||||
If we want three gaps in a path with length of 168.71 mm and a gap length of 2 mm we set the stroke-dasharray to:
|
dashes = [] #central dashes array
|
||||||
50.236 2.0 → because 3 * 50.236 mm + 3 * 2.0 mm = 168.71 mm
|
dashes.append(((stotal - length_link * self.options.link_count) / self.options.link_count) - 2 * length_link * (self.options.link_multiplicator))
|
||||||
|
|
||||||
examples having a circle with a circumference of length = 100:
|
|
||||||
- the array "20 5" will create 4 dashes with length = 20 and 4 gaps with length = 5 (20 + 5 + 20 + 5 + 20 + 5 + 20 + 5 = 100)
|
|
||||||
- the array "5 20" will create 4 dashes with length = 5 and 4 gaps with length = 20 (5 + 20 + 5 + 20 + 5 + 20 + 5 + 20 = 100)
|
|
||||||
- the array "5 15" will create 5 dashes with length = 5 and 5 gaps with length = 15 (5 + 15 + 5 + 15 + 5 + 15 + 5 + 15 + 5 + 15 = 100)
|
|
||||||
- the array "5 14" will create 6 dashes with length = 5 and 5 gaps with length = 15 (5 + 14 + 5 + 14 + 5 + 14 + 5 + 14 + 5 + 14 + 5 = 100) - the first dash will connect to the last dash fluently
|
|
||||||
in the examples above we always match the full length. But we do not always match it.
|
|
||||||
'''
|
|
||||||
|
|
||||||
dashes = []
|
|
||||||
dashes.append((stotal - length_link * self.options.link_count) / self.options.link_count)
|
|
||||||
dashes.append(length_link)
|
dashes.append(length_link)
|
||||||
|
|
||||||
for i in range(0, self.options.link_multiplicator):
|
for i in range(0, self.options.link_multiplicator):
|
||||||
dashes.append(length_link) #stroke (=gap)
|
dashes.append(length_link) #stroke (=gap)
|
||||||
dashes.append(length_link) #gap
|
dashes.append(length_link) #gap
|
||||||
|
|
||||||
|
if self.options.creationtype == "use_existing" and self.options.no_convert is True:
|
||||||
|
inkex.errormsg("Nothing to do. Please select another creation method or disable cosmetic style output paths.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.options.creationtype == "use_existing":
|
||||||
|
stroke_dashoffset = 0
|
||||||
|
style = node.style
|
||||||
|
if 'stroke-dashoffset' in style:
|
||||||
|
stroke_dashoffset = style['stroke-dashoffset']
|
||||||
|
try:
|
||||||
|
floats = [float(dash) for dash in re.findall(r"[-+]?\d*\.\d+|\d+", style['stroke-dasharray'])]
|
||||||
|
if len(floats) > 0:
|
||||||
|
dashes = floats #overwrite previously calculated values with custom input
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
except:
|
||||||
|
inkex.errormsg("no dash style to continue with.")
|
||||||
|
return
|
||||||
|
|
||||||
if self.options.creationtype == "custom_dasharray":
|
if self.options.creationtype == "custom_dasharray":
|
||||||
try:
|
try:
|
||||||
floats = [float(dash) for dash in re.findall(r"[-+]?\d*\.\d+|\d+", self.options.custom_dasharray_value)]
|
floats = [float(dash) for dash in re.findall(r"[-+]?\d*\.\d+|\d+", self.options.custom_dasharray_value)]
|
||||||
@ -149,28 +154,15 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
except:
|
except:
|
||||||
inkex.errormsg("Error in custom dasharray string (might be empty or does not contain any numbers). Using regular input instead ...")
|
inkex.errormsg("Error in custom dasharray string (might be empty or does not contain any numbers).")
|
||||||
|
return
|
||||||
|
|
||||||
stroke_dasharray = ' '.join(format(dash, "1.3f") for dash in dashes)
|
stroke_dasharray = ' '.join(format(dash, "1.3f") for dash in dashes)
|
||||||
|
|
||||||
if self.options.unit == "percent":
|
if self.options.creationunit == "percent":
|
||||||
stroke_dashoffset = self.options.link_offset / 100.0
|
stroke_dashoffset = self.options.link_offset / 100.0
|
||||||
else:
|
else:
|
||||||
stroke_dashoffset = self.svg.unittouu(str(self.options.link_offset) + self.options.unit)
|
stroke_dashoffset = self.svg.unittouu(str(self.options.link_offset) + self.options.creationunit)
|
||||||
|
|
||||||
if self.options.show_info is True:
|
|
||||||
inkex.utils.debug("node " + node.get('id'))
|
|
||||||
if self.options.unit == "percent":
|
|
||||||
inkex.utils.debug("total path length = {:1.3f} {}".format(stotal, self.svg.unit)) #show length, converted in selected unit
|
|
||||||
inkex.utils.debug("(calculated) offset: {:1.3f} %".format(stroke_dashoffset))
|
|
||||||
inkex.utils.debug("(calculated) gap length: {:1.3f} %".format(length_link))
|
|
||||||
else:
|
|
||||||
inkex.utils.debug("total path length = {:1.3f} {} ({:1.3f} {})".format(self.svg.uutounit(stotal, self.options.unit), self.options.unit, stotal, self.svg.unit)) #show length, converted in selected unit
|
|
||||||
inkex.utils.debug("(calculated) offset: {:1.3f} {}".format(self.svg.uutounit(stroke_dashoffset, self.options.unit), self.options.unit))
|
|
||||||
inkex.utils.debug("(calculated) gap length: {:1.3f} {}".format(length_link, self.options.unit))
|
|
||||||
inkex.utils.debug("total gaps = {}".format(self.options.link_count))
|
|
||||||
inkex.utils.debug("(calculated) dash/gap pattern: {} ({})".format(stroke_dasharray, self.svg.unit))
|
|
||||||
inkex.utils.debug("--------------------------------------------------------------------------------------------------")
|
|
||||||
|
|
||||||
# check if the node has a style attribute. If not we create a blank one with a black stroke and without fill
|
# check if the node has a style attribute. If not we create a blank one with a black stroke and without fill
|
||||||
style = None
|
style = None
|
||||||
@ -203,49 +195,70 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
style = 'fill:none;stroke:#000000;stroke-width:1px;stroke-dasharray:{};stroke-dashoffset:{};'.format(stroke_dasharray, stroke_dashoffset)
|
style = 'fill:none;stroke:#000000;stroke-width:1px;stroke-dasharray:{};stroke-dashoffset:{};'.format(stroke_dasharray, stroke_dashoffset)
|
||||||
node.set('style', style)
|
node.set('style', style)
|
||||||
|
|
||||||
style = node.style #get the style again, but this time as style class
|
# Print some info about values
|
||||||
|
if self.options.show_info is True:
|
||||||
|
inkex.utils.debug("node " + node.get('id'))
|
||||||
|
if self.options.creationunit == "percent":
|
||||||
|
inkex.utils.debug("total path length = {:1.3f} {}".format(stotal, self.svg.unit)) #show length, converted in selected unit
|
||||||
|
inkex.utils.debug("(calculated) offset: {:1.3f} %".format(stroke_dashoffset))
|
||||||
|
if self.options.creationtype == "entered_values":
|
||||||
|
inkex.utils.debug("(calculated) gap length: {:1.3f} %".format(length_link))
|
||||||
|
else:
|
||||||
|
inkex.utils.debug("total path length = {:1.3f} {} ({:1.3f} {})".format(self.svg.uutounit(stotal, self.options.creationunit), self.options.creationunit, stotal, self.svg.unit)) #show length, converted in selected unit
|
||||||
|
inkex.utils.debug("(calculated) offset: {:1.3f} {}".format(self.svg.uutounit(stroke_dashoffset, self.options.creationunit), self.options.creationunit))
|
||||||
|
if self.options.creationtype == "entered_values":
|
||||||
|
inkex.utils.debug("(calculated) gap length: {:1.3f} {}".format(length_link, self.options.creationunit))
|
||||||
|
if self.options.creationtype == "entered_values":
|
||||||
|
inkex.utils.debug("total gaps = {}".format(self.options.link_count))
|
||||||
|
inkex.utils.debug("(calculated) dash/gap pattern: {} ({})".format(stroke_dasharray, self.svg.unit))
|
||||||
|
inkex.utils.debug("--------------------------------------------------------------------------------------------------")
|
||||||
|
|
||||||
new = []
|
# Conversion step (split cosmetic path into real segments)
|
||||||
for sub in node.path.to_superpath():
|
if self.options.no_convert is False:
|
||||||
idash = 0
|
style = node.style #get the style again, but this time as style class
|
||||||
dash = dashes[0]
|
|
||||||
length = float(stroke_dashoffset)
|
new = []
|
||||||
while dash < length:
|
for sub in node.path.to_superpath():
|
||||||
length = length - dash
|
idash = 0
|
||||||
idash = (idash + 1) % len(dashes)
|
dash = dashes[0]
|
||||||
dash = dashes[idash]
|
length = float(stroke_dashoffset)
|
||||||
new.append([sub[0][:]])
|
|
||||||
i = 1
|
|
||||||
while i < len(sub):
|
|
||||||
dash = dash - length
|
|
||||||
length = bezier.cspseglength(new[-1][-1], sub[i])
|
|
||||||
while dash < length:
|
while dash < length:
|
||||||
new[-1][-1], nxt, sub[i] = \
|
|
||||||
bezier.cspbezsplitatlength(new[-1][-1], sub[i], dash/length)
|
|
||||||
if idash % 2: # create a gap
|
|
||||||
new.append([nxt[:]])
|
|
||||||
else: # splice the curve
|
|
||||||
new[-1].append(nxt[:])
|
|
||||||
length = length - dash
|
length = length - dash
|
||||||
idash = (idash + 1) % len(dashes)
|
idash = (idash + 1) % len(dashes)
|
||||||
dash = dashes[idash]
|
dash = dashes[idash]
|
||||||
if idash % 2:
|
new.append([sub[0][:]])
|
||||||
new.append([sub[i]])
|
i = 1
|
||||||
else:
|
while i < len(sub):
|
||||||
new[-1].append(sub[i])
|
dash = dash - length
|
||||||
i += 1
|
length = bezier.cspseglength(new[-1][-1], sub[i])
|
||||||
style.pop('stroke-dasharray')
|
while dash < length:
|
||||||
node.pop('sodipodi:type')
|
new[-1][-1], nxt, sub[i] = \
|
||||||
node.path = CubicSuperPath(new)
|
bezier.cspbezsplitatlength(new[-1][-1], sub[i], dash/length)
|
||||||
node.style = style
|
if idash % 2: # create a gap
|
||||||
|
new.append([nxt[:]])
|
||||||
|
else: # splice the curve
|
||||||
|
new[-1].append(nxt[:])
|
||||||
|
length = length - dash
|
||||||
|
idash = (idash + 1) % len(dashes)
|
||||||
|
dash = dashes[idash]
|
||||||
|
if idash % 2:
|
||||||
|
new.append([sub[i]])
|
||||||
|
else:
|
||||||
|
new[-1].append(sub[i])
|
||||||
|
i += 1
|
||||||
|
style.pop('stroke-dasharray')
|
||||||
|
node.pop('sodipodi:type')
|
||||||
|
node.path = CubicSuperPath(new)
|
||||||
|
node.style = style
|
||||||
|
|
||||||
if self.options.breakapart is True:
|
# break apart the combined path to have multiple elements
|
||||||
breakOutputNodes = self.breakContours(node)
|
if self.options.breakapart is True:
|
||||||
breakApartGroup = nodeParent.add(inkex.Group())
|
breakOutputNodes = self.breakContours(node)
|
||||||
for breakOutputNode in breakOutputNodes:
|
breakApartGroup = nodeParent.add(inkex.Group())
|
||||||
breakApartGroup.append(breakOutputNode)
|
for breakOutputNode in breakOutputNodes:
|
||||||
#inkex.utils.debug(replacedNode.get('id'))
|
breakApartGroup.append(breakOutputNode)
|
||||||
#self.svg.selection.set(replacedNode.get('id')) #update selection to split paths segments (does not work, so commented out)
|
#inkex.utils.debug(replacedNode.get('id'))
|
||||||
|
#self.svg.selection.set(replacedNode.get('id')) #update selection to split paths segments (does not work, so commented out)
|
||||||
|
|
||||||
if len(self.svg.selected) > 0:
|
if len(self.svg.selected) > 0:
|
||||||
pathNodes = self.svg.selection.filter(PathElement).values()
|
pathNodes = self.svg.selection.filter(PathElement).values()
|
||||||
|
Reference in New Issue
Block a user