Пример #1
0
def realistic_stitch(start, end):
    """Generate a stitch vector path given a start and end point."""

    end = Point(*end)
    start = Point(*start)

    stitch_length = (end - start).length()
    stitch_center = (end + start) / 2.0
    stitch_direction = (end - start)
    stitch_angle = math.atan2(stitch_direction.y, stitch_direction.x)

    stitch_length = max(0, stitch_length - 0.2 * PIXELS_PER_MM)

    # create the path by filling in the length in the template
    path = simplepath.parsePath(stitch_path % stitch_length)

    # rotate the path to match the stitch
    rotation_center_x = -stitch_length / 2.0
    rotation_center_y = stitch_height / 2.0
    simplepath.rotatePath(path,
                          stitch_angle,
                          cx=rotation_center_x,
                          cy=rotation_center_y)

    # move the path to the location of the stitch
    simplepath.translatePath(path, stitch_center.x - rotation_center_x,
                             stitch_center.y - rotation_center_y)

    return simplepath.formatPath(path)
Пример #2
0
    def test_simplepath(self):
        """Test simplepath API"""
        import simplepath

        data = 'M12 34L56 78Z'
        path = simplepath.parsePath(data)
        self.assertEqual(path,
                         [['M', [12., 34.]], ['L', [56., 78.]], ['Z', []]])

        d_out = simplepath.formatPath(path)
        d_out = d_out.replace('.0', '')
        self.assertEqual(data.replace(' ', ''), d_out.replace(' ', ''))

        simplepath.translatePath(path, -3, -4)
        self.assertEqual(path,
                         [['M', [9., 30.]], ['L', [53., 74.]], ['Z', []]])

        simplepath.scalePath(path, 10, 20)
        self.assertEqual(path,
                         [['M', [90., 600.]], ['L', [530., 1480.]], ['Z', []]])

        simplepath.rotatePath(path, math.pi / 2.0, cx=5, cy=7)
        approxed = [[code, approx(coords)] for (code, coords) in path]
        self.assertEqual(
            approxed, [['M', [-588., 92.]], ['L', [-1468., 532.]], ['Z', []]])
def resolve_path(node, transform=False):
    path = simplepath.parsePath(node.attrib['d'])
    if transform and 'transform' in node.attrib:
        transforms = re.findall(
            "([a-z,A-Z]+)\(([0-9,\s,.,-]*)\)",
            node.attrib['transform'])
        for k, vs in transforms:
            sc = ' '
            if ',' in vs:
                sc = ','
            args = map(lambda v: float(v.strip()), vs.split(sc))
            if k == 'translate':
                simplepath.translatePath(path, *args)
            elif k == 'scale':
                simplepath.scalePath(path, *args)
            elif k == 'rotate':
                simplepath.rotatePath(path, *args)
            else:
                error(
                    "Invalid path data: contains unsupported transform %s" % k)
    return path
Пример #4
0
    def effect(self):

        # get user-entered params
        x_scale = self.options.x_scale
        y_scale = self.options.y_scale

        t_start = self.options.t_start
        t_end = self.options.t_end
        n_steps = self.options.n_steps
        fps = self.options.fps
        dt = self.options.dt

        x_eqn = self.options.x_eqn
        y_eqn = self.options.y_eqn

        x_size_eqn = self.options.x_size_eqn
        y_size_eqn = self.options.y_size_eqn

        theta_eqn = self.options.theta_eqn

        # get doc root
        svg = self.document.getroot()
        doc_w = self.unittouu(svg.get('width'))
        doc_h = self.unittouu(svg.get('height'))

        # get selected items and validate
        selected = pathmodifier.zSort(self.document.getroot(),
                                      self.selected.keys())

        if not selected:
            inkex.errormsg(
                'Exactly two objects must be selected: a rect and a template. See "help" for details.'
            )
            return
        elif len(selected) != 2:
            inkex.errormsg(
                'Exactly two objects must be selected: a rect and a template. See "help" for details.'
            )
            return

        # rect
        rect = self.selected[selected[0]]

        if not rect.tag.endswith('rect'):
            inkex.errormsg('Bottom object must be rect. See "help" for usage.')
            return

        # object
        obj = self.selected[selected[1]]

        if not (obj.tag.endswith('path') or obj.tag.endswith('g')):
            inkex.errormsg(
                'Template object must be path or group of paths. See "help" for usage.'
            )
            return
        if obj.tag.endswith('g'):
            children = obj.getchildren()
            if not all([ch.tag.endswith('path') for ch in children]):
                msg = 'All elements of group must be paths, but they are: '
                msg += ', '.join(['{}'.format(ch) for ch in children])
                inkex.errormsg(msg)
                return
            objs = children
            is_group = True
        else:
            objs = [obj]
            is_group = False

        # get rect params
        w = float(rect.get('width'))
        h = float(rect.get('height'))

        x_rect = float(rect.get('x'))
        y_rect = float(rect.get('y'))

        # lower left corner
        x_0 = x_rect
        y_0 = y_rect + h

        # get object path(s)
        obj_ps = [simplepath.parsePath(obj_.get('d')) for obj_ in objs]
        n_segs = [len(obj_p_) for obj_p_ in obj_ps]
        obj_p = sum(obj_ps, [])

        # compute travel parameters
        if not n_steps:
            # compute dt
            if dt == 0:
                dt = 1. / fps
            ts = np.arange(t_start, t_end, dt)
        else:
            ts = np.linspace(t_start, t_end, n_steps)

        # compute xs, ys, stretches, and rotations in arbitrary coordinates
        xs = np.nan * np.zeros(len(ts))
        ys = np.nan * np.zeros(len(ts))
        x_sizes = np.nan * np.zeros(len(ts))
        y_sizes = np.nan * np.zeros(len(ts))
        thetas = np.nan * np.zeros(len(ts))

        for ctr, t in enumerate(ts):
            xs[ctr] = eval(x_eqn)
            ys[ctr] = eval(y_eqn)
            x_sizes[ctr] = eval(x_size_eqn)
            y_sizes[ctr] = eval(y_size_eqn)
            thetas[ctr] = eval(theta_eqn) * pi / 180

        # ensure no Infs
        if np.any(np.isinf(xs)):
            raise Exception('Inf detected in x(t), please remove.')
            return
        if np.any(np.isinf(ys)):
            raise Exception('Inf detected in y(t), please remove.')
            return
        if np.any(np.isinf(x_sizes)):
            raise Exception('Inf detected in x_size(t), please remove.')
            return
        if np.any(np.isinf(y_sizes)):
            raise Exception('Inf detected in y_size(t), please remove.')
            return
        if np.any(np.isinf(thetas)):
            raise Exception('Inf detected in theta(t), please remove.')
            return

        # convert to screen coordinates
        xs *= (w / x_scale)
        xs += x_0

        ys *= (-h / y_scale)  # neg sign to invert y for inkscape screen
        ys += y_0

        # get obj center
        b_box = simpletransform.refinedBBox(
            cubicsuperpath.CubicSuperPath(obj_p))
        c_x = 0.5 * (b_box[0] + b_box[1])
        c_y = 0.5 * (b_box[2] + b_box[3])

        # get rotation anchor
        if any([k.endswith('transform-center-x') for k in obj.keys()]):
            k_r_x = [
                k for k in obj.keys() if k.endswith('transform-center-x')
            ][0]
            k_r_y = [
                k for k in obj.keys() if k.endswith('transform-center-y')
            ][0]
            r_x = c_x + float(obj.get(k_r_x))
            r_y = c_y - float(obj.get(k_r_y))
        else:
            r_x, r_y = c_x, c_y

        paths = []

        # compute new paths
        for x, y, x_size, y_size, theta in zip(xs, ys, x_sizes, y_sizes,
                                               thetas):

            path = deepcopy(obj_p)

            # move to origin
            simplepath.translatePath(path, -x_0, -y_0)

            # move rotation anchor accordingly
            r_x_1 = r_x - x_0
            r_y_1 = r_y - y_0

            # scale
            simplepath.scalePath(path, x_size, y_size)

            # scale rotation anchor accordingly
            r_x_2 = r_x_1 * x_size
            r_y_2 = r_y_1 * y_size

            # move to final location
            simplepath.translatePath(path, x, y)

            # move rotation anchor accordingly
            r_x_3 = r_x_2 + x
            r_y_3 = r_y_2 + y

            # rotate
            simplepath.rotatePath(path, -theta, cx=r_x_3, cy=r_y_3)

            paths.append(path)

        parent = self.current_layer
        group = inkex.etree.SubElement(parent, inkex.addNS('g', 'svg'), {})

        for path in paths:

            if is_group:
                group_ = inkex.etree.SubElement(group, inkex.addNS('g', 'svg'),
                                                {})
                path_components = split(path, n_segs)

                for path_component, child in zip(path_components, children):
                    attribs = {k: child.get(k) for k in child.keys()}

                    attribs['d'] = simplepath.formatPath(path_component)

                    child_copy = inkex.etree.SubElement(
                        group_, child.tag, attribs)

            else:
                attribs = {k: obj.get(k) for k in obj.keys()}

                attribs['d'] = simplepath.formatPath(path)

                obj_copy = inkex.etree.SubElement(group, obj.tag, attribs)
Пример #5
0
 def rotatePath(self, a, x=0, y=0):
     simplepath.rotatePath(self.data, a, x, y)
Пример #6
0
	def rotatePath(self,a,x=0,y=0):
		simplepath.rotatePath(self.data,a,x,y)