22from __future__ 
import division
 
   29    A class to simplify many aspects of footprint creation, leaving only
 
   30    the footprint specific routines to the wizards themselves.
 
   32    Inherit this 
class to make a new wizard.
 
   34    Provides simplified access to helpers like drawing functions, a transform
 
   35    matrix stack 
and simple parameter checking.
 
   37    Generally, you need to implement:
 
   49    uFloat = pcbnew.uFloat
 
   50    uInteger = pcbnew.uInteger
 
   52    uRadians = pcbnew.uRadians
 
   53    uDegrees = pcbnew.uDegrees
 
   54    uPercent = pcbnew.uPercent
 
   55    uString = pcbnew.uString
 
   63        Return the name of the footprint wizard 
   65        raise NotImplementedError
 
   69        Return the footprint wizard description 
   71        raise NotImplementedError
 
   75        Return the value (name) of the generated footprint 
   77        raise NotImplementedError
 
   81        Footprint parameter specification is done here
 
   83        raise NotImplementedError
 
   87        Any custom parameter checking should be performed here 
   89        raise NotImplementedError
 
   95        This is specific to each footprint 
class, you need to implement
 
   96        this to draw what you want
 
   98        raise NotImplementedError
 
  103        Actually make the footprint. We defer all but the set-up to 
  104        the implementing class 
  120                                  "Parameters have errors:\n")
 
  123                if len(p.error_list) > 0:
 
  125                        page=p.page, name=p.name)
 
  127                    for error 
in p.error_list:
 
  133            "Building new {name} footprint with the following parameters:\n" 
  134            .format(name=self.
name))
 
  160        If your plug-in sets a 3D model, override this function
 
  166        Get the default text size for the footprint. Override to change it.
 
  168        Defaults to IPC nominal of 1.0mm
 
  174        Thicker than IPC guidelines (10% of text height = 0.12mm) 
  175        as 5 wires/mm 
is a common silk screen limitation
 
  182    Collection of handy functions to simplify drawing shapes from within
 
  185    A 
"drawing context" is provided which can be used to set 
and retain
 
  186    settings such 
as line thickness 
and layer. The DC also contains a
 
  187    "transform stack", which allows easy positioning 
and transforming of
 
  188    drawn elements without lots of geometric book-keeping.
 
  207    xfrmIDENTITY = [1, 0, 0, 0, 1, 0]  
 
  213        return pcbnew.F_SilkS
 
  230        Add a transform to the top of the stack and recompute the
 
  233        @param mat: the transform matrix to add to the stack
 
  235        self.dc['transforms'].append(mat)
 
  240        Remove a transform from the top of the stack 
and recompute the
 
  243        @param num: the number of transforms to pop 
from the stack.
 
  244        @return the last popped transform
 
  248            mat = self.
dc[
'transforms'].pop()
 
  254        Reset the transform stack to the identity matrix. 
  256        self.dc['transforms'] = []
 
  259    def _ComposeMatricesWithIdentity(self, mats):
 
  261        Compose a sequence of matrices together by sequential 
  262        pre-multiplication with the identity matrix.
 
  264        @param mats: list of matrices to compose
 
  265        @return: the composed transform matrix
 
  273                x[0] * mat[0] + x[1] * mat[3],
 
  274                x[0] * mat[1] + x[1] * mat[4],
 
  275                x[0] * mat[2] + x[1] * mat[5] + x[2],
 
  276                x[3] * mat[0] + x[4] * mat[3],
 
  277                x[3] * mat[1] + x[4] * mat[4],
 
  278                x[3] * mat[2] + x[4] * mat[5] + x[5]]
 
  284        Re-compute the transform stack into a single transform and 
  288            self.
dc[
'transforms'])
 
  292        Set up and return a transform matrix representing a translation
 
  293        optionally pushing onto the stack
 
  298        @param x: translation 
in x-direction
 
  299        @param y: translation 
in y-direction
 
  300        @param push: add this transform to the current stack
 
  301        @return the generated transform matrix
 
  303        mat = [1, 0, x, 0, 1, y] 
  311        Set up and return a transform matrix representing a horizontal,
 
  312        vertical 
or both flip about the origin
 
  314        @param flip: one of flipNone, flipX, flipY, flipBoth
 
  315        @param push: add this transform to the current stack
 
  316        @return the generated transform matrix
 
  319        if flip == self.
flipX:
 
  320            mat = [-1, 0, 0, 0, 1, 0]
 
  321        elif flip == self.
flipY:
 
  322            mat = [1, 0, 0, 0, -1, 0]
 
  324            mat = [-1, 0, 0, 0, -1, 0]
 
  336        Set up and return a transform matrix representing a horizontal,
 
  337        vertical 
or both flip about a point (x,y)
 
  339        This 
is performed by a translate-to-origin, flip, translate-
 
  342        @param x: the x coordinate of the flip point
 
  343        @param y: the y coordinate of the flip point
 
  344        @param flip: one of flipNone, flipX, flipY, flipBoth
 
  345        @param push: add this transform to the current stack
 
  346        @return the generated transform matrix
 
  361        Set up and return a transform matrix representing a rotation
 
  362        about the origin, 
and optionally push onto the stack
 
  367        @param rot: the rotation angle 
in degrees
 
  368        @param push: add this transform to the current stack
 
  369        @return the generated transform matrix
 
  371        rads = rot * math.pi / 180 
  372        mat = [math.cos(rads), -math.sin(rads), 0, 
  373               math.sin(rads), math.cos(rads), 0] 
  381        Set up and return a transform matrix representing a rotation
 
  382        about the point (x,y), 
and optionally push onto the stack
 
  384        This 
is performed by a translate-to-origin, rotate, translate-
 
  387        @param x: the x coordinate of the rotation centre
 
  388        @param y: the y coordinate of the rotation centre
 
  389        @param rot: the rotation angle 
in degrees
 
  390        @param push: add this transform to the current stack
 
  391        @return the generated transform matrix
 
  407        Set up and return a transform matrix representing a scale about
 
  408        the origin, 
and optionally push onto the stack
 
  413        @param sx: the scale factor 
in the x direction
 
  414        @param sy: the scale factor 
in the y direction
 
  415        @param push: add this transform to the current stack
 
  416        @return the generated transform matrix
 
  422        mat = [sx, 0, 0, 0, sy, 0]
 
  430        Return a point (x, y) transformed by the given matrix, or if 
  431        that 
is not given, the drawing context transform
 
  433        @param x: the x coordinate of the point to transform
 
  434        @param y: the y coordinate of the point to transform
 
  435        @param mat: the transform matrix to use 
or None to use the current DC
's 
  436        @return: the transformed point 
as a VECTOR2I
 
  440            mat = self.
dc[
'transform']
 
  443                                (int)(x * mat[3] + y * mat[4] + mat[5]) )
 
  447        Set the current pen lineThickness used for subsequent drawing
 
  450        @param lineThickness: the new line thickness to set
 
  452        self.dc['lineThickness'] = lineThickness
 
  456        Old version of SetLineThickness. 
  457        Does the same thing, but is only here 
for compatibility 
with old
 
  459        Set the current pen lineThickness used 
for subsequent drawing
 
  462        @param lineThickness: the new line thickness to set
 
  468        Get the current drawing context line thickness 
  470        return self.
dc[
'lineThickness']
 
  474        Set the current drawing layer, used for subsequent drawing
 
  477        self.dc['layer'] = layer
 
  481        Return the current drawing layer, used for drawing operations
 
  483        return self.
dc[
'layer']
 
  485    def Line(self, x1, y1, x2, y2):
 
  487        Draw a line from (x1, y1) to (x2, y2)
 
  492        outline.SetShape(pcbnew.S_SEGMENT) 
  495        outline.SetStartEnd(start, end) 
  500        Draw a circle at (x,y) of radius r 
  501        If filled is true, the thickness 
and radius of the line will be set
 
  502        such that the circle appears filled
 
  504        @param x: the x coordinate of the arc centre
 
  505        @param y: the y coordinate of the arc centre
 
  506        @param r: the circle
's radius 
  507        @param filled: 
True to draw a filled circle, 
False to use the current
 
  518            circle.SetWidth(self.
dc[
'lineThickness'])
 
  521        circle.SetLayer(self.
dc[
'layer'])
 
  522        circle.SetShape(pcbnew.S_CIRCLE)
 
  523        circle.SetStartEnd(start, end)
 
  528        replace the cmp() of python2 
  536    def Arc(self, cx, cy, sx, sy, angle):
 
  538        Draw an arc based on centre, start and angle
 
  540        The transform matrix 
is applied
 
  542        Note that this won
't work properly if the result is not a 
  543        circular arc (e.g. a horizontal scale) 
  545        @param cx: the x coordinate of the arc centre
 
  546        @param cy: the y coordinate of the arc centre
 
  547        @param sx: the x coordinate of the arc start point
 
  548        @param sy: the y coordinate of the arc start point
 
  549        @param angle: the arc
's central angle (in deci-degrees) 
  552        arc.SetShape(pcbnew.SHAPE_T_ARC) 
  553        arc.SetWidth(self.dc['lineThickness'])
 
  558        arc.SetLayer(self.
dc[
'layer'])
 
  561        if self.
MyCmp(self.
dc[
'transform'][0], 0) != self.
MyCmp(self.
dc[
'transform'][4], 0):
 
  564        arc.SetCenter(center)
 
  566        arc.SetArcAngleAndEnd(angle, 
True)
 
  572        Draw a horizontal line from (x,y), rightwards
 
  574        @param x: line start x coordinate
 
  575        @param y: line start y coordinate
 
  576        @param l: line length
 
  578        self.Line(x, y, x + l, y) 
  582        Draw a vertical line from (x1,y1), downwards
 
  584        @param x: line start x coordinate
 
  585        @param y: line start y coordinate
 
  586        @param l: line length
 
  588        self.Line(x, y, x, y + l) 
  590    def Polyline(self, pts, mirrorX=None, mirrorY=None):
 
  592        Draw a polyline, optionally mirroring around the given points 
  594        @param pts: list of polyline vertices (list of (x, y))
 
  595        @param mirrorX: x coordinate of mirror point (
None for no x-flip)
 
  596        @param mirrorY: y coordinate of mirror point (
None for no y-flip)
 
  599        def _PolyLineInternal(pts):
 
  603            for i 
in range(0, len(pts) - 1):
 
  604                self.
Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1])
 
  606        if mirrorX 
is None and mirrorY 
is None:
 
  607            _PolyLineInternal(pts)  
 
  609        elif mirrorX 
is not None and mirrorY 
is not None:
 
  611            _PolyLineInternal(pts)
 
  614        elif mirrorX 
is not None:
 
  616            _PolyLineInternal(pts)
 
  619        elif mirrorY 
is not None:
 
  621            _PolyLineInternal(pts)
 
  626        Draw the module's reference as the given point. 
  628        The actual setting of the reference is not done 
in this drawing
 
  629        aid - that 
is up to the wizard
 
  631        @param x: the x position of the reference
 
  632        @param y: the y position of the reference
 
  633        @param size: the text size (
in both directions)
 
  634        @param orientation_degree: text orientation 
in degrees
 
  643    def Value(self, x, y, size, orientation_degree=0):
 
  645        As for references, draw the module
's value 
  647        @param x: the x position of the value
 
  648        @param y: the y position of the value
 
  649        @param size: the text size (
in both directions)
 
  650        @param orientation_degree: text orientation 
in degrees
 
  659    def Box(self, x, y, w, h):
 
  661        Draw a rectangular box, centred at (x,y), with given width 
and 
  664        @param x: the x coordinate of the box
's centre 
  665        @param y: the y coordinate of the box
's centre 
  666        @param w: the width of the box
 
  667        @param h: the height of the box
 
  670        pts = [[x - w/2, y - h/2],   
  680        Circle radius r centred at (x, y) with a raised 
or depressed notch
 
  682        Notch height 
is measured 
from the top of the circle radius
 
  684        @param x: the x coordinate of the circle
's centre 
  685        @param y: the y coordinate of the circle
's centre 
  686        @param r: the radius of the circle
 
  687        @param notch_w: the width of the notch
 
  688        @param notch_h: the height of the notch
 
  689        @param rotate: the rotation of the whole figure, 
in degrees
 
  695        angle_intercept = math.asin(notch_w/(2 * r))
 
  698        sx = math.sin(angle_intercept) * r
 
  699        sy = -math.cos(angle_intercept) * r
 
  702        arc_angle = (math.pi * 2 - angle_intercept * 2) * (1800/math.pi)
 
  704        self.
Arc(x, y, sx, sy, arc_angle)
 
  716        Draw a box with a notch 
in the centre of the top edge
 
  718        @param x: the x coordinate of the circle
's centre 
  719        @param y: the y coordinate of the circle
's centre 
  720        @param w: the width of the box
 
  721        @param h: the height of the box
 
  722        @param notchW: the width of the notch
 
  723        @param notchH: the height of the notch
 
  724        @param rotate: the rotation of the whole figure, 
in degrees
 
  730        notchW = min(x + w/2, notchW)
 
  740            (notchW/2, y - h/2 + notchH),
 
  741            (-notchW/2, y - h/2 + notchH),
 
  742            (-notchW/2, y - h/2),
 
  749                                setback=pcbnew.FromMM(1.27), flip=flipNone):
 
  751        Draw a box with a diagonal at the top left corner.
 
  753        @param x: the x coordinate of the circle
's centre 
  754        @param y: the y coordinate of the circle
's centre 
  755        @param w: the width of the box
 
  756        @param h: the height of the box
 
  757        @param setback: the set-back of the diagonal, 
in both x 
and y
 
  758        @param flip: one of flipNone, flipX, flipY 
or flipBoth to change the
 
  764        pts = [[x - w/2 + setback, y - h/2],
 
  765               [x - w/2,           y - h/2 + setback],
 
  769               [x - w/2 + setback, y - h/2]]
 
  776                          setback=pcbnew.FromMM(1.27), flip=flipNone):
 
  778        Draw a box with an opening at the top left corner
 
  780        @param x: the x coordinate of the circle
's centre 
  781        @param y: the y coordinate of the circle
's centre 
  782        @param w: the width of the box
 
  783        @param h: the height of the box
 
  784        @param setback: the set-back of the opening, 
in both x 
and y
 
  785        @param flip: one of flipNone, flipX, flipY 
or flipBoth to change the
 
  792        pts = [[- w/2,           - h/2 + setback], 
  796               [- w/2 + setback, - h/2]] 
  804        Draw a box with rounded corners (i.e. a 90-degree circular arc)
 
  806        :param x: the x coordinate of the box
's centre 
  807        :param y: the y coordinate of the box's centre 
  808        :param w: the width of the box 
  809        :param h: the height of the box 
  810        :param rad: the radius of the corner rounds 
  813        x_inner = w - rad * 2 
  814        y_inner = h - rad * 2 
  820        self.
HLine(x_left + rad, y_top, x_inner)
 
  821        self.
HLine(x_left + rad, -y_top, x_inner)
 
  823        self.
VLine(x_left, y_top + rad, y_inner)
 
  824        self.
VLine(-x_left, y_top + rad, y_inner)
 
  832        self.
Arc(+cx, +cy, +x_left, +cy, +ninety_deg)
 
  833        self.
Arc(-cx, +cy, -x_left, +cy, -ninety_deg)
 
  834        self.
Arc(+cx, -cy, +x_left, -cy, -ninety_deg)
 
  835        self.
Arc(-cx, -cy, -x_left, -cy, +ninety_deg)
 
  839        Draw a box with chamfered corners.
 
  841        :param x: the x coordinate of the box
's centre 
  842        :param y: the y coordinate of the box's centre 
  843        :param w: the width of the box 
  844        :param h: the height of the box 
  845        :param chamfer_x: the size of the chamfer set-back in the x direction
 
  846        :param chamfer_y: the size of the chamfer set-back 
in the y direction
 
  853        x_inner = x_left + chamfer_x
 
  854        y_inner = y_top + chamfer_y
 
  870    def MarkerArrow(self, x, y, direction=dirN, width=pcbnew.FromMM(1)):
 
  872        Draw a marker arrow facing in the given direction, 
with the
 
  875        @param x: x position of the arrow tip
 
  876        @param y: y position of the arrow tip
 
  877        @param direction: arrow direction 
in degrees (0 
is "north", can use
 
  879        @param width: arrow width
 
  886               [width / 2,  width / 2], 
  887               [-width / 2, width / 2],