adding back more extensions

This commit is contained in:
2022-11-05 12:30:28 +01:00
parent fed542ba37
commit 990f87171a
93 changed files with 602807 additions and 137 deletions

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Create Links (Breakaway Connectors)</name>
<id>fablabchemnitz.de.create_links</id>
<param name="tab" type="notebook">
<page name="tab_settings" gui-text="Settings">
<hbox>
<vbox>
<param name="path_types" type="optiongroup" appearance="combo" gui-text="Apply for">
<option value="open_paths">open paths</option>
<option value="closed_paths">closed paths</option>
<option value="both">both</option>
</param>
<param name="creationtype" type="optiongroup" appearance="combo" gui-text="Creation">
<option value="use_existing">Existing dash style from element</option>
<option value="custom_dashpattern">Custom dash pattern</option>
<option value="entered_values">Render by unit and link settings</option>
</param>
<label appearance="header">Creation: Link Settings</label>
<param name="creationunit" type="optiongroup" appearance="combo" gui-text="Creation Units">
<option value="mm">mm</option>
<option value="cm">cm</option>
<option value="in">in</option>
<option value="pt">pt</option>
<option value="px">px</option>
<option value="pc">pc</option>
<option value="percent">%</option>
</param>
<param name="link_count" type="int" min="1" max="9999" gui-text="Link count">1</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="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_offset" type="float" min="-9999.000" max="9999.000" precision="3" appearance="full" gui-text="Link offset (+/-)" gui-description="If you selected '%' as creation unit, enter values 0..100. The link will be placed in the middle">0.000</param>
<param name="switch_pattern" type="bool" gui-text="Swap links with dashes" gui-description="If enabled, we use gap length as dash length (switches the dasharray pattern).">false</param>
<param name="weakening_mode" type="bool" gui-text="Weakening mode" gui-description="If enabled, we colorize the swap links in #0000ff (blue) and disable the option 'Keep selected elements'">false</param>
<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.5 2.0 2.0</param>
<param name="custom_dashoffset_value" type="float" min="-9999.000" max="9999.000" precision="3" gui-text="Link offset (+/-)">0.000</param>
</vbox>
<separator/>
<vbox>
<label appearance="header">General Settings</label>
<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_unit" type="optiongroup" appearance="combo" gui-text="Length filter unit">
<option value="mm">mm</option>
<option value="cm">cm</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="no_convert" type="bool" gui-text="Do not create output path(s) (cosmetic style 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. Recommended to enable because default break apart of Inkscape might produce pointy paths.">true</param>
<param name="show_info" type="bool" gui-text="Print length, pattern and filtering information/errors" 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="skip_errors" type="bool" gui-text="Skip errors">false</param>
</vbox>
</hbox>
<separator/>
<label>Pro tip: Use 'Keep selected elements' to create links as usual (but with a copy). Then, as second step, work with the 'Swap links' and 'Weakening mode' options on the original element selection to create extra lasercutter weakening lines for better breaking out the parts later after processing.</label>
</page>
<page name="tab_about" gui-text="About">
<label appearance="header">Create Links</label>
<label>A utility to create links, also known as tabs, breakaway connectors or bridges. Intended to use with laser cutters.</label>
<label>2021 / written by Mario Voigt (Stadtfabrikanten e.V. / FabLab Chemnitz)</label>
<spacer/>
<label appearance="header">Online Documentation</label>
<label appearance="url">https://y.stadtfabrikanten.org/createlinks</label>
<spacer/>
<label appearance="header">Contributing</label>
<label appearance="url">https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X</label>
<label appearance="url">mailto:mario.voigt@stadtfabrikanten.org</label>
<spacer/>
<label appearance="header">MightyScape Extension Collection</label>
<label>This piece of software is part of the MightyScape for Inkscape Extension Collection and is licensed under GNU GPL v3</label>
<label appearance="url">https://y.stadtfabrikanten.org/mightyscape-overview</label>
</page>
<page name="tab_donate" gui-text="Donate">
<label appearance="header">Coffee + Pizza</label>
<label>We are the Stadtfabrikanten, running the FabLab Chemnitz since 2016. A FabLab is an open workshop that gives people access to machines and digital tools like 3D printers, laser cutters and CNC milling machines.</label>
<spacer/>
<label>You like our work and want to support us? You can donate to our non-profit organization by different ways:</label>
<label appearance="url">https://y.stadtfabrikanten.org/donate</label>
<spacer/>
<label>Thanks for using our extension and helping us!</label>
<image>../000_about_fablabchemnitz.svg</image>
</page>
</param>
<effect>
<object-type>path</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Paths - Cut/Intersect/Purge"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">create_links.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,300 @@
#!/usr/bin/env python3
#
# Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org
# Copyright (C) 2009 Alvin Penner, penner@vaxxine.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.
#
"""
This extension converts a path into a dashed line using 'stroke-dasharray'
It is a modification of the file addelements.py
It is a modification of the file convert2dash.py
Extension to convert paths into dash-array line
Extension for InkScape 1.X
Author: Mario Voigt / FabLab Chemnitz
Mail: mario.voigt@stadtfabrikanten.org
Date: 09.04.2021
Last patch: 28.10.2021
License: GNU GPL v3
"""
import copy
import re
import inkex
from inkex import bezier, CubicSuperPath, Group, PathElement
from inkex.bezier import csplength
class LinksCreator(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--tab")
pars.add_argument("--path_types", default="closed_paths", help="Apply for closed paths, open paths or both")
pars.add_argument("--creationunit", default="mm", help="Creation Units")
pars.add_argument("--creationtype", default="entered_values", help="Creation")
pars.add_argument("--link_count", type=int, default=1, help="Link count")
pars.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")
pars.add_argument("--length_link", type=float, default=1.000, help="Link length")
pars.add_argument("--link_offset", type=float, default=0.000, help="Link offset (+/-)")
pars.add_argument("--switch_pattern", type=inkex.Boolean, default=False, help="If enabled, we use gap length as dash length (switches the dasharray pattern")
pars.add_argument("--weakening_mode", type=inkex.Boolean, default=False, help="If enabled, we colorize the swap links in #0000ff (blue) and disable the option 'Keep selected elements'")
pars.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.")
pars.add_argument("--custom_dashoffset_value", type=float, default=0.000, help="Link offset (+/-)")
pars.add_argument("--length_filter", type=inkex.Boolean, default=False, help="Enable path length filtering")
pars.add_argument("--length_filter_value", type=float, default=0.000, help="Paths with length more than")
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=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")
def breakContours(self, element, breakelements = None): #this does the same as "CTRL + SHIFT + K"
if breakelements == None:
breakelements = []
if element.tag == inkex.addNS('path','svg'):
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:
subPaths.append(raw[prev:i])
prev = i
subPaths.append(raw[prev:])
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.set('d', csp)
if len(subPaths) == 1:
replacedelement.set('id', oldId)
else:
replacedelement.set('id', oldId + str(idSuffix))
idSuffix += 1
parent.insert(idx, replacedelement)
breakelements.append(replacedelement)
parent.remove(element)
for child in element.getchildren():
self.breakContours(child, breakelements)
return breakelements
def effect(self):
def createLinks(element):
elementParent = element.getparent()
path = element.path.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
if self.options.path_types == 'open_paths' and pathIsClosed is True:
return #skip this loop iteration
elif self.options.path_types == 'closed_paths' and pathIsClosed is False:
return #skip this loop iteration
elif self.options.path_types == 'both':
pass
# if keeping is enabled we make of copy of the current element and insert it while modifying the original ones. We could also delete the original and modify a copy...
if self.options.keep_selected is True and self.options.weakening_mode is False:
parent = element.getparent()
idx = parent.index(element)
copyelement = copy.copy(element)
parent.insert(idx, copyelement)
# we measure the length of the path to calculate the required dash configuration
csp = element.path.transform(element.composed_transform()).to_superpath()
slengths, stotal = csplength(csp) #get segment lengths and total length of path in document's internal unit
if self.options.length_filter is True:
if stotal < self.svg.unittouu(str(self.options.length_filter_value) + self.options.length_filter_unit):
if self.options.show_info is True: self.msg("element " + element.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
if self.options.creationunit == "percent":
length_link = (self.options.length_link / 100.0) * stotal
else:
length_link = self.svg.unittouu(str(self.options.length_link) + self.options.creationunit)
dashes = [] #central dashes array
if self.options.creationtype == "entered_values":
dash_length = ((stotal - length_link * self.options.link_count) / self.options.link_count) - 2 * length_link * self.options.link_multiplicator
dashes.append(dash_length)
dashes.append(length_link)
for i in range(0, self.options.link_multiplicator):
dashes.append(length_link) #stroke (=gap)
dashes.append(length_link) #gap
if self.options.switch_pattern is True:
dashes = dashes[::-1] #reverse the array
#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 self.options.show_info is True: self.msg("element " + element.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)
if self.options.creationunit == "percent":
stroke_dashoffset = (self.options.link_offset / 100.0 * stotal) - length_link/2
else:
stroke_dashoffset = self.svg.unittouu(str(self.options.link_offset) + self.options.creationunit)
if self.options.switch_pattern is True:
stroke_dashoffset = stroke_dashoffset + ((self.options.link_multiplicator * 2) + 1) * length_link
if self.options.creationtype == "use_existing":
if self.options.no_convert is True:
if self.options.show_info is True: self.msg("element " + element.get('id') + ": Nothing to do. Please select another creation method or disable cosmetic style output paths.")
return False if self.options.skip_errors is True else exit(1)
stroke_dashoffset = 0
style = element.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'])] #allow only positive values
if len(floats) > 0:
dashes = floats #overwrite previously calculated values with custom input
else:
raise ValueError
except:
if self.options.show_info is True: self.msg("element " + element.get('id') + ": No dash style to continue with.")
return False if self.options.skip_errors is True else exit(1)
if self.options.creationtype == "custom_dashpattern":
stroke_dashoffset = self.options.custom_dashoffset_value
try:
floats = [float(dash) for dash in re.findall(r"[+]?\d*\.\d+|\d+", self.options.custom_dasharray_value)] #allow only positive values
if len(floats) > 0:
dashes = floats #overwrite previously calculated values with custom input
else:
raise ValueError
except:
if self.options.show_info is True: self.msg("element " + element.get('id') + ": Error in custom dasharray string (might be empty or does not contain any numbers).")
return False if self.options.skip_errors is True else exit(1)
#assign stroke dasharray from entered values, existing style or custom dashpattern
stroke_dasharray = ' '.join(format(dash, "1.3f") for dash in dashes)
# check if the element has a style attribute. If not we create a blank one with a black stroke and without fill
style = None
default_fill = 'none'
default_stroke = '#000000'
default_stroke_width = str(self.svg.unittouu('1px'))
if element.attrib.has_key('style'):
element.style['stroke-dasharray'] = stroke_dasharray
element.style['stroke-dashoffset'] = stroke_dashoffset
#if has style attribute but the style attribute does not contain fill, stroke, stroke-width, stroke-dasharray or stroke-dashoffset yet
if element.style.get('fill') is None: element.style['fill'] = default_fill
if element.style.get('stroke') is None: element.style['stroke'] = default_stroke
if element.style.get('stroke-width') is None: element.style['stroke-width'] = default_stroke_width
else:
element.style = 'fill:{};stroke:{};stroke-width:{};stroke-dasharray:{};stroke-dashoffset:{};'.format(
default_fill, default_stroke, default_stroke_width, stroke_dasharray, stroke_dashoffset)
#if enabled, we override stroke color with blue (now, as the element definitely has a style)
if self.options.weakening_mode is True and self.options.switch_pattern is True:
element.style['stroke'] = "#0000ff"
# Print some info about values
if self.options.show_info is True:
self.msg("element " + element.get('id') + ":")
if self.options.creationunit == "percent":
self.msg(" * total path length = {:1.3f} {}".format(stotal, self.svg.unit)) #show length, converted in selected unit
self.msg(" * (calculated) offset: {:1.3f} %".format(stroke_dashoffset))
if self.options.creationtype == "entered_values":
self.msg(" * (calculated) gap length: {:1.3f} %".format(length_link))
else:
self.msg(" * 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
self.msg(" * (calculated) offset: {:1.3f} {}".format(self.svg.uutounit(stroke_dashoffset, self.options.creationunit), self.options.creationunit))
if self.options.creationtype == "entered_values":
self.msg(" * (calculated) gap length: {:1.3f} {}".format(length_link, self.options.creationunit))
if self.options.creationtype == "entered_values":
self.msg(" * total gaps = {}".format(self.options.link_count))
self.msg(" * (calculated) dash/gap pattern: {} ({})".format(stroke_dasharray, self.svg.unit))
# Conversion step (split cosmetic path into real segments)
if self.options.no_convert is False:
style = element.style #get the style again, but this time as style class
gaps = []
new = []
for sub in element.path.to_superpath():
idash = 0
dash = dashes[0]
length = float(stroke_dashoffset)
while dash < length:
length = length - dash
idash = (idash + 1) % len(dashes)
dash = dashes[idash]
new.append([sub[0][:]])
i = 1
while i < len(sub):
dash = dash - length
length = bezier.cspseglength(new[-1][-1], sub[i])
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
idash = (idash + 1) % len(dashes)
dash = dashes[idash]
if idash % 2:
new.append([sub[i]])
else:
new[-1].append(sub[i])
i += 1
#filter pointy subpaths
final_new = []
for sub in new:
if len(sub) > 1:
final_new.append(sub)
style.pop('stroke-dasharray')
element.pop('sodipodi:type')
element.path = CubicSuperPath(final_new)
element.style = style
# break apart the combined path to have multiple elements
if self.options.breakapart is True:
breakOutputelements = None
breakOutputelements = self.breakContours(element, breakOutputelements)
breakApartGroup = elementParent.add(inkex.Group())
for breakOutputelement in breakOutputelements:
breakApartGroup.append(breakOutputelement)
#self.msg(replacedelement.get('id'))
#self.svg.selection.set(replacedelement.get('id')) #update selection to split paths segments (does not work, so commented out)
if len(self.svg.selected) > 0:
for element in self.svg.selection.values():
#at first we need to break down combined elements to single path, otherwise dasharray cannot properly be applied
breakInputelements = None
breakInputelements = self.breakContours(element, breakInputelements)
for breakInputelement in breakInputelements:
createLinks(breakInputelement)
else:
self.msg('Please select some paths first.')
return
if __name__ == '__main__':
LinksCreator().run()

View File

@ -0,0 +1,20 @@
[
{
"name": "Create Links (Breakaway Connectors)",
"id": "fablabchemnitz.de.create_links",
"path": "create_links",
"dependent_extensions": null,
"original_name": "Create Links (Breakaway Connectors)",
"original_id": "fablabchemnitz.de.create_links",
"license": "GNU GPL v3",
"license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/LICENSE",
"comment": "Written by Mario Voigt",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/create_links",
"fork_url": null,
"documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=104923235",
"inkscape_gallery_url": "https://inkscape.org/~MarioVoigt/%E2%98%85create-links-breakaway-connectors",
"main_authors": [
"github.com/vmario89"
]
}
]