# Authors: see git history # # Copyright (c) 2010 Authors # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. import inkex from .tags import SVG_GROUP_TAG, SVG_LINK_TAG from .units import get_viewbox_transform def apply_transforms(path, node): transform = get_node_transform(node) # apply the combined transform to this node's path path = path.transform(transform) return path def compose_parent_transforms(node, mat): # This is adapted from Inkscape's simpletransform.py's composeParents() # function. That one can't handle nodes that are detached from a DOM. trans = node.get('transform') if trans: mat = inkex.transforms.Transform(trans) @ mat if node.getparent() is not None: if node.getparent().tag in [SVG_GROUP_TAG, SVG_LINK_TAG]: mat = compose_parent_transforms(node.getparent(), mat) return mat def get_node_transform(node): """ if getattr(node, "composed_transform", None): return node.composed_transform() """ # start with the identity transform transform = inkex.transforms.Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) # this if is because sometimes inkscape likes to create paths outside of a layer?! if node.getparent() is not None: # combine this node's transform with all parent groups' transforms transform = compose_parent_transforms(node, transform) # add in the transform implied by the viewBox viewbox_transform = get_viewbox_transform(node.getroottree().getroot()) transform = viewbox_transform @ transform return transform def get_correction_transform(node, child=False): """Get a transform to apply to new siblings or children of this SVG node Arguments: child (boolean) -- whether the new nodes we're going to add will be children of node (child=True) or siblings of node (child=False) This allows us to add a new child node that has its path specified in absolute coordinates. The correction transform will undo the effects of the parent's and ancestors' transforms so that absolute coordinates work properly. """ if child: transform = get_node_transform(node) else: # we can ignore the transform on the node itself since it won't apply # to the objects we add transform = get_node_transform(node.getparent()) # now invert it, so that we can position our objects in absolute # coordinates transform = -transform return str(transform) def line_strings_to_csp(line_strings): try: # This lets us accept a MultiLineString or a list. line_strings = line_strings.geoms except AttributeError: pass return point_lists_to_csp(ls.coords for ls in line_strings) def point_lists_to_csp(point_lists): csp = [] for point_list in point_lists: subpath = [] for point in point_list: # cubicsuperpath is very particular that these must be lists, not tuples point = list(point) # create a straight line as a degenerate bezier subpath.append([point, point, point]) csp.append(subpath) return csp def line_strings_to_path(line_strings): csp = line_strings_to_csp(line_strings) return inkex.PathElement(attrib={ "d": str(inkex.paths.CubicSuperPath(csp)) })