Commit 533f4d8a authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Bugfixes with nested states

parent 1c5933ff
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
This module is managing the Copy and Paste functions. This module is managing the Copy and Paste functions.
""" """
import logging
from itertools import chain
import PySide
import ogAST import ogAST
import sdlSymbols import sdlSymbols
import genericSymbols import genericSymbols
import logging
import Renderer import Renderer
import PySide
__all__ = ['copy', 'paste'] __all__ = ['copy', 'paste']
...@@ -120,6 +122,8 @@ def paste_floating_objects(scene): ...@@ -120,6 +122,8 @@ def paste_floating_objects(scene):
states = [i for i in item_list if isinstance(i, ogAST.State)] states = [i for i in item_list if isinstance(i, ogAST.State)]
text_areas = (i for i in item_list if isinstance(i, ogAST.TextArea)) text_areas = (i for i in item_list if isinstance(i, ogAST.TextArea))
labels = (i for i in item_list if isinstance(i, ogAST.Floating_label)) labels = (i for i in item_list if isinstance(i, ogAST.Floating_label))
procedures = (i for i in item_list if isinstance(i, ogAST.Procedure))
processes = (i for i in item_list if isinstance(i, ogAST.Process))
for state in states: for state in states:
# First check if state has already been pasted # First check if state has already been pasted
try: try:
...@@ -133,20 +137,16 @@ def paste_floating_objects(scene): ...@@ -133,20 +137,16 @@ def paste_floating_objects(scene):
LOG.debug('PASTE STATE "' + state.inputString + '"') LOG.debug('PASTE STATE "' + state.inputString + '"')
symbols.append(new_item) symbols.append(new_item)
# Insert the new state at click coordinates # Insert the new state at click coordinates
scene.addItem(new_item) Renderer.add_to_scene(new_item, scene)
for text_area in text_areas: for each in chain(text_areas, labels, procedures, processes):
LOG.debug('PASTE TEXT AREA') LOG.debug('PASTE TA/LAB/PROC')
new_item = Renderer.render(text_area, scene) new_item = Renderer.render(each, scene, states=states)
symbols.append(new_item)
for label in labels:
LOG.debug('PASTE LABEL')
new_item = Renderer.render(label, scene, states=states)
symbols.append(new_item) symbols.append(new_item)
if start: if start:
start, = start start, = start
LOG.debug('PASTE START') LOG.debug('PASTE START')
for item in scene.items(): for item in scene.visible_symb:
if isinstance(item, sdlSymbols.Start) and item.isVisible(): if isinstance(item, sdlSymbols.Start):
raise TypeError('Only one START symbol is possible') raise TypeError('Only one START symbol is possible')
new_item = Renderer.render(start, scene, states=states) new_item = Renderer.render(start, scene, states=states)
symbols.append(new_item) symbols.append(new_item)
...@@ -168,7 +168,7 @@ def paste_below_item(parent, scene): ...@@ -168,7 +168,7 @@ def paste_below_item(parent, scene):
# Check that item is compatible with parent # Check that item is compatible with parent
if (type(new_item).__name__ in parent.allowed_followers): if (type(new_item).__name__ in parent.allowed_followers):
# Move the item from the clipboard to the scene # Move the item from the clipboard to the scene
scene.addItem(new_item) Renderer.add_to_scene(new_item, scene)
new_item.setPos(0, 0) new_item.setPos(0, 0)
symbols.append(new_item) symbols.append(new_item)
else: else:
......
...@@ -27,7 +27,6 @@ from PySide.QtGui import QGraphicsPathItem, QPainterPath, QGraphicsItem, QPen,\ ...@@ -27,7 +27,6 @@ from PySide.QtGui import QGraphicsPathItem, QPainterPath, QGraphicsItem, QPen,\
QPainter, QFont, QGraphicsTextItem, QColor, \ QPainter, QFont, QGraphicsTextItem, QColor, \
QFontMetrics QFontMetrics
# pylint: disable=R0904 # pylint: disable=R0904
class Connection(QGraphicsPathItem, object): class Connection(QGraphicsPathItem, object):
''' Connection between two symbols (top-level class) ''' ''' Connection between two symbols (top-level class) '''
...@@ -67,17 +66,47 @@ class Connection(QGraphicsPathItem, object): ...@@ -67,17 +66,47 @@ class Connection(QGraphicsPathItem, object):
''' Compute connection intermediate points - redefine in subclasses ''' ''' Compute connection intermediate points - redefine in subclasses '''
return self._middle_points return self._middle_points
def arrow(self, path=None): def simple_arrow(self, origin='head', path=None):
''' Compute the two points of an arrow head - vertical by default ''' ''' Compute the two points of an vertical arrow head '''
endp = self.end_point if origin == 'head':
endp = self.end_point
else:
endp = self.start_point
return (QPointF(endp.x() - 5, endp.y() - 5), return (QPointF(endp.x() - 5, endp.y() - 5),
QPointF(endp.x() + 5, endp.y() - 5)) QPointF(endp.x() + 5, endp.y() - 5))
def draw_arrow_head(self, shape): def angle_arrow(self, path, origin='head'):
''' Generic function to draw any arrow head - don't redefine ''' ''' Compute the two points of the arrow head with the right angle '''
arrowhead = self.arrow(shape) if origin == 'tail':
path = path.toReversed()
length = path.length()
percent = path.percentAtLength(length - 10.0)
src = path.pointAtPercent(percent)
#path.moveTo(path.pointAtPercent(1))
end_point = path.pointAtPercent(1)
#end_point = path.currentPosition()
line = QLineF(src, end_point)
angle = math.acos(line.dx() / (line.length() or 1))
if line.dy() >= 0:
angle = math.pi * 2 - angle
arrow_size = 10.0
arrow_p1 = end_point + QPointF(
math.sin(angle - math.pi/3) * arrow_size,
math.cos(angle - math.pi/3) * arrow_size)
arrow_p2 = end_point + QPointF(
math.sin(angle - math.pi + math.pi/3) * arrow_size,
math.cos(angle - math.pi + math.pi/3) * arrow_size)
return (arrow_p1, arrow_p2)
def draw_arrow_head(self, shape, origin='head', kind='simple'):
''' Generic function to draw a simple arrow '''
if kind == 'simple':
arrowhead = self.simple_arrow(path=shape)
else:
arrowhead = self.angle_arrow(shape, origin)
shape.lineTo(arrowhead[0]) shape.lineTo(arrowhead[0])
shape.moveTo(self.end_point) shape.moveTo(self.end_point if origin == 'head' else self.start_point)
shape.lineTo(arrowhead[1]) shape.lineTo(arrowhead[1])
def __str__(self): def __str__(self):
...@@ -94,7 +123,12 @@ class Connection(QGraphicsPathItem, object): ...@@ -94,7 +123,12 @@ class Connection(QGraphicsPathItem, object):
shape.lineTo(self.end_point) shape.lineTo(self.end_point)
# If required draw an arrow head (e.g. in SDL NEXTSTATE and JOIN) # If required draw an arrow head (e.g. in SDL NEXTSTATE and JOIN)
if self.child.arrow_head: if self.child.arrow_head:
self.draw_arrow_head(shape) self.draw_arrow_head(shape, origin='head',
kind=self.child.arrow_head)
if self.child.arrow_tail:
shape.moveTo(shape.pointAtPercent(0))
self.draw_arrow_head(shape, origin='tail',
kind=self.child.arrow_head)
self.setPath(shape) self.setPath(shape)
...@@ -203,21 +237,27 @@ class CommentConnection(Connection): ...@@ -203,21 +237,27 @@ class CommentConnection(Connection):
class Channel(Connection): class Channel(Connection):
''' Subclass of Connection used to draw channels between processes ''' ''' Subclass of Connection used to draw channels between processes '''
def __init__(self, elem1, elem2): def __init__(self, process):
''' Set generic parameters from Connection class ''' ''' Set generic parameters from Connection class '''
super(Channel, self).__init__(elem1, elem2) super(Channel, self).__init__(process, process)
self.text_label = None self.text_label = None
self.elem1 = elem1 self.process = process
self.elem2 = elem2
def reshape(self): @property
''' Update the shape of the connection line ''' def start_point(self):
super(Channel, self).reshape() ''' Compute connection origin - redefined function '''
parent_rect = self.process.boundingRect()
return QPointF(parent_rect.x(), parent_rect.height() / 2)
def paint(self, painter, option, widget): @property
''' Apply antialiasing ''' def end_point(self):
painter.setRenderHint(QPainter.Antialiasing, True) ''' Compute connection end point - redefined function '''
super(Channel, self).paint(painter, option, widget) # Arrow always bumps at the screen edge
view = self.scene().views()[0]
view_pos = view.mapToScene(
view.viewport().geometry()).boundingRect().topLeft()
scene_pos_x = self.mapFromScene(view_pos).x()
return QPointF(scene_pos_x, self.start_point.y())
class Controlpoint(QGraphicsPathItem, object): class Controlpoint(QGraphicsPathItem, object):
...@@ -356,26 +396,7 @@ class Edge(Connection): ...@@ -356,26 +396,7 @@ class Edge(Connection):
''' On a mouse click, display the control points ''' ''' On a mouse click, display the control points '''
self.bezier_set_visible(True) self.bezier_set_visible(True)
def arrow(self, path): # pylint: disable=R0914
''' Compute the two points of the arrow head with the right angle '''
length = path.length()
percent = path.percentAtLength(length - 10.0)
src = path.pointAtPercent(percent)
end_point = path.currentPosition()
line = QLineF(src, end_point)
angle = math.acos(line.dx() / line.length())
if line.dy() >= 0:
angle = math.pi * 2 - angle
arrow_size = 10.0
arrow_p1 = end_point + QPointF(
math.sin(angle - math.pi/3) * arrow_size,
math.cos(angle - math.pi/3) * arrow_size)
arrow_p2 = end_point + QPointF(
math.sin(angle - math.pi + math.pi/3) * arrow_size,
math.cos(angle - math.pi + math.pi/3) * arrow_size)
return (arrow_p1, arrow_p2)
# pylint: disable=R0914
def reshape(self): def reshape(self):
''' Update the shape of the edge (redefined function) ''' ''' Update the shape of the edge (redefined function) '''
path = QPainterPath() path = QPainterPath()
...@@ -394,7 +415,7 @@ class Edge(Connection): ...@@ -394,7 +415,7 @@ class Edge(Connection):
path.lineTo(self.end_connection.center) path.lineTo(self.end_connection.center)
end_point = path.currentPosition() end_point = path.currentPosition()
arrowhead = self.arrow(path) arrowhead = self.angle_arrow(path)
path.lineTo(arrowhead[0]) path.lineTo(arrowhead[0])
path.moveTo(end_point) path.moveTo(end_point)
path.lineTo(arrowhead[1]) path.lineTo(arrowhead[1])
......
...@@ -54,15 +54,15 @@ def flatten(process): ...@@ -54,15 +54,15 @@ def flatten(process):
''' Flatten the nested states: ''' Flatten the nested states:
Rename inner states, procedures, etc. and move them to process level Rename inner states, procedures, etc. and move them to process level
''' '''
def update_terminator(context, term): def update_terminator(context, term, process):
'''Set next_id, identifying the next transition to run ''' '''Set next_id, identifying the next transition to run '''
if term.inputString.lower() in (st.statename.lower() if term.inputString.lower() in (st.statename.lower()
for st in context.composite_states): for st in context.composite_states):
if not term.via: if not term.via:
term.next_id = context.mapping \ term.next_id = process.mapping \
[term.inputString.lower() + '_START'] [term.inputString.lower() + '_START']
else: else:
term.next_id = context.mapping[term.inputString.lower() term.next_id = process.mapping[term.inputString.lower()
+ '_' + '_'
+ term.entrypoint.lower() + term.entrypoint.lower()
+ '_START'] + '_START']
...@@ -118,6 +118,8 @@ def flatten(process): ...@@ -118,6 +118,8 @@ def flatten(process):
# Go recursively in inner composite states # Go recursively in inner composite states
inner.statename = prefix + inner.statename inner.statename = prefix + inner.statename
update_composite_state(inner, process) update_composite_state(inner, process)
propagate_inputs(inner, process.mapping[inner.statename]) # TESTME
del process.mapping[inner.statename]
for each in state.terminators: for each in state.terminators:
# Give prefix to terminators # Give prefix to terminators
if each.label: if each.label:
...@@ -125,7 +127,7 @@ def flatten(process): ...@@ -125,7 +127,7 @@ def flatten(process):
if each.kind == 'next_state': if each.kind == 'next_state':
each.inputString = prefix + each.inputString each.inputString = prefix + each.inputString
# Set next transition id # Set next transition id
update_terminator(state, each) update_terminator(context=state, term=each, process=process)
elif each.kind == 'join': elif each.kind == 'join':
rename_everything(state.content, rename_everything(state.content,
each.inputString, each.inputString,
...@@ -158,7 +160,7 @@ def flatten(process): ...@@ -158,7 +160,7 @@ def flatten(process):
for each in nested_state.composite_states: for each in nested_state.composite_states:
# do the same recursively # do the same recursively
propagate_inputs(each, nested_state.mapping[each.statename]) propagate_inputs(each, nested_state.mapping[each.statename])
del nested_state.mapping[each.statename] #del nested_state.mapping[each.statename]
for each in process.composite_states: for each in process.composite_states:
update_composite_state(each, process) update_composite_state(each, process)
...@@ -168,7 +170,7 @@ def flatten(process): ...@@ -168,7 +170,7 @@ def flatten(process):
# Update terminators at process level # Update terminators at process level
for each in process.terminators: for each in process.terminators:
if each.kind == 'next_state': if each.kind == 'next_state':
update_terminator(process, each) update_terminator(process, each, process)
@singledispatch @singledispatch
......
...@@ -39,7 +39,15 @@ from singledispatch import singledispatch ...@@ -39,7 +39,15 @@ from singledispatch import singledispatch
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
__all__ = ['render'] __all__ = ['render', 'add_to_scene']
def add_to_scene(item, scene):
''' Add item to a scene after verifying that the scene allows it '''
if type(item) in scene.allowed_symbols:
scene.addItem(item)
else:
raise TypeError('This symbol does not fit the current scene')
@singledispatch @singledispatch
def render(ast, scene, parent, states, terminators=None): def render(ast, scene, parent, states, terminators=None):
...@@ -62,7 +70,7 @@ def _block(ast, scene): ...@@ -62,7 +70,7 @@ def _block(ast, scene):
@render.register(ogAST.Process) @render.register(ogAST.Process)
def _process(ast, scene): def _process(ast, scene, **_):
''' Render a Process symbol (in a BLOCK diagram) ''' ''' Render a Process symbol (in a BLOCK diagram) '''
# Set autocompletion lists for input, output, state, types, variables: # Set autocompletion lists for input, output, state, types, variables:
try: try:
...@@ -82,7 +90,7 @@ def _process(ast, scene): ...@@ -82,7 +90,7 @@ def _process(ast, scene):
proc.inputString for proc in ast.procedures} proc.inputString for proc in ast.procedures}
symbol = sdlSymbols.Process(ast, ast) symbol = sdlSymbols.Process(ast, ast)
scene.addItem(symbol) add_to_scene(symbol, scene)
return symbol return symbol
...@@ -149,7 +157,7 @@ def _state(ast, scene, states, terminators, parent=None): ...@@ -149,7 +157,7 @@ def _state(ast, scene, states, terminators, parent=None):
raise TypeError('This state is a terminator') raise TypeError('This state is a terminator')
new_state = sdlSymbols.State(parent=None, ast=ast) new_state = sdlSymbols.State(parent=None, ast=ast)
if new_state not in scene.items(): if new_state not in scene.items():
scene.addItem(new_state) add_to_scene(new_state, scene)
for exit in chain(ast.inputs, ast.connects): for exit in chain(ast.inputs, ast.connects):
render(exit, scene=scene, parent=new_state, states=states) render(exit, scene=scene, parent=new_state, states=states)
...@@ -164,7 +172,7 @@ def _procedure(ast, scene, parent=None, states=None): ...@@ -164,7 +172,7 @@ def _procedure(ast, scene, parent=None, states=None):
''' Add a procedure symbol to the scene ''' ''' Add a procedure symbol to the scene '''
_, _ = parent, states _, _ = parent, states
proc_symbol = sdlSymbols.Procedure(ast, ast) proc_symbol = sdlSymbols.Procedure(ast, ast)
scene.addItem(proc_symbol) add_to_scene(proc_symbol, scene)
return proc_symbol return proc_symbol
...@@ -173,7 +181,7 @@ def _text_area(ast, scene, parent=None, states=None): ...@@ -173,7 +181,7 @@ def _text_area(ast, scene, parent=None, states=None):
''' Render a text area from the AST ''' ''' Render a text area from the AST '''
_, _ = parent, states _, _ = parent, states
text = sdlSymbols.TextSymbol(ast) text = sdlSymbols.TextSymbol(ast)
scene.addItem(text) add_to_scene(text, scene)
return text return text
...@@ -182,7 +190,7 @@ def _start(ast, scene, states, parent=None): ...@@ -182,7 +190,7 @@ def _start(ast, scene, states, parent=None):
''' Add the start symbol to a scene ''' ''' Add the start symbol to a scene '''
_ = parent _ = parent
start_symbol = sdlSymbols.Start(ast) start_symbol = sdlSymbols.Start(ast)
scene.addItem(start_symbol) add_to_scene(start_symbol, scene)
if ast.transition: if ast.transition:
render(ast.transition, scene=scene, parent=start_symbol, states=states) render(ast.transition, scene=scene, parent=start_symbol, states=states)
return start_symbol return start_symbol
...@@ -193,7 +201,7 @@ def _start(ast, scene, states, parent=None): ...@@ -193,7 +201,7 @@ def _start(ast, scene, states, parent=None):
''' Add an editable start symbol to a scene (in composite states) ''' ''' Add an editable start symbol to a scene (in composite states) '''
_ = parent _ = parent
start_symbol = sdlSymbols.StateStart(ast) start_symbol = sdlSymbols.StateStart(ast)
scene.addItem(start_symbol) add_to_scene(start_symbol, scene)
if ast.transition: if ast.transition:
render(ast.transition, render(ast.transition,
scene=scene, parent=start_symbol, states=states) scene=scene, parent=start_symbol, states=states)
...@@ -205,7 +213,7 @@ def _procedure_start(ast, scene, states, parent=None): ...@@ -205,7 +213,7 @@ def _procedure_start(ast, scene, states, parent=None):
''' Add the procedure start symbol to a scene ''' ''' Add the procedure start symbol to a scene '''
_ = parent _ = parent
start_symbol = sdlSymbols.ProcedureStart(ast) start_symbol = sdlSymbols.ProcedureStart(ast)
scene.addItem(start_symbol) add_to_scene(start_symbol, scene)
if ast.transition: if ast.transition:
render(ast.transition, scene=scene, parent=start_symbol, states=states) render(ast.transition, scene=scene, parent=start_symbol, states=states)
return start_symbol return start_symbol
...@@ -217,7 +225,7 @@ def _floating_label(ast, scene, states, parent=None): ...@@ -217,7 +225,7 @@ def _floating_label(ast, scene, states, parent=None):
_ = parent _ = parent
lab = sdlSymbols.Label(parent=None, ast=ast) lab = sdlSymbols.Label(parent=None, ast=ast)
if lab not in scene.items(): if lab not in scene.items():
scene.addItem(lab) add_to_scene(lab, scene)
lab.setPos(ast.pos_x, ast.pos_y) lab.setPos(ast.pos_x, ast.pos_y)
if ast.transition: if ast.transition:
render(ast.transition, scene=scene, parent=lab, states=states) render(ast.transition, scene=scene, parent=lab, states=states)
...@@ -334,7 +342,7 @@ def _input(ast, scene, parent, states): ...@@ -334,7 +342,7 @@ def _input(ast, scene, parent, states):
# Note: PROVIDED clause is not supported # Note: PROVIDED clause is not supported
inp = sdlSymbols.Input(parent, ast=ast) inp = sdlSymbols.Input(parent, ast=ast)
if inp not in scene.items(): if inp not in scene.items():
scene.addItem(inp) add_to_scene(inp, scene)
if not parent: if not parent:
inp.setPos(ast.pos_x, ast.pos_y) inp.setPos(ast.pos_x, ast.pos_y)
if ast.transition: if ast.transition:
...@@ -349,7 +357,7 @@ def _connect(ast, scene, parent, states): ...@@ -349,7 +357,7 @@ def _connect(ast, scene, parent, states):
''' Add connect symbol from the AST to the scene ''' ''' Add connect symbol from the AST to the scene '''
conn = sdlSymbols.Connect(parent, ast=ast) conn = sdlSymbols.Connect(parent, ast=ast)
if conn not in scene.items(): if conn not in scene.items():
scene.addItem(conn) add_to_scene(conn, scene)
if not parent: if not parent:
conn.setPos(ast.pos_x, ast.pos_y) conn.setPos(ast.pos_x, ast.pos_y)
if ast.transition: if ast.transition:
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
Contact: maxime.perrotin@esa.int Contact: maxime.perrotin@esa.int
""" """
__all__ = ['Symbol', 'VerticalSymbol', 'HorizontalSymbol', 'Comment']
import os import os
import sys import sys
import logging import logging
...@@ -434,7 +435,8 @@ class Symbol(QObject, QGraphicsPathItem, object): ...@@ -434,7 +435,8 @@ class Symbol(QObject, QGraphicsPathItem, object):
# By default symbol size may expand when inner text exceeds border # By default symbol size may expand when inner text exceeds border
auto_expand = True auto_expand = True
# By default connections between symbols are lines, not arrows # By default connections between symbols are lines, not arrows
arrow_head = False arrow_head = None
arrow_tail = None
# Default mouse cursor # Default mouse cursor
default_cursor = Qt.SizeAllCursor default_cursor = Qt.SizeAllCursor
# Decide if a symbol can be copy-pasted several times # Decide if a symbol can be copy-pasted several times
......
This diff is collapsed.
icons/connect.png

1.76 KB | W: | H:

icons/connect.png

1.3 KB | W: | H:

icons/connect.png
icons/connect.png
icons/connect.png
icons/connect.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
version="1.1" version="1.1"
inkscape:version="0.48.4 r9939" inkscape:version="0.48.4 r9939"
sodipodi:docname="connect.svg" sodipodi:docname="connect.svg"
inkscape:export-filename="/home/maxime/taste/tool-src/misc/opengeode/icons/connect.png" inkscape:export-filename="/home/maxime/taste/tool-src/trunk/misc/opengeode/icons/connect.png"
inkscape:export-xdpi="90" inkscape:export-xdpi="90"
inkscape:export-ydpi="90"> inkscape:export-ydpi="90">
<defs <defs
...@@ -23,41 +23,16 @@ ...@@ -23,41 +23,16 @@
<marker <marker
inkscape:stockid="Arrow2Mend" inkscape:stockid="Arrow2Mend"
orient="auto" orient="auto"
refY="0.0" refY="0"
refX="0.0" refX="0"
id="Arrow2Mend" id="Arrow2Mend"
style="overflow:visible;">
<path
id="path3838"
style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mstart"
style="overflow:visible"> style="overflow:visible">
<path <path
id="path3817" inkscape:connector-curvature="0"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " id="path3838"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
transform="scale(0.4) translate(10,0)" /> d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
</marker> transform="scale(-0.6,-0.6)" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
id="path3832"
style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>