def effect(self):
        #References:   Minimum Requirements for Creating a DXF File of a 3D Model By Paul Bourke
        #              NURB Curves: A Guide for the Uninitiated By Philip J. Schneider
        #              The NURBS Book By Les Piegl and Wayne Tiller (Springer, 1995)
        self.dxf_add("999\nDXF created by Inkscape\n")
        self.dxf_add(dxf_templates.r14_header)

        scale = 25.4/90.0
        h = inkex.unittouu(self.document.getroot().xpath('@height', namespaces=inkex.NSS)[0])
        path = '//svg:path'
        for node in self.document.getroot().xpath(path, namespaces=inkex.NSS):
            d = node.get('d')
            sim = simplepath.parsePath(d)
            if len(sim):
                simplepath.scalePath(sim,scale,-scale)
                simplepath.translatePath(sim,0,h*scale)            
                p = cubicsuperpath.CubicSuperPath(sim)
                for sub in p:
                    for i in range(len(sub)-1):
                        s = sub[i]
                        e = sub[i+1]
                        if s[1] == s[2] and e[0] == e[1]:
                            self.dxf_line([s[1],e[1]])
                        elif (self.options.ROBO == 'true'):
                            self.ROBO_spline([s[1],s[2],e[0],e[1]])
                        else:
                            self.dxf_spline([s[1],s[2],e[0],e[1]])
        if self.options.ROBO == 'true':
            self.ROBO_output()
        self.LWPOLY_output()
        self.dxf_add(dxf_templates.r14_footer)
Beispiel #2
0
    def addPathVertices(self,
                        path,
                        node=None,
                        transform=None,
                        clone_transform=None):
        """
        Decompose the path data from an SVG element into individual
        subpaths, each subpath consisting of absolute move to and line
        to coordinates.  Place these coordinates into a list of polygon
        vertices.
        """

        if (not path) or (len(path) == 0):
            # Nothing to do
            return

        # parsePath() may raise an exception.  This is okay
        sp = simplepath.parsePath(path)
        if (not sp) or (len(sp) == 0):
            # Path must have been devoid of any real content
            return

        # Get a cubic super path
        p = cubicsuperpath.CubicSuperPath(sp)
        if (not p) or (len(p) == 0):
            # Probably never happens, but...
            return

        # Now traverse the cubic super path
        subpath_list = []
        subpath_vertices = []
        for sp in p:
            if len(subpath_vertices):
                # There's a prior subpath: see if it is closed and should be saved
                if distanceSquared(subpath_vertices[0],
                                   subpath_vertices[-1]) < 1:
                    # Keep the prior subpath: it appears to be a closed path
                    subpath_list.append(subpath_vertices)
            subpath_vertices = []
            subdivideCubicPath(sp, 0.2)
            for csp in sp:
                # Add this vertex to the list of vertices
                subpath_vertices.append(csp[1])

        # Handle final subpath
        if len(subpath_vertices):
            if distanceSquared(subpath_vertices[0], subpath_vertices[-1]) < 1:
                # Path appears to be closed so let's keep it
                subpath_list.append(subpath_vertices)

        # Empty path?
        if not subpath_list:
            return

        # Store the list of subpaths in a dictionary keyed off of the path's node pointer
        self.paths[node] = subpath_list
        self.paths_clone_transform[node] = clone_transform
Beispiel #3
0
def parsePath(d):
    '''
	Parse line and replace quadratic bezier segments and arcs by
	cubic bezier segments.
	'''
    import simplepath
    p = simplepath.parsePath(d)
    if any(cmd not in 'MLCZ' for (cmd, params) in p):
        import cubicsuperpath
        csp = cubicsuperpath.CubicSuperPath(p)
        p = cubicsuperpath.unCubicSuperPath(csp)
    return p
Beispiel #4
0
    def getNodeDimensions(self, node):
        try:
            nodeX = float(node.attrib["x"])
            nodeY = float(node.attrib["y"])
            nodeWidth = float(node.attrib["width"])
            nodeHeight = float(node.attrib["height"])
        except Exception:
            try:
                (nodeMinX, nodeMaxX, nodeMinY, nodeMaxY) = \
                    simpletransform.roughBBox(node.attrib["d"])
            except Exception:
                (nodeMinX, nodeMaxX, nodeMinY, nodeMaxY) = \
                    simpletransform.roughBBox(
                        cubicsuperpath.CubicSuperPath(
                            simplepath.parsePath(node.attrib["d"])
                        )
                    )
            nodeX = nodeMinX
            nodeY = nodeMinY
            nodeWidth = nodeMaxX - nodeMinX
            nodeHeight = nodeMaxY - nodeMinY

        return nodeX, nodeY, nodeWidth, nodeHeight
Beispiel #5
0
def morphPath(path, axes):
    bounds = simpletransform.roughBBox(cubicsuperpath.CubicSuperPath(path))
    newPath = []
    current = [0.0, 0.0]
    start = [0.0, 0.0]

    for cmd, params in path:
        segmentType = cmd
        points = params
        if segmentType == "M":
            start[0] = points[0]
            start[1] = points[1]
        segmentType = convertSegmentToCubic(current, segmentType, points,
                                            start)
        percentages = [0.0] * len(points)
        morphed = [0.0] * len(points)
        numPts = getNumPts(segmentType)
        normalizePoints(bounds, points, percentages, numPts)
        mapPointsToMorph(axes, percentages, morphed, numPts)
        addSegment(newPath, segmentType, morphed)
        if len(points) >= 2:
            current[0] = points[len(points) - 2]
            current[1] = points[len(points) - 1]
    return newPath
    def effect(self):
        #References:   Minimum Requirements for Creating a DXF File of a 3D Model By Paul Bourke
        #              NURB Curves: A Guide for the Uninitiated By Philip J. Schneider
        self.dxf_add("999\nDXF created by Inkscape\n0\nSECTION\n2\nENTITIES")
        
        scale = 25.4/90.0
        h = inkex.unittouu(inkex.xml.xpath.Evaluate('/svg/@height',self.document)[0].value)

        path = '//path'
        for node in inkex.xml.xpath.Evaluate(path,self.document):
            d = node.attributes.getNamedItem('d').value
            sim = simplepath.parsePath(d)
            simplepath.scalePath(sim,scale,-scale)
            simplepath.translatePath(sim,0,h*scale)            
            p = cubicsuperpath.CubicSuperPath(sim)
            for sub in p:
                for i in range(len(sub)-1):
                    s = sub[i]
                    e = sub[i+1]
                    if s[1] == s[2] and e[0] == e[1]:
                        self.dxf_line([s[1],e[1]])
                    else:
                        self.dxf_spline([s[1],s[2],e[0],e[1]])
        self.dxf_add("\n0\nENDSEC\n0\nEOF\n")
Beispiel #7
0
    def getPathVertices(self, path, node=None, transform=None):
        '''
        Decompose the path data from an SVG element into individual
        subpaths, each subpath consisting of absolute move to and line
        to coordinates.  Place these coordinates into a list of polygon
        vertices.
        '''

        if (not path) or (len(path) == 0):
            # Nothing to do
            return None

        # parsePath() may raise an exception.  This is okay
        sp = simplepath.parsePath(path)
        if (not sp) or (len(sp) == 0):
            # Path must have been devoid of any real content
            return None

        # Get a cubic super path
        p = cubicsuperpath.CubicSuperPath(sp)
        if (not p) or (len(p) == 0):
            # Probably never happens, but...
            return None

        if transform:
            simpletransform.applyTransformToPath(transform, p)

        # Now traverse the cubic super path
        subpath_list = []
        subpath_vertices = []

        for sp in p:

            # We've started a new subpath
            # See if there is a prior subpath and whether we should keep it
            if len(subpath_vertices):
                subpath_list.append(
                    [subpath_vertices, [sp_xmin, sp_xmax, sp_ymin, sp_ymax]])

            subpath_vertices = []
            subdivideCubicPath(sp, float(self.options.smoothness))

            # Note the first point of the subpath
            first_point = sp[0][1]
            subpath_vertices.append(first_point)
            sp_xmin = first_point[0]
            sp_xmax = first_point[0]
            sp_ymin = first_point[1]
            sp_ymax = first_point[1]

            # See if the first and last points are identical
            # OpenSCAD doesn't mind if we duplicate the first and last
            # vertex, but our polygon in polygon algorithm may
            n = len(sp)
            last_point = sp[n - 1][1]
            if first_point[0] == last_point[0] and \
                    first_point[1] == last_point[1]:
                n = n - 1

            # Traverse each point of the subpath
            for csp in sp[1:n]:

                # Append the vertex to our list of vertices
                pt = csp[1]
                subpath_vertices.append(pt)

                # Track the bounding box of this subpath
                if pt[0] < sp_xmin:
                    sp_xmin = pt[0]
                elif pt[0] > sp_xmax:
                    sp_xmax = pt[0]
                if pt[1] < sp_ymin:
                    sp_ymin = pt[1]
                elif pt[1] > sp_ymax:
                    sp_ymax = pt[1]

            # Track the bounding box of the overall drawing
            # This is used for centering the polygons in OpenSCAD around the
            # (x,y) origin
            if sp_xmin < self.xmin:
                self.xmin = sp_xmin
            if sp_xmax > self.xmax:
                self.xmax = sp_xmax
            if sp_ymin < self.ymin:
                self.ymin = sp_ymin
            if sp_ymax > self.ymax:
                self.ymax = sp_ymax

        # Handle the final subpath
        if len(subpath_vertices):
            subpath_list.append(
                [subpath_vertices, [sp_xmin, sp_xmax, sp_ymin, sp_ymax]])

        if len(subpath_list) > 0:
            self.paths[node] = subpath_list
    def getPathVertices(self,
                        path,
                        node=None,
                        transform=None,
                        smoothness=None):
        '''
        Decompose the path data from an SVG element into individual
        subpaths, each subpath consisting of absolute move to and line
        to coordinates.  Place these coordinates into a list of polygon
        vertices.

        The result is appended to self.paths as a two-element tuple of the
        form (node, path_list). This preserves the native ordering of
        the SVG file as much as possible, while still making all attributes
        if the node available when processing the path list.
        '''

        if not smoothness:
            smoothness = self.smoothness  # self.smoothness is deprecated.

        if (not path) or (len(path) == 0):
            # Nothing to do
            return None

        if node is not None:
            path = self.styleDasharray(path, node)

        # parsePath() may raise an exception.  This is okay
        sp = simplepath.parsePath(path)
        if (not sp) or (len(sp) == 0):
            # Path must have been devoid of any real content
            return None

        # Get a cubic super path
        p = cubicsuperpath.CubicSuperPath(sp)
        if (not p) or (len(p) == 0):
            # Probably never happens, but...
            return None

        if transform:
            simpletransform.applyTransformToPath(transform, p)

        # Now traverse the cubic super path
        subpath_list = []
        subpath_vertices = []

        for sp in p:

            # We've started a new subpath
            # See if there is a prior subpath and whether we should keep it
            if len(subpath_vertices):
                subpath_list.append(
                    [subpath_vertices, [sp_xmin, sp_xmax, sp_ymin, sp_ymax]])

            subpath_vertices = []
            self.subdivideCubicPath(sp, float(smoothness))

            # Note the first point of the subpath
            first_point = sp[0][1]
            subpath_vertices.append(first_point)
            sp_xmin = first_point[0]
            sp_xmax = first_point[0]
            sp_ymin = first_point[1]
            sp_ymax = first_point[1]

            n = len(sp)

            # Traverse each point of the subpath
            for csp in sp[1:n]:

                # Append the vertex to our list of vertices
                pt = csp[1]
                subpath_vertices.append(pt)

                # Track the bounding box of this subpath
                if pt[0] < sp_xmin:
                    sp_xmin = pt[0]
                elif pt[0] > sp_xmax:
                    sp_xmax = pt[0]
                if pt[1] < sp_ymin:
                    sp_ymin = pt[1]
                elif pt[1] > sp_ymax:
                    sp_ymax = pt[1]

            # Track the bounding box of the overall drawing
            # This is used for centering the polygons in OpenSCAD around the
            # (x,y) origin
            if sp_xmin < self.xmin:
                self.xmin = sp_xmin
            if sp_xmax > self.xmax:
                self.xmax = sp_xmax
            if sp_ymin < self.ymin:
                self.ymin = sp_ymin
            if sp_ymax > self.ymax:
                self.ymax = sp_ymax

        # Handle the final subpath
        if len(subpath_vertices):
            subpath_list.append(
                [subpath_vertices, [sp_xmin, sp_xmax, sp_ymin, sp_ymax]])

        if len(subpath_list) > 0:
            self.paths.append((node, subpath_list))
    def addPathVertices(self, path, node=None, transform=None):
        '''
		Decompose the path data from an SVG element into individual
		subpaths, each starting with an absolute move-to (x, y)
		coordinate followed by one or more absolute line-to (x, y)
		coordinates.  Each subpath is stored as a list of (x, y)
		coordinates, with the first entry understood to be a
		move-to coordinate and the rest line-to coordinates.  A list
		is then made of all the subpath lists and then stored in the
		self.paths dictionary using the path's lxml.etree node pointer
		as the dictionary key.
		'''

        if (not path) or (len(path) == 0):
            return

        # parsePath() may raise an exception.  This is okay
        sp = simplepath.parsePath(path)
        if (not sp) or (len(sp) == 0):
            return

        # Get a cubic super duper path
        p = cubicsuperpath.CubicSuperPath(sp)
        if (not p) or (len(p) == 0):
            return

        # Apply any transformation
        if transform != None:
            simpletransform.applyTransformToPath(transform, p)

        # Now traverse the simplified path
        subpaths = []
        subpath_vertices = []
        for sp in p:
            # We've started a new subpath
            # See if there is a prior subpath and whether we should keep it
            if len(subpath_vertices):
                if distanceSquared(subpath_vertices[0],
                                   subpath_vertices[-1]) < 1:
                    # Keep the prior subpath: it appears to be a closed path
                    subpaths.append(subpath_vertices)
            subpath_vertices = []
            subdivideCubicPath(sp, float(self.options['tolerance'] / 10))
            for csp in sp:
                # Add this vertex to the list of vetices
                subpath_vertices.append(csp[1])

        # Handle final subpath
        if len(subpath_vertices):
            if distanceSquared(subpath_vertices[0], subpath_vertices[-1]) < 1:
                # Path appears to be closed so let's keep it
                subpaths.append(subpath_vertices)

        # Empty path?
        if len(subpaths) == 0:
            return

        # And add this path to our dictionary of paths
        self.paths[node] = subpaths

        # And save the transform for this element in a dictionary keyed
        # by the element's lxml node pointer
        self.transforms[node] = transform
Beispiel #10
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)
Beispiel #11
0
 def boundingBox(self):
     csp = cubicsuperpath.CubicSuperPath(self.data)
     self.bbox = list(simpletransform.roughBBox(csp))
     return list(simpletransform.roughBBox(csp))  # [minx,maxx,miny,maxy]
Beispiel #12
0
    def getPathVertices(self,
                        path,
                        node=None,
                        transform=None,
                        find_bbox=False):
        '''
		Decompose the path data from an SVG element into individual
		subpaths, each subpath consisting of absolute move to and line
		to coordinates.  Place these coordinates into a list of polygon
		vertices.
		'''

        if (not path) or (len(path) == 0):
            # Nothing to do
            return None

        # parsePath() may raise an exception.  This is okay
        sp = simplepath.parsePath(path)
        if (not sp) or (len(sp) == 0):
            # Path must have been devoid of any real content
            return None

        # Get a cubic super path
        p = cubicsuperpath.CubicSuperPath(sp)
        if (not p) or (len(p) == 0):
            # Probably never happens, but...
            return None

        if transform:
            simpletransform.applyTransformToPath(transform, p)

        # Now traverse the cubic super path
        subpath_list = []
        subpath_vertices = []
        for sp in p:
            if len(subpath_vertices):
                subpath_list.append(subpath_vertices)
            subpath_vertices = []
            last_csp = None
            subdivideCubicPath(sp, float(self.options.smoothness))
            for csp in sp:
                if (last_csp != None) and (math.fabs(csp[1][1] - last_csp[1]) >
                                           self.options.maxDy):
                    dy = (csp[1][1] - last_csp[1])
                    dx = (csp[1][0] - last_csp[0])
                    nsteps = math.ceil(math.fabs(dy / self.options.maxDy))
                    for n in range(1, int(1 + nsteps)):
                        s = n / nsteps
                        subpath_vertices.append(
                            [last_csp[0] + s * dx, last_csp[1] + s * dy])
                else:
                    # Add this vertex to the list of vetices
                    subpath_vertices.append(csp[1])
                last_csp = csp[1]
                if find_bbox:
                    if last_csp[0] < self.xmin:
                        self.xmin = last_csp[0]
                    elif last_csp[0] > self.xmax:
                        self.xmax = last_csp[0]

        # Handle final subpath
        if len(subpath_vertices):
            subpath_list.append(subpath_vertices)

        if len(subpath_list) > 0:
            self.paths[node] = subpath_list
            self.transforms[node] = transform