Merge branch 'master' of https://a57dddbd884b156656bcbfbcfdaec326792169a2@gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X.git
This commit is contained in:
commit
d6409fda72
@ -36,7 +36,7 @@ DETACHED_PROCESS = 0x00000008
|
|||||||
|
|
||||||
class AnimateOrder(inkex.EffectExtension):
|
class AnimateOrder(inkex.EffectExtension):
|
||||||
|
|
||||||
def spawnIndependentProcess(self, args): #function to spawn non-blocking inkscape instance. the inkscape command is available because it is added to ENVIRONMENT when Inkscape main instance is started
|
def spawnIndependentProcess(self, args):
|
||||||
warnings.simplefilter('ignore', ResourceWarning) #suppress "enable tracemalloc to get the object allocation traceback"
|
warnings.simplefilter('ignore', ResourceWarning) #suppress "enable tracemalloc to get the object allocation traceback"
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
subprocess.Popen(args, close_fds=True, creationflags=DETACHED_PROCESS)
|
subprocess.Popen(args, close_fds=True, creationflags=DETACHED_PROCESS)
|
||||||
|
@ -3,7 +3,13 @@
|
|||||||
<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">
|
||||||
|
<option value="separate_groups">To separate groups</option>
|
||||||
|
<option value="separate_layers">To separate layers</option>
|
||||||
|
<option value="element_index">At element's index</option>
|
||||||
|
</param>
|
||||||
|
<separator/>
|
||||||
<param name="draw_dots" type="bool" gui-text="Draw dots" gui-description="Start and end point of opened (red + blue) and closed paths (green + yellow)">true</param>
|
<param name="draw_dots" type="bool" gui-text="Draw dots" gui-description="Start and end point of opened (red + blue) and closed paths (green + yellow)">true</param>
|
||||||
<param name="dotsize" type="int" min="1" max="9999" gui-text="Dot size (px)">10</param>
|
<param name="dotsize" type="int" min="1" max="9999" gui-text="Dot size (px)">10</param>
|
||||||
<separator/>
|
<separator/>
|
||||||
@ -15,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)
|
||||||
@ -30,9 +31,35 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
|
|||||||
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")
|
||||||
|
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("--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("--dotsize", type=int, default=10, help="Dot size (px)")
|
||||||
pars.add_argument("--draw_travel_moves", type=inkex.Boolean, default=False)
|
pars.add_argument("--draw_travel_moves", type=inkex.Boolean, default=False)
|
||||||
@ -45,62 +72,76 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
|
|||||||
def effect(self):
|
def effect(self):
|
||||||
global so
|
global so
|
||||||
so = self.options
|
so = self.options
|
||||||
linePrefix = "travelLine-"
|
dotPrefix = "dots-"
|
||||||
|
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():
|
||||||
parseChildren(element)
|
parseChildren(element)
|
||||||
|
|
||||||
dot_group = self.svg.add(inkex.Group())
|
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:
|
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')
|
||||||
@ -112,11 +153,21 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
|
|||||||
groupName = groupPrefix + strokeColor
|
groupName = groupPrefix + strokeColor
|
||||||
travelGroup = self.find_group(groupName)
|
travelGroup = self.find_group(groupName)
|
||||||
if travelGroup is None:
|
if travelGroup is None:
|
||||||
self.document.getroot().append(inkex.Group(id=groupName))
|
travelGroup = inkex.Group(id=groupName)
|
||||||
|
self.document.getroot().append(travelGroup)
|
||||||
else: #exists
|
else: #exists
|
||||||
self.document.getroot().append(travelGroup)
|
self.document.getroot().append(travelGroup)
|
||||||
for child in travelGroup:
|
for child in travelGroup:
|
||||||
child.delete()
|
child.delete()
|
||||||
|
if so.order == "separate_layers":
|
||||||
|
travelGroup.set("inkscape:groupmode", "layer")
|
||||||
|
travelGroup.set("inkscape:label", groupName + "-layer")
|
||||||
|
if so.order == "separate_groups":
|
||||||
|
travelGroup.pop("inkscape:groupmode")
|
||||||
|
travelGroup.pop("inkscape:label")
|
||||||
|
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())
|
||||||
points = list(p.end_points)
|
points = list(p.end_points)
|
||||||
@ -127,11 +178,11 @@ class DrawDirectionsTravelMoves(inkex.EffectExtension):
|
|||||||
|
|
||||||
if so.draw_dots is True:
|
if so.draw_dots is True:
|
||||||
if start[0] == end[0] and start[1] == end[1]:
|
if start[0] == end[0] and start[1] == end[1]:
|
||||||
self.drawCircle(dot_group, '#00FF00', start)
|
self.drawCircle(dotGroup, '#00FF00', start)
|
||||||
self.drawCircle(dot_group, '#FFFF00', points[1]) #draw one point which gives direction of the path
|
self.drawCircle(dotGroup, '#FFFF00', points[1]) #draw one point which gives direction of the path
|
||||||
else: #open contour with start and end point
|
else: #open contour with start and end point
|
||||||
self.drawCircle(dot_group, '#FF0000', start)
|
self.drawCircle(dotGroup, '#FF0000', start)
|
||||||
self.drawCircle( dot_group, '#0000FF', end)
|
self.drawCircle( dotGroup, '#0000FF', end)
|
||||||
|
|
||||||
for strokeColor in strokeColors:
|
for strokeColor in strokeColors:
|
||||||
if strokeColor in strokeColorsAndCounts:
|
if strokeColor in strokeColorsAndCounts:
|
||||||
@ -149,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"
|
||||||
|
|
||||||
@ -177,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'
|
||||||
@ -189,22 +253,50 @@ 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)
|
||||||
|
|
||||||
#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))
|
||||||
if so.debug is True: inkex.utils.debug("-"*40)
|
if so.debug is True: inkex.utils.debug("-"*40)
|
||||||
|
|
||||||
#cleanup empty groups
|
#cleanup empty groups
|
||||||
if len(dot_group) == 0:
|
if len(dotGroup) == 0:
|
||||||
dot_group.delete()
|
dotGroup.delete()
|
||||||
travelGroups = self.document.xpath("//svg:g[starts-with(@id, 'travelLines-')]", namespaces=inkex.NSS)
|
travelGroups = self.document.xpath("//svg:g[starts-with(@id, 'travelLines-')]", namespaces=inkex.NSS)
|
||||||
for travelGroup in travelGroups:
|
for travelGroup in travelGroups:
|
||||||
if len(travelGroup) == 0:
|
if len(travelGroup) == 0:
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
<label appearance="header">General Settings</label>
|
<label appearance="header">General Settings</label>
|
||||||
<param name="debug" type="bool" gui-text="Enable debug">false</param>
|
<param name="debug" type="bool" gui-text="Enable debug">false</param>
|
||||||
<param name="apply_transformations" type="bool" gui-text="Apply transformations (requires separate extension)" gui-description="This will call the extension 'Apply Transformations'. Helps avoiding geometry shifting">false</param>
|
<param name="apply_transformations" type="bool" gui-text="Apply transformations (requires separate extension)" gui-description="This will call the extension 'Apply Transformations'. Helps avoiding geometry shifting">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="breakapart" type="bool" gui-text="Break apart selected path(s) into segments" gui-description="Performs CTRL + SHIFT + K to break paths into parts">true</param>
|
||||||
|
<param name="breakapart_total" type="bool" gui-text="Break segments to lines" gui-description="Gives the best results for nodes/<interval> filtering">true</param>
|
||||||
<hbox>
|
<hbox>
|
||||||
<vbox>
|
<vbox>
|
||||||
<label appearance="header">Threshold</label>
|
<label appearance="header">Threshold</label>
|
||||||
|
@ -30,7 +30,8 @@ class FilterByLengthArea(inkex.EffectExtension):
|
|||||||
pars.add_argument('--tab')
|
pars.add_argument('--tab')
|
||||||
pars.add_argument('--debug', type=inkex.Boolean, default=False)
|
pars.add_argument('--debug', type=inkex.Boolean, default=False)
|
||||||
pars.add_argument("--apply_transformations", type=inkex.Boolean, default=False, help="Run 'Apply Transformations' extension before running vpype. Helps avoiding geometry shifting")
|
pars.add_argument("--apply_transformations", type=inkex.Boolean, default=False, help="Run 'Apply Transformations' extension before running vpype. Helps avoiding geometry shifting")
|
||||||
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("--breakapart", type=inkex.Boolean, default=True, help="Break apart selected path(s) into segments")
|
||||||
|
pars.add_argument("--breakapart_total", type=inkex.Boolean, default=True, help="Gives the best results for nodes/<interval> filtering")
|
||||||
pars.add_argument("--cleanup", type=inkex.Boolean, default = True, help = "Cleanup all unused groups/layers (requires separate extension)")
|
pars.add_argument("--cleanup", type=inkex.Boolean, default = True, help = "Cleanup all unused groups/layers (requires separate extension)")
|
||||||
pars.add_argument('--unit')
|
pars.add_argument('--unit')
|
||||||
pars.add_argument('--min_filter_enable', type=inkex.Boolean, default=True, help='Enable filtering min.')
|
pars.add_argument('--min_filter_enable', type=inkex.Boolean, default=True, help='Enable filtering min.')
|
||||||
@ -63,21 +64,40 @@ class FilterByLengthArea(inkex.EffectExtension):
|
|||||||
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
|
if self.options.breakapart_total is False:
|
||||||
if raw[i][0] == 'M' and i != 0:
|
for i in range(len(raw)): # Breaks compound paths into simple paths
|
||||||
subPaths.append(raw[prev:i])
|
if raw[i][0] == 'M' and i != 0:
|
||||||
prev = i
|
subPaths.append(raw[prev:i])
|
||||||
subPaths.append(raw[prev:])
|
prev = i
|
||||||
|
subPaths.append(raw[prev:])
|
||||||
|
else:
|
||||||
|
rawCopy = element.path.to_arrays() #we need another set of the same path
|
||||||
|
for i in range(len(raw)): # Breaks compound paths into simple paths
|
||||||
|
if i != 0:
|
||||||
|
if raw[i][0] == 'C':
|
||||||
|
rawCopy[i][1] = [raw[i][1][-2], raw[i][1][-1]]
|
||||||
|
elif raw[i][0] == 'L':
|
||||||
|
rawCopy[i][1] = [raw[i][1][0], raw[i][1][1]]
|
||||||
|
elif raw[i][0] == 'Z': #replace Z with another L command (which moves to the coordinates of the first M command in path) to have better overview
|
||||||
|
raw[-1][0] = 'L'
|
||||||
|
raw[-1][1] = raw[0][1]
|
||||||
|
rawCopy[i][0] = 'M' #we really need M. Does not matter if 'L' or 'C'.
|
||||||
|
#self.msg("s1={},s2={}".format(rawCopy[i-1], raw[i]))
|
||||||
|
subPaths.append([rawCopy[i-1], raw[i]])
|
||||||
|
prev = i
|
||||||
|
subPaths = subPaths[::-1]
|
||||||
|
|
||||||
for subpath in subPaths:
|
for subpath in subPaths:
|
||||||
|
#self.msg(subpath)
|
||||||
replacedelement = copy.copy(element)
|
replacedelement = copy.copy(element)
|
||||||
oldId = replacedelement.get('id')
|
oldId = replacedelement.get('id')
|
||||||
csp = CubicSuperPath(subpath)
|
csp = CubicSuperPath(subpath)
|
||||||
if len(subpath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
|
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)
|
replacedelement.set('d', csp)
|
||||||
if len(subPaths) == 1:
|
if len(subPaths) == 1:
|
||||||
replacedelement.set('id', oldId)
|
replacedelement.set('id', "{}".format(oldId))
|
||||||
else:
|
else:
|
||||||
replacedelement.set('id', oldId + str(idSuffix))
|
replacedelement.set('id', "{}-{}".format(oldId, str(idSuffix)))
|
||||||
idSuffix += 1
|
idSuffix += 1
|
||||||
parent.insert(idx, replacedelement)
|
parent.insert(idx, replacedelement)
|
||||||
breakelements.append(replacedelement)
|
breakelements.append(replacedelement)
|
||||||
@ -116,7 +136,7 @@ class FilterByLengthArea(inkex.EffectExtension):
|
|||||||
elements.extend(self.breakContours(element, None))
|
elements.extend(self.breakContours(element, None))
|
||||||
|
|
||||||
if so.debug is True:
|
if so.debug is True:
|
||||||
inkex.utils.debug("Collecting elements ...")
|
inkex.utils.debug("Collecting svg:path elements ...")
|
||||||
|
|
||||||
for element in elements:
|
for element in elements:
|
||||||
# additional option to apply transformations. As we clear up some groups to form new layers, we might lose translations, rotations, etc.
|
# additional option to apply transformations. As we clear up some groups to form new layers, we might lose translations, rotations, etc.
|
||||||
@ -229,12 +249,15 @@ class FilterByLengthArea(inkex.EffectExtension):
|
|||||||
if so.group is True:
|
if so.group is True:
|
||||||
group.append(element)
|
group.append(element)
|
||||||
|
|
||||||
if so.cleanup == True:
|
#if len(group) == 0:
|
||||||
try:
|
# group.delete()
|
||||||
import remove_empty_groups
|
|
||||||
remove_empty_groups.RemoveEmptyGroups.effect(self)
|
if so.cleanup is True:
|
||||||
except:
|
try:
|
||||||
self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...")
|
import remove_empty_groups
|
||||||
|
remove_empty_groups.RemoveEmptyGroups.effect(self)
|
||||||
|
except:
|
||||||
|
self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
FilterByLengthArea().run()
|
FilterByLengthArea().run()
|
@ -5,6 +5,7 @@
|
|||||||
<param name="begin_str" type="string" gui-text="begin_str:">0</param>
|
<param name="begin_str" type="string" gui-text="begin_str:">0</param>
|
||||||
<param name="repeat_str" type="string" gui-text="repeat_str:">indefinite</param>
|
<param name="repeat_str" type="string" gui-text="repeat_str:">indefinite</param>
|
||||||
<param name="dur_str" type="string" gui-text="dur_str:">9.1</param>
|
<param name="dur_str" type="string" gui-text="dur_str:">9.1</param>
|
||||||
|
<param name="delete" type="bool" gui-text="Remove frames">true</param>
|
||||||
<effect>
|
<effect>
|
||||||
<object-type>all</object-type>
|
<object-type>all</object-type>
|
||||||
<effects-menu>
|
<effects-menu>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# coding=utf-8
|
|
||||||
#
|
#
|
||||||
# Copyright (C) 2021 roberta bennett repeatingshadow@protonmail.com
|
# Copyright (C) 2021 roberta bennett repeatingshadow@protonmail.com
|
||||||
#
|
#
|
||||||
@ -18,15 +17,18 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
"""
|
"""
|
||||||
Create svg path animation from frames.
|
Create svg path animation as SMIL from frames.
|
||||||
|
|
||||||
Place each frame of the animation in a layer named 'frame'.
|
Place each frame of the animation in a layer named 'frame'.
|
||||||
Each of these layers should have the same number of paths,
|
Each of these layers should have the same number of paths,
|
||||||
and each path should have the same number of points as the corresponding
|
and each path should have the same number of points as the corresponding
|
||||||
path in other layers.
|
path in other layers.
|
||||||
|
Note if there are more than one path in the frames, the Z order of the paths
|
||||||
|
must match. It helps to use the XML editor option to observe the z order.
|
||||||
|
|
||||||
The animation is applied to the paths in the first layer in the sequence, so the
|
The animation is applied to the paths in the first layer in the sequence, so the
|
||||||
properties of that layer are used.
|
properties of that layer are used. In particular, the first layer ought to be set
|
||||||
|
visible.
|
||||||
|
|
||||||
Animations with different numbers of frames can be put into different sequences,
|
Animations with different numbers of frames can be put into different sequences,
|
||||||
named 'sequence', using sub-groups:
|
named 'sequence', using sub-groups:
|
||||||
@ -51,9 +53,9 @@ Layers:
|
|||||||
frame
|
frame
|
||||||
frame
|
frame
|
||||||
|
|
||||||
|
Layer names must contain 'frame' and groups names contain 'sequence',
|
||||||
|
eg, frame1 frame 2 frame 30, sequence 1, rythm sequence, rocket sequence
|
||||||
|
|
||||||
use layer named exactly 'frame' and groups named exactly 'sequence',
|
|
||||||
not, eg, frame1 frame2 frame3 !
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -70,36 +72,52 @@ class AnimateElement(inkex.BaseElement):
|
|||||||
class AnimationExtension(inkex.EffectExtension):
|
class AnimationExtension(inkex.EffectExtension):
|
||||||
|
|
||||||
def add_arguments(self, pars):
|
def add_arguments(self, pars):
|
||||||
|
pars.add_argument("--delete", type=inkex.Boolean, help="Remove frames")
|
||||||
pars.add_argument("--begin_str", default="0", help="begin string: eg 0;an2.end;an3.begin")
|
pars.add_argument("--begin_str", default="0", help="begin string: eg 0;an2.end;an3.begin")
|
||||||
pars.add_argument("--repeat_str", default="indefinite", help="indefinite or an integer")
|
pars.add_argument("--repeat_str", default="indefinite", help="indefinite or an integer")
|
||||||
pars.add_argument("--dur_str", default="7.9", help="duration in seconds. Do not decorate with units")
|
pars.add_argument("--dur_str", default="7.9", help="duration in seconds. Do not decorate with units")
|
||||||
|
|
||||||
|
|
||||||
|
def crunchFrames(self,frames):
|
||||||
|
if frames is None:
|
||||||
|
raise inkex.AbortExtension("layer named frame does not exist.")
|
||||||
|
frame0paths = frames[0].findall('svg:path')
|
||||||
|
Dlists = [p.get_path() for p in frame0paths]
|
||||||
|
for frame in frames[1:]:
|
||||||
|
paths = frame.findall("svg:path")
|
||||||
|
for i,p in enumerate(paths):
|
||||||
|
Dlists[i] += ";\n"+p.get_path()
|
||||||
|
for i,dl in enumerate(Dlists):
|
||||||
|
animel = AnimateElement(
|
||||||
|
attributeName="d",
|
||||||
|
attributeType="XML",
|
||||||
|
begin=self.options.begin_str,
|
||||||
|
dur=self.options.dur_str,
|
||||||
|
repeatCount=self.options.repeat_str,
|
||||||
|
values=dl)
|
||||||
|
frame0paths[i].append(animel)
|
||||||
|
for frame in frames[1:]:
|
||||||
|
if self.options.delete:
|
||||||
|
frame.delete()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def effect(self):
|
def effect(self):
|
||||||
sequences = self.svg.findall("svg:g[@inkscape:label='sequence']")
|
sequences = [ elem for elem in self.svg.findall("svg:g[@inkscape:label]")
|
||||||
if len(sequences) == 0:
|
if "sequence" in (elem.get('inkscape:label'))
|
||||||
raise inkex.AbortExtension("layer named sequence does not exist.")
|
]
|
||||||
|
if len(sequences)==0:
|
||||||
|
frames = [ elem for elem in self.svg.findall("svg:g[@inkscape:label]")
|
||||||
|
if "frame" in (elem.get('inkscape:label'))
|
||||||
|
]
|
||||||
|
self.crunchFrames(frames)
|
||||||
|
return
|
||||||
for sequence in sequences:
|
for sequence in sequences:
|
||||||
frames = sequence.findall("svg:g[@inkscape:label='frame']")
|
frames = [ elem for elem in sequence.findall("svg:g[@inkscape:label]")
|
||||||
if len(frames) == 0:
|
if "frame" in (elem.get('inkscape:label'))
|
||||||
raise inkex.AbortExtension("layer named frame does not exist.")
|
]
|
||||||
frame0paths = frames[0].findall('svg:path')
|
self.crunchFrames(frames)
|
||||||
Dlists = [p.get_path() for p in frame0paths]
|
|
||||||
for frame in frames[1:]:
|
|
||||||
paths = frame.findall("svg:path")
|
|
||||||
for i,p in enumerate(paths):
|
|
||||||
Dlists[i] += ";\n"+p.get_path()
|
|
||||||
for i,dl in enumerate(Dlists):
|
|
||||||
animel = AnimateElement(
|
|
||||||
attributeName="d",
|
|
||||||
attributeType="XML",
|
|
||||||
begin=self.options.begin_str,
|
|
||||||
dur=self.options.dur_str,
|
|
||||||
repeatCount=self.options.repeat_str,
|
|
||||||
values=dl)
|
|
||||||
frame0paths[i].append(animel)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
AnimationExtension().run()
|
AnimationExtension().run()
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,9 +59,8 @@
|
|||||||
<option value="1016x711">1016 x 711 mm (Fusion M2 40)</option>
|
<option value="1016x711">1016 x 711 mm (Fusion M2 40)</option>
|
||||||
<option value="1219x914">1219 x 914 mm (Fusion Pro 48)</option>
|
<option value="1219x914">1219 x 914 mm (Fusion Pro 48)</option>
|
||||||
</param>
|
</param>
|
||||||
<param name="max_cutting_speed" type="float" min="1.000" max="9999.000" precision="2" gui-text="Max. cutting speed (mm/s)">120</param>
|
<param name="max_cutting_speed" type="float" min="1.000" max="9999.000" precision="2" gui-text="Max. cutting speed (mm/s)">120.0</param>
|
||||||
<param name="max_travel_speed" type="float" min="1.000" max="9999.000" precision="2" gui-text="Max. travel speed (mm/s)">500</param>
|
<param name="max_travel_speed" type="float" min="1.000" max="9999.000" precision="2" gui-text="Max. travel speed (mm/s)">500.0</param>
|
||||||
<param name="cut_travel_factor" type="float" min="0.001" max="10.00" precision="3" gui-text="Factor between cutting/travel moves" gui-description="Usually ~60-80% are cutting time, rest is travel time. Set this factor to express the amount of travel time in relation to cutting time.">0.60</param>
|
|
||||||
<param name="price_per_minute_gross" type="float" min="0.0" max="9999.0" precision="2" gui-text="Price/minute € (gross)">2.0</param>
|
<param name="price_per_minute_gross" type="float" min="0.0" max="9999.0" precision="2" gui-text="Price/minute € (gross)">2.0</param>
|
||||||
<param name="vector_grid_xy" type="float" min="0.0" max="9999.0" precision="2" gui-text="Vector grid (mm)">12.0</param>
|
<param name="vector_grid_xy" type="float" min="0.0" max="9999.0" precision="2" gui-text="Vector grid (mm)">12.0</param>
|
||||||
</page>
|
</page>
|
||||||
|
@ -13,17 +13,16 @@ class LaserCheck(inkex.EffectExtension):
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
ToDos:
|
ToDos:
|
||||||
|
- check for elements which have the attribute "display:none" (some groups have this)
|
||||||
- inx:
|
- inx:
|
||||||
- set speed manually or pick machine (epilog) - travel and cut speed are prefilled then
|
- set speed manually or pick machine (epilog) - travel and cut speed are prefilled then
|
||||||
- calculate cut estimation with linear or non-linear (epiloog) speeds > select formula or like this
|
- calculate cut estimation with linear or non-linear (epilog) speeds > select formula or like this
|
||||||
- select time estimation for specific speed percentage for for all speeds (100,90, ...)
|
- select time estimation for specific speed percentage for for all speeds (100,90, ...)
|
||||||
- select material (parameters -> how to???)
|
- select material (parameters -> how to???)
|
||||||
- select power of CO² source
|
- select power of CO² source
|
||||||
- add fields for additional costs like configuring the machine or grabbing parts out of the machine (weeding), etc.
|
- add fields for additional costs like configuring the machine or grabbing parts out of the machine (weeding), etc.
|
||||||
- add mode select: cut, engrave
|
- add mode select: cut, engrave
|
||||||
- look for lines especially containing id "travelLines-" and sum up travel lines
|
|
||||||
- add some extra seconds for start, stop, removing parts, attaching material, ...
|
- add some extra seconds for start, stop, removing parts, attaching material, ...
|
||||||
- maybe remove totalTravelLength and set manually ...
|
|
||||||
- Handlungsempfehlungen einbauen
|
- Handlungsempfehlungen einbauen
|
||||||
- verweisen auf diverse plugins, die man nutzen kann:
|
- verweisen auf diverse plugins, die man nutzen kann:
|
||||||
- migrate ungrouper
|
- migrate ungrouper
|
||||||
@ -65,9 +64,8 @@ class LaserCheck(inkex.EffectExtension):
|
|||||||
pars.add_argument('--tab')
|
pars.add_argument('--tab')
|
||||||
|
|
||||||
pars.add_argument('--machine_size', default="812x508")
|
pars.add_argument('--machine_size', default="812x508")
|
||||||
pars.add_argument('--max_cutting_speed', type=float, default=500)
|
pars.add_argument('--max_cutting_speed', type=float, default=120)
|
||||||
pars.add_argument('--max_travel_speed', type=float, default=150)
|
pars.add_argument('--max_travel_speed', type=float, default=500)
|
||||||
pars.add_argument('--cut_travel_factor', type=float, default=0.60)
|
|
||||||
pars.add_argument('--price_per_minute_gross', type=float, default=2.0)
|
pars.add_argument('--price_per_minute_gross', type=float, default=2.0)
|
||||||
pars.add_argument('--vector_grid_xy', type=float, default=12.0) #TODO
|
pars.add_argument('--vector_grid_xy', type=float, default=12.0) #TODO
|
||||||
|
|
||||||
@ -572,27 +570,36 @@ class LaserCheck(inkex.EffectExtension):
|
|||||||
if so.checks == "check_all" or so.cutting_estimation is True:
|
if so.checks == "check_all" or so.cutting_estimation is True:
|
||||||
inkex.utils.debug("\n---------- Cutting time estimation (Epilog Lasers)")
|
inkex.utils.debug("\n---------- Cutting time estimation (Epilog Lasers)")
|
||||||
totalCuttingLength = 0
|
totalCuttingLength = 0
|
||||||
pathCount = 0
|
totalTravelLength = 0
|
||||||
|
cuttingPathCount = 0
|
||||||
|
travelPathCount = 0
|
||||||
|
|
||||||
for element in shapes:
|
for element in shapes:
|
||||||
if isinstance(element, inkex.PathElement):
|
if isinstance(element, inkex.PathElement):
|
||||||
slengths, stotal = csplength(element.path.transform(element.composed_transform()).to_superpath())
|
slengths, stotal = csplength(element.path.transform(element.composed_transform()).to_superpath())
|
||||||
totalCuttingLength += stotal
|
if "-travelLine" in element.get('id'): #we use that id scheme together with the extension "Draw Directions / Travel Moves"
|
||||||
pathCount += 1 #each path has one start and one end (if open path) or start=end on closed path. For cutting the we calculate with 2 points because we enter and leave each path ALWAYS
|
totalTravelLength += stotal
|
||||||
totalTravelLength = totalCuttingLength * so.cut_travel_factor
|
travelPathCount += 1
|
||||||
|
elif "markerId-" in element.get('id'):
|
||||||
|
pass #we skip the path "markerId-<nr>", possibly generated by the extension "Draw Directions / Travel Moves
|
||||||
|
else:
|
||||||
|
totalCuttingLength += stotal
|
||||||
|
cuttingPathCount += 1
|
||||||
totalLength = totalCuttingLength + totalTravelLength
|
totalLength = totalCuttingLength + totalTravelLength
|
||||||
inkex.utils.debug("total paths={}".format(pathCount))
|
inkex.utils.debug("total cutting paths={}".format(cuttingPathCount))
|
||||||
|
inkex.utils.debug("total travel paths={}".format(travelPathCount))
|
||||||
inkex.utils.debug("(measured) cutting length (mm) = {:0.2f} mm".format(self.svg.uutounit(str(totalCuttingLength), "mm"), self.svg.uutounit(str(totalCuttingLength), "mm")))
|
inkex.utils.debug("(measured) cutting length (mm) = {:0.2f} mm".format(self.svg.uutounit(str(totalCuttingLength), "mm"), self.svg.uutounit(str(totalCuttingLength), "mm")))
|
||||||
inkex.utils.debug("(estimated) travel length (mm) = {:0.2f} mm".format(self.svg.uutounit(str(totalTravelLength), "mm"), self.svg.uutounit(str(totalTravelLength), "mm")))
|
inkex.utils.debug("(measured) travel length (mm) = {:0.2f} mm".format(self.svg.uutounit(str(totalTravelLength), "mm"), self.svg.uutounit(str(totalTravelLength), "mm")))
|
||||||
inkex.utils.debug("(estimated) total length (mm) = {:0.2f} mm".format(self.svg.uutounit(str(totalLength), "mm"), self.svg.uutounit(str(totalLength), "mm")))
|
inkex.utils.debug("(measured) total length (mm) = {:0.2f} mm".format(self.svg.uutounit(str(totalLength), "mm"), self.svg.uutounit(str(totalLength), "mm")))
|
||||||
''' from https://www.epiloglaser.com/assets/downloads/fusion-material-settings.pdf
|
''' from https://www.epiloglaser.com/assets/downloads/fusion-material-settings.pdf
|
||||||
Speed Settings: The speed setting scale of 1% to 100% is not linear –
|
"Speed Settings: The speed setting scale of 1% to 100% is not linear –
|
||||||
i.e. 100% speed will not be twice as fast as 50% speed. This non-linear
|
i.e. 100% speed will not be twice as fast as 50% speed. This non-linear
|
||||||
scale is very useful in compensating for the different factors that affect engraving time.
|
scale is very useful in compensating for the different factors that affect engraving time."
|
||||||
'''
|
'''
|
||||||
for speedFactor in [100,90,80,70,60,50,40,30,20,10,9,8,7,6,5,4,3,2,1]:
|
for speedFactor in [100,90,80,70,60,50,40,30,20,10,9,8,7,6,5,4,3,2,1]:
|
||||||
speedFactorR = speedFactor / 100.0
|
speedFactorR = speedFactor / 100.0
|
||||||
adjusted_speed = 482.4000 / so.max_cutting_speed #empiric - found out by trying for hours ...
|
adjusted_speed = 480.0 / so.max_cutting_speed #empiric - found out by trying for hours ...
|
||||||
empiric_scale = 1 + (speedFactorR**2) / 19.0 #empiric - found out by trying for hours ...
|
empiric_scale = 1 + (speedFactorR**2) / 15.25 #empiric - found out by trying for hours ...
|
||||||
v_cut = so.max_cutting_speed * speedFactorR
|
v_cut = so.max_cutting_speed * speedFactorR
|
||||||
v_travel = so.max_travel_speed #this is always at maximum
|
v_travel = so.max_travel_speed #this is always at maximum
|
||||||
tsec_cut = (self.svg.uutounit(str(totalCuttingLength)) / (adjusted_speed * so.max_cutting_speed * speedFactorR)) * empiric_scale
|
tsec_cut = (self.svg.uutounit(str(totalCuttingLength)) / (adjusted_speed * so.max_cutting_speed * speedFactorR)) * empiric_scale
|
||||||
|
20
extensions/fablabchemnitz/open_dir/meta.json
Normal file
20
extensions/fablabchemnitz/open_dir/meta.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Open Extension Directory",
|
||||||
|
"id": "fablabchemnitz.de.open_dir",
|
||||||
|
"path": "open_dir",
|
||||||
|
"dependent_extensions": null,
|
||||||
|
"original_name": "Open Extension Directory",
|
||||||
|
"original_id": "fablabchemnitz.de.open_dir",
|
||||||
|
"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/open_dir",
|
||||||
|
"fork_url": null,
|
||||||
|
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Open+Extension+Directory",
|
||||||
|
"inkscape_gallery_url": null,
|
||||||
|
"main_authors": [
|
||||||
|
"github.com/vmario89"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
14
extensions/fablabchemnitz/open_dir/open_dir.inx
Normal file
14
extensions/fablabchemnitz/open_dir/open_dir.inx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<name>Open Extension Directory</name>
|
||||||
|
<id>fablabchemnitz.de.open_dir</id>
|
||||||
|
<effect needs-live-preview="false">
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu name="FabLab Chemnitz"/>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command location="inx" interpreter="python">open_dir.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
36
extensions/fablabchemnitz/open_dir/open_dir.py
Normal file
36
extensions/fablabchemnitz/open_dir/open_dir.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import warnings
|
||||||
|
import inkex
|
||||||
|
|
||||||
|
DETACHED_PROCESS = 0x00000008
|
||||||
|
|
||||||
|
class OpenExtensionDirectory(inkex.EffectExtension):
|
||||||
|
|
||||||
|
def spawnIndependentProcess(self, args):
|
||||||
|
warnings.simplefilter('ignore', ResourceWarning) #suppress "enable tracemalloc to get the object allocation traceback"
|
||||||
|
if os.name == 'nt':
|
||||||
|
subprocess.Popen(args, close_fds=True, creationflags=DETACHED_PROCESS)
|
||||||
|
else:
|
||||||
|
subprocess.Popen(args, start_new_session=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
warnings.simplefilter("default", ResourceWarning)
|
||||||
|
|
||||||
|
def effect(self):
|
||||||
|
extension_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..', '..')
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
explorer = "explorer"
|
||||||
|
else:
|
||||||
|
explorer = "xdg-open"
|
||||||
|
args = [explorer, extension_dir]
|
||||||
|
try:
|
||||||
|
self.spawnIndependentProcess(args)
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
inkex.utils.debug(e)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
OpenExtensionDirectory().run()
|
@ -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