Different enhancements

This commit is contained in:
Mario Voigt 2021-11-10 02:18:39 +01:00
parent ad73bd72a5
commit 2929277f6f
4 changed files with 123 additions and 45 deletions

View File

@ -3,7 +3,7 @@
<name>Draw Directions / Travel Moves</name> <name>Draw Directions / Travel Moves</name>
<id>fablabchemnitz.de.draw_directions_tavel_moves</id> <id>fablabchemnitz.de.draw_directions_tavel_moves</id>
<param name="nb_main" type="notebook"> <param name="nb_main" type="notebook">
<page name="tab_settings" gui-text="Settings"> <page name="tab_draw" gui-text="Draw">
<param name="order" type="optiongroup" appearance="combo" gui-text="Order"> <param name="order" type="optiongroup" appearance="combo" gui-text="Order">
<option value="separate_groups">To separate groups</option> <option value="separate_groups">To separate groups</option>
<option value="separate_layers">To separate layers</option> <option value="separate_layers">To separate layers</option>
@ -21,9 +21,12 @@
<separator/> <separator/>
<param name="debug" type="bool" gui-text="Print debug info">false</param> <param name="debug" type="bool" gui-text="Print debug info">false</param>
</page> </page>
<page name="tab_remove" gui-text="Remove">
<label>If this page is selected, you can remove all old travel lines/groups Just press 'apply'.</label>
</page>
<page name="tab_about" gui-text="About"> <page name="tab_about" gui-text="About">
<label appearance="header">Draw Directions / Travel Moves</label> <label appearance="header">Draw Directions / Travel Moves</label>
<label>Draw travel lines and/or dots to mark start and end points of paths</label> <label>Draw travel lines and/or dots to mark start and end points of paths and to show the line order.</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

@ -6,21 +6,22 @@ import inkex
from inkex import Circle, Vector2d from inkex import Circle, Vector2d
from inkex.paths import Path from inkex.paths import Path
from inkex.bezier import csplength from inkex.bezier import csplength
from debugpy.common.timestamp import current
''' '''
ToDos ToDos
- draw numbers for each travel lines next to the line - draw numbers for each travel lines next to the line
- option selection: add travel lines by color groups or add them at the index of the line -> this keeps the order in total (will need transform of start point and second transform of end point, if they are in different groups)
- option to just remove all generated travelLines/dots (especially hard to delete if they are inserted at element order)
''' '''
class DrawDirectionsTravelMoves(inkex.EffectExtension): class DrawDirectionsTravelMoves(inkex.EffectExtension):
def drawCircle(self, group, color, point): def drawCircle(self, group, color, point):
style = inkex.Style({'stroke': 'none', 'fill': color}) style = inkex.Style({'stroke': 'none', 'fill': color})
startCircle = group.add(Circle(cx=str(point[0]), cy=str(point[1]), r=str(self.svg.unittouu(str(so.dotsize/2) + "px")))) startCircle = group.add(Circle(cx=str(point[0]), cy=str(point[1]), r=str(self.svg.unittouu(str(so.dotsize/2) + "px"))))
startCircle.style = style startCircle.style = style
def find_group(self, groupId): def find_group(self, groupId):
''' check if a group with a given id exists or not. Returns None if not found, else returns the group element ''' ''' check if a group with a given id exists or not. Returns None if not found, else returns the group element '''
groups = self.document.xpath('//svg:g', namespaces=inkex.NSS) groups = self.document.xpath('//svg:g', namespaces=inkex.NSS)
@ -30,58 +31,8 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
return group return group
return None return None
def add_arguments(self, pars):
pars.add_argument("--nb_main")
pars.add_argument("--order", default="separate_groups")
pars.add_argument("--draw_dots", type=inkex.Boolean, default=True, help="Start and end point of opened (red + blue) and closed paths (green + yellow)")
pars.add_argument("--dotsize", type=int, default=10, help="Dot size (px)")
pars.add_argument("--draw_travel_moves", type=inkex.Boolean, default=False)
pars.add_argument("--ignore_colors", type=inkex.Boolean, default=False, help="If enabled we connect all lines by order, ignoring the stroke color (normally we have one travel line group per color)")
pars.add_argument("--dashed_style", type=inkex.Boolean, default=True)
pars.add_argument("--arrow_style", type=inkex.Boolean, default=True)
pars.add_argument("--arrow_size", type=float, default=True)
pars.add_argument("--debug", type=inkex.Boolean, default=False)
def effect(self): def createTravelMarker(self, markerId):
global so
so = self.options
dotPrefix = "dots-"
linePrefix = "travelLine-"
groupPrefix = "travelLines-"
ignoreWord = "ignore"
selectedPaths = [] #total list of elements to parse
def parseChildren(element):
if isinstance(element, inkex.PathElement) and element not in selectedPaths and linePrefix not in element.get('id') and not isinstance(element.getparent(), inkex.Marker):
selectedPaths.append(element)
children = element.getchildren()
if children is not None:
for child in children:
if isinstance(child, inkex.PathElement) and child not in selectedPaths and linePrefix not in element.get('id') and not isinstance(element.getparent(), inkex.Marker):
selectedPaths.append(child)
parseChildren(child) #go deeper and deeper
#check if we have selectedPaths elements or if we should parse the whole document instead
if len(self.svg.selected) == 0:
for element in self.document.getroot().iter(tag=etree.Element):
if isinstance(element, inkex.PathElement) and element != self.document.getroot() and linePrefix not in element.get('id') and not isinstance(element.getparent(), inkex.Marker):
selectedPaths.append(element)
else:
for element in self.svg.selected.values():
parseChildren(element)
dotGroup = self.svg.add(inkex.Group(id=self.svg.get_unique_id(dotPrefix)))
if so.order == "separate_layers":
dotGroup.set("inkscape:groupmode", "layer")
dotGroup.set("inkscape:label", dotPrefix + "layer")
if so.order == "separate_groups":
dotGroup.pop("inkscape:groupmode")
dotGroup.pop("inkscape:label")
dotGroup.style.pop("display") #if the group previously has been a layer (which was hidden), a display:none will be added. we don't want that
if so.arrow_style is True:
markerId = "travel_move_arrow"
#add new marker to defs (or overwrite if existent) #add new marker to defs (or overwrite if existent)
defs = self.svg.defs defs = self.svg.defs
for defi in defs: for defi in defs:
@ -105,10 +56,92 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
marker.append(markerPath) marker.append(markerPath)
defs.append(marker) #do not append before letting contain it one path. Otherwise Inkscape is going to crash immediately defs.append(marker) #do not append before letting contain it one path. Otherwise Inkscape is going to crash immediately
def add_arguments(self, pars):
pars.add_argument("--nb_main")
pars.add_argument("--order", default="separate_groups")
pars.add_argument("--draw_dots", type=inkex.Boolean, default=True, help="Start and end point of opened (red + blue) and closed paths (green + yellow)")
pars.add_argument("--dotsize", type=int, default=10, help="Dot size (px)")
pars.add_argument("--draw_travel_moves", type=inkex.Boolean, default=False)
pars.add_argument("--ignore_colors", type=inkex.Boolean, default=False, help="If enabled we connect all lines by order, ignoring the stroke color (normally we have one travel line group per color)")
pars.add_argument("--dashed_style", type=inkex.Boolean, default=True)
pars.add_argument("--arrow_style", type=inkex.Boolean, default=True)
pars.add_argument("--arrow_size", type=float, default=True)
pars.add_argument("--debug", type=inkex.Boolean, default=False)
def effect(self):
global so
so = self.options
dotPrefix = "dots-"
lineSuffix = "-travelLine"
groupPrefix = "travelLines-"
ignoreWord = "ignore"
if so.nb_main == "tab_remove":
#remove dots
dots = self.document.xpath("//svg:g[starts-with(@id, '" + dotPrefix + "')]", namespaces=inkex.NSS)
for dot in dots:
dot.delete()
#remove travel lines
travelLines = self.document.xpath("//svg:path[contains(@id, '" + lineSuffix + "')]", namespaces=inkex.NSS)
for travelLine in travelLines:
travelLine.delete()
#remove travel groups/layers
travelGroups = self.document.xpath("//svg:g[starts-with(@id, '" + groupPrefix + "')]", namespaces=inkex.NSS)
for travelGroup in travelGroups:
if len(travelGroup) == 0:
travelGroup.delete()
return
#else ...
selectedPaths = [] #total list of elements to parse
def parseChildren(element):
if isinstance(element, inkex.PathElement) and element not in selectedPaths and lineSuffix not in element.get('id') and not isinstance(element.getparent(), inkex.Marker):
selectedPaths.append(element)
children = element.getchildren()
if children is not None:
for child in children:
if isinstance(child, inkex.PathElement) and child not in selectedPaths and lineSuffix not in element.get('id') and not isinstance(element.getparent(), inkex.Marker):
selectedPaths.append(child)
parseChildren(child) #go deeper and deeper
#check if we have selectedPaths elements or if we should parse the whole document instead
if len(self.svg.selected) == 0:
for element in self.document.getroot().iter(tag=etree.Element):
if isinstance(element, inkex.PathElement) and element != self.document.getroot() and lineSuffix not in element.get('id') and not isinstance(element.getparent(), inkex.Marker):
selectedPaths.append(element)
else:
for element in self.svg.selected.values():
parseChildren(element)
dotGroup = self.svg.add(inkex.Group(id=self.svg.get_unique_id(dotPrefix)))
if so.order == "separate_layers":
dotGroup.set("inkscape:groupmode", "layer")
dotGroup.set("inkscape:label", dotPrefix + "layer")
if so.order == "separate_groups":
dotGroup.pop("inkscape:groupmode")
dotGroup.pop("inkscape:label")
if dotGroup.style.get('display') is not None:
dotGroup.style.pop("display") #if the group previously has been a layer (which was hidden), a display:none will be added. we don't want that
if so.arrow_style is True:
markerId = "travel_move_arrow"
self.createTravelMarker(markerId)
#collect all different stroke colors to distinguish by groups #collect all different stroke colors to distinguish by groups
strokeColors = [] strokeColors = []
strokeColorsAndCounts = {} strokeColorsAndCounts = {}
startEndPath = [] #the container for all paths we will loop on '''
the container for all paths we will loop on. Index:
0 = element
1 = start point
2 = end point
'''
startEndPath = []
for element in selectedPaths: for element in selectedPaths:
strokeColor = element.style.get('stroke') strokeColor = element.style.get('stroke')
@ -132,6 +165,7 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
if so.order == "separate_groups": if so.order == "separate_groups":
travelGroup.pop("inkscape:groupmode") travelGroup.pop("inkscape:groupmode")
travelGroup.pop("inkscape:label") travelGroup.pop("inkscape:label")
if travelGroup.style.get('display') is not None:
travelGroup.style.pop("display") travelGroup.style.pop("display")
@ -166,8 +200,22 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
for i in range(0, ran): #loop through the item selection. nested loop. so we loop over alle elements again for each color for i in range(0, ran): #loop through the item selection. nested loop. so we loop over alle elements again for each color
if i < ran - 1: if i < ran - 1:
elementStroke = startEndPath[i][0].style.get('stroke') elementStroke = startEndPath[i][0].style.get('stroke')
currentElement = startEndPath[i][0]
idx = currentElement.getparent().index(currentElement)
travelLineId = currentElement.get('id') + lineSuffix + ("-begin" if firstOccurence is True else "")
if i == ran or createdMoves == colorCount: if i == ran or createdMoves == colorCount:
elementStroke = startEndPath[i-1][0].style.get('stroke') elementStroke = startEndPath[i-1][0].style.get('stroke')
currentElement = startEndPath[i-1][0]
idx = currentElement.getparent().index(currentElement) + 1
travelLineId = currentElement.get('id') + lineSuffix + "-end"
if i < ran - 2:
nextElement = startEndPath[i+1][0]
elif i < ran - 1:
nextElement = startEndPath[i][0]
else:
nextElement = None
if elementStroke is None or elementStroke == "none": if elementStroke is None or elementStroke == "none":
elementStroke = "none" elementStroke = "none"
@ -194,11 +242,10 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
if i == ran - 1: if i == ran - 1:
inkex.utils.debug("segment={},{}".format(startEndPath[i-1][1], travelEnd)) inkex.utils.debug("segment={},{}".format(startEndPath[i-1][1], travelEnd))
travelLine = inkex.PathElement(id=self.svg.get_unique_id(linePrefix) + element.get('id')) travelLine = inkex.PathElement(id=travelLineId)
#if some objects are at svg:svg level this may cause errors #if some objects are at svg:svg level this may cause errors
#if element.getparent() != self.document.getroot(): #if element.getparent() != self.document.getroot():
# travelLine.transform = element.getparent().composed_transform() # travelLine.transform = element.getparent().composed_transform()
travelLine.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(travelStart[0],travelStart[1],travelEnd[0],travelEnd[1]))
travelLine.style = {'stroke': ("#000000" if so.ignore_colors is True else sc), 'fill': 'none', 'stroke-width': str(self.svg.unittouu('1px')), 'marker-end': 'url(#marker1426)'} travelLine.style = {'stroke': ("#000000" if so.ignore_colors is True else sc), 'fill': 'none', 'stroke-width': str(self.svg.unittouu('1px')), 'marker-end': 'url(#marker1426)'}
if so.dashed_style is True: if so.dashed_style is True:
travelLine.style['stroke-dasharray'] = '1,1' travelLine.style['stroke-dasharray'] = '1,1'
@ -206,12 +253,40 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
if so.arrow_style is True: if so.arrow_style is True:
travelLine.style["marker-end"] = "url(#{})".format(markerId) travelLine.style["marker-end"] = "url(#{})".format(markerId)
#this is a really dirty block of code
if so.order == "element_index":
#adding the lines at element index requires to apply transformations for start point and end point (in case they are in different groups)
pseudo1 = inkex.PathElement()
pseudo1.set('d', "M{:0.6f},{:0.6f}".format(travelStart[0],travelStart[1]))
pseudo2 = inkex.PathElement()
pseudo2.set('d', "M{:0.6f},{:0.6f}".format(travelEnd[0],travelEnd[1]))
if nextElement is not None:
if currentElement.getparent() == nextElement.getparent():
pseudo1.path = pseudo1.path.transform(-currentElement.composed_transform()).to_superpath()
pseudo2.path = pseudo2.path.transform(-nextElement.composed_transform()).to_superpath()
else:
pseudo1.path = pseudo1.path.transform(-currentElement.composed_transform()).to_superpath()
pseudo2.path = pseudo2.path.transform(-currentElement.composed_transform()).to_superpath()
else:
pseudo1.path = pseudo1.path.transform(-currentElement.composed_transform()).to_superpath()
pseudo2.path = pseudo2.path.transform(-currentElement.composed_transform()).to_superpath()
travelLine.path = pseudo1.path + pseudo2.get('d').replace("M", "L")
if so.debug is True: self.msg("travelLine={}".format(travelLine.path))
#check the length. if zero we do not add #check the length. if zero we do not add
slengths, stotal = csplength(travelLine.path.transform(element.composed_transform()).to_superpath()) #get segment lengths and total length of path in document's internal unit slengths, stotal = csplength(travelLine.path.transform(currentElement.composed_transform()).to_superpath()) #get segment lengths and total length of path in document's internal unit
if stotal > 0: if stotal > 0:
#finally add the line #finally add the line
travelGroup = self.find_group(groupPrefix + sc) currentElement.getparent().insert(idx, travelLine)
travelGroup.add(travelLine) else:
if so.debug is True: inkex.utils.debug("Line has length of zero")
else:
travelLine.set('d', "M{:0.6f},{:0.6f} L{:0.6f},{:0.6f}".format(travelStart[0],travelStart[1],travelEnd[0],travelEnd[1]))
#check the length. if zero we do not add
slengths, stotal = csplength(travelLine.path.transform(currentElement.composed_transform()).to_superpath()) #get segment lengths and total length of path in document's internal unit
if stotal > 0:
#finally add the line
self.find_group(groupPrefix + sc).add(travelLine)
else: else:
if so.debug is True: inkex.utils.debug("Line has length of zero") if so.debug is True: inkex.utils.debug("Line has length of zero")

View File

@ -307,7 +307,7 @@ class RobotBoxes(inkex.EffectExtension):
# Translate group # Translate group
#transform = 'translate(' + str( self.svg.namedview.center[0] ) + ',' + str( self.svg.namedview.center[1] ) + ')' #transform = 'translate(' + str( self.svg.namedview.center[0] ) + ',' + str( self.svg.namedview.center[1] ) + ')'
g = etree.SubElement(self.svg.get_current_layer(), 'g', {inkex.addNS('label','inkscape'):'RobotBox'}) g = etree.SubElement(self.svg.get_current_layer(), 'g', {inkex.addNS('label','inkscape'):'RobotBox'})
g.transform = transform #g.transform = transform
# Create SVG Path for box bounds # Create SVG Path for box bounds
style = { 'stroke': '#000000', 'fill': 'none', 'stroke-width':str(self.svg.unittouu("1px")) } style = { 'stroke': '#000000', 'fill': 'none', 'stroke-width':str(self.svg.unittouu("1px")) }