Different enhancements
This commit is contained in:
parent
ad73bd72a5
commit
2929277f6f
@ -69,7 +69,7 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
if element.tag == inkex.addNS('path','svg'):
|
if element.tag == inkex.addNS('path','svg'):
|
||||||
parent = element.getparent()
|
parent = element.getparent()
|
||||||
idx = parent.index(element)
|
idx = parent.index(element)
|
||||||
idSuffix = 0
|
idSuffix = 0
|
||||||
raw = element.path.to_arrays()
|
raw = element.path.to_arrays()
|
||||||
subPaths, prev = [], 0
|
subPaths, prev = [], 0
|
||||||
for i in range(len(raw)): # Breaks compound paths into simple paths
|
for i in range(len(raw)): # Breaks compound paths into simple paths
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
@ -29,6 +30,32 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
|
|||||||
if group.get('id') == groupId:
|
if group.get('id') == groupId:
|
||||||
return group
|
return group
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def createTravelMarker(self, markerId):
|
||||||
|
#add new marker to defs (or overwrite if existent)
|
||||||
|
defs = self.svg.defs
|
||||||
|
for defi in defs:
|
||||||
|
if defi.tag == "{http://www.w3.org/2000/svg}marker" and defi.get('id') == markerId: #delete
|
||||||
|
defi.delete()
|
||||||
|
marker = inkex.Marker(id=markerId)
|
||||||
|
marker.set("inkscape:isstock", "true")
|
||||||
|
marker.set("inkscape:stockid", markerId)
|
||||||
|
marker.set("orient", "auto")
|
||||||
|
marker.set("refY", "0.0")
|
||||||
|
marker.set("refX", "0.0")
|
||||||
|
marker.set("style", "overflow:visible;")
|
||||||
|
|
||||||
|
markerPath = inkex.PathElement(id=self.svg.get_unique_id('markerId-'))
|
||||||
|
markerPath.style = {"fill-rule": "evenodd", "fill": "context-stroke", "stroke-width": str(self.svg.unittouu('1px'))}
|
||||||
|
markerPath.transform = "scale(1.0,1.0) rotate(0) translate(-6.0,0)"
|
||||||
|
arrowHeight = 6.0
|
||||||
|
markerPath.attrib["transform"] = "scale({},{}) rotate(0) translate(-{},0)".format(so.arrow_size, so.arrow_size, arrowHeight)
|
||||||
|
markerPath.path = "M {},0.0 L -3.0,5.0 L -3.0,-5.0 L {},0.0 z".format(arrowHeight, arrowHeight)
|
||||||
|
|
||||||
|
marker.append(markerPath)
|
||||||
|
defs.append(marker) #do not append before letting contain it one path. Otherwise Inkscape is going to crash immediately
|
||||||
|
|
||||||
|
|
||||||
def add_arguments(self, pars):
|
def add_arguments(self, pars):
|
||||||
pars.add_argument("--nb_main")
|
pars.add_argument("--nb_main")
|
||||||
@ -46,26 +73,46 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
|
|||||||
global so
|
global so
|
||||||
so = self.options
|
so = self.options
|
||||||
dotPrefix = "dots-"
|
dotPrefix = "dots-"
|
||||||
linePrefix = "travelLine-"
|
lineSuffix = "-travelLine"
|
||||||
groupPrefix = "travelLines-"
|
groupPrefix = "travelLines-"
|
||||||
ignoreWord = "ignore"
|
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
|
selectedPaths = [] #total list of elements to parse
|
||||||
|
|
||||||
def parseChildren(element):
|
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):
|
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)
|
selectedPaths.append(element)
|
||||||
children = element.getchildren()
|
children = element.getchildren()
|
||||||
if children is not None:
|
if children is not None:
|
||||||
for child in children:
|
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):
|
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)
|
selectedPaths.append(child)
|
||||||
parseChildren(child) #go deeper and deeper
|
parseChildren(child) #go deeper and deeper
|
||||||
|
|
||||||
#check if we have selectedPaths elements or if we should parse the whole document instead
|
#check if we have selectedPaths elements or if we should parse the whole document instead
|
||||||
if len(self.svg.selected) == 0:
|
if len(self.svg.selected) == 0:
|
||||||
for element in self.document.getroot().iter(tag=etree.Element):
|
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):
|
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)
|
selectedPaths.append(element)
|
||||||
else:
|
else:
|
||||||
for element in self.svg.selected.values():
|
for element in self.svg.selected.values():
|
||||||
@ -78,37 +125,23 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
|
|||||||
if so.order == "separate_groups":
|
if so.order == "separate_groups":
|
||||||
dotGroup.pop("inkscape:groupmode")
|
dotGroup.pop("inkscape:groupmode")
|
||||||
dotGroup.pop("inkscape:label")
|
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 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:
|
if so.arrow_style is True:
|
||||||
markerId = "travel_move_arrow"
|
markerId = "travel_move_arrow"
|
||||||
#add new marker to defs (or overwrite if existent)
|
self.createTravelMarker(markerId)
|
||||||
defs = self.svg.defs
|
|
||||||
for defi in defs:
|
|
||||||
if defi.tag == "{http://www.w3.org/2000/svg}marker" and defi.get('id') == markerId: #delete
|
|
||||||
defi.delete()
|
|
||||||
marker = inkex.Marker(id=markerId)
|
|
||||||
marker.set("inkscape:isstock", "true")
|
|
||||||
marker.set("inkscape:stockid", markerId)
|
|
||||||
marker.set("orient", "auto")
|
|
||||||
marker.set("refY", "0.0")
|
|
||||||
marker.set("refX", "0.0")
|
|
||||||
marker.set("style", "overflow:visible;")
|
|
||||||
|
|
||||||
markerPath = inkex.PathElement(id=self.svg.get_unique_id('markerId-'))
|
|
||||||
markerPath.style = {"fill-rule": "evenodd", "fill": "context-stroke", "stroke-width": str(self.svg.unittouu('1px'))}
|
|
||||||
markerPath.transform = "scale(1.0,1.0) rotate(0) translate(-6.0,0)"
|
|
||||||
arrowHeight = 6.0
|
|
||||||
markerPath.attrib["transform"] = "scale({},{}) rotate(0) translate(-{},0)".format(so.arrow_size, so.arrow_size, arrowHeight)
|
|
||||||
markerPath.path = "M {},0.0 L -3.0,5.0 L -3.0,-5.0 L {},0.0 z".format(arrowHeight, arrowHeight)
|
|
||||||
|
|
||||||
marker.append(markerPath)
|
|
||||||
defs.append(marker) #do not append before letting contain it one path. Otherwise Inkscape is going to crash immediately
|
|
||||||
|
|
||||||
#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,7 +165,8 @@ 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")
|
||||||
travelGroup.style.pop("display")
|
if travelGroup.style.get('display') is not None:
|
||||||
|
travelGroup.style.pop("display")
|
||||||
|
|
||||||
|
|
||||||
p = element.path.transform(element.composed_transform())
|
p = element.path.transform(element.composed_transform())
|
||||||
@ -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,26 +242,53 @@ 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'
|
||||||
travelLine.style['stroke-dashoffset'] = '0'
|
travelLine.style['stroke-dashoffset'] = '0'
|
||||||
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)
|
||||||
|
|
||||||
#check the length. if zero we do not add
|
#this is a really dirty block of code
|
||||||
slengths, stotal = csplength(travelLine.path.transform(element.composed_transform()).to_superpath()) #get segment lengths and total length of path in document's internal unit
|
if so.order == "element_index":
|
||||||
if stotal > 0:
|
#adding the lines at element index requires to apply transformations for start point and end point (in case they are in different groups)
|
||||||
#finally add the line
|
pseudo1 = inkex.PathElement()
|
||||||
travelGroup = self.find_group(groupPrefix + sc)
|
pseudo1.set('d', "M{:0.6f},{:0.6f}".format(travelStart[0],travelStart[1]))
|
||||||
travelGroup.add(travelLine)
|
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
|
||||||
|
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
|
||||||
|
currentElement.getparent().insert(idx, travelLine)
|
||||||
|
else:
|
||||||
|
if so.debug is True: inkex.utils.debug("Line has length of zero")
|
||||||
else:
|
else:
|
||||||
if so.debug is True: inkex.utils.debug("Line has length of zero")
|
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:
|
||||||
|
if so.debug is True: inkex.utils.debug("Line has length of zero")
|
||||||
|
|
||||||
createdMoves += 1 #each time we created a move we count up. we want to compare against the total count of that color
|
createdMoves += 1 #each time we created a move we count up. we want to compare against the total count of that color
|
||||||
if so.debug is True: inkex.utils.debug("createdMoves={}".format(createdMoves))
|
if so.debug is True: inkex.utils.debug("createdMoves={}".format(createdMoves))
|
||||||
|
@ -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")) }
|
||||||
|
Reference in New Issue
Block a user