Exemple #1
0
 def process_clone(self, node):
     """Process a clone node, looking for internal paths"""
     trans = node.get('transform')
     x = node.get('x')
     y = node.get('y')
     mat = Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
     if trans:
         mat *= Transform(trans)
     if x:
         mat *= Transform([[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]])
     if y:
         mat *= Transform([[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]])
     # push transform
     if trans or x or y:
         self.groupmat.append(Transform(self.groupmat[-1]) * mat)
     # get referenced node
     refid = node.get('xlink:href')
     refnode = self.svg.getElementById(refid[1:])
     if refnode is not None:
         if isinstance(refnode, Group):
             self.process_group(refnode)
         elif isinstance(refnode, Use):
             self.process_clone(refnode)
         else:
             self.process_shape(refnode, self.groupmat[-1])
     # pop transform
     if trans or x or y:
         self.groupmat.pop()
Exemple #2
0
def match(p1, p2, a1, a2):
    x = 0
    y = 1
    # distances
    dp = [p2[x] - p1[x], p2[y] - p1[y]]
    da = [a2[x] - a1[x], a2[y] - a1[y]]
    # angles
    angle_p = math.atan2(dp[x], dp[y])
    angle_a = math.atan2(da[x], da[y])
    # radians
    #rp = math.sqrt( dp[x]*dp[x] + dp[y]*dp[y] )
    #ra = math.sqrt( da[x]*da[x] + da[y]*da[y] )
    rp = math.hypot(dp[x], dp[y])
    ra = math.hypot(da[x], da[y])
    # scale
    scale = ra / rp
    # transforms in the order they are applied
    t1 = Transform("translate(%f,%f)" % (-p1[x], -p1[y])).matrix
    #t2 = Transform( "rotate(%f)"%(-angle_p) ).matrix
    #t3 = Transform( "scale(%f,%f)"%(scale,scale) ).matrix
    #t4 = Transform( "rotate(%f)"%angle_a ).matrix
    t2 = rotateTransform(-angle_p)
    t3 = scale_transform(scale, scale)
    t4 = rotateTransform(angle_a)
    t5 = Transform("translate(%f,%f)" % (a1[x], a1[y])).matrix
    # transforms in the order they are multiplied
    t = t5
    t = Transform(t) * Transform(t4)
    t = Transform(t) * Transform(t3)
    t = Transform(t) * Transform(t2)
    t = Transform(t) * Transform(t1)
    # return the combined transform
    return t
Exemple #3
0
    def process_group(self, group):
        """Process group elements"""
        if isinstance(group, Layer):
            style = group.style
            if style.get(
                    'display', ''
            ) == 'none' and self.options.layer_option and self.options.layer_option == 'visible':
                return
            layer = group.label
            if self.options.layer_name and self.options.layer_option == 'name':
                if not layer.lower() in self.options.layer_name:
                    return

            layer = layer.replace(' ', '_')
            if layer in self.layers:
                self.layer = layer
        trans = group.get('transform')
        if trans:
            self.groupmat.append(
                Transform(self.groupmat[-1]) * Transform(trans))
        for node in group:
            if isinstance(node, Group):
                self.process_group(node)
            elif isinstance(node, Use):
                self.process_clone(node)
            else:
                self.process_shape(node, self.groupmat[-1])
        if trans:
            self.groupmat.pop()
Exemple #4
0
 def process_clone(self, node):
     trans = node.get('transform')
     x = node.get('x')
     y = node.get('y')
     mat = Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
     if trans:
         mat *= Transform(trans)
     if x:
         mat *= Transform([[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]])
     if y:
         mat *= Transform([[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]])
     # push transform
     if trans or x or y:
         self.groupmat.append(Transform(self.groupmat[-1]) * mat)
     # get referenced node
     refnode = node.href
     if refnode is not None:
         if isinstance(refnode, inkex.Group):
             self.process_group(refnode)
         elif refnode.tag == 'svg:use':
             self.process_clone(refnode)
         else:
             self.process_shape(refnode, self.groupmat[-1])
     # pop transform
     if trans or x or y:
         self.groupmat.pop()
Exemple #5
0
    def effect(self):
        if len(self.svg.selected) != 1:
            sys.exit("Error: You must select exactly one rectangle")
        if list(self.svg.selected.items())[0][1].tag != inkex.addNS('rect','svg'):
            sys.exit("Error: You must select exactly one rectangle")
            
        sel = None
        for pathId in self.svg.selected:
            sel = self.svg.selected[pathId]

        mat = [[1,0,0],[0,1,0]]
        cur = sel
        while cur is not None:
            curMat = Transform(cur.get('transform'))
            mat = Transform(curMat) * Transform(mat)
            cur = cur.getparent()

        [x,y,w,h] = map(lambda attr: float(sel.get(attr)),
                ['x','y','width','height'])
    
        (x1,y1) = transformPoint(mat, (x,y))
        (x2,y2) = transformPoint(mat, (x+w,y+h))

        ww = x2-x1
        hh = y2-y1

        root = self.svg.getElement('//svg:svg');
        root.set('viewBox', '%f %f %f %f' % (x1,y1,ww,hh))
        root.set('width', str(ww))
        root.set('height', str(hh))
Exemple #6
0
    def snap_path_scale(self, elem, parent_transform=None):

        path = elem.original_path.to_arrays()
        transform = elem.transform * Transform(parent_transform)
        bbox = elem.bounding_box()

        # In case somebody tries to snap a 0-high element,
        # or a curve/arc with all nodes in a line, and of course
        # because we should always check for divide-by-zero!
        if not bbox.width or not bbox.height:
            return

        width, height = bbox.width, bbox.height
        min_xy, max_xy = bbox.minimum, bbox.maximum
        rescale = round(width) / width, round(height) / height

        min_xy = transform_point(transform, min_xy, inverse=True)
        max_xy = transform_point(transform, max_xy, inverse=True)

        for i in range(len(path)):
            translate = Transform(translate=min_xy)
            self.transform_path_node(-translate, path, i)  # center transform
            self.transform_path_node(Transform(scale=rescale), path, i)
            self.transform_path_node(translate, path, i)  # uncenter transform

        elem.original_path = path
Exemple #7
0
def _merge_transform(node, transform):
    """Propagate style and transform to remove inheritance
    Originally from
    https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370
    """
    def _get_dimension(s="1024"):
        """Convert an SVG length string from arbitrary units to pixels"""
        if s == "":
            return 0
        try:
            last = int(s[-1])
        except:
            last = None

        if type(last) == int:
            return float(s)
        elif s[-1] == "%":
            return 1024
        elif s[-2:] == "px":
            return float(s[:-2])
        elif s[-2:] == "pt":
            return float(s[:-2]) * 1.25
        elif s[-2:] == "em":
            return float(s[:-2]) * 16
        elif s[-2:] == "mm":
            return float(s[:-2]) * 3.54
        elif s[-2:] == "pc":
            return float(s[:-2]) * 15
        elif s[-2:] == "cm":
            return float(s[:-2]) * 35.43
        elif s[-2:] == "in":
            return float(s[:-2]) * 90
        else:
            return 1024

    # 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, transform)
        this_transform = simpletransform.parseTransform(
            node.get("transform"), this_transform)
        del node.attrib["viewBox"]
    else:
        this_transform = Transform(transform) * Transform(
            node.get("transform"))


#                this_transform = simpletransform.parseTransform(node.get("transform"), transform)    # deprecated, https://inkscape.gitlab.io/inkscape/doxygen-extensions/simpletransform_8py_source.html

# Set the node's transform attrib
#            node.set("transform", simpletransform.formatTransform(this_transform)) # deprecated
    node.set("transform", str(this_transform))
Exemple #8
0
    def effect(self):
        unit_factor = 1.0 / self.svg.uutounit(1.0, self.options.unit)
        for id, node in self.svg.selected.items():

            #get recent XY coordinates (top left corner of the bounding box)
            bbox = node.bounding_box()
            new_horiz_scale = self.options.expected_size * unit_factor / bbox.width
            new_vert_scale = self.options.expected_size * unit_factor / bbox.height

            if self.options.scale_type == "Horizontal":
                translation_matrix = [[new_horiz_scale, 0.0, 0.0],
                                      [0.0, 1.0, 0.0]]
            elif self.options.scale_type == "Vertical":
                translation_matrix = [[1.0, 0.0, 0.0],
                                      [0.0, new_vert_scale, 0.0]]
            else:  #Uniform
                translation_matrix = [[new_horiz_scale, 0.0, 0.0],
                                      [0.0, new_vert_scale, 0.0]]
            node.transform = Transform(translation_matrix) * node.transform

            # now that the node moved we need to get the nodes XY coordinates again to fix them
            bbox_new = node.bounding_box()

            #inkex.utils.debug(cx)
            #inkex.utils.debug(cy)
            #inkex.utils.debug(cx_new)
            #inkex.utils.debug(cy_new)

            # We remove the transformation attribute from SVG XML tree in case it's regular path. In case the node is an object like arc,circle, ellipse or star we have the attribute "sodipodi:type". Then we do not play with it's path because the size transformation will not apply (this code block is ugly)
            if node.get('sodipodi:type') is None and 'd' in node.attrib:
                #inkex.utils.debug("it's a path!")
                d = node.get('d')
                p = CubicSuperPath(d)
                transf = Transform(node.get("transform", None))
                if 'transform' in node.attrib:
                    del node.attrib['transform']
                p = Path(p).to_absolute().transform(transf, True)
                node.set('d', Path(CubicSuperPath(p).to_path()))
            #else:
            #inkex.utils.debug("it's an object!")

            #we perform second translation to reset the center of the path
            translation_matrix = [[
                1.0, 0.0,
                bbox.left - bbox_new.left + (bbox.width - bbox_new.width) / 2
            ],
                                  [
                                      0.0, 1.0, bbox.top - bbox_new.top +
                                      (bbox.height - bbox_new.height) / 2
                                  ]]
            node.transform = Transform(translation_matrix) * node.transform
Exemple #9
0
    def process_shape(self, node, mat):
        rgb = (0, 0, 0)
        style = node.get('style')
        if style:
            style = dict(inkex.Style.parse_str(style))
            if 'stroke' in style:
                if style['stroke'] and style['stroke'] != 'none' and style[
                        'stroke'][0:3] != 'url':
                    rgb = inkex.Color(style['stroke']).to_rgb()
        hsl = colors.rgb_to_hsl(rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0)
        self.color = 7  # default is black
        if hsl[2]:
            self.color = 1 + (int(6 * hsl[0] + 0.5) % 6)  # use 6 hues

        if not isinstance(node,
                          (PathElement, Rectangle, Line, Circle, Ellipse)):
            return

        # Transforming /after/ superpath is more reliable than before
        # because of some issues with arcs in transformations
        for sub in node.path.to_superpath().transform(
                Transform(mat) * node.transform):
            for i in range(len(sub) - 1):
                s = sub[i]
                e = sub[i + 1]
                if s[1] == s[2] and e[0] == e[1]:
                    if self.options.POLY:
                        self.LWPOLY_line([s[1], e[1]])
                    else:
                        self.dxf_line([s[1], e[1]])
                elif self.options.ROBO:
                    self.ROBO_spline([s[1], s[2], e[0], e[1]])
                else:
                    self.dxf_spline([s[1], s[2], e[0], e[1]])
Exemple #10
0
    def addtransform(self, el, trnsfrm):
        # Adds a transform and fuses it to any paths, preserving stroke
        myt = el.get('transform')
        prt = self.getparenttransform(el)
        # if parent is transformed, use transformed coordinate system
        if myt == None:
            newtr = (-prt) * trnsfrm * prt
        else:
            newtr = (-prt) * trnsfrm * prt * Transform(myt)

        sw = dh.Get_Composed_Width(el, 'stroke-width')
        sd = dh.Get_Composed_List(el, 'stroke-dasharray')
        el.set('transform', newtr)
        # Add the new transform
        if not (el.typename in ['TextElement', 'Image', 'Group']):
            #                sty=str(el.composed_style());
            #                sw=dh.Get_Style_Comp(sty,'stroke-width');
            ApplyTransform().recursiveFuseTransform(el)
            if sw is not None:
                nw = float(dh.Get_Style_Comp(el.get('style'), 'stroke-width'))
                sw = nw * sw / dh.Get_Composed_Width(el, 'stroke-width')
                dh.Set_Style_Comp(el, 'stroke-width', str(sw))
                # fix width
            if not (sd == None) and not (sd == 'none'):
                nd = dh.Get_Style_Comp(el.get('style'),
                                       'stroke-dasharray').split(',')
                cd = dh.Get_Composed_List(el, 'stroke-dasharray')
                for ii in range(len(sd)):
                    sd[ii] = float(nd[ii]) * sd[ii] / cd[ii]
                dh.Set_Style_Comp(el, 'stroke-dasharray',
                                  str(sd).strip('[').strip(']'))
Exemple #11
0
    def _expand_defs(root):
        from inkex import Transform, ShapeElement
        from copy import deepcopy
        for el in root:
            if isinstance(el, inkex.Use):
                # <group> element will replace <use> node
                group = inkex.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)
 def effect(self):
     for node in self.svg.selected.values():
         min_bbox_angle = rotate_helper.optimal_rotations(node)[1]
         if min_bbox_angle is not None:
             node.transform = Transform(
                 rotate_helper.rotate_matrix(
                     node, min_bbox_angle)) * node.transform
def map_points_to_morph(axes, percentage, morphed, num_points):
    # rename the axes for legibility
    y_cubic_0 = axes[1]
    y_cubic_1 = axes[3]
    x_cubic_0 = axes[0]
    x_cubic_1 = axes[2]
    # morph each point
    for i in range(0, num_points):
        x = i * 2
        y = i * 2 + 1
        # tween between the morphed y axes according to the x percentage
        tweened_y = tween_cubic(y_cubic_0, y_cubic_1, percentage[x])
        # get 2 points on the morphed x axes
        x_spot_0 = calc_point_on_cubic(x_cubic_0, percentage[x])
        x_spot_1 = calc_point_on_cubic(x_cubic_1, percentage[x])
        # create a transform that stretches the
        # y axis tween between these 2 points
        y_anchor_0 = [tweened_y[0], tweened_y[1]]
        y_anchor_1 = [tweened_y[6], tweened_y[7]]
        x_transform = match(y_anchor_0, y_anchor_1, x_spot_0, x_spot_1)
        # map the y axis tween to the 2 points by
        # applying the stretch transform
        for j in range(4):
            x2 = j * 2
            y2 = j * 2 + 1
            point_on_y = [tweened_y[x2], tweened_y[y2]]
            Transform(x_transform).apply_to_point(point_on_y)
            tweened_y[x2] = point_on_y[0]
            tweened_y[y2] = point_on_y[1]
        # get the point on the tweened and transformed y axis
        # according to the y percentage
        morphed_point = calc_point_on_cubic(tweened_y, percentage[y])
        morphed[x] = morphed_point[0]
        morphed[y] = morphed_point[1]
Exemple #14
0
def mapPointsToMorph(axes, percentage, morphed, numPts):
    # rename the axes for legibility
    yCubic0 = axes[1]
    yCubic1 = axes[3]
    xCubic0 = axes[0]
    xCubic1 = axes[2]
    # morph each point
    for i in range(0, numPts):
        x = i * 2
        y = i * 2 + 1
        # tween between the morphed y axes according to the x percentage
        tweenedY = tweenCubic(yCubic0, yCubic1, percentage[x])
        # get 2 points on the morphed x axes
        xSpot0 = pointOnCubic(xCubic0, percentage[x])
        xSpot1 = pointOnCubic(xCubic1, percentage[x])
        # create a transform that stretches the y axis tween between these 2 points
        yAnchor0 = [tweenedY[0], tweenedY[1]]
        yAnchor1 = [tweenedY[6], tweenedY[7]]
        xTransform = match(yAnchor0, yAnchor1, xSpot0, xSpot1)
        # map the y axis tween to the 2 points by applying the stretch transform
        for j in range(0, 4):
            x2 = j * 2
            y2 = j * 2 + 1
            pointOnY = [tweenedY[x2], tweenedY[y2]]
            Transform(xTransform).apply_to_point(pointOnY)
            tweenedY[x2] = pointOnY[0]
            tweenedY[y2] = pointOnY[1]
        # get the point on the tweened and transformed y axis according to the y percentage
        morphedPoint = pointOnCubic(tweenedY, percentage[y])
        morphed[x] = morphedPoint[0]
        morphed[y] = morphedPoint[1]
Exemple #15
0
def ungroup(groupnode):
    # Pops a node out of its group, unless it's already in a layer or the base
    # Preserves style and clipping
    #    inkex.utils.debug(groupnode.typename)
    global ncall
    ncall += 1
    node_index = list(groupnode.getparent()).index(
        groupnode)  # parent's location in grandparent
    #        node_style = simplestyle.parseStyle(node_parent.get("style")) # deprecated
    node_style = dict(Style.parse_str(groupnode.get("style")))
    #        node_transform = simpletransform.parseTransform(node_parent.get("transform"))  # deprecated
    node_transform = Transform(groupnode.get("transform")).matrix
    node_clippathurl = groupnode.get('clip-path')

    els = groupnode.getchildren()
    for el in list(reversed(els)):
        if not (isinstance(el, (NamedView, Defs, Metadata, ForeignObject))):
            _merge_transform(el, node_transform)
            _merge_style(el, node_style)
            _merge_clippath(el, node_clippathurl)
            groupnode.getparent().insert(node_index + 1, el)
            # places above
            # node_parent.getparent().insert(node_index,node);   # places below
    if len(groupnode.getchildren()) == 0:
        groupnode.delete()
Exemple #16
0
    def test_group_with_number_of_rects_translated(self):

        group = Group()

        dx, dy = 5, 10

        xmin, ymin = 1000, 1000
        xmax, ymax = -1000, -1000
        rects = []

        for x, y, w, h in [
            (10, 20, 5, 7),
            (30, 40, 5, 7),
        ]:
            rect = Rectangle(width=str(w), height=str(h), x=str(x), y=str(y))
            rects.append(rect)

            xmin = min(xmin, x)
            xmax = max(xmax, x + w)
            ymin = min(ymin, y)
            ymax = max(ymax, y + h)

            group.add(rect)

        group.transform = Transform(translate=(dx, dy))

        self.assert_bounding_box_is_equal(group, (dx + xmin,
                                                  dx + xmax),
                                          (dy + ymin,
                                           dy + ymax))
 def test_apply_transform(self):
     """Transformation can be applied to path"""
     path = self.svg.getElementById('D')
     path.transform = Transform(translate=(10, 10))
     self.assertEqual(path.get('d'), 'M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150')
     path.apply_transform()
     self.assertEqual(path.get('d'), 'M 40 140 L 70 140 L 70 130 L 80 150 '
                                     'L 70 170 L 70 160 L 40 160')
     self.assertFalse(path.transform)
Exemple #18
0
    def op_transform(self, layers, mtx, name="Transform", is_end=False):
        """Apply a matrix transformation to the given layers

        Keyword arguments:
        layers -- list of layers
        mtx -- transformation matrix
        name -- name of the Transform layer that is added
        is_end -- set to True if layers are at the end of a canvas

        Returns: list of layers
        """
        if not layers:
            return layers
        if mtx is None or mtx == [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]:
            return layers

        src_tl = [100, 100]
        src_br = [200, 200]

        dest_tl = [100, 100]
        dest_tr = [200, 100]
        dest_br = [200, 200]
        dest_bl = [100, 200]

        dest_tl = Transform(mtx).apply_to_point(dest_tl)
        dest_tr = Transform(mtx).apply_to_point(dest_tr)
        dest_br = Transform(mtx).apply_to_point(dest_br)
        dest_bl = Transform(mtx).apply_to_point(dest_bl)

        warp = self.create_layer("warp",
                                 name,
                                 params={
                                     "src_tl": self.coor_svg2sif(src_tl),
                                     "src_br": self.coor_svg2sif(src_br),
                                     "dest_tl": self.coor_svg2sif(dest_tl),
                                     "dest_tr": self.coor_svg2sif(dest_tr),
                                     "dest_br": self.coor_svg2sif(dest_br),
                                     "dest_bl": self.coor_svg2sif(dest_bl)
                                 })

        if is_end:
            return layers + [warp]
        else:
            return self.op_encapsulate(layers + [warp])
Exemple #19
0
 def process_group(self, group):
     if isinstance(group, inkex.Layer):
         style = group.style
         if 'display' in style:
             if style['display'] == 'none' and self.visibleLayers:
                 return
     trans = group.get('transform')
     if trans:
         self.groupmat.append(
             Transform(self.groupmat[-1]) * Transform(trans))
     for node in group:
         if isinstance(node, Group):
             self.process_group(node)
         elif isinstance(node, Use):
             self.process_clone(node)
         else:
             self.process_shape(node, self.groupmat[-1])
     if trans:
         self.groupmat.pop()
Exemple #20
0
 def process_shape(self, node, mat):
     """Process shape"""
     rgb = (0, 0, 0)  # stroke color
     fillcolor = None  # fill color
     stroke = 1  # pen width in printer pixels
     # Very NB : If the pen width is greater than 1 then the output will Not be a vector output !
     style = node.style
     if style:
         if 'stroke' in style:
             if style['stroke'] and style['stroke'] != 'none' and style[
                     'stroke'][0:3] != 'url':
                 rgb = inkex.Color(style['stroke']).to_rgb()
         if 'stroke-width' in style:
             stroke = self.svg.unittouu(
                 style['stroke-width']) / self.svg.unittouu('1px')
             stroke = int(stroke * self.scale)
         if 'fill' in style:
             if style['fill'] and style['fill'] != 'none' and style['fill'][
                     0:3] != 'url':
                 fill = inkex.Color(style['fill']).to_rgb()
                 fillcolor = fill[0] + 256 * fill[1] + 256 * 256 * fill[2]
     color = rgb[0] + 256 * rgb[1] + 256 * 256 * rgb[2]
     if isinstance(node, PathElement):
         p = node.path.to_superpath()
         if not p:
             return
     elif isinstance(node, Rectangle):
         x = float(node.get('x'))
         y = float(node.get('y'))
         width = float(node.get('width'))
         height = float(node.get('height'))
         p = [[[x, y], [x, y], [x, y]]]
         p.append([[x + width, y], [x + width, y], [x + width, y]])
         p.append([[x + width, y + height], [x + width, y + height],
                   [x + width, y + height]])
         p.append([[x, y + height], [x, y + height], [x, y + height]])
         p.append([[x, y], [x, y], [x, y]])
         p = [p]
     else:
         return
     mat += node.transform
     p = Path(p).transform(Transform(mat)).to_arrays()
     hPen = mygdi.CreatePen(0, stroke, color)
     mygdi.SelectObject(self.hDC, hPen)
     self.emit_path(p)
     if fillcolor is not None:
         brush = LOGBRUSH(0, fillcolor, 0)
         hBrush = mygdi.CreateBrushIndirect(ctypes.addressof(brush))
         mygdi.SelectObject(self.hDC, hBrush)
         mygdi.BeginPath(self.hDC)
         self.emit_path(p)
         mygdi.EndPath(self.hDC)
         mygdi.FillPath(self.hDC)
     return
Exemple #21
0
    def test_group_nested_transform(self):
        group = Group()

        x, y = 10, 20
        w, h = 7, 20

        scale = 2

        rect = Rectangle(width=str(w), height=str(h), x=str(x), y=str(y))

        rect.transform = Transform(rotate=45, scale=scale)

        group.add(rect)

        group.transform = Transform(rotate=-45)  # rotation is compensated, but scale is not

        a = rect.composed_transform()
        self.assert_bounding_box_is_equal(group, (scale * x,
                                                  scale * (x + w)),
                                          (scale * y,
                                           scale * (y + h)))
Exemple #22
0
    def test_path_straight_line_scaled(self):
        path = PathElement()

        scale_x = 2
        scale_y = 3

        path.set_path("M 10 10 "
                      "L 20 20")

        path.transform = Transform(scale=(scale_x, scale_y))
        self.assert_bounding_box_is_equal(path, (scale_x * 10, 20 * scale_x),
                                          (scale_y * 10, 20 * scale_y))
Exemple #23
0
    def convert_url(self, url_id, mtx, d):
        """Return a list Synfig layers that represent the gradient with the given id"""
        gradient = d.get_gradient(url_id)
        if gradient is None:
            # Patterns and other URLs not supported
            return [None]

        if gradient["type"] == "linear":
            layer = d.create_layer("linear_gradient",
                                   url_id,
                                   d.gradient_to_params(gradient),
                                   guids={"gradient": gradient["stops_guid"]})

        if gradient["type"] == "radial":
            layer = d.create_layer("radial_gradient",
                                   url_id,
                                   d.gradient_to_params(gradient),
                                   guids={"gradient": gradient["stops_guid"]})

        trm = Transform(mtx) * Transform(gradient["mtx"])
        return d.op_transform([layer], trm.matrix)
Exemple #24
0
    def snap_path_pos(self, elem, parent_transform=None):
        path = elem.original_path.to_arrays()
        transform = elem.transform * Transform(parent_transform)
        bbox = elem.bounding_box()
        min_xy, max_xy = bbox.minimum, bbox.maximum

        fractional_offset = min_xy[0] - round(min_xy[0]), min_xy[1] - round(
            min_xy[1]) - self.document_offset
        fractional_offset = transform_dimensions(transform,
                                                 fractional_offset[0],
                                                 fractional_offset[1],
                                                 inverse=True)

        for i in range(len(path)):
            self.transform_path_node(-Transform(translate=fractional_offset),
                                     path, i)

        path = str(inkex.Path(path))
        if elem.get('inkscape:original-d'):
            elem.set('inkscape:original-d', path)
        else:
            elem.set('d', path)
Exemple #25
0
    def effect(self):
        offset = 1.0  #in documents' units

        # create a new bounding box and get the bbox size of all elements of the document (we cannot use the page's bbox)
        bbox = inkex.BoundingBox()
        for element in self.svg.root.getchildren():
            if isinstance(element, inkex.ShapeElement):
                bbox += element.bounding_box()

        # adjust the viewBox to the bbox size and add the desired offset
        self.document.getroot().attrib[
            'viewBox'] = f'{-offset} {-offset} {bbox.width + offset * 2} {bbox.height + offset * 2}'
        self.document.getroot(
        ).attrib['width'] = f'{bbox.width + offset * 2}' + self.svg.unit
        self.document.getroot(
        ).attrib['height'] = f'{bbox.height + offset * 2}' + self.svg.unit

        # translate all elements to fit the adjusted viewBox
        mat = Transform("translate(%f, %f)" % (-bbox.left, -bbox.top)).matrix
        for element in self.svg.root.getchildren():
            if isinstance(element, inkex.ShapeElement):
                element.transform = Transform(mat) * element.transform
Exemple #26
0
    def effect(self):
        mesh = om.read_trimesh(self.options.inputfile)
        fullUnfolded, unfoldedComponents = unfold(mesh)
        # Compute maxSize of the components
        # All components must be scaled to the same size as the largest component
        maxSize = 0
        for unfolding in unfoldedComponents:
            [xmin, ymin, boxSize] = findBoundingBox(unfolding[0])
            if boxSize > maxSize:
                maxSize = boxSize

        # Create a new container group to attach all paperfolds
        paperfoldMainGroup = self.document.getroot().add(
            inkex.Group(id=self.svg.get_unique_id(
                "paperfold-")))  #make a new group at root level
        for i in range(len(unfoldedComponents)):
            paperfoldPageGroup = writeSVG(self, unfoldedComponents[i], maxSize,
                                          self.options.printNumbers)
            #translate the groups next to each other to remove overlappings
            if i != 0:
                previous_bbox = paperfoldMainGroup[i - 1].bounding_box()
                this_bbox = paperfoldPageGroup.bounding_box()
                paperfoldPageGroup.set(
                    "transform", "translate(" +
                    str(previous_bbox.left + previous_bbox.width -
                        this_bbox.left) + ", 0.0)")
            paperfoldMainGroup.append(paperfoldPageGroup)

        #apply scale factor
        translation_matrix = [[self.options.scalefactor, 0.0, 0.0],
                              [0.0, self.options.scalefactor, 0.0]]
        paperfoldMainGroup.transform = Transform(
            translation_matrix) * paperfoldMainGroup.transform
        #paperfoldMainGroup.set('transform', 'scale(%f,%f)' % (self.options.scalefactor, self.options.scalefactor))

        #adjust canvas to the inserted unfolding
        if self.options.resizetoimport:
            bbox = paperfoldMainGroup.bounding_box()
            namedView = self.document.getroot().find(
                inkex.addNS('namedview', 'sodipodi'))
            doc_units = namedView.get(inkex.addNS('document-units',
                                                  'inkscape'))
            root = self.svg.getElement('//svg:svg')
            offset = self.svg.unittouu(
                str(self.options.extraborder) + self.options.extraborder_units)
            root.set(
                'viewBox', '%f %f %f %f' %
                (bbox.left - offset, bbox.top - offset,
                 bbox.width + 2 * offset, bbox.height + 2 * offset))
            root.set('width', str(bbox.width + 2 * offset) + doc_units)
            root.set('height', str(bbox.height + 2 * offset) + doc_units)
Exemple #27
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 import Transform
        scale_transform = Transform("scale(%f)" % relative_scale)

        old_transform = Transform(ref_node.transform)

        # Account for vertical flipping of nodes created via pstoedit in TexText <= 0.11.x
        revert_flip = Transform("scale(1)")
        if ref_node.get_meta("pdfconverter", "pstoedit") == "pstoedit":
            revert_flip = Transform(matrix=((1, 0, 0),
                                            (0, -1, 0)))  # vertical reflection

        composition = scale_transform * old_transform * revert_flip

        # 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()))
Exemple #28
0
    def snap_transform(self, elem):
        # Only snaps the x/y translation of the transform, nothing else.
        # Doesn't take any parent_transform into account -- assumes
        # that the parent's transform has already been snapped.
        transform = elem.transform
        # if we've got any skew/rotation, get outta here
        if transform.c or transform.b:
            raise TransformError(
                "TR: Selection contains transformations with skew/rotation")

        trm = list(transform.to_hexad())
        trm[4] = round(transform.e)
        trm[5] = round(transform.f)
        elem.transform *= Transform(trm)
Exemple #29
0
    def test_regular_rectangle_scaled(self):

        x, y = 10, 20
        w, h = 7, 20

        scale_x = 2
        scale_y = 3

        rect = Rectangle(width=str(w), height=str(h), x=str(x), y=str(y))

        rect.transform = Transform(scale=(scale_x, scale_y))

        self.assert_bounding_box_is_equal(rect,
                                          (scale_x * x,
                                           scale_x * (x + w)),
                                          (scale_y * y,
                                           scale_y * (y + h)))
Exemple #30
0
    def effect(self):
        w = self.svg.width
        h = self.svg.height
        s = 1 / self.svg.unittouu('1mm')
        w = w * s
        h = h * s

        #print(f"w: {w} h: {h} s: {s}", file=sys.stderr)
        bbox = Rect()
        bbox.setBounds(Vec2(0, 0), Vec2(w, h))
        converter = nodeconverter.NodeToPolylines(bbox)
        converter.accept(self.document.getroot(),
                         Transform([[s, 0.0, 0.0], [0.0, -s, h]]))
        planner = Planner()
        planner.optimize(converter.drawing)
        gcode = drawing_to_gcode(converter.drawing, self.options)

        if self.options.tab == 'filetab':
            filename = os.path.join(
                os.path.abspath(os.path.expanduser(self.options.directory)),
                os.path.splitext(self.options.filename)[0] + '.gcode')
            with open(filename, 'w') as f:
                f.write('\n'.join(gcode))
        elif self.options.tab == 'serialtab':
            # Open serial port
            try:
                serial = Serial(self.options.serialPort,
                                self.options.serialBaudRate,
                                timeout=None)

                # Wake up grbl
                serial.write("\r\n\r\n")
                time.sleep(2)  # Wait for grbl to initialize
                serial.flushInput()  # Flush startup text in serial input

                # Stream g-code
                for line in gcode:
                    serial.write(line + '\n')  # Send g-code block
                    grbl_out = serial.readline(
                    )  # Wait for response with carriage return
                time.sleep(2)
                # Close serial port
                serial.close()
            except (OSError, serial.SerialException):
                inkex.errormsg(_("Problem connecting to serial device."))