def effect(self):
    clippingLineSegments = None
    pathTag = inkex.addNS('path','svg')
    groupTag = inkex.addNS('g','svg')
    error_messages = []
    for id in self.options.ids:  # the selection, top-down
      node = self.selected[id]
      if node.tag == pathTag:
        if clippingLineSegments is None: # first path is the clipper
          (clippingLineSegments, errors) = self.simplepathToLineSegments(simplepath.parsePath(node.get('d')))
          error_messages.extend(['{}: {}'.format(id, err) for err in errors])
        else:
          # do all the work!
          segmentsToClip, errors = self.simplepathToLineSegments(simplepath.parsePath(node.get('d')))
          error_messages.extend(['{}: {}'.format(id, err) for err in errors])
          clippedSegments = self.clipLineSegments(segmentsToClip, clippingLineSegments)
          if len(clippedSegments) != 0:
            # replace the path
            node.set('d', simplepath.formatPath(self.linesgmentsToSimplePath(clippedSegments)))
          else:
            # don't put back an empty path(?)  could perhaps put move, move?
            inkex.debug('Object {} clipped to nothing, will not be updated.'.format(node.get('id')))
      elif node.tag == groupTag:  # we don't look inside groups for paths
        inkex.debug('Group object {} will be ignored. Please ungroup before running the script.'.format(id))
      else: # something else
        inkex.debug('Object {} is not of type path ({}), and will be ignored. Current type "{}".'.format(id, pathTag, node.tag))

    for error in error_messages:
        inkex.debug(error)
Beispiel #2
0
def point_generator(path, mat, flatness):

        rirCount = 0

        if len(simplepath.parsePath(path)) == 0:
                return
       
        simple_path = simplepath.parsePath(path)
        startX,startY = float(simple_path[0][1][0]), float(simple_path[0][1][1])
        command = simple_path[0][0][0]
        
        yield startX, startY, command

        p = cubicsuperpath.parsePath(path)
                
        if mat:
            simpletransform.applyTransformToPath(mat, p)

        commandPile = []

        for sp in p:
                cspsubdiv.subdiv( sp, flatness)
                for csp in sp:
                    ctrl_pt1 = csp[0]
                    ctrl_pt2 = csp[1]
                    end_pt = csp[2]
                    command = csp[-1]
                    commandPile.append(command)
                    
                    yield end_pt[0], end_pt[1], command
                    rirCount += 1
Beispiel #3
0
    def effect(self):
        for id, node in self.selected.iteritems():
            if node.tagName == 'path':
                self.group = self.document.createElement('svg:g')
                node.parentNode.appendChild(self.group)
                new = self.document.createElement('svg:path')
                
                try:
                    t = node.attributes.getNamedItem('transform').value
                    self.group.setAttribute('transform', t)
                except AttributeError:
                    pass

                s = simplestyle.parseStyle(node.attributes.getNamedItem('style').value)
                s['stroke-linecap']='round'
                s['stroke-width']=self.options.dotsize
                new.setAttribute('style', simplestyle.formatStyle(s))

                a =[]
                p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
                num = 1
                for cmd,params in p:
                    if cmd != 'Z':
                        a.append(['M',params[-2:]])
                        a.append(['L',params[-2:]])
                        self.addText(self.group,params[-2],params[-1],num)
                        num += 1
                new.setAttribute('d', simplepath.formatPath(a))
                self.group.appendChild(new)
                node.parentNode.removeChild(node)
Beispiel #4
0
    def effect(self):
        for id, node in self.selected.iteritems():
            if node.tag == inkex.addNS('path','svg'):
                p = simplepath.parsePath(node.get('d'))
                a =[]
                pen = None
                subPathStart = None
                for cmd,params in p:
                    if cmd == 'C':
                        a.extend([['M', params[:2]], ['L', pen],
                            ['M', params[2:4]], ['L', params[-2:]]])
                    if cmd == 'Q':
                        a.extend([['M', params[:2]], ['L', pen],
                            ['M', params[:2]], ['L', params[-2:]]])
                    
                    if cmd == 'M':
                        subPathStart = params

                    if cmd == 'Z':
                        pen = subPathStart
                    else:
                        pen = params[-2:]
                    
                if len(a) > 0:
                    s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px', 
                        'stroke-opacity': '1.0', 'fill-opacity': '1.0', 
                        'stroke': '#000000', 'stroke-linecap': 'butt', 
                        'fill': 'none'}
                    attribs = {'style':simplestyle.formatStyle(s),'d':simplepath.formatPath(a)}
                    inkex.etree.SubElement(node.getparent(), inkex.addNS('path','svg'), attribs)
Beispiel #5
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)
Beispiel #6
0
    def path_bounding_box(self, elem, parent_transform=None):
        """ Returns [min_x, min_y], [max_x, max_y] of the transformed
            element. (It doesn't make any sense to return the untransformed
            bounding box, with the intent of transforming it later, because
            the min/max points will be completely different points)
            
            The returned bounding box includes stroke-width offset.
            
            This function uses a simplistic algorithm & doesn't take curves
            or arcs into account, just node positions.
        """
        # If we have a Live Path Effect, modify original-d. If anyone clamours
        # for it, we could make an option to ignore paths with Live Path Effects
        original_d = '{%s}original-d' % inkex.NSS['inkscape']
        path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib['d']))

        transform = self.transform(elem, parent_transform=parent_transform)
        offset = self.elem_offset(elem, parent_transform)
        
        min_x = min_y = max_x = max_y = 0
        for i in range(len(path)):
            x, y = self.pathxy(path, i)
            x, y = transform_point(transform, (x, y))
            
            if i == 0:
                min_x = max_x = x
                min_y = max_y = y
            else:
                min_x = min(x, min_x)
                min_y = min(y, min_y)
                max_x = max(x, max_x)
                max_y = max(y, max_y)
        
        return (min_x-offset, min_y-offset), (max_x+offset, max_y+offset)
   def plotPath(self, node, matTransform):
      """ Plot the path while applying the transformation defined by the matrix matTransform. """

      filledPath = (simplestyle.parseStyle(node.get("style")).get("fill", "none") != "none")

      # Plan: Turn this path into a cubicsuperpath (list of beziers)...
      d = node.get("d")
      if len(simplepath.parsePath(d)) == 0:
         return
      p = cubicsuperpath.parsePath(d)

      # ... and apply the transformation to each point.
      simpletransform.applyTransformToPath(matTransform, p)

      # p is now a list of lists of cubic beziers [cp1, cp2, endp]
      # where the start-point is the last point of the previous segment.
      # For some reason the inkscape extensions uses csp[1] as the coordinates of each point,
      # but that makes it seem like they are using control point 2 as line points.
      # Maybe that is a side-effect of the CSP subdivion process? TODO
      realPoints = []
      for sp in p:
         cspsubdiv.subdiv(sp, self.smoothness)
         for csp in sp:
            realPoints.append( (csp[1][0], csp[1][1]) )

      self.rawObjects.append( (filledPath, realPoints) )
Beispiel #8
0
 def effect(self):
     for id, node in self.selected.iteritems():
         if node.tag == inkex.addNS('path', 'svg'):
             d = node.get('d')
             p = simplepath.parsePath(d)
             last = []
             subPathStart = []
             for cmd, params in p:
                 if cmd == 'C':
                     if self.options.behave <= 1:
                         #shorten handles towards end points
                         params[:2] = pointAtPercent(
                             params[:2], last[:], self.options.percent)
                         params[2:4] = pointAtPercent(
                             params[2:4], params[-2:], self.options.percent)
                     else:
                         #shorten handles towards thirds of the segment
                         dest1 = pointAtPercent(last[:], params[-2:], 33.3)
                         dest2 = pointAtPercent(params[-2:], last[:], 33.3)
                         params[:2] = pointAtPercent(
                             params[:2], dest1[:], self.options.percent)
                         params[2:4] = pointAtPercent(
                             params[2:4], dest2[:], self.options.percent)
                 elif cmd == 'Q':
                     dest = pointAtPercent(last[:], params[-2:], 50)
                     params[:2] = pointAtPercent(params[:2], dest,
                                                 self.options.percent)
                 if cmd == 'M':
                     subPathStart = params[-2:]
                 if cmd == 'Z':
                     last = subPathStart[:]
                 else:
                     last = params[-2:]
             node.set('d', simplepath.formatPath(p))
Beispiel #9
0
def convert_element_to_path(node):
    """Convert an SVG element into a simplepath.
    
    This handles paths, rectangles, circles, ellipses, lines, and polylines.
    Anything else raises and exception.
    """    
    node_tag = get_node_tag(node) # node tag stripped of namespace part
        
    if node_tag == 'path':
        return simplepath.parsePath(node.get('d'))
    elif node_tag == 'rect':
        return convert_rect_to_path(node)
    elif node_tag == 'line':
        return convert_line_to_path(node)
    elif node_tag == 'circle':
        return convert_circle_to_path(node)
    elif node_tag == 'ellipse':
        return convert_ellipse_to_path(node)    
    elif node_tag == 'polyline':
        return convert_polyline_to_path(node)    
    elif node_tag == 'polygon':
        return convert_polygon_to_path(node)
    elif node_tag == 'text':
        raise Exception(_('Unable to convert text; please convert text to paths first.'))
    elif node_tag == 'image':
        raise Exception(_('Unable to convert bitmap images; please convert them to line art first.'))
    else:
        raise Exception(_('Unable to convert this SVG element to a path: <%s>') % (node.tag))
Beispiel #10
0
  def load(self, node, mat):
    #JiB
    #split the syle in separate tuples and assign to path
    s = node.get('style')
    if s: 
      self.style = s
      for item in s.split(';'):
        attribute , value = item.split(':')
        #print attribute, value
        value = value.replace('px', '')
        setattr(self, attribute.replace('-','') , value)
        #print getattr(self, attribute.replace('-','') )
      #print ";" + self.strokewidth
        #print attribute.replace('-','')
    d = node.get('d')
    if len(simplepath.parsePath(d)) == 0:
      return
    p = cubicsuperpath.parsePath(d)
    applyTransformToPath(mat, p)

    # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint]
    # where the start-point is the last point in the previous segment
    self.segments = []
    for sp in p:
      points = []
      subdivideCubicPath(sp,0.2)  # TODO: smoothness preference
      for csp in sp:
        points.append((csp[1][0],csp[1][1]))
      self.segments.append(points)
Beispiel #11
0
    def addDot(self, node):
        self.group = inkex.etree.SubElement(node.getparent(), inkex.addNS("g", "svg"))
        self.dotGroup = inkex.etree.SubElement(self.group, inkex.addNS("g", "svg"))
        self.numGroup = inkex.etree.SubElement(self.group, inkex.addNS("g", "svg"))

        try:
            t = node.get("transform")
            self.group.set("transform", t)
        except:
            pass

        style = simplestyle.formatStyle({"stroke": "none", "fill": "#000"})
        a = []
        p = simplepath.parsePath(node.get("d"))

        self.separateLastAndFirst(p)

        num = self.options.start
        for cmd, params in p:
            if cmd != "Z" and cmd != "z":
                dot_att = {
                    "style": style,
                    "r": str(inkex.unittouu(self.options.dotsize) / 2),
                    "cx": str(params[-2]),
                    "cy": str(params[-1]),
                }
                inkex.etree.SubElement(self.dotGroup, inkex.addNS("circle", "svg"), dot_att)
                self.addText(
                    self.numGroup,
                    params[-2] + (inkex.unittouu(self.options.dotsize) / 2),
                    params[-1] - (inkex.unittouu(self.options.dotsize) / 2),
                    num,
                )
                num += self.options.step
        node.getparent().remove(node)
    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)
    def effect(self):
        for id, node in self.selected.iteritems():
            if node.tag == inkex.addNS('path', 'svg'):
                self.group = inkex.etree.SubElement(node.getparent(),
                                                    inkex.addNS('g', 'svg'))
                new = inkex.etree.SubElement(self.group,
                                             inkex.addNS('path', 'svg'))

                try:
                    t = node.get('transform')
                    self.group.set('transform', t)
                except:
                    pass

                s = simplestyle.parseStyle(node.get('style'))
                s['stroke-linecap'] = 'round'
                s['stroke-width'] = self.options.dotsize
                new.set('style', simplestyle.formatStyle(s))

                a = []
                p = simplepath.parsePath(node.get('d'))
                num = 1
                for cmd, params in p:
                    if cmd != 'Z':
                        a.append(['M', params[-2:]])
                        a.append(['L', params[-2:]])
                        self.addText(self.group, params[-2], params[-1], num)
                        num += 1
                new.set('d', simplepath.formatPath(a))
                node.clear()
Beispiel #14
0
    def get_start_end(self, node):
        """Given a node, return the start and end points"""
        if node.tag != inkex.addNS('path', 'svg'):
            inkex.errormsg(
                "Groups are not supported, please ungroup for better results")
            return (0, 0, 0, 0)

        d = node.get('d')
        sp = simplepath.parsePath(d)

        # simplepath converts coordinates to absolute and cleans them up, but
        # these are still some big assumptions here, are they always valid? TODO
        startX = sp[0][1][0]
        startY = sp[0][1][1]
        if sp[-1][0] == 'Z':
            # go back to start
            endX = startX
            endY = startY
        else:
            endX = sp[-1][1][-2]
            endY = sp[-1][1][-1]

        transform = node.get('transform')
        if transform:
            transform = simpletransform.parseTransform(transform)

        sx, sy = conv(startX, startY, transform)
        ex, ey = conv(endX, endY, transform)
        return (sx, sy, ex, ey)
Beispiel #15
0
    def snap_path_scale(self, elem, parent_transform=None):
        # If we have a Live Path Effect, modify original-d. If anyone clamours
        # for it, we could make an option to ignore paths with Live Path Effects
        original_d = '{%s}original-d' % inkex.NSS['inkscape']
        path = simplepath.parsePath(
            elem.attrib.get(original_d, elem.attrib['d']))
        transform = self.transform(elem, parent_transform=parent_transform)
        min_xy, max_xy = self.path_bounding_box(elem, parent_transform)

        width = max_xy[0] - min_xy[0]
        height = max_xy[1] - min_xy[1]

        # 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 (width == 0 or height == 0): return

        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)):
            self.transform_path_node([[1, 0, -min_xy[0]], [0, 1, -min_xy[1]]],
                                     path, i)  # center transform
            self.transform_path_node([[rescale[0], 0, 0], [0, rescale[1], 0]],
                                     path, i)
            self.transform_path_node([[1, 0, +min_xy[0]], [0, 1, +min_xy[1]]],
                                     path, i)  # uncenter transform

        path = simplepath.formatPath(path)
        if original_d in elem.attrib: elem.attrib[original_d] = path
        else: elem.attrib['d'] = path
Beispiel #16
0
    def load(self, node, mat):
        #JiB
        #split the syle in separate tuples and assign to path
        s = node.get('style')
        if s:
            self.style = s
            for item in s.split(';'):
                attribute, value = item.split(':')
                #print attribute, value
                value = value.replace('px', '')
                setattr(self, attribute.replace('-', ''), value)
                #print getattr(self, attribute.replace('-','') )
            #print ";" + self.strokewidth
            #print attribute.replace('-','')
        d = node.get('d')
        if len(simplepath.parsePath(d)) == 0:
            return
        p = cubicsuperpath.parsePath(d)
        applyTransformToPath(mat, p)

        # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint]
        # where the start-point is the last point in the previous segment
        self.segments = []
        for sp in p:
            points = []
            subdivideCubicPath(sp, 0.2)  # TODO: smoothness preference
            for csp in sp:
                points.append((csp[1][0], csp[1][1]))
            self.segments.append(points)
Beispiel #17
0
	def effect(self):
		totalPathCoords = []

		for node in self.document.getroot().iter():
			if node.tag == '{http://www.w3.org/2000/svg}path': # TODO: Ugly
				d = node.get('d')
				path = parsePath(d)

                pathCoords = []
				for point in path:
					x = point[1][0]
					y = point[1][1]
					pathCoords.append([x, y])

				revPathCoords = pathCoords[:] # TODO: Ugly
				revPathCoords.reverse()

				if isInTotalPaths(pathCoords, totalPathCoords, self.options.radius):
					inkex.debug("I WANT TO BREAK FREE")
					node.getparent().remove(node)
				elif self.options.reverse and isInTotalPaths(revPathCoords, totalPathCoords, self.options.radius):
					inkex.debug("I WANT TO BREAK FREE")
					node.getparent().remove(node)
				else:
					totalPathCoords.append(pathCoords)
Beispiel #18
0
    def snap_path_scale(self, elem, parent_transform=None):
        # If we have a Live Path Effect, modify original-d. If anyone clamours
        # for it, we could make an option to ignore paths with Live Path Effects
        original_d = "{%s}original-d" % inkex.NSS["inkscape"]
        path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib["d"]))
        transform = self.transform(elem, parent_transform=parent_transform)
        min_xy, max_xy = self.path_bounding_box(elem, parent_transform)

        width = max_xy[0] - min_xy[0]
        height = max_xy[1] - min_xy[1]

        # 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 width == 0 or height == 0:
            return

        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)):
            self.transform_path_node([[1, 0, -min_xy[0]], [0, 1, -min_xy[1]]], path, i)  # center transform
            self.transform_path_node([[rescale[0], 0, 0], [0, rescale[1], 0]], path, i)
            self.transform_path_node([[1, 0, +min_xy[0]], [0, 1, +min_xy[1]]], path, i)  # uncenter transform

        path = simplepath.formatPath(path)
        if original_d in elem.attrib:
            elem.attrib[original_d] = path
        else:
            elem.attrib["d"] = path
    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 convertToSegments(cls, path_node):
        path_start = None
        currentPoint = None

        # work on copy to be shure not breaking anything
        path = copy.deepcopy(path_node)

        # apply transformation info on path, otherwise dealing with transform would be a mess
        simpletransform.fuseTransform(path)

        for cmd, params in simplepath.parsePath(path.get('d')):
            print_('cmd, params', cmd, params)
            if cmd == 'M':
                if(path_start is None):
                    path_start = params
                currentPoint = params

            elif cmd == 'L':
                yield Segment(currentPoint, params)
                currentPoint = params

            elif cmd in ['A', 'Q', 'C']:
                yield Segment(currentPoint, params[-2:], command=cmd, extra_parameters=params[:-2])
                currentPoint = params[-2:]

            elif (cmd == 'Z'):
                # Z is a line between the last point and the start of the shape
                yield Segment(currentPoint, path_start)
                currentPoint = None
                path_start = None

            else:
                inkex.errormsg("Path Command %s not managed Yet" % cmd)
Beispiel #21
0
    def load(self, node, mat):
        a = node.get('style').split(";")
        d = dict(s.split(':') for s in a)
        if d['stroke'] == "#ff0000":
            self.cutStyle = 2
        elif d['stroke'] == "#0000ff":
            self.cutStyle = 3
        else:
            self.cutStyle = 1

        d = node.get('d')
        if len(simplepath.parsePath(d)) == 0:
            return
        p = cubicsuperpath.parsePath(d)
        applyTransformToPath(mat, p)

        # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint]
        # where the start-point is the last point in the previous segment
        self.segments = []
        for sp in p:
            points = []
            subdivideCubicPath(sp, 0.2)  # TODO: smoothness preference
            for csp in sp:
                points.append((csp[1][0], csp[1][1]))
            self.segments.append(points)
Beispiel #22
0
def get_n_points_from_path( node, n):#returns a list of first n points (x,y) in an SVG path-representing node

    p = simplepath.parsePath(node.get('d')) #parse the path
    
    xi = [] #temporary storage for x and y (will combine at end)
    yi = []
    
    for cmd,params in p:                    #a parsed path is made up of (cmd, params) pairs
        defs = simplepath.pathdefs[cmd]
        for i in range(defs[1]):
            if   defs[3][i] == 'x' and len(xi) < n:#only collect the first three
                xi.append(params[i])
            elif defs[3][i] == 'y' and len(yi) < n:#only collect the first three
                yi.append(params[i])

    if len(xi) == n and len(yi) == n:
        points = [] # returned pairs of points
        for i in range(n):
            xi[i] = Draw_From_Triangle.unittouu(e, str(xi[i]) + 'px')
            yi[i] = Draw_From_Triangle.unittouu(e, str(yi[i]) + 'px')
            points.append( [ xi[i], yi[i] ] )
    else:
        #inkex.errormsg(_('Error: Not enough nodes to gather coordinates.')) #fail silently and exit, rather than invoke an error console
        return [] #return a blank
        
    return points
    def snap_path_scale(self, elem, parent_transform=None):
        # If we have a Live Path Effect, modify original-d. If anyone clamours
        # for it, we could make an option to ignore paths with Live Path Effects
        original_d = '{%s}original-d' % inkex.NSS['inkscape']
        path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib['d']))
        transform = self.transform(elem, parent_transform=parent_transform)
        min_xy, max_xy = self.path_bounding_box(elem, parent_transform)
        
        width = max_xy[0] - min_xy[0]
        height = max_xy[1] - min_xy[1]
        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)):
            self.transform_path_node([[1, 0, -min_xy[0]], [0, 1, -min_xy[1]]], path, i)     # center transform
            self.transform_path_node([[rescale[0], 0, 0],
                                       [0, rescale[1], 0]],
                                       path, i)
            self.transform_path_node([[1, 0, +min_xy[0]], [0, 1, +min_xy[1]]], path, i)     # uncenter transform
        
        path = simplepath.formatPath(path)
        if original_d in elem.attrib: elem.attrib[original_d] = path
        else: elem.attrib['d'] = path
    def effect(self):
        for id, node in self.selected.iteritems():
            if node.tag == inkex.addNS('path','svg'):
                self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('g','svg'))
                new = inkex.etree.SubElement(self.group,inkex.addNS('path','svg'))
                
                try:
                    t = node.get('transform')
                    self.group.set('transform', t)
                except:
                    pass

                s = simplestyle.parseStyle(node.get('style'))
                s['stroke-linecap']='round'
                s['stroke-width']=self.options.dotsize
                new.set('style', simplestyle.formatStyle(s))

                a =[]
                p = simplepath.parsePath(node.get('d'))
                num = 1
                for cmd,params in p:
                    if cmd != 'Z':
                        a.append(['M',params[-2:]])
                        a.append(['L',params[-2:]])
                        self.addText(self.group,params[-2],params[-1],num)
                        num += 1
                new.set('d', simplepath.formatPath(a))
                node.clear()
Beispiel #25
0
    def snap_path_pos(self, elem, parent_transform=None):
        """ Goes through each node in the given path and modifies it as
            necessary in order to shift the entire path by the required
            (calculated) distance.
        """

        # If we have a Live Path Effect, modify original-d. If anyone clamours
        # for it, we could make an option to ignore paths with Live Path Effects
        original_d = '{%s}original-d' % inkex.NSS['inkscape']
        path = simplepath.parsePath(
            elem.attrib.get(original_d, elem.attrib['d']))
        transform = self.get_transform(elem, parent_transform)
        min_xy, max_xy = self.path_bounding_box(elem, parent_transform)

        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(
                [[1, 0, -fractional_offset[0]], [0, 1, -fractional_offset[1]]],
                path, i)

        path = simplepath.formatPath(path)
        if original_d in elem.attrib: elem.attrib[original_d] = path
        else: elem.attrib['d'] = path
    def movePath(self, node, x, y, origin):
        tagName = self.getTagName(node)

        if tagName != "path":
            inkex.debug('movePath only works on SVG Path elements. Argument was of type "' + tagName + '"')
            return False

        path = simplepath.parsePath(node.get("d"))
        id = node.get("id")

        box = list(simpletransform.computeBBox([node]))

        offset_x = box[0] - x
        offset_y = box[2] - (y)

        for cmd in path:
            params = cmd[1]
            i = 0

            while i < len(params):
                if i % 2 == 0:
                    # inkex.debug('x point at ' + str( round( params[i] )))
                    params[i] = params[i] - offset_x
                    # inkex.debug('moved to ' + str( round( params[i] )))
                else:
                    # inkex.debug('y point at ' + str( round( params[i]) ))
                    params[i] = params[i] - offset_y
                    # inkex.debug('moved to ' + str( round( params[i] )))
                i = i + 1

        return simplepath.formatPath(path)
Beispiel #27
0
def readTangents(nid, aSize=0.1, doPrint=False):
    el = e.getElementById(nid)
    if el is None:
        print "Cant find ", nid
        return
    points, svgL = shapereco.toArray(simplepath.parsePath(el.get('d')))
    #print points
    tg = shapereco.buildTangents(points)
    res = e.checkForCircle(points, tg)
    e.points = points
    e.tg = tg
    (deltasD, angles, fits, dAdD) = e.temp
    #clList=shapereco.clusterValues(angles,aSize,refScaleAbs='abs')
    #clList.sort(key=lambda cl:len(cl))
    #print [len(cl) for cl in clList]
    #print (len(clList[-1])+len(clList[-2]))/float(len(angles))
    #print res
    deltasDD = (deltasD[1:] - deltasD[:-1])

    belowT, count = True, 0
    x, y, w, h = shapereco.computeBox(points)
    for i, v in enumerate(dAdD):
        if v > 6 and belowT:
            count += 1
            belowT = False
        belowT = (v < 6)

    if doPrint:
        print 'deltasD ', deltasD
        print 'deltasDD ', deltasDD
        #print 'dist to fit=', dist_to_fit
    return deltasD[-1] / 3.14, count, numpy.sum(
        deltasDD[numpy.where(dAdD < 0.3)]) / (deltasD[-1] - deltasD[0])
Beispiel #28
0
 def effect(self):
     for id, node in self.selected.iteritems():
         if node.tag == inkex.addNS('path', 'svg'):
             d = node.get('d')
             p = simplepath.parsePath(d)
             last = []
             subPathStart = []
             for cmd,params in p:
                 if cmd == 'C':
                     if self.options.behave <= 1:
                         #shorten handles towards end points
                         params[:2] = pointAtPercent(params[:2],last[:],self.options.percent)    
                         params[2:4] = pointAtPercent(params[2:4],params[-2:],self.options.percent)
                     else:
                         #shorten handles towards thirds of the segment                            
                         dest1 = pointAtPercent(last[:],params[-2:],33.3)
                         dest2 = pointAtPercent(params[-2:],last[:],33.3)
                         params[:2] = pointAtPercent(params[:2],dest1[:],self.options.percent)    
                         params[2:4] = pointAtPercent(params[2:4],dest2[:],self.options.percent)
                 elif cmd == 'Q':
                     dest = pointAtPercent(last[:],params[-2:],50)
                     params[:2] = pointAtPercent(params[:2],dest,self.options.percent)
                 if cmd == 'M':
                     subPathStart = params[-2:]
                 if cmd == 'Z':
                     last = subPathStart[:]
                 else:
                     last = params[-2:]
             node.set('d',simplepath.formatPath(p))
Beispiel #29
0
    def path_bounding_box(self, elem, parent_transform=None):
        """ Returns [min_x, min_y], [max_x, max_y] of the transformed
            element. (It doesn't make any sense to return the untransformed
            bounding box, with the intent of transforming it later, because
            the min/max points will be completely different points)
            
            The returned bounding box includes stroke-width offset.
            
            This function uses a simplistic algorithm & doesn't take curves
            or arcs into account, just node positions.
        """
        # If we have a Live Path Effect, modify original-d. If anyone clamours
        # for it, we could make an option to ignore paths with Live Path Effects
        original_d = "{%s}original-d" % inkex.NSS["inkscape"]
        path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib["d"]))

        transform = self.transform(elem, parent_transform=parent_transform)
        offset = self.elem_offset(elem, parent_transform)

        min_x = min_y = max_x = max_y = 0
        for i in range(len(path)):
            x, y = self.pathxy(path, i)
            x, y = transform_point(transform, (x, y))

            if i == 0:
                min_x = max_x = x
                min_y = max_y = y
            else:
                min_x = min(x, min_x)
                min_y = min(y, min_y)
                max_x = max(x, max_x)
                max_y = max(y, max_y)

        return (min_x - offset, min_y - offset), (max_x + offset, max_y + offset)
    def parseArc(self,node,parent):

        #self.parsing_context = 'arc'

        style = node.get('style')
        style = self.parseStyleAttribute(style)

        arc = {
            'id':node.get('id',''),
            'svg':'arc',
            'label':str(node.get(inkex.addNS('label', 'inkscape'),'')),
            'cx': node.get(inkex.addNS('cx', 'sodipodi'),''),
            'cy':node.get(inkex.addNS('cy', 'sodipodi'),''),
            'rx':node.get(inkex.addNS('rx', 'sodipodi'),''),
            'ry':node.get(inkex.addNS('ry', 'sodipodi'),''),
            'path':simplepath.parsePath(node.get('d')),
            'd':node.get('d',''),
            'box':list(simpletransform.computeBBox([node])),
            'fill':style.get('fill',''),
            'fill-opacity':style.get('fillOpacity',''),
            'stroke':style.get('stroke',''),
            'stroke-width':style.get('strokeWidth',''),
            'stroke-opacity':style.get('strokeOpacity',''),
            'transform':node.get('transform','')
        }


        if(self.reposition):
            arc['path'] = self.movePath(node,0,0,'tl')
        else:
            arc['path'] = arc['d']

        parent.append(arc)
def getCubicSuperPath(d = None):
    if(CommonDefs.inkVer == 1.0):
        if(d == None): return CubicSuperPath([])
        return CubicSuperPath(Path(d).to_superpath())
    else:
        if(d == None): return []
        return CubicSuperPath(simplepath.parsePath(d))
Beispiel #32
0
def pathdata_last_point(path):
    '''
    Return the last (X,Y) point from an SVG path data string
    
    Input:  A path data string; the text of the 'd' attribute of an SVG path
    Output: Two floats in a list representing the x and y coordinates of the last point
    '''

    command, params = simplepath.parsePath(path)[
        -1]  # parsePath splits path into segments

    if command.upper() == 'Z':
        return pathdata_first_point(path)  # Trivial case
    '''
    Otherwise: The last command should be in the set 'MLCQA'
        - All commands converted to absolute by parsePath.
        - Can ignore Z (case handled)
        - Can ignore H,V, since those are converted to L by parsePath.
        - Can ignore S, converted to C by parsePath.
        - Can ignore T, converted to Q by parsePath.
        
        MLCQA: Commands all ending in (X,Y) pair. 
    '''

    x_val = params[-2]  # Second to last parameter given
    y_val = params[-1]  # Last parameter given

    return [x_val, y_val]
Beispiel #33
0
    def effect(self):
        for id, node in self.selected.iteritems():
            if node.tagName == 'path':
                p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
                a =[]
                pen = None
                subPathStart = None
                for cmd,params in p:
                    if cmd == 'C':
                        a.extend([['M', params[:2]], ['L', pen],
                            ['M', params[2:4]], ['L', params[-2:]]])
                    if cmd == 'Q':
                        a.extend([['M', params[:2]], ['L', pen],
                            ['M', params[:2]], ['L', params[-2:]]])
                    
                    if cmd == 'M':
                        subPathStart = params

                    if cmd == 'Z':
                        pen = subPathStart
                    else:
                        pen = params[-2:]
                    
                if len(a) > 0:
                    new = self.document.createElement('svg:path')
                    s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px', 
                        'stroke-opacity': '1.0', 'fill-opacity': '1.0', 
                        'stroke': '#000000', 'stroke-linecap': 'butt', 
                        'fill': 'none'}
                    new.setAttribute('style', simplestyle.formatStyle(s))
                    new.setAttribute('d', simplepath.formatPath(a))
                    node.parentNode.appendChild(new)
Beispiel #34
0
def path_to_segments(node, smoothness=0.1):
    '''
        Generator to convert a path node to an interator on
        segmented paths (bezier curves broken to approximated
        straights lines).
    '''
    mat = simpletransform.composeParents(node,
                                         [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
    d = node.get('d')

    if len(simplepath.parsePath(d)) == 0:
        return

    p = cubicsuperpath.parsePath(d)
    simpletransform.applyTransformToPath(mat, p)

    # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint]
    # where the start-point is the last point in the previous segment

    for sp in p:
        path = []
        subdivideCubicPath(sp, smoothness)
        for csp in sp:
            path.append([csp[1][0], csp[1][1]])
        yield path
Beispiel #35
0
    def effect(self):
        if len(self.options.ids) < 2:
            raise Exception, "Two paths must be selected. The 1st is the letter, the 2nd is the envelope and must have 4 sides."
            exit()

        letterElement = self.selected[self.options.ids[0]]
        envelopeElement = self.selected[self.options.ids[1]]

        if letterElement.tag != inkex.addNS(
                'path', 'svg') or envelopeElement.tag != inkex.addNS(
                    'path', 'svg'):
            raise Exception, "Both letter and envelope must be SVG paths."
            exit()

        axes = extractMorphAxes(simplepath.parsePath(envelopeElement.get('d')))
        if axes is None:
            raise Exception, "No axes found on envelope."
        axisCount = len(axes)
        if axisCount < 4:
            raise Exception, "The envelope path has less than 4 segments."
        for i in range(0, 4):
            if axes[i] is None:
                raise Exception, "axes[%i] is None" % i
        # morph the enveloped element according to the axes
        morphElement(letterElement, envelopeElement, axes)
    def effect(self):
        for id, node in self.selected.iteritems():
            if node.tag == inkex.addNS('path', 'svg'):
                d = node.get('d')
                p = simplepath.parsePath(d)

                a = []
                first = 1
                for cmd, params in p:
                    if cmd != 'Z':
                        if first == 1:
                            x1 = params[-2]
                            y1 = params[-1]
                            a.append(['M', params[-2:]])
                            first = 2
                        else:
                            x2 = params[-2]
                            y2 = params[-1]
                            self.fractalize(a, x1, y1, x2, y2,
                                            self.options.subdivs,
                                            self.options.smooth)
                            x1 = x2
                            y1 = y2
                            a.append(['L', params[-2:]])

                node.set('d', simplepath.formatPath(a))
Beispiel #37
0
def get_n_points_from_path(
    node, n
):  #returns a list of first n points (x,y) in an SVG path-representing node

    p = simplepath.parsePath(node.get('d'))  #parse the path

    xi = []  #temporary storage for x and y (will combine at end)
    yi = []

    for cmd, params in p:  #a parsed path is made up of (cmd, params) pairs
        defs = simplepath.pathdefs[cmd]
        for i in range(defs[1]):
            if defs[3][i] == 'x' and len(
                    xi) < n:  #only collect the first three
                xi.append(params[i])
            elif defs[3][i] == 'y' and len(
                    yi) < n:  #only collect the first three
                yi.append(params[i])

    if len(xi) == n and len(yi) == n:
        points = []  # returned pairs of points
        for i in range(n):
            points.append([xi[i], yi[i]])
    else:
        #inkex.errormsg(_('Error: Not enough nodes to gather coordinates.')) #fail silently and exit, rather than invoke an error console
        return []  #return a blank

    return points
Beispiel #38
0
	def plotPath( self, path, matTransform ):
		'''
		Plot the path while applying the transformation defined
		by the matrix [matTransform].
		'''
		# turn this path into a cubicsuperpath (list of beziers)...

		d = path.get( 'd' )

		if len( simplepath.parsePath( d ) ) == 0:
			return

		p = cubicsuperpath.parsePath( d )

		# ...and apply the transformation to each point
		applyTransformToPath( matTransform, p )

		# p is now a list of lists of cubic beziers [control pt1, control pt2, endpoint]
		# where the start-point is the last point in the previous segment.
		for sp in p:

			plot_utils.subdivideCubicPath( sp, self.options.smoothness )
			nIndex = 0

			for csp in sp:

				if self.bStopped:
					return

				self.fX = 2 * float( csp[1][0] ) / self.step_scaling_factor
				self.fY = 2 * float( csp[1][1] ) / self.step_scaling_factor

				# store home
				if self.ptFirst is None:

					# if we should start at center, then the first line segment should draw from there
					if self.options.startCentered:
						self.fPrevX = self.svgWidth / ( self.step_scaling_factor )
						self.fPrevY = self.svgHeight / ( self.step_scaling_factor )

						self.ptFirst = ( self.fPrevX, self.fPrevY )
					else:
						self.ptFirst = ( self.fX, self.fY )
						
				if self.plotCurrentLayer:
					if nIndex == 0:
						if (plot_utils.distance(self.fX - self.fPrevX,self.fY - self.fPrevY) > eggbot_conf.MIN_GAP):
							# Only raise pen between two points if there is at least a 1 step gap between them.
							self.penUp()
							self.virtualPenIsUp = True
					elif nIndex == 1:
						self.penDown()
						self.virtualPenIsUp = False

				nIndex += 1

				if self.plotCurrentLayer:
					self.plotLineAndTime()
					self.fPrevX = self.fX
					self.fPrevY = self.fY
Beispiel #39
0
    def effect(self):
        """This is the main entry point"""

        # based partially on the restack.py extension
        if len(self.selected) > 0:
            # TODO check for non-path elements?
            # TODO it seems like the order of selection is not consistent
            # => self.selected is a dict so it has no meaningful order and should not be used to evaluate the original path length

            #fid = open("/home/matthew/debug.txt", "w")

            # for each selected item
            # I can think of two options:
            # 1. Iterate over all paths in root, then iterate over all layers, and their paths
            # 2. Some magic with xpath? (would this limit us to specific node types?)

            objlist = []
            for id, node in self.selected.iteritems():
                (sx, sy, ex, ey) = self.get_start_end(node)
                path = Path(id, (sx, sy), (ex, ey))
                objlist.append(path)

            # sort / order the objects
            sort_order, air_distance_default, air_distance_ordered = find_ordering(
                objlist, self.options.allowReverse)

            reverseCount = 0
            for path in sort_order:
                node = self.selected[path.id]
                if node.tag == inkex.addNS('path', 'svg'):
                    node_sp = simplepath.parsePath(node.get('d'))
                    if (path.reversed):
                        node_sp_string = reversePath(node_sp)
                        reverseCount += 1
                    else:
                        node_sp_string = simplepath.formatPath(node_sp)

                    node.set('d', node_sp_string)

                #keep in mind the different selected ids might have different parents
                self.getParentNode(node).append(node)

            inkex.errormsg("Reversed {} paths.".format(reverseCount))
            #fid.close()

            if air_distance_default > 0:  # don't divide by zero. :P
                improvement_pct = 100 * (
                    (air_distance_default - air_distance_ordered) /
                    (air_distance_default))
                inkex.errormsg(
                    gettext.gettext(
                        "Selected paths have been reordered and optimized for quicker EggBot plotting.\n\nDefault air-distance: %d\nOptimized air-distance: %d\nDistance reduced by: %1.2d%%\n\nHave a nice day!"
                        % (air_distance_default, air_distance_ordered,
                           improvement_pct)))
            else:
                inkex.errormsg(
                    gettext.gettext(
                        "Unable to start. Please select multiple distinct paths. :)"
                    ))
 def _handle_path(self, node):
     try:
         raw_path = node.get('d')
         p = simplepath.parsePath(raw_path)
     except:
         logging.warning('Failed to parse path %s, will ignore it', raw_path)
         p = None
     return p, []
Beispiel #41
0
def point_generator(path):

        if len(simplepath.parsePath(path)) == 0:
                return
       
        simple_path = simplepath.parsePath(path)
        startX,startY = float(simple_path[0][1][0]), float(simple_path[0][1][1])
        yield startX, startY

        p = cubicsuperpath.parsePath(path)
        for sp in p:
                cspsubdiv.subdiv( sp, .2 )
                for csp in sp:
                    ctrl_pt1 = csp[0]
                    ctrl_pt2 = csp[1]
                    end_pt = csp[2]
                    yield end_pt[0], end_pt[1],    
Beispiel #42
0
	def plotPath( self, path, matTransform ):
		'''
		Plot the path while applying the transformation defined
		by the matrix [matTransform].
		'''
		# turn this path into a cubicsuperpath (list of beziers)...

		d = path.get( 'd' )

		if len( simplepath.parsePath( d ) ) == 0:
			return

		p = cubicsuperpath.parsePath( d )

		# ...and apply the transformation to each point
		applyTransformToPath( matTransform, p )

		# p is now a list of lists of cubic beziers [control pt1, control pt2, endpoint]
		# where the start-point is the last point in the previous segment.
		for sp in p:

			plot_utils.subdivideCubicPath( sp, self.options.smoothness )
			nIndex = 0

			for csp in sp:

				if self.bStopped:
					return

				if self.plotCurrentLayer:
					if nIndex == 0:
						self.penUp()
						self.virtualPenIsUp = True
					elif nIndex == 1:
						self.penDown()
						self.virtualPenIsUp = False

				nIndex += 1

				self.fX = 2 * float( csp[1][0] ) / self.step_scaling_factor
				self.fY = 2 * float( csp[1][1] ) / self.step_scaling_factor

				# store home
				if self.ptFirst is None:

					# if we should start at center, then the first line segment should draw from there
					if self.options.startCentered:
						self.fPrevX = self.svgWidth / ( self.step_scaling_factor )
						self.fPrevY = self.svgHeight / ( self.step_scaling_factor )

						self.ptFirst = ( self.fPrevX, self.fPrevY )
					else:
						self.ptFirst = ( self.fX, self.fY )

				if self.plotCurrentLayer:
					self.plotLineAndTime()
					self.fPrevX = self.fX
					self.fPrevY = self.fY
    def effect(self):
        """ This method is called first, and sets up the self.commands list for later output. """
        svg = self.document.getroot()
        # find document width and height, used to scale down
        self.doc_width = inkex.unittouu(svg.get('width'))
        self.doc_height = inkex.unittouu(svg.get('height'))

        # add header
        self.commands.append("^DF;")
        self.commands.append("! 1;")
        self.commands.append("H;")
        self.commands.append("@ %d %d;" % (self.options.z_down, self.options.z_up))
        self.commands.append("V {0};F {0};\n".format(self.options.feed_rate_moving))
        self.commands.append("Z 0 0 %d;" % self.options.z_up)

        # mostly borrowed from hgpl_output.py
        lastX = 0
        lastY = 0

        # find paths in layers
        i = 0
        layerPath = '//svg:g[@inkscape:groupmode="layer"]'
        for layer in svg.xpath(layerPath, namespaces=inkex.NSS):
            i += 1

            nodePath = ('//svg:g[@inkscape:groupmode="layer"][%d]/descendant::svg:path') % i
            for node in svg.xpath(nodePath, namespaces=inkex.NSS):
                # these next lines added from this patch to fix the transformation issues - http://launchpadlibrarian.net/36269154/hpgl_output.py.patch
                # possibly also want to try this code: https://bugs.launchpad.net/inkscape/+bug/600472/+attachment/1475310/+files/hpgl_output.py
                transforms = node.xpath("./ancestor-or-self::svg:*[@transform]",namespaces=inkex.NSS)
                matrix = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
                for parenttransform in transforms:
                    newmatrix = simpletransform.parseTransform(parenttransform.get("transform"))
                    matrix = simpletransform.composeTransform(matrix, newmatrix)

                d = node.get('d')
                if len(simplepath.parsePath(d)):
                    p = cubicsuperpath.parsePath(d)
                    simpletransform.applyTransformToPath(matrix, p) # this line is also from the transform-fixing patch mentioned above
                    cspsubdiv.cspsubdiv(p, self.options.flat)
                    for sp in p:
                        first = True
                        for csp in sp:
                            if first:
                                x, y = self.conv_coords(csp[1][0], self.doc_height - csp[1][1])
                                self.commands.append("Z %d %d %d;" % (x, y, self.options.z_up))
                                self.commands.append("V {0};F {0};".format(self.options.feed_rate_cutting))
                            first = False
                            x, y = self.conv_coords(csp[1][0], self.doc_height - csp[1][1])
                            self.commands.append("Z %d %d %d;" % (x, y, self.options.z_down))
                            lastX = x
                            lastY = y
                        self.commands.append("V {0};F {0};".format(self.options.feed_rate_moving))
                        self.commands.append("Z %d %d %d;" % (lastX, lastY, self.options.z_up))

        self.commands.append("Z 0 0 %d;" % self.options.z_up)
        self.commands.append("H;")
def getTranslatedPath(d, posX, posY):
    if(CommonDefs.inkVer == 1.0):
        path = Path(d)
        path.translate(posX, posY, inplace = True)
        return path.to_superpath().__str__()
    else:
        path = simplepath.parsePath(d)
        simplepath.translatePath(path, posX, posY)
        return simplepath.formatPath(path)
Beispiel #45
0
    def effect(self):
        self.vx = math.cos(math.radians(
            self.options.angle)) * self.options.magnitude
        self.vy = math.sin(math.radians(
            self.options.angle)) * self.options.magnitude
        for id, node in self.selected.iteritems():
            if node.tag == inkex.addNS('path', 'svg'):
                group = inkex.etree.SubElement(node.getparent(),
                                               inkex.addNS('g', 'svg'))
                self.facegroup = inkex.etree.SubElement(
                    group, inkex.addNS('g', 'svg'))
                group.append(node)

                t = node.get('transform')
                if t:
                    group.set('transform', t)
                    node.set('transform', '')

                s = node.get('style')
                self.facegroup.set('style', s)

                p = simplepath.parsePath(node.get('d'))
                for cmd, params in p:
                    tees = []
                    if cmd == 'C':
                        bez = (last, params[:2], params[2:4], params[-2:])
                        tees = [
                            t for t in bezmisc.beziertatslope(
                                bez, (self.vy, self.vx)) if 0 < t < 1
                        ]
                        tees.sort()

                    segments = []
                    if len(tees) == 0 and cmd in ['L', 'C']:
                        segments.append([cmd, params[:]])
                    elif len(tees) == 1:
                        one, two = bezmisc.beziersplitatt(bez, tees[0])
                        segments.append([cmd, list(one[1] + one[2] + one[3])])
                        segments.append([cmd, list(two[1] + two[2] + two[3])])
                    elif len(tees) == 2:
                        one, two = bezmisc.beziersplitatt(bez, tees[0])
                        two, three = bezmisc.beziersplitatt(two, tees[1])
                        segments.append([cmd, list(one[1] + one[2] + one[3])])
                        segments.append([cmd, list(two[1] + two[2] + two[3])])
                        segments.append(
                            [cmd, list(three[1] + three[2] + three[3])])

                    for seg in segments:
                        self.makeface(last, seg)
                        last = seg[1][-2:]

                    if cmd == 'M':
                        subPathStart = params[-2:]
                    if cmd == 'Z':
                        last = subPathStart
                    else:
                        last = params[-2:]
Beispiel #46
0
 def __call__(self, elem):
     # logger.debug(elem.attrib)
     path = elem.get("d")
     if path is None:
         return []
     parsed = simplepath.parsePath(path)
     self.paths.append((parsed, elem))
     # logger.debug(parsed)
     return []
Beispiel #47
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
    def effect(self):
        clippingLineSegments = None
        pathTag = inkex.addNS('path', 'svg')
        groupTag = inkex.addNS('g', 'svg')
        error_messages = []
        for id in self.options.ids:  # the selection, top-down
            node = self.selected[id]
            if node.tag == pathTag:
                if clippingLineSegments is None:  # first path is the clipper
                    (clippingLineSegments,
                     errors) = self.simplepathToLineSegments(
                         simplepath.parsePath(node.get('d')))
                    error_messages.extend(
                        ['{}: {}'.format(id, err) for err in errors])
                else:
                    # do all the work!
                    segmentsToClip, errors = self.simplepathToLineSegments(
                        simplepath.parsePath(node.get('d')))
                    error_messages.extend(
                        ['{}: {}'.format(id, err) for err in errors])
                    clippedSegments = self.clipLineSegments(
                        segmentsToClip, clippingLineSegments)
                    if len(clippedSegments) != 0:
                        # replace the path
                        node.set(
                            'd',
                            simplepath.formatPath(
                                self.linesgmentsToSimplePath(clippedSegments)))
                    else:
                        # don't put back an empty path(?)  could perhaps put move, move?
                        inkex.debug(
                            'Object {} clipped to nothing, will not be updated.'
                            .format(node.get('id')))
            elif node.tag == groupTag:  # we don't look inside groups for paths
                inkex.debug(
                    'Group object {} will be ignored. Please ungroup before running the script.'
                    .format(id))
            else:  # something else
                inkex.debug(
                    'Object {} is not of type path ({}), and will be ignored. Current type "{}".'
                    .format(id, pathTag, node.tag))

        for error in error_messages:
            inkex.debug(error)
	def addPathVertices( self, path, node=None, transform=None, cloneTransform=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

		#if transform:
		#	simpletransform.applyTransformToPath( transform, p )

		# 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, float( 0.2 ) )
			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
				subpath_list.append( subpath_vertices )

		# Empty path?
		if len( subpath_list ) == 0:
			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] = cloneTransform
Beispiel #50
0
    def process_path(self, ipath, mat_x, mat_y, term1):
        mat = simpletransform.composeParents(
            ipath, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
        path_string = ipath.get('d')
        svg_path = simplepath.parsePath(path_string)

        paths = []

        # for path in svg_path:
        # inkex.debug("svg_path: " + str(svg_path))
        for path in svg_path:
            if path[0] == 'M' or path[0] == 'L':
                paths.append([path[0], [path[1]]])
            elif path[0] == 'C' or path[0] == 'Q':
                pts = []
                if path[0] == 'C':
                    num = 3
                else:
                    num = 2
                for i in range(0, num):
                    pt = [path[1][2 * i], path[1][2 * i + 1]]
                    pts.append(pt)
                paths.append([path[0], pts])

            elif path[0] == 'Z':
                paths.append(['Z', []])

        # inkex.debug("paths: " + str(paths) + "\n\n")
        mat = simpletransform.invertTransform(mat)
        # simpletransform.applyTransformToPath(mat, p)
        for path in paths:
            for pt in path[1]:
                simpletransform.applyTransformToPoint(mat, pt)

        # do transformation
        for path in paths:
            for pt in path[1]:
                self.project_point(pt, mat_x, mat_y, term1)

        # back to original form
        res_paths = []
        for path in paths:
            if path[0] == 'C' or path[0] == 'Q':
                flat_pts = []
                for pt in path[1]:
                    flat_pts.append(pt[0])
                    flat_pts.append(pt[1])
                res_paths.append([path[0], flat_pts])
            elif path[0] == 'M' or path[0] == 'L':
                res_paths.append([path[0], path[1][0]])
            elif path[0] == 'Z':
                res_paths.append(path)
        # inkex.debug("res_paths: " + str(res_paths))
        res_svg_paths = simplepath.formatPath(res_paths)
        # inkex.debug("res_svg_paths: " + str(res_svg_paths))
        ipath.set('d', res_svg_paths)
Beispiel #51
0
	def effect(self):
		linewidth=int(self.options.linewidth)
		# メインのルート要素であるSVGを取得
		svg = self.document.getroot()
		pathlist=svg.findall(ALL+"{"+inkex.NSS['svg']+"}path")

		for path in pathlist:
			if path == None:
				inkex.errormsg(u"パスを書いてください!!")
			#パスの頂点座標を取得
			vals=simplepath.parsePath(path.get('d'))
			bone=[]
			for cmd,vert in vals:
				#たまに空のが入ってるため、それ対策
				if len(vert) != 0:
					bone.append(Vertex(vert[0],vert[1]))
			outVertexArray=stripline(bone,linewidth,self.options.logfilename)

			pointer=0
			for t in range(len(outVertexArray)-2):
				tri=Triangle(outVertexArray[pointer][0],outVertexArray[pointer+1][0],outVertexArray[pointer+2][0])

				stripstr=tri.toSVG()
				color2="blue"
				if outVertexArray[pointer][1]:
					color="blue"
				else:
					color="red"
				pointer+=1
				attributes={"points":stripstr,
				"style":"fill:"+color2+";stroke:"+color2+";stroke-width:"+str(linewidth/3),"fill-opacity":"0.5"}
				pth =inkex.etree.Element("polygon",attributes)
				svg.append(pth)
			pointer=0
			#+−を示す点を描く
			for t in range(len(outVertexArray)):

				if outVertexArray[pointer][1]:
					point=Plus(outVertexArray[pointer][0].x,outVertexArray[pointer][0].y,linewidth/3)
					color="blue"
				else:
					point=Minus(outVertexArray[pointer][0].x,outVertexArray[pointer][0].y,linewidth/3)
					color="red"
				if pointer==0:
					color="#6f0018"#暗い赤
				point.appendToSVG(color,svg)
				#svg.append(Circle.toSVG(outVertexArray[pointer][0].x,outVertexArray[pointer][0].y,linewidth/3,color,0))
				pointer+=1
			pointer=0
			pathstr="M "
			for t in range(len(outVertexArray)):
				pathstr+=str(outVertexArray[pointer][0].x)+" "+str(outVertexArray[pointer][0].y)+" "
				pointer+=1

			att3={"d":pathstr,"r":"1","fill":"none","stroke-width":"1","stroke":"white"}
			pt=inkex.etree.Element("path",att3)
    def plotPath( self, path, matTransform ): # MIP
        '''
        Plot the path while applying the transformation defined
        by the matrix [matTransform].
        '''
        # turn this path into a cubicsuperpath (list of beziers)...

        d = path.get( 'd' )

        if len( simplepath.parsePath( d ) ) == 0:
            return

        p = cubicsuperpath.parsePath( d )

        # ...and apply the transformation to each point
        applyTransformToPath( matTransform, p )

        # p is now a list of lists of cubic beziers [control pt1, control pt2, endpoint]
        # where the start-point is the last point in the previous segment.
        for sp in p:

            subdivideCubicPath( sp, self.options.smoothness )
            nIndex = 0

            for csp in sp:
                if self.bStopped:
                    return

                if self.plotCurrentLayer:
                    if nIndex == 0: # Pen up to start of curve
                        self.ms.cmd_pen_up()
                        self.virtualPenIsUp = True
                    elif nIndex == 1: # Pen down to the end of the curve
                        self.ms.cmd_pen_down()
                        self.virtualPenIsUp = False

                nIndex += 1

                self.fX = float( csp[1][0] )
                self.fY = float( csp[1][1] )

                # Precondition: where the heck are we coming from?
                if self.ptFirst is None:
                    self.fPrevX = self.ms.area_x()
                    self.fPrevY = self.ms.area_y()

                    self.ptFirst = (self.fPrevX, self.fPrevY)


                if self.plotCurrentLayer:
                    self.plotLineAndTime()
                    self.fPrevX = self.fX
                    self.fPrevY = self.fY

            self.ms.cmd_pen_up() # Raise the pen at the end of each curve
    def load(self, node, mat):
        self.id = node.get('id')
        d = node.get('d')
        if len(simplepath.parsePath(d)) == 0:
            return
        p = cubicsuperpath.parsePath(d)
        applyTransformToPath(mat, p)

        # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint]
        # where the start-point is the last point in the previous segment
        self.points = []
        self.paths = []
        for sp in p:
            path = []
            subdivide_cubic_path(sp, 0.2)  # TODO: smoothness preference
            for csp in sp:
                point = [csp[1][0], csp[1][1]]
                if point not in self.points:
                    self.points.append(point)
                path.append(self.points.index(point))
            self.paths.append(path)

        # get color
        style = node.get('style')
        try:
            hexcolor = re.search('fill:#([0-9a-fA-f]{6})', style).group(1)
            rgb = [
                int(hexcolor[0:2], 16),
                int(hexcolor[2:4], 16),
                int(hexcolor[4:6], 16)
            ]
        except (TypeError, AttributeError):
            rgb = None

        # get optional opacity
        try:
            opacity = float(re.search('(?:^|;)opacity:([0-9]*\.?[0-9]+)', style).group(1))
        except (TypeError, AttributeError):
            opacity = 1.0

        # get optional fill-opacity (of course there is more than one way to set opacity of paths...)
        try:
            fill_opacity = float(re.search('(?:^|;)fill-opacity:([0-9]*\.?[0-9]+)', style).group(1))
        except (TypeError, AttributeError):
            fill_opacity = 1.0

        if rgb:
            self.color = [
                rgb[0] / 255.0,
                rgb[1] / 255.0,
                rgb[2] / 255.0,
                opacity * fill_opacity
            ]
        else:
            self.color = None
def loadPath(svgPath):
    extensionDir = os.path.normpath(os.path.join(os.getcwd(), os.path.dirname(sys.argv[0])))
    tree = inkex.etree.parse(extensionDir + "/" + svgPath)
    root = tree.getroot()
    pathElement = root.find("{http://www.w3.org/2000/svg}path")
    if pathElement == None:
        return None, 0, 0
    d = pathElement.get("d")
    width = float(root.get("width"))
    height = float(root.get("height"))
    return simplepath.parsePath(d), width, height  # Currently we only support a single path
Beispiel #55
0
def point_generator(path, mat, flatness):

        if len(simplepath.parsePath(path)) == 0:
                return
       
        simple_path = simplepath.parsePath(path)
        startX,startY = float(simple_path[0][1][0]), float(simple_path[0][1][1])
        yield startX, startY

        p = cubicsuperpath.parsePath(path)
        
        if mat:
            simpletransform.applyTransformToPath(mat, p)

        for sp in p:
                cspsubdiv.subdiv( sp, flatness)
                for csp in sp:
                    ctrl_pt1 = csp[0]
                    ctrl_pt2 = csp[1]
                    end_pt = csp[2]
                    yield end_pt[0], end_pt[1],    
Beispiel #56
0
    def effect(self):
        self.vx = math.cos(math.radians(self.options.angle))*self.options.magnitude
        self.vy = math.sin(math.radians(self.options.angle))*self.options.magnitude
        for id, node in self.selected.iteritems():
            if node.tagName == 'path':
                group = self.document.createElement('svg:g')
                self.facegroup = self.document.createElement('svg:g')
                node.parentNode.appendChild(group)
                group.appendChild(self.facegroup)
                group.appendChild(node)
                
                try:
                    t = node.attributes.getNamedItem('transform').value
                    group.setAttribute('transform', t)
                    node.attributes.getNamedItem('transform').value=""
                except AttributeError:
                    pass

                s = node.attributes.getNamedItem('style').value
                self.facegroup.setAttribute('style', s)

                p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
                for cmd,params in p:
                    tees = []
                    if cmd == 'C':
                        bez = (last,params[:2],params[2:4],params[-2:])
                        tees = [t for t in bezmisc.beziertatslope(bez,(self.vy,self.vx)) if 0<t<1]
                        tees.sort()

                    segments = []
                    if len(tees) == 0 and cmd in ['L','C']:
                            segments.append([cmd,params[:]])
                    elif len(tees) == 1:
                            one,two = bezmisc.beziersplitatt(bez,tees[0])
                            segments.append([cmd,list(one[1]+one[2]+one[3])])
                            segments.append([cmd,list(two[1]+two[2]+two[3])])
                    elif len(tees) == 2:
                            one,two = bezmisc.beziersplitatt(bez,tees[0])
                            two,three = bezmisc.beziersplitatt(two,tees[1])
                            segments.append([cmd,list(one[1]+one[2]+one[3])])
                            segments.append([cmd,list(two[1]+two[2]+two[3])])
                            segments.append([cmd,list(three[1]+three[2]+three[3])])

                    for seg in segments:
                        self.makeface(last,seg)
                        last = seg[1][-2:]
                    
                    if cmd == 'M':
                        subPathStart = params[-2:]
                    if cmd == 'Z':
                        last = subPathStart
                    else:
                        last = params[-2:]
Beispiel #57
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