Example #1
0
  def export_footprint(self, interim, timestamp = None):
    if timestamp is None:
      timestamp = time.time()
    meta = inter.get_meta(interim)
    name = eget(meta, 'name', 'Name not found')
    # make name kicad compatible
    name = re.sub(' ','_',name)
    self.name = name
    desc = oget(meta, 'desc', '')
    parent_idx = oget(meta, 'parent', None)
    d = []
    # generate kicad-old for individual footprint
    # use metric; convert to imperial in "save" if needed
    d.append("$MODULE %s" % (name))
    d.append("Po 0 0 0 15 %x 00000000 ~~" % timestamp)
    d.append("Li %s" % (name))
    d.append("Cd %s" % (desc.replace('\n',' '))) # ugly
    # assuming Kw is optional
    d.append("Sc 0")
    # d.append("AR ") assume AR is optional
    d.append("Op 0 0 0")
    # if no T0 or T1 are specified, kicad defaults to this:
    # right now I'm assuming this is optional
    # T0 0 0 1.524 1.524 0 0.15 N V 21 N ""
    # T1 0 0 1.524 1.524 0 0.15 N V 21 N ""

    def pad(shape, smd=False):
      l = ['$PAD']
      # Sh "<pad name>" shape Xsize Ysize Xdelta Ydelta Orientation
      # octagons are not supported by kicad
      if shape['shape'] == 'disc' or shape['shape'] == 'octagon':
        sh = 'C'
        dx = shape['r']*2
        dy = dx
      elif shape['shape'] == 'rect':
        dx = shape['dx']
        dy = shape['dy']
        sh = 'R'
        # any rect with roundness >= 50 is considered kicad 'oblong'
        if 'ro' in shape:
          if shape['ro'] >= 50:
            sh = 'O'
      rot = fget(shape, 'rot')*10
      l.append("Sh \"%s\" %s %s %s %s %s %s" 
               % (shape['name'], sh, dx, dy, 0, 0, rot))
      # Dr <Pad drill> Xoffset Yoffset (round hole)
      if not smd:
        l.append("Dr %s %s %s" % (fget(shape, 'drill'), 
          fget(shape, 'drill_off_dx'), fc(-fget(shape, 'drill_off_dy'))))
      # Po <x> <y>
      l.append("Po %s %s" % (fget(shape,'x'), fc(-fget(shape,'y'))))
      # At <Pad type> N <layer mask>
      t = 'STD'
      layer_mask = '00E0FFFF'
      if smd:
        t = 'SMD'
        layer_mask = '00888000'
      l.append("At %s N %s" % (t, layer_mask))
      l.append('Ne 0 ""')
      l.append("$ENDPAD")
      return l

    # DS Xstart Ystart Xend Yend Width Layer
    # DS 6000 1500 6000 -1500 120 21
    # DA Xcentre Ycentre Xstart_point Ystart_point angle width layer
    def vertex(shape, layer):
      l = []
      x1 = fget(shape, 'x1')
      y1 = fget(shape, 'y1')
      x2 = fget(shape, 'x2')
      y2 = fget(shape, 'y2')
      w = fget(shape, 'w')
      if not 'curve' in shape or shape['curve'] == 0.0:
        line = "DS %s %s %s %s %s %s" % (x1, fc(-y1), x2, fc(-y2), w, layer)
        l.append(line)
      else:
        curve =  fget(shape, 'curve')
        angle = curve*math.pi/180.0
        ((x0, y0), r, a1, a2) = mutil.calc_center_r_a1_a2((x1,y1),(x2,y2),angle)
        arc = "DA %f %f %f %f %s %s %s" % (x0, fc(-y0), x1, fc(-y1), int(round((-10.0)*(a2-a1))), w, layer)
        l.append(arc)
      return l

    # DC Xcentre Ycentre Xpoint Ypoint Width Layer
    def circle(shape, layer):
      l = []
      x = fget(shape, 'x')
      y = fget(shape, 'y')
      r = fget(shape, 'r')
      w = fget(shape, 'w')
      if not 'a1' in shape and not 'a2' in shape:
        circle = "DC %s %s %s %s %s %s" % (x, fc(-y), fc(x+(r/math.sqrt(2))), fc(-y+(r/math.sqrt(2))), w, layer)
        l.append(circle)
      else:
        # start == center point
        # end == start point of arc
        # angle == angled part in that direction
        a1 = fget(shape, 'a1')
        a2 = fget(shape, 'a2')
        a1rad = a1 * math.pi/180.0
        ex = x + r*math.cos(a1rad)
        ey = y + r*math.sin(a1rad)
        arc = "DA %f %f %f %f %s %s %s" % (x, fc(-y), ex, fc(-ey), int(round((-10)*(a2-a1))), w, layer)
        l.append(arc)
      return l
 
    def disc(shape, layer):
      l = []
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      r = fget(shape, 'r')
      rad = r/2
      ex = x+(rad/math.sqrt(2))
      ey = y+(rad/math.sqrt(2))
      circle = "DC %s %s %s %s %s %s" % (x, fc(y), fc(ex), fc(ey), rad, layer)
      l.append(circle)
      return l

    def hole(shape):
      layer = type_to_num(shape['type'])
      shape['r'] = shape['drill'] / 2
      return circle(shape, layer)

    # T0 -79 -3307 600 600 0 120 N V 21 N "XT"
    def label(shape, layer):
      s = shape['value'].upper()
      t = 'T2'
      visible = 'V'
      if s == 'VALUE': 
        t = 'T1'
        visible = 'I'
      if s == 'NAME': 
        t = 'T0'
      dy = fget(shape, 'dy', 1/1.6)
      w = fget(shape, 'w', 0.1)
      x = fget(shape, 'x')
      y = fc(-fget(shape, 'y'))
      # T0 -7 -3 60 60 0 10 N V 21 N "XT"
      line = "%s %s %s %s %s 0 %s N %s %s N \"%s\"" % (t, x, y, dy, dy, w, visible, layer, shape['value'])
      return [line]

    def rect(shape, layer):
      print "rect", shape, layer
      l = []
      w = fget(shape,'w')
      rot = abs(fget(shape, 'rot'))
      l.append("DP 0 0 0 0 %s %s %s" % (5, w, layer))
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      dx = fget(shape, 'dx')
      dy = fget(shape, 'dy')
      if rot == 90 or rot == 270:
        (dx,dy) = (dy,dx)
      def add(x1, y1):
        l.append("Dl %f %f" % (fc(x1), fc(y1)))
      add(x - dx/2, y - dy/2)
      add(x - dx/2, y + dy/2)
      add(x + dx/2, y + dy/2)
      add(x + dx/2, y - dy/2)
      add(x - dx/2, y - dy/2)
      return l
 
    # DP 0 0 0 0 corners_count width layer
    # DP 0 0 0 0 5 0.1 24
    # Dl corner_posx corner_posy
    # Dl 0 -1
    def polygon(shape, layer):
      l = []
      n = len(shape['v'])
      w = shape['w']
      l.append("DP 0 0 0 0 %s %s %s" % (n + 1, w, layer))
      for v in shape['v']:
        l.append("Dl %g %g" % (fc(v['x1']), fc(-v['y1'])))
      l.append("Dl %g %g" % (fc(shape['v'][0]['x1']), fc(-shape['v'][0]['y1'])))
      return l

    def silk(shape):
      if not 'shape' in shape: return None
      layer = type_to_num(shape['type'])
      s = shape['shape']
      if s == 'line': return vertex(shape, layer)
      if s == 'vertex': return vertex(shape, layer)
      elif s == 'circle': return circle(shape, layer)
      elif s == 'disc': return disc(shape, layer)
      elif s == 'label': return label(shape, layer)
      elif s == 'rect': return rect(shape, layer)
      elif s == 'polygon': return polygon(shape, layer) 

    def unknown(shape):
      return None

    for shape in interim:
      if 'type' in shape:
        l = {
          'pad': pad,
          'cu': silk,
          'silk': silk,
          'docu': silk,
          'keepout': unknown,
          'stop': silk,
          'glue': silk,
          'restrict': unknown,
          'vrestrict': unknown,
          'smd': lambda s: pad(s, smd=True),
          'hole': hole,
          }.get(shape['type'], unknown)(shape)
        if l != None:
         d += l
      
    d.append("$EndMODULE %s" % (name))
    self.data = d
    return name
Example #2
0
    def export_footprint(self, interim):
        meta = inter.get_meta(interim)
        name = eget(meta, 'name', 'Name not found')
        descr = oget(meta, 'desc', '')
        parent_idx = oget(meta, 'parent', None)
        l = [
            S('module'),
            S(name),
            [S('layer'), S('F.Cu')],
            [S('descr'), descr],
        ]

        def pad_line(x1, y1, x2, y2, width, layer):
            l = [S('fp_line')]
            l.append([S('start'), x1, y1])
            l.append([S('end'), x2, y2])
            l.append([S('layer'), S(layer)])
            l.append([S('width'), width])
            return l

        def pad_lines(s, x1, y1, x2, y2, width):
            s.append(pad_line(x1, y1, x2, y2, width, 'F.Cu'))
            s.append(pad_line(x1, y1, x2, y2, width, 'F.Paste'))
            s.append(pad_line(x1, y1, x2, y2, width, 'F.Mask'))

        def gen_lines(l, x, y, rot, radius, dx, dy):
            # 4 corners
            xo = dx / 2 - radius
            yo = dy / 2 - radius

            rot = math.radians(rot)

            xp = math.cos(rot) * xo - math.sin(rot) * yo
            yp = math.cos(rot) * yo + math.sin(rot) * xo

            x1 = x - xp
            x2 = x + xp
            y1 = y - yp
            y2 = y + yp

            pad_lines(l, x1, y1, x2, y1, radius * 2)
            pad_lines(l, x2, y1, x2, y2, radius * 2)
            pad_lines(l, x2, y2, x1, y2, radius * 2)
            pad_lines(l, x1, y2, x1, y1, radius * 2)

        def pad(shape, smd=False):
            want_paste = True
            if 'paste' in shape:
                want_paste = shape['paste']
            if 'name' in shape:
                name = shape['name']
                if name is None or name == "":
                    name = ""
                else:
                    name = S(name)
            else:
                name = ""
            l = [S('pad'), name]
            shapes = [l]
            if smd:
                l.append(S('smd'))
            else:
                l.append(S('thru_hole'))
            shape2 = 'disc'  # disc is the default
            if 'shape' in shape:
                shape2 = shape['shape']
            r = fget(shape, 'r')
            if shape2 == 'disc':
                l.append(S('circle'))
                l.append([S('size'), r * 2, r * 2])
            elif shape2 == 'rect':
                ro = iget(shape, 'ro')
                dx = fget(shape, 'dx')
                dy = fget(shape, 'dy')
                if ro == 100:
                    l.append(S('oval'))
                    l.append([S('size'), dx, dy])
                else:
                    l.append(S('rect'))
                    if ro == 0:
                        l.append([S('size'), dx, dy])
                    else:
                        #find the smallest dimension and create a rectangular pad squished by that amount
                        #TODO: the rectangular pad is simple with 4 lines, 1 rect and guaranteed no holes
                        #however it can create arbitrarily small pad which will make text in kicad hard to
                        #read. may be better to use a oval pad, which can be not shrunk and is still guaranteed
                        #to not overrun the pad, however it is tricky to make sure the 4 lines don't create any holes.
                        small = dx
                        if dy < dx:
                            small = dy
                        radius = small / 2 * ro / 100.0
                        l.append([S('size'), dx - radius * 2, dy - radius * 2])
                        gen_lines(shapes, fget(shape, 'x'), -fget(shape, 'y'),
                                  iget(shape, 'rot'), radius, dx, dy)
            else:
                raise Exception("%s shaped pad not supported in kicad" %
                                (shape2))
            l.append([
                S('at'),
                fget(shape, 'x'), -fget(shape, 'y'),
                iget(shape, 'rot')
            ])
            if smd:
                if shape['type'] != 'smd':
                    l.append([S('layers'), S('F.Paste')])
                else:
                    if want_paste:
                        l.append([
                            S('layers'),
                            S('F.Cu'),
                            S('F.Paste'),
                            S('F.Mask')
                        ])
                    else:
                        l.append([S('layers'), S('F.Cu'), S('F.Mask')])
            else:
                l.append([S('layers'), S('*.Cu'), S('*.Mask')])
            if not smd:
                if 'drill_dx' in shape or 'drill_dy' in shape:
                    drill_dx = fget(shape, 'drill_dx')
                    drill_dy = fget(shape, 'drill_dy')
                    l2 = [S('drill'), S('oval'), drill_dx, drill_dy]
                else:
                    l2 = [S('drill'), fget(shape, 'drill')]
                if 'drill_off_dx' in shape or 'drill_off_dy' in shape:
                    l2.append([
                        S('offset'),
                        fget(shape, 'drill_off_dx'),
                        fget(shape, 'drill_off_dy')
                    ])
                l.append(l2)
            l.append([S('solder_mask_margin'), fget(shape, 'mask_swell')])
            l.append(
                [S('solder_paste_margin_ratio'),
                 fget(shape, 'paste_ratio')])
            return shapes

        #(fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.381))
        # (fp_arc (start 7.62 0) (end 7.62 -2.54) (angle 90) (layer F.SilkS) (width 0.15))
        def vertex(shape, layer):
            if not 'curve' in shape or shape['curve'] == 0.0:
                l = [S('fp_line')]
                l.append([S('start'), fget(shape, 'x1'), -fget(shape, 'y1')])
                l.append([S('end'), fget(shape, 'x2'), -fget(shape, 'y2')])
                l.append([S('layer'), S(layer)])
                l.append([S('width'), fget(shape, 'w')])
            else:
                l = [S('fp_arc')]
                # start == center point
                # end == start point of arc
                # angle == angled part in that direction
                x1 = fget(shape, 'x1')
                y1 = fget(shape, 'y1')
                x2 = fget(shape, 'x2')
                y2 = fget(shape, 'y2')
                curve = fget(shape, 'curve')
                angle = curve * math.pi / 180.0
                ((x0, y0), r, a1, a2) = calc_center_r_a1_a2((x1, y1), (x2, y2),
                                                            angle)
                l.append([S('start'), fc(x0), fc(-y0)])
                l.append([S('end'), fc(x1), fc(-y1)])
                # also invert angle because of y inversion
                l.append([S('angle'), -(a2 - a1)])
                l.append([S('layer'), S(layer)])
                l.append([S('width'), fget(shape, 'w')])
            return [l]

        # (fp_circle (center 5.08 0) (end 6.35 -1.27) (layer F.SilkS) (width 0.15))
        def circle(shape, layer):
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            r = fget(shape, 'r')
            if not 'a1' in shape and not 'a2' in shape:
                l = [S('fp_circle')]
                l.append([S('center'), fc(x), fc(y)])
                l.append([
                    S('end'),
                    fc(x + (r / math.sqrt(2))),
                    fc(y + (r / math.sqrt(2)))
                ])
                l.append([S('layer'), S(layer)])
                l.append([S('width'), fget(shape, 'w')])
            else:
                l = [S('fp_arc')]
                l.append([S('start'), fc(x), fc(y)])
                # start == center point
                # end == start point of arc
                # angle == angled part in that direction
                a1 = fget(shape, 'a1')
                a2 = fget(shape, 'a2')
                a1rad = a1 * math.pi / 180.0
                ex = x + r * math.cos(a1rad)
                ey = y + r * math.sin(a1rad)
                l.append([S('end'), fc(ex), fc(-ey)])
                l.append([S('angle'), -(a2 - a1)])
            l.append([S('layer'), S(layer)])
            l.append([S('width'), fget(shape, 'w')])
            return [l]

        # a disc is just a circle with a clever radius and width
        def disc(shape, layer):
            l = [S('fp_circle')]
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            l.append([S('center'), fc(x), fc(y)])
            r = fget(shape, 'r')
            rad = r / 2
            l.append(
                [S('end'), x + (rad / math.sqrt(2)), y + (rad / math.sqrt(2))])
            l.append([S('layer'), S(layer)])
            l.append([S('width'), rad])
            return [l]

        def hole(shape):
            l = [S('pad'), ""]
            l.append(S('np_thru_hole'))
            l.append(S('circle'))
            l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y')])
            drill = fget(shape, 'drill')
            l.append([S('size'), drill, drill])
            l.append([S('drill'), drill])
            l.append([S('layers'), S('*.Cu'), S('*.Mask'), S('F.SilkS')])
            return [l]

        # (fp_poly (pts (xy 6.7818 1.6002) (xy 6.6294 1.6002) (xy 6.6294 1.4478) (xy 6.7818 1.4478) (xy 6.7818 1.6002)) (layer F.Cu) (width 0.00254))
        # kicad doesn't do arced vertex in polygon :(
        def polygon(shape, layer):
            l = [S('fp_poly')]
            lxy = [S('pts')]
            for v in shape['v']:
                xy = [S('xy'), fc(v['x1']), fc(-v['y1'])]
                lxy.append(xy)
            xy = [S('xy'), fc(shape['v'][0]['x1']), fc(-shape['v'][0]['y1'])]
            lxy.append(xy)
            l.append(lxy)
            l.append([S('layer'), S(layer)])
            l.append([S('width'), shape['w']])
            return [l]

        def rect(shape, layer):
            l = [S('fp_poly')]
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            dx = fget(shape, 'dx')
            dy = fget(shape, 'dy')
            rot = fget(shape, 'rot')
            if rot == 90 or rot == 270:
                (dx, dy) = (dy, dx)
            lxy = [S('pts')]

            def add(x1, y1):
                lxy.append([S('xy'), fc(x1), fc(y1)])

            add(x - dx / 2, y - dy / 2)
            add(x - dx / 2, y + dy / 2)
            add(x + dx / 2, y + dy / 2)
            add(x + dx / 2, y - dy / 2)
            add(x - dx / 2, y - dy / 2)
            l.append(lxy)
            l.append([S('layer'), S(layer)])
            l.append([S('width'), 0])
            return [l]

        # (fp_text reference MYCONN3 (at 0 -2.54) (layer F.SilkS)
        #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
        # )
        # (fp_text value SMD (at 0 2.54) (layer F.SilkS) hide
        #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
        # )
        def label(shape, layer):
            s = shape['value'].upper()
            t = "user"
            if s == "VALUE":
                t = "value"
                l = [S('fp_text'), S(t), 'VAL**']
            elif s == "NAME":
                t = "reference"
                l = [S('fp_text'), S(t), 'REF**']
            else:
                l = [S('fp_text'), S(t), shape['value']]
            if (('rot' in shape) and (fget(shape, 'rot') != 0.0)):
                l.append([
                    S('at'),
                    fget(shape, 'x'),
                    fc(-fget(shape, 'y')),
                    fget(shape, 'rot')
                ])
            else:
                l.append([S('at'), fget(shape, 'x'), fc(-fget(shape, 'y'))])
            l.append([S('layer'), S(layer)])
            if s == 'VALUE':
                l.append(S('hide'))
            dy = fget(shape, 'dy', 1 / 1.6)
            th = fget(shape, 'w', 0.1)
            l.append([
                S('effects'),
                [S('font'), [S('size'), dy, dy], [S('thickness'), th]]
            ])
            return [l]

        def silk(shape):
            if not 'shape' in shape: return None
            layer = type_to_layer_name(shape['type'])
            s = shape['shape']
            if s == 'line': return vertex(shape, layer)
            if s == 'vertex': return vertex(shape, layer)
            elif s == 'circle': return circle(shape, layer)
            elif s == 'disc': return disc(shape, layer)
            elif s == 'label': return label(shape, layer)
            elif s == 'rect': return rect(shape, layer)
            elif s == 'polygon': return polygon(shape, layer)

        def unknown(shape):
            return None

        for shape in interim:
            if 'type' in shape:
                l2 = {
                    'pad': pad,
                    'cu': silk,
                    'silk': silk,
                    'bsilk': silk,
                    'docu': silk,
                    'keepout': silk,
                    'bkeepout': silk,
                    'stop': silk,
                    'bstop': silk,
                    'glue': silk,
                    'paste': silk,
                    'bpaste': silk,
                    'restrict': unknown,
                    'vrestrict': unknown,
                    'comments': silk,
                    'user1': silk,
                    'user2': silk,
                    'margin': silk,
                    'assembly': silk,
                    'bassembly': silk,
                    'smd': lambda s: pad(s, smd=True),
                    'hole': hole,
                    'edge': silk,
                }.get(shape['type'], unknown)(shape)
                if l2 != None:
                    l.extend(l2)
        self.data = l
        self.name = name
        return name
Example #3
0
  def export_footprint(self, interim):
    meta = inter.get_meta(interim)
    name = eget(meta, 'name', 'Name not found')
    idx = eget(meta, 'id', 'Id not found')
    descr = oget(meta, 'desc', '')
    parent_idx = oget(meta, 'parent', None)
    l = [
      S('module'),
      name,
      [S('layer'), S('F.Cu')],
      [S('descr'), descr],
    ]
    
    def pad(shape, smd=False):
      l = [S('pad'), S(shape['name'])]
      if smd:
        l.append(S('smd'))
      else:
        l.append(S('thru_hole'))
      shape2 = 'disc' # disc is the default
      if 'shape' in shape:
        shape2 = shape['shape']
      r = fget(shape, 'r')
      if shape2 == 'disc':
        l.append(S('circle'))
        l.append([S('size'), r*2, r*2])
      elif shape2 == 'rect':
        ro = iget(shape, 'ro')
        if ro == 0:
          l.append(S('rect'))
        else:
          l.append(S('oval'))
        l.append([S('size'), fget(shape, 'dx'), fget(shape, 'dy')])
      else:
        raise Exception("%s shaped pad not supported in kicad" % (shape2))
      l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y'), iget(shape, 'rot')])
      if smd:
        l.append([S('layers'), S('F.Cu'), S('F.Paste'), S('F.Mask')])
      else:
        l.append([S('layers'), S('*.Cu'), S('*.Mask')])
      if not smd:
        l2 = [S('drill'), fget(shape, 'drill')]
        if 'drill_dx' in shape or 'drill_dy' in shape:
          l2.append([S('offset'), fget(shape, 'drill_dx'), fget(shape, 'drill_dy')])
        l.append(l2)
      return l
    
    #(fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.381))
    # (fp_arc (start 7.62 0) (end 7.62 -2.54) (angle 90) (layer F.SilkS) (width 0.15))
    def vertex(shape, layer):
      if not 'curve' in shape or shape['curve'] == 0.0:
        l = [S('fp_line')] 
        l.append([S('start'), fget(shape, 'x1'), -fget(shape, 'y1')])
        l.append([S('end'), fget(shape, 'x2'), -fget(shape, 'y2')])
        l.append([S('layer'), S(layer)])
        l.append([S('width'), fget(shape, 'w')])
      else:
        l = [S('fp_arc')] 
        # start == center point
        # end == start point of arc
        # angle == angled part in that direction
        x1 = fget(shape, 'x1')
        y1 = fget(shape, 'y1')
        x2 = fget(shape, 'x2')
        y2 = fget(shape, 'y2')
        curve =  fget(shape, 'curve')
        angle = curve*math.pi/180.0
        ((x0, y0), r, a1, a2) = calc_center_r_a1_a2((x1,y1),(x2,y2),angle)
        l.append([S('start'), fc(x0), fc(-y0)])
        l.append([S('end'), fc(x1), fc(-y1)])
        # also invert angle because of y inversion
        l.append([S('angle'), -(a2-a1)])
        l.append([S('layer'), S(layer)])
        l.append([S('width'), fget(shape, 'w')])
      return l

    # (fp_circle (center 5.08 0) (end 6.35 -1.27) (layer F.SilkS) (width 0.15))
    def circle(shape, layer):
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      r = fget(shape, 'r')
      if not 'a1' in shape and not 'a2' in shape:
        l = [S('fp_circle')] 
        l.append([S('center'),fc(x),fc(y)])
        l.append([S('end'), fc(x+(r/math.sqrt(2))), fc(y+(r/math.sqrt(2)))])
        l.append([S('layer'), S(layer)])
        l.append([S('width'), fget(shape, 'w')])
      else:
        l = [S('fp_arc')] 
        l.append([S('start'),fc(x),fc(y)])
        # start == center point
        # end == start point of arc
        # angle == angled part in that direction
        a1 = fget(shape, 'a1')
        a2 = fget(shape, 'a2')
        a1rad = a1 * math.pi/180.0
        ex = x + r*math.cos(a1rad)
        ey = y + r*math.sin(a1rad)
        l.append([S('end'), fc(ex), fc(-ey)])
        l.append([S('angle'), -(a2-a1)])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), fget(shape, 'w')])
      return l

    # a disc is just a circle with a clever radius and width
    def disc(shape, layer):
      l = [S('fp_circle')] 
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      l.append([S('center'), fc(x), fc(y)])
      r = fget(shape, 'r')
      rad = r/2
      l.append([S('end'), x+(rad/math.sqrt(2)), y+(rad/math.sqrt(2))])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), rad])
      return l

    def hole(shape):
      layer = type_to_layer_name(shape['type']) # aka 'hole'
      shape['r'] = shape['drill'] / 2
      return circle(shape, layer)

    # (fp_poly (pts (xy 6.7818 1.6002) (xy 6.6294 1.6002) (xy 6.6294 1.4478) (xy 6.7818 1.4478) (xy 6.7818 1.6002)) (layer F.Cu) (width 0.00254))
    # kicad doesn't do arced vertex in polygon :(
    def polygon(shape, layer):
      l = [S('fp_poly')]
      lxy = [S('pts')]
      for v in shape['v']:
        xy = [S('xy'), fc(v['x1']), fc(-v['y1'])]
        lxy.append(xy)
      xy = [S('xy'), fc(shape['v'][0]['x1']), fc(-shape['v'][0]['y1'])]
      lxy.append(xy)
      l.append(lxy)
      l.append([S('layer'), S(layer)])
      l.append([S('width'), shape['w']])
      return l

    def rect(shape, layer):
      l = [S('fp_poly')]
      x = fget(shape, 'x')
      y = - fget(shape, 'y')
      dx = fget(shape, 'dx')
      dy = fget(shape, 'dy')
      lxy = [S('pts')]
      def add(x1, y1):
        lxy.append([S('xy'), fc(x1), fc(y1)])
      add(x - dx/2, y - dy/2)
      add(x - dx/2, y + dy/2)
      add(x + dx/2, y + dy/2)
      add(x + dx/2, y - dy/2)
      add(x - dx/2, y - dy/2)
      l.append(lxy)
      l.append([S('layer'), S(layer)])
      l.append([S('width'), 0])
      return l

    # (fp_text reference MYCONN3 (at 0 -2.54) (layer F.SilkS)
    #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
    # )
    # (fp_text value SMD (at 0 2.54) (layer F.SilkS) hide
    #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
    # )
    def label(shape, layer):
      s = shape['value'].upper()
      t = 'user'
      if s == 'VALUE': t = 'value'
      if s == 'NAME': t = 'reference'
      l = [S('fp_text'), S(t), S(shape['value'])]
      if (('rot' in shape) and (fget(shape, 'rot') != 0.0)):
        l.append([S('at'), fget(shape, 'x'), fc(-fget(shape, 'y')), fget(shape, 'rot')])
      else:
        l.append([S('at'), fget(shape, 'x'), fc(-fget(shape, 'y'))])
      l.append([S('layer'), S(layer)])
      if s == 'VALUE':
        l.append(S('hide'))
      dy = fget(shape, 'dy', 1/1.6)
      th = fget(shape, 'w', 0.1)
      l.append([S('effects'), 
                [S('font'), [S('size'), dy, dy], [S('thickness'), th]]])
      return l

    def silk(shape):
      if not 'shape' in shape: return None
      layer = type_to_layer_name(shape['type'])
      s = shape['shape']
      if s == 'line': return vertex(shape, layer)
      if s == 'vertex': return vertex(shape, layer)
      elif s == 'circle': return circle(shape, layer)
      elif s == 'disc': return disc(shape, layer)
      elif s == 'label': return label(shape, layer)
      elif s == 'rect': return rect(shape, layer)
      elif s == 'polygon': return polygon(shape, layer)

    def unknown(shape):
      return None

    for shape in interim:
      if 'type' in shape:
        l2 = {
          'pad': pad,
          'cu': silk,
          'silk': silk,
          'docu': silk,
          'keepout': unknown,
          'stop': silk,
          'glue': silk,
          'restrict': unknown,
          'vrestrict': unknown,
          'smd': lambda s: pad(s, smd=True),
          'hole': hole,
          }.get(shape['type'], unknown)(shape)
        if l2 != None:
         l.append(l2)
    self.data = l
    self.name = name
    return name
Example #4
0
  def export_footprint(self, interim):
    # make a deep copy so we can make mods without harm
    interim = copy.deepcopy(interim)
    interim = self.add_ats_to_names(interim)
    meta = inter.get_meta(interim)
    name = eget(meta, 'name', 'Name not found')
    # make name eagle compatible
    name = re.sub(' ','_',name)
    # check if there is an existing package
    # and if so, replace it
    packages = self.soup.eagle.drawing.packages('package')
    package = None
    for some_package in packages:
      if some_package['name'].lower() == name.lower():
        package = some_package
        package.clear()
        break
    if package == None:
      package = self.soup.new_tag('package')
      self.soup.eagle.drawing.packages.append(package)
      package['name'] = name

    def pad(shape):
      pad = self.soup.new_tag('pad')
      pad['name'] = shape['name']
      # don't set layer in a pad, it is implicit
      pad['x'] = fget(shape, 'x')
      pad['y'] = fget(shape, 'y')
      drill = fget(shape, 'drill')
      pad['drill'] = drill
      pad['rot'] = "R%d" % (fget(shape, 'rot'))
      r = fget(shape, 'r')
      shape2 = 'disc' # disc is the default
      if 'shape' in shape:
        shape2 = shape['shape']
      if shape2 == 'disc':
        pad['shape'] = 'round'
        if f_neq(r, drill*1.5):
          pad['diameter'] = r*2
      elif shape2 == 'octagon':
        pad['shape'] = 'octagon'
        if f_neq(r, drill*1.5):
          pad['diameter'] = r*2
      elif shape2 == 'rect':
        ro = iget(shape, 'ro')
        if ro == 0: 
          pad['shape'] = 'square'
          if f_neq(shape['dx'], drill*1.5):
            pad['diameter'] = float(shape['dx'])
        elif 'drill_dx' in shape:
          pad['shape'] = 'offset'
          if f_neq(shape['dy'], drill*1.5):
            pad['diameter'] = float(shape['dy'])
        else:
          pad['shape'] = 'long'
          if f_neq(shape['dy'], drill*1.5):
            pad['diameter'] = float(shape['dy'])
      package.append(pad)

    def smd(shape):
      smd = self.soup.new_tag('smd')
      smd['name'] = shape['name']
      smd['x'] = fget(shape, 'x')
      smd['y'] = fget(shape, 'y')
      smd['dx'] = fget(shape, 'dx')
      smd['dy'] = fget(shape, 'dy')
      smd['roundness'] = iget(shape, 'ro')
      smd['rot'] = "R%d" % (fget(shape, 'rot'))
      smd['layer'] = type_to_layer_number('smd')
      package.append(smd)

    def rect(shape, layer):
      rect = self.soup.new_tag('rectangle')
      x = fget(shape, 'x')
      y = fget(shape, 'y')
      dx = fget(shape, 'dx')
      dy = fget(shape, 'dy')
      rect['x1'] = x - dx/2
      rect['x2'] = x + dx/2
      rect['y1'] = y - dy/2
      rect['y2'] = y + dy/2
      rect['rot'] = "R%d" % (fget(shape, 'rot'))
      rect['layer'] = layer
      package.append(rect)

    def label(shape, layer):
      label = self.soup.new_tag('text')
      x = fget(shape,'x')
      y = fget(shape,'y')
      dy = fget(shape,'dy', 1)
      s = shape['value']
      if s.upper() == "NAME": 
        s = ">NAME"
        layer = type_to_layer_number('name')
      if s.upper() == "VALUE": 
        s = ">VALUE"
        layer = type_to_layer_number('value')
      label['x'] = x
      label['y'] = y
      label['size'] = dy
      label['layer'] = layer
      label['align'] = 'center'
      label.string = s
      package.append(label)
    
    def disc(shape, layer):
      r = fget(shape, 'r')
      rx = fget(shape, 'rx', r)
      ry = fget(shape, 'ry', r)
      x = fget(shape,'x')
      y = fget(shape,'y')
      # a disc is just a circle with a
      # clever radius and width
      disc = self.soup.new_tag('circle')
      disc['x'] = x
      disc['y'] = y
      disc['radius'] = r/2
      disc['width'] = r/2
      disc['layer'] = layer
      package.append(disc)
  
    def circle(shape, layer):
      r = fget(shape, 'r')
      rx = fget(shape, 'rx', r)
      ry = fget(shape, 'ry', r)
      x = fget(shape,'x')
      y = fget(shape,'y')
      w = fget(shape,'w')
      circle = self.soup.new_tag('circle')
      circle['x'] = x
      circle['y'] = y
      circle['radius'] = r
      circle['width'] = w
      circle['layer'] = layer
      package.append(circle)

    def line(shape, layer):
      x1 = fget(shape, 'x1')
      y1 = fget(shape, 'y1')
      x2 = fget(shape, 'x2')
      y2 = fget(shape, 'y2')
      w = fget(shape, 'w')
      line = self.soup.new_tag('wire')
      line['x1'] = x1
      line['y1'] = y1
      line['x2'] = x2
      line['y2'] = y2
      line['width'] = w
      line['layer'] = layer
      package.append(line)
  
    def silk(shape):
      if not 'shape' in shape: return
      layer = type_to_layer_number(shape['type'])
      s = shape['shape']
      if s == 'line': line(shape, layer)
      elif s == 'circle': circle(shape, layer)
      elif s == 'disc': disc(shape, layer)
      elif s == 'label': label(shape, layer)
      elif s == 'rect': rect(shape, layer)

    def unknown(shape):
      pass

    idx = eget(meta, 'id', 'Id not found')
    desc = oget(meta, 'desc', '')
    parent_idx = oget(meta, 'parent', None)
    description = self.soup.new_tag('description')
    package.append(description)
    parent_str = ""
    if parent_idx != None:
      parent_str = " parent: %s" % parent_idx
    description.string = desc + "\n<br/><br/>\nGenerated by 'madparts'.<br/>\nId: " + idx   +"\n" + parent_str
    # TODO rework to be shape+type based ?
    for shape in interim:
      if 'type' in shape:
        {
          'pad': pad,
          'silk': silk,
          'docu': silk,
          'keepout': silk,
          'stop': silk,
          'restrict': silk,
          'vrestrict': silk,
          'smd': smd,
          }.get(shape['type'], unknown)(shape)
    return name
Example #5
0
    def export_footprint(self, interim, timestamp=None):
        if timestamp is None:
            timestamp = time.time()
        meta = inter.get_meta(interim)
        name = eget(meta, 'name', 'Name not found')
        # make name kicad compatible
        name = re.sub(' ', '_', name)
        self.name = name
        desc = oget(meta, 'desc', '')
        parent_idx = oget(meta, 'parent', None)
        d = []
        # generate kicad-old for individual footprint
        # use metric; convert to imperial in "save" if needed
        d.append("$MODULE %s" % (name))
        d.append("Po 0 0 0 15 %x 00000000 ~~" % timestamp)
        d.append("Li %s" % (name))
        d.append("Cd %s" % (desc.replace('\n', ' ')))  # ugly
        # assuming Kw is optional
        d.append("Sc 0")
        # d.append("AR ") assume AR is optional
        d.append("Op 0 0 0")

        # if no T0 or T1 are specified, kicad defaults to this:
        # right now I'm assuming this is optional
        # T0 0 0 1.524 1.524 0 0.15 N V 21 N ""
        # T1 0 0 1.524 1.524 0 0.15 N V 21 N ""

        def pad(shape, smd=False):
            l = ['$PAD']
            # Sh "<pad name>" shape Xsize Ysize Xdelta Ydelta Orientation
            # octagons are not supported by kicad
            if shape['shape'] == 'disc' or shape['shape'] == 'octagon':
                sh = 'C'
                dx = shape['r'] * 2
                dy = dx
            elif shape['shape'] == 'rect':
                dx = shape['dx']
                dy = shape['dy']
                sh = 'R'
                # any rect with roundness >= 50 is considered kicad 'oblong'
                if 'ro' in shape:
                    if shape['ro'] >= 50:
                        sh = 'O'
            rot = fget(shape, 'rot') * 10
            l.append("Sh \"%s\" %s %s %s %s %s %s" %
                     (shape['name'], sh, dx, dy, 0, 0, rot))
            # Dr <Pad drill> Xoffset Yoffset (round hole)
            if not smd:
                l.append("Dr %s %s %s" %
                         (fget(shape, 'drill'), fget(shape, 'drill_off_dx'),
                          fc(-fget(shape, 'drill_off_dy'))))
            # Po <x> <y>
            l.append("Po %s %s" % (fget(shape, 'x'), fc(-fget(shape, 'y'))))
            # At <Pad type> N <layer mask>
            t = 'STD'
            layer_mask = '00E0FFFF'
            if smd:
                t = 'SMD'
                layer_mask = '00888000'
            l.append("At %s N %s" % (t, layer_mask))
            l.append('Ne 0 ""')
            l.append("$ENDPAD")
            return l

        # DS Xstart Ystart Xend Yend Width Layer
        # DS 6000 1500 6000 -1500 120 21
        # DA Xcentre Ycentre Xstart_point Ystart_point angle width layer
        def vertex(shape, layer):
            l = []
            x1 = fget(shape, 'x1')
            y1 = fget(shape, 'y1')
            x2 = fget(shape, 'x2')
            y2 = fget(shape, 'y2')
            w = fget(shape, 'w')
            if not 'curve' in shape or shape['curve'] == 0.0:
                line = "DS %s %s %s %s %s %s" % (x1, fc(-y1), x2, fc(-y2), w,
                                                 layer)
                l.append(line)
            else:
                curve = fget(shape, 'curve')
                angle = curve * math.pi / 180.0
                ((x0, y0), r, a1, a2) = mutil.calc_center_r_a1_a2(
                    (x1, y1), (x2, y2), angle)
                arc = "DA %f %f %f %f %s %s %s" % (
                    x0, fc(-y0), x1, fc(-y1), int(round(
                        (-10.0) * (a2 - a1))), w, layer)
                l.append(arc)
            return l

        # DC Xcentre Ycentre Xpoint Ypoint Width Layer
        def circle(shape, layer):
            l = []
            x = fget(shape, 'x')
            y = fget(shape, 'y')
            r = fget(shape, 'r')
            w = fget(shape, 'w')
            if not 'a1' in shape and not 'a2' in shape:
                circle = "DC %s %s %s %s %s %s" % (
                    x, fc(-y), fc(x + (r / math.sqrt(2))),
                    fc(-y + (r / math.sqrt(2))), w, layer)
                l.append(circle)
            else:
                # start == center point
                # end == start point of arc
                # angle == angled part in that direction
                a1 = fget(shape, 'a1')
                a2 = fget(shape, 'a2')
                a1rad = a1 * math.pi / 180.0
                ex = x + r * math.cos(a1rad)
                ey = y + r * math.sin(a1rad)
                arc = "DA %f %f %f %f %s %s %s" % (x, fc(-y), ex, fc(-ey),
                                                   int(round(
                                                       (-10) *
                                                       (a2 - a1))), w, layer)
                l.append(arc)
            return l

        def disc(shape, layer):
            l = []
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            r = fget(shape, 'r')
            rad = r / 2
            ex = x + (rad / math.sqrt(2))
            ey = y + (rad / math.sqrt(2))
            circle = "DC %s %s %s %s %s %s" % (x, fc(y), fc(ex), fc(ey), rad,
                                               layer)
            l.append(circle)
            return l

        def hole(shape):
            layer = type_to_num(shape['type'])
            shape['r'] = shape['drill'] / 2
            return circle(shape, layer)

        # T0 -79 -3307 600 600 0 120 N V 21 N "XT"
        def label(shape, layer):
            s = shape['value'].upper()
            t = 'T2'
            visible = 'V'
            if s == 'VALUE':
                t = 'T1'
                visible = 'I'
            if s == 'NAME':
                t = 'T0'
            dy = fget(shape, 'dy', 1 / 1.6)
            w = fget(shape, 'w', 0.1)
            x = fget(shape, 'x')
            y = fc(-fget(shape, 'y'))
            # T0 -7 -3 60 60 0 10 N V 21 N "XT"
            line = "%s %s %s %s %s 0 %s N %s %s N \"%s\"" % (
                t, x, y, dy, dy, w, visible, layer, shape['value'])
            return [line]

        def rect(shape, layer):
            print "rect", shape, layer
            l = []
            w = fget(shape, 'w')
            rot = abs(fget(shape, 'rot'))
            l.append("DP 0 0 0 0 %s %s %s" % (5, w, layer))
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            dx = fget(shape, 'dx')
            dy = fget(shape, 'dy')
            if rot == 90 or rot == 270:
                (dx, dy) = (dy, dx)

            def add(x1, y1):
                l.append("Dl %f %f" % (fc(x1), fc(y1)))

            add(x - dx / 2, y - dy / 2)
            add(x - dx / 2, y + dy / 2)
            add(x + dx / 2, y + dy / 2)
            add(x + dx / 2, y - dy / 2)
            add(x - dx / 2, y - dy / 2)
            return l

        # DP 0 0 0 0 corners_count width layer
        # DP 0 0 0 0 5 0.1 24
        # Dl corner_posx corner_posy
        # Dl 0 -1
        def polygon(shape, layer):
            l = []
            n = len(shape['v'])
            w = shape['w']
            l.append("DP 0 0 0 0 %s %s %s" % (n + 1, w, layer))
            for v in shape['v']:
                l.append("Dl %g %g" % (fc(v['x1']), fc(-v['y1'])))
            l.append("Dl %g %g" %
                     (fc(shape['v'][0]['x1']), fc(-shape['v'][0]['y1'])))
            return l

        def silk(shape):
            if not 'shape' in shape: return None
            layer = type_to_num(shape['type'])
            s = shape['shape']
            if s == 'line': return vertex(shape, layer)
            if s == 'vertex': return vertex(shape, layer)
            elif s == 'circle': return circle(shape, layer)
            elif s == 'disc': return disc(shape, layer)
            elif s == 'label': return label(shape, layer)
            elif s == 'rect': return rect(shape, layer)
            elif s == 'polygon': return polygon(shape, layer)

        def unknown(shape):
            return None

        for shape in interim:
            if 'type' in shape:
                l = {
                    'pad': pad,
                    'cu': silk,
                    'silk': silk,
                    'docu': silk,
                    'keepout': unknown,
                    'stop': silk,
                    'glue': silk,
                    'restrict': unknown,
                    'vrestrict': unknown,
                    'smd': lambda s: pad(s, smd=True),
                    'hole': hole,
                }.get(shape['type'], unknown)(shape)
                if l != None:
                    d += l

        d.append("$EndMODULE %s" % (name))
        self.data = d
        return name
Example #6
0
  def export_footprint(self, interim):
    # make a deep copy so we can make mods without harm
    interim = copy.deepcopy(interim)
    interim = self.add_ats_to_names(interim)
    interim = clean_floats(interim)
    meta = inter.get_meta(interim)
    name = eget(meta, 'name', 'Name not found')
    # make name eagle compatible
    name = re.sub(' ','_',name)
    # check if there is an existing package
    # and if so, replace it
    packages = self.soup.eagle.drawing.packages('package')
    package = None
    for some_package in packages:
      if some_package['name'].lower() == name.lower():
        package = some_package
        package.clear()
        break
    if package == None:
      package = self.soup.new_tag('package')
      self.soup.eagle.drawing.packages.append(package)
      package['name'] = name

    def pad(shape):
      pad = self.soup.new_tag('pad')
      pad['name'] = shape['name']
      # don't set layer in a pad, it is implicit
      pad['x'] = fget(shape, 'x')
      pad['y'] = fget(shape, 'y')
      drill = fget(shape, 'drill')
      pad['drill'] = drill
      pad['rot'] = "R%d" % (fget(shape, 'rot'))
      r = fget(shape, 'r')
      shape2 = 'disc' # disc is the default
      if 'shape' in shape:
        shape2 = shape['shape']
      if shape2 == 'disc':
        pad['shape'] = 'round'
        if f_neq(r, drill*1.5):
          pad['diameter'] = r*2
      elif shape2 == 'octagon':
        pad['shape'] = 'octagon'
        if f_neq(r, drill*1.5):
          pad['diameter'] = r*2
      elif shape2 == 'rect':
        ro = iget(shape, 'ro')
        if ro == 0: 
          pad['shape'] = 'square'
          if f_neq(shape['dx'], drill*1.5):
            pad['diameter'] = float(shape['dx'])
        elif 'drill_off_dx' in shape:
          pad['shape'] = 'offset'
          if f_neq(shape['dy'], drill*1.5):
            pad['diameter'] = float(shape['dy'])
        else:
          pad['shape'] = 'long'
          if f_neq(shape['dy'], drill*1.5):
            pad['diameter'] = float(shape['dy'])
      package.append(pad)

    def smd(shape):
      smd = self.soup.new_tag('smd')
      smd['name'] = shape['name']
      smd['x'] = fget(shape, 'x')
      smd['y'] = fget(shape, 'y')
      smd['dx'] = fget(shape, 'dx')
      smd['dy'] = fget(shape, 'dy')
      smd['roundness'] = iget(shape, 'ro')
      smd['rot'] = "R%d" % (fget(shape, 'rot'))
      smd['layer'] = type_to_layer_number('smd')
      package.append(smd)

    def hole(shape):
      hole = self.soup.new_tag('hole')
      hole['drill'] = fget(shape, 'drill')
      hole['x'] = fget(shape, 'x')
      hole['y'] = fget(shape, 'y')
      package.append(hole)

    def rect(shape, layer):
      rect = self.soup.new_tag('rectangle')
      x = fget(shape, 'x')
      y = fget(shape, 'y')
      dx = fget(shape, 'dx')
      dy = fget(shape, 'dy')
      rect['x1'] = x - dx/2
      rect['x2'] = x + dx/2
      rect['y1'] = y - dy/2
      rect['y2'] = y + dy/2
      rect['rot'] = "R%d" % (fget(shape, 'rot'))
      rect['layer'] = layer
      package.append(rect)

    def label(shape, layer):
      label = self.soup.new_tag('text')
      x = fget(shape,'x')
      y = fget(shape,'y')
      dy = fget(shape,'dy', 1)
      s = shape['value'].upper()
      if s == "NAME": 
        s = ">NAME"
        layer = type_to_layer_number('name')
      if s == "VALUE": 
        s = ">VALUE"
        layer = type_to_layer_number('value')
      label['x'] = x
      label['y'] = y
      label['size'] = dy
      label['layer'] = layer
      label['align'] = 'center'
      label.string = s
      package.append(label)
    
    # a disc is just a circle with a clever radius and width
    def disc(shape, layer):
      r = fget(shape, 'r')
      rx = fget(shape, 'rx', r)
      ry = fget(shape, 'ry', r)
      x = fget(shape,'x')
      y = fget(shape,'y')
      disc = self.soup.new_tag('circle')
      disc['x'] = x
      disc['y'] = y
      disc['radius'] = r/2
      disc['width'] = r/2
      disc['layer'] = layer
      package.append(disc)
  
    def circle(shape, layer):
      r = fget(shape, 'r')
      rx = fget(shape, 'rx', r)
      ry = fget(shape, 'ry', r)
      x = fget(shape,'x')
      y = fget(shape,'y')
      w = fget(shape,'w')
      if 'a1' in shape or 'a2' in shape:
        wire = self.soup.new_tag('wire')
        a1 = fget(shape, 'a1')
        a2 = fget(shape, 'a2')
        wire['width'] = w
        wire['curve'] = a2-a1
        a1 = a1 * math.pi / 180
        a2 = a2 * math.pi / 180
        wire['x1'] = x + r * math.cos(a1)
        wire['y1'] = y + r * math.sin(a1)
        wire['x2'] = x + r * math.cos(a2)
        wire['y2'] = y + r * math.sin(a2)
        wire['layer'] = layer
        package.append(wire)
      else:
        circle = self.soup.new_tag('circle')
        circle['x'] = x
        circle['y'] = y
        circle['radius'] = r
        circle['width'] = w
        circle['layer'] = layer
        package.append(circle)

    def line(shape, layer):
      x1 = fget(shape, 'x1')
      y1 = fget(shape, 'y1')
      x2 = fget(shape, 'x2')
      y2 = fget(shape, 'y2')
      w = fget(shape, 'w')
      line = self.soup.new_tag('wire')
      line['x1'] = x1
      line['y1'] = y1
      line['x2'] = x2
      line['y2'] = y2
      line['width'] = w
      line['layer'] = layer
      if 'curve' in shape:
        if shape['curve'] != 0.0:
          line['curve'] = fget(shape, 'curve')
      package.append(line)
  
    # eagle polygon format is somewhat wierd
    # each vertex is actually a starting point towards the next
    # where the last one is a starting point around towards the first
    #  <polygon width="0.127" layer="21">
    #  <vertex x="-1" y="-1"/>
    #  <vertex x="-1" y="1"/>
    #  <vertex x="0" y="1" curve="-90"/>
    #  <vertex x="1" y="0" curve="-90"/>
    #  <vertex x="0" y="-1"/>
    #  </polygon>
    def polygon(shape, layer):
      p = self.soup.new_tag('polygon')
      p['width'] = fget(shape, 'w')
      p['layer'] = layer
      for v in shape['v']:
        vert = self.soup.new_tag('vertex')
        vert['x'] = fget(v, 'x1')
        vert['y'] = fget(v, 'y1')
        curve = fget(v, 'curve')
        if curve != 0.0:
          vert['curve'] = fget(v, 'curve')
        p.append(vert)
      package.append(p)

    def silk(shape):
      if not 'shape' in shape: return
      layer = type_to_layer_number(shape['type'])
      s = shape['shape']
      if s == 'line' or s == 'vertex': line(shape, layer)
      elif s == 'circle': circle(shape, layer)
      elif s == 'disc': disc(shape, layer)
      elif s == 'label': label(shape, layer)
      elif s == 'rect': rect(shape, layer)
      elif s == 'polygon': polygon(shape, layer)

    def unknown(shape):
      pass

    desc = oget(meta, 'desc', '')
    parent_idx = oget(meta, 'parent', None)
    description = self.soup.new_tag('description')
    package.append(description)
    description.string = desc + "\n<br/><br/>\nGenerated by 'madparts'.<br/>\n"

    # TODO rework to be shape+type based ?
    for shape in interim:
      if 'type' in shape:
        {
          'pad': pad,
          'silk': silk,
          'cu': silk,
          'docu': silk,
          'keepout': silk,
          'stop': silk,
          'restrict': silk,
          'vrestrict': silk,
          'smd': smd,
          'hole': hole,
          }.get(shape['type'], unknown)(shape)
    return name
Example #7
0
  def export_footprint(self, interim):
    meta = inter.get_meta(interim)
    name = eget(meta, 'name', 'Name not found')
    idx = eget(meta, 'id', 'Id not found')
    descr = oget(meta, 'desc', '')
    parent_idx = oget(meta, 'parent', None)
    l = [
      S('module'),
      S(name),
      [S('layer'), S('F.Cu')],
      [S('descr'), descr],
    ]
    
    def pad(shape, smd=False):
      l = [S('pad'), S(shape['name'])]
      if smd:
        l.append(S('smd'))
      else:
        l.append(S('thru_hole'))
      shape2 = 'disc' # disc is the default
      if 'shape' in shape:
        shape2 = shape['shape']
      r = fget(shape, 'r')
      if shape2 == 'disc':
        l.append(S('circle'))
        l.append([S('size'), r, r])
      elif shape2 == 'rect':
        ro = iget(shape, 'ro')
        if ro == 0:
          l.append(S('rect'))
        else:
          l.append(S('oval'))
        l.append([S('size'), fget(shape, 'dx'), fget(shape, 'dy')])
      else:
        raise Exception("%s shaped pad not supported in kicad" % (shape2))
      l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y'), iget(shape, 'rot')])
      if smd:
        l.append([S('layers'), S('F.Cu'), S('F.Paste'), S('F.Mask')])
      else:
        l.append([S('layers'), S('*.Cu'), S('*.Mask')])
      if not smd:
        l2 = [S('drill'), fget(shape, 'drill')]
        if 'drill_dx' in shape or 'drill_dy' in shape:
          l2.append([S('offset'), fget(shape, 'drill_dx'), fget(shape, 'drill_dy')])
        l.append(l2)
      return l
    
    #(fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.381))
    def line(shape, layer):
      l = [S('fp_line')] 
      l.append([S('start'), fget(shape, 'x1'), -fget(shape, 'y1')])
      l.append([S('end'), fget(shape, 'x2'), -fget(shape, 'y2')])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), fget(shape, 'w')])
      return l

    # (fp_circle (center 5.08 0) (end 6.35 -1.27) (layer F.SilkS) (width 0.15))
    def circle(shape, layer):
      l = [S('fp_circle')]  
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      l.append([S('center'), x, y])
      r = fget(shape, 'r')
      l.append([S('end'), x+(r/math.sqrt(2)), y+(r/math.sqrt(2))])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), fget(shape, 'w')])
      return l

    # a disc is just a circle with a clever radius and width
    def disc(shape, layer):
      l = [S('fp_circle')] 
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      l.append([S('center'), x, y])
      r = fget(shape, 'r')
      rad = r/2
      l.append([S('end'), x+(rad/math.sqrt(2)), y+(rad/math.sqrt(2))])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), rad])
      return l

    # (fp_arc (start 7.62 0) (end 7.62 -2.54) (angle 90) (layer F.SilkS) (width 0.15))
    def arc(shape, layer):
      l = [S('fp_arc')] 
      l.append([S('start'), fget(shape, 'x1'), -fget(shape, 'y1')])
      l.append([S('end'), fget(shape, 'x2'), -fget(shape, 'y2')])
      l.append([S('angle'), fget(shape, 'a')])
      l.append([S('layer'), S(layer)])
      l.append([S('w'), fget(shape, 'w')])
      return l


    # (pad "" smd rect (at 1.27 0) (size 0.39878 0.8001) (layers F.SilkS))
    def rect(shape, layer):
      # TODO: Don't do this with a pad. Use a polygon
      l = [S('pad'), "", S('smd'), S('rect')] 
      l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y'), iget(shape, 'rot')])
      l.append([S('size'), fget(shape, 'dx'), fget(shape, 'dy')])
      l.append([S('layers'), S(layer)])
      return l

    # (fp_text reference MYCONN3 (at 0 -2.54) (layer F.SilkS)
    #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
    # )
    # (fp_text value SMD (at 0 2.54) (layer F.SilkS) hide
    #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
    # )
    def label(shape, layer):
      s = shape['value'].upper()
      t = 'user'
      if s == 'VALUE': t = 'value'
      if s == 'NAME': t = 'reference'
      l = [S('fp_text'), S(t), S(shape['value'])]
      if (('rot' in shape) and (fget(shape, 'rot') != 0.0)):
        l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y'), fget(shape, 'rot')])
      else:
        l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y')])
      l.append([S('layer'), S(layer)])
      if s == 'VALUE':
        l.append(S('hide'))
      dy = fget(shape, 'dy', 1/1.6)
      th = fget(shape, 'w', 0.1)
      l.append([S('effects'), 
                [S('font'), [S('size'), dy, dy], [S('thickness'), th]]])
      return l

    def silk(shape):
      if not 'shape' in shape: return None
      layer = type_to_layer_name(shape['type'])
      s = shape['shape']
      if s == 'line': return line(shape, layer)
      elif s == 'arc': return arc(shape, layer)
      elif s == 'circle': return circle(shape, layer)
      elif s == 'disc': return disc(shape, layer)
      elif s == 'label': return label(shape, layer)
      elif s == 'rect': return rect(shape, layer)

    def unknown(shape):
      return None

    for shape in interim:
      if 'type' in shape:
        l2 = {
          'pad': pad,
          'silk': silk,
          'docu': silk,
          'keepout': unknown,
          'stop': silk,
          'glue': silk,
          'restrict': unknown,
          'vrestrict': unknown,
          'smd': lambda s: pad(s, smd=True),
          }.get(shape['type'], unknown)(shape)
        if l2 != None:
         l.append(l2)
    self.data = l
    self.name = name
    return name
Example #8
0
  def export_footprint(self, interim):
    meta = inter.get_meta(interim)
    name = eget(meta, 'name', 'Name not found')
    descr = oget(meta, 'desc', '')
    parent_idx = oget(meta, 'parent', None)
    l = [
      S('module'),
      name,
      [S('layer'), S('F.Cu')],
      [S('descr'), descr],
    ]


    def pad_line(x1,y1,x2,y2,width,layer):
      l = [S('fp_line')] 
      l.append([S('start'), x1,y1])
      l.append([S('end'), x2,y2])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), width])
      return l

    def pad_lines(s,x1,y1,x2,y2,width):
      s.append(pad_line(x1,y1,x2,y2,width,'F.Cu'))
      s.append(pad_line(x1,y1,x2,y2,width,'F.Paste'))
      s.append(pad_line(x1,y1,x2,y2,width,'F.Mask'))

    def gen_lines(l,x,y,rot,radius,dx,dy):
      # 4 corners
      xo = dx/2 - radius
      yo = dy/2 - radius

      rot = math.radians(rot)

      xp = math.cos(rot)*xo - math.sin(rot)*yo
      yp = math.cos(rot)*yo +  math.sin(rot)*xo
            
      x1 = x - xp
      x2 = x + xp
      y1 = y - yp
      y2 = y + yp

      pad_lines(l,x1,y1,x2,y1,radius*2)
      pad_lines(l,x2,y1,x2,y2,radius*2)
      pad_lines(l,x2,y2,x1,y2,radius*2)
      pad_lines(l,x1,y2,x1,y1,radius*2)


    def pad(shape, smd=False):
      want_paste = True
      if 'paste' in shape:
        want_paste = shape['paste']
      if 'name' in shape:
        name = shape['name']
        if name is None or name == "":
          name = ""
        else:
          name = S(name)
      else:
        name = ""
      l = [S('pad'), name]
      shapes = [l]
      if smd:
        l.append(S('smd'))
      else:
        l.append(S('thru_hole'))
      shape2 = 'disc' # disc is the default
      if 'shape' in shape:
        shape2 = shape['shape']
      r = fget(shape, 'r')
      if shape2 == 'disc':
        l.append(S('circle'))
        l.append([S('size'), r*2, r*2])
      elif shape2 == 'rect':
        ro = iget(shape, 'ro')
        dx = fget(shape, 'dx')
        dy = fget(shape, 'dy')
        if ro == 100:
          l.append(S('oval'))
          l.append([S('size'), dx, dy])
        else:
          l.append(S('rect'))
          if ro == 0:    
            l.append([S('size'), dx, dy])
	  else:
	    #find the smallest dimension and create a rectangular pad squished by that amount
	    #TODO: the rectangular pad is simple with 4 lines, 1 rect and guaranteed no holes		
	    #however it can create arbitrarily small pad which will make text in kicad hard to 
	    #read. may be better to use a oval pad, which can be not shrunk and is still guaranteed 
	    #to not overrun the pad, however it is tricky to make sure the 4 lines don't create any holes. 
	    small = dx
	    if dy < dx :
               small = dy
            radius = small/2 * ro / 100.0;
            l.append([S('size'), dx-radius*2, dy-radius*2])
            gen_lines(shapes, fget(shape, 'x'), -fget(shape, 'y'), iget(shape, 'rot'), radius, dx, dy)
      else:
        raise Exception("%s shaped pad not supported in kicad" % (shape2))
      l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y'), iget(shape, 'rot')])
      if smd:
        if shape['type'] != 'smd':
          l.append([S('layers'), S('F.Paste')])
        else:
          if want_paste:
            l.append([S('layers'), S('F.Cu'), S('F.Paste'), S('F.Mask')])
          else:
            l.append([S('layers'), S('F.Cu'), S('F.Mask')])
      else:
        l.append([S('layers'), S('*.Cu'), S('*.Mask')])
      if not smd:
        if 'drill_dx' in shape or 'drill_dy' in shape:
          drill_dx = fget(shape, 'drill_dx')
          drill_dy = fget(shape, 'drill_dy')
          l2 = [S('drill'), S('oval'), drill_dx, drill_dy]
        else:
          l2 = [S('drill'), fget(shape, 'drill')]
        if 'drill_off_dx' in shape or 'drill_off_dy' in shape:
          l2.append([S('offset'), fget(shape, 'drill_off_dx'), fget(shape, 'drill_off_dy')])
        l.append(l2)
      l.append([S('solder_mask_margin'), fget(shape, 'mask_swell')])
      l.append([S('solder_paste_margin_ratio'), fget(shape, 'paste_ratio')])
      return shapes
    
    #(fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.381))
    # (fp_arc (start 7.62 0) (end 7.62 -2.54) (angle 90) (layer F.SilkS) (width 0.15))
    def vertex(shape, layer):
      if not 'curve' in shape or shape['curve'] == 0.0:
        l = [S('fp_line')] 
        l.append([S('start'), fget(shape, 'x1'), -fget(shape, 'y1')])
        l.append([S('end'), fget(shape, 'x2'), -fget(shape, 'y2')])
        l.append([S('layer'), S(layer)])
        l.append([S('width'), fget(shape, 'w')])
      else:
        l = [S('fp_arc')] 
        # start == center point
        # end == start point of arc
        # angle == angled part in that direction
        x1 = fget(shape, 'x1')
        y1 = fget(shape, 'y1')
        x2 = fget(shape, 'x2')
        y2 = fget(shape, 'y2')
        curve =  fget(shape, 'curve')
        angle = curve*math.pi/180.0
        ((x0, y0), r, a1, a2) = calc_center_r_a1_a2((x1,y1),(x2,y2),angle)
        l.append([S('start'), fc(x0), fc(-y0)])
        l.append([S('end'), fc(x1), fc(-y1)])
        # also invert angle because of y inversion
        l.append([S('angle'), -(a2-a1)])
        l.append([S('layer'), S(layer)])
        l.append([S('width'), fget(shape, 'w')])
      return [l]

    # (fp_circle (center 5.08 0) (end 6.35 -1.27) (layer F.SilkS) (width 0.15))
    def circle(shape, layer):
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      r = fget(shape, 'r')
      if not 'a1' in shape and not 'a2' in shape:
        l = [S('fp_circle')] 
        l.append([S('center'),fc(x),fc(y)])
        l.append([S('end'), fc(x+(r/math.sqrt(2))), fc(y+(r/math.sqrt(2)))])
        l.append([S('layer'), S(layer)])
        l.append([S('width'), fget(shape, 'w')])
      else:
        l = [S('fp_arc')] 
        l.append([S('start'),fc(x),fc(y)])
        # start == center point
        # end == start point of arc
        # angle == angled part in that direction
        a1 = fget(shape, 'a1')
        a2 = fget(shape, 'a2')
        a1rad = a1 * math.pi/180.0
        ex = x + r*math.cos(a1rad)
        ey = y + r*math.sin(a1rad)
        l.append([S('end'), fc(ex), fc(-ey)])
        l.append([S('angle'), -(a2-a1)])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), fget(shape, 'w')])
      return [l]

    # a disc is just a circle with a clever radius and width
    def disc(shape, layer):
      l = [S('fp_circle')] 
      x = fget(shape, 'x')
      y = -fget(shape, 'y')
      l.append([S('center'), fc(x), fc(y)])
      r = fget(shape, 'r')
      rad = r/2
      l.append([S('end'), x+(rad/math.sqrt(2)), y+(rad/math.sqrt(2))])
      l.append([S('layer'), S(layer)])
      l.append([S('width'), rad])
      return [l]

    def hole(shape):
      l = [S('pad'), ""]
      l.append(S('np_thru_hole'))
      l.append(S('circle'))
      l.append([S('at'), fget(shape, 'x'), -fget(shape, 'y')])
      drill = fget(shape, 'drill')
      l.append([S('size'), drill, drill])
      l.append([S('drill'), drill])
      l.append([S('layers'), S('*.Cu'), S('*.Mask'), S('F.SilkS')])
      return [l]

    # (fp_poly (pts (xy 6.7818 1.6002) (xy 6.6294 1.6002) (xy 6.6294 1.4478) (xy 6.7818 1.4478) (xy 6.7818 1.6002)) (layer F.Cu) (width 0.00254))
    # kicad doesn't do arced vertex in polygon :(
    def polygon(shape, layer):
      l = [S('fp_poly')]
      lxy = [S('pts')]
      for v in shape['v']:
        xy = [S('xy'), fc(v['x1']), fc(-v['y1'])]
        lxy.append(xy)
      xy = [S('xy'), fc(shape['v'][0]['x1']), fc(-shape['v'][0]['y1'])]
      lxy.append(xy)
      l.append(lxy)
      l.append([S('layer'), S(layer)])
      l.append([S('width'), shape['w']])
      return [l]

    def rect(shape, layer):
      l = [S('fp_poly')]
      x = fget(shape, 'x')
      y = - fget(shape, 'y')
      dx = fget(shape, 'dx')
      dy = fget(shape, 'dy')
      rot = fget(shape, 'rot')
      if rot == 90 or rot == 270:
        (dx, dy) = (dy, dx)
      lxy = [S('pts')]
      def add(x1, y1):
        lxy.append([S('xy'), fc(x1), fc(y1)])
      add(x - dx/2, y - dy/2)
      add(x - dx/2, y + dy/2)
      add(x + dx/2, y + dy/2)
      add(x + dx/2, y - dy/2)
      add(x - dx/2, y - dy/2)
      l.append(lxy)
      l.append([S('layer'), S(layer)])
      l.append([S('width'), 0])
      return [l]

    # (fp_text reference MYCONN3 (at 0 -2.54) (layer F.SilkS)
    #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
    # )
    # (fp_text value SMD (at 0 2.54) (layer F.SilkS) hide
    #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
    # )
    def label(shape, layer):
      s = shape['value'].upper()
      t = "user"
      if s == "VALUE":
        t = "value"
        l = [S('fp_text'), S(t), 'VAL**']
      elif s == "NAME":
        t = "reference"
        l = [S('fp_text'), S(t), 'REF**']
      else:
        l = [S('fp_text'), S(t), shape['value']]
      if (('rot' in shape) and (fget(shape, 'rot') != 0.0)):
        l.append([S('at'), fget(shape, 'x'), fc(-fget(shape, 'y')), fget(shape, 'rot')])
      else:
        l.append([S('at'), fget(shape, 'x'), fc(-fget(shape, 'y'))])
      l.append([S('layer'), S(layer)])
      if s == 'VALUE':
        l.append(S('hide'))
      dy = fget(shape, 'dy', 1/1.6)
      th = fget(shape, 'w', 0.1)
      l.append([S('effects'), 
                [S('font'), [S('size'), dy, dy], [S('thickness'), th]]])
      return [l]

    def silk(shape):
      if not 'shape' in shape: return None
      layer = type_to_layer_name(shape['type'])
      s = shape['shape']
      if s == 'line': return vertex(shape, layer)
      if s == 'vertex': return vertex(shape, layer)
      elif s == 'circle': return circle(shape, layer)
      elif s == 'disc': return disc(shape, layer)
      elif s == 'label': return label(shape, layer)
      elif s == 'rect': return rect(shape, layer)
      elif s == 'polygon': return polygon(shape, layer)

    def unknown(shape):
      return None

    for shape in interim:
      if 'type' in shape:
        l2 = {
          'pad': pad,
          'cu': silk,
          'silk': silk,
          'bsilk': silk,
          'docu': silk,
          'keepout': silk,
          'bkeepout': silk,
          'stop': silk,
          'bstop': silk,
          'glue': silk,
          'paste': silk,
          'bpaste': silk,
          'restrict': unknown,
          'vrestrict': unknown,
          'comments': silk,
          'user1': silk,
          'user2': silk,
          'margin': silk,
          'assembly': silk,
          'bassembly': silk,
          'smd': lambda s: pad(s, smd=True),
          'hole': hole,
          'edge': silk,
          }.get(shape['type'], unknown)(shape)
        if l2 != None:
         l.extend(l2)
    self.data = l
    self.name = name
    return name
Example #9
0
    def export_footprint(self, interim):
        meta = inter.get_meta(interim)
        name = eget(meta, 'name', 'Name not found')
        idx = eget(meta, 'id', 'Id not found')
        descr = oget(meta, 'desc', '')
        parent_idx = oget(meta, 'parent', None)
        l = [
            S('module'),
            name,
            [S('layer'), S('F.Cu')],
            [S('descr'), descr],
        ]

        def pad(shape, smd=False):
            l = [S('pad'), S(shape['name'])]
            if smd:
                l.append(S('smd'))
            else:
                l.append(S('thru_hole'))
            shape2 = 'disc'  # disc is the default
            if 'shape' in shape:
                shape2 = shape['shape']
            r = fget(shape, 'r')
            if shape2 == 'disc':
                l.append(S('circle'))
                l.append([S('size'), r * 2, r * 2])
            elif shape2 == 'rect':
                ro = iget(shape, 'ro')
                if ro == 0:
                    l.append(S('rect'))
                else:
                    l.append(S('oval'))
                l.append([S('size'), fget(shape, 'dx'), fget(shape, 'dy')])
            else:
                raise Exception("%s shaped pad not supported in kicad" %
                                (shape2))
            l.append([
                S('at'),
                fget(shape, 'x'), -fget(shape, 'y'),
                iget(shape, 'rot')
            ])
            if smd:
                l.append([S('layers'), S('F.Cu'), S('F.Paste'), S('F.Mask')])
            else:
                l.append([S('layers'), S('*.Cu'), S('*.Mask')])
            if not smd:
                l2 = [S('drill'), fget(shape, 'drill')]
                if 'drill_dx' in shape or 'drill_dy' in shape:
                    l2.append([
                        S('offset'),
                        fget(shape, 'drill_dx'),
                        fget(shape, 'drill_dy')
                    ])
                l.append(l2)
            return l

        #(fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.381))
        # (fp_arc (start 7.62 0) (end 7.62 -2.54) (angle 90) (layer F.SilkS) (width 0.15))
        def vertex(shape, layer):
            if not 'curve' in shape or shape['curve'] == 0.0:
                l = [S('fp_line')]
                l.append([S('start'), fget(shape, 'x1'), -fget(shape, 'y1')])
                l.append([S('end'), fget(shape, 'x2'), -fget(shape, 'y2')])
                l.append([S('layer'), S(layer)])
                l.append([S('width'), fget(shape, 'w')])
            else:
                l = [S('fp_arc')]
                # start == center point
                # end == start point of arc
                # angle == angled part in that direction
                x1 = fget(shape, 'x1')
                y1 = fget(shape, 'y1')
                x2 = fget(shape, 'x2')
                y2 = fget(shape, 'y2')
                curve = fget(shape, 'curve')
                angle = curve * math.pi / 180.0
                ((x0, y0), r, a1, a2) = calc_center_r_a1_a2((x1, y1), (x2, y2),
                                                            angle)
                l.append([S('start'), fc(x0), fc(-y0)])
                l.append([S('end'), fc(x1), fc(-y1)])
                # also invert angle because of y inversion
                l.append([S('angle'), -(a2 - a1)])
                l.append([S('layer'), S(layer)])
                l.append([S('width'), fget(shape, 'w')])
            return l

        # (fp_circle (center 5.08 0) (end 6.35 -1.27) (layer F.SilkS) (width 0.15))
        def circle(shape, layer):
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            r = fget(shape, 'r')
            if not 'a1' in shape and not 'a2' in shape:
                l = [S('fp_circle')]
                l.append([S('center'), fc(x), fc(y)])
                l.append([
                    S('end'),
                    fc(x + (r / math.sqrt(2))),
                    fc(y + (r / math.sqrt(2)))
                ])
                l.append([S('layer'), S(layer)])
                l.append([S('width'), fget(shape, 'w')])
            else:
                l = [S('fp_arc')]
                l.append([S('start'), fc(x), fc(y)])
                # start == center point
                # end == start point of arc
                # angle == angled part in that direction
                a1 = fget(shape, 'a1')
                a2 = fget(shape, 'a2')
                a1rad = a1 * math.pi / 180.0
                ex = x + r * math.cos(a1rad)
                ey = y + r * math.sin(a1rad)
                l.append([S('end'), fc(ex), fc(-ey)])
                l.append([S('angle'), -(a2 - a1)])
            l.append([S('layer'), S(layer)])
            l.append([S('width'), fget(shape, 'w')])
            return l

        # a disc is just a circle with a clever radius and width
        def disc(shape, layer):
            l = [S('fp_circle')]
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            l.append([S('center'), fc(x), fc(y)])
            r = fget(shape, 'r')
            rad = r / 2
            l.append(
                [S('end'), x + (rad / math.sqrt(2)), y + (rad / math.sqrt(2))])
            l.append([S('layer'), S(layer)])
            l.append([S('width'), rad])
            return l

        def hole(shape):
            layer = type_to_layer_name(shape['type'])  # aka 'hole'
            shape['r'] = shape['drill'] / 2
            return circle(shape, layer)

        # (fp_poly (pts (xy 6.7818 1.6002) (xy 6.6294 1.6002) (xy 6.6294 1.4478) (xy 6.7818 1.4478) (xy 6.7818 1.6002)) (layer F.Cu) (width 0.00254))
        # kicad doesn't do arced vertex in polygon :(
        def polygon(shape, layer):
            l = [S('fp_poly')]
            lxy = [S('pts')]
            for v in shape['v']:
                xy = [S('xy'), fc(v['x1']), fc(-v['y1'])]
                lxy.append(xy)
            xy = [S('xy'), fc(shape['v'][0]['x1']), fc(-shape['v'][0]['y1'])]
            lxy.append(xy)
            l.append(lxy)
            l.append([S('layer'), S(layer)])
            l.append([S('width'), shape['w']])
            return l

        def rect(shape, layer):
            l = [S('fp_poly')]
            x = fget(shape, 'x')
            y = -fget(shape, 'y')
            dx = fget(shape, 'dx')
            dy = fget(shape, 'dy')
            lxy = [S('pts')]

            def add(x1, y1):
                lxy.append([S('xy'), fc(x1), fc(y1)])

            add(x - dx / 2, y - dy / 2)
            add(x - dx / 2, y + dy / 2)
            add(x + dx / 2, y + dy / 2)
            add(x + dx / 2, y - dy / 2)
            add(x - dx / 2, y - dy / 2)
            l.append(lxy)
            l.append([S('layer'), S(layer)])
            l.append([S('width'), 0])
            return l

        # (fp_text reference MYCONN3 (at 0 -2.54) (layer F.SilkS)
        #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
        # )
        # (fp_text value SMD (at 0 2.54) (layer F.SilkS) hide
        #   (effects (font (size 1.00076 1.00076) (thickness 0.25146)))
        # )
        def label(shape, layer):
            s = shape['value'].upper()
            t = 'user'
            if s == 'VALUE': t = 'value'
            if s == 'NAME': t = 'reference'
            l = [S('fp_text'), S(t), S(shape['value'])]
            if (('rot' in shape) and (fget(shape, 'rot') != 0.0)):
                l.append([
                    S('at'),
                    fget(shape, 'x'),
                    fc(-fget(shape, 'y')),
                    fget(shape, 'rot')
                ])
            else:
                l.append([S('at'), fget(shape, 'x'), fc(-fget(shape, 'y'))])
            l.append([S('layer'), S(layer)])
            if s == 'VALUE':
                l.append(S('hide'))
            dy = fget(shape, 'dy', 1 / 1.6)
            th = fget(shape, 'w', 0.1)
            l.append([
                S('effects'),
                [S('font'), [S('size'), dy, dy], [S('thickness'), th]]
            ])
            return l

        def silk(shape):
            if not 'shape' in shape: return None
            layer = type_to_layer_name(shape['type'])
            s = shape['shape']
            if s == 'line': return vertex(shape, layer)
            if s == 'vertex': return vertex(shape, layer)
            elif s == 'circle': return circle(shape, layer)
            elif s == 'disc': return disc(shape, layer)
            elif s == 'label': return label(shape, layer)
            elif s == 'rect': return rect(shape, layer)
            elif s == 'polygon': return polygon(shape, layer)

        def unknown(shape):
            return None

        for shape in interim:
            if 'type' in shape:
                l2 = {
                    'pad': pad,
                    'cu': silk,
                    'silk': silk,
                    'docu': silk,
                    'keepout': unknown,
                    'stop': silk,
                    'glue': silk,
                    'restrict': unknown,
                    'vrestrict': unknown,
                    'smd': lambda s: pad(s, smd=True),
                    'hole': hole,
                }.get(shape['type'], unknown)(shape)
                if l2 != None:
                    l.append(l2)
        self.data = l
        self.name = name
        return name
Example #10
0
    def export_footprint(self, interim):
        # make a deep copy so we can make mods without harm
        interim = copy.deepcopy(interim)
        interim = self.add_ats_to_names(interim)
        meta = inter.get_meta(interim)
        name = eget(meta, 'name', 'Name not found')
        # make name eagle compatible
        name = re.sub(' ', '_', name)
        # check if there is an existing package
        # and if so, replace it
        packages = self.soup.eagle.drawing.packages('package')
        package = None
        for some_package in packages:
            if some_package['name'].lower() == name.lower():
                package = some_package
                package.clear()
                break
        if package == None:
            package = self.soup.new_tag('package')
            self.soup.eagle.drawing.packages.append(package)
            package['name'] = name

        def pad(shape):
            pad = self.soup.new_tag('pad')
            pad['name'] = shape['name']
            # don't set layer in a pad, it is implicit
            pad['x'] = fget(shape, 'x')
            pad['y'] = fget(shape, 'y')
            drill = fget(shape, 'drill')
            pad['drill'] = drill
            pad['rot'] = "R%d" % (fget(shape, 'rot'))
            r = fget(shape, 'r')
            shape2 = 'disc'  # disc is the default
            if 'shape' in shape:
                shape2 = shape['shape']
            if shape2 == 'disc':
                pad['shape'] = 'round'
                if f_neq(r, drill * 1.5):
                    pad['diameter'] = r * 2
            elif shape2 == 'octagon':
                pad['shape'] = 'octagon'
                if f_neq(r, drill * 1.5):
                    pad['diameter'] = r * 2
            elif shape2 == 'rect':
                ro = iget(shape, 'ro')
                if ro == 0:
                    pad['shape'] = 'square'
                    if f_neq(shape['dx'], drill * 1.5):
                        pad['diameter'] = float(shape['dx'])
                elif 'drill_dx' in shape:
                    pad['shape'] = 'offset'
                    if f_neq(shape['dy'], drill * 1.5):
                        pad['diameter'] = float(shape['dy'])
                else:
                    pad['shape'] = 'long'
                    if f_neq(shape['dy'], drill * 1.5):
                        pad['diameter'] = float(shape['dy'])
            package.append(pad)

        def smd(shape):
            smd = self.soup.new_tag('smd')
            smd['name'] = shape['name']
            smd['x'] = fget(shape, 'x')
            smd['y'] = fget(shape, 'y')
            smd['dx'] = fget(shape, 'dx')
            smd['dy'] = fget(shape, 'dy')
            smd['roundness'] = iget(shape, 'ro')
            smd['rot'] = "R%d" % (fget(shape, 'rot'))
            smd['layer'] = type_to_layer_number('smd')
            package.append(smd)

        def rect(shape, layer):
            rect = self.soup.new_tag('rectangle')
            x = fget(shape, 'x')
            y = fget(shape, 'y')
            dx = fget(shape, 'dx')
            dy = fget(shape, 'dy')
            rect['x1'] = x - dx / 2
            rect['x2'] = x + dx / 2
            rect['y1'] = y - dy / 2
            rect['y2'] = y + dy / 2
            rect['rot'] = "R%d" % (fget(shape, 'rot'))
            rect['layer'] = layer
            package.append(rect)

        def label(shape, layer):
            label = self.soup.new_tag('text')
            x = fget(shape, 'x')
            y = fget(shape, 'y')
            dy = fget(shape, 'dy', 1)
            s = shape['value']
            if s.upper() == "NAME":
                s = ">NAME"
                layer = type_to_layer_number('name')
            if s.upper() == "VALUE":
                s = ">VALUE"
                layer = type_to_layer_number('value')
            label['x'] = x
            label['y'] = y
            label['size'] = dy
            label['layer'] = layer
            label['align'] = 'center'
            label.string = s
            package.append(label)

        def disc(shape, layer):
            r = fget(shape, 'r')
            rx = fget(shape, 'rx', r)
            ry = fget(shape, 'ry', r)
            x = fget(shape, 'x')
            y = fget(shape, 'y')
            # a disc is just a circle with a
            # clever radius and width
            disc = self.soup.new_tag('circle')
            disc['x'] = x
            disc['y'] = y
            disc['radius'] = r / 2
            disc['width'] = r / 2
            disc['layer'] = layer
            package.append(disc)

        def circle(shape, layer):
            r = fget(shape, 'r')
            rx = fget(shape, 'rx', r)
            ry = fget(shape, 'ry', r)
            x = fget(shape, 'x')
            y = fget(shape, 'y')
            w = fget(shape, 'w')
            circle = self.soup.new_tag('circle')
            circle['x'] = x
            circle['y'] = y
            circle['radius'] = r
            circle['width'] = w
            circle['layer'] = layer
            package.append(circle)

        def line(shape, layer):
            x1 = fget(shape, 'x1')
            y1 = fget(shape, 'y1')
            x2 = fget(shape, 'x2')
            y2 = fget(shape, 'y2')
            w = fget(shape, 'w')
            line = self.soup.new_tag('wire')
            line['x1'] = x1
            line['y1'] = y1
            line['x2'] = x2
            line['y2'] = y2
            line['width'] = w
            line['layer'] = layer
            package.append(line)

        def silk(shape):
            if not 'shape' in shape: return
            layer = type_to_layer_number(shape['type'])
            s = shape['shape']
            if s == 'line': line(shape, layer)
            elif s == 'circle': circle(shape, layer)
            elif s == 'disc': disc(shape, layer)
            elif s == 'label': label(shape, layer)
            elif s == 'rect': rect(shape, layer)

        def unknown(shape):
            pass

        idx = eget(meta, 'id', 'Id not found')
        desc = oget(meta, 'desc', '')
        parent_idx = oget(meta, 'parent', None)
        description = self.soup.new_tag('description')
        package.append(description)
        parent_str = ""
        if parent_idx != None:
            parent_str = " parent: %s" % parent_idx
        description.string = desc + "\n<br/><br/>\nGenerated by 'madparts'.<br/>\nId: " + idx + "\n" + parent_str
        # TODO rework to be shape+type based ?
        for shape in interim:
            if 'type' in shape:
                {
                    'pad': pad,
                    'silk': silk,
                    'docu': silk,
                    'keepout': silk,
                    'stop': silk,
                    'restrict': silk,
                    'vrestrict': silk,
                    'smd': smd,
                }.get(shape['type'], unknown)(shape)
        return name