def scaleCubicSuper(self, cspath, scaleFactor, scaleFrom):

        xmin, xmax, ymin, ymax = simpletransform.refinedBBox(cspath)

        if (scaleFrom == 'topLeft'):
            oldOrigin = [xmin, ymin]
        elif (scaleFrom == 'topRight'):
            oldOrigin = [xmax, ymin]
        elif (scaleFrom == 'bottomLeft'):
            oldOrigin = [xmin, ymax]
        elif (scaleFrom == 'bottomRight'):
            oldOrigin = [xmax, ymax]
        else:  #if(scaleFrom == 'center'):
            oldOrigin = [xmin + (xmax - xmin) / 2., ymin + (ymax - ymin) / 2.]

        newOrigin = [oldOrigin[0] * scaleFactor, oldOrigin[1] * scaleFactor]

        for subpath in cspath:
            for bezierPt in subpath:
                for i in range(0, len(bezierPt)):

                    bezierPt[i] = [
                        bezierPt[i][0] * scaleFactor,
                        bezierPt[i][1] * scaleFactor
                    ]

                    bezierPt[i][0] += (oldOrigin[0] - newOrigin[0])
                    bezierPt[i][1] += (oldOrigin[1] - newOrigin[1])
Exemplo n.º 2
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)
Exemplo n.º 3
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
Exemplo n.º 4
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
Exemplo n.º 5
0
def getBoundingBox(cspath):
    if (ver == 1.0):
        bbox = cspath.to_path().bounding_box()
        return bbox.left, bbox.right, bbox.top, bbox.bottom
    else:
        return simpletransform.refinedBBox(cspath)
def getCubicBoundingBox(csp):
    if(CommonDefs.inkVer == 1.0):
        bbox = csp.to_path().bounding_box()
        return bbox.left, bbox.right, bbox.top, bbox.bottom
    else:
        return simpletransform.refinedBBox(csp)