diff --git a/cli/axicli.py b/cli/axicli.py
index e18273c..e52912b 100755
--- a/cli/axicli.py
+++ b/cli/axicli.py
@@ -4,11 +4,11 @@
For quick help:
python axicli.py --help
-Full user guide:
+Full user guide:
https://axidraw.com/doc/cli_api/
-This script is a stand-alone version of AxiDraw Control, accepting
+This script is a stand-alone version of AxiDraw Control, accepting
various options and providing a facility for setting default values.
'''
diff --git a/cli/test/test_axicli/test_utils.py b/cli/test/test_axicli/test_utils.py
index aa535c4..e33786b 100644
--- a/cli/test/test_axicli/test_utils.py
+++ b/cli/test/test_axicli/test_utils.py
@@ -13,7 +13,7 @@
class UtilsTestCase(unittest.TestCase):
-
+
def test_get_configured_value_no_configs(self):
""" If no configs are provided, raise an error """
with self.assertRaises(BaseException):
@@ -60,7 +60,7 @@ def test_assign_option_values(self):
configured_values = { "not_overridden": "configured value", "overridden": "configured value" }
command_line_values = optparse.Values({ "not_overridden": None, "overridden": "commandline value" })
resulting_options = optparse.Values() # will contain the result of running assign_option_values
-
+
assign_option_values(resulting_options, command_line_values, [configured_values], option_names)
self.assertTrue(hasattr(resulting_options, "not_overridden"))
diff --git a/inkscape driver/axidraw_control.py b/inkscape driver/axidraw_control.py
index 19633ea..07e7e0b 100644
--- a/inkscape driver/axidraw_control.py
+++ b/inkscape driver/axidraw_control.py
@@ -119,7 +119,7 @@ def effect( self ):
* If no port is specified, use the first available AxiDraw
1: Use first AxiDraw located via USB, even if a port is given.
-
+
2: Use only specified port, given by self.options.port
3: Plot to all attached AxiDraw units
diff --git a/inkscape driver/axidraw_svg_reorder.py b/inkscape driver/axidraw_svg_reorder.py
index 6068287..214629c 100644
--- a/inkscape driver/axidraw_svg_reorder.py
+++ b/inkscape driver/axidraw_svg_reorder.py
@@ -4,8 +4,8 @@
# This extension uses a simple TSP algorithm to order the paths so as
# to reduce plotting time by plotting nearby paths consecutively.
#
-#
-# While written from scratch, this is a derivative in spirit of the work by
+#
+# While written from scratch, this is a derivative in spirit of the work by
# Matthew Beckler and Daniel C. Newman for the EggBot project.
#
# The MIT License (MIT)
@@ -64,7 +64,7 @@
* Consider re-introducing GUI method for rendering:
-false
+false
"""
@@ -77,45 +77,45 @@ class ReorderEffect(inkex.Effect):
objects within that layer only
Objects in root of document are treated as being on a _single_ layer, and will all
be sorted.
-
+
"""
-
+
def __init__( self ):
inkex.Effect.__init__( self )
-
+
self.OptionParser.add_option( "--reordering",\
action="store", type="int", dest="reordering",\
default=1,help="How groups are handled")
-
+
self.auto_rotate = True
def effect(self):
# Main entry point of the program
- self.svg_width = 0
+ self.svg_width = 0
self.svg_height = 0
self.air_total_default = 0
self.air_total_sorted = 0
self.printPortrait = False
-
+
# Rendering is available for debug purposes. It only previews
# pen-up movements that are reordered and typically does not
# include all possible movement.
-
- self.preview_rendering = False
+
+ self.preview_rendering = False
self.layer_index = 0 # index for coloring layers
-
+
self.svg = self.document.getroot()
-
+
self.DocUnits = "in" # Default
self.DocUnits = self.getDocumentUnit()
-
+
self.unit_scaling = 1
self.getDocProps()
"""
- Set up the document-wide transforms to handle SVG viewbox
+ Set up the document-wide transforms to handle SVG viewbox
"""
matCurrent = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
@@ -126,24 +126,24 @@ def effect(self):
if vb:
p_a_r = self.svg.get('preserveAspectRatio')
sx,sy,ox,oy = plot_utils.vb_scale(vb, p_a_r, self.svg_width, self.svg_height)
- else:
+ else:
sx = 1.0 / float(plot_utils.PX_PER_INCH) # Handle case of no viewbox
sy = sx
ox = 0.0
oy = 0.0
-
+
# Initial transform of document is based on viewbox, if present:
matCurrent = simpletransform.parseTransform('scale({0:.6E},{1:.6E}) translate({2:.6E},{3:.6E})'.format(sx, sy, ox, oy))
# Set up x_last, y_last, which keep track of last known pen position
- # The initial position is given by the expected initial pen position
+ # The initial position is given by the expected initial pen position
self.y_last = 0
-
+
if (self.printPortrait):
self.x_last = self.svg_width
else:
self.x_last = 0
-
+
parent_vis='visible'
self.root_nodes = []
@@ -152,7 +152,7 @@ def effect(self):
# Remove old preview layers, if rendering is enabled
for node in self.svg:
if node.tag == inkex.addNS( 'g', 'svg' ) or node.tag == 'g':
- if ( node.get( inkex.addNS( 'groupmode', 'inkscape' ) ) == 'layer' ):
+ if ( node.get( inkex.addNS( 'groupmode', 'inkscape' ) ) == 'layer' ):
LayerName = node.get( inkex.addNS( 'label', 'inkscape' ) )
if LayerName == '% Preview':
self.svg.remove( node )
@@ -163,8 +163,8 @@ def effect(self):
path_attrs = { 'transform': simpletransform.formatTransform(preview_transform)}
self.preview_layer = etree.Element(inkex.addNS('g', 'svg'),
path_attrs, nsmap=inkex.NSS)
-
-
+
+
self.preview_layer.set( inkex.addNS('groupmode', 'inkscape' ), 'layer' )
self.preview_layer.set( inkex.addNS( 'label', 'inkscape' ), '% Preview' )
self.svg.append( self.preview_layer )
@@ -178,12 +178,12 @@ def effect(self):
"""
Stroke-width is a css style element, and cannot accept scientific notation.
-
+
Thus, in cases with large scaling (i.e., high values of 1/sx, 1/sy)
- resulting from the viewbox attribute of the SVG document, it may be necessary to use
+ resulting from the viewbox attribute of the SVG document, it may be necessary to use
a _very small_ stroke width, so that the stroke width displayed on the screen
has a reasonable width after being displayed greatly magnified thanks to the viewbox.
-
+
Use log10(the number) to determine the scale, and thus the precision needed.
"""
@@ -216,31 +216,31 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
# coord_dict maps a node ID to the following data:
# Is the node plottable, first coordinate pair, last coordinate pair.
# i.e., Node_id -> (Boolean: plottable, Xi, Yi, Xf, Yf)
-
+
group_dict = {}
# group_dict maps a node ID for a group to the contents of that group.
# The contents may be a preserved nested group or a flat list, depending
# on the selected group handling mode. Example:
- # group_dict = {'id_1': ,
+ # group_dict = {'id_1': ,
# 'id_2':
nodes_to_delete = []
-
+
counter = 0 # TODO: Replace this with better unique ID system
# Account for input_node's transform and any transforms above it:
if mat_current is None:
mat_current = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
- try:
+ try:
matNew = simpletransform.composeTransform( mat_current,
simpletransform.parseTransform( input_node.get( "transform" )))
except AttributeError:
matNew = mat_current
-
+
for node in input_node:
# Step through each object within the top-level input node
-
-
+
+
if node.tag is etree.Comment:
continue
@@ -261,22 +261,22 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
style = simplestyle.parseStyle(node.get('style'))
if 'display' in style.keys() and style['display'] == 'none':
skip_object = True # Plot neither this object nor its children
-
+
# The node may have a display="none" attribute as well:
if node.get( 'display' ) == 'none':
skip_object = True # Plot neither this object nor its children
-
+
# Visibility attributes control whether a given object will plot.
# Children of hidden (not visible) parents may be plotted if
# they assert visibility.
- visibility = node.get( 'visibility', parent_vis )
+ visibility = node.get( 'visibility', parent_vis )
if 'visibility' in style.keys():
visibility = style['visibility'] # Style may override attribute.
if visibility == 'inherit':
visibility = parent_vis
-
+
if visibility != 'visible':
skip_object = True # Skip this object and its children
@@ -284,7 +284,7 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
if node.tag == inkex.addNS( 'g', 'svg' ) or node.tag == 'g':
# Use the user-given option to decide what to do with subgroups:
- subgroup_mode = self.options.reordering
+ subgroup_mode = self.options.reordering
# Values of the parameter:
# subgroup_mode=="1": Preserve groups
@@ -293,19 +293,19 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
if node.get(inkex.addNS('groupmode', 'inkscape')) == 'layer':
# The node is a layer or sub-layer, not a regular group.
- # Parse it separately, and re-order its contents.
+ # Parse it separately, and re-order its contents.
subgroup_mode = 2 # Always sort within each layer.
self.layer_index += 1
layer_name = node.get( inkex.addNS( 'label', 'inkscape' ) )
-
+
if sys.version_info < (3,): # Yes this is ugly. More elegant suggestions welcome. :)
- layer_name = layer_name.encode( 'ascii', 'ignore' ) #Drop non-ascii characters
+ layer_name = layer_name.encode( 'ascii', 'ignore' ) #Drop non-ascii characters
else:
- layer_name = str(layer_name)
+ layer_name = str(layer_name)
layer_name.lstrip # Remove leading whitespace
-
+
if layer_name:
if layer_name[0] == '%': # First character is '%'; This
skip_object = True # is a documentation layer; skip plotting.
@@ -318,10 +318,10 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
if subgroup_mode == 3:
# Break apart this non-layer subgroup and add it to
# the set of things to be re-ordered.
-
+
nodes_to_delete.append(node)
nodes_inside_group = self.group2NodeDict(node)
-
+
for a_node in nodes_inside_group:
try:
id = a_node.get( 'id' )
@@ -335,12 +335,12 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
# Use getFirstPoint and getLastPoint on each object:
start_plottable, first_point = self.getFirstPoint(a_node, matNew)
end_plottable, last_point = self.getLastPoint(a_node, matNew)
-
+
coord_dict[id] = (start_plottable and end_plottable,
first_point[0], first_point[1], last_point[0], last_point[1] )
- # Entry in group_dict is this node
+ # Entry in group_dict is this node
group_dict[id] = a_node
-
+
elif subgroup_mode == 2:
# Reorder a layer or subgroup with a recursive call.
@@ -353,9 +353,9 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
# Then add this optimized node to the coord_dict
coord_dict[id] = (start_plottable and end_plottable,
first_point[0], first_point[1], last_point[0], last_point[1] )
- # Entry in group_dict is this node
+ # Entry in group_dict is this node
group_dict[id] = node
-
+
else: # (subgroup_mode == 1)
# Preserve the group, but find its first and last point so
# that it can be re-ordered with respect to other items
@@ -367,13 +367,13 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
last_point = [(-1.), (-1.)]
else:
start_plottable, first_point = self.group_first_pt(node, matNew)
- end_plottable, last_point = self.group_last_pt(node, matNew)
+ end_plottable, last_point = self.group_last_pt(node, matNew)
coord_dict[id] = (start_plottable and end_plottable,
first_point[0], first_point[1], last_point[0], last_point[1] )
- # Entry in group_dict is this node
+ # Entry in group_dict is this node
group_dict[id] = node
-
+
else: # Handle objects that are not groups
if skip_object:
start_plottable = False
@@ -386,7 +386,7 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
coord_dict[id] = (start_plottable and end_plottable,
first_point[0], first_point[1], last_point[0], last_point[1] )
- group_dict[id] = node # Entry in group_dict is this node
+ group_dict[id] = node # Entry in group_dict is this node
# Perform the re-ordering:
ordered_element_list = self.ReorderNodeList(coord_dict, group_dict)
@@ -396,28 +396,28 @@ def parse_svg(self, input_node, mat_current=None, parent_vis='visible'):
for elt in ordered_element_list:
# Creates identical node at the correct location according to ordered_element_list
input_node.append(elt)
- # Once program is finished parsing through
- for element_to_remove in nodes_to_delete:
+ # Once program is finished parsing through
+ for element_to_remove in nodes_to_delete:
try:
input_node.remove(element_to_remove)
except ValueError:
- inkex.errormsg(str(element_to_remove.get('id'))+" is not a member of " + str(input_node.get('id')))
+ inkex.errormsg(str(element_to_remove.get('id'))+" is not a member of " + str(input_node.get('id')))
return input_node
- def break_apart_path(self, path):
+ def break_apart_path(self, path):
"""
An SVG path may contain multiple distinct portions, that are normally separated
by pen-up movements.
-
+
This function takes the path data string from an SVG path, parses it, and returns
a dictionary of independent path data strings, each of which represents a single
pen-down movement. It is equivalent to the Inkscape function Path > Break Apart
-
+
Input: path data string, representing a single SVG path
Output: Dictionary of (separated) path data strings
-
+
"""
MaxLength = len(path)
ix = 0
@@ -425,56 +425,56 @@ def break_apart_path(self, path):
path_dictionary = {}
path_list = []
path_number = 1
-
+
# Search for M or m location
while ix < MaxLength:
if(path[ix] == 'm' or path[ix] == 'M'):
- move_to_location.append(ix)
+ move_to_location.append(ix)
ix = ix + 1
# Iterate through every M or m location in our list of move to instructions
# Slice the path string according to path beginning and ends as indicated by the
# location of these instructions
-
+
for counter, m in enumerate(move_to_location):
- if (m == move_to_location[-1]):
+ if (m == move_to_location[-1]):
# last entry
path_list.append(path[m:MaxLength].rstrip())
- else:
+ else:
path_list.append(path[m:move_to_location[counter + 1]].rstrip())
-
+
for counter, current_path in enumerate(path_list):
-
+
# Enumerate over every entry in the path looking for relative m commands
- if current_path[0] == 'm' and counter > 0:
+ if current_path[0] == 'm' and counter > 0:
# If path contains relative m command, the best case is when the last command
# was a Z or z. In this case, all relative operations are performed relative to
# initial x, y coordinates of the previous path
-
+
if path_list[counter -1][-1].upper() == 'Z':
- current_path_x, current_path_y,index = self.getFirstPoint(current_path, matNew)
- prev_path_x, prev_path_y,ignore = self.getFirstPoint(path_list[counter-1])
- adapted_x = current_path_x + prev_path_x
- adapted_y = current_path_y + prev_path_y
+ current_path_x, current_path_y,index = self.getFirstPoint(current_path, matNew)
+ prev_path_x, prev_path_y,ignore = self.getFirstPoint(path_list[counter-1])
+ adapted_x = current_path_x + prev_path_x
+ adapted_y = current_path_y + prev_path_y
# Now we can replace the path data with an Absolute Move to instruction
- # HOWEVER, we need to adapt all the data until we reach a different command in the case of a repeating
+ # HOWEVER, we need to adapt all the data until we reach a different command in the case of a repeating
path_list[counter] = "m "+str(adapted_x)+","+str(adapted_y) + ' ' +current_path[index:]
-
- # If there is no z or absolute commands, we need to parse the entire path
+
+ # If there is no z or absolute commands, we need to parse the entire path
else:
-
+
# scan path for absolute coordinates. If present, begin parsing from their index
# instead of the beginning
prev_path = path_list[counter-1]
prev_path_length = len(prev_path)
jx = 0
- x_val, y_val = 0,0
- # Check one char at a time
+ x_val, y_val = 0,0
+ # Check one char at a time
# until we have the moveTo Command
last_command = ''
is_absolute_command = False
repeated_command = False
# name of command
- # how many parameters we need to skip
+ # how many parameters we need to skip
accepted_commands = {
'M':0,
'L':0,
@@ -485,134 +485,134 @@ def break_apart_path(self, path):
'Q':2,
'T':0,
'A':5
- }
-
- # If there is an absolute command which specifies a new initial point
+ }
+
+ # If there is an absolute command which specifies a new initial point
# then we can save time by setting our index directly to its location in the path data
- # See if an accepted_command is present in the path data. If it is present further in the
- # string than any command found before, then set the pointer to that location
+ # See if an accepted_command is present in the path data. If it is present further in the
+ # string than any command found before, then set the pointer to that location
# if a command is not found, find() will return a -1. jx is initialized to 0, so if no matches
# are found, the program will parse from the beginning to the end of the path
-
+
for keys in 'MLCSQTA': # TODO: Compare to last_point; see if we can clean up this part
if(prev_path.find(keys) > jx):
- jx = prev_path.find(keys)
-
+ jx = prev_path.find(keys)
+
while jx < prev_path_length:
-
+
temp_x_val = ''
temp_y_val = ''
num_of_params_to_skip = 0
-
- # SVG Path commands can be repeated
+
+ # SVG Path commands can be repeated
if (prev_path[jx].isdigit() and last_command):
- repeated_command = True
+ repeated_command = True
else:
repeated_command = False
-
+
if (prev_path[jx].isalpha() and prev_path[jx].upper() in accepted_commands) or repeated_command:
-
+
if repeated_command:
#is_relative_command is saved from last iteration of the loop
current_command = last_command
else:
# If the character is accepted, we must parse until reach the x y coordinates
- is_absolute_command = prev_path[jx].isupper()
+ is_absolute_command = prev_path[jx].isupper()
current_command = prev_path[jx].upper()
-
+
# Each command has a certain number of parameters we must pass before we reach the
# information we care about. We will parse until we know that we have reached them
-
+
# Get to start of next number
# We will know we have reached a number if the current character is a +/- sign
- # or current character is a digit
+ # or current character is a digit
while jx < prev_path_length:
if(prev_path[jx] in '+-' or prev_path[jx].isdigit()):
break
- jx = jx + 1
-
+ jx = jx + 1
+
# We need to parse past the unused parameters in our command
- # The number of parameters to parse past is dependent on the command and stored
+ # The number of parameters to parse past is dependent on the command and stored
# as the value of accepted_command
- # Spaces and commas are used to deliniate paramters
+ # Spaces and commas are used to deliniate paramters
while jx < prev_path_length and num_of_params_to_skip < accepted_commands[current_command]:
if(prev_path[jx].isspace() or prev_path[jx] == ','):
- num_of_params_to_skip = num_of_params_to_skip + 1
- jx = jx + 1
-
+ num_of_params_to_skip = num_of_params_to_skip + 1
+ jx = jx + 1
+
# Now, we are in front of the x character
-
+
if current_command.upper() == 'V':
- temp_x_val = 0
-
+ temp_x_val = 0
+
if current_command.upper() == 'H':
- temp_y_val = 0
-
+ temp_y_val = 0
+
# Parse until next character is a digit or +/- character
while jx < prev_path_length and current_command.upper() != 'V':
if(prev_path[jx] in '+-' or prev_path[jx].isdigit()):
break
- jx = jx + 1
-
+ jx = jx + 1
+
# Save each next character until we reach a space
while jx < prev_path_length and current_command.upper() != 'V' and not (prev_path[jx].isspace() or prev_path[jx] == ','):
temp_x_val = temp_x_val + prev_path[jx]
- jx = jx + 1
-
+ jx = jx + 1
+
# Then we know we have completely parsed the x character
-
+
# Now we are in front of the y character
-
+
# Parse until next character is a digit or +/- character
while jx < prev_path_length and current_command.upper() != 'H':
if(prev_path[jx] in '+-' or prev_path[jx].isdigit()):
break
- jx = jx + 1
-
+ jx = jx + 1
+
## Save each next character until we reach a space
while jx < prev_path_length and current_command.upper() != 'H' and not (prev_path[jx].isspace() or prev_path[jx] == ','):
temp_y_val = temp_y_val + prev_path[jx]
- jx = jx + 1
-
+ jx = jx + 1
+
# Then we know we have completely parsed the y character
-
+
if is_absolute_command:
-
+
if current_command == 'H':
- # Absolute commands create new x,y position
+ # Absolute commands create new x,y position
try:
x_val = float(temp_x_val)
except ValueError:
pass
elif current_command == 'V':
- # Absolute commands create new x,y position
+ # Absolute commands create new x,y position
try:
y_val = float(temp_y_val)
except ValueError:
pass
else:
- # Absolute commands create new x,y position
+ # Absolute commands create new x,y position
try:
x_val = float(temp_x_val)
y_val = float(temp_y_val)
except ValueError:
pass
else:
-
+
if current_command == 'h':
- # Absolute commands create new x,y position
+ # Absolute commands create new x,y position
try:
x_val = x_val + float(temp_x_val)
except ValueError:
pass
elif current_command == 'V':
- # Absolute commands create new x,y position
+ # Absolute commands create new x,y position
try:
y_val = y_val + float(temp_y_val)
except ValueError:
pass
else:
- # Absolute commands create new x,y position
+ # Absolute commands create new x,y position
try:
x_val = x_val + float(temp_x_val)
y_val = y_val + float(temp_y_val)
@@ -620,12 +620,12 @@ def break_apart_path(self, path):
pass
last_command = current_command
jx = jx + 1
- x,y,index = self.getFirstPoint(current_path,None)
+ x,y,index = self.getFirstPoint(current_path,None)
path_list[counter] = "m "+str(x_val+x)+","+str(y_val+y) + ' ' + current_path[index:]
-
+
for counter, path in enumerate(path_list):
- path_dictionary['ad_path'+ str(counter)] = path
-
+ path_dictionary['ad_path'+ str(counter)] = path
+
return path_dictionary
@@ -642,42 +642,42 @@ def getFirstPoint(self, node, matCurrent):
point = [float(-1), float(-1)]
try:
if node.tag == inkex.addNS( 'path', 'svg' ):
-
+
pathdata = node.get('d')
-
+
point = plot_utils.pathdata_first_point(pathdata)
if point:
simpletransform.applyTransformToPoint(matNew, point)
return True, point
else:
return False, [float(-1), float(-1)]
-
+
if node.tag == inkex.addNS( 'rect', 'svg' ) or node.tag == 'rect':
-
+
"""
The x,y coordinates for a rect are included in their specific attributes
If there is a transform, we need translate the x & y coordinates to their
correct location via applyTransformToPoint.
"""
-
+
point[0] = float( node.get( 'x' ) )
point[1] = float( node.get( 'y' ) )
-
+
simpletransform.applyTransformToPoint(matNew, point)
-
+
return True, point
-
+
if node.tag == inkex.addNS( 'line', 'svg' ) or node.tag == 'line':
"""
The x1 and y1 attributes are where we will start to draw
So, get them, apply the transform matrix, and return the point
"""
-
+
point[0] = float( node.get( 'x1' ) )
point[1] = float( node.get( 'y1' ) )
-
+
simpletransform.applyTransformToPoint(matNew, point)
-
+
return True, point
elif node.tag in [inkex.addNS('polyline', 'svg'), 'polyline',
@@ -691,43 +691,43 @@ def getFirstPoint(self, node, matCurrent):
and split methods. Then apply transforms
"""
pl = node.get( 'points', '' ).strip()
-
+
if pl == '':
return False, point
-
+
pa = pl.replace(',',' ').split() # replace comma with space before splitting
-
+
if not pa:
return False, point
pathLength = len( pa )
if (pathLength < 4): # Minimum of x1,y1 x2,y2 required.
return False, point
-
+
d = "M " + pa[0] + " " + pa[1]
i = 2
while (i < (pathLength - 1 )):
d += " L " + pa[i] + " " + pa[i + 1]
i += 2
-
+
point = plot_utils.pathdata_first_point(d)
simpletransform.applyTransformToPoint(matNew, point)
-
+
return True, point
-
+
if node.tag == inkex.addNS( 'ellipse', 'svg' ) or \
node.tag == 'ellipse':
-
+
cx = float( node.get( 'cx', '0' ) )
cy = float( node.get( 'cy', '0' ) )
rx = float( node.get( 'rx', '0' ) )
-
+
point[0] = cx - rx
point[1] = cy
-
+
simpletransform.applyTransformToPoint(matNew, point)
-
+
return True, point
-
+
if node.tag == inkex.addNS( 'circle', 'svg' ) or \
node.tag == 'circle':
cx = float( node.get( 'cx', '0' ) )
@@ -735,25 +735,25 @@ def getFirstPoint(self, node, matCurrent):
r = float( node.get( 'r', '0' ) )
point[0] = cx - r
point[1] = cy
-
+
simpletransform.applyTransformToPoint(matNew, point)
-
+
return True, point
-
+
if node.tag == inkex.addNS('symbol', 'svg') or node.tag == 'symbol':
# A symbol is much like a group, except that
# it's an invisible object.
return False, point # Skip this element.
-
+
if node.tag == inkex.addNS('use', 'svg') or node.tag == 'use':
-
+
"""
A