示例#1
0
    def align_to_node(self, ref_node, alignment, relative_scale):
        """
        Aligns the node represented by self to a reference node according to the settings defined by the user
        :param ref_node: Reference node subclassed from SvgElement to which self is going to be aligned
        :param alignment: A 2-element string list defining the alignment
        :param relative_scale: Scaling of the new node relative to the scale of the reference node
        """
        scale_transform = st.parseTransform("scale(%f)" % relative_scale)

        old_transform = ref_node.get_attrib('transform')
        composition = st.parseTransform(old_transform, scale_transform)

        # Account for vertical flipping of pstoedit nodes when recompiled via pdf2svg and vice versa
        composition = self._check_and_fix_transform(ref_node, composition)

        # keep alignment point of drawing intact, calculate required shift
        self.set_attrib('transform', st.formatTransform(composition))

        x, y, w, h = ref_node.get_frame()
        new_x, new_y, new_w, new_h = self.get_frame()

        p_old = self._get_pos(x, y, w, h, alignment)
        p_new = self._get_pos(new_x, new_y, new_w, new_h, alignment)

        dx = p_old[0] - p_new[0]
        dy = p_old[1] - p_new[1]

        composition[0][2] += dx
        composition[1][2] += dy

        self.set_attrib('transform', st.formatTransform(composition))
        self.set_attrib("jacobian_sqrt", str(self.get_jacobian_sqrt()), TEXTEXT_NS)
示例#2
0
def check_text_on_path(svg, element, scale_x, scale_y):
    """Check whether to skip scaling a text put on a path."""
    skip = False
    path = get_linked(svg, element.find(inkex.addNS('textPath', 'svg')))
    if not is_in_defs(svg, path):
        if is_sibling(element, path):
            # skip common element scaling if both text and path are siblings
            skip = True
            # scale offset
            if 'transform' in element.attrib:
                mat = simpletransform.parseTransform(element.get('transform'))
                mat[0][2] *= scale_x
                mat[1][2] *= scale_y
                element.set('transform', simpletransform.formatTransform(mat))
            # scale font size
            mat = simpletransform.parseTransform(
                'scale({},{})'.format(scale_x, scale_y))
            det = abs(mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0])
            descrim = math.sqrt(abs(det))
            prop = 'font-size'
            # outer text
            sdict = simplestyle.parseStyle(element.get('style'))
            if prop in sdict:
                sdict[prop] = float(sdict[prop]) * descrim
                element.set('style', simplestyle.formatStyle(sdict))
            # inner tspans
            for child in element.iterdescendants():
                if child.tag == inkex.addNS('tspan', 'svg'): 
                    sdict = simplestyle.parseStyle(child.get('style'))
                    if prop in sdict:
                        sdict[prop] = float(sdict[prop]) * descrim
                        child.set('style', simplestyle.formatStyle(sdict))
    return skip
    def _merge_transform(self, node, transform):
        """Propagate style and transform to remove inheritance
        Originally from
        https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370
        """

        # Compose the transformations
        if node.tag == addNS("svg", "svg") and node.get("viewBox"):
            vx, vy, vw, vh = [self._get_dimension(x)
                for x in node.get("viewBox").split()]
            dw = self._get_dimension(node.get("width", vw))
            dh = self._get_dimension(node.get("height", vh))
            t = ("translate(%f, %f) scale(%f, %f)" %
                (-vx, -vy, dw / vw, dh / vh))
            this_transform = simpletransform.parseTransform(
                t, transform)
            this_transform = simpletransform.parseTransform(
                node.get("transform"), this_transform)
            del node.attrib["viewBox"]
        else:
            this_transform = simpletransform.parseTransform(node.get(
                "transform"), transform)

        # Set the node's transform attrib
        node.set("transform",
                simpletransform.formatTransform(this_transform))
示例#4
0
    def fixUses(self, node, index):
        '''
    Fix <use> objects after transformation the objects their refer to
    '''

        # Go deep first
        for i in node:
            self.fixUses(i, index)

        # Is it a <use> tag?
        if node.tag == inkex.addNS("use", "svg"):
            # Get reference
            href = node.get(inkex.addNS('href', 'xlink'))
            if href[0] == "#":
                # Did we apply any transforms to the referred node?
                if href[1:] in index:
                    # Yes!
                    thatTr = index[href[1:]]
                    thisTr = SpeleoTransform.getTransform(node)
                    invThatTr = SpeleoTransform.invertTransform(thatTr)

                    # So, first transform of this <use> should be *reverting* that transform!
                    node.set(
                        "transform",
                        simpletransform.formatTransform(
                            simpletransform.composeTransform(
                                thisTr, invThatTr)))
示例#5
0
    def _merge_transform(self, node, transform):
        """Propagate style and transform to remove inheritance
        Originally from
        https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370
        """

        # Compose the transformations
        if node.tag == addNS("svg", "svg") and node.get("viewBox"):
            vx, vy, vw, vh = [
                self._get_dimension(x) for x in node.get("viewBox").split()
            ]
            dw = self._get_dimension(node.get("width", vw))
            dh = self._get_dimension(node.get("height", vh))
            t = ("translate(%f, %f) scale(%f, %f)" %
                 (-vx, -vy, dw / vw, dh / vh))
            this_transform = simpletransform.parseTransform(t, transform)
            this_transform = simpletransform.parseTransform(
                node.get("transform"), this_transform)
            del node.attrib["viewBox"]
        else:
            this_transform = simpletransform.parseTransform(
                node.get("transform"), transform)

        # Set the node's transform attrib
        node.set("transform", simpletransform.formatTransform(this_transform))
 def _merge_clippath(self, node, clippathurl):
     if (clippathurl):
         node_transform = simpletransform.parseTransform(
             node.get("transform"))
         if (node_transform):
             # Clip-paths on nodes with a transform have the transform
             # applied to the clipPath as well, which we don't want.  So, we
             # create new clipPath element with references to all existing
             # clippath subelements, but with the inverse transform applied
             inverse_node_transform = simpletransform.formatTransform(
                 self._invert_transform(node_transform))
             new_clippath = inkex.etree.SubElement(
                 self.xpathSingle('//svg:defs'), 'clipPath', {
                     'clipPathUnits': 'userSpaceOnUse',
                     'id': self.uniqueId("clipPath")
                 })
             clippath = self.getElementById(clippathurl[5:-1])
             for c in (clippath.iterchildren()):
                 inkex.etree.SubElement(
                     new_clippath, 'use', {
                         inkex.addNS('href', 'xlink'): '#' + c.get("id"),
                         'transform': inverse_node_transform,
                         'id': self.uniqueId("use")
                     })
             # Set the clippathurl to be the one with the inverse transform
             clippathurl = "url(#" + new_clippath.get("id") + ")"
         # Reference the parent clip-path to keep clipping intersection
         # Find end of clip-path chain and add reference there
         node_clippathurl = node.get("clip-path")
         while (node_clippathurl):
             node = self.getElementById(node_clippathurl[5:-1])
             node_clippathurl = node.get("clip-path")
         node.set("clip-path", clippathurl)
 def _merge_clippath(self, node, clippathurl):
     if (clippathurl):
         node_transform = simpletransform.parseTransform(
             node.get("transform"))
         if (node_transform):
             # Clip-paths on nodes with a transform have the transform
             # applied to the clipPath as well, which we don't want.  So, we
             # create new clipPath element with references to all existing
             # clippath subelements, but with the inverse transform applied
             inverse_node_transform = simpletransform.formatTransform(
                 self._invert_transform(node_transform))
             new_clippath = inkex.etree.SubElement(
                 self.xpathSingle('//svg:defs'), 'clipPath',
                 {'clipPathUnits': 'userSpaceOnUse',
                  'id': self.uniqueId("clipPath")})
             clippath = self.getElementById(clippathurl[5:-1])
             for c in (clippath.iterchildren()):
                 inkex.etree.SubElement(
                     new_clippath, 'use',
                     {inkex.addNS('href', 'xlink'): '#' + c.get("id"),
                      'transform': inverse_node_transform,
                      'id': self.uniqueId("use")})
             # Set the clippathurl to be the one with the inverse transform
             clippathurl = "url(#" + new_clippath.get("id") + ")"
         # Reference the parent clip-path to keep clipping intersection
         # Find end of clip-path chain and add reference there
         node_clippathurl = node.get("clip-path")
         while (node_clippathurl):
             node = self.getElementById(node_clippathurl[5:-1])
             node_clippathurl = node.get("clip-path")
         node.set("clip-path", clippathurl)
示例#8
0
def get_correction_transform(svg):
    transform = get_viewbox_transform(svg)

    # we need to correct for the viewbox
    transform = simpletransform.invertTransform(transform)
    transform = simpletransform.formatTransform(transform)

    return transform
示例#9
0
    def recursiveFuseTransform(self, node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = composeTransform(transf, parseTransform(node.get("transform", None)))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        if 'style' in node.attrib:
            style = node.attrib.get('style')
            style = simplestyle.parseStyle(style)
            update = False

            if 'stroke-width' in style:
                try:
                    stroke_width = self.unittouu(style.get('stroke-width').strip())
                    # pixelsnap ext assumes scaling is similar in x and y
                    # and uses the x scale...
                    # let's try to be a bit smarter
                    stroke_width *= math.sqrt(transf[0][0]**2 + transf[1][1]**2)
                    style['stroke-width'] = str(stroke_width)
                    update = True
                except AttributeError:
                    pass

            if update:
                style = simplestyle.formatStyle(style)
                node.attrib['style'] = style

        node = ApplyTransform.objectToPath(node)

        if 'd' in node.attrib:
            d = node.get('d')
            p = cubicsuperpath.parsePath(d)
            applyTransformToPath(transf, p)
            node.set('d', cubicsuperpath.formatPath(p))

        elif node.tag in [inkex.addNS('polygon', 'svg'),
                          inkex.addNS('polyline', 'svg')]:
            points = node.get('points')
            points = points.strip().split(' ')
            for k,p in enumerate(points):
                if ',' in p:
                    p = p.split(',')
                    p = [float(p[0]),float(p[1])]
                    applyTransformToPoint(transf, p)
                    p = [str(p[0]),str(p[1])]
                    p = ','.join(p)
                    points[k] = p
            points = ' '.join(points)
            node.set('points', points)

        elif node.tag in [inkex.addNS('rect', 'svg'),
                          inkex.addNS('text', 'svg'),
                          inkex.addNS('image', 'svg'),
                          inkex.addNS('use', 'svg')]:
            node.set('transform', formatTransform(transf))

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
示例#10
0
	def effect(self):
		layer = self.get_current_layer()
		affine = inverse(i2d_affine(self, layer))
		transform = simpletransform.formatTransform(affine) + \
			' translate' + str(self.view_center)

		g = Scalebar(self.options.scale, self.options.dpi, self.options.text, self.uutounit(1, 'px')).get_tree()
		g.set('transform', transform)
		layer.append(g)
示例#11
0
    def effect(self):
        layer = self.get_current_layer()
        affine = inverse(i2d_affine(self, layer))
        transform = simpletransform.formatTransform(affine) + \
         ' translate' + str(self.view_center)

        g = Scalebar(self.options.scale, self.options.dpi, self.options.text,
                     self.uutounit(1, 'px')).get_tree()
        g.set('transform', transform)
        layer.append(g)
示例#12
0
 def copy_interior(self, basename,status, newbasename,newstatus, dx):
     current = self.getElementById(basename+'-'+status)
     if current != None:
         new = copy.deepcopy(current)
         new.set('id', newbasename+'-'+newstatus)
         if new.attrib.has_key('transform'):
             mat = simpletransform.parseTransform(new.get('transform'))
             mat[0][2] = mat[0][2]+dx
         else:
             mat = [[1,0,dx],[0,1,0]]
         new.set('transform', simpletransform.formatTransform(mat))
         current.getparent().append(new)
示例#13
0
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = composeTransform(transf,
                                  parseTransform(node.get("transform", None)))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        node = self.objectToPath(node)

        if 'd' in node.attrib:
            d = node.get('d')
            p = cubicsuperpath.parsePath(d)
            applyTransformToPath(transf, p)
            node.set('d', cubicsuperpath.formatPath(p))

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('polygon', 'svg'),
                inkex.addNS('polyline', 'svg')
        ]:
            points = node.get('points')
            points = points.strip().split(' ')
            for k, p in enumerate(points):
                if ',' in p:
                    p = p.split(',')
                    p = [float(p[0]), float(p[1])]
                    applyTransformToPoint(transf, p)
                    p = [str(p[0]), str(p[1])]
                    p = ','.join(p)
                    points[k] = p
            points = ' '.join(points)
            node.set('points', points)

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('rect', 'svg'),
                inkex.addNS('text', 'svg'),
                inkex.addNS('image', 'svg'),
                inkex.addNS('use', 'svg'),
                inkex.addNS('circle', 'svg')
        ]:
            node.set('transform', formatTransform(transf))

        else:
            # e.g. <g style="...">
            self.scaleStrokeWidth(node, transf)

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
示例#14
0
    def get_correction_transform(self, node):
        # if we want to place our new nodes in the same group as this node,
        # then we'll need to factor in the effects of any transforms set on
        # the parents of this node.

        # 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 = simpletransform.invertTransform(transform)

        return simpletransform.formatTransform(transform)
示例#15
0
def check_use(svg, element, scale_x, scale_y):
    """Check whether to skip scaling an instanciated element (<use>)."""
    skip = False
    path = get_linked(svg, element)
    if not is_in_defs(svg, path):
        if is_sibling(element, path):
            skip = True
            # scale offset
            if 'transform' in element.attrib:
                mat = simpletransform.parseTransform(element.get('transform'))
                mat[0][2] *= scale_x
                mat[1][2] *= scale_y
                element.set('transform', simpletransform.formatTransform(mat))
    return skip
    def translateElement(self, node, x, y, relative=False):

        # Grab transform attribute if it exists.
        transform = node.get("transform", "")

        # Compute the nodes bounding box
        box = list(simpletransform.computeBBox([node]))

        pos_x = box[0]
        pos_y = box[2]

        # rotation center is not a breeze to calculate from the matrix, so thanks inkscape ;)
        origin_x = float(node.get(inkex.addNS("transform-center-x", "inkscape"), 0))
        origin_y = float(node.get(inkex.addNS("transform-center-y", "inkscape"), 0))
        origin_x = origin_x + (box[1] / 2)
        origin_y = (origin_y * -1) + (box[3] / 2)

        if transform == "":
            # If there is no transform attribute on the node we add one
            node.attrib["transform"] = ""

        # simpletransform returns a multi dim array of matrix values
        transform = simpletransform.parseTransform(transform)

        transformObject = self.normalizeMatrix(transform)
        inkex.debug(transformObject)
        # offset_x = (transform[0][2]-pos_x)
        # offset_y = (transform[1][2]-pos_y)
        offset_x = pos_x * -1
        offset_y = pos_y * -1

        inkex.debug([offset_x, offset_y])

        transform = simpletransform.parseTransform(
            ("translate(" + str(offset_x) + " " + str(offset_y) + ")"), transform
        )

        transformObject = self.normalizeMatrix(transform)
        inkex.debug(transformObject)

        inkex.debug(transform)

        if relative == False:
            matrix = simpletransform.formatTransform(transform)
            node.set("transform", matrix)
            inkex.debug(matrix)
        else:
            simpletransform.applyTransformToNode(transform, node)
示例#17
0
    def effect(self):
        """
        Apply the transformation. If an element already has a transformation
        attribute, it will be combined with the transformation matrix for the
        requested conversion.
        """

        if self.options.reverse == "true":
            conversion = "from_" + self.options.conversion
        else:
            conversion = "to_" + self.options.conversion

        if len(self.selected) == 0:
            inkex.errormsg(
                _("Please select an object to perform the " +
                  "isometric projection transformation on."))
            return

        # Default to the flat 2D to isometric top down view conversion if an
        # invalid identifier is passed.
        effect_matrix = self.transformations.get(
            conversion, self.transformations.get('to_top'))

        for id, node in self.selected.items():
            bbox = computeBBox([node])
            midpoint = self.getMidPoint(bbox, node)
            center_old = self.getTransformCenter(midpoint, node)
            transform = node.get("transform")
            # Combine our transformation matrix with any pre-existing
            # transform.
            matrix = parseTransform(transform, effect_matrix)

            # Compute the location of the transformation center after applying
            # the transformation matrix.
            center_new = center_old[:]
            applyTransformToPoint(matrix, center_new)
            applyTransformToPoint(matrix, midpoint)

            # Add a translation transformation that will move the object to
            # keep its transformation center in the same place.
            self.translateBetweenPoints(matrix, center_new, center_old)

            node.set('transform', formatTransform(matrix))

            # Adjust the transformation center.
            self.moveTransformationCenter(node, midpoint, center_new)
示例#18
0
    def scanTree(self, node, sel, group, correctiveTransform):
        '''
    Recursively look for <use>s referring to symbol sel
    
    Adds all these symbols to group 'group', applying transforms accordingly
    '''

        # Avoid too much recursion
        if node == group: return

        # Do not go into invisible layers
        if self.isLayer(node):
            if self.hasDisplayNone(node):
                return

        # Recurse first
        for i in node:
            self.scanTree(i, sel, group, correctiveTransform)

        # See if it's the symbol we need
        href = node.get(inkex.addNS('href', 'xlink'))

        # Perhaps not a reference at all...
        if href == None: return

        # Is this the right symbol?
        if href == sel:
            # Move to our group
            if group <> None:
                # Get total transform of this symbol
                transform = SpeleoTransform.getTotalTransform(node)

                # Group it together with others
                group.append(node)

                # Reset this node transform
                node.set(
                    "transform",
                    simpletransform.formatTransform(
                        simpletransform.composeTransform(
                            correctiveTransform, transform)))

            # Did anyone order a replace?
            if self.options.replace:
                node.set(inkex.addNS('href', 'xlink'),
                         '#' + self.options.replace)
    def effect(self):
        """
        Apply the transformation. If an element already has a transformation
        attribute, it will be combined with the transformation matrix for the
        requested conversion.
        """

        if self.options.reverse == "true":
            conversion = "from_" + self.options.conversion
        else:
            conversion = "to_" + self.options.conversion

        if len(self.selected) == 0:
            inkex.errormsg(_("Please select an object to perform the " +
                             "isometric projection transformation on."))
            return

        # Default to the flat 2D to isometric top down view conversion if an
        # invalid identifier is passed.
        effect_matrix = self.transformations.get(
            conversion, self.transformations.get('to_top'))

        for id, node in self.selected.iteritems():
            bbox = computeBBox([node])
            midpoint = self.getMidPoint(bbox, node)
            center_old = self.getTransformCenter(midpoint, node)
            transform = node.get("transform")
            # Combine our transformation matrix with any pre-existing
            # transform.
            matrix = parseTransform(transform, effect_matrix)

            # Compute the location of the transformation center after applying
            # the transformation matrix.
            center_new = center_old[:]
            applyTransformToPoint(matrix, center_new)
            applyTransformToPoint(matrix, midpoint)

            # Add a translation transformation that will move the object to
            # keep its transformation center in the same place.
            self.translateBetweenPoints(matrix, center_new, center_old)

            node.set('transform', formatTransform(matrix))

            # Adjust the transformation center.
            self.moveTransformationCenter(node, midpoint, center_new)
示例#20
0
    def transform(self, elem, setval=None, parent_transform=None):
        """ Gets this element's transform. Use setval=matrix to
            set this element's transform.
            You can only specify parent_transform when getting.
        """
        transform = elem.attrib.get("transform", "").strip()

        if transform:
            transform = simpletransform.parseTransform(transform)
        else:
            transform = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
        if parent_transform:
            transform = simpletransform.composeTransform(parent_transform, transform)

        if setval:
            elem.attrib["transform"] = simpletransform.formatTransform(setval)
        else:
            return transform
示例#21
0
 def transform(self, elem, setval=None, parent_transform=None):
     """ Gets this element's transform. Use setval=matrix to
         set this element's transform.
         You can only specify parent_transform when getting.
     """
     transform = elem.attrib.get('transform', '').strip()
     
     if transform:
         transform = simpletransform.parseTransform(transform)
     else:
         transform = [[1,0,0], [0,1,0], [0,0,1]]
     if parent_transform:
         transform = simpletransform.composeTransform(parent_transform, transform)
         
     if setval:
         elem.attrib['transform'] = simpletransform.formatTransform(setval)
     else:
         return transform
    def recursiveFuseTransform(node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = composeTransform(transf, parseTransform(node.get("transform", None)))

        if "transform" in node.attrib:
            del node.attrib["transform"]

        node = ApplyTransform.objectToPath(node)

        if "d" in node.attrib:
            d = node.get("d")
            p = cubicsuperpath.parsePath(d)
            applyTransformToPath(transf, p)
            node.set("d", cubicsuperpath.formatPath(p))

        elif node.tag == inkex.addNS("rect", "svg"):
            node.set("transform", formatTransform(transf))

        for child in node.getchildren():
            ApplyTransform.recursiveFuseTransform(child, transf)
    def recursiveFuseTransform(node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = composeTransform(transf, parseTransform(node.get("transform", None)))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        node = ApplyTransform.objectToPath(node)

        if 'd' in node.attrib:
            d = node.get('d')
            p = cubicsuperpath.parsePath(d)
            applyTransformToPath(transf, p)
            node.set('d', cubicsuperpath.formatPath(p))

        elif node.tag == inkex.addNS('rect', 'svg'):
            node.set('transform', formatTransform(transf))

        for child in node.getchildren():
            ApplyTransform.recursiveFuseTransform(child, transf)
示例#24
0
    def test_simpletransform(self):
        """Test simpletransform API"""
        import simpletransform

        self.assertEqual(simpletransform.parseTransform('scale(10)'),
                         [[10, 0, 0], [0, 10, 0]])
        self.assertEqual(simpletransform.parseTransform('translate(2,3)'),
                         [[1, 0, 2], [0, 1, 3]])
        self.assertEqual(
            simpletransform.parseTransform('translate(2,3) rotate(90)'),
            [approx([0, -1, 2]), approx([1, 0, 3])])
        m = simpletransform.formatTransform([[0, -1, 2], [1, 0, 3]])
        self.assertEqual(re.sub(r',', ' ', re.sub(r'\.0*\b', '', m)),
                         'matrix(0 1 -1 0 2 3)')
        self.assertEqual(
            simpletransform.invertTransform([[1, 0, 2], [0, 1, 3]]),
            [[1, 0, -2], [0, 1, -3]])
        self.assertEqual(
            simpletransform.composeTransform([[1, 0, 2], [0, 1, 3]],
                                             [[0, -1, 0], [1, 0, 0]]),
            [[0, -1, 2], [1, 0, 3]])

        pt = [4, 5]
        self.assertEqual(
            simpletransform.applyTransformToPoint([[0, -1, 2], [1, 0, 3]], pt),
            None)
        self.assertEqual(pt, [-3, 7])

        self.assertEqual(simpletransform.boxunion([3, 5, 2, 4], [4, 6, 1, 3]),
                         (3, 6, 1, 4))
        self.assertEqual(simpletransform.cubicExtrema(1, 2, 3, 4), (1, 4))

        # TODO need cubic superpath
        self.assertTrue(simpletransform.applyTransformToPath)
        self.assertTrue(simpletransform.roughBBox)
        self.assertTrue(simpletransform.refinedBBox)

        # TODO need node
        self.assertTrue(simpletransform.fuseTransform)
        self.assertTrue(simpletransform.composeParents)
        self.assertTrue(simpletransform.applyTransformToNode)
        self.assertTrue(simpletransform.computeBBox)
        self.assertTrue(simpletransform.computePointInNode)
示例#25
0
文件: path.py 项目: derco0n/inkstitch
def get_correction_transform(node, child=False):
    """Get a transform to apply to new siblings or children of this SVG node"""

    # if we want to place our new nodes in the same group/layer as this node,
    # then we'll need to factor in the effects of any transforms set on
    # the parents of this node.

    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 = simpletransform.invertTransform(transform)

    return simpletransform.formatTransform(transform)
示例#26
0
def emit_inkscape(parent, stitches):
    transform = get_viewbox_transform(parent.getroottree().getroot())

    # we need to correct for the viewbox
    transform = simpletransform.invertTransform(transform)
    transform = simpletransform.formatTransform(transform)

    for color, polyline in stitches_to_polylines(stitches):
        # dbg.write('polyline: %s %s\n' % (color, repr(polyline)))
        inkex.etree.SubElement(
            parent, inkex.addNS('polyline', 'svg'), {
                'style':
                simplestyle.formatStyle(
                    {
                        'stroke': color if color is not None else '#000000',
                        'stroke-width': "0.4",
                        'fill': 'none'
                    }),
                'points':
                " ".join(",".join(str(coord) for coord in point)
                         for point in polyline),
                'transform':
                transform
            })
示例#27
0
    def effect(self):
        # search for pattern layer
        triangle_layer = self.document.xpath('//svg:g[@id="triangle_layer"]',
                                             namespaces=inkex.NSS)
        if len(triangle_layer) == 0:
            # append pattern layer
            triangle_layer = self.createLayer("triangle_layer",
                                              "Triangle Boundary")
            self.document.getroot().append(triangle_layer)
            inkex.debug(
                "1. draw exactly one triangle in Triangle Boundary layer\n"
                "2. create a pattern composed of only paths\n"
                "3. select triangles that you want to apply pattern to\n"
                "4. enter pattern id (or default to use first pattern), then apply"
            )
        else:
            triangle_layer = triangle_layer[0]
            # find triangle in the triangle_layer
            trngl_lyr_children = triangle_layer.getchildren()
            if not len(trngl_lyr_children) == 1:
                inkex.debug(
                    "more or less than 1 element in Triangle Boundary layer: "
                    + str(len(trngl_lyr_children)))
                return
            else:
                bndry_trngle = triangle_layer.getchildren()[0]
                # seems like a path
                if isPath(bndry_trngle):
                    path_string = bndry_trngle.attrib[u'd']
                    svg_path = simplepath.parsePath(path_string)

                    # verified to be triangle
                    if pathIsTriangle(svg_path):
                        self.bndry_trngle_verts = getTriangleVerts(svg_path)
                        self.bndry_trngle_matrx = formMatrix(
                            self.bndry_trngle_verts)

                        # find pattern
                        self.defs = self.document.xpath(
                            '//svg:defs', namespaces=inkex.NSS)[0]
                        # get first pattern is default
                        if self.options.pattern_name == "default":
                            patterns = self.defs.xpath('./svg:pattern',
                                                       namespaces=inkex.NSS)
                        # find pattern with name
                        else:
                            patterns = self.defs.xpath(
                                './svg:pattern[@id="' +
                                self.options.pattern_name + '"]',
                                namespaces=inkex.NSS)

                        if len(patterns) > 0:
                            self.pattern = patterns[0]
                            # calculate the size of the pattern so that the pattern repeats exactly once in the bounding triangle
                            # get the union of all paths in pattern and boundary triangle
                            pattern_trngle_union = self.pattern.xpath(
                                './/svg:path', namespaces=inkex.NSS)
                            pattern_trngle_union.append(bndry_trngle)
                            # get bounding box of the union
                            bb_x_min, bb_x_max, bb_y_min, bb_y_max = simpletransform.computeBBox(
                                pattern_trngle_union)
                            # calculate size of union
                            pattern_width = bb_x_max - bb_x_min
                            pattern_height = bb_y_max - bb_y_min
                            # get scaling factor of pattern
                            pattern_trnsfrm = simpletransform.parseTransform(
                                self.pattern.attrib[u'patternTransform'])
                            scale_x = pattern_trnsfrm[0][0]
                            scale_y = pattern_trnsfrm[1][1]
                            # set size of pattern
                            self.pattern.attrib[u'width'] = str(pattern_width /
                                                                scale_x)
                            self.pattern.attrib[u'height'] = str(
                                pattern_height / scale_y)
                        else:
                            inkex.debug("cannot find pattern")
                            return
                else:
                    inkex.debug(
                        "the shape in triangle boundary layer is not a triangle"
                    )
                    return

        for id, node in self.selected.iteritems():
            if isPath(node):
                path_string = node.attrib[u'd']
                svg_path = simplepath.parsePath(path_string)
                if pathIsTriangle(svg_path):
                    trngle_verts = getTriangleVerts(svg_path)
                    trngle_matrx = formMatrix(trngle_verts)
                    # apply affine transform
                    pattern_trnsform = three.multiply(
                        trngle_matrx,
                        three.getInverse(self.bndry_trngle_matrx))
                    # compose with initial transform of pattern
                    initial_trnsform = simpletransform.parseTransform(
                        self.pattern.attrib[u'patternTransform'])
                    final_trnsform = simpletransform.composeTransform(
                        pattern_trnsform, initial_trnsform)
                    # if pattern for triangle exists, use it
                    pattern_name = "pattern_for_" + str(id)
                    existing_patterns = self.defs.xpath('./svg:pattern[@id="' +
                                                        pattern_name + '"]',
                                                        namespaces=inkex.NSS)
                    if len(existing_patterns) > 0:
                        pattern_transformed = existing_patterns[0]
                    else:
                        # create transformed pattern
                        pattern_transformed = etree.Element("{%s}pattern" %
                                                            inkex.NSS[u'svg'])
                    # fill in the attributes for pattern
                    pattern_transformed.attrib[u'id'] = "pattern_for_" + str(
                        id)
                    pattern_transformed.attrib[
                        "{%s}collect" % inkex.NSS[u'inkscape']] = "always"
                    pattern_transformed.attrib[
                        "{%s}href" %
                        inkex.NSS[u'xlink']] = '#' + self.pattern.attrib[u'id']
                    pattern_transformed.attrib[
                        u'patternTransform'] = simpletransform.formatTransform(
                            final_trnsform)
                    # append transformed pattern
                    self.defs.append(pattern_transformed)
                    # fill triangle with pattern
                    trngle_styles = simplestyle.parseStyle(
                        node.attrib[u'style'])
                    trngle_styles[u'fill'] = u'url(#' + str(
                        pattern_transformed.attrib[u'id']) + ')'
                    node.attrib[u'style'] = simplestyle.formatStyle(
                        trngle_styles)
                else:
                    inkex.debug("not triangle")
示例#28
0
def propagate_attribs(node,
                      parent_style={},
                      parent_transform=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
    """Propagate style and transform to remove inheritance"""

    # Don't enter non-graphical portions of the document
    if (node.tag == addNS("namedview", "sodipodi")
            or node.tag == addNS("defs", "svg")
            or node.tag == addNS("metadata", "svg")
            or node.tag == addNS("foreignObject", "svg")):
        return

    # Compose the transformations
    if node.tag == addNS("svg", "svg") and node.get("viewBox"):
        vx, vy, vw, vh = [
            get_dimension(x) for x in node.get("viewBox").split()
        ]
        dw = get_dimension(node.get("width", vw))
        dh = get_dimension(node.get("height", vh))
        t = "translate(%f, %f) scale(%f, %f)" % (-vx, -vy, dw / vw, dh / vh)
        this_transform = simpletransform.parseTransform(t, parent_transform)
        this_transform = simpletransform.parseTransform(
            node.get("transform"), this_transform)
        del node.attrib["viewBox"]
    else:
        this_transform = simpletransform.parseTransform(
            node.get("transform"), parent_transform)

    # Compose the style attribs
    this_style = simplestyle.parseStyle(node.get("style", ""))
    remaining_style = {}  # Style attributes that are not propagated

    non_propagated = ["filter"
                      ]  # Filters should remain on the topmost ancestor
    for key in non_propagated:
        if key in this_style.keys():
            remaining_style[key] = this_style[key]
            del this_style[key]

    # Create a copy of the parent style, and merge this style into it
    parent_style_copy = parent_style.copy()
    parent_style_copy.update(this_style)
    this_style = parent_style_copy

    # Merge in any attributes outside of the style
    style_attribs = ["fill", "stroke"]
    for attrib in style_attribs:
        if node.get(attrib):
            this_style[attrib] = node.get(attrib)
            del node.attrib[attrib]

    if (node.tag == addNS("svg", "svg") or node.tag == addNS("g", "svg")
            or node.tag == addNS("a", "svg")
            or node.tag == addNS("switch", "svg")):
        # Leave only non-propagating style attributes
        if len(remaining_style) == 0:
            if "style" in node.keys():
                del node.attrib["style"]
        else:
            node.set("style", simplestyle.formatStyle(remaining_style))

        # Remove the transform attribute
        if "transform" in node.keys():
            del node.attrib["transform"]

        # Continue propagating on subelements
        for c in node.iterchildren():
            propagate_attribs(c, this_style, this_transform)
    else:
        # This element is not a container

        # Merge remaining_style into this_style
        this_style.update(remaining_style)

        # Set the element's style and transform attribs
        node.set("style", simplestyle.formatStyle(this_style))
        node.set("transform", simpletransform.formatTransform(this_transform))
	def effect(self) :
		if (self.options.create_bearing_gear and self.options.active_tab == '"help"' ):
			self.error(
"""English spport forum:
http://www.cnc-club.ru/forum/viewforum.php?f=33		
			
Russian support forum:
	http://cnc-club.ru/forum/viewtopic.php?f=15&t=287
			
			
			""")		
			return	
				
		time_ = time.time()
		self.distance = self.options.distance * self.options.units
		self.options.linear_distance *= self.options.units
		self.options.gear_r *= self.options.units
		self.options.bearings_d *= self.options.units
		
		self.first_teeth = self.options.selected_puley_teeth
		self.second_teeth = self.options.generated_puley_teeth
		self.num = self.options.number_of_copies

		def add_circle(c,r, center_mark=False) :
			return (
					"M%s,%s a %s,%s 0 1 1 %s,0 %s,%s 0 1 1 %s,0 z " % ( c[0]+r,c[1], r,r, -2*r, r,r, 2*r) + 
						#c+r,c   r r        -2*r  r   r       2*r
					( ("M %s,%s l -11,-11 22,22 -11,-11 -11,11, 22,-22" % (c[0],c[1])) if center_mark else "")
				)	
				
					
	
		c = list(self.view_center)
		d = ""
		d1 = ""		
		if (self.options.create_bearing_gear and self.options.active_tab == '"linear_shaft"' ):
			r = (self.options.gear_r*2+self.options.bearings_d/2+100)
			for i in range(self.options.number_of_bearings):
				a = i*math.pi*2/self.options.number_of_bearings
				d += add_circle([c[0]+math.cos(a)*self.options.gear_r, c[1]+math.sin(a)*self.options.gear_r	], self.options.bearings_d/2)
				d1 += add_circle([c[0]+math.cos(a)*self.options.gear_r, -r+c[1]+math.sin(a)*self.options.gear_r	], self.options.bearings_d/2, True)
			d1 += add_circle([c[0], c[1]-r], self.options.gear_r, True)


			path = inkex.etree.SubElement( self.current_layer, inkex.addNS('path','svg'), {"d":d, "style": "stroke:#4d4d4d;fill:#ececec"} )
			path1 = inkex.etree.SubElement( self.current_layer, inkex.addNS('path','svg'), {"d":d1, "style": "stroke:#4d4d4d;fill:#ececec"} )							

		
			csp = cubicsuperpath.parsePath(d)
			minx,miny,maxx,maxy = csp_true_bounds(csp)
			c1 = [ (maxx[0] + minx[0])/2, (maxy[1] + miny[1])/2 ] 
			path.set(inkex.addNS('transform-center-x','inkscape'),str(-c1[0]+c[0]))
			path.set(inkex.addNS('transform-center-y','inkscape'),str(-c1[1]+c[1]))


		
			self.selected = {"1":path}
		
		
		if len(self.selected)!=1: self.error('Please select one and only one path!','error')
		path = self.selected.values()[0]
		if "d" not in path.keys() :  self.error('Please select a "Path"!','error')
		csp = cubicsuperpath.parsePath(path.get("d"))
		
		center_group = inkex.etree.SubElement( path.getparent(),  inkex.addNS('g','svg') )
		group = inkex.etree.SubElement( path.getparent(),  inkex.addNS('g','svg') )
		attrib = path.attrib

		if "transform" in path.keys() :	
				t = path.get('transform')
				t = simpletransform.parseTransform(t)
				simpletransform.applyTransformToPath(t,csp)
				path.set("transform", "")
				path.set('d', cubicsuperpath.formatPath(csp))
				inkex.etree.SubElement( group, inkex.addNS('path','svg'), {"d": cubicsuperpath.formatPath(csp)})							
				self.error(path.get("transform"))

		# Will have to find center of bbox
		minx,miny,maxx,maxy = csp_true_bounds(csp)

		c1 = [ (maxx[0] + minx[0])/2, (maxy[1] + miny[1])/2 ] 
		w,h  = max(maxx[0]-minx[0], abs(c1[0]-minx[0]), abs(c1[0]-maxx[0]) ), max(maxy[1]-miny[1], abs(c1[1]-miny[1]), abs(c1[1]-maxy[1]) )
		if inkex.addNS('transform-center-x','inkscape') in path.keys() : c1[0] += float(path.get(inkex.addNS('transform-center-x','inkscape')))
		if inkex.addNS('transform-center-y','inkscape') in path.keys() : c1[1] -= float(path.get(inkex.addNS('transform-center-y','inkscape')))
		
		c2 = [c1[0]-self.distance, c1[1]]

		def get_transform(c1,c2,a1,a2):
			[c1x,c1y], [c2x,c2y] = c1,c2
			# move c1 to 0 
			transform = [ [1,0,-c1x], [0,1,-c1y] ]
			# Rotate to a1 to 0 
			transform = simpletransform.composeTransform([ [math.cos(a1), -math.sin(a1), 0], [math.sin(a1), math.cos(a1), 0] ], transform )
			# Move c2 to 0 			
			transform = simpletransform.composeTransform( [ [1,0,-c2x+c1x], [0,1,-c2y+c1y] ], transform)
			# Rotate to a2 to 0 
			transform = simpletransform.composeTransform( [ [math.cos(a2), -math.sin(a2), 0], [math.sin(a2), math.cos(a2), 0] ] , transform)
			# move c2 back to c2
			transform = simpletransform.composeTransform([ [1,0,c2x], [0,1,c2y] ], transform)
			return transform
		if not self.options.active_tab == '"linear_shaft"' :
			# Radial gear
			if not self.options.variable_speed :
				for i in range(self.num):
					
					alpha = math.pi*2*(i)/self.num*self.options.rev
					alpha1 = alpha*self.second_teeth
					alpha2 = alpha*self.first_teeth 

					transform = get_transform(c1,c2,alpha1,alpha2)
					# add path's clone 
					attrib["transform"] = simpletransform.formatTransform(transform)
					inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib )							

			else :
				def get_k (csp, c1,d):
					c2 = [c1[0]-d, c1[1]]
					alpha2_ = []
				
					for n in range(self.num):
						alpha1 = math.pi*2*(n)/self.num * self.second_teeth
						d_alpha1 = math.pi*2/self.num * self.second_teeth
						csp_ = [[[p[:] for p in point] for point in subpath] for subpath in csp ]
						transform = get_transform(c1,c2,alpha1,0)
						simpletransform.applyTransformToPath(transform, csp_)
						# r2 = distance to second gear's center
						[r2, i,j,t] = csp_to_point_distance(csp_, c2, dist_bounds = [0,1e100], tolerance=.001)
						r2 = math.sqrt(r2)

						p = csp_at_t(csp_[i][j-1],csp_[i][j],t)
						r1 = math.sqrt((p[0]-c1[0])**2 +(p[1]-c1[1])**2)
						# d_alpha2 = rotation speed factor
						if r2 == 0 : return 1e100, []
						alpha2_.append(d_alpha1 * r1/r2)
					return math.pi*2 * self.first_teeth / sum(alpha2_), alpha2_
				
				
				#get K, firs calculate aproximate turn and then get the K
				if not self.options.optimize_distance : 
					K, alpha2_ = get_k(csp,c1,self.distance)
				else : 		
					#set min and max distances
					dists = [0., math.sqrt(w**2+h**2)*(1+self.second_teeth/self.first_teeth) ]
					first = True
					for i in range(optimize_distance_max_iters):
						d = (dists[0]+dists[1])/2 #	if not first and not dists[0]<self.distance<dists[1] else self.distance
						first = False
						K, alpha2_ = get_k(csp,c1,d)
						if K>1 : 
							dists = [dists[0], d]
						else: 
							dists = [d, dists[1]] 
						if abs(1.-K)< optimize_distance_tolerance : 
							break
						#self.error(str((i,K,d)))	
					self.distance = d			
				c2 = [c1[0]-self.distance, c1[1]]	
				# Now create the paths
				alpha2 = 0
				for i in range(self.num):
					alpha = math.pi*2*(i)/self.num
					alpha1 = alpha*self.second_teeth
					alpha2 += alpha2_[i] * K

				
					transform = get_transform(c1,c2,alpha1,alpha2)
					# add path's clone 
					attrib["transform"] = simpletransform.formatTransform(transform)
					inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib )							
							
				self.error("Optimized distance: %s. "%(self.distance/self.options.units))
				self.error("Optimized parameter K: %s (the closer to 1.0 the better)."%K)
				self.error("Time elapsed %s seconds." %(time.time()-time_))			
			self.draw_pointer(c1, color = "#000080", width = 1, group = center_group )
			self.draw_pointer(c2, color = "#000080", width = 1, group = center_group )
		else :
			# Linear gear
			c1x,c1y = c1[0], c1[1]
			i = 0 
			self.distance = self.options.linear_distance
			if self.options.standatd_distance and self.options.create_bearing_gear: 
				self.distance = self.options.gear_r+self.options.bearings_d/2
				
			while i<=self.options.rev*self.num :
				a = math.pi*2*i/self.num
				d = self.distance * a 
				# Move c to 0  			
				transform = [ [1,0,-c1x], [0,1,-c1y] ]
				# Rotate to a
				transform = simpletransform.composeTransform( [ [math.cos(a), -math.sin(a), 0], [math.sin(a), math.cos(a), 0] ] , transform)
				# Move 0 to c + d  			
				transform = simpletransform.composeTransform( [ [1,0,c1x+d], [0,1,c1y] ], transform)
				attrib["transform"] = simpletransform.formatTransform(transform)
				inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib )							
				i += 1
示例#30
0
	def output(self):
		root = self.document.getroot()
		doc_width = self.unittouu(root.get('width'))
		doc_height = self.unittouu(root.get('height'))

		# load prefs from file
		th2pref_load_from_xml(root)
		th2pref.xyascenter = self.options.xyascenter

		self.r2d = [[1, 0, 0],[0, -1, doc_height]]
		viewBox = root.get('viewBox')
		if viewBox:
			m1 = parseViewBox(viewBox, doc_width, doc_height)
			self.r2d = simpletransform.composeTransform(self.r2d, m1)

		self.classes = {}
		stylenodes = self.document.xpath('//svg:style', namespaces=inkex.NSS)
		pattern = re.compile(r'\.(\w+)\s*\{(.*?)\}')
		for stylenode in stylenodes:
			if isinstance(stylenode.text, str):
				for x in pattern.finditer(stylenode.text):
					self.classes[x.group(1)] = simplestyle.parseStyle(x.group(2).strip())

		print '''encoding  utf-8
##XTHERION## xth_me_area_adjust 0 0 %f %f
##XTHERION## xth_me_area_zoom_to 100
''' % (doc_width * th2pref.basescale, doc_height * th2pref.basescale)

		# text on path
		if th2pref.textonpath:
			textpaths = self.document.xpath('//svg:textPath', namespaces=inkex.NSS)
			for node in textpaths:
				href = node.get(xlink_href).split('#', 1)[-1]
				options = {'text': self.get_point_text(node)}
				self.guess_text_scale(node, self.get_style(node.getparent()), options, self.i2d_affine(node))
				self.textpath_dict[href] = options

		if self.options.images:
			images = self.document.xpath('//svg:image', namespaces=inkex.NSS) + \
					self.document.xpath('//svg:g[@therion:type="xth_me_image_insert"]', namespaces=inkex.NSS)
			#for node in reversed(images):
			for node in images:
				params = [ self.unittouu(node.get('x', '0')), self.unittouu(node.get('y', '0')) ]
				mat = self.i2d_affine(node)
				href = node.get(xlink_href, '')
				if href == '': # xvi image (svg:g)
					options = parse_options(node.get(therion_options, ''))
					href = options.get('href', '')
				elif href.startswith('data:'):
					inkex.errormsg('Embedded images not supported!')
					continue
				paramsTrans = transformParams(mat, params)
				mat = simpletransform.composeTransform(mat, [[1,0,params[0]],[0,1,params[1]]])
				w = node.get('width', '100%')
				h = node.get('height', '100%')
				if th2pref.image_inkscape:
					print '##INKSCAPE## image %s %s %s %s' % (w, h, simpletransform.formatTransform(mat), href)
					continue
				if href.startswith('file://'):
					href = href[7:]
				print '##XTHERION## xth_me_image_insert {%f 1 1.0} {%f 1} "%s" 0 {}' % \
						(paramsTrans[0], paramsTrans[1], href)

		self.print_scrap_begin('scrap1', not self.options.lay2scr)

		if self.options.layers == 'current':
			layer = self.current_layer
			while layer.get(inkscape_groupmode, '') != "layer" and layer.getparent():
				layer = layer.getparent()
			self.output_scrap(layer)
		else:
			layers = self.document.xpath('/svg:svg/svg:g[@inkscape:groupmode="layer"]', namespaces=inkex.NSS)
			if len(layers) == 0:
				inkex.errormsg("Document has no layers!\nFallback to single scrap")
				layers = [ root ]
			for layer in layers:
				if layer.get(therion_role) == 'none':
					continue
				if self.options.layers == 'visible':
					style = self.get_style(layer)
					if style.get('display') == 'none':
						continue
				self.output_scrap(layer)

		self.print_scrap_end(not self.options.lay2scr)
示例#31
0
	def compute_bbox(self, node, transform=True, use_cache=False):
		'''
		Compute the bounding box of a element in its parent coordinate system,
		or in its own coordinate system if "transform" is False.

		Uses a cache to not compute the bounding box multiple times for
		elements like referenced symbols.

		Returns [xmin, xmax, ymin, ymax]

		Enhanced version of simpletransform.computeBBox()

		Warning: Evaluates "transform" attribute for symbol tags, which is
		wrong according to SVG spec, but matches Inkscape's behaviour.
		'''
		import cubicsuperpath
		from simpletransform import boxunion, parseTransform, applyTransformToPath, formatTransform
		try:
			from simpletransform import refinedBBox
		except:
			from simpletransform import roughBBox as refinedBBox

		d = None
		recurse = False
		node_bbox = None

		if transform:
			transform = node.get('transform', '')
		else:
			transform = ''

		if use_cache and node in self.bbox_cache:
			node_bbox = self.bbox_cache[node]
		elif node.tag in [ svg_use, 'use' ]:
			x, y = float(node.get('x', 0)), float(node.get('y', 0))
			refid = node.get(xlink_href)
			refnode = self.getElementById(refid[1:])

			if refnode is None:
				return None

			if 'width' in node.attrib and 'height' in node.attrib and 'viewBox' in refnode.attrib:
				mat = parseViewBox(refnode.get('viewBox'), node.get('width'), node.get('height'))
				transform += ' ' + formatTransform(mat)

			refbbox = self.compute_bbox(refnode, True, True)
			if refbbox is not None:
				node_bbox = [refbbox[0] + x, refbbox[1] + x, refbbox[2] + y, refbbox[3] + y]

		elif node.get('d'):
			d = node.get('d')
		elif node.get('points'):
			d = 'M' + node.get('points')
		elif node.tag in [ svg_rect, 'rect', svg_image, 'image' ]:
			d = 'M' + node.get('x', '0') + ',' + node.get('y', '0') + \
				'h' + node.get('width') + 'v' + node.get('height') + \
				'h-' + node.get('width')
		elif node.tag in [ svg_line, 'line' ]:
			d = 'M' + node.get('x1') + ',' + node.get('y1') + \
				' ' + node.get('x2') + ',' + node.get('y2')
		elif node.tag in [ svg_circle, 'circle', svg_ellipse, 'ellipse' ]:
			rx = node.get('r')
			if rx is not None:
				ry = rx
			else:
				rx = node.get('rx')
				ry = node.get('ry')
			rx, ry = float(rx), float(ry)
			cx = float(node.get('cx', '0'))
			cy = float(node.get('cy', '0'))
			node_bbox = [cx - rx, cx + rx, cy - ry, cy + ry]
			'''
			a = 0.555
			d = 'M %f %f C' % (cx-rx, cy) + ' '.join('%f' % c for c in [
				cx-rx,   cy-ry*a, cx-rx*a, cy-ry,   cx,    cy-ry,
				cx+rx*a, cy-ry,   cx+rx,   cy-ry*a, cx+rx, cy,
				cx+rx,   cy+ry*a, cx+rx*a, cy+ry,   cx,    cy+ry,
				cx-rx*a, cy+ry,   cx-rx,   cy+ry*a, cx-rx, cy,
				])
			'''
		elif node.tag in [ svg_text, 'text', svg_tspan, 'tspan' ]:
			# very rough estimate of text bounding box
			x = node.get('x', '0').split()
			y = node.get('y', '0').split()
			if len(x) == 1 and len(y) > 1:
				x = x * len(y)
			elif len(y) == 1 and len(x) > 1:
				y = y * len(x)
			d = 'M' + ' '.join('%f' % self.unittouu(c) for xy in zip(x, y) for c in xy)
			recurse = True
		elif node.tag in [ svg_g, 'g', svg_symbol, 'symbol', svg_svg, 'svg' ]:
			recurse = True

		if d is not None:
			p = cubicsuperpath.parsePath(d)
			node_bbox = refinedBBox(p)

		if recurse:
			for child in node:
				child_bbox = self.compute_bbox(child, True, use_cache)
				node_bbox = boxunion(child_bbox, node_bbox)

		self.bbox_cache[node] = node_bbox

		if transform.strip() != '' and node_bbox != None:
			mat = parseTransform(transform)
			p = [[[	[node_bbox[0], node_bbox[2]],
					[node_bbox[0], node_bbox[3]],
					[node_bbox[1], node_bbox[2]],
					[node_bbox[1], node_bbox[3]]]]]
			applyTransformToPath(mat, p)
			x, y = zip(*p[0][0])
			node_bbox = [min(x), max(x), min(y), max(y)]

		return node_bbox
    def effect(self):
        if (self.options.create_bearing_gear
                and self.options.active_tab == '"help"'):
            self.error("""English spport forum:
http://www.cnc-club.ru/forum/viewforum.php?f=33		
			
Russian support forum:
	http://cnc-club.ru/forum/viewtopic.php?f=15&t=287
			
			
			""")
            return

        time_ = time.time()
        self.distance = self.options.distance * self.options.units
        self.options.linear_distance *= self.options.units
        self.options.gear_r *= self.options.units
        self.options.bearings_d *= self.options.units

        self.first_teeth = self.options.selected_puley_teeth
        self.second_teeth = self.options.generated_puley_teeth
        self.num = self.options.number_of_copies

        def add_circle(c, r, center_mark=False):
            return ("M%s,%s a %s,%s 0 1 1 %s,0 %s,%s 0 1 1 %s,0 z " %
                    (c[0] + r, c[1], r, r, -2 * r, r, r, 2 * r) +
                    #c+r,c   r r        -2*r  r   r       2*r
                    (("M %s,%s l -11,-11 22,22 -11,-11 -11,11, 22,-22" %
                      (c[0], c[1])) if center_mark else ""))

        c = list(self.view_center)
        d = ""
        d1 = ""
        if (self.options.create_bearing_gear
                and self.options.active_tab == '"linear_shaft"'):
            r = (self.options.gear_r * 2 + self.options.bearings_d / 2 + 100)
            for i in range(self.options.number_of_bearings):
                a = i * math.pi * 2 / self.options.number_of_bearings
                d += add_circle([
                    c[0] + math.cos(a) * self.options.gear_r,
                    c[1] + math.sin(a) * self.options.gear_r
                ], self.options.bearings_d / 2)
                d1 += add_circle([
                    c[0] + math.cos(a) * self.options.gear_r,
                    -r + c[1] + math.sin(a) * self.options.gear_r
                ], self.options.bearings_d / 2, True)
            d1 += add_circle([c[0], c[1] - r], self.options.gear_r, True)

            path = inkex.etree.SubElement(
                self.current_layer, inkex.addNS('path', 'svg'), {
                    "d": d,
                    "style": "stroke:#4d4d4d;fill:#ececec"
                })
            path1 = inkex.etree.SubElement(
                self.current_layer, inkex.addNS('path', 'svg'), {
                    "d": d1,
                    "style": "stroke:#4d4d4d;fill:#ececec"
                })

            csp = cubicsuperpath.parsePath(d)
            minx, miny, maxx, maxy = csp_true_bounds(csp)
            c1 = [(maxx[0] + minx[0]) / 2, (maxy[1] + miny[1]) / 2]
            path.set(inkex.addNS('transform-center-x', 'inkscape'),
                     str(-c1[0] + c[0]))
            path.set(inkex.addNS('transform-center-y', 'inkscape'),
                     str(-c1[1] + c[1]))

            self.selected = {"1": path}

        if len(self.selected) != 1:
            self.error('Please select one and only one path!', 'error')
        path = self.selected.values()[0]
        if "d" not in path.keys():
            self.error('Please select a "Path"!', 'error')
        csp = cubicsuperpath.parsePath(path.get("d"))

        center_group = inkex.etree.SubElement(path.getparent(),
                                              inkex.addNS('g', 'svg'))
        group = inkex.etree.SubElement(path.getparent(),
                                       inkex.addNS('g', 'svg'))
        attrib = path.attrib

        if "transform" in path.keys():
            t = path.get('transform')
            t = simpletransform.parseTransform(t)
            simpletransform.applyTransformToPath(t, csp)
            path.set("transform", "")
            path.set('d', cubicsuperpath.formatPath(csp))
            inkex.etree.SubElement(group, inkex.addNS('path', 'svg'),
                                   {"d": cubicsuperpath.formatPath(csp)})
            self.error(path.get("transform"))

        # Will have to find center of bbox
        minx, miny, maxx, maxy = csp_true_bounds(csp)

        c1 = [(maxx[0] + minx[0]) / 2, (maxy[1] + miny[1]) / 2]
        w, h = max(maxx[0] - minx[0], abs(c1[0] - minx[0]),
                   abs(c1[0] - maxx[0])), max(maxy[1] - miny[1],
                                              abs(c1[1] - miny[1]),
                                              abs(c1[1] - maxy[1]))
        if inkex.addNS('transform-center-x', 'inkscape') in path.keys():
            c1[0] += float(
                path.get(inkex.addNS('transform-center-x', 'inkscape')))
        if inkex.addNS('transform-center-y', 'inkscape') in path.keys():
            c1[1] -= float(
                path.get(inkex.addNS('transform-center-y', 'inkscape')))

        c2 = [c1[0] - self.distance, c1[1]]

        def get_transform(c1, c2, a1, a2):
            [c1x, c1y], [c2x, c2y] = c1, c2
            # move c1 to 0
            transform = [[1, 0, -c1x], [0, 1, -c1y]]
            # Rotate to a1 to 0
            transform = simpletransform.composeTransform(
                [[math.cos(a1), -math.sin(a1), 0],
                 [math.sin(a1), math.cos(a1), 0]], transform)
            # Move c2 to 0
            transform = simpletransform.composeTransform(
                [[1, 0, -c2x + c1x], [0, 1, -c2y + c1y]], transform)
            # Rotate to a2 to 0
            transform = simpletransform.composeTransform(
                [[math.cos(a2), -math.sin(a2), 0],
                 [math.sin(a2), math.cos(a2), 0]], transform)
            # move c2 back to c2
            transform = simpletransform.composeTransform(
                [[1, 0, c2x], [0, 1, c2y]], transform)
            return transform

        if not self.options.active_tab == '"linear_shaft"':
            # Radial gear
            if not self.options.variable_speed:
                for i in range(self.num):
                    alpha = math.pi * 2 * (i) / self.num
                    alpha1 = alpha * self.second_teeth
                    alpha2 = alpha * self.first_teeth

                    transform = get_transform(c1, c2, alpha1, alpha2)
                    # add path's clone
                    attrib["transform"] = simpletransform.formatTransform(
                        transform)
                    inkex.etree.SubElement(group, inkex.addNS('path', 'svg'),
                                           attrib)

            else:

                def get_k(csp, c1, d):
                    c2 = [c1[0] - d, c1[1]]
                    alpha2_ = []

                    for n in range(self.num):
                        alpha1 = math.pi * 2 * (
                            n) / self.num * self.second_teeth
                        d_alpha1 = math.pi * 2 / self.num * self.second_teeth
                        csp_ = [[[p[:] for p in point] for point in subpath]
                                for subpath in csp]
                        transform = get_transform(c1, c2, alpha1, 0)
                        simpletransform.applyTransformToPath(transform, csp_)
                        # r2 = distance to second gear's center
                        [r2, i, j,
                         t] = csp_to_point_distance(csp_,
                                                    c2,
                                                    dist_bounds=[0, 1e100],
                                                    tolerance=.001)
                        r2 = math.sqrt(r2)

                        p = csp_at_t(csp_[i][j - 1], csp_[i][j], t)
                        r1 = math.sqrt((p[0] - c1[0])**2 + (p[1] - c1[1])**2)
                        # d_alpha2 = rotation speed factor
                        if r2 == 0: return 1e100, []
                        alpha2_.append(d_alpha1 * r1 / r2)
                    return math.pi * 2 * self.first_teeth / sum(
                        alpha2_), alpha2_

                #get K, firs calculate aproximate turn and then get the K
                if not self.options.optimize_distance:
                    K, alpha2_ = get_k(csp, c1, self.distance)
                else:
                    #set min and max distances
                    dists = [
                        0.,
                        math.sqrt(w**2 + h**2) *
                        (1 + self.second_teeth / self.first_teeth)
                    ]
                    first = True
                    for i in range(optimize_distance_max_iters):
                        d = (
                            dists[0] + dists[1]
                        ) / 2  #	if not first and not dists[0]<self.distance<dists[1] else self.distance
                        first = False
                        K, alpha2_ = get_k(csp, c1, d)
                        if K > 1:
                            dists = [dists[0], d]
                        else:
                            dists = [d, dists[1]]
                        if abs(1. - K) < optimize_distance_tolerance:
                            break
                        #self.error(str((i,K,d)))
                    self.distance = d
                c2 = [c1[0] - self.distance, c1[1]]
                # Now create the paths
                alpha2 = 0
                for i in range(self.num):
                    alpha = math.pi * 2 * (i) / self.num
                    alpha1 = alpha * self.second_teeth
                    alpha2 += alpha2_[i] * K

                    transform = get_transform(c1, c2, alpha1, alpha2)
                    # add path's clone
                    attrib["transform"] = simpletransform.formatTransform(
                        transform)
                    inkex.etree.SubElement(group, inkex.addNS('path', 'svg'),
                                           attrib)

                self.error("Optimized distance: %s. " %
                           (self.distance / self.options.units))
                self.error(
                    "Optimized parameter K: %s (the closer to 1.0 the better)."
                    % K)
                self.error("Time elapsed %s seconds." % (time.time() - time_))
            self.draw_pointer(c1, color="#000080", width=1, group=center_group)
            self.draw_pointer(c2, color="#000080", width=1, group=center_group)
        else:
            # Linear gear
            c1x, c1y = c1[0], c1[1]
            i = 0
            self.distance = self.options.linear_distance
            if self.options.standatd_distance and self.options.create_bearing_gear:
                self.distance = self.options.gear_r + self.options.bearings_d / 2

            while i <= self.options.rev * self.num:
                a = math.pi * 2 * i / self.num
                d = self.distance * a
                # Move c to 0
                transform = [[1, 0, -c1x], [0, 1, -c1y]]
                # Rotate to a
                transform = simpletransform.composeTransform(
                    [[math.cos(a), -math.sin(a), 0],
                     [math.sin(a), math.cos(a), 0]], transform)
                # Move 0 to c + d
                transform = simpletransform.composeTransform(
                    [[1, 0, c1x + d], [0, 1, c1y]], transform)
                attrib["transform"] = simpletransform.formatTransform(
                    transform)
                inkex.etree.SubElement(group, inkex.addNS('path', 'svg'),
                                       attrib)
                i += 1
示例#33
0
 def set_transform(self, elem, matrix):
     """ Sets this element's transform value to the given matrix """
     elem.attrib['transform'] = simpletransform.formatTransform(matrix)
示例#34
0
	def output(self):
		root = self.document.getroot()
		doc_width = self.unittouu(root.get('width') or '0')
		doc_height = self.unittouu(root.get('height') or '0')

		# load prefs from file
		th2pref_load_from_xml(root)
		th2pref.xyascenter = self.options.xyascenter

		self.r2d = [[1, 0, 0],[0, -1, doc_height]]
		viewBox = root.get('viewBox')
		if viewBox and doc_width and doc_height:
			m1 = parseViewBox(viewBox, doc_width, doc_height)
			self.r2d = simpletransform.composeTransform(self.r2d, m1)

		self.classes = {}
		stylenodes = self.document.xpath('//svg:style', namespaces=inkex.NSS)
		pattern = re.compile(r'\.(\w+)\s*\{(.*?)\}')
		for stylenode in stylenodes:
			if isinstance(stylenode.text, basestring):
				for x in pattern.finditer(stylenode.text):
					self.classes[x.group(1)] = simplestyle.parseStyle(x.group(2).strip())

		print('encoding  utf-8')
		if doc_width and doc_height:
			print('##XTHERION## xth_me_area_adjust 0 0 %f %f' % (
				doc_width * th2pref.basescale,
				doc_height * th2pref.basescale))
		print('##XTHERION## xth_me_area_zoom_to 100')

		# text on path
		if th2pref.textonpath:
			textpaths = self.document.xpath('//svg:textPath', namespaces=inkex.NSS)
			for node in textpaths:
				href = node.get(xlink_href).split('#', 1)[-1]
				options = {'text': self.get_point_text(node)}
				self.guess_text_scale(node, self.get_style(node.getparent()), options, self.i2d_affine(node))
				self.textpath_dict[href] = options

		if self.options.images:
			images = self.document.xpath('//svg:image', namespaces=inkex.NSS) + \
					self.document.xpath('//svg:g[@therion:type="xth_me_image_insert"]', namespaces=inkex.NSS)
			#for node in reversed(images):
			for node in images:
				params = [ self.unittouu(node.get('x', '0')), self.unittouu(node.get('y', '0')) ]
				mat = self.i2d_affine(node)
				href = node.get(xlink_href, '')
				XVIroot = '{}'
				if href == '': # xvi image (svg:g)
					options = parse_options(node.get(therion_options, ''))
					href = options.get('href', '')
					XVIroot = options.get('XVIroot', '{}')
				elif href.startswith('data:'):
					inkex.errormsg('Embedded images not supported!')
					continue
				paramsTrans = transformParams(mat, params)
				mat = simpletransform.composeTransform(mat, [[1,0,params[0]],[0,1,params[1]]])
				w = node.get('width', '100%')
				h = node.get('height', '100%')
				if th2pref.image_inkscape:
					print('##INKSCAPE## image %s %s %s %s' % (w, h, simpletransform.formatTransform(mat), href))
					continue
				if href.startswith('file://'):
					href = href[7:]
				print('##XTHERION## xth_me_image_insert {%f 1 1.0} {%f %s} "%s" 0 {}' % \
						(paramsTrans[0], paramsTrans[1], XVIroot, href))

		self.print_scrap_begin('scrap1', not self.options.lay2scr)

		if self.options.layers == 'current':
			layer = self.current_layer
			while layer.get(inkscape_groupmode, '') != "layer" and layer.getparent():
				layer = layer.getparent()
			self.output_scrap(layer)
		else:
			layers = self.document.xpath('/svg:svg/svg:g[@inkscape:groupmode="layer"]', namespaces=inkex.NSS)
			if len(layers) == 0:
				inkex.errormsg("Document has no layers!\nFallback to single scrap")
				layers = [ root ]
			for layer in layers:
				if layer.get(therion_role) == 'none':
					continue
				if self.options.layers == 'visible':
					style = self.get_style(layer)
					if style.get('display') == 'none':
						continue
				self.output_scrap(layer)

		self.print_scrap_end(not self.options.lay2scr)
示例#35
0
 def set_transform(self, elem, matrix):
     """ Sets this element's transform value to the given matrix """
     elem.attrib['transform'] = simpletransform.formatTransform(matrix)
示例#36
0
    def compute_bbox(self, node, transform=True, use_cache=False):
        '''
		Compute the bounding box of a element in its parent coordinate system,
		or in its own coordinate system if "transform" is False.

		Uses a cache to not compute the bounding box multiple times for
		elements like referenced symbols.

		Returns [xmin, xmax, ymin, ymax]

		Enhanced version of simpletransform.computeBBox()

		Warning: Evaluates "transform" attribute for symbol tags, which is
		wrong according to SVG spec, but matches Inkscape's behaviour.
		'''
        import cubicsuperpath
        from simpletransform import boxunion, parseTransform, applyTransformToPath, formatTransform
        try:
            from simpletransform import refinedBBox
        except:
            from simpletransform import roughBBox as refinedBBox

        d = None
        recurse = False
        node_bbox = None

        if transform:
            transform = node.get('transform', '')
        else:
            transform = ''

        if use_cache and node in self.bbox_cache:
            node_bbox = self.bbox_cache[node]
        elif node.tag in [svg_use, 'use']:
            x, y = float(node.get('x', 0)), float(node.get('y', 0))
            refid = node.get(xlink_href)
            refnode = self.getElementById(refid[1:])

            if refnode is None:
                return None

            if 'width' in node.attrib and 'height' in node.attrib and 'viewBox' in refnode.attrib:
                mat = parseViewBox(refnode.get('viewBox'), node.get('width'),
                                   node.get('height'))
                transform += ' ' + formatTransform(mat)

            refbbox = self.compute_bbox(refnode, True, True)
            if refbbox is not None:
                node_bbox = [
                    refbbox[0] + x, refbbox[1] + x, refbbox[2] + y,
                    refbbox[3] + y
                ]

        elif node.get('d'):
            d = node.get('d')
        elif node.get('points'):
            d = 'M' + node.get('points')
        elif node.tag in [svg_rect, 'rect', svg_image, 'image']:
            d = 'M' + node.get('x', '0') + ',' + node.get('y', '0') + \
             'h' + node.get('width') + 'v' + node.get('height') + \
             'h-' + node.get('width')
        elif node.tag in [svg_line, 'line']:
            d = 'M' + node.get('x1') + ',' + node.get('y1') + \
             ' ' + node.get('x2') + ',' + node.get('y2')
        elif node.tag in [svg_circle, 'circle', svg_ellipse, 'ellipse']:
            rx = node.get('r')
            if rx is not None:
                ry = rx
            else:
                rx = node.get('rx')
                ry = node.get('ry')
            rx, ry = float(rx), float(ry)
            cx = float(node.get('cx', '0'))
            cy = float(node.get('cy', '0'))
            node_bbox = [cx - rx, cx + rx, cy - ry, cy + ry]
            '''
			a = 0.555
			d = 'M %f %f C' % (cx-rx, cy) + ' '.join('%f' % c for c in [
				cx-rx,   cy-ry*a, cx-rx*a, cy-ry,   cx,    cy-ry,
				cx+rx*a, cy-ry,   cx+rx,   cy-ry*a, cx+rx, cy,
				cx+rx,   cy+ry*a, cx+rx*a, cy+ry,   cx,    cy+ry,
				cx-rx*a, cy+ry,   cx-rx,   cy+ry*a, cx-rx, cy,
				])
			'''
        elif node.tag in [svg_text, 'text', svg_tspan, 'tspan']:
            # very rough estimate of text bounding box
            x = node.get('x', '0').split()
            y = node.get('y', '0').split()
            if len(x) == 1 and len(y) > 1:
                x = x * len(y)
            elif len(y) == 1 and len(x) > 1:
                y = y * len(x)
            d = 'M' + ' '.join('%f' % self.unittouu(c) for xy in zip(x, y)
                               for c in xy)
            recurse = True
        elif node.tag in [svg_g, 'g', svg_symbol, 'symbol', svg_svg, 'svg']:
            recurse = True

        if d is not None:
            p = cubicsuperpath.parsePath(d)
            node_bbox = refinedBBox(p)

        if recurse:
            for child in node:
                child_bbox = self.compute_bbox(child, True, use_cache)
                node_bbox = boxunion(child_bbox, node_bbox)

        self.bbox_cache[node] = node_bbox

        if transform.strip() != '' and node_bbox != None:
            mat = parseTransform(transform)
            p = [[[[node_bbox[0], node_bbox[2]], [node_bbox[0], node_bbox[3]],
                   [node_bbox[1], node_bbox[2]], [node_bbox[1],
                                                  node_bbox[3]]]]]
            applyTransformToPath(mat, p)
            x, y = zip(*p[0][0])
            node_bbox = [min(x), max(x), min(y), max(y)]

        return node_bbox
示例#37
0
def propagate_attribs(node, parent_style={}, parent_transform=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
    """Propagate style and transform to remove inheritance"""

    # Don't enter non-graphical portions of the document
    if (node.tag == addNS("namedview", "sodipodi")
        or node.tag == addNS("defs", "svg")
        or node.tag == addNS("metadata", "svg")
        or node.tag == addNS("foreignObject", "svg")):
        return


    # Compose the transformations
    if node.tag == addNS("svg", "svg") and node.get("viewBox"):
        vx, vy, vw, vh = [get_dimension(x) for x in node.get("viewBox").split()]
        dw = get_dimension(node.get("width", vw))
        dh = get_dimension(node.get("height", vh))
        t = "translate(%f, %f) scale(%f, %f)" % (-vx, -vy, dw/vw, dh/vh)
        this_transform = simpletransform.parseTransform(t, parent_transform)
        this_transform = simpletransform.parseTransform(node.get("transform"), this_transform)
        del node.attrib["viewBox"]
    else:
        this_transform = simpletransform.parseTransform(node.get("transform"), parent_transform)

    # Compose the style attribs
    this_style = simplestyle.parseStyle(node.get("style", ""))
    remaining_style = {} # Style attributes that are not propagated

    non_propagated = ["filter"] # Filters should remain on the topmost ancestor
    for key in non_propagated:
        if key in this_style.keys():
            remaining_style[key] = this_style[key]
            del this_style[key]

    # Create a copy of the parent style, and merge this style into it
    parent_style_copy = parent_style.copy()
    parent_style_copy.update(this_style)
    this_style = parent_style_copy

    # Merge in any attributes outside of the style
    style_attribs = ["fill", "stroke"]
    for attrib in style_attribs:
        if node.get(attrib):
            this_style[attrib] = node.get(attrib)
            del node.attrib[attrib]

    if (node.tag == addNS("svg", "svg")
        or node.tag == addNS("g", "svg")
        or node.tag == addNS("a", "svg")
        or node.tag == addNS("switch", "svg")):
        # Leave only non-propagating style attributes
        if len(remaining_style) == 0:
            if "style" in node.keys():
                del node.attrib["style"]
        else:
            node.set("style", simplestyle.formatStyle(remaining_style))

        # Remove the transform attribute
        if "transform" in node.keys():
            del node.attrib["transform"]

        # Continue propagating on subelements
        for c in node.iterchildren():
            propagate_attribs(c, this_style, this_transform)
    else:
        # This element is not a container

        # Merge remaining_style into this_style
        this_style.update(remaining_style)

        # Set the element's style and transform attribs
        node.set("style", simplestyle.formatStyle(this_style))
        node.set("transform", simpletransform.formatTransform(this_transform))
示例#38
0
    def copy_frame(self, basename,status, newbasename,newstatus):
        current = self.getElementById(basename+'-'+status+'-top')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-top')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)

        current = self.getElementById(basename+'-'+status+'-bottom')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-bottom')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)

        current = self.getElementById(basename+'-'+status+'-left')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-left')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)

        current = self.getElementById(basename+'-'+status+'-right')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-right')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)

        current = self.getElementById(basename+'-'+status+'-topleft')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-topleft')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)

        current = self.getElementById(basename+'-'+status+'-topright')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-topright')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)

        current = self.getElementById(basename+'-'+status+'-bottomleft')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-bottomleft')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)

        current = self.getElementById(basename+'-'+status+'-bottomright')
        if current != None:
            new = copy.deepcopy(current)
            new.set('id', newbasename+'-'+newstatus+'-bottomright')
            if new.attrib.has_key('transform'):
                mat = simpletransform.parseTransform(new.get('transform'))
                mat[1][2] = mat[1][2]-30
            else:
                mat = [[1,0,0],[0,1,-30]]
            new.set('transform', simpletransform.formatTransform(mat))
            current.getparent().append(new)