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
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 __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")
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
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 __init__(self, **kwargs): self.start_pos = Point(kwargs['start']) self.end_pos = Point(kwargs['end']) polygone_line = [{ 'x': self.start_pos.x, 'y': self.start_pos.y }, { 'x': self.start_pos.x, 'y': self.end_pos.y }, { 'x': self.end_pos.x, 'y': self.end_pos.y }, { 'x': self.end_pos.x, 'y': self.start_pos.y }, { 'x': self.start_pos.x, 'y': self.start_pos.y }] PolygoneLine.__init__(self, polygone=polygone_line, layer=kwargs.get('layer', 'F.SilkS'), width=kwargs.get('width'))
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 _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 __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 __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', 0.12) # TODO: auto detection self.virtual_childs = self._createChildNodes(self.start_pos, self.end_pos, self.layer, self.width)
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 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 __init__(self, **kwargs): self.start_pos = Point(kwargs['start']) self.end_pos = Point(kwargs['end']) # If specifed, an 'offset' can be applied to the RectLine. # For example, creating a border around a given Rect of a specified size if kwargs.get('offset'): # offset for the rect line # e.g. for creating a rectLine 0.5mm LARGER than the given rect, or similar offset = [0, 0] # Has an offset / inset been specified? if type(kwargs['offset']) in [int, float]: offset[0] = offset[1] = kwargs['offset'] elif type(kwargs['offset']) in [list, tuple] and len( kwargs['offset']) == 2: # Ensure that all offset params are numerical if all([type(i) in [int, float] for i in kwargs['offset']]): offset = kwargs['offset'] # For the offset to work properly, start-pos must be top-left, and end-pos must be bottom-right x1 = min(self.start_pos.x, self.end_pos.x) x2 = max(self.start_pos.x, self.end_pos.x) y1 = min(self.start_pos.y, self.end_pos.y) y2 = max(self.start_pos.y, self.end_pos.y) # Put the offset back in self.start_pos.x = x1 - offset[0] self.start_pos.y = y1 - offset[1] self.end_pos.x = x2 + offset[0] self.end_pos.y = y2 + offset[1] polygone_line = [{ 'x': self.start_pos.x, 'y': self.start_pos.y }, { 'x': self.start_pos.x, 'y': self.end_pos.y }, { 'x': self.end_pos.x, 'y': self.end_pos.y }, { 'x': self.end_pos.x, 'y': self.start_pos.y }, { 'x': self.start_pos.x, 'y': self.start_pos.y }] PolygoneLine.__init__(self, polygone=polygone_line, layer=kwargs['layer'], width=kwargs.get('width'))
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
def getRealPosition(self, coordinate, rotation=None): ''' return position of point after applying all transformation and rotation operations ''' if not self._parent: if rotation is None: return Point(coordinate) else: return Point(coordinate), rotation return self._parent.getRealPosition(coordinate, rotation)
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
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 __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', 0.15) # TODO: better variation to get line width self.virtual_childs = self._createChildNodes(self.start_pos, self.end_pos, self.layer, self.width)
def testInit(self): p1 = Point([1, 2, 3]) self.assertEqual(p1.x, 1) self.assertEqual(p1.y, 2) self.assertEqual(p1.z, 3) p1_xy = Point([1, 2]) self.assertEqual(p1_xy.x, 1) self.assertEqual(p1_xy.y, 2) self.assertEqual(p1_xy.z, 0) p2 = Point((4, 5, 6)) self.assertEqual(p2.x, 4) self.assertEqual(p2.y, 5) self.assertEqual(p2.z, 6) p2_xy = Point((4, 5)) self.assertEqual(p2_xy.x, 4) self.assertEqual(p2_xy.y, 5) self.assertEqual(p2_xy.z, 0) p3 = Point({'x': 7, 'y': 8, 'z': 9}) self.assertEqual(p3.x, 7) self.assertEqual(p3.y, 8) self.assertEqual(p3.z, 9) p3_xy = Point({'x': 7, 'y': 8}) self.assertEqual(p3_xy.x, 7) self.assertEqual(p3_xy.y, 8) self.assertEqual(p3_xy.z, 0) p3_empty = Point({}) self.assertEqual(p3_empty.x, 0) self.assertEqual(p3_empty.y, 0) self.assertEqual(p3_empty.z, 0) p4 = Point(p1) self.assertEqual(p4.x, 1) self.assertEqual(p4.y, 2) self.assertEqual(p4.z, 3) p5 = Point(1, 2, 3) self.assertEqual(p5.x, 1) self.assertEqual(p5.y, 2) self.assertEqual(p5.z, 3) p5_xy = Point(1, 2) self.assertEqual(p5_xy.x, 1) self.assertEqual(p5_xy.y, 2) self.assertEqual(p5_xy.z, 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 getRealPosition(self, coordinate, rotation=None): if rotation is None: rotation = 0 parsed_coordinate = Point(coordinate) phi = self.rotation * math.pi / 180 rotation_coordinate = { 'x': parsed_coordinate.x * math.cos(phi) + parsed_coordinate.y * math.sin(phi), 'y': -parsed_coordinate.x * math.sin(phi) + parsed_coordinate.y * math.cos(phi) } if not self._parent: if rotation is None: return rotation_coordinate else: return rotation_coordinate, rotation + self.rotation else: if rotation is None: rotation = 0 return self._parent.getRealPosition(rotation_coordinate, rotation + self.rotation)
def _createChildNodes(self, start_pos, end_pos, layer, width): nodes = [] cur_y_pos = min([start_pos.y, end_pos.y]) max_y_pos = max([start_pos.y, end_pos.y]) while (cur_y_pos + width) < max_y_pos: cur_y_pos += width new_node = Line(start=Point(start_pos.x, cur_y_pos), end=Point(end_pos.x, cur_y_pos), layer=layer, width=width) new_node._parent = self nodes.append(new_node) return nodes
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', 0.15) # TODO: better variation to get line width rect_line = RectLine(**kwargs) rect_line._parent = self rect_fill = RectFill(**kwargs) rect_fill._parent = self self.virtual_childs = [rect_line, rect_fill]
def testSub(self): p1 = Point([1, 2, 3]) self.assertEqual(p1.x, 1) self.assertEqual(p1.y, 2) self.assertEqual(p1.z, 3) p2 = p1 - 5 self.assertEqual(p2.x, -4) self.assertEqual(p2.y, -3) self.assertEqual(p2.z, -2) p3 = p1 - (-5) self.assertEqual(p3.x, 6) self.assertEqual(p3.y, 7) self.assertEqual(p3.z, 8) p4 = p1 - [4, 2, -2] self.assertEqual(p4.x, -3) self.assertEqual(p4.y, 0) self.assertEqual(p4.z, 5) p5 = p1 - [-5, -3] self.assertEqual(p5.x, 6) self.assertEqual(p5.y, 5) self.assertEqual(p5.z, 3)
def testMul(self): p1 = Point([1, 2, 3]) self.assertEqual(p1.x, 1) self.assertEqual(p1.y, 2) self.assertEqual(p1.z, 3) p2 = p1 * 5 self.assertEqual(p2.x, 5) self.assertEqual(p2.y, 10) self.assertEqual(p2.z, 15) p3 = p1 * (-5) self.assertEqual(p3.x, -5) self.assertEqual(p3.y, -10) self.assertEqual(p3.z, -15) p4 = p1 * [4, 5, -2] self.assertEqual(p4.x, 4) self.assertEqual(p4.y, 10) self.assertEqual(p4.z, -6) p5 = p1 * [-5, -3] self.assertEqual(p5.x, -5) self.assertEqual(p5.y, -6) self.assertEqual(p5.z, 3)
def testDiv(self): p1 = Point([1, 2, 3]) self.assertEqual(p1.x, 1) self.assertEqual(p1.y, 2) self.assertEqual(p1.z, 3) p2 = p1 / 5 self.assertEqual(p2.x, 0.2) self.assertEqual(p2.y, 0.4) self.assertEqual(p2.z, 0.6) p3 = p1 / (-5) self.assertEqual(p3.x, -0.2) self.assertEqual(p3.y, -0.4) self.assertEqual(p3.z, -0.6) p4 = p1 / [4, 5, -2] self.assertEqual(p4.x, 0.25) self.assertEqual(p4.y, 0.4) self.assertEqual(p4.z, -1.5) p5 = p1 / [-5, -2] self.assertEqual(p5.x, -0.2) self.assertEqual(p5.y, -1) self.assertEqual(p5.z, 3)
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
def testAdd(self): p1 = Point([1, 2, 3]) self.assertEqual(p1.x, 1) self.assertEqual(p1.y, 2) self.assertEqual(p1.z, 3) p2 = p1 + 5 self.assertEqual(p2.x, 6) self.assertEqual(p2.y, 7) self.assertEqual(p2.z, 8) p3 = p1 + (-5) self.assertEqual(p3.x, -4) self.assertEqual(p3.y, -3) self.assertEqual(p3.z, -2) p4 = p1 + [4, 2, -2] self.assertEqual(p4.x, 5) self.assertEqual(p4.y, 4) self.assertEqual(p4.z, 1) p5 = p1 + [-5, -3] self.assertEqual(p5.x, -4) self.assertEqual(p5.y, -1) self.assertEqual(p5.z, 3)
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
def calculateBoundingBox(self, outline=None): min_x, min_y = 0, 0 max_x, max_y = 0, 0 if outline: min_x = outline['min']['x'] min_y = outline['min']['y'] max_x = outline['max']['x'] max_y = outline['max']['y'] for child in self.getAllChilds(): child_outline = child.calculateBoundingBox() min_x = min([min_x, child_outline['min']['x']]) min_y = min([min_y, child_outline['min']['y']]) max_x = max([max_x, child_outline['max']['x']]) max_y = max([max_y, child_outline['max']['y']]) return {'min': Point(min_x, min_y), 'max': Point(max_x, max_y)}
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
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
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]))
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
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 __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'])
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