Пример #1
0
    def test_single_point_transform(self):
        from math import sqrt, sin, cos
        self.assertAlmostTuple(list(Path("M 10 10 30 20").control_points),
                               ((10, 10), (30, 20)))
        self.assertAlmostTuple(
            list(
                Path("M 10 10 30 20").transform(
                    Transform(translate=(10, 7))).control_points),
            ((20, 17), (40, 27)))
        self.assertAlmostTuple(
            list(
                Path("M 20 20 5 0 0 7 ").transform(
                    Transform(scale=10)).control_points),
            ((200, 200), (50, 0), (0, 70)))

        self.assertAlmostTuple(
            list(
                Path("M 20 20 1 0").transform(
                    Transform(rotate=90)).control_points), ((-20, 20), (0, 1)))

        self.assertAlmostTuple(
            list(
                Path("M 20 20 1 0").transform(
                    Transform(rotate=45)).control_points),
            ((0, sqrt(20**2 + 20**2)), (sqrt(2) / 2, sqrt(2) / 2)))

        self.assertAlmostTuple(
            list(
                Path("M 1 0 0 1").transform(
                    Transform(rotate=30)).control_points),
            ((sqrt(3) / 2, 0.5), (-0.5, sqrt(3) / 2)))
Пример #2
0
 def test_interpolate(self):
     """Test interpolate with other transform"""
     t1 = Transform((0, 0, 0, 0, 0, 0))
     t2 = Transform((1, 1, 1, 1, 1, 1))
     val = t1.interpolate(t2, 0.5)
     assert all(
         getattr(val, a) == pytest.approx(0.5, 1e-3) for a in 'abcdef')
Пример #3
0
 def test_scale(self):
     """In-place scaling from blank transform"""
     elem = self.svg.getElementById('F')
     self.assertEqual(elem.transform, Transform())
     self.assertEqual(elem.get('transform'), None)
     elem.transform.add_scale(1.0666666666666667, 1.0666666666666667)
     self.assertEqual(elem.get('transform'), Transform(scale=1.06667))
     self.assertIn(b'transform', etree.tostring(elem))
Пример #4
0
    def exportDrill(self, kicad_mod=False):
        self.setInkscapeScaling()

        kicad_drill_string = ""

        i = 0

        if kicad_mod:
            pad_template = "(pad {n} thru_hole circle (at {x} {y}) (size {d} {d}) (drill {d}) (layers *.Cu *.Mask))\n"
        else:
            pad_template = """
                (module Wire_Pads:SolderWirePad_single_0-8mmDrill (layer F.Cu) (tedit 0) (tstamp 5ABD66D0)
                    (at {x} {y})
                    (pad {n} thru_hole circle (at 0 0) (size {d} {d}) (drill {d}) (layers *.Cu *.Mask))
                )
            """

        layerPath = '//svg:g[@inkscape:groupmode="layer"][@inkscape:label="Drill"]'

        for layer in self.document.getroot().xpath(layerPath,
                                                   namespaces=inkex.NSS):

            layer_trans = layer.get('transform')
            if layer_trans:
                layer_m = Transform(layer_trans).matrix
            else:
                layer_m = IDENTITY_MATRIX

            nodePath = 'descendant::svg:circle'

            count = 0
            for node in layer.xpath(nodePath, namespaces=inkex.NSS):
                count = count + 1
                cx = float(node.get('cx'))
                cy = float(node.get('cy'))

                radius = float(node.get('r'))
                drill_size = radius * 2

                t = node.get('transform')

                if t:
                    m = Transform(t).matrix
                    trans = (Transform(layer_m) * Transform(m)).matrix
                else:
                    trans = layer_m

                pt = Transform(trans).apply_to_point([cx, cy])
                padCoord = self.coordToKicad(pt)

                kicad_drill_string += pad_template.format(x=padCoord[0],
                                                          y=padCoord[1],
                                                          n=count,
                                                          d=drill_size)

        return kicad_drill_string
Пример #5
0
    def test_pop_wrapped_attribute(self):
        """Remove wrapped attribute using .pop()"""
        group = Group()

        self.assertEqual(group.pop('transform'), Transform())

        group.update(
            transform=Transform(scale=2)
        )
        self.assertEqual(group.pop('transform'), Transform(scale=2))
        self.assertEqual(group.pop('transform'), Transform())
        self.assertRaises(AttributeError, getattr, group, 'foo')
Пример #6
0
 def test_update_consistant(self):
     """Update doesn't keep callbacks around"""
     elem = self.svg.getElementById('D')
     tr_a = Transform(translate=(10, 10))
     tr_b = Transform(translate=(-20, 15))
     elem.transform = tr_a
     elem.transform = tr_b
     self.assertEqual(str(elem.transform), 'translate(-20, 15)')
     tr_a.add_translate(10, 10)
     self.assertEqual(str(elem.transform), 'translate(-20, 15)')
     elem.set('transform', None)
     self.assertEqual(elem.get('transform'), None)
Пример #7
0
    def test_inline_transformations(self):
        path = Path()
        self.assertTrue(path is not path.translate(10, 20))
        self.assertTrue(path is not path.transform(Transform(scale=10)))
        self.assertTrue(path is not path.rotate(10))
        self.assertTrue(path is not path.scale(10, 20))

        self.assertTrue(path is path.translate(10, 20, inplace=True))
        self.assertTrue(
            path is path.transform(Transform(scale=10), inplace=True))
        self.assertTrue(path is path.rotate(10, inplace=True))
        self.assertTrue(path is path.scale(10, 20, inplace=True))
Пример #8
0
    def test_set_wrapped_attribute(self):
        """Remove wrapped attribute using .set()"""
        group = Group().update(
            transform=Transform(scale=2)
        )
        self.assertEqual(group.transform.matrix[0][0], 2)
        self.assertEqual(group.transform.matrix[1][1], 2)

        group.update(
            transform=None
        )
        self.assertEqual(group.transform, Transform())
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = Transform(transf) * Transform(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(d)
            p = Path(p).to_absolute().transform(transf, True)
            node.set('d', Path(CubicSuperPath(p).to_path()))

            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', str(Transform(transf)))
            inkex.utils.errormsg("Shape %s not yet supported" % node.tag)

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

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
Пример #10
0
 def test_in_place_transforms(self):
     """Do style and transforms update correctly"""
     elem = self.svg.getElementById('D')
     self.assertEqual(type(elem.transform), Transform)
     self.assertEqual(type(elem.style), Style)
     self.assertTrue(elem.transform)
     elem.transform = Transform()
     self.assertEqual(elem.transform, Transform())
     self.assertEqual(elem.get('transform'), None)
     self.assertNotIn(b'transform', etree.tostring(elem))
     elem.transform.add_translate(10, 10)
     self.assertIn(b'transform', etree.tostring(elem))
     elem.transform.add_translate(-10, -10)
     self.assertNotIn(b'transform', etree.tostring(elem))
Пример #11
0
 def getGlobalTransform(self, node):
     parent = node.getparent()
     myTrans = Transform(node.get('transform')).matrix
     if myTrans:
         if parent is not None:
             parentTrans = self.getGlobalTransform(parent)
             if parentTrans:
                 return Transform(parentTrans) * Transform(myTrans)
             else:
                 return myTrans
     else:
         if parent is not None:
             return self.getGlobalTransform(parent)
         else:
             return None
Пример #12
0
 def test_arc_transformation(self):
     cases = [
         ("M 10 10 A 100 100 0 1 0 100 100 Z", ((1, 0, 1), (0, 1, 0)),
          "M 11 10 A 100 100 0 1 0 101 100 Z"),
         ("M 10 10 A 100 100 0 1 0 100 100 Z", ((1, 0, 0), (0, 1, 1)),
          "M 10 11 A 100 100 0 1 0 100 101 Z"),
         ("M 10 10 A 100 100 0 1 0 100 100 Z", ((1, 0, 1), (0, 1, 1)),
          "M 11 11 A 100 100 0 1 0 101 101 Z"),
         ("M 10 10 A 100 100 0 1 0 100 100 Z", ((2, 0, 0), (0, 1, 0)),
          "M 20 10 A 200 100 0 1 0 200 100 Z"),
         ("M 10 10 A 100 100 0 1 0 100 100 Z", ((1, 0, 0), (0, 2, 0)),
          "M 10 20 A 200 100 90 1 0 100 200 Z"),
         ("M 10 10 A 100 100 0 1 0 100 100 Z", ((1, 0, 0), (0, -1, 0)),
          "M 10 -10 A 100 100 0 1 1 100 -100 Z"),
         ("M 10 10 A 100 100 0 1 0 100 100 Z", ((1, 2, 0), (0, 2, 0)),
          "M 30 20 "
          "A 292.081 68.4742 41.4375 1 0 300 200 Z"),
         ("M 10 10 "
          "A 100 100 0 1 0 100 100 "
          "A 300 200 0 1 0 50 20 Z", ((1, 2, 0), (5, 6, 0)), "M 30,110 "
          "A 810.90492,49.327608 74.368134 1 1 "
          "300,1100 1981.2436,121.13604 75.800007 1 1 90,370 Z"),
     ]
     for path, transform, expected in cases:
         expected = Path(expected)
         result = Path(path).transform(Transform(matrix=transform))
         self.assertDeepAlmostEqual(expected.to_arrays(),
                                    result.to_arrays(),
                                    places=4)
Пример #13
0
def applyTransformToPoint(mat, pt):
    """Transform(mat).apply_to_point(pt)"""
    pt2 = Transform(mat).apply_to_point(pt)
    # Apply in place as original method was modifying arrays in place.
    # but don't do this in your code! This is not good code design.
    pt[0] = pt2[0]
    pt[1] = pt2[1]
Пример #14
0
        def _expand_defs(root):
            from inkex.transforms import Transform
            from inkex.elements import ShapeElement
            from copy import deepcopy
            for el in root:
                if isinstance(el, inkex.elements.Use):
                    # <group> element will replace <use> node
                    group = inkex.elements.Group()

                    # add all objects from symbol node
                    for obj in el.href:
                        group.append(deepcopy(obj))

                    # translate group
                    group.transform = Transform(
                        translate=(float(el.attrib["x"]),
                                   float(el.attrib["y"])))

                    # replace use node with group node
                    parent = el.getparent()
                    parent.remove(el)
                    parent.add(group)

                    el = group  # required for recursive defs

                # expand children defs
                TexTextElement._expand_defs(el)
Пример #15
0
 def test_transform(self):
     """Transform by a whole matrix"""
     ret = Path("M 100 100 L 110 120 L 140 140 L 300 300")
     ret = ret.transform(Transform(translate=(10, 10)))
     self.assertEqual(str(ret), 'M 110 110 L 120 130 L 150 150 L 310 310')
     ret = ret.transform(Transform(translate=(-10, -10)))
     self.assertEqual(str(ret), 'M 100 100 L 110 120 L 140 140 L 300 300')
     ret = Path('M 5 5 H 10 V 15')
     ret = ret.transform(Transform(rotate=-10))
     self.assertEqual(
         'M 5.79228 4.0558 '
         'L 10.7163 3.18756 '
         'L 12.4528 13.0356', str(ret))
     ret = Path("M 10 10 A 50,50 0 0 1 85.355333,85.355341 L 100 0")
     ret = ret.transform(Transform(scale=10))
     self.assertEqual(str(ret),
                      'M 100 100 A 500 500 0 0 1 853.553 853.553 L 1000 0')
     self.assertRaises(ValueError, Horz([10]).transform, Transform())
Пример #16
0
    def test_transformation_preserve_type(self):
        import re
        paths = [
            "M 10 10 A 100 100 0 1 0 100 100 C 10 15 20 20 5 5 Z",
            "m 10 10 a 100 100 0 1 0 100 100 c 10 15 20 20 5 5 z",
            "m 10 10 l 100 200 L 20 30 C 10 20 30 40 11 12",
            "M 10 10 Q 12 13 14 15 T 11 32 T 32 11",
            "m 10 10 q 12 13 14 15 t 11 32 t 32 11",
        ]
        t = Transform(matrix=((1, 2, 3), (4, 5, 6)))
        for path_str in paths:
            path = Path(path_str)
            new_path = path.transform(t)
            cmds = "".join([cmd.letter for cmd in new_path])
            expected = re.sub(r"\d|\s|,", "", path_str)

            self.assertEqual(expected, cmds)
            self.assertAlmostTuple(
                [t.apply_to_point(p) for p in path.control_points],
                list(new_path.control_points))
Пример #17
0
    def exportDrillLayer(self, layerPath, pad_template):

        kicad_drill_string = ""

        for layer in self.document.getroot().xpath(layerPath,
                                                   namespaces=inkex.NSS):

            layer_trans = layer.get('transform')
            if layer_trans:
                layer_m = Transform(layer_trans).matrix
            else:
                layer_m = IDENTITY_MATRIX

            nodePath = 'descendant::svg:circle'

            count = 0
            for node in layer.xpath(nodePath, namespaces=inkex.NSS):
                count = count + 1
                cx = float(node.get('cx'))
                cy = float(node.get('cy'))

                radius = float(node.get('r'))
                drill_size = radius * 2

                t = node.get('transform')

                if t:
                    m = Transform(t).matrix
                    trans = (Transform(layer_m) * Transform(m)).matrix
                else:
                    trans = layer_m

                pt = Transform(trans).apply_to_point([cx, cy])
                padCoord = self.coordToKicad(pt)

                kicad_drill_string += pad_template.format(x=padCoord[0],
                                                          y=padCoord[1],
                                                          n=count,
                                                          d=drill_size)

        return kicad_drill_string
Пример #18
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 (TexTextElement) ref_node: Reference node subclassed from SvgElement to which self is going to be aligned
            :param (str) alignment: A 2-element string list defining the alignment
            :param (float) relative_scale: Scaling of the new node relative to the scale of the reference node
            """
            from inkex.transforms import Transform
            scale_transform = Transform("scale(%f)" % relative_scale)

            old_transform = Transform(ref_node.transform)

            # Account for vertical flipping of pstoedit nodes when recompiled via pdf2svg and vice versa
            revert_flip = Transform("scale(1)")
            if ref_node.get_meta("pdfconverter") == "pdf2svg":
                revert_flip = Transform(matrix=((1, 0, 0),
                                                (0, -1,
                                                 0)))  # vertical reflection

            composition = old_transform * revert_flip

            composition = scale_transform * composition

            # keep alignment point of drawing intact, calculate required shift
            self.transform = composition

            ref_bb = ref_node.bounding_box()
            x, y, w, h = ref_bb.left, ref_bb.top, ref_bb.width, ref_bb.height
            bb = self.bounding_box()
            new_x, new_y, new_w, new_h = bb.left, bb.top, bb.width, bb.height

            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 = Transform(translate=(dx, dy)) * composition

            self.transform = composition
            self.set_meta("jacobian_sqrt", str(self.get_jacobian_sqrt()))
Пример #19
0
 def test_add_transform(self):
     """Test add_TRANSFORM syntax for quickly composing known transforms"""
     tr1 = Transform()
     tr1.add_scale(5.0, 1.0)
     self.assertEqual(str(tr1), 'scale(5, 1)')
     tr1.add_translate(10, 10)
     self.assertEqual(str(tr1), 'matrix(5 0 0 1 50 10)')
Пример #20
0
    def test_rotation_degrees(self):
        """Test parsing and composition of different rotations"""
        self.assertAlmostEqual(Transform(rotate=30).rotation_degrees(), 30)
        self.assertAlmostEqual(
            Transform(translate=(10, 20)).rotation_degrees(), 0)
        self.assertAlmostEqual(Transform(scale=(1, 1)).rotation_degrees(), 0)

        self.assertAlmostEqual(
            Transform(rotate=35, translate=(10, 20)).rotation_degrees(), 35)
        self.assertAlmostEqual(
            Transform(rotate=35, translate=(10, 20),
                      scale=5).rotation_degrees(), 35)
        self.assertAlmostEqual(
            Transform(rotate=35, translate=(10, 20),
                      scale=(5, 5)).rotation_degrees(), 35)

        def rotation_degrees(**kwargs):
            return Transform(**kwargs).rotation_degrees()

        self.assertRaises(ValueError, rotation_degrees, rotate=35, skewx=1)
        self.assertRaises(ValueError, rotation_degrees, rotate=35, skewy=1)
        self.assertRaises(ValueError,
                          rotation_degrees,
                          rotate=35,
                          scale=(10, 11))
        self.assertRaises(ValueError,
                          rotation_degrees,
                          rotate=35,
                          scale=(10, 11))
Пример #21
0
    def test_construction_order(self):
        """Test transform kwargs construction order"""
        if not PY3:
            self.skipTest(
                "Construction order is known to fail on python2 (by design).")
            return

        self.assertEqual(str(Transform(scale=2.0, translate=(5, 6))),
                         'matrix(2 0 0 2 5 6)')
        self.assertEqual(str(Transform(scale=2.0, rotate=45)),
                         'matrix(1.41421 1.41421 -1.41421 1.41421 0 0)')

        x, y, angle = 5, 7, 31
        rotation = Transform(rotate=angle)
        translation = Transform(translate=(x, y))

        rotation_then_translation = translation * rotation
        translation_then_rotation = rotation * translation

        tr1 = Transform(rotate=angle, translate=(x, y))
        tr2 = Transform(translate=(x, y), rotate=angle)

        self.assertNotEqual(tr1, tr2)
        self.assertDeepAlmostEqual(tr1.matrix,
                                   rotation_then_translation.matrix)
        self.assertDeepAlmostEqual(tr2.matrix,
                                   translation_then_rotation.matrix)
Пример #22
0
    def fill_row(self, node):
        #max_line_width = self.svg.unittouu('450mm')
        #x_start = self.svg.unittouu('3mm')
        #y_start = self.svg.unittouu('1600mm') - self.svg.unittouu('3mm')
        #gap_x = gap_y = self.svg.unittouu('10mm')

        svg = self.document.getroot()
        x_start = 0
        y_start = self.svg.unittouu(svg.attrib['height'])
        max_line_width = self.svg.unittouu(svg.get('width'))

        total_width = 0
        total_height = self.total_height

        group = etree.SubElement(self.svg.get_current_layer(),
                                 addNS('g', 'svg'))

        bbox = node.bounding_box()
        x = bbox.left
        y = bbox.top
        node_width = self.options.gap_x + bbox.width

        while total_width + node_width < max_line_width:
            node_copy = deepcopy(node)
            group.append(node_copy)

            x_dest = x_start + total_width
            y_dest = y_start - (total_height + bbox.height)

            # translation logic
            if node_copy.tag == addNS('path', 'svg'):
                x_delta = x_dest - x
                y_delta = y_dest - y

                path = Path(node_copy.attrib['d'])
                path.translate(x_delta, y_delta, True)
                node_copy.attrib['d'] = str(Path(path))
            elif node_copy.tag == addNS('g', 'svg'):
                x_delta = x_dest - x
                y_delta = y_dest - y

                translation_matrix = [[1.0, 0.0, x_delta], [0.0, 1.0, y_delta]]
                Transform(translation_matrix) * node_copy.transform
            else:
                node_copy.attrib['x'] = str(x_dest)
                node_copy.attrib['y'] = str(y_dest)

            total_width += node_width

        self.total_height += group.bounding_box().height + self.options.gap_y
    def drawLabel(self, group, angle, segment_angle, outer_diameter, labelNum):
        outer_radius = outer_diameter / 2
        label_angle = angle + (segment_angle / 2)
        point = calculatePoint(label_angle, outer_radius)
        matrix = Transform('rotate(' + str(label_angle + 90) + ')').matrix
        matrix_str = str(matrix[0][0]) + "," + str(matrix[0][1])
        matrix_str += "," + str(matrix[1][0]) + "," + str(matrix[1][1]) + ",0,0"
        text = {
            'id': 'text' + str(labelNum),
            #'sodipodi:linespacing': '0%',
            'style': 'font-size: 6px;font-style: normal;font-family: Sans',
            #'transform': 'matrix(' + matrix_str + ')',
            'x': str(point[0]),
            'y': str(point[1]),
            #'xml:space': 'preserve'
            }
        textElement = etree.SubElement(group, inkex.addNS('text', 'svg'), text)
        #tspanElement = etree.Element(
        #    textElement, '{%s}%s' % (svg_uri, 'tspan'), tspan)
        textElement.text = string.printable[labelNum % len(string.printable)]

        self.svg.get_current_layer().append(textElement)
    def effect(self):

        opt = self.options

        if not opt.placeholderid:
            raise inkex.AbortExtension('Please enter the placeholder ID')
        elif not opt.qrcodeid:
            raise inkex.AbortExtension('Please enter the QRCode ID')

        placeholder = self.svg.getElementById(opt.placeholderid)
        qrcode = self.svg.getElementById(opt.qrcodeid)

        if placeholder is None or qrcode is None:
            # Delete the generated qrcode
            qrcode.getparent().remove(qrcode)
            return

        # Reset scale before processing
        qrcode.set('transform', 'scale(1,1)')

        # Get scaling factors
        scalex = placeholder.bounding_box().width  / qrcode.bounding_box().width
        scaley = placeholder.bounding_box().height / qrcode.bounding_box().height

        # Apply scaling and translating
        tr = Transform()
        tr.add_translate(placeholder.bounding_box().left, placeholder.bounding_box().top)
        qrcode.set('transform', tr)
        tr.add_scale(scalex, scaley)
        qrcode.set('transform', tr)

        # Move qrcode inplace of the placeholder
        placeholder.getparent().append(qrcode)

        # Delete the placeholder
        placeholder.getparent().remove(placeholder)
Пример #25
0
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        # Modification by David Burghoff:
        # Since transforms apply to an object's clips, before applying the transform
        # we will need to duplicate the clip path and transform it
        clippathurl = node.get('clip-path')
        if clippathurl is not None and node.get("transform") is not None:
            myn = node
            while not (myn.getparent() == None):  # get svg handle
                myn = myn.getparent()
            svg = myn
            clippath = svg.getElementById(clippathurl[5:-1])
            if clippath is not None:
                d = clippath.duplicate()
                clippathurl = "url(#" + d.get("id") + ")"
                node.set("clip-path", clippathurl)
                for k in d.getchildren():
                    if k.get('transform') is not None:
                        tr = Transform(node.get("transform")) * Transform(
                            k.get('transform'))
                    else:
                        tr = Transform(node.get("transform"))
                    k.set('transform', tr)

        transf = Transform(transf) * Transform(node.get("transform", None))

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

        node = ApplyTransform.objectToPath(node)

        if transf == NULL_TRANSFORM:
            # Don't do anything if there is effectively no transform applied
            # reduces alerts for unsupported nodes
            pass
        elif 'd' in node.attrib:
            d = node.get('d')
            p = CubicSuperPath(d)
            p = Path(p).to_absolute().transform(transf, True)
            node.set('d', str(Path(CubicSuperPath(p).to_path())))

            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])]
                    p = transf.apply_to_point(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("ellipse", "svg"),
                inkex.addNS("circle", "svg")
        ]:

            def isequal(a, b):
                return abs(a - b) <= transf.absolute_tolerance

            if node.TAG == "ellipse":
                rx = float(node.get("rx"))
                ry = float(node.get("ry"))
            else:
                rx = float(node.get("r"))
                ry = rx

            cx = float(node.get("cx"))
            cy = float(node.get("cy"))
            sqxy1 = (cx - rx, cy - ry)
            sqxy2 = (cx + rx, cy - ry)
            sqxy3 = (cx + rx, cy + ry)
            newxy1 = transf.apply_to_point(sqxy1)
            newxy2 = transf.apply_to_point(sqxy2)
            newxy3 = transf.apply_to_point(sqxy3)

            node.set("cx", (newxy1[0] + newxy3[0]) / 2)
            node.set("cy", (newxy1[1] + newxy3[1]) / 2)
            edgex = math.sqrt(
                abs(newxy1[0] - newxy2[0])**2 + abs(newxy1[1] - newxy2[1])**2)
            edgey = math.sqrt(
                abs(newxy2[0] - newxy3[0])**2 + abs(newxy2[1] - newxy3[1])**2)

            if not isequal(edgex, edgey) and (
                    node.TAG == "circle" or not isequal(newxy2[0], newxy3[0])
                    or not isequal(newxy1[1], newxy2[1])):
                inkex.utils.errormsg(
                    "Warning: Shape %s (%s) is approximate only, try Object to path first for better results"
                    % (node.TAG, node.get("id")))

            if node.TAG == "ellipse":
                node.set("rx", edgex / 2)
                node.set("ry", edgey / 2)
            else:
                node.set("r", edgex / 2)

        # Modficiation by David Burghoff: Added support for lines
        elif node.tag in inkex.addNS('line', 'svg'):
            x1 = node.get('x1')
            x2 = node.get('x2')
            y1 = node.get('y1')
            y2 = node.get('y2')
            p1 = transf.apply_to_point([x1, y1])
            p2 = transf.apply_to_point([x2, y2])
            node.set('x1', str(p1[0]))
            node.set('y1', str(p1[1]))
            node.set('x2', str(p2[0]))
            node.set('y2', str(p2[1]))
            self.scaleStrokeWidth(node, transf)

        elif node.typename in ['Rectangle']:
            x = float(node.get('x'))
            y = float(node.get('y'))
            w = float(node.get('width'))
            h = float(node.get('height'))
            pts = [[x, y], [x + w, y], [x + w, y + h], [x, y + h], [x, y]]
            xs = []
            ys = []
            for p in pts:
                p = transf.apply_to_point(p)
                xs.append(p.x)
                ys.append(p.y)

            node.set('x', str(min(xs)))
            node.set('y', str(min(ys)))
            node.set('width', str(max(xs) - min(xs)))
            node.set('height', str(max(ys) - min(ys)))
            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('text', 'svg'),
                inkex.addNS('image', 'svg'),
                inkex.addNS('use', 'svg')
        ]:
            inkex.utils.errormsg(
                "Shape %s (%s) not yet supported, try Object to path first" %
                (node.TAG, node.get("id")))

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

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
Пример #26
0
#!/usr/bin/env python3
#
# License: GPL2
# Copyright Mark "Klowner" Riedesel
# https://github.com/Klowner/inkscape-applytransforms
# Modified by David Burghoff

import inkex
import math
from inkex.paths import CubicSuperPath, Path
from inkex.transforms import Transform
from inkex.styles import Style

NULL_TRANSFORM = Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
from lxml import etree


class ApplyTransform(inkex.EffectExtension):
    def __init__(self):
        super(ApplyTransform, self).__init__()

    def effect(self):
        if self.svg.selected:
            for (_, shape) in self.svg.selected.items():
                self.recursiveFuseTransform(shape)
        else:
            self.recursiveFuseTransform(self.document.getroot())

    @staticmethod
    def objectToPath(node):
        if node.tag == inkex.addNS('g', 'svg'):
Пример #27
0
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):

        transf = Transform(transf) * Transform(node.get("transform", None))

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

        node = ApplyTransform.objectToPath(node)

        if transf == NULL_TRANSFORM:
            # Don't do anything if there is effectively no transform applied
            # reduces alerts for unsupported nodes
            pass
        elif 'd' in node.attrib:
            d = node.get('d')
            p = CubicSuperPath(d)
            p = Path(p).to_absolute().transform(transf, True)
            node.set('d', Path(CubicSuperPath(p).to_path()))

            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])]
                    p = transf.apply_to_point(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("ellipse", "svg"),
                inkex.addNS("circle", "svg")
        ]:

            def isequal(a, b):
                return abs(a - b) <= transf.absolute_tolerance

            if node.TAG == "ellipse":
                rx = float(node.get("rx"))
                ry = float(node.get("ry"))
            else:
                rx = float(node.get("r"))
                ry = rx

            cx = float(node.get("cx"))
            cy = float(node.get("cy"))
            sqxy1 = (cx - rx, cy - ry)
            sqxy2 = (cx + rx, cy - ry)
            sqxy3 = (cx + rx, cy + ry)
            newxy1 = transf.apply_to_point(sqxy1)
            newxy2 = transf.apply_to_point(sqxy2)
            newxy3 = transf.apply_to_point(sqxy3)

            node.set("cx", (newxy1[0] + newxy3[0]) / 2)
            node.set("cy", (newxy1[1] + newxy3[1]) / 2)
            edgex = math.sqrt(
                abs(newxy1[0] - newxy2[0])**2 + abs(newxy1[1] - newxy2[1])**2)
            edgey = math.sqrt(
                abs(newxy2[0] - newxy3[0])**2 + abs(newxy2[1] - newxy3[1])**2)

            if not isequal(edgex, edgey) and (
                    node.TAG == "circle" or not isequal(newxy2[0], newxy3[0])
                    or not isequal(newxy1[1], newxy2[1])):
                inkex.utils.errormsg(
                    "Warning: Shape %s (%s) is approximate only, try Object to path first for better results"
                    % (node.TAG, node.get("id")))

            if node.TAG == "ellipse":
                node.set("rx", edgex / 2)
                node.set("ry", edgey / 2)
            else:
                node.set("r", edgex / 2)

        elif node.tag in [
                inkex.addNS('rect', 'svg'),
                inkex.addNS('text', 'svg'),
                inkex.addNS('image', 'svg'),
                inkex.addNS('use', 'svg')
        ]:
            inkex.utils.errormsg(
                "Shape %s (%s) not yet supported, try Object to path first" %
                (node.TAG, node.get("id")))

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

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
Пример #28
0
    def recursively_traverse_svg(self, node_list,
                                 trans_current=Transform(((1.0, 0.0, 0.0), (0.0, -1.0, 0.0))),
                                 parent_visibility='visible'):
        """
    Recursively traverse the svg file to plot out all of the
    paths.  The function keeps track of the composite transformation
    that should be applied to each path.

    This function handles path, group, line, rect, polyline, polygon,
    circle, ellipse and use (clone) elements. Notable elements not
    handled include text.  Unhandled elements should be converted to
    paths in Inkscape.

    TODO: There's a lot of inlined code in the eggbot version of this
    that would benefit from the Entities method of dealing with things.
    """
        for node in node_list:
            # Ignore invisible nodes
            v = node.get('visibility', parent_visibility)
            if v == 'inherit':
                v = parent_visibility
            if v == 'hidden' or v == 'collapse':
                pass

            # first apply the current matrix transform to this node's transform

            trans = Transform(node.get("transform"))
            trans_new = trans_current * trans

            if node.tag == inkex.addNS('g', 'svg') or node.tag == 'g':
                if node.get(inkex.addNS('groupmode', 'inkscape')) == 'layer':
                    node.get(inkex.addNS('label', 'inkscape'))

                self.recursively_traverse_svg(node, trans_new, parent_visibility=v)
            elif node.tag == inkex.addNS('use', 'svg') or node.tag == 'use':
                ref_id = node.get(inkex.addNS('href', 'xlink'))
                if ref_id:
                    # [1:] to ignore leading '#' in reference
                    path = '//*[@id="%s"]' % ref_id[1:]
                    ref_node = node.xpath(path)
                    if ref_node:
                        x = float(node.get('x', '0'))
                        y = float(node.get('y', '0'))
                        # Note: the transform has already been applied
                        if (x != 0) or (y != 0):
                            trans_new2 = trans_new * Transform('translate(%f,%f)' % (x, y))
                        else:
                            trans_new2 = trans_new
                        v = node.get('visibility', v)
                        self.recursively_traverse_svg(ref_node, trans_new2, parent_visibility=v)
                    else:
                        pass
                else:
                    pass
            elif not isinstance(node.tag, str):
                pass
            else:
                entity = self.make_entity(node, trans_new)
                if entity is None:
                    inkex.errormsg(
                        'Warning: unable to draw object, please convert it to a path first. objID: ' + node.get('id'))
Пример #29
0
 def parse(self):
     # 0.28222 scale determined by comparing pixels-per-mm in a default Inkscape file.
     # self.svgWidth = self.getLength('width', 354) * 0.28222
     # self.svgHeight = self.getLength('height', 354) * 0.28222
     self.recursively_traverse_svg(self.svg, Transform(((1.0, 0.0, 0), (0.0, -1.0, self.svgHeight))))
Пример #30
0
    def exportEdgeCut(self, kicad_mod=False):
        x0 = 0
        y0 = 0
        mirror = 1.0

        line_type = "fp_line" if kicad_mod else "gr_line"

        kicad_edgecut_string = ""

        i = 0
        layerPath = '//svg:g[@inkscape:groupmode="layer"]'

        if (self.options.autoflatten):
            self.flatten_bezier()

        for layer in self.document.getroot().xpath(layerPath,
                                                   namespaces=inkex.NSS):
            i += 1

            label_attrib_name = "{%s}label" % layer.nsmap['inkscape']
            if label_attrib_name not in layer.attrib:
                continue

            layer_name = (layer.attrib[label_attrib_name])

            if layer_name != "Edge.Cuts":
                continue

            layer_trans = layer.get('transform')
            if layer_trans:
                layer_m = Transform(layer_trans).matrix
            else:
                layer_m = IDENTITY_MATRIX

            nodePath = (
                '//svg:g[@inkscape:groupmode="layer"][%d]/descendant::svg:path'
            ) % i
            for node in self.document.getroot().xpath(nodePath,
                                                      namespaces=inkex.NSS):
                p = node.path.to_arrays()

                points = []
                if p:
                    #sanity check
                    if p[0][0] == 'M':
                        t = node.get('transform')
                        if t:
                            trans = (Transform(layer_m) * Transform(t)).matrix
                        else:
                            trans = layer_m

                        for path in p:
                            if path[0] != "Z":
                                x = (path[1][0])
                                y = (path[1][1])
                                xy = Transform(trans).apply_to_point([x, y])
                                points.append(
                                    self.coordToKicad([(xy[0] - x0),
                                                       xy[1] * mirror - y0]))

                        points_count = len(points)
                        points.append(points[0])

                        for x in range(0, points_count):
                            kicad_edgecut_string = kicad_edgecut_string + (
                                "(%s (start %f %f) (end %f %f) (layer Edge.Cuts) (width 0.1))\n"
                                % (line_type, points[x][0], points[x][1],
                                   points[x + 1][0], points[x + 1][1]))

        return kicad_edgecut_string