def mapPointsToMorph( axes, percentage, morphed, numPts ):
	# rename the axes for legibility
	yCubic0 = axes[1]
	yCubic1 = axes[3]
	xCubic0 = axes[0]
	xCubic1 = axes[2]
	# morph each point
	for i in range( 0, numPts ):
		x = i*2
		y = i*2+1
		# tween between the morphed y axes according to the x percentage
		tweenedY = tweenCubic( yCubic0, yCubic1, percentage[x] )
		# get 2 points on the morphed x axes
		xSpot0 = pointOnCubic( xCubic0, percentage[x] )
		xSpot1 = pointOnCubic( xCubic1, percentage[x] )
		# create a transform that stretches the y axis tween between these 2 points
		yAnchor0 = [ tweenedY[0], tweenedY[1] ]
		yAnchor1 = [ tweenedY[6], tweenedY[7] ]
		xTransform = match( yAnchor0, yAnchor1, xSpot0, xSpot1 )
		# map the y axis tween to the 2 points by applying the stretch transform
		for j in range(0,4):
			x2 = j*2
			y2 = j*2+1
			pointOnY = [tweenedY[x2],tweenedY[y2]]
			simpletransform.applyTransformToPoint( xTransform, pointOnY )
			tweenedY[x2] = pointOnY[0]
			tweenedY[y2] = pointOnY[1]
		# get the point on the tweened and transformed y axis according to the y percentage
		morphedPoint = pointOnCubic( tweenedY, percentage[y] )
		morphed[x] = morphedPoint[0]
		morphed[y] = morphedPoint[1]
Example #2
0
def mapPointsToMorph(axes, percentage, morphed, numPts):
    # rename the axes for legibility
    yCubic0 = axes[1]
    yCubic1 = axes[3]
    xCubic0 = axes[0]
    xCubic1 = axes[2]
    # morph each point
    for i in range(0, numPts):
        x = i * 2
        y = i * 2 + 1
        # tween between the morphed y axes according to the x percentage
        tweenedY = tweenCubic(yCubic0, yCubic1, percentage[x])
        # get 2 points on the morphed x axes
        xSpot0 = pointOnCubic(xCubic0, percentage[x])
        xSpot1 = pointOnCubic(xCubic1, percentage[x])
        # create a transform that stretches the y axis tween between these 2 points
        yAnchor0 = [tweenedY[0], tweenedY[1]]
        yAnchor1 = [tweenedY[6], tweenedY[7]]
        xTransform = match(yAnchor0, yAnchor1, xSpot0, xSpot1)
        # map the y axis tween to the 2 points by applying the stretch transform
        for j in range(0, 4):
            x2 = j * 2
            y2 = j * 2 + 1
            pointOnY = [tweenedY[x2], tweenedY[y2]]
            simpletransform.applyTransformToPoint(xTransform, pointOnY)
            tweenedY[x2] = pointOnY[0]
            tweenedY[y2] = pointOnY[1]
        # get the point on the tweened and transformed y axis according to the y percentage
        morphedPoint = pointOnCubic(tweenedY, percentage[y])
        morphed[x] = morphedPoint[0]
        morphed[y] = morphedPoint[1]
	def mapPathVertices( self, node ):

		steps2rads = math.pi / float( 1600 )

		transform = self.transforms[node]
		if transform is None:
			invTransform = None
		else:
			invTransform = inverseTransform( transform )

		newPath = ''
		for subpath in self.paths[node]:
			lastPoint = subpath[0]
			lastPoint[0] = self.cx + ( lastPoint[0] - self.cx ) / math.cos( ( lastPoint[1] - self.cy ) * steps2rads )
			if invTransform != None:
				simpletransform.applyTransformToPoint( invTransform, lastPoint )
			newPath += ' M %f,%f' % ( lastPoint[0], lastPoint[1] )
			for point in subpath[1:]:
				x = self.cx + ( point[0] - self.cx ) / math.cos( ( point[1] - self.cy ) * steps2rads )
				pt = [x, point[1] ]
				if invTransform != None:
					simpletransform.applyTransformToPoint( invTransform, pt )
				newPath += ' l %f,%f' % ( pt[0] - lastPoint[0], pt[1] - lastPoint[1] )
				lastPoint = pt

		self.paths[node] = newPath
Example #4
0
    def center(self):
        point = [float(self.node.get('x', 0)), float(self.node.get('y', 0))]

        transform = get_node_transform(self.node)
        applyTransformToPoint(transform, point)

        return point
Example #5
0
    def mapPathVertices(self, node):

        steps2rads = math.pi / float(1600)

        transform = self.transforms[node]
        if transform is None:
            inv_transform = None
        else:
            inv_transform = inverseTransform(transform)

        new_path = ''
        for subpath in self.paths[node]:
            last_point = subpath[0]
            last_point[0] = self.cx + (last_point[0] - self.cx) / math.cos(
                (last_point[1] - self.cy) * steps2rads)
            if inv_transform is not None:
                applyTransformToPoint(inv_transform, last_point)
            new_path += ' M {0:f},{1:f}'.format(last_point[0], last_point[1])
            for point in subpath[1:]:
                x = self.cx + (point[0] - self.cx) / math.cos(
                    (point[1] - self.cy) * steps2rads)
                pt = [x, point[1]]
                if inv_transform is not None:
                    applyTransformToPoint(inv_transform, pt)
                new_path += ' l {0:f},{1:f}'.format(pt[0] - last_point[0],
                                                    pt[1] - last_point[1])
                last_point = pt

        self.paths[node] = new_path
Example #6
0
    def process_layer(self, layer_element, layer_name):
        #For each layer group, get each path.

        for element in layer_element.iter(tag_path):
            log("Found path: " + str(element.attrib['d']))
            #Get the point transform at node
            svg_transforms = self.get_transform_list(element)
            #Parse path
            parsed_path = cubicsuperpath.parsePath(element.attrib['d'])
            #Convert into polyline
            cspsubdiv.cspsubdiv(parsed_path, self.resolution)
            #At this point, parsed_path contains a list of list of points (yes, I know)
            #so for each "path", each "subpath" we should get an array of points
            for subpath in parsed_path:
                log("  Subpath (%d points)" % len(subpath))
                #Write footprint path begining
                self.out_file.write(polygon_header)
                for point in subpath:
                    point = list(point[1])
                    for transform in svg_transforms:
                        log("Applying transform: " + str(transform))
                        simpletransform.applyTransformToPoint(transform, point)
                    log("    Point: " + str(point))
                    #transform point using self.transform matrix
                    #write individual point
                    self.out_file.write("(xy %f %f) " % (point[0], point[1]))
                self.out_file.write(polygon_footer.format(layer=layer_name))
Example #7
0
    def mapPathVertices(self, node):

        steps2rads = math.pi / float(1600)

        transform = self.transforms[node]
        if transform is None:
            invTransform = None
        else:
            invTransform = inverseTransform(transform)

        newPath = ''
        for subpath in self.paths[node]:
            lastPoint = subpath[0]
            lastPoint[0] = self.cx + (lastPoint[0] - self.cx) / math.cos(
                (lastPoint[1] - self.cy) * steps2rads)
            if invTransform != None:
                simpletransform.applyTransformToPoint(invTransform, lastPoint)
            newPath += ' M %f,%f' % (lastPoint[0], lastPoint[1])
            for point in subpath[1:]:
                x = self.cx + (point[0] - self.cx) / math.cos(
                    (point[1] - self.cy) * steps2rads)
                pt = [x, point[1]]
                if invTransform != None:
                    simpletransform.applyTransformToPoint(invTransform, pt)
                newPath += ' l %f,%f' % (pt[0] - lastPoint[0],
                                         pt[1] - lastPoint[1])
                lastPoint = pt

        self.paths[node] = newPath
Example #8
0
    def exportDrill(self, kicad_mod=False):
        x0 = 0
        y0 = 0
        mirror = 1.0

        self.setInkscapeScaling()

        kicad_drill_string = ""

        i = 0

        if kicad_mod:
            pad_template = "(pad {n} thru_hole circle (at {x} {y}) (size {d} {d}) (drill {d}) (layers *.Cu *.Mask))\n"
        else:
            pad_template = """
                (module Wire_Pads:SolderWirePad_single_0-8mmDrill (layer F.Cu) (tedit 0) (tstamp 5ABD66D0)
                    (at {x} {y})
                    (pad {n} thru_hole circle (at 0 0) (size {d} {d}) (drill {d}) (layers *.Cu *.Mask))
                )
            """

        layerPath = '//svg:g[@inkscape:groupmode="layer"][@inkscape:label="Drill"]'

        for layer in self.document.getroot().xpath(layerPath, namespaces=inkex.NSS):

            layer_trans = layer.get('transform')
            if layer_trans:
                layer_m = simpletransform.parseTransform(layer_trans)
            else:
                layer_m = IDENTITY_MATRIX

            nodePath = 'descendant::svg:circle'

            count = 0
            for node in layer.xpath(nodePath, namespaces=inkex.NSS):
                count = count + 1
                cx = float(node.get('cx'))
                cy = float(node.get('cy'))

                radius = float(node.get('r'))
                drill_size = radius * 2

                t = node.get('transform')

                pt = [cx, cy]

                if t:
                    m = simpletransform.parseTransform(t)
                    trans = simpletransform.composeTransform(layer_m, m)
                else:
                    trans = layer_m

                simpletransform.applyTransformToPoint(trans,pt)
                padCoord = self.coordToKicad(pt)

                kicad_drill_string += pad_template.format(x=padCoord[0], y=padCoord[1], n=count, d=drill_size)

            return kicad_drill_string
Example #9
0
    def recursiveFuseTransform(self, node, transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = composeTransform(transf, parseTransform(node.get("transform", None)))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        if 'style' in node.attrib:
            style = node.attrib.get('style')
            style = simplestyle.parseStyle(style)
            update = False

            if 'stroke-width' in style:
                try:
                    stroke_width = self.unittouu(style.get('stroke-width').strip())
                    # pixelsnap ext assumes scaling is similar in x and y
                    # and uses the x scale...
                    # let's try to be a bit smarter
                    stroke_width *= math.sqrt(transf[0][0]**2 + transf[1][1]**2)
                    style['stroke-width'] = str(stroke_width)
                    update = True
                except AttributeError:
                    pass

            if update:
                style = simplestyle.formatStyle(style)
                node.attrib['style'] = style

        node = ApplyTransform.objectToPath(node)

        if 'd' in node.attrib:
            d = node.get('d')
            p = cubicsuperpath.parsePath(d)
            applyTransformToPath(transf, p)
            node.set('d', cubicsuperpath.formatPath(p))

        elif node.tag in [inkex.addNS('polygon', 'svg'),
                          inkex.addNS('polyline', 'svg')]:
            points = node.get('points')
            points = points.strip().split(' ')
            for k,p in enumerate(points):
                if ',' in p:
                    p = p.split(',')
                    p = [float(p[0]),float(p[1])]
                    applyTransformToPoint(transf, p)
                    p = [str(p[0]),str(p[1])]
                    p = ','.join(p)
                    points[k] = p
            points = ' '.join(points)
            node.set('points', points)

        elif node.tag in [inkex.addNS('rect', 'svg'),
                          inkex.addNS('text', 'svg'),
                          inkex.addNS('image', 'svg'),
                          inkex.addNS('use', 'svg')]:
            node.set('transform', formatTransform(transf))

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
Example #10
0
    def center(self):
        point = [float(self.node.get('x', 0)), float(self.node.get('y', 0))]
        point = [(point[0] + (float(self.node.get('width', 0)) / 2)),
                 (point[1] + (float(self.node.get('height', 0)) / 2))]

        transform = get_node_transform(self.node)
        applyTransformToPoint(transform, point)

        return point
Example #11
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)
Example #12
0
        def to_point(point):
            """ Extracts a point in our format from a point in simplepath format
            """

            transformed_point = [point[1][0], point[1][1]]
            simpletransform.applyTransformToPoint(self.current_transform(),
                                                  transformed_point)

            return (self.to_mm(transformed_point[0]),
                    self.to_mm(transformed_point[1]))
Example #13
0
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = composeTransform(transf,
                                  parseTransform(node.get("transform", None)))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        node = self.objectToPath(node)

        if 'd' in node.attrib:
            d = node.get('d')
            p = cubicsuperpath.parsePath(d)
            applyTransformToPath(transf, p)
            node.set('d', cubicsuperpath.formatPath(p))

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('polygon', 'svg'),
                inkex.addNS('polyline', 'svg')
        ]:
            points = node.get('points')
            points = points.strip().split(' ')
            for k, p in enumerate(points):
                if ',' in p:
                    p = p.split(',')
                    p = [float(p[0]), float(p[1])]
                    applyTransformToPoint(transf, p)
                    p = [str(p[0]), str(p[1])]
                    p = ','.join(p)
                    points[k] = p
            points = ' '.join(points)
            node.set('points', points)

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('rect', 'svg'),
                inkex.addNS('text', 'svg'),
                inkex.addNS('image', 'svg'),
                inkex.addNS('use', 'svg'),
                inkex.addNS('circle', 'svg')
        ]:
            node.set('transform', formatTransform(transf))

        else:
            # e.g. <g style="...">
            self.scaleStrokeWidth(node, transf)

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
Example #14
0
    def _readPath(self, item, flat, transform):
        p = cubicsuperpath.parsePath(item.get('d'))
        cspsubdiv.cspsubdiv(p, flat)
        subpaths = []
        for sp in p:
            sps = []
            subpaths.append(sps)
            for c0, c1, c2 in sp:
                pt = list(c2)
                simpletransform.applyTransformToPoint(transform, pt)
                sps.append(tuple(pt))
 
        self[:] = mergePaths(sortPaths(subpaths))
def element_center (node) :
	if node.tag == inkex.addNS('path','svg') :#assume circle
		x=float(node.get(inkex.addNS("cx","sodipodi")))
		y=float(node.get(inkex.addNS("cy","sodipodi")))
	elif node.tag == inkex.addNS('rect','svg') :
		x=float(node.get("x"))+float(node.get("width"))/2.
		y=float(node.get("y"))+float(node.get("height"))/2.
	else :
		raise UserWarning("unrecognized node")
	pt=[x,y]
	if node.get("transform") is not None :
		mat=simpletransform.parseTransform(node.get("transform"))
		simpletransform.applyTransformToPoint(mat,pt)
	return pt
def element_center(node):
    if node.tag == inkex.addNS('path', 'svg'):  #assume circle
        x = float(node.get(inkex.addNS("cx", "sodipodi")))
        y = float(node.get(inkex.addNS("cy", "sodipodi")))
    elif node.tag == inkex.addNS('rect', 'svg'):
        x = float(node.get("x")) + float(node.get("width")) / 2.
        y = float(node.get("y")) + float(node.get("height")) / 2.
    else:
        raise UserWarning("unrecognized node")
    pt = [x, y]
    if node.get("transform") is not None:
        mat = simpletransform.parseTransform(node.get("transform"))
        simpletransform.applyTransformToPoint(mat, pt)
    return pt
Example #17
0
    def draw(self, transform):
        """ Draws the working area

        :param transform: the transform to apply to points
        :type transform: a 2x3 matrix
        """

        # Using a viewBox so that we can express all measures relative to it. We compute the
        # view box height when the width is 100 to keep the aspect ratio. We also compute the stroke
        # width so that it is 0.5 millimiters
        self.factor = 100.0 / self.dim_x
        self.view_box_height = self.factor * self.dim_y
        line_width = self.factor * 0.5

        # inverting transformation, we know absolute coordinates
        inv_transform = simpletransform.invertTransform(transform)
        # tranforming the position of the box
        box_origin = [0, self.page_height - self.dim_y]
        simpletransform.applyTransformToPoint(inv_transform, box_origin)
        # transforming lengths (ignoring translation)
        box_dims = [self.dim_x, self.dim_y]
        length_inv_transform = [[
            inv_transform[0][0], inv_transform[0][1], 0.0
        ], [inv_transform[1][0], inv_transform[1][1], 0.0]]
        simpletransform.applyTransformToPoint(length_inv_transform, box_dims)

        self.area = inkex.etree.Element(
            "svg", {
                'id':
                self.working_area_id,
                'x':
                str(self.to_uu(box_origin[0])),
                'y':
                str(self.to_uu(box_origin[1])),
                'width':
                str(self.to_uu(box_dims[0])),
                'height':
                str(self.to_uu(box_dims[1])),
                'viewBox':
                "0 0 100 " + str(self.view_box_height),
                'preserveAspectRatio':
                "none",
                'style':
                "fill:none;stroke-width:{};stroke:rgb(0,0,0)".format(
                    line_width)
            })

        self.draw_rectangle()
        self.draw_cross()
        self.draw_text()
def element_size (node) :
	if node.tag == inkex.addNS('path','svg') :#assume circle
		rx=float(node.get(inkex.addNS("rx","sodipodi")))
		ry=float(node.get(inkex.addNS("ry","sodipodi")))
	elif node.tag == inkex.addNS('rect','svg') :
		rx=float(node.get("width"))/2.
		ry=float(node.get("height"))/2.
	else :
		raise UserWarning("unrecognized node")
	pt=[rx,ry]
	if node.get("transform") is not None :
		mat=simpletransform.parseTransform(node.get("transform"))
		mat[0][2]=0
		mat[1][2]=0
		simpletransform.applyTransformToPoint(mat,pt)
	return pt
def element_size(node):
    if node.tag == inkex.addNS('path', 'svg'):  #assume circle
        rx = float(node.get(inkex.addNS("rx", "sodipodi")))
        ry = float(node.get(inkex.addNS("ry", "sodipodi")))
    elif node.tag == inkex.addNS('rect', 'svg'):
        rx = float(node.get("width")) / 2.
        ry = float(node.get("height")) / 2.
    else:
        raise UserWarning("unrecognized node")
    pt = [rx, ry]
    if node.get("transform") is not None:
        mat = simpletransform.parseTransform(node.get("transform"))
        mat[0][2] = 0
        mat[1][2] = 0
        simpletransform.applyTransformToPoint(mat, pt)
    return pt
Example #20
0
    def effect(self):
        """
        Apply the transformation. If an element already has a transformation
        attribute, it will be combined with the transformation matrix for the
        requested conversion.
        """

        if self.options.reverse == "true":
            conversion = "from_" + self.options.conversion
        else:
            conversion = "to_" + self.options.conversion

        if len(self.selected) == 0:
            inkex.errormsg(
                _("Please select an object to perform the " +
                  "isometric projection transformation on."))
            return

        # Default to the flat 2D to isometric top down view conversion if an
        # invalid identifier is passed.
        effect_matrix = self.transformations.get(
            conversion, self.transformations.get('to_top'))

        for id, node in self.selected.items():
            bbox = computeBBox([node])
            midpoint = self.getMidPoint(bbox, node)
            center_old = self.getTransformCenter(midpoint, node)
            transform = node.get("transform")
            # Combine our transformation matrix with any pre-existing
            # transform.
            matrix = parseTransform(transform, effect_matrix)

            # Compute the location of the transformation center after applying
            # the transformation matrix.
            center_new = center_old[:]
            applyTransformToPoint(matrix, center_new)
            applyTransformToPoint(matrix, midpoint)

            # Add a translation transformation that will move the object to
            # keep its transformation center in the same place.
            self.translateBetweenPoints(matrix, center_new, center_old)

            node.set('transform', formatTransform(matrix))

            # Adjust the transformation center.
            self.moveTransformationCenter(node, midpoint, center_new)
    def effect(self):
        """
        Apply the transformation. If an element already has a transformation
        attribute, it will be combined with the transformation matrix for the
        requested conversion.
        """

        if self.options.reverse == "true":
            conversion = "from_" + self.options.conversion
        else:
            conversion = "to_" + self.options.conversion

        if len(self.selected) == 0:
            inkex.errormsg(_("Please select an object to perform the " +
                             "isometric projection transformation on."))
            return

        # Default to the flat 2D to isometric top down view conversion if an
        # invalid identifier is passed.
        effect_matrix = self.transformations.get(
            conversion, self.transformations.get('to_top'))

        for id, node in self.selected.iteritems():
            bbox = computeBBox([node])
            midpoint = self.getMidPoint(bbox, node)
            center_old = self.getTransformCenter(midpoint, node)
            transform = node.get("transform")
            # Combine our transformation matrix with any pre-existing
            # transform.
            matrix = parseTransform(transform, effect_matrix)

            # Compute the location of the transformation center after applying
            # the transformation matrix.
            center_new = center_old[:]
            applyTransformToPoint(matrix, center_new)
            applyTransformToPoint(matrix, midpoint)

            # Add a translation transformation that will move the object to
            # keep its transformation center in the same place.
            self.translateBetweenPoints(matrix, center_new, center_old)

            node.set('transform', formatTransform(matrix))

            # Adjust the transformation center.
            self.moveTransformationCenter(node, midpoint, center_new)
Example #22
0
    def dxf_arc_transform(self,m,cx,cy,rx,ry,abase,a0,a1):
        cp = [cx,cy]
        abaserads = math.radians(abase)
        if rx >= ry:
            abaserads = abaserads + math.pi
            rmaj = rx
            rmin = ry
            # major axis vector points left

            # angles in inkscape = cw from elipse local x axis;
            # angles in dxf ccw from major axis
            # major axis at Pi
            # so invert and offset by Pi
            a0 = math.pi - a0
            a1 = math.pi - a1
        else:
            abaserads = abaserads - math.pi / 2
            rmaj = ry
            rmin = rx
            # major axis vector is up the page (-ve y in inkscape)

            # angles in inkscape = cw from elipse local x axis;
            # angles in dxf ccw from major axis
            # major axis at 3 * Pi / 2
            # so invert and offset by 3 * Pi / 2
            a0 = 3 * math.pi / 2 - a0
            a1 = 3 * math.pi / 2 - a1
        rmm = rmin / rmaj
        majaxisp = [cx + rmaj*cos(abaserads), cy + rmaj*sin(abaserads)]

        if ((a0 < 0) or (a1 < 0)):
            a0 = a0 + 2 * math.pi
            a1 = a1 + 2 * math.pi
        
        # apply transforms
        simpletransform.applyTransformToPoint(m,cp)
        simpletransform.applyTransformToPoint(m,majaxisp)

        # Maj axis is relative to centre...
        majaxisp[0] = majaxisp[0] - cp[0]
        majaxisp[1] = majaxisp[1] - cp[1]

        # reverse angles from inkscape cw to DXF ccw
        self.dxf_arc(cp,majaxisp,rmm,a1,a0)
Example #23
0
def get_origin(svg):
    origin_command = global_command(svg, "origin")

    if origin_command:
        return origin_command.point
    else:
        # default: center of the canvas

        doc_size = list(get_doc_size(svg))

        # convert the size from viewbox-relative to real-world pixels
        viewbox_transform = get_viewbox_transform(svg)
        simpletransform.applyTransformToPoint(simpletransform.invertTransform(viewbox_transform), doc_size)

        default = [doc_size[0] / 2.0, doc_size[1] / 2.0]
        simpletransform.applyTransformToPoint(viewbox_transform, default)
        default = Point(*default)

        return default
Example #24
0
    def _parse(self):
        self.label = self.node.get(INKSCAPE_LABEL, "")

        doc_size = list(get_doc_size(self.svg))

        # convert the size from viewbox-relative to real-world pixels
        viewbox_transform = get_viewbox_transform(self.svg)
        simpletransform.applyTransformToPoint(
            simpletransform.invertTransform(viewbox_transform), doc_size)

        self.position = Point(*string_to_floats(self.node.get('position')))

        # inkscape's Y axis is reversed from SVG's, and the guide is in inkscape coordinates
        self.position.y = doc_size[1] - self.position.y

        # This one baffles me.  I think inkscape might have gotten the order of
        # their vector wrong?
        parts = string_to_floats(self.node.get('orientation'))
        self.direction = Point(parts[1], parts[0])
    def __init__(self, document, options, size, scale):
        super(KiCadFootprintBuilder, self).__init__(document, options, size,
                                                    scale)
        self.expression = [
            MODULE, MODULE_NAME, [LAYER, 'F.Cu'], [TEDIT, timestamp()],
            [ATTR, 'smd']
        ]
        T.foo()
        if options.description:
            self.expression.append([DESCR, options.description])

        if options.tags > 0:
            self.expression.append([TAGS, options.tags])

        font_size = 1
        field_offset = 1.2 * font_size
        if options.ref_mode != 'none':
            hidden = options.ref_mode == 'hidden'
            p = [0.5 * self.size[0], 0]
            simpletransform.applyTransformToPoint(self.currentTransform(), p)
            p[1] -= field_offset
            self.appendField(FIELD_REFERENCE, 'REF**', p, 'F.SilkS', hidden,
                             font_size)

        if options.value_mode != 'none':
            hidden = options.value_mode == 'hidden'
            value = ''
            if options.value_src == 'document':
                title_node = self.document.xpath('//dc:title',
                                                 namespaces=ix.NSS)[0]
                if title_node is None or title_node.text is None or len(
                        title_node.text) == 0:
                    abort('Document Properties/Metadata/Title is missing')
                value = title_node.text
            elif options.value_src == 'custom':
                value = options.custom_value
            else:
                abort('Unhandled value-src')
            p = [0.5 * self.size[0], self.size[1]]
            simpletransform.applyTransformToPoint(self.currentTransform(), p)
            p[1] += field_offset
            self.appendField(FIELD_VALUE, value, p, 'F.SilkS', hidden,
                             font_size)
Example #26
0
def rect_bounding_box(rect, box=None):
    """Get the bounding box of an SVG rectangle.

    :param rect: The XML node defining the object.
    :param box: The existing :class:`bounds.BoundingBox` if available.
    :return: A :class:`bounds.BoundingBox` encompassing the object.

    """

    # Get the position and dimension of the rectangle
    x = float(rect.get('x', 0))
    y = float(rect.get('y', 0))
    width = float(rect.get('width'))
    height = float(rect.get('height'))

    # Width and height can't be negative
    if width < 0:
        raise ValueError(_('Width of rect object cannot be negative.'))
    if height < 0:
        raise ValueError(_('Height of rect object cannot be negative.'))

    # Width or height of zero disables rendering
    if width == 0 or height == 0:
        return box

    # Create the four points
    bl = [x, y]
    br = [x + width, y]
    tr = [x + width, y + height]
    tl = [x, y + height]

    # Get the transform
    transform = rect.get('transform', None)
    if transform:
        transform = simpletransform.parseTransform(transform)
        simpletransform.applyTransformToPoint(transform, bl)
        simpletransform.applyTransformToPoint(transform, br)
        simpletransform.applyTransformToPoint(transform, tr)
        simpletransform.applyTransformToPoint(transform, tl)

    # Extend the box
    if box is None:
        box = BoundingBox(bl[0], bl[0], bl[1], bl[1])
    else:
        box.extend(bl)
    box.extend(br)
    box.extend(tr)
    box.extend(tl)

    # And done.
    return box
Example #27
0
def get_origin(svg):
    # The user can specify the embroidery origin by defining two guides
    # named "embroidery origin" that intersect.

    namedview = svg.find(inkex.addNS('namedview', 'sodipodi'))
    all_guides = namedview.findall(inkex.addNS('guide', 'sodipodi'))
    label_attribute = inkex.addNS('label', 'inkscape')
    guides = [
        guide for guide in all_guides
        if guide.get(label_attribute, "").startswith("embroidery origin")
    ]

    # document size used below
    doc_size = list(get_doc_size(svg))

    # convert the size from viewbox-relative to real-world pixels
    viewbox_transform = get_viewbox_transform(svg)
    simpletransform.applyTransformToPoint(
        simpletransform.invertTransform(viewbox_transform), doc_size)

    default = [doc_size[0] / 2.0, doc_size[1] / 2.0]
    simpletransform.applyTransformToPoint(viewbox_transform, default)
    default = Point(*default)

    if len(guides) < 2:
        return default

    # Find out where the guides intersect.  Only pay attention to the first two.
    guides = guides[:2]

    lines = []
    for guide in guides:
        # inkscape's Y axis is reversed from SVG's, and the guide is in inkscape coordinates
        position = Point(*_string_to_floats(guide.get('position')))
        position.y = doc_size[1] - position.y

        # This one baffles me.  I think inkscape might have gotten the order of
        # their vector wrong?
        parts = _string_to_floats(guide.get('orientation'))
        direction = Point(parts[1], parts[0])

        # We have a theoretically infinite line defined by a point on the line
        # and a vector direction.  Shapely can only deal in concrete line
        # segments, so we'll pick points really far in either direction on the
        # line and call it good enough.
        lines.append(
            shgeo.LineString((position + 100000 * direction,
                              position - 100000 * direction)))

    intersection = lines[0].intersection(lines[1])

    if isinstance(intersection, shgeo.Point):
        origin = [intersection.x, intersection.y]
        simpletransform.applyTransformToPoint(viewbox_transform, origin)
        return Point(*origin)
    else:
        # Either the two guides are the same line, or they're parallel.
        return default
Example #28
0
 def effect(self):
     x0 = self.options.xOrigin
     y0 = self.options.yOrigin
     mirror = 1.0
     if self.options.mirror:
         mirror = -1.0
         if self.document.getroot().get('height'):
             y0 -= float(self.document.getroot().get('height'))
     i = 0
     layerPath = '//svg:g[@inkscape:groupmode="layer"]'
     for layer in self.document.getroot().xpath(layerPath, namespaces=inkex.NSS):
         i += 1
         layer_trans = layer.get('transform')
         if layer_trans:
             layer_m = simpletransform.parseTransform(layer_trans)
         else:
             layer_m = identity_m
         
         nodePath = ('//svg:g[@inkscape:groupmode="layer"][%d]/descendant::svg:path') % i
         for node in self.document.getroot().xpath(nodePath, namespaces=inkex.NSS):
             d = node.get('d')
             p = simplepath.parsePath(d)
             if p:
                 #sanity check
                 if p[0][0] == 'M':
                     pt = [p[0][1][0], p[0][1][1]]
                     t = node.get('transform')
                     if t:
                         m = simpletransform.parseTransform(t)
                         trans = simpletransform.composeTransform(layer_m, m)
                     else:
                         trans = layer_m
                     simpletransform.applyTransformToPoint(trans,pt)
                     
                     self.x.append(str(pt[0]-x0))
                     self.y.append(str(pt[1]*mirror-y0))
    def op_transform(self, layers, mtx, name="Transform", is_end=False):
        """Apply a matrix transformation to the given layers

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

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

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

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

        simpletransform.applyTransformToPoint(mtx, dest_tl)
        simpletransform.applyTransformToPoint(mtx, dest_tr)
        simpletransform.applyTransformToPoint(mtx, dest_br)
        simpletransform.applyTransformToPoint(mtx, dest_bl)

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

        if is_end:
            return layers + [warp]
        else:
            return self.op_encapsulate(layers + [warp])
Example #30
0
    def test_simpletransform(self):
        """Test simpletransform API"""
        import simpletransform

        self.assertEqual(simpletransform.parseTransform('scale(10)'),
                         [[10, 0, 0], [0, 10, 0]])
        self.assertEqual(simpletransform.parseTransform('translate(2,3)'),
                         [[1, 0, 2], [0, 1, 3]])
        self.assertEqual(
            simpletransform.parseTransform('translate(2,3) rotate(90)'),
            [approx([0, -1, 2]), approx([1, 0, 3])])
        m = simpletransform.formatTransform([[0, -1, 2], [1, 0, 3]])
        self.assertEqual(re.sub(r',', ' ', re.sub(r'\.0*\b', '', m)),
                         'matrix(0 1 -1 0 2 3)')
        self.assertEqual(
            simpletransform.invertTransform([[1, 0, 2], [0, 1, 3]]),
            [[1, 0, -2], [0, 1, -3]])
        self.assertEqual(
            simpletransform.composeTransform([[1, 0, 2], [0, 1, 3]],
                                             [[0, -1, 0], [1, 0, 0]]),
            [[0, -1, 2], [1, 0, 3]])

        pt = [4, 5]
        self.assertEqual(
            simpletransform.applyTransformToPoint([[0, -1, 2], [1, 0, 3]], pt),
            None)
        self.assertEqual(pt, [-3, 7])

        self.assertEqual(simpletransform.boxunion([3, 5, 2, 4], [4, 6, 1, 3]),
                         (3, 6, 1, 4))
        self.assertEqual(simpletransform.cubicExtrema(1, 2, 3, 4), (1, 4))

        # TODO need cubic superpath
        self.assertTrue(simpletransform.applyTransformToPath)
        self.assertTrue(simpletransform.roughBBox)
        self.assertTrue(simpletransform.refinedBBox)

        # TODO need node
        self.assertTrue(simpletransform.fuseTransform)
        self.assertTrue(simpletransform.composeParents)
        self.assertTrue(simpletransform.applyTransformToNode)
        self.assertTrue(simpletransform.computeBBox)
        self.assertTrue(simpletransform.computePointInNode)
Example #31
0
    def renderFoil(self, naca_num, size, twist=0.0):
        l = len(naca_num)
        if l == 4:
            pts = naca.naca4(naca_num, self.options.points, False, True)
        elif l == 5:
            pts = naca.naca5(naca_num, self.options.points, False, True)
        else:
            #sys.stderr.write("Naca number must be 4 or 5 digits\n")
            return None, None

        for i, pt in enumerate(pts):
            pts[i] = list(pt)

        upper = [ pts[0:self.options.points+1] ]
        lower = [ pts[self.options.points:] + [pts[0]] ]

        beam_x = self.options.beampos/100.0

        n_up, pt_up = self.pointAt(upper[0], beam_x)
        n_low, pt_low = self.pointAt(lower[0], beam_x)
        beam_y = (pt_up[1] + pt_low[1]) / 2.0

        trans = simpletransform.composeTransform(
            simpletransform.parseTransform("rotate(%f)" % (-1*twist)),
            [[size,0.0,-beam_x*size],
             [0.0,size,-beam_y*size]])

        for pt in pts:
            simpletransform.applyTransformToPoint(trans, pt)
        for pt in pt_up, pt_low:
            simpletransform.applyTransformToPoint(trans, pt)

        if self.options.beamtype in [1,2,11,12]: # center beam
            if self.options.beamtype in [1,2]: # round
                beam = self.circle(self.options.beamwidth)
            else: # rectangular
                beam = self.rectangle(self.options.beamwidth,
                                      self.options.beamheight)

            if self.options.beamtype in [1, 3]: # from above
                upper = [ upper[0][:n_up] + [ pt_up ],
                          [pt_up, beam[0]],
                          beam,
                          [ beam[-1], pt_up ],
                          [pt_up] + upper[0][n_up :] ]
            else: # from below
                beam = self.upsidedown(beam)
                lower = [ lower[0][:n_low] + [ pt_low ],
                          [pt_low, beam[0]],
                          beam,
                          [beam[-1], pt_low ],
                          [pt_low] + lower[0][n_low:]]
        elif self.options.beamtype in [3,13]:
            if self.options.beamtype == 3:
                beamleft = self.halfcircle(self.options.beamwidth)
            else:
                beamleft = self.halfrectangle(self.options.beamwidth,
                                              self.options.beamheight)
            beamright = self.lefttoright(beamleft)
            beamleft.reverse()
            upper = [ upper[0][:n_up] + [ pt_up ],
                      [pt_up, beamright[0]],
                      beamright,
                      [beamright[-1], pt_low],
                      [pt_low, beamleft[0]],
                      beamleft,
                      [beamleft[-1], pt_up],
                      [pt_up] + upper[0][n_up :] ]
            lower = [ lower[0][:n_low] + [ pt_low ],
                      self.move(10,0, [pt_low] + lower[0][n_low:])]

            for i in xrange(4):
                upper[i] = self.move(10,0, upper[i])
            # add connection below
            upper[4:4] = [ [upper[3][-1],upper[4][0]]]

        else: # Surface beam(s)
            if self.options.beamtype in [5, 7]: # Top beam
                pass
            if self.options.beamtype in [6, 7]: # Bottom beam
                pass

        if self.options.approach <= 2: # Start with left/leading eadge
            pts = lower + upper
        else:
            pts = upper + lower

        return pts
Example #32
0
    def point(self):
        pos = [float(self.node.get("x", 0)), float(self.node.get("y", 0))]
        transform = get_node_transform(self.node)
        simpletransform.applyTransformToPoint(transform, pos)

        return Point(*pos)
Example #33
0
    def convert(self,
                on_progress=None,
                on_progress_args=None,
                on_progress_kwargs=None):

        self.init_output_file()
        self.parse()
        options = self.options
        options['doc_root'] = self.document.getroot()

        # Get all Gcodetools data from the scene.
        self.calculate_conversion_matrix()
        self.collect_paths()

        for p in self.paths:
            #print "path", etree.tostring(p)
            pass

        def report_progress(on_progress, on_progress_args, on_progress_kwargs,
                            done, total):
            if (total == 0):
                total = 1

            progress = done / float(total)
            if on_progress is not None:
                if on_progress_args is None:
                    on_progress_args = ()
                if on_progress_kwargs is None:
                    on_progress_kwargs = dict()

                on_progress_kwargs["_progress"] = progress
                on_progress(*on_progress_args, **on_progress_kwargs)

        self._log.info("processing %i layers" % len(self.layers))
        # sum up
        itemAmount = 1
        for layer in self.layers:
            if layer in self.paths:
                itemAmount += len(self.paths[layer])
            if layer in self.images:
                itemAmount += len(self.images[layer])

        processedItemCount = 0
        report_progress(on_progress, on_progress_args, on_progress_kwargs,
                        processedItemCount, itemAmount)

        with open(self._tempfile, 'a') as fh:
            # write comments to gcode
            gc_options_str = "; gc_nexgen gc_options: {}\n".format(
                self.gc_options)
            fh.write(gc_options_str)
            fh.write("; created:{}\n".format(
                time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())))
            gc_color_str = "; laser params: {}\n".format(self.colorParams)
            fh.write(gc_color_str)

            fh.write(self._get_gcode_header())

            # images
            self._log.info('Raster conversion: %s' % self.options['engrave'])
            for layer in self.layers:
                if layer in self.images and self.options['engrave']:
                    for imgNode in self.images[layer]:
                        file_id = imgNode.get('data-serveurl', '')
                        x = imgNode.get('x')
                        y = imgNode.get('y')
                        if x is None:
                            x = "0"
                        if y is None:
                            y = "0"

                        # pt units
                        x = float(x)
                        y = float(y)
                        w = float(imgNode.get("width"))
                        h = float(imgNode.get("height"))

                        _upperLeft = [x, y]
                        _lowerRight = [x + w, y + h]

                        # apply svg transforms
                        _mat = self._get_transforms(imgNode)
                        simpletransform.applyTransformToPoint(_mat, _upperLeft)
                        simpletransform.applyTransformToPoint(
                            _mat, _lowerRight)

                        ### original style with orientation points :( ... TODO
                        # mm conversion
                        upperLeft = self._transform(_upperLeft, layer, False)
                        lowerRight = self._transform(_lowerRight, layer, False)

                        w = abs(lowerRight[0] - upperLeft[0])
                        h = abs(lowerRight[1] - upperLeft[1])

                        # contrast = 1.0, sharpening = 1.0, beam_diameter = 0.25,
                        # intensity_black = 1000, intensity_white = 0, speed_black = 30, speed_white = 500,
                        # dithering = True, pierce_time = 500, material = "default"
                        rasterParams = self.options['raster']
                        ip = ImageProcessor(
                            output_filehandle=fh,
                            contrast=rasterParams['contrast'],
                            sharpening=rasterParams['sharpening'],
                            beam_diameter=rasterParams['beam_diameter'],
                            intensity_black=rasterParams['intensity_black'],
                            intensity_white=rasterParams['intensity_white'],
                            speed_black=rasterParams['speed_black'],
                            speed_white=rasterParams['speed_white'],
                            dithering=rasterParams['dithering'],
                            pierce_time=rasterParams['pierce_time'],
                            material="default")
                        data = imgNode.get('href')
                        if (data is None):
                            data = imgNode.get(_add_ns('href', 'xlink'))

                        if (data.startswith("data:")):
                            ip.dataUrl_to_gcode(data, w, h, upperLeft[0],
                                                lowerRight[1], file_id)
                        elif (data.startswith("http://")):
                            ip.imgurl_to_gcode(data, w, h, upperLeft[0],
                                               lowerRight[1], file_id)
                        else:
                            self._log.error("Unable to parse img data", data)

                        processedItemCount += 1
                        report_progress(on_progress, on_progress_args,
                                        on_progress_kwargs, processedItemCount,
                                        itemAmount)
                    else:
                        self._log.info("postponing non-image layer %s" %
                                       (layer.get('id')))

            # paths
            self._log.info('Vector conversion: %s paths' % len(self.paths))

            for layer in self.layers:
                if layer in self.paths:
                    paths_by_color = dict()
                    for path in self.paths[layer]:
                        self._log.info(
                            "path %s, %s, stroke: %s, fill: %s, mb:gc: %s" %
                            (layer.get('id'), path.get('id'),
                             path.get('stroke'), path.get('class'),
                             path.get(_add_ns('gc', 'mb'))[:100]))

                        #						if path.get('stroke') is not None: #todo catch None stroke/fill earlier
                        #							stroke = path.get('stroke')
                        #						elif path.get('fill') is not None:
                        #							stroke = path.get('fill')
                        #						elif path.get('class') is not None:
                        #							stroke = path.get('class')
                        #						else:
                        #							stroke = 'default'
                        #continue

                        strokeInfo = self._get_stroke(path)
                        #print('strokeInfo:', strokeInfo)
                        if (strokeInfo['visible'] == False):
                            continue

                        stroke = strokeInfo['color']
                        if "d" not in path.keys():
                            self._log.error(
                                "Warning: One or more paths don't have 'd' parameter"
                            )
                            continue
                        if stroke not in paths_by_color.keys(
                        ) and stroke != 'default':
                            paths_by_color[stroke] = []
                        d = path.get("d")
                        if d != '':
                            paths_by_color[stroke].append(path)  # += path
                            processedItemCount += 1
                            report_progress(on_progress, on_progress_args,
                                            on_progress_kwargs,
                                            processedItemCount, itemAmount)

#					curvesD = dict() #diction
#					for colorKey in paths_by_color.keys():
#						if colorKey == 'none':
#							continue

#						curvesD[colorKey] = self._parse_curve(paths_by_color[colorKey], layer)

#pierce_time = self.options['pierce_time']
                    layerId = layer.get('id') or '?'
                    pathId = path.get('id') or '?'

                    #for each color generate GCode
                    #for colorKey in curvesD.keys():
                    for colorKey in paths_by_color.keys():
                        if colorKey == 'none':
                            continue

                        for path in paths_by_color[colorKey]:
                            print('p', path)
                            curveGCode = ""
                            mbgc = path.get(_add_ns('gc', 'mb'), None)
                            if (mbgc != None):
                                curveGCode = self._use_embedded_gcode(
                                    mbgc, colorKey)
                            else:
                                d = path.get('d')
                                csp = cubicsuperpath.parsePath(d)
                                csp = self._apply_transforms(path, csp)
                                curve = self._parse_curve(csp, layer)
                                curveGCode = self._generate_gcode(
                                    curve, colorKey)

                            settings = self.colorParams.get(
                                colorKey, {
                                    'intensity': -1,
                                    'feedrate': -1,
                                    'passes': 0,
                                    'pierce_time': 0
                                })
                            fh.write("; Layer:" + layerId + ", outline of:" +
                                     pathId + ", stroke:" + colorKey + ', ' +
                                     str(settings) + "\n")
                            for p in range(0, int(settings['passes'])):
                                fh.write("; pass:%i/%s\n" %
                                         (p + 1, settings['passes']))
                                fh.write(curveGCode)

            fh.write(self._get_gcode_footer())

        self.export_gcode()
    def effect(
        self,
        hatchSpacing=10,
        crossHatch=False,
        hatchAngle=0,
        tolerance=20,
        minGap=5,
    ):
        '''
			crossHatch : Generate a cross hatch pattern 
			hatchAngle : Angle of inclination for hatch lines 
			hatchSpacing : Spacing between hatch lines
			tolerance : Allowed deviation from original paths
			minGap : Minimum length of hatch segments and gaps
		'''
        self.options = {}
        self.options['crossHatch'] = crossHatch
        self.options['hatchAngle'] = hatchAngle
        self.options['hatchSpacing'] = hatchSpacing * 90 / 25.4
        self.options['tolerance'] = tolerance
        self.options['minGap'] = minGap

        # Viewbox handling
        self.handleViewBox()

        # Traverse the selected nodes
        self.recursivelyTraverseSvg(self.nodes, self.docTransform)

        # Build a grid of possible hatch lines
        self.makeHatchGrid(float(self.options['hatchAngle']),
                           float(self.options['hatchSpacing']), True)
        if self.options['crossHatch']:
            self.makeHatchGrid(float(self.options['hatchAngle'] + 90.0),
                               float(self.options['hatchSpacing']), False)

        # Now loop over our hatch lines looking for intersections
        for h in self.grid:
            interstices((h[0], h[1]), (h[2], h[3]), self.paths, self.hatches,
                        self.minGap)

        # Target stroke width will be (doc width + doc height) / 2 / 1000
        # stroke_width_target = ( self.docHeight + self.docWidth ) / 2000
        stroke_width_target = 1

        # Each hatch line stroke will be within an SVG object which may
        # be subject to transforms.  So, on an object by object basis,
        # we need to transform our target width to a width suitable
        # for that object (so that after the object and its hatches are
        # transformed, the result has the desired width).

        # To aid in the process, we use a diagonal line segment of length
        # stroke_width_target.  We then run this segment through an object's
        # inverse transform and see what the resulting length of the inversely
        # transformed segment is.  We could, alternatively, look at the
        # x and y scaling factors in the transform and average them.
        s = stroke_width_target / math.sqrt(2)

        # Now, dump the hatch fills sorted by which document element
        # they correspond to.  This is made easy by the fact that we
        # saved the information and used each element's lxml.etree node
        # pointer as the dictionary key under which to save the hatch
        # fills for that node.

        fillings = []
        for key in self.hatches:
            path = ''
            direction = True
            if self.transforms.has_key(key):
                transform = inverseTransform(self.transforms[key])
                # Determine the scaled stroke width for a hatch line
                # We produce a line segment of unit length, transform
                # its endpoints and then determine the length of the
                # resulting line segment.
                pt1 = [0, 0]
                pt2 = [s, s]
                simpletransform.applyTransformToPoint(transform, pt1)
                simpletransform.applyTransformToPoint(transform, pt2)
                dx = pt2[0] - pt1[0]
                dy = pt2[1] - pt1[1]
                stroke_width = math.sqrt(dx * dx + dy * dy)
            else:
                transform = None
                stroke_width = float(1.0)
            for segment in self.hatches[key]:
                style = simplestyle.parseStyle(key.get("style"))
                color = style["fill"]
                if len(segment) < 2:
                    continue
                pt1 = segment[0]
                pt2 = segment[1]
                # Okay, we're going to put these hatch lines into the same
                # group as the element they hatch.  That element is down
                # some chain of SVG elements, some of which may have
                # transforms attached.  But, our hatch lines have been
                # computed assuming that those transforms have already
                # been applied (since we had to apply them so as to know
                # where this element is on the page relative to other
                # elements and their transforms).  So, we need to invert
                # the transforms for this element and then either apply
                # that inverse transform here and now or set it in a
                # transform attribute of the <path> element.  Having it
                # set in the path element seems a bit counterintuitive
                # after the fact (i.e., what's this tranform here for?).
                # So, we compute the inverse transform and apply it here.
                if transform != None:
                    simpletransform.applyTransformToPoint(transform, pt1)
                    simpletransform.applyTransformToPoint(transform, pt2)
                # Now generate the path data for the <path>
                if direction:
                    # Go this direction
                    path += 'M %f,%f l %f,%f ' % \
                     ( pt1[0], pt1[1], pt2[0] - pt1[0], pt2[1] - pt1[1] )
                else:
                    # Or go this direction
                    path += 'M %f,%f l %f,%f ' % \
                     ( pt2[0], pt2[1], pt1[0] - pt2[0], pt1[1] - pt2[1] )
                direction = not direction
            fillment = self.joinFillsWithNode(key, stroke_width, color,
                                              path[:-1])
            fillment['id'] = key.get('id')
            fillings.append(fillment)

        #inkex.errormsg("Elapsed CPU time was %f" % (time.clock()-self.t0))
        return fillings
Example #35
0
 def center(self, source_node):
     xmin, xmax, ymin, ymax = computeBBox([source_node])
     point = [(xmax - ((xmax - xmin) / 2)), (ymax - ((ymax - ymin) / 2))]
     transform = get_node_transform(self.node)
     applyTransformToPoint(transform, point)
     return point
Example #36
0
	def effect(self):

		#{{{ Check that elements have been selected

		if len(self.options.ids) == 0:
			inkex.errormsg(_("Please select objects!"))
			return

		#}}}

		#{{{ Drawing styles

		linestyle = {
			'stroke': '#000000',
			'stroke-width': str(self.unittouu('1px')),
			'fill': 'none'
		}

		facestyle = {
			'stroke': '#000000',
			'stroke-width':'0px',# str(self.unittouu('1px')),
			'fill': 'none'
		}

		#}}}

		#{{{ Handle the transformation of the current group
		parentGroup = self.getParentNode(self.selected[self.options.ids[0]])

		svg = self.document.getroot()
		children =svg.getchildren()
		fp=open("log.txt","w")
		img=None
		width_in_svg=1
		height_in_svg=1
		for child in children:
			if child.tag=="{http://www.w3.org/2000/svg}g":
				ccc=child.getchildren()
				for c in ccc:
					if c.tag=="{http://www.w3.org/2000/svg}image":
						href=c.attrib["{http://www.w3.org/1999/xlink}href"]
						fp.write(href)
						img = Image.open(href)
						width_in_svg=child.attrib['width']
						height_in_svg=child.attrib['height']
			elif child.tag=="{http://www.w3.org/2000/svg}image":
				href=child.attrib["{http://www.w3.org/1999/xlink}href"]
				width_in_svg=child.attrib['width']
				height_in_svg=child.attrib['height']
				if "file://" in href:
					href=href[7:]
				fp.write(href+"\n")
				img = Image.open(href).convert("RGB")
		width=-1
		height=-1
		if img!=None:
			imagesize = img.size
			width=img.size[0]
			height=img.size[1]
		fp.write("imageSize="+str(imagesize))



		trans = self.getGlobalTransform(parentGroup)
		invtrans = None
		if trans:
			invtrans = self.invertTransform(trans)

		#}}}

		#{{{ Recovery of the selected objects

		pts = []
		nodes = []
		seeds = []

		fp.write('num:'+str(len(self.options.ids))+'\n')
		for id in self.options.ids:
			node = self.selected[id]
			nodes.append(node)
			if(node.tag=="{http://www.w3.org/2000/svg}path"):#pathだった場合
				#パスの頂点座標を取得
				points = cubicsuperpath.parsePath(node.get('d'))
				fp.write(str(points)+"\n")
				for p in points[0]:
					pt=[p[1][0],p[1][1]]
					if trans:
						simpletransform.applyTransformToPoint(trans, pt)
					pts.append(Point(pt[0], pt[1]))
					seeds.append(Point(p[1][0], p[1][1]))
			else:#その他の図形の場合
				bbox = simpletransform.computeBBox([node])
				if bbox:
					cx = 0.5 * (bbox[0] + bbox[1])
					cy = 0.5 * (bbox[2] + bbox[3])
					pt = [cx, cy]
					if trans:
						simpletransform.applyTransformToPoint(trans, pt)
					pts.append(Point(pt[0], pt[1]))
					seeds.append(Point(cx, cy))
		pts.sort()
		seeds.sort()
		fp.write("*******sorted!***********"+str(len(seeds))+"\n")

		#}}}

		#{{{ Creation of groups to store the result
		# Delaunay
		groupDelaunay = inkex.etree.SubElement(parentGroup, inkex.addNS('g', 'svg'))
		groupDelaunay.set(inkex.addNS('label', 'inkscape'), 'Delaunay')

		#}}}

		scale_x=float(width_in_svg)/float(width)
		scale_y=float(height_in_svg)/float(height)
		fp.write('width='+str(width)+', height='+str(height)+'\n')
		fp.write('scale_x='+str(scale_x)+', scale_y='+str(scale_y)+'\n')

		#{{{ Voronoi diagram generation

		triangles = voronoi.computeDelaunayTriangulation(seeds)
		for triangle in triangles:
			p1 = seeds[triangle[0]]
			p2 = seeds[triangle[1]]
			p3 = seeds[triangle[2]]
			cmds = [['M', [p1.x, p1.y]],
					['L', [p2.x, p2.y]],
					['L', [p3.x, p3.y]],
					['Z', []]]
			path = inkex.etree.Element(inkex.addNS('path', 'svg'))
			path.set('d', simplepath.formatPath(cmds))
			middleX=(p1.x+p2.x+p3.x)/3.0/scale_x
			middleY=(p1.y+p2.y+p3.y)/3.0/scale_y
			fp.write("x:"+str(middleX)+" y:"+str(middleY)+"\n")
			if img!=None and imagesize[0]>middleX and imagesize[1]>middleY and middleX>=0 and middleY>=0:
				r,g,b = img.getpixel((middleX,middleY))
				facestyle["fill"]=simplestyle.formatColor3i(r,g,b)
			else:
				facestyle["fill"]="black"
			path.set('style', simplestyle.formatStyle(facestyle))
			groupDelaunay.append(path)
		fp.close()
Example #37
0
def path_bounding_box(path, box=None):
    """Compute the bounding box for an SVG path.

    :param path: The XML node defining the path.
    :param box: The existing :class:`bounds.BoundingBox` if available.
    :return: A :class:`bounds.BoundingBox` encompassing the path.

    SVG paths are a collection of various types of segments:

    * Straight lines
    * Quadratic Bézier curves
    * Cubic Bézier curves
    * Elliptical arcs

    This function splits the path into its segments, calculates the bounding
    box for each segment and combines them to get the bounding box of the path.
    If an existing bounding box is given in the ``box`` parameter, it is
    extended to encompass the path and returned. Otherwise, a new bounding box
    is created and returned.

    """

    # Get the transform
    transform = path.get('transform', None)
    if transform:
        transform = simpletransform.parseTransform(transform)

    # Parse the path details.
    # Note that when parsing all path segments are converted to absolute
    # coordinates. It also converts H and V segments to L, S segments to C and
    # T segments to Q.
    parsed = simplepath.parsePath(path.get('d'))

    # Starting point
    current = parsed[0][1]
    if transform:
        simpletransform.applyTransformToPoint(transform, current)
    objbox = BoundingBox(current[0], current[0], current[1], current[1])

    # Loop through each segment.
    for type,params in parsed[1:]:
        # End of path
        if type == 'Z':
            break

        # Line or move to
        elif type == 'L' or type == 'M':
            point = params
            if transform:
                simpletransform.applyTransformToPoint(transform, point)
            objbox.extend(point)
            current = point

        # Cubic Bézier curve
        elif type == 'C':
            p1 = params[0:2]
            p2 = params[2:4]
            p3 = params[4:6]
            if transform:
                simpletransform.applyTransformToPoint(transform, p1)
                simpletransform.applyTransformToPoint(transform, p2)
                simpletransform.applyTransformToPoint(transform, p3)
            objbox = cubic_bounding_box(current, p1, p2, p3, objbox)
            current = p3

        # Quadratic Bézier curve
        elif type == 'Q':
            p1 = params[0:2]
            p2 = params[2:4]
            if transform:
                simpletransform.applyTransformToPoint(transform, p1)
                simpletransform.applyTransformToPoint(transform, p2)
            objbox = quadratic_bounding_box(current, p1, p2, objbox)
            current = p2

        # Elliptical arc
        elif type == 'A':
            rx, ry, rotation, large_arc, sweep = params[0:5]
            end = params[5:7]
            if transform:
                simpletransform.applyTransformToPoint(transform, end)
            objbox = elliptical_arc_bounding_box(current, rx, ry, rotation,
                                                 large_arc, sweep, end, objbox)
            current = end

        # Unknown segment type
        else:
            raise Exception(_('Unknown path segment type %s.' % type))

    # Returnt the appropriate box
    if box is None:
        return objbox
    else:
        return box.combine(objbox)
	def effect( self , hatchSpacing = 10, crossHatch = False, hatchAngle = 0, tolerance = 20, minGap = 5, ):
		'''
			crossHatch : Generate a cross hatch pattern 
			hatchAngle : Angle of inclination for hatch lines 
			hatchSpacing : Spacing between hatch lines
			tolerance : Allowed deviation from original paths
			minGap : Minimum length of hatch segments and gaps
		'''
		self.options = {}
		self.options['crossHatch'] = crossHatch 
		self.options['hatchAngle'] = hatchAngle 
		self.options['hatchSpacing'] = hatchSpacing * 90/25.4
		self.options['tolerance'] = tolerance 
		self.options['minGap'] = minGap

		# Viewbox handling
		self.handleViewBox()

		# Traverse the selected nodes
		self.recursivelyTraverseSvg( self.nodes, self.docTransform )

		# Build a grid of possible hatch lines
		self.makeHatchGrid( float( self.options['hatchAngle'] ),
				float( self.options['hatchSpacing'] ), True )
		if self.options['crossHatch']:
			self.makeHatchGrid( float( self.options['hatchAngle'] + 90.0 ),
				float( self.options['hatchSpacing'] ), False )

		# Now loop over our hatch lines looking for intersections
		for h in self.grid:
			interstices( (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.minGap )

		# Target stroke width will be (doc width + doc height) / 2 / 1000
		# stroke_width_target = ( self.docHeight + self.docWidth ) / 2000
		stroke_width_target = 1

		# Each hatch line stroke will be within an SVG object which may
		# be subject to transforms.  So, on an object by object basis,
		# we need to transform our target width to a width suitable
		# for that object (so that after the object and its hatches are
		# transformed, the result has the desired width).

		# To aid in the process, we use a diagonal line segment of length
		# stroke_width_target.  We then run this segment through an object's
		# inverse transform and see what the resulting length of the inversely
		# transformed segment is.  We could, alternatively, look at the
		# x and y scaling factors in the transform and average them.
		s = stroke_width_target / math.sqrt( 2 )

		# Now, dump the hatch fills sorted by which document element
		# they correspond to.  This is made easy by the fact that we
		# saved the information and used each element's lxml.etree node
		# pointer as the dictionary key under which to save the hatch
		# fills for that node.

		fillings = []
		for key in self.hatches:
			path = ''
			direction = True
			if self.transforms.has_key( key ):
				transform = inverseTransform( self.transforms[key] )
				# Determine the scaled stroke width for a hatch line
				# We produce a line segment of unit length, transform
				# its endpoints and then determine the length of the
				# resulting line segment.
				pt1 = [0, 0]
				pt2 = [s, s]
				simpletransform.applyTransformToPoint( transform, pt1 )
				simpletransform.applyTransformToPoint( transform, pt2 )
				dx = pt2[0] - pt1[0]
				dy = pt2[1] - pt1[1]
				stroke_width = math.sqrt( dx * dx + dy * dy )
			else:
				transform = None
				stroke_width = float( 1.0 )
			for segment in self.hatches[key]:
				style = simplestyle.parseStyle(key.get("style"))
				color = style["fill"]
				if len( segment ) < 2:
					continue
				pt1 = segment[0]
				pt2 = segment[1]
				# Okay, we're going to put these hatch lines into the same
				# group as the element they hatch.  That element is down
				# some chain of SVG elements, some of which may have
				# transforms attached.  But, our hatch lines have been
				# computed assuming that those transforms have already
				# been applied (since we had to apply them so as to know
				# where this element is on the page relative to other
				# elements and their transforms).  So, we need to invert
				# the transforms for this element and then either apply
				# that inverse transform here and now or set it in a
				# transform attribute of the <path> element.  Having it
				# set in the path element seems a bit counterintuitive
				# after the fact (i.e., what's this tranform here for?).
				# So, we compute the inverse transform and apply it here.
				if transform != None:
					simpletransform.applyTransformToPoint( transform, pt1 )
					simpletransform.applyTransformToPoint( transform, pt2 )
				# Now generate the path data for the <path>
				if direction:
					# Go this direction
					path += 'M %f,%f l %f,%f ' % \
						( pt1[0], pt1[1], pt2[0] - pt1[0], pt2[1] - pt1[1] )
				else:
					# Or go this direction
					path += 'M %f,%f l %f,%f ' % \
						( pt2[0], pt2[1], pt1[0] - pt2[0], pt1[1] - pt2[1] )
				direction = not direction
			fillment = self.joinFillsWithNode( key, stroke_width, color, path[:-1] )
			fillment['id'] = key.get('id')
			fillings.append(fillment)

		#inkex.errormsg("Elapsed CPU time was %f" % (time.clock()-self.t0))
		return fillings
 def t(point):
     p = point[:]
     simpletransform.applyTransformToPoint(mat, p)
     return p
Example #40
0
def applyTransformToRegions(mtx, regions):
    for poly in regions:
        for pt in poly:
            applyTransformToPoint(mtx, pt)
Example #41
0
    def exportEdgeCut(self, kicad_mod=False):
        x0 = 0
        y0 = 0
        mirror = 1.0

        line_type = "fp_line" if kicad_mod else "gr_line"

        kicad_edgecut_string = ""

        i = 0
        layerPath = '//svg:g[@inkscape:groupmode="layer"]'

        if (self.options.autoflatten):
            self.flatten_bezier()

        for layer in self.document.getroot().xpath(layerPath,
                                                   namespaces=inkex.NSS):
            i += 1

            label_attrib_name = "{%s}label" % layer.nsmap['inkscape']
            if label_attrib_name not in layer.attrib:
                continue

            layer_name = (layer.attrib[label_attrib_name])

            if layer_name != "Edge.Cuts":
                continue

            layer_trans = layer.get('transform')
            if layer_trans:
                layer_m = simpletransform.parseTransform(layer_trans)
            else:
                layer_m = IDENTITY_MATRIX

            nodePath = (
                '//svg:g[@inkscape:groupmode="layer"][%d]/descendant::svg:path'
            ) % i
            for node in self.document.getroot().xpath(nodePath,
                                                      namespaces=inkex.NSS):
                d = node.get('d')
                p = simplepath.parsePath(d)

                points = []
                if p:
                    #sanity check
                    if p[0][0] == 'M':
                        t = node.get('transform')
                        if t:
                            m = simpletransform.parseTransform(t)
                            trans = simpletransform.composeTransform(
                                layer_m, m)
                        else:
                            trans = layer_m

                        for path in p:
                            if path[0] != "Z":
                                x = (path[1][0])
                                y = (path[1][1])
                                xy = [x, y]
                                simpletransform.applyTransformToPoint(
                                    trans, xy)
                                points.append(
                                    self.coordToKicad([(xy[0] - x0),
                                                       xy[1] * mirror - y0]))

                        points_count = len(points)
                        points.append(points[0])

                        for x in range(0, points_count):
                            kicad_edgecut_string = kicad_edgecut_string + (
                                "(%s (start %f %f) (end %f %f) (layer Edge.Cuts) (width 0.1))\n"
                                % (line_type, points[x][0], points[x][1],
                                   points[x + 1][0], points[x + 1][1]))

        return kicad_edgecut_string
    def effect(self):

        # Viewbox handling
        self.handleViewBox()

        # Build a list of the vertices for the document's graphical elements
        if self.options.ids:
            # Traverse the selected objects
            for id in self.options.ids:
                self.recursivelyTraverseSvg([self.selected[id]],
                                            self.docTransform)
        else:
            # Traverse the entire document
            self.recursivelyTraverseSvg(self.document.getroot(),
                                        self.docTransform)

        # Build a grid of possible hatch lines
        self.makeHatchGrid(float(self.options.hatchAngle),
                           float(self.options.hatchSpacing), True)
        if self.options.crossHatch:
            self.makeHatchGrid(float(self.options.hatchAngle + 90.0),
                               float(self.options.hatchSpacing), False)

        # Now loop over our hatch lines looking for intersections
        for h in self.grid:
            interstices((h[0], h[1]), (h[2], h[3]), self.paths, self.hatches,
                        self.minGap)

        # Target stroke width will be (doc width + doc height) / 2 / 1000
        # stroke_width_target = ( self.docHeight + self.docWidth ) / 2000
        stroke_width_target = 1

        # Each hatch line stroke will be within an SVG object which may
        # be subject to transforms.  So, on an object by object basis,
        # we need to transform our target width to a width suitable
        # for that object (so that after the object and its hatches are
        # transformed, the result has the desired width).

        # To aid in the process, we use a diagonal line segment of length
        # stroke_width_target.  We then run this segment through an object's
        # inverse transform and see what the resulting length of the inversely
        # transformed segment is.  We could, alternatively, look at the
        # x and y scaling factors in the transform and average them.
        s = stroke_width_target / math.sqrt(2)

        # Now, dump the hatch fills sorted by which document element
        # they correspond to.  This is made easy by the fact that we
        # saved the information and used each element's lxml.etree node
        # pointer as the dictionary key under which to save the hatch
        # fills for that node.

        for key in self.hatches:
            path = ''
            direction = True
            if self.transforms.has_key(key):
                transform = inverseTransform(self.transforms[key])
                # Determine the scaled stroke width for a hatch line
                # We produce a line segment of unit length, transform
                # its endpoints and then determine the length of the
                # resulting line segment.
                pt1 = [0, 0]
                pt2 = [s, s]
                simpletransform.applyTransformToPoint(transform, pt1)
                simpletransform.applyTransformToPoint(transform, pt2)
                dx = pt2[0] - pt1[0]
                dy = pt2[1] - pt1[1]
                stroke_width = math.sqrt(dx * dx + dy * dy)
            else:
                transform = None
                stroke_width = float(1.0)
            for segment in self.hatches[key]:
                if len(segment) < 2:
                    continue
                pt1 = segment[0]
                pt2 = segment[1]
                # Okay, we're going to put these hatch lines into the same
                # group as the element they hatch.  That element is down
                # some chain of SVG elements, some of which may have
                # transforms attached.  But, our hatch lines have been
                # computed assuming that those transforms have already
                # been applied (since we had to apply them so as to know
                # where this element is on the page relative to other
                # elements and their transforms).  So, we need to invert
                # the transforms for this element and then either apply
                # that inverse transform here and now or set it in a
                # transform attribute of the <path> element.  Having it
                # set in the path element seems a bit counterintuitive
                # after the fact (i.e., what's this tranform here for?).
                # So, we compute the inverse transform and apply it here.
                if transform != None:
                    simpletransform.applyTransformToPoint(transform, pt1)
                    simpletransform.applyTransformToPoint(transform, pt2)
                # Now generate the path data for the <path>
                if direction:
                    # Go this direction
                    path += 'M %f,%f l %f,%f ' % \
                     ( pt1[0], pt1[1], pt2[0] - pt1[0], pt2[1] - pt1[1] )
                else:
                    # Or go this direction
                    path += 'M %f,%f l %f,%f ' % \
                     ( pt2[0], pt2[1], pt1[0] - pt2[0], pt1[1] - pt2[1] )
                direction = not direction
            self.joinFillsWithNode(key, stroke_width, path[:-1])
def path_to_bline_list(path_d, nodetypes=None, mtx=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
    """
    Convert a path to a BLine List

    bline_list format:

    Vertex:
    [[tg1x, tg1y], [x,y], [tg2x, tg2y], split = T/F]
    Vertex list:
    [ vertex, vertex, vertex, ...]
    Bline:
    {
    "points"    : vertex_list,
    "loop"      : True / False
    }
    """

    # Exit on empty paths
    if not path_d:
        return []

    # Parse the path
    path = simplepath.parsePath(path_d)

    # Append (more than) enough c's to the nodetypes
    if nodetypes is None:
        nt = ""
    else:
        nt = nodetypes

    for _ in range(len(path)):
        nt += "c"

    # Create bline list
    #     borrows code from cubicsuperpath.py

    # bline_list := [bline, bline, ...]
    # bline := {
    #           "points":[vertex, vertex, ...],
    #           "loop":True/False,
    #          }

    bline_list = []

    subpathstart = []
    last = []
    lastctrl = []
    lastsplit = True
    for s in path:
        cmd, params = s
        if cmd != "M" and bline_list == []:
            raise MalformedSVGError, "Bad path data: path doesn't start with moveto, %s, %s" % (s, path)
        elif cmd == "M":
            # Add previous point to subpath
            if last:
                bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit])
            # Start a new subpath
            bline_list.append({"nodetypes": "", "loop": False, "points": []})
            # Save coordinates of this point
            subpathstart = params[:]
            last = params[:]
            lastctrl = params[:]
            lastsplit = False if nt[0] == "z" else True
            nt = nt[1:]
        elif cmd == "L":
            bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit])
            last = params[:]
            lastctrl = params[:]
            lastsplit = False if nt[0] == "z" else True
            nt = nt[1:]
        elif cmd == "C":
            bline_list[-1]["points"].append([lastctrl[:], last[:], params[:2], lastsplit])
            last = params[-2:]
            lastctrl = params[2:4]
            lastsplit = False if nt[0] == "z" else True
            nt = nt[1:]
        elif cmd == "Q":
            q0 = last[:]
            q1 = params[0:2]
            q2 = params[2:4]
            x0 = q0[0]
            x1 = 1.0 / 3 * q0[0] + 2.0 / 3 * q1[0]
            x2 = 2.0 / 3 * q1[0] + 1.0 / 3 * q2[0]
            x3 = q2[0]
            y0 = q0[1]
            y1 = 1.0 / 3 * q0[1] + 2.0 / 3 * q1[1]
            y2 = 2.0 / 3 * q1[1] + 1.0 / 3 * q2[1]
            y3 = q2[1]
            bline_list[-1]["points"].append([lastctrl[:], [x0, y0], [x1, y1], lastsplit])
            last = [x3, y3]
            lastctrl = [x2, y2]
            lastsplit = False if nt[0] == "z" else True
            nt = nt[1:]
        elif cmd == "A":
            arcp = cubicsuperpath.ArcToPath(last[:], params[:])
            arcp[0][0] = lastctrl[:]
            last = arcp[-1][1]
            lastctrl = arcp[-1][0]
            lastsplit = False if nt[0] == "z" else True
            nt = nt[1:]
            for el in arcp[:-1]:
                el.append(True)
                bline_list[-1]["points"].append(el)
        elif cmd == "Z":
            if len(bline_list[-1]["points"]) == 0:
                # If the path "loops" after only one point
                #  e.g. "M 0 0 Z"
                bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], False])
            elif last == subpathstart:
                # If we are back to the original position
                # merge our tangent into the first point
                bline_list[-1]["points"][0][0] = lastctrl[:]
            else:
                # Otherwise draw a line to the starting point
                bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit])

            # Clear the variables (no more points need to be added)
            last = []
            lastctrl = []
            lastsplit = True

            # Loop the subpath
            bline_list[-1]["loop"] = True

    # Append final superpoint, if needed
    if last:
        bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit])

    # Apply the transformation
    if mtx != [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]:
        for bline in bline_list:
            for vertex in bline["points"]:
                for pt in vertex:
                    if type(pt) != bool:
                        simpletransform.applyTransformToPoint(mtx, pt)

    return bline_list
Example #44
0
	def effect( self ):

		# Viewbox handling
		self.handleViewBox()

		# Build a list of the vertices for the document's graphical elements
		if self.options.ids:
			# Traverse the selected objects
			for id in self.options.ids:
				self.recursivelyTraverseSvg( [self.selected[id]], self.docTransform )
		else:
			# Traverse the entire document
			self.recursivelyTraverseSvg( self.document.getroot(), self.docTransform )

		# Build a grid of possible hatch lines
		self.makeHatchGrid( float( self.options.hatchAngle ),
				float( 90 / self.options.hatchSpacing), True )
		if self.options.crossHatch:
			self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),
				float( 90 / self.options.hatchSpacing), False )

		# Now loop over our hatch lines looking for intersections
		for h in self.grid:
			interstices( (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.minGap )

		# Target stroke width will be (doc width + doc height) / 2 / 1000
		# stroke_width_target = ( self.docHeight + self.docWidth ) / 2000
		stroke_width_target = 1

		# Each hatch line stroke will be within an SVG object which may
		# be subject to transforms.  So, on an object by object basis,
		# we need to transform our target width to a width suitable
		# for that object (so that after the object and its hatches are
		# transformed, the result has the desired width).

		# To aid in the process, we use a diagonal line segment of length
		# stroke_width_target.  We then run this segment through an object's
		# inverse transform and see what the resulting length of the inversely
		# transformed segment is.  We could, alternatively, look at the
		# x and y scaling factors in the transform and average them.
		s = stroke_width_target / math.sqrt( 2 )

		# Now, dump the hatch fills sorted by which document element
		# they correspond to.  This is made easy by the fact that we
		# saved the information and used each element's lxml.etree node
		# pointer as the dictionary key under which to save the hatch
		# fills for that node.

		for key in self.hatches:
			path = ''
			direction = True
			if self.transforms.has_key( key ):
				transform = inverseTransform( self.transforms[key] )
				# Determine the scaled stroke width for a hatch line
				# We produce a line segment of unit length, transform
				# its endpoints and then determine the length of the
				# resulting line segment.
				pt1 = [0, 0]
				pt2 = [s, s]
				simpletransform.applyTransformToPoint( transform, pt1 )
				simpletransform.applyTransformToPoint( transform, pt2 )
				dx = pt2[0] - pt1[0]
				dy = pt2[1] - pt1[1]
				stroke_width = math.sqrt( dx * dx + dy * dy )
			else:
				transform = None
				stroke_width = float( 1.0 )
			for segment in self.hatches[key]:
				if len( segment ) < 2:
					continue
				pt1 = segment[0]
				pt2 = segment[1]
				# Okay, we're going to put these hatch lines into the same
				# group as the element they hatch.  That element is down
				# some chain of SVG elements, some of which may have
				# transforms attached.  But, our hatch lines have been
				# computed assuming that those transforms have already
				# been applied (since we had to apply them so as to know
				# where this element is on the page relative to other
				# elements and their transforms).  So, we need to invert
				# the transforms for this element and then either apply
				# that inverse transform here and now or set it in a
				# transform attribute of the <path> element.  Having it
				# set in the path element seems a bit counterintuitive
				# after the fact (i.e., what's this tranform here for?).
				# So, we compute the inverse transform and apply it here.
				if transform != None:
					simpletransform.applyTransformToPoint( transform, pt1 )
					simpletransform.applyTransformToPoint( transform, pt2 )
				# Now generate the path data for the <path>
				if direction:
					# Go this direction
					path += 'M %f,%f l %f,%f ' % \
						( pt1[0], pt1[1], pt2[0] - pt1[0], pt2[1] - pt1[1] )
				else:
					# Or go this direction
					path += 'M %f,%f l %f,%f ' % \
						( pt2[0], pt2[1], pt1[0] - pt2[0], pt1[1] - pt2[1] )
				direction = not direction
			self.joinFillsWithNode( key, stroke_width, path[:-1] )
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        transf = composeTransform(transf,
                                  parseTransform(node.get("transform", None)))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        if 'style' in node.attrib:
            style = node.attrib.get('style')
            style = simplestyle.parseStyle(style)
            update = False

            if 'stroke-width' in style:
                unit = self.getUnit(style.get('stroke-width').strip())
                stroke_width = self.getVal(style.get('stroke-width').strip())
                # pixelsnap ext assumes scaling is similar in x and y
                # and uses the x scale...
                # let's try to be a bit smarter
                stroke_width *= math.sqrt(
                    (transf[0][0]**2 + transf[1][1]**2) / 2)

                style['stroke-width'] = self.valWithUnit(stroke_width, unit)
                update = True

            if update:
                style = simplestyle.formatStyle(style)
                node.attrib['style'] = style

        node = ApplyTransform.objectToPath(node)

        if 'd' in node.attrib:
            d = node.get('d')
            p = cubicsuperpath.parsePath(d)
            applyTransformToPath(transf, p)
            node.set('d', cubicsuperpath.formatPath(p))

        elif node.tag == inkex.addNS('polygon', 'svg'):
            points = node.get('points')
            points = points.strip().split(' ')
            for k, p in enumerate(points):
                p = p.split(',')
                unit = self.getUnit(p[0])
                p = [self.getVal(p[0]), self.getVal(p[1])]
                applyTransformToPoint(transf, p)
                p = [
                    self.valWithUnit(p[0], unit),
                    self.valWithUnit(p[1], unit)
                ]
                p = ','.join(p)
                points[k] = p
            points = ' '.join(points)
            node.set('points', points)

        # if there is cx, there is also cy
        if 'cx' in node.attrib:
            cx = node.get('cx')
            cy = node.get('cy')
            unit = self.getUnit(cx)
            pt = [self.getVal(cx), self.getVal(cy)]
            applyTransformToPoint(transf, pt)
            node.set('cx', self.valWithUnit(pt[0], unit))
            node.set('cy', self.valWithUnit(pt[1], unit))

        if 'r' in node.attrib:
            unit = self.getUnit(node.get('r'))
            r = self.getVal(node.get('r'))
            # this is a circle: is the scale uniform?
            if transf[0][0] == transf[1][1]:
                r *= abs(transf[0][0])
                node.set('r', self.valWithUnit(r, unit))
            else:
                # transform is not uniform: go from circle to ellipse
                # NOTE!!! Inkscape currently applies this particular transform as soon as we touch the object.
                # therefore rx and ry are both assigned to r, otherwise the scaling is applied two times!
                # this is kind of a bug of the implementation
                rx = r  #*abs(transf[0][0])
                ry = r  #*abs(transf[1][1])
                node.set('rx', self.valWithUnit(rx, unit))
                node.set('ry', self.valWithUnit(ry, unit))
                del node.attrib['r']
                node.tag = inkex.addNS('ellipse', 'svg')

        if 'rx' in node.attrib:
            unit = self.getUnit(node.get('rx'))
            rx = self.getVal(node.get('rx')) * abs(transf[0][0])
            ry = self.getVal(node.get('ry')) * abs(transf[1][1])
            node.set('rx', self.valWithUnit(rx, unit))
            node.set('ry', self.valWithUnit(ry, unit))

        if 'x' in node.attrib:
            unit = self.getUnit(node.get('x'))
            x = self.getVal(node.get('x')) * transf[0][0]
            y = self.getVal(node.get('y')) * transf[1][1]
            node.set('x', self.valWithUnit(x, unit))
            node.set('y', self.valWithUnit(y, unit))

        if 'width' in node.attrib:
            unit = self.getUnit(node.get('width'))
            w = self.getVal(node.get('width')) * transf[0][0]
            h = self.getVal(node.get('height')) * transf[1][1]
            if w < 0:
                xUnit = self.getUnit(node.get('x'))
                x = self.getVal(node.get('x'))
                x += w
                w = -w
                node.set('x', self.valWithUnit(x, xUnit))
            if h < 0:
                yUnit = self.getUnit(node.get('y'))
                y = self.getVal(node.get('y'))
                y += h
                h = -h
                node.set('y', self.valWithUnit(y, yUnit))
            node.set('width', self.valWithUnit(w, unit))
            node.set('height', self.valWithUnit(h, unit))

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
Example #46
0
  def effect(self):

    #{{{ Check that elements have been selected

    if len(self.options.ids) == 0:
      inkex.errormsg(_("Please select objects!"))
      return

    #}}}

    #{{{ Drawing styles

    linestyle = {
        'stroke'       : '#000000',
        'stroke-width' : str(self.unittouu('1px')),
        'fill'         : 'none'
        }

    facestyle = {
        'stroke'       : '#ff0000',
        'stroke-width' : str(self.unittouu('1px')),
        'fill'         : 'none'
        }

    #}}}

    #{{{ Handle the transformation of the current group
    parentGroup = self.getParentNode(self.selected[self.options.ids[0]])

    trans = self.getGlobalTransform(parentGroup)
    invtrans = None
    if trans:
      invtrans = simpletransform.invertTransform(trans)

    #}}}

    #{{{ Recovery of the selected objects

    pts = []
    nodes = []
    seeds = []


    for id in self.options.ids:
      node = self.selected[id]
      nodes.append(node)
      bbox = simpletransform.computeBBox([node])
      if bbox:
        cx = 0.5*(bbox[0]+bbox[1])
        cy = 0.5*(bbox[2]+bbox[3])
        pt = [cx,cy]
        if trans:
          simpletransform.applyTransformToPoint(trans,pt)
        pts.append(Point(pt[0],pt[1]))
        seeds.append(Point(cx,cy))

    #}}}

    #{{{ Creation of groups to store the result

    if self.options.diagramType != 'Delaunay':
      # Voronoi
      groupVoronoi = inkex.etree.SubElement(parentGroup,inkex.addNS('g','svg'))
      groupVoronoi.set(inkex.addNS('label', 'inkscape'), 'Voronoi')
      if invtrans:
        simpletransform.applyTransformToNode(invtrans,groupVoronoi)
    if self.options.diagramType != 'Voronoi':
      # Delaunay
      groupDelaunay = inkex.etree.SubElement(parentGroup,inkex.addNS('g','svg'))
      groupDelaunay.set(inkex.addNS('label', 'inkscape'), 'Delaunay')

    #}}}

    #{{{ Clipping box handling

    if self.options.diagramType != 'Delaunay':
      #Clipping bounding box creation
      gBbox = simpletransform.computeBBox(nodes)

      #Clipbox is the box to which the Voronoi diagram is restricted
      clipBox = ()
      if self.options.clipBox == 'Page':
        svg = self.document.getroot()
        w = self.unittouu(svg.get('width'))
        h = self.unittouu(svg.get('height'))
        clipBox = (0,w,0,h)
      else:
        clipBox = (2*gBbox[0]-gBbox[1],
                   2*gBbox[1]-gBbox[0],
                   2*gBbox[2]-gBbox[3],
                   2*gBbox[3]-gBbox[2])
      
      #Safebox adds points so that no Voronoi edge in clipBox is infinite
      safeBox = (2*clipBox[0]-clipBox[1],
                 2*clipBox[1]-clipBox[0],
                 2*clipBox[2]-clipBox[3],
                 2*clipBox[3]-clipBox[2])
      pts.append(Point(safeBox[0],safeBox[2]))
      pts.append(Point(safeBox[1],safeBox[2]))
      pts.append(Point(safeBox[1],safeBox[3]))
      pts.append(Point(safeBox[0],safeBox[3]))

      if self.options.showClipBox:
        #Add the clip box to the drawing
        rect = inkex.etree.SubElement(groupVoronoi,inkex.addNS('rect','svg'))
        rect.set('x',str(clipBox[0]))
        rect.set('y',str(clipBox[2]))
        rect.set('width',str(clipBox[1]-clipBox[0]))
        rect.set('height',str(clipBox[3]-clipBox[2]))
        rect.set('style',simplestyle.formatStyle(linestyle))

    #}}}

    #{{{ Voronoi diagram generation

    if self.options.diagramType != 'Delaunay':
      vertices,lines,edges = voronoi.computeVoronoiDiagram(pts)
      for edge in edges:
        line = edge[0]
        vindex1 = edge[1]
        vindex2 = edge[2]
        if (vindex1 <0) or (vindex2 <0):
          continue # infinite lines have no need to be handled in the clipped box
        else:
          segment = self.clipEdge(vertices,lines,edge,clipBox)
          #segment = [vertices[vindex1],vertices[vindex2]] # deactivate clipping
          if len(segment)>1:
            v1 = segment[0]
            v2 = segment[1]
            cmds = [['M',[v1[0],v1[1]]],['L',[v2[0],v2[1]]]]
            path = inkex.etree.Element(inkex.addNS('path','svg'))
            path.set('d',simplepath.formatPath(cmds))
            path.set('style',simplestyle.formatStyle(linestyle))
            groupVoronoi.append(path)

    if self.options.diagramType != 'Voronoi':
      triangles = voronoi.computeDelaunayTriangulation(seeds)
      for triangle in triangles:
        p1 = seeds[triangle[0]]
        p2 = seeds[triangle[1]]
        p3 = seeds[triangle[2]]
        cmds = [['M',[p1.x,p1.y]],
                ['L',[p2.x,p2.y]],
                ['L',[p3.x,p3.y]],
                ['Z',[]]]
        path = inkex.etree.Element(inkex.addNS('path','svg'))
        path.set('d',simplepath.formatPath(cmds))
        path.set('style',simplestyle.formatStyle(facestyle))
        groupDelaunay.append(path)
Example #47
0
    def process_shape(self, node, mat):
        nodetype = node.get(inkex.addNS("type","sodipodi"))
        if nodetype == "arc":
            # These are actually only used for checking the maths
            ui_arc = True
            ui_cx = float(node.get(inkex.addNS('cx','sodipodi')))
            ui_cy = float(node.get(inkex.addNS('cy','sodipodi')))
            ui_r = float(node.get(inkex.addNS('r','sodipodi'),0.0))
            ui_rx = float(node.get(inkex.addNS('rx','sodipodi'),ui_r))
            ui_ry = float(node.get(inkex.addNS('ry','sodipodi'),ui_r))
            ui_a0 = float(node.get(inkex.addNS('start','sodipodi'),0))
            ui_a1 = float(node.get(inkex.addNS('end','sodipodi'),2*math.pi))
        else:
            ui_arc = False

        rgb = (0,0,0)
        style = node.get('style')
        if style:
            style = simplestyle.parseStyle(style)
            if style.has_key('stroke'):
                if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url':
                    rgb = simplestyle.parseColor(style['stroke'])
        hsl = coloreffect.ColorEffect.rgb_to_hsl(coloreffect.ColorEffect(),rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0)
        self.closed = 0                                 # only for LWPOLYLINE
        self.color = 7                                  # default is black
        if hsl[2]:
            self.color = 1 + (int(6*hsl[0] + 0.5) % 6)  # use 6 hues
        trans = node.get('transform')
        if trans:
            mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans))
        if node.tag == inkex.addNS('path','svg'):
            d = node.get('d')
            if not d:
                inkex.errormsg("PATH DATA MISSING!")
                inkex.sys.exit()
                return
            # Filter out any eliptical arcs for special treatment:
            simplep = simplepath.parsePath(d)
            split = split_arc_nonarc(simplep)
            arc_simplep = split[1]
            simplep = split[0]
            if len(simplep)>0:
                if (simplep[-1][0] == 'z' or simplep[-1][0] == 'Z'):
                    self.closed = 1
                p = cubicsuperpath.CubicSuperPath(simplep)
                if (self.options.FLATTENBES):
                    cspsubdiv.cspsubdiv(p, self.options.flat)
                    np = []
                    for sp in p:
                        first = True
                        for csp in sp:
                            cmd = 'L'
                            if first:
                                cmd = 'M'
                            first = False
                            np.append([cmd,[csp[1][0],csp[1][1]]])
                    p = cubicsuperpath.parsePath(simplepath.formatPath(np))
                simpletransform.applyTransformToPath(mat, p)
                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]:
                            if (self.options.POLY == 'true'):
                                self.LWPOLY_line([s[1],e[1]])
                            else:
                                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]])

            # Now process any arc segments:

            if len(arc_simplep) > 0:

                # As our path is broken by arcs, we cannot have a closed polyline:
                self.closed = 0

                i = 0
                while i < len(arc_simplep):
                    cmd, params = arc_simplep[i]
                    if cmd == 'M':
                        p0 = params[:]
                    else:
                        p1 = params[-2:]
                        rx,ry,theta,largearc,sweep = params[0:5]
                        e_params = convert_arc_abrxry0_to_crxry00102(p0,p1,rx,ry,theta,largearc==1,sweep==1)
                        cx,cy = e_params[0]
                        if (i<len(arc_simplep)-1):
                            cmd2, params2 = arc_simplep[i+1]
                        else:
                            cmd2 = '-'
                        if cmd2 == 'A' and params2[0:5] == params[0:5] and params2[-2:] == p0:
                            # complete circle or ellipse
                            a0 = 0
                            a1 = 2.0*math.pi
                            i = i + 1
                            p1 = p0
                        else:
                            a0 = e_params[4]
                            a1 = e_params[5]
                            p0 = p1
                        self.dxf_arc_transform(mat,cx,cy,rx,ry,theta,a0,a1)
                        # check did we get our maths right?
                        if ui_arc and ((abs(cx - ui_cx) > 0.05) or (abs(cy - ui_cy) > 0.05) or (abs(a0 - ui_a0)>0.1) or (abs(a1 - ui_a1)>0.1)):
                            inkex.errormsg("WARNING, Maths failure. Stored attributes of arc and calculated values do not agree!:")
                            inkex.errormsg("sodipodi:\tc=[%f,%f],r=[%f,%f],a0=%fpi,a1=%fpi" % (ui_cx,ui_cy,ui_rx,ui_ry,ui_a0/math.pi,ui_a1/math.pi))
                            inkex.errormsg("raw:\tc=[%f,%f],r=[%f,%f],a0=%fpi,a1=%fpi" % (cx,cy,rx,ry,a0/math.pi,a1/math.pi))
                    i = i+1

                return
        elif node.tag in [ inkex.addNS('circle','svg'), 'circle', \
                            inkex.addNS('ellipse','svg'), 'ellipse' ]:
                cx = float(node.get('cx',0))
                cy = float(node.get('cy',0))
                if node.tag == inkex.addNS('circle','svg'):
                    rx = float(node.get('r',0))
                    ry = rx
                else:
                    rx = float(node.get('rx',0))
                    ry = float(node.get('ry',rx))
                a0 = 0.0
                a1 = 2*math.pi
                self.dxf_arc_transform(mat,cx,cy,rx,ry,0,a0,a1)
                return
        elif node.tag == inkex.addNS('rect','svg'):
            self.closed = 1
            x = float(node.get('x'))
            y = float(node.get('y'))
            width = float(node.get('width'))
            height = float(node.get('height'))
            pt0 = [x,y]
            pt1 = [x + width, y]
            pt2 = [x + width, y + height]
            pt3 = [x, y + height]
            simpletransform.applyTransformToPoint(mat,pt0)
            simpletransform.applyTransformToPoint(mat,pt1)
            simpletransform.applyTransformToPoint(mat,pt2)
            simpletransform.applyTransformToPoint(mat,pt3)
            if (self.options.POLY == 'true'):
                self.LWPOLY_line([pt0,pt1])
                self.LWPOLY_line([pt1,pt2])
                self.LWPOLY_line([pt2,pt3])
                self.LWPOLY_line([pt3,pt0])
            else:
                self.dxf_line([pt0,pt1])
                self.dxf_line([pt1,pt2])
                self.dxf_line([pt2,pt3])
                self.dxf_line([pt3,pt0])
            return
        else:
            return