Error in python script

Hello,

Im trying to develop a plugin to create zones of certain shapes, as an exercise I tried to take the coordinates of two selected pads and creating a zone between the two.

Starting from some code I found @ https://github.com/mmccoo/kicad_mmccoo/blob/master/dxf_stuff/dxf_to_graphic.py, I wrote the following code (only the problematic part is shown):

`

    selectedPads = filter(lambda x: x.IsSelected(),pcbnew.GetBoard().GetPads())

    if(len(selectedPads) == 2):

        firstCenter = selectedPads[0].GetCenter()
        secondCenter = selectedPads[1].GetCenter()
        
        SCALE = 1000000.0
        seg = pcbnew.DRAWSEGMENT(board)
        seg.SetLayer(layertable['F.Cu'])
        seg.SetShape(pcbnew.S_POLYGON)
        sps = seg.GetPolyShape()
        o = sps.NewOutline()

        print(type(firstCenter.x))
        
        sps.Append(int(firstCenter.x*SCALE),int(firstCenter.y*SCALE), o)
        #sps.Append(int(firstCenter.x + 10*SCALE),int(firstCenter.y*SCALE), o)
        #sps.Append(int(firstCenter.x+10*SCALE),int(firstCenter.y-10*SCALE), o)
        #sps.Append(int(firstCenter.x*SCALE),int(firstCenter.y-10*SCALE), o)
        board.Add(seg)

`

But when i run with two pads selected I get:

TypeError: Wrong number or type of arguments for overloaded function 'SHAPE_POLY_SET_Append'. Possible C/C++ prototypes are: SHAPE_POLY_SET::Append(int,int,int,int,bool) SHAPE_POLY_SET::Append(int,int,int,int) SHAPE_POLY_SET::Append(int,int,int) SHAPE_POLY_SET::Append(int,int) SHAPE_POLY_SET::Append(SHAPE_POLY_SET const &) SHAPE_POLY_SET::Append(VECTOR2I const &,int,int) SHAPE_POLY_SET::Append(VECTOR2I const &,int) SHAPE_POLY_SET::Append(VECTOR2I const &)
Error that disappears if I change firstCenter.x/.y with a fixed value.
I checked manually in the scripting console what the type of those three arguments are and they all come out as int, which is ok given the third method signature, so I don’t see whats the problem in using firstCenter.x/,y instead of a fixed value.

What am I doing wrong?

I am running KiCad 5.1.10 on a Windows 10 machine.

Thanks.

Few things to note that don’t necessarily solve the particular issue you will run into:

  1. Pad coordinates are relative to footprint center. Your code wont work unless footprint is at 0,0 of the board.
  2. You shouldn’t need to multiply by scale if you take coordinates from objects, they are already at correct scale. Also there are helper functions like pcbnew.FromMM()
  3. You don’t need to pass outline if you are appending to the last outline of the SHAPE_POLY_SET

I am not sure why you get type error. It’s a pot shot but: if you are using 32 bit kicad and therefore 32 bit python you may be overflowing int in int(firstCenter.x*SCALE).

Thanks for the reply!

Addressing your points:

  1. I tried to print out the values of pad.GetPosition(), and its always a very big and different number based on what pad I have selected, so I don’t understand how what you say can be true in this regard, maybe the API changed recentely?

  2. I tried to print out the values of position and they always are very big numbers, something like 12345000, this cant be a value in mm so I tried applying the ToMM() function and the value returned is precisely the position in the board of that pad, see pad coordinate at bottom of screenshoot:


    The problem is that if I use what looks to be the correct value, the script throws the original error, because for some reason I don’t understand the method only accepts integers positions, how am I supposed to precisely bridge two pads with a copper zone by doing so?

  3. You are right! No need to pass that obejct, but I still need to instantiate it, otherwise kicad, yes the whole program, crashes.

As you can see I don’t know really well the APi yet, are there any resources you recommend reading? The self build API docs is not taht useful, and so far I’ve been learning from other’s people scripts, no the most fun when I would like to really learn this stuff, so much potential.

Thanks for your time.

You are right about coordinates, it seems like when you get pads directly from the board they are already translated and rotated using footprint position. I previously only accessed pads through footprint itself which is why I had the impression that they are always relative.

I tested your code on v6 which has a bit different API and it works fine for me. I’ll try later on v5 and share the code if I get it to work fully.
Also if you are just starting to learn I suggest you look into v6 release candidate (can be downloaded from nighty section on kicad downloads page) and learn that API so that you don’t have to relearn when it inevitably releases soon-ish.
Re: API reading recommendation: use the python scripting console to inspect objects as you create them. It will give you the same docs as in doxygen generated page but in better format and it has some rudimentary autocomplete.
When in doubt how particular api works best way to understand it is to read KiCad source code and look at the implementation/usages of the method. It’s tedious but until we have new API (was planned for v6, now slipped to v7) it is what it is.

1 Like

Here, I wrote a simple plugin for v5.1 that creates 1 mm wide rectangle polygon between 2 pad centers

Source:

import math
import pcbnew
import wx


class AddPolygon(pcbnew.ActionPlugin):
    def defaults(self):
        self.name = "Add Polygon"
        self.category = "Test"
        self.description = "Adds polygon between 2 pads"

    def Run(self):
        board = pcbnew.GetBoard()
        selectedPads = list(
            filter(lambda x: x.IsSelected(), pcbnew.GetBoard().GetPads()))

        if(len(selectedPads) != 2):
            wx.MessageBox("Select 2 pads to create a polygon",
                          style=wx.ICON_EXCLAMATION)
            return

        p1 = selectedPads[0].GetCenter()
        p2 = selectedPads[1].GetCenter()

        WIDTH = pcbnew.FromMM(1)

        # Find vector V perpendicular to (p2 - p1) with length WIDTH / 2
        # then points of the polygon are p1 +/- V and p2 +/- V
        WIDTH /= 2
        d = math.sqrt( (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y) )
        v = pcbnew.wxPoint( -(p2.y - p1.y) * WIDTH / d, (p2.x - p1.x) * WIDTH / d)

        polygon = pcbnew.DRAWSEGMENT(board)
        polygon.SetLayer(pcbnew.F_Cu)
        polygon.SetShape(pcbnew.S_POLYGON)
        shape = polygon.GetPolyShape()  # type: pcbnew.SHAPE_POLY_SET
        shape.NewOutline()

        shape.Append(p1.x + v.x, p1.y + v.y)
        shape.Append(p1.x - v.x, p1.y - v.y)
        shape.Append(p2.x - v.x, p2.y - v.y)
        shape.Append(p2.x + v.x, p2.y + v.y)

        board.Add(polygon)


AddPolygon().register()

Your code was pretty much correct.

Update: oh and disregard my rambling about coordinates being relative, I just tested and they are always absolute even when accessed from footprints. I’m not sure why I remembered that they are relative. I think it’s because of pad drill hole offset/angle.

2 Likes

Awesome, thanks! I will expand that script to account for pad thickness and thus creating a perfect match betweent the pads and polygon.

Don’t worry about your error, its all good :slight_smile:

Thats a real pity for the new API to slip to v7, guess I’ll wait patiently :smiley:

I am having issue with the plugin installation, I can’t make kicad to load it.

I have used this code to see where kicad looks to load plugins:
immagine

And so I placed the simple_plugin.py that I found here in C:\Users\Stefano\AppData\Roaming\kicad\scripting\plugins, along with its icon. But after refreshing the external tools I never get the new plugin added to the toolbar or dropdown menu.
Yes I put self.show_toolbar_button = True inside the plugin.
I also tried to close and reopen kicad with no luck.

What am I doing wrong?

Thanks.

Kicad remembers the toolbar button setting, changing it in plugin only changes the default, not the user settings. Go to preferences -> action plugins and enable the button there. If the plugin doesn’t show up in the list then see this post Plugin Problem If Writing/Reading External Files

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.