Beispiel #1
0
class Line(Node):
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.start_pos = Point(kwargs['start'])
        self.end_pos = Point(kwargs['end'])

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def calculateBoundingBox(self):
        render_start_pos = self.getRealPosition(self.start_pos)
        render_end_pos = self.getRealPosition(self.end_pos)

        min_x = min([render_start_pos.x, render_end_pos.x])
        min_y = min([render_start_pos.y, render_end_pos.y])
        max_x = max([render_start_pos.x, render_end_pos.x])
        max_y = max([render_start_pos.y, render_end_pos.y])

        return Node.calculateBoundingBox({'min': Point(min_x, min_y), 'max': Point(max_x, max_y)})

    def _getRenderTreeText(self):
        render_strings = ['fp_line']
        render_strings.append(self.start_pos.render('(start {x} {y})'))
        render_strings.append(self.end_pos.render('(end {x} {y})'))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text
class Line(Node):

    _width_default = 0.15
    _layer_default = "F.SilkS"

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.start_pos = Point(kwargs["start"], **kwargs)
        self.end_pos = Point(kwargs["end"], **kwargs)

        self.layer = kwargs.get("layer", "F.SilkS")
        self.width = kwargs.get("width")

    def calculateBoundingBox(self):
        render_start_pos = self.getRealPosition(self.start_pos)
        render_end_pos = self.getRealPosition(self.end_pos)

        min_x = min([render_start_pos.x, render_end_pos.x])
        min_y = min([render_start_pos.y, render_end_pos.y])
        max_x = max([render_start_pos.x, render_end_pos.x])
        max_y = max([render_start_pos.y, render_end_pos.y])

        return Node.calculateBoundingBox({"min": Point(min_x, min_y), "max": Point(max_x, max_y)})

    def _getRenderTreeText(self):
        render_strings = ["fp_line"]
        render_strings.append(self.start_pos.render("(start {x} {y})"))
        render_strings.append(self.end_pos.render("(end {x} {y})"))
        render_strings.append("(layer {layer})".format(layer=self.layer))
        render_strings.append("(width {width})".format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += " ({})".format(" ".join(render_strings))

        return render_text
class Circle(Node):
    r"""Add a Circle to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *center* (``Point``) --
          center of the circle
        * *radius* (``float``) --
          radius of the circle
        * *layer* (``str``) --
          layer on which the circle is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the circle line (default: None, which means auto detection)

    :Example:

    >>> from KicadModTree import *
    >>> Circle(center=[0, 0], radius=1.5, layer='F.SilkS')
    """
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.center_pos = Point(kwargs['center'])
        self.radius = kwargs['radius']

        self.end_pos = Point(
            [self.center_pos.x + self.radius, self.center_pos.y])

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def calculateBoundingBox(self):
        min_x = self.center_pos.x - self.radius
        min_y = self.center_pos.y - self.radius
        max_x = self.center_pos.x + self.radius
        max_y = self.center_pos.y + self.radius

        return Node.calculateBoundingBox({
            'min': ParseXY(min_x, min_y),
            'max': ParseXY(max_x, max_y)
        })

    def _getRenderTreeText(self):
        render_strings = ['fp_circle']
        render_strings.append(self.center_pos.render('(center {x} {y})'))
        render_strings.append(self.end_pos.render('(end {x} {y})'))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text
class Line(Node):
    r"""Add a Line to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *start* (``Point``) --
          start point of the line
        * *end* (``Point``) --
          end point of the line
        * *layer* (``str``) --
          layer on which the line is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the line (default: None, which means auto detection)

    :Example:

    >>> from KicadModTree import *
    >>> Line(start=[1, 0], end=[-1, 0], layer='F.SilkS')
    """
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.start_pos = Point(kwargs['start'])
        self.end_pos = Point(kwargs['end'])

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def calculateBoundingBox(self):
        render_start_pos = self.getRealPosition(self.start_pos)
        render_end_pos = self.getRealPosition(self.end_pos)

        min_x = min([render_start_pos.x, render_end_pos.x])
        min_y = min([render_start_pos.y, render_end_pos.y])
        max_x = max([render_start_pos.x, render_end_pos.x])
        max_y = max([render_start_pos.y, render_end_pos.y])

        return Node.calculateBoundingBox({
            'min': Point(min_x, min_y),
            'max': Point(max_x, max_y)
        })

    def _getRenderTreeText(self):
        render_strings = ['fp_line']
        render_strings.append(self.start_pos.render('(start {x} {y})'))
        render_strings.append(self.end_pos.render('(end {x} {y})'))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text
Beispiel #5
0
class Circle(Node):
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.center_pos = Point(kwargs['center'])
        self.radius = kwargs['radius']

        self.end_pos = {'x': self.center_pos.x+self.radius, 'y': self.center_pos.y}

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def calculateBoundingBox(self):
        min_x = self.center_pos.x-self.radius
        min_y = self.center_pos.y-self.radius
        max_x = self.center_pos.x+self.radius
        max_y = self.center_pos.y+self.radius

        return Node.calculateBoundingBox({'min': ParseXY(min_x, min_y), 'max': ParseXY(max_x, max_y)})

    def _getRenderTreeText(self):
        render_strings = ['fp_circle']
        render_strings.append(self.center_pos.render('(center {x} {y})'))
        render_strings.append(self.end_pos.render('(end {x} {y})'))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text
class Model(Node):
    r"""Add a 3D-Model to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *filename* (``str``) --
          name of the 3d-model file
        * *at* (``Point``) --
          position of the model
        * *scale* (``Point``) --
          scale of the model
        * *rotate* (``Point``) --
          rotation of the model

    :Example:

    >>> from KicadModTree import *
    >>> Model(filename="example.3dshapes/example_footprint.wrl",
    ...       at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0])
    """
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.filename = kwargs['filename']
        self.at = Point(kwargs['at'])
        self.scale = Point(kwargs['scale'])
        self.rotate = Point(kwargs['rotate'])

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = [
            'filename: {filename}'.format(filename=self.filename),
            'at: {at}'.format(at=self.at.render('(xyz {x} {y} {z})')),
            'scale: {scale}'.format(
                scale=self.scale.render('(xyz {x} {y} {z})')),
            'rotate: {rotate}'.format(
                rotate=self.rotate.render('(xyz {x} {y} {z})'))
        ]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text
class Model(Node):
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.filename = kwargs['filename']
        self.at = Point(kwargs['at'])
        self.scale = Point(kwargs['scale'])
        self.rotate = Point(kwargs['rotate'])

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = ['filename: {filename}'.format(filename=self.filename),
                         'at: {at}'.format(at=self.at.render('(xyz {x} {y} {z})')),
                         'scale: {scale}'.format(scale=self.scale.render('(xyz {x} {y} {z})')),
                         'rotate: {rotate}'.format(rotate=self.rotate.render('(xyz {x} {y} {z})'))]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text
Beispiel #8
0
class Text(Node):
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.type = kwargs['type']
        self.text = kwargs['text']
        self.at = Point(kwargs['at'])
        self.rotation = kwargs.get('rotation', 0)

        self.layer = kwargs['layer']
        self.size = Point(kwargs.get('size', [1, 1]))
        self.thickness = kwargs.get('thickness', 0.15)

        self.hide = kwargs.get('hide', False)

    def calculateBoundingBox(self):
        width = len(self.text) * self.size['x']
        height = self.size['y']

        min_x = self.at[x] - width / 2.
        min_y = self.at[y] - height / 2.
        max_x = self.at[x] + width / 2.
        max_y = self.at[y] + height / 2.

        return Node.calculateBoundingBox({
            'min': Point(min_x, min_y),
            'max': Point(max_x, max_y)
        })

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = [
            'type: "{}"'.format(self.type), 'text: "{}"'.format(self.text),
            'at: {}'.format(self.at.render('(at {x} {y})')),
            'layer: {}'.format(self.layer),
            'size: {}'.format(self.size.render('(size {x} {y})')),
            'thickness: {}'.format(self.thickness)
        ]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text
class Model(Node):
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.filename = kwargs['filename']
        self.at = Point(kwargs.get('at', [0, 0, 0]))
        self.scale = Point(kwargs.get('scale', [1, 1, 1]))
        self.rotate = Point(kwargs.get('rotate', [0, 0, 0]))

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = [
            'filename: {filename}'.format(filename=self.filename),
            'at: {at}'.format(at=self.at.render('(xyz {x} {y} {z})')),
            'scale: {scale}'.format(
                scale=self.scale.render('(xyz {x} {y} {z})')),
            'rotate: {rotate}'.format(
                rotate=self.rotate.render('(xyz {x} {y} {z})'))
        ]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text
class Arc(Node):
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.center_pos = Point(kwargs['center'])
        self.start_pos = Point(kwargs['start'])
        self.angle = kwargs['angle']

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def calculateBoundingBox(self):
        # TODO: finish implementation
        min_x = min(self.start_pos.x, self._calulateEndPos().x)
        min_y = min(self.start_pos.x, self._calulateEndPos().y)
        max_x = max(self.start_pos.x, self._calulateEndPos().x)
        max_y = max(self.start_pos.x, self._calulateEndPos().y)

        '''
        for angle in range(4):
            float_angle = angle * math.pi/2.

            start_angle = _calculateStartAngle(self)
            end_angle = start_angle + math.radians(self.angle)

            # TODO: +- pi border
            if float_angle < start_angle:
                continue
            if float_angle > end_angle:
                continue

            print("TODO: add angle side: {1}".format(float_angle))
        '''

        return Node.calculateBoundingBox({'min': Point((min_x, min_y)), 'max': Point((max_x, max_y))})

    def _calulateEndPos(self):
        radius = self._calculateRadius()

        angle = self._calculateStartAngle() + math.radians(self.angle)

        return Point(math.sin(angle)*radius, math.cos(angle)*radius)

    def _calculateRadius(self):
        x_size = self.start_pos.x - self.center_pos.x
        y_size = self.start_pos.y - self.center_pos.y

        return math.sqrt(math.pow(x_size, 2) + math.pow(y_size, 2))

    def _calculateStartAngle(self):
        x_size = self.start_pos.x - self.center_pos.x
        y_size = self.start_pos.y - self.center_pos.y

        return math.atan2(y_size, x_size)

    def _getRenderTreeText(self):
        render_strings = ['fp_arc']
        render_strings.append(self.center_pos.render('(center {x} {y})'))
        render_strings.append(self.start_pos.render('(start {x} {y})'))
        render_strings.append('(angle {angle})'.format(angle=self.angle))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text
class Text(Node):
    r"""Add a Line to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *type* (``str``) --
          type of text
        * *text* (``str``) --
          text which is been visualized
        * *at* (``Point``) --
          position of text
        * *rotation* (``float``) --
          rotation of text
        * *layer* (``str``) --
          layer on which the text is drawn
        * *size* (``Point``) --
          size of the text
        * *thickness* (``float``) --
          thickness of the text
        * *hide* (``bool``) --
          hide text

    :Example:

    >>> from KicadModTree import *
    >>> Text(type='reference', text='REF**', at=[0, -3], layer='F.SilkS')
    >>> Text(type='value', text="footprint name", at=[0, 3], layer='F.Fab')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.type = kwargs['type']
        self.text = kwargs['text']
        self.at = Point(kwargs['at'])
        self.rotation = kwargs.get('rotation', 0)

        self.layer = kwargs['layer']
        self.size = Point(kwargs.get('size', [1, 1]))
        self.thickness = kwargs.get('thickness', 0.15)

        self.hide = kwargs.get('hide', False)

    def calculateBoundingBox(self):
        width = len(self.text)*self.size['x']
        height = self.size['y']

        min_x = self.at[x]-width/2.
        min_y = self.at[y]-height/2.
        max_x = self.at[x]+width/2.
        max_y = self.at[y]+height/2.

        return Node.calculateBoundingBox({'min': Point(min_x, min_y), 'max': Point(max_x, max_y)})

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = ['type: "{}"'.format(self.type),
                         'text: "{}"'.format(self.text),
                         'at: {}'.format(self.at.render('(at {x} {y})')),
                         'layer: {}'.format(self.layer),
                         'size: {}'.format(self.size.render('(size {x} {y})')),
                         'thickness: {}'.format(self.thickness)]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text
Beispiel #12
0
class Pad(Node):
    TYPE_THT = 'thru_hole'
    TYPE_SMT = 'smd'
    TYPE_CONNECT = 'connect'
    TYPE_NPTH = 'np_thru_hole'
    _TYPES = [TYPE_THT, TYPE_SMT, TYPE_CONNECT, TYPE_NPTH]

    SHAPE_CIRCLE = 'circle'
    SHAPE_OVAL = 'oval'
    SHAPE_RECT = 'rect'
    SHAPE_TRAPEZE = 'trapezoid'
    _SHAPES = [SHAPE_CIRCLE, SHAPE_OVAL, SHAPE_RECT, SHAPE_TRAPEZE]

    def __init__(self, **kwargs):
        Node.__init__(self)

        self._initNumber(**kwargs)
        self._initType(**kwargs)
        self._initShape(**kwargs)
        self._initPosition(**kwargs)
        self._initSize(**kwargs)
        self._initOffset(**kwargs)
        self._initDrill(**kwargs)  # requires pad type and offset
        self._initSolderPasteMargin(**kwargs)
        self._initLayers(**kwargs)

    def _initNumber(self, **kwargs):
        self.number = kwargs.get('number')

    def _initType(self, **kwargs):
        if not kwargs.get('type'):
            raise KeyError('type not declared (like "type=Pad.TYPE_THT")')
        self.type = kwargs.get('type')
        if self.type not in Pad._TYPES:
            raise ValueError(
                '{type} is an invalid type for pads'.format(type=self.type))

    def _initShape(self, **kwargs):
        if not kwargs.get('shape'):
            raise KeyError(
                'shape not declared (like "shape=Pad.SHAPE_CIRCLE")')
        self.shape = kwargs.get('shape')
        if self.shape not in Pad._SHAPES:
            raise ValueError('{shape} is an invalid shape for pads'.format(
                shape=self.shape))

    def _initPosition(self, **kwargs):
        if not kwargs.get('at'):
            raise KeyError('center position not declared (like "at=[0,0]")')
        self.at = Point(kwargs.get('at'))

        self.rotation = kwargs.get('rotation', 0)

    def _initSize(self, **kwargs):
        if not kwargs.get('size'):
            raise KeyError('pad size not declared (like "size=[1,1]")')
        if type(kwargs.get('size')) in [int, float]:
            # when the attribute is a simple number, use it for x and y
            self.size = Point([kwargs.get('size'), kwargs.get('size')])
        else:
            self.size = Point(kwargs.get('size'))

    def _initOffset(self, **kwargs):
        self.offset = Point(kwargs.get('offset', [0, 0]))

    def _initDrill(self, **kwargs):
        if self.type in [Pad.TYPE_THT, Pad.TYPE_NPTH]:
            if not kwargs.get('drill'):
                raise KeyError('drill size required (like "drill=1")')
            if type(kwargs.get('drill')) in [int, float]:
                # when the attribute is a simple number, use it for x and y
                self.drill = Point([kwargs.get('drill'), kwargs.get('drill')])
            else:
                self.drill = Point(kwargs.get('drill'))
            if self.drill.x < 0 or self.drill.y < 0:
                raise ValueError("negative drill size not allowed")
        else:
            self.drill = None
            if kwargs.get('drill'):
                pass  # TODO: throw warning because drill is not supported

    def _initSolderPasteMargin(self, **kwargs):
        self.solder_paste_margin_ratio = kwargs.get(
            'solder_paste_margin_ratio', 0)

    def _initLayers(self, **kwargs):
        if not kwargs.get('layers'):
            raise KeyError(
                'layers not declared (like "layers=[\'*.Cu\', \'*.Mask\', \'F.SilkS\']")'
            )
        self.layers = kwargs.get('layers')

    def calculateBoundingBox(self):
        return Node.calculateBoundingBox(self)

    def _getRenderTreeText(self):
        render_strings = ['pad']
        render_strings.append(lispString(self.number))
        render_strings.append(lispString(self.type))
        render_strings.append(lispString(self.shape))
        render_strings.append(self.at.render('(at {x} {y})'))
        render_strings.append(self.size.render('(size {x} {y})'))
        render_strings.append('(drill {})'.format(self.drill))
        render_strings.append('(layers {})'.format(' '.join(self.layers)))

        render_text = Node._getRenderTreeText(self)
        render_text += '({})'.format(' '.join(render_strings))

        return render_text
Beispiel #13
0
class Arc(Node):
    r"""Add an Arc to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *center* (``Point``) --
          center of arc
        * *start* (``Point``) --
          start point of arc
        * *angle* (``float``) --
          angle of arc
        * *layer* (``str``) --
          layer on which the arc is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the arc line (default: None, which means auto detection)

    :Example:

    >>> from KicadModTree import *
    >>> Arc(center=[0, 0], start=[-1, 0], angle=180, layer='F.SilkS')
    """
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.center_pos = Point(kwargs['center'])
        self.start_pos = Point(kwargs['start'])
        self.angle = kwargs['angle']

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def calculateBoundingBox(self):
        # TODO: finish implementation
        min_x = min(self.start_pos.x, self._calulateEndPos().x)
        min_y = min(self.start_pos.x, self._calulateEndPos().y)
        max_x = max(self.start_pos.x, self._calulateEndPos().x)
        max_y = max(self.start_pos.x, self._calulateEndPos().y)
        '''
        for angle in range(4):
            float_angle = angle * math.pi/2.

            start_angle = _calculateStartAngle(self)
            end_angle = start_angle + math.radians(self.angle)

            # TODO: +- pi border
            if float_angle < start_angle:
                continue
            if float_angle > end_angle:
                continue

            print("TODO: add angle side: {1}".format(float_angle))
        '''

        return Node.calculateBoundingBox({
            'min': Point((min_x, min_y)),
            'max': Point((max_x, max_y))
        })

    def _calulateEndPos(self):
        radius = self._calculateRadius()

        angle = self._calculateStartAngle() + math.radians(self.angle)

        return Point(math.sin(angle) * radius, math.cos(angle) * radius)

    def _calculateRadius(self):
        x_size = self.start_pos.x - self.center_pos.x
        y_size = self.start_pos.y - self.center_pos.y

        return math.sqrt(math.pow(x_size, 2) + math.pow(y_size, 2))

    def _calculateStartAngle(self):
        x_size = self.start_pos.x - self.center_pos.x
        y_size = self.start_pos.y - self.center_pos.y

        return math.atan2(y_size, x_size)

    def _getRenderTreeText(self):
        render_strings = ['fp_arc']
        render_strings.append(self.center_pos.render('(center {x} {y})'))
        render_strings.append(self.start_pos.render('(start {x} {y})'))
        render_strings.append('(angle {angle})'.format(angle=self.angle))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text
Beispiel #14
0
class Pad(Node):
    r"""Add a Pad to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *number* (``int``, ``str``) --
          number/name of the pad (default: \"\")
        * *type* (``Pad.TYPE_THT``, ``Pad.TYPE_SMT``, ``Pad.TYPE_CONNECT``, ``Pad.TYPE_NPTH``) --
          type of the pad
        * *shape* (``Pad.SHAPE_CIRCLE``, ``Pad.SHAPE_OVAL``, ``Pad.SHAPE_RECT``, ``Pad.SHAPE_TRAPEZE``) --
          shape of the pad
        * *at* (``Point``) --
          center position of the pad
        * *rotation* (``float``) --
          rotation of the pad
        * *size* (``float``, ``Point``) --
          size of the pad
        * *offset* (``Point``) --
          offset of the pad
        * *drill* (``float``, ``Point``) --
          drill-size of the pad
        * *solder_paste_margin_ratio* (``float``) --
          solder paste margin ratio of the pad (default: 0)
        * *layers* (``Pad.LAYERS_SMT``, ``Pad.LAYERS_THT``, ``Pad.LAYERS_NPTH``) --
          layers on which are used for the pad

    :Example:

    >>> from KicadModTree import *
    >>> Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    ...     at=[0, 0], size=[2, 2], drill=1.2, layers=Pad.LAYERS_THT)
    """

    TYPE_THT = 'thru_hole'
    TYPE_SMT = 'smd'
    TYPE_CONNECT = 'connect'
    TYPE_NPTH = 'np_thru_hole'
    _TYPES = [TYPE_THT, TYPE_SMT, TYPE_CONNECT, TYPE_NPTH]

    SHAPE_CIRCLE = 'circle'
    SHAPE_OVAL = 'oval'
    SHAPE_RECT = 'rect'
    SHAPE_TRAPEZE = 'trapezoid'
    _SHAPES = [SHAPE_CIRCLE, SHAPE_OVAL, SHAPE_RECT, SHAPE_TRAPEZE]

    LAYERS_SMT = ['F.Cu', 'F.Mask', 'F.Paste']
    LAYERS_THT = ['*.Cu', '*.Mask']
    LAYERS_NPTH = ['*.Cu', '*.Mask']

    def __init__(self, **kwargs):
        Node.__init__(self)

        self._initNumber(**kwargs)
        self._initType(**kwargs)
        self._initShape(**kwargs)
        self._initPosition(**kwargs)
        self._initSize(**kwargs)
        self._initOffset(**kwargs)
        self._initDrill(**kwargs)  # requires pad type and offset
        self._initSolderPasteMargin(**kwargs)
        self._initLayers(**kwargs)

    def _initNumber(self, **kwargs):
        self.number = kwargs.get('number', "")  # default to an un-numbered pad

    def _initType(self, **kwargs):
        if not kwargs.get('type'):
            raise KeyError('type not declared (like "type=Pad.TYPE_THT")')
        self.type = kwargs.get('type')
        if self.type not in Pad._TYPES:
            raise ValueError('{type} is an invalid type for pads'.format(type=self.type))

    def _initShape(self, **kwargs):
        if not kwargs.get('shape'):
            raise KeyError('shape not declared (like "shape=Pad.SHAPE_CIRCLE")')
        self.shape = kwargs.get('shape')
        if self.shape not in Pad._SHAPES:
            raise ValueError('{shape} is an invalid shape for pads'.format(shape=self.shape))

    def _initPosition(self, **kwargs):
        if not kwargs.get('at'):
            raise KeyError('center position not declared (like "at=[0,0]")')
        self.at = Point(kwargs.get('at'))

        self.rotation = kwargs.get('rotation', 0)

    def _initSize(self, **kwargs):
        if not kwargs.get('size'):
            raise KeyError('pad size not declared (like "size=[1,1]")')
        if type(kwargs.get('size')) in [int, float]:
            # when the attribute is a simple number, use it for x and y
            self.size = Point([kwargs.get('size'), kwargs.get('size')])
        else:
            self.size = Point(kwargs.get('size'))

    def _initOffset(self, **kwargs):
        self.offset = Point(kwargs.get('offset', [0, 0]))

    def _initDrill(self, **kwargs):
        if self.type in [Pad.TYPE_THT, Pad.TYPE_NPTH]:
            if not kwargs.get('drill'):
                raise KeyError('drill size required (like "drill=1")')
            if type(kwargs.get('drill')) in [int, float]:
                # when the attribute is a simple number, use it for x and y
                self.drill = Point([kwargs.get('drill'), kwargs.get('drill')])
            else:
                self.drill = Point(kwargs.get('drill'))
            if self.drill.x < 0 or self.drill.y < 0:
                raise ValueError("negative drill size not allowed")
        else:
            self.drill = None
            if kwargs.get('drill'):
                pass  # TODO: throw warning because drill is not supported

    def _initSolderPasteMargin(self, **kwargs):
        self.solder_paste_margin_ratio = kwargs.get('solder_paste_margin_ratio', 0)

    def _initLayers(self, **kwargs):
        if not kwargs.get('layers'):
            raise KeyError('layers not declared (like "layers=[\'*.Cu\', \'*.Mask\', \'F.SilkS\']")')
        self.layers = kwargs.get('layers')

    # calculate the outline of a pad
    def calculateBoundingBox(self):
        return Node.calculateBoundingBox(self)

    def _getRenderTreeText(self):
        render_strings = ['padd']
        render_strings.append(lispString(self.number))
        render_strings.append(lispString(self.type))
        render_strings.append(lispString(self.shape))
        render_strings.append(self.at.render('(at {x} {y})'))
        render_strings.append(self.size.render('(size {x} {y})'))
        print self.offset
        if self.offset == [0, 0]:
            render_strings.append('(drill {})'.format(self.drill))
        else:
            render_strings.append('(drill {} (offset {} {}))'.format(self.drill, self.offset[0], self.offset[1]))
        render_strings.append('(layers {})'.format(' '.join(self.layers)))

        render_text = Node._getRenderTreeText(self)
        render_text += '({})'.format(' '.join(render_strings))

        return render_text
class Pad(Node):
    TYPE_THT = 'thru_hole'
    TYPE_SMT = 'smd'
    TYPE_CONNECT = 'connect'
    TYPE_NPTH = 'np_thru_hole'
    _TYPES = [TYPE_THT, TYPE_SMT, TYPE_CONNECT, TYPE_NPTH]

    SHAPE_CIRCLE = 'circle'
    SHAPE_OVAL = 'oval'
    SHAPE_RECT = 'rect'
    SHAPE_TRAPEZE = 'trapezoid'
    _SHAPES = [SHAPE_CIRCLE, SHAPE_OVAL, SHAPE_RECT, SHAPE_TRAPEZE]
    
    LAYERS_SMT = ['F.Cu','F.Mask','F.Paste']
    LAYERS_THT = ['*.Cu','*.Mask']
    LAYERS_NPTH = ['*.Cu']

    def __init__(self, **kwargs):
        Node.__init__(self)

        self._initNumber(**kwargs)
        self._initType(**kwargs)
        self._initShape(**kwargs)
        self._initPosition(**kwargs)
        self._initSize(**kwargs)
        self._initOffset(**kwargs)
        self._initDrill(**kwargs)  # requires pad type and offset
        self._initSolderPasteMargin(**kwargs)
        self._initLayers(**kwargs)

    def _initNumber(self, **kwargs):
        self.number = kwargs.get('number','""') #default to an un-numbered pad

    def _initType(self, **kwargs):
        if not kwargs.get('type'):
            raise KeyError('type not declared (like "type=Pad.TYPE_THT")')
        self.type = kwargs.get('type')
        if self.type not in Pad._TYPES:
            raise ValueError('{type} is an invalid type for pads'.format(type=self.type))

    def _initShape(self, **kwargs):
        if not kwargs.get('shape'):
            raise KeyError('shape not declared (like "shape=Pad.SHAPE_CIRCLE")')
        self.shape = kwargs.get('shape')
        if self.shape not in Pad._SHAPES:
            raise ValueError('{shape} is an invalid shape for pads'.format(shape=self.shape))

    def _initPosition(self, **kwargs):
        if not kwargs.get('at'):
            raise KeyError('center position not declared (like "at=[0,0]")')
        self.at = Point(kwargs.get('at'))

        self.rotation = kwargs.get('rotation', 0)

    def _initSize(self, **kwargs):
        if not kwargs.get('size'):
            raise KeyError('pad size not declared (like "size=[1,1]")')
        if type(kwargs.get('size')) in [int, float]:
            # when the attribute is a simple number, use it for x and y
            self.size = Point([kwargs.get('size'), kwargs.get('size')])
        else:
            self.size = Point(kwargs.get('size'))

    def _initOffset(self, **kwargs):
        self.offset = Point(kwargs.get('offset', [0, 0]))

    def _initDrill(self, **kwargs):
        if self.type in [Pad.TYPE_THT, Pad.TYPE_NPTH]:
            if not kwargs.get('drill'):
                raise KeyError('drill size required (like "drill=1")')
            if type(kwargs.get('drill')) in [int, float]:
                # when the attribute is a simple number, use it for x and y
                self.drill = Point([kwargs.get('drill'), kwargs.get('drill')])
            else:
                self.drill = Point(kwargs.get('drill'))
            if self.drill.x < 0 or self.drill.y < 0:
                raise ValueError("negative drill size not allowed")
        else:
            self.drill = None
            if kwargs.get('drill'):
                pass  # TODO: throw warning because drill is not supported

    def _initSolderPasteMargin(self, **kwargs):
        self.solder_paste_margin_ratio = kwargs.get('solder_paste_margin_ratio', 0)

    def _initLayers(self, **kwargs):
        if not kwargs.get('layers'):
            raise KeyError('layers not declared (like "layers=[\'*.Cu\', \'*.Mask\', \'F.SilkS\']")')
        self.layers = kwargs.get('layers')

    #calculate the outline of a pad
    def calculateBoundingBox(self):
        return Node.calculateBoundingBox(self)

    def _getRenderTreeText(self):
        render_strings = ['pad']
        render_strings.append(lispString(self.number))
        render_strings.append(lispString(self.type))
        render_strings.append(lispString(self.shape))
        render_strings.append(self.at.render('(at {x} {y})'))
        render_strings.append(self.size.render('(size {x} {y})'))
        render_strings.append('(drill {})'.format(self.drill))
        render_strings.append('(layers {})'.format(' '.join(self.layers)))

        render_text = Node._getRenderTreeText(self)
        render_text += '({})'.format(' '.join(render_strings))

        return render_text
Beispiel #16
0
class Arc(Node):
    def __init__(self, **kwargs):
        Node.__init__(self)
        self.center_pos = Point(kwargs['center'])
        self.start_pos = Point(kwargs['start'])
        self.angle = kwargs['angle']

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def calculateBoundingBox(self):
        # TODO: finish implementation
        min_x = min(self.start_pos.x, self._calulateEndPos().x)
        min_y = min(self.start_pos.x, self._calulateEndPos().y)
        max_x = max(self.start_pos.x, self._calulateEndPos().x)
        max_y = max(self.start_pos.x, self._calulateEndPos().y)
        '''
        for angle in range(4):
            float_angle = angle * math.pi/2.

            start_angle = _calculateStartAngle(self)
            end_angle = start_angle + math.radians(self.angle)

            # TODO: +- pi border
            if float_angle < start_angle:
                continue
            if float_angle > end_angle:
                continue

            print("TODO: add angle side: {1}".format(float_angle))
        '''

        return Node.calculateBoundingBox({
            'min': Point((min_x, min_y)),
            'max': Point((max_x, max_y))
        })

    def _calulateEndPos(self):
        radius = self._calculateRadius()

        angle = self._calculateStartAngle() + math.radians(self.angle)

        return Point(math.sin(angle) * radius, math.cos(angle) * radius)

    def _calculateRadius(self):
        x_size = self.start_pos.x - self.center_pos.x
        y_size = self.start_pos.y - self.center_pos.y

        return math.sqrt(math.pow(x_size, 2) + math.pow(y_size, 2))

    def _calculateStartAngle(self):
        x_size = self.start_pos.x - self.center_pos.x
        y_size = self.start_pos.y - self.center_pos.y

        return math.atan2(y_size, x_size)

    def _getRenderTreeText(self):
        render_strings = ['fp_arc']
        render_strings.append(self.center_pos.render('(center {x} {y})'))
        render_strings.append(self.start_pos.render('(start {x} {y})'))
        render_strings.append('(angle {angle})'.format(angle=self.angle))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text