Browse Source

Added KiCad tools

Gareth O'Brien 6 years ago
parent
commit
882c3fc679

+ 14 - 5
et.py

@@ -1,7 +1,16 @@
 #!/usr/bin/env python
 # Expose track for pcbnew
-
+import collections
+from collections import defaultdict, Counter
+from itertools import compress,izip, cycle
+import itertools
 import pcbnew
+import time
+import os, sys
+import math
+import re
+from textwrap import wrap
+import wx
 
 def AddMask():
 #Copy track to mask layer
@@ -14,12 +23,12 @@ def AddMask():
             if track.GetLayer() == pcbnew.F_Cu:
                 maskLayer = pcbnew.F_Mask
             else:
-                if(track.GetLayer() == pcbnew.B_Cu):
-                    maskLayer = pcbnew.B_Mask
-                else:
+#                if(track.GetLayer() == pcbnew.B_Cu):
+#                    maskLayer = pcbnew.B_Mask
+#                else:
                     continue
 
-            trackMask = pcbnew.TRACK(aParent=None, idtype=PCB_TRACE_T)
+            trackMask = pcbnew.DRAWSEGMENT(pcb)
             trackMask.SetStart(track.GetStart())
             trackMask.SetEnd(track.GetEnd())
             trackMask.SetWidth(track.GetWidth())

+ 355 - 0
kicommand/KiCommand_GUI.fbp

@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<wxFormBuilder_Project>
+    <FileVersion major="1" minor="13" />
+    <object class="Project" expanded="1">
+        <property name="class_decoration"></property>
+        <property name="code_generation">Python</property>
+        <property name="disconnect_events">1</property>
+        <property name="disconnect_mode">source_name</property>
+        <property name="disconnect_php_events">0</property>
+        <property name="disconnect_python_events">0</property>
+        <property name="embedded_files_path">res</property>
+        <property name="encoding">UTF-8</property>
+        <property name="event_generation">connect</property>
+        <property name="file">kicommand_gui</property>
+        <property name="first_id">1000</property>
+        <property name="help_provider">none</property>
+        <property name="internationalize">0</property>
+        <property name="name">KiCommand_GUI</property>
+        <property name="namespace"></property>
+        <property name="path">.</property>
+        <property name="precompiled_header"></property>
+        <property name="relative_path">1</property>
+        <property name="skip_lua_events">1</property>
+        <property name="skip_php_events">1</property>
+        <property name="skip_python_events">1</property>
+        <property name="ui_table">UI</property>
+        <property name="use_enum">0</property>
+        <property name="use_microsoft_bom">0</property>
+        <object class="Panel" expanded="1">
+            <property name="aui_managed">1</property>
+            <property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
+            <property name="bg"></property>
+            <property name="context_help"></property>
+            <property name="context_menu">1</property>
+            <property name="enabled">1</property>
+            <property name="event_handler">impl_virtual</property>
+            <property name="fg"></property>
+            <property name="font"></property>
+            <property name="hidden">0</property>
+            <property name="id">wxID_ANY</property>
+            <property name="maximum_size"></property>
+            <property name="minimum_size"></property>
+            <property name="name">kicommand_panel</property>
+            <property name="pos"></property>
+            <property name="size">500,300</property>
+            <property name="subclass"></property>
+            <property name="tooltip"></property>
+            <property name="window_extra_style"></property>
+            <property name="window_name"></property>
+            <property name="window_style">wxTAB_TRAVERSAL</property>
+            <event name="OnAuiFindManager"></event>
+            <event name="OnAuiPaneButton"></event>
+            <event name="OnAuiPaneClose"></event>
+            <event name="OnAuiPaneMaximize"></event>
+            <event name="OnAuiPaneRestore"></event>
+            <event name="OnAuiRender"></event>
+            <event name="OnChar"></event>
+            <event name="OnEnterWindow"></event>
+            <event name="OnEraseBackground"></event>
+            <event name="OnInitDialog"></event>
+            <event name="OnKeyDown"></event>
+            <event name="OnKeyUp"></event>
+            <event name="OnKillFocus"></event>
+            <event name="OnLeaveWindow"></event>
+            <event name="OnLeftDClick"></event>
+            <event name="OnLeftDown"></event>
+            <event name="OnLeftUp"></event>
+            <event name="OnMiddleDClick"></event>
+            <event name="OnMiddleDown"></event>
+            <event name="OnMiddleUp"></event>
+            <event name="OnMotion"></event>
+            <event name="OnMouseEvents"></event>
+            <event name="OnMouseWheel"></event>
+            <event name="OnPaint"></event>
+            <event name="OnRightDClick"></event>
+            <event name="OnRightDown"></event>
+            <event name="OnRightUp"></event>
+            <event name="OnSetFocus"></event>
+            <event name="OnSize"></event>
+            <event name="OnUpdateUI"></event>
+            <object class="wxPanel" expanded="1">
+                <property name="BottomDockable">1</property>
+                <property name="LeftDockable">1</property>
+                <property name="RightDockable">1</property>
+                <property name="TopDockable">1</property>
+                <property name="aui_layer"></property>
+                <property name="aui_name"></property>
+                <property name="aui_position"></property>
+                <property name="aui_row"></property>
+                <property name="best_size"></property>
+                <property name="bg"></property>
+                <property name="caption"></property>
+                <property name="caption_visible">0</property>
+                <property name="center_pane">0</property>
+                <property name="close_button">0</property>
+                <property name="context_help"></property>
+                <property name="context_menu">1</property>
+                <property name="default_pane">0</property>
+                <property name="dock">Dock</property>
+                <property name="dock_fixed">1</property>
+                <property name="docking">Center</property>
+                <property name="enabled">1</property>
+                <property name="fg"></property>
+                <property name="floatable">1</property>
+                <property name="font"></property>
+                <property name="gripper">0</property>
+                <property name="hidden">0</property>
+                <property name="id">wxID_ANY</property>
+                <property name="max_size"></property>
+                <property name="maximize_button">0</property>
+                <property name="maximum_size"></property>
+                <property name="min_size"></property>
+                <property name="minimize_button">0</property>
+                <property name="minimum_size"></property>
+                <property name="moveable">1</property>
+                <property name="name">m_panel1</property>
+                <property name="pane_border">1</property>
+                <property name="pane_position"></property>
+                <property name="pane_size"></property>
+                <property name="permission">protected</property>
+                <property name="pin_button">0</property>
+                <property name="pos"></property>
+                <property name="resize">Resizable</property>
+                <property name="show">1</property>
+                <property name="size"></property>
+                <property name="subclass"></property>
+                <property name="toolbar_pane">0</property>
+                <property name="tooltip"></property>
+                <property name="window_extra_style"></property>
+                <property name="window_name"></property>
+                <property name="window_style">wxTAB_TRAVERSAL</property>
+                <event name="OnChar"></event>
+                <event name="OnEnterWindow"></event>
+                <event name="OnEraseBackground"></event>
+                <event name="OnKeyDown"></event>
+                <event name="OnKeyUp"></event>
+                <event name="OnKillFocus"></event>
+                <event name="OnLeaveWindow"></event>
+                <event name="OnLeftDClick"></event>
+                <event name="OnLeftDown"></event>
+                <event name="OnLeftUp"></event>
+                <event name="OnMiddleDClick"></event>
+                <event name="OnMiddleDown"></event>
+                <event name="OnMiddleUp"></event>
+                <event name="OnMotion"></event>
+                <event name="OnMouseEvents"></event>
+                <event name="OnMouseWheel"></event>
+                <event name="OnPaint"></event>
+                <event name="OnRightDClick"></event>
+                <event name="OnRightDown"></event>
+                <event name="OnRightUp"></event>
+                <event name="OnSetFocus"></event>
+                <event name="OnSize"></event>
+                <event name="OnUpdateUI"></event>
+                <object class="wxBoxSizer" expanded="1">
+                    <property name="minimum_size"></property>
+                    <property name="name">bSizer2</property>
+                    <property name="orient">wxVERTICAL</property>
+                    <property name="permission">none</property>
+                    <object class="sizeritem" expanded="1">
+                        <property name="border">5</property>
+                        <property name="flag">wxALL|wxEXPAND</property>
+                        <property name="proportion">0</property>
+                        <object class="wxComboBox" expanded="1">
+                            <property name="BottomDockable">1</property>
+                            <property name="LeftDockable">1</property>
+                            <property name="RightDockable">1</property>
+                            <property name="TopDockable">1</property>
+                            <property name="aui_layer"></property>
+                            <property name="aui_name"></property>
+                            <property name="aui_position"></property>
+                            <property name="aui_row"></property>
+                            <property name="best_size"></property>
+                            <property name="bg"></property>
+                            <property name="caption"></property>
+                            <property name="caption_visible">1</property>
+                            <property name="center_pane">0</property>
+                            <property name="choices"></property>
+                            <property name="close_button">1</property>
+                            <property name="context_help"></property>
+                            <property name="context_menu">1</property>
+                            <property name="default_pane">0</property>
+                            <property name="dock">Dock</property>
+                            <property name="dock_fixed">0</property>
+                            <property name="docking">Left</property>
+                            <property name="enabled">1</property>
+                            <property name="fg"></property>
+                            <property name="floatable">1</property>
+                            <property name="font"></property>
+                            <property name="gripper">0</property>
+                            <property name="hidden">0</property>
+                            <property name="id">wxID_ANY</property>
+                            <property name="max_size"></property>
+                            <property name="maximize_button">0</property>
+                            <property name="maximum_size"></property>
+                            <property name="min_size"></property>
+                            <property name="minimize_button">0</property>
+                            <property name="minimum_size"></property>
+                            <property name="moveable">1</property>
+                            <property name="name">entrybox</property>
+                            <property name="pane_border">1</property>
+                            <property name="pane_position"></property>
+                            <property name="pane_size"></property>
+                            <property name="permission">protected</property>
+                            <property name="pin_button">1</property>
+                            <property name="pos"></property>
+                            <property name="resize">Resizable</property>
+                            <property name="selection">-1</property>
+                            <property name="show">1</property>
+                            <property name="size"></property>
+                            <property name="style">wxCB_DROPDOWN|wxTE_PROCESS_ENTER</property>
+                            <property name="subclass"></property>
+                            <property name="toolbar_pane">0</property>
+                            <property name="tooltip"></property>
+                            <property name="validator_data_type"></property>
+                            <property name="validator_style">wxFILTER_NONE</property>
+                            <property name="validator_type">wxDefaultValidator</property>
+                            <property name="validator_variable"></property>
+                            <property name="value">help</property>
+                            <property name="window_extra_style"></property>
+                            <property name="window_name"></property>
+                            <property name="window_style"></property>
+                            <event name="OnChar"></event>
+                            <event name="OnCombobox"></event>
+                            <event name="OnComboboxCloseup"></event>
+                            <event name="OnComboboxDropdown"></event>
+                            <event name="OnEnterWindow"></event>
+                            <event name="OnEraseBackground"></event>
+                            <event name="OnKeyDown"></event>
+                            <event name="OnKeyUp"></event>
+                            <event name="OnKillFocus"></event>
+                            <event name="OnLeaveWindow"></event>
+                            <event name="OnLeftDClick"></event>
+                            <event name="OnLeftDown"></event>
+                            <event name="OnLeftUp"></event>
+                            <event name="OnMiddleDClick"></event>
+                            <event name="OnMiddleDown"></event>
+                            <event name="OnMiddleUp"></event>
+                            <event name="OnMotion"></event>
+                            <event name="OnMouseEvents"></event>
+                            <event name="OnMouseWheel"></event>
+                            <event name="OnPaint"></event>
+                            <event name="OnRightDClick"></event>
+                            <event name="OnRightDown"></event>
+                            <event name="OnRightUp"></event>
+                            <event name="OnSetFocus"></event>
+                            <event name="OnSize"></event>
+                            <event name="OnText"></event>
+                            <event name="OnTextEnter">process</event>
+                            <event name="OnUpdateUI"></event>
+                        </object>
+                    </object>
+                    <object class="sizeritem" expanded="1">
+                        <property name="border">5</property>
+                        <property name="flag">wxEXPAND | wxALL</property>
+                        <property name="proportion">1</property>
+                        <object class="wxRichTextCtrl" expanded="1">
+                            <property name="BottomDockable">1</property>
+                            <property name="LeftDockable">1</property>
+                            <property name="RightDockable">1</property>
+                            <property name="TopDockable">1</property>
+                            <property name="aui_layer"></property>
+                            <property name="aui_name"></property>
+                            <property name="aui_position"></property>
+                            <property name="aui_row"></property>
+                            <property name="best_size"></property>
+                            <property name="bg"></property>
+                            <property name="caption"></property>
+                            <property name="caption_visible">1</property>
+                            <property name="center_pane">0</property>
+                            <property name="close_button">1</property>
+                            <property name="context_help"></property>
+                            <property name="context_menu">1</property>
+                            <property name="default_pane">0</property>
+                            <property name="dock">Dock</property>
+                            <property name="dock_fixed">0</property>
+                            <property name="docking">Left</property>
+                            <property name="enabled">1</property>
+                            <property name="fg"></property>
+                            <property name="floatable">1</property>
+                            <property name="font"></property>
+                            <property name="gripper">0</property>
+                            <property name="hidden">0</property>
+                            <property name="id">wxID_ANY</property>
+                            <property name="max_size"></property>
+                            <property name="maximize_button">0</property>
+                            <property name="maximum_size"></property>
+                            <property name="min_size"></property>
+                            <property name="minimize_button">0</property>
+                            <property name="minimum_size"></property>
+                            <property name="moveable">1</property>
+                            <property name="name">outputbox</property>
+                            <property name="pane_border">1</property>
+                            <property name="pane_position"></property>
+                            <property name="pane_size"></property>
+                            <property name="permission">protected</property>
+                            <property name="pin_button">1</property>
+                            <property name="pos"></property>
+                            <property name="resize">Resizable</property>
+                            <property name="show">1</property>
+                            <property name="size"></property>
+                            <property name="style"></property>
+                            <property name="subclass"></property>
+                            <property name="toolbar_pane">0</property>
+                            <property name="tooltip"></property>
+                            <property name="validator_data_type"></property>
+                            <property name="validator_style">wxFILTER_NONE</property>
+                            <property name="validator_type">wxDefaultValidator</property>
+                            <property name="validator_variable"></property>
+                            <property name="window_extra_style"></property>
+                            <property name="window_name"></property>
+                            <property name="window_style">wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS</property>
+                            <event name="OnChar"></event>
+                            <event name="OnEnterWindow"></event>
+                            <event name="OnEraseBackground"></event>
+                            <event name="OnKeyDown"></event>
+                            <event name="OnKeyUp"></event>
+                            <event name="OnKillFocus"></event>
+                            <event name="OnLeaveWindow"></event>
+                            <event name="OnLeftDClick"></event>
+                            <event name="OnLeftDown"></event>
+                            <event name="OnLeftUp"></event>
+                            <event name="OnMiddleDClick"></event>
+                            <event name="OnMiddleDown"></event>
+                            <event name="OnMiddleUp"></event>
+                            <event name="OnMotion"></event>
+                            <event name="OnMouseEvents"></event>
+                            <event name="OnMouseWheel"></event>
+                            <event name="OnPaint"></event>
+                            <event name="OnRichTextCharacter"></event>
+                            <event name="OnRichTextContentDeleted"></event>
+                            <event name="OnRichTextContentInserted"></event>
+                            <event name="OnRichTextDelete"></event>
+                            <event name="OnRichTextReturn"></event>
+                            <event name="OnRichTextStyleChanged"></event>
+                            <event name="OnRichTextStyleSheetChanged"></event>
+                            <event name="OnRichTextStyleSheetReplaced"></event>
+                            <event name="OnRichTextStyleSheetReplacing"></event>
+                            <event name="OnRightDClick"></event>
+                            <event name="OnRightDown"></event>
+                            <event name="OnRightUp"></event>
+                            <event name="OnSetFocus"></event>
+                            <event name="OnSize"></event>
+                            <event name="OnText"></event>
+                            <event name="OnTextEnter"></event>
+                            <event name="OnTextMaxLen"></event>
+                            <event name="OnTextURL"></event>
+                            <event name="OnUpdateUI"></event>
+                        </object>
+                    </object>
+                </object>
+            </object>
+        </object>
+    </object>
+</wxFormBuilder_Project>

+ 6 - 0
kicommand/__init__.py

@@ -0,0 +1,6 @@
+#from .kicommand import aplugin
+from .kicommand import *
+
+plugin = aplugin()
+plugin.register()
+plugin.Run()

File diff suppressed because it is too large
+ 3185 - 0
kicommand/kicommand.py


+ 59 - 0
kicommand/kicommand_gui.py

@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*- 
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Jun 28 2017)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO "NOT" EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+import wx.aui
+import wx.richtext
+
+###########################################################################
+## Class kicommand_panel
+###########################################################################
+
+class kicommand_panel ( wx.Panel ):
+	
+	def __init__( self, parent ):
+		wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.TAB_TRAVERSAL )
+		
+		self.m_mgr = wx.aui.AuiManager()
+		self.m_mgr.SetManagedWindow( self )
+		self.m_mgr.SetFlags(wx.aui.AUI_MGR_DEFAULT)
+		
+		self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
+		self.m_mgr.AddPane( self.m_panel1, wx.aui.AuiPaneInfo() .Center() .CaptionVisible( False ).CloseButton( False ).Dock().Resizable().FloatingSize( wx.DefaultSize ).DockFixed( True ) )
+		
+		bSizer2 = wx.BoxSizer( wx.VERTICAL )
+		
+		entryboxChoices = []
+		self.entrybox = wx.ComboBox( self.m_panel1, wx.ID_ANY, u"help", wx.DefaultPosition, wx.DefaultSize, entryboxChoices, wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER )
+		bSizer2.Add( self.entrybox, 0, wx.ALL|wx.EXPAND, 5 )
+		
+		self.outputbox = wx.richtext.RichTextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0|wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER|wx.WANTS_CHARS )
+		bSizer2.Add( self.outputbox, 1, wx.EXPAND |wx.ALL, 5 )
+		
+		
+		self.m_panel1.SetSizer( bSizer2 )
+		self.m_panel1.Layout()
+		bSizer2.Fit( self.m_panel1 )
+		
+		self.m_mgr.Update()
+		
+		# Connect Events
+		self.entrybox.Bind( wx.EVT_TEXT_ENTER, self.process )
+	
+	def __del__( self ):
+		self.m_mgr.UnInit()
+		
+	
+	
+	# Virtual event handlers, overide them in your derived class
+	def process( self, event ):
+		event.Skip()
+	
+

+ 68 - 0
kicommand/kicommand_persist.commands

@@ -0,0 +1,68 @@
+:persist wxpoint "Geometry [X,Y] Create a  wxpoint" pcbnew list swap list wxPoint callargs ;
+:persist toptextobj "Elements Get the top level text objects." drawings EDA_TEXT filtertype ;
+:persist valuetextobj "Elements Get all module's Value text objects." modules Value call ;
+:persist referencetextobj "Elements Get all module's Reference text objects." modules Reference call ;
+:persist moduletextobj "Elements Get all module's text objects that are not Value and not Reference." modules GraphicalItems calllist EDA_TEXT filtertype ;
+:persist drawparams "Draw [THICKNESS,WIDTH,HEIGHT LAYER] Set drawing parameters for future draw commands.\nExample: 1,5,5 mm F.Fab drawparams" 'l param t,w,h param ;
+:persist textfromobj "Elements [TEXTOBJECT] Get the text string from a text object." GetShownText call ;
+:persist valuetext "Elements Get all module's Value text as a string." modules GetValue call ;
+:persist referencetext "Elements Get all module's Reference text as a string." modules GetReference call ;
+:persist not "Programming [VALUELIST] Invert the boolean value. False, 0, None becomes True and True, non-zero, non-empty list becomes False." ' = ;
+:persist copy "Programming Copies the top of the stack." 0 pick ;
+:persist setselect "Elements [OBJECTLIST] Sets the objects as Selected." SetSelected call pop ;
+:persist clearselect "Elements [OBJECTLIST] Sets the objects as Unselected." ClearSelected call pop ;
+:persist orthogonal "Draw Make the angle between all elements a integer multiple 90 degrees." 90 makeangle ;
+:persist clearallselected "Elements Clear the selection of all items."
+        modules copy GetReference call clearselect
+        copy GetValue call clearselect
+        copy GraphicalItems calllist clearselect
+        clearselect
+        pads clearselect
+        tracks clearselect
+        drawings clearselect 
+        ;
+:persist outlinepads "Draw Outline all pads using line segments with the layer and width specified by drawparams." 
+        pads copy corners swap copy GetCenter call swap 
+        GetOrientationDegrees call rotatepoints drawpoly
+        ;
+:persist outlinetext "Draw Outline all text objects with the layer and width specified by drawparams."
+        valuetextobj
+        referencetextobj append 
+        moduletextobj append 
+        toptextobj append
+        copy GetTextBox call corners swap copy GetCenter call swap 
+        copy GetTextAngleDegrees call swap GetParent call Cast call GetOrientationDegrees call
+        +l rotatepoints drawpoly
+        ;
+        
+:persist outlinetoptext "Draw Outline all top text objects with the layer and width specified by drawparams."
+        toptextobj
+        copy GetTextBox call corners swap copy GetCenter call swap
+        GetTextAngleDegrees call rotatepoints drawpoly ;
+        ;
+:persist texttosegments "Draw [TEXTOBJLIST LAYER] Copies text objects in TEXTOBJLIST to LAYER."
+        swap copy GetThickness call list swap 
+        topoints pairwise 2 pick tosegments 
+        copy 2 pick SetWidth callargs pop
+        swap pop swap pop
+        ;
+:persist regularsize "Draw,Geometry [SIDELENGTH] [PARALLELANGLE] regularsize takes the selected segments, joins them into a regular polygon, then sizes the edges to the specified length, and places one of the edges parallel to the specified angle Example: 30 mm 0 regularsize"
+        drawings selected copy connect copy
+        regular copy copy length delist stack 4 pick swap /f 
+        scale copy delist list angle delist 2 pick swap -f rotate
+        pop pop
+        ;
+        
+:persist range "Programming [START,STOP,INC] Returns a list of numbers" builtins 'range sindex list stack swap int list fcallargs delist ;
+:persist len "Conversion [LIST] return the length of the list" ilist list list builtins 'len sindex list swap stack fcallargs sum stack ;
+:persist newboard "Elements Create a new empty board and make it the current board." pcbnew list BOARD call delist Board spush ;
+:persist newadd "Elements [TYPE PARENT] Add a new element of TYPE to PARENT. Returns the new module." list copy pcbnew list swap list 3 pick callargs 1 pick 1 pick list Add callargs pop swap pop swap pop delist ;
+:persist drawsegments "Draw [POINTSLIST] Alias for drawpoly." drawpoly ;
+
+:persist true "Programming Returns the value True." 1 bool ;
+:persist false "Programming Returns the value False."' bool ;
+
+:persist regexref "Filter,Comparison [MODULELIST REGULAREXPRESSION] return only those modules in MODULELIST whose reference are matched by the REGULAREXPRESSION" swap copy GetReference call 2 pick regex isnotnone filter swap pop ;
+:persist refobj "Elements [MODULELIST] Return the reference objects of the modules" Reference call ;
+:persist setvisible "Elements [OBJECTLIST] Set the objects to visible." true SetVisible callargs pop ;
+:persist clearvisible "Elements [OBJECTLIST] Set the objects to invisible." false SetVisible callargs pop ;

+ 12 - 0
kicommand/loadable/elephant.txt

@@ -0,0 +1,12 @@
+-5,3,-5,2,-3,-2 mm drawpoly delist
+-4,0,-5,-4,-5,-8,-4,-13,-4,-22,-2,-23,0,-22,0,-12,1,-10,2,-12,2,-22,4,-23,6,-22,6,-13,7,-8,7,-4,6,0 mm drawpoly delist append
+7,-10,8,-12,8,-18,9,-19,11,-18,11,-9,12,-7 mm drawpoly delist append
+6.5,-10,8,-10,10,-9,12,-7,13,-4,13,2,12,5,9,7 mm drawpoly delist append
+6,7,7,6,9,5,9,7,10,10,11,12,13,14,13,16,11,17,7,17,3,15 mm drawpoly delist append
+4,13,3,15,1,17,-2,17,-3,16,-4,14,-5,15 mm drawpoly delist append
+-1,9,-2,8,-3,8,-4,10,-5,15,-6,19,-8,22,-10,22,-11,21,-10,20,-9,20,-8,18,-8,10,-7,6,-6,4,-5,3,-2,2,-1,2,1,3,2,4 mm drawpoly delist append
+1,3,0,1,-2,0,-1,2 mm drawpoly delist append
+-2,0,-3,0,-1,-2 mm drawpoly delist append
+-8,16,-12,16,-13,15,-12,12,-10,10,-9,8,-8,3,-6.5,4.5 mm drawpoly delist append
+-2,11,-2,10,-3,10,-2,11 mm drawpoly delist append
+1,11,1,10,2,10,1,11 mm drawpoly delist append

+ 13 - 0
kicommand/loadable/santaclause.txt

@@ -0,0 +1,13 @@
+2,12,2,13,3,14,5,15,5,13,2,12,0,11,-3,8,-4,10,-3,10,-4,13,-3,13,-2,15,-1,15,1,17,1,16,2,17,4,18,5,18,7,19,7,18,9,19,11,19,10,18,11,17,11,16,12,14,10,14,10,13,8,13,7,12,7,9,9,9,9,10,8,11,7,11 mm drawpoly
+-1,10,0,8,-2,7,-2,4,-1,3,1,5,3,6,4,6,5,5,6,6,7,5,8,5,10,6,10,7,9,8,7,9 mm drawpoly
+9,19,7,21,4,22,-4,20,-7,18,-8,15,-8,13,-7,11 mm drawpoly
+10,7,11,8,12,7,13,7,14,9 mm drawpoly
+10,14,8,15,7,15,7,14,5,13 mm drawpoly
+7,14,9,13,10,12,9,9 mm drawpoly
+10,13,11,11,13,10,15,8,18,6,19,2,18,-1,18,-3,16,-7,12,-12,9,-12,5,-11,2,-10,-1,-8,-4,-7,-6,-3,-7,-2,-9,-2,-10,-3,-11,-5,-11,-6,-10,-7,-8,-8,-6,-7,-5,-5 mm drawpoly
+15,8,15,5,14,4,10,2,8,0,7,0,6,1,4,1,2,0,-1,1,-3,3 mm drawpoly
+-3,8,-3,3,-6,-3 mm drawpoly
+-8,13,-10,8,-10,5,-8,0,-8,-2 mm drawpoly
+5,8,6,11,5,12,4,12,3,11,3,8,5,8,5,9,4,10,3,10 mm drawpoly
+6,1,9,4,8,3,10,2 mm drawpoly
+"Andtofinish…​Drawlargedotsat(4,9)and(8,10)​​​" pop

File diff suppressed because it is too large
+ 2 - 0
kicommand/loadable/switzerland.txt


+ 1 - 0
kicommand/test/__init__.py

@@ -0,0 +1 @@
+from test import *

+ 121 - 0
kicommand/test/test.py

@@ -0,0 +1,121 @@
+#import unittest
+import kicommand 
+#.run as kc
+import platform
+import sys
+import pcbnew
+
+if platform.python_version() < '2.7':
+    unittest = __import__('unittest2')
+else:
+    import unittest
+
+if True:#__name__ == '__main__':
+    testsuite = unittest.TestLoader().discover('kicommand.test',pattern="test_*.py")
+    results = unittest.TextTestRunner(verbosity=100).run(testsuite)
+
+    # Return an error code if any of the testsuite tests fail
+    # if not results.wasSuccessful():
+        # sys.exit(1)
+
+class TestKiCommand(unittest.TestCase):
+    def test_load(self):
+        pcommands = ['moduletextobj', 'wxpoint', 'outlinetoptext', 'setselect', 'referencetextobj', 'outlinepads', 'valuetextobj', 'drawparams', 'textfromobj', 'referencetext', 'toptextobj', 'outlinetext', 'clearallselected', 'not', 'orthogonal', 'copy', 'clearselect', 'texttosegments', 'valuetext']
+        self.assertTrue(set(pcommands) <= set(kicommand.kicommand._dictionary['persist'].keys()))
+        self.assertFalse(set(['thiscommand doesnt exist']) < set(kicommand.kicommand._dictionary['persist'].keys()))
+
+    def test_mils_mil_mm(self):
+        result = kicommand.run('10 mm')
+        self.assertEqual(result,10*pcbnew.IU_PER_MM)
+        result = kicommand.run('10 mils')
+        self.assertEqual(result,10*pcbnew.IU_PER_MILS)
+        result = kicommand.run('10 mil')
+        self.assertEqual(result,10*pcbnew.IU_PER_MILS)
+        
+    
+    def test_drawsegments(self):
+        result = kicommand.run('clear 0,0,1,1 mm drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0]),1)
+        # Test single list of list of numbers:
+        result = kicommand.run('delist remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        result = kicommand.run('clear 0,0,1,1 mm list drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),1)
+        result = kicommand.run('delist remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        # Test single list of numbers:
+        result = kicommand.run('clear 0,0,1,1,2,2,3,3 mm list drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),3)
+        result = kicommand.run('delist remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        # Test two lists of numbers:
+        result = kicommand.run('clear 0,0,1,1 mm list 2,2,3,3 mm list append drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),1)
+        self.assertEqual(len(result[0][1]),1)
+        result = kicommand.run('copy 1 index remove 0 index remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        result = kicommand.run('clear 0,0,1000000,1000000 ,2000000,2000000,3000000,3000000 append drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),3)
+        result = kicommand.run('delist remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        result = kicommand.run('clear 0,0,1000000,1000000,2000000,2000000,3000000,3000000 drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),3)
+        result = kicommand.run('delist remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        result = kicommand.run('clear 0,0,1000000,1000000 list 2000000,2000000,3000000,3000000 list append drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),1)
+        self.assertEqual(len(result[0][1]),1)
+        result = kicommand.run('copy 1 index remove 0 index remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        result = kicommand.run('clear 0,0 mm wxpoint 1,1 mm wxpoint append 2,2 mm wxpoint append 3,3 mm wxpoint append drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),3)
+        result = kicommand.run('delist remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+        result = kicommand.run('clear 0,0 mm wxpoint 1,1 mm wxpoint append list 2,2 mm wxpoint 3,3 mm wxpoint append list append drawpoly',returnval=-1)
+        self.assertEqual(len(result),1)
+        self.assertEqual(len(result[0][0]),1)
+        self.assertEqual(len(result[0][1]),1)
+        result = kicommand.run('copy 1 index remove 0 index remove',returnval=-1)
+        self.assertEqual(result,[])
+        
+    def test_help_helpcat_explain_see_seeall(self):
+        result = kicommand.run("help All helpcat 'help explain seeall 'bool see",returnval=-1)
+        self.assertEqual(result,[])
+        
+    def test_coverage(self):
+        prefix = 'test_'
+        fulltestnames = filter(lambda x: x.startswith(prefix),dir(self))
+        testnames = set()
+        #testnames = set(map(lambda x:  x[len(prefix):],fulltestnames))
+        set(map(lambda x: testnames.update(x.split('_')),fulltestnames))
+        
+        untested = set(kicommand.kicommand._dictionary['command'].keys()) - testnames
+        print 'untested',untested
+        self.assertEqual(True,True)
+
+            
+#unittest.main()
+
+# The following lines enable testing from pcbnew Script Console
+# just "import kicommand_test" and you can view the output in the
+# Script Console window.
+suite = unittest.TestLoader().loadTestsFromTestCase(TestKiCommand)
+unittest.TextTestRunner(verbosity=2).run(suite)
+
+# from kicommand_test import test_001_pcb_kicad

+ 17 - 0
kicommand/test/test_000_qa_works.py

@@ -0,0 +1,17 @@
+import unittest
+
+class TestQAWorks(unittest.TestCase):
+
+    def setUp(self):
+        self.pcb = None
+
+    def test_assert_true( self ):
+        self.assertTrue( True )
+
+    def test_assert_equal( self ):
+        self.assertEqual(2, 1+1)
+
+
+if __name__ == '__main__':
+    unittest.main()
+   

File diff suppressed because it is too large
+ 70 - 0
kicommand/test/test_001_pcb_load.py


+ 197 - 0
kicommand/test/test_002_board_class.py

@@ -0,0 +1,197 @@
+import code
+import unittest
+import os
+import pcbnew
+import pdb
+import tempfile
+from kicommand import run as kc
+
+
+from pcbnew import *
+
+
+BACK_COPPER = 'Back_Copper'
+B_CU = 'B.Cu'
+NEW_NAME = 'My_Fancy_Layer_Name'
+KICAD_INSTALL = r'C:\Program Files\KiCad'
+
+class TestBoardClass(unittest.TestCase):
+
+    def setUp(self):
+        file = os.path.join(KICAD_INSTALL,r'share\kicad\demos\complex_hierarchy\complex_hierarchy.kicad_pcb')
+        self.pcb = kc(
+            'clear pcbnew list "%s" list list LoadBoard callargs '
+            'delist Board spush board'%file)
+        #self.pcb = LoadBoard("data/complex_hierarchy.kicad_pcb")
+        self.TITLE="Test Board"
+        self.COMMENT1="For load/save test"
+        self.FILENAME=tempfile.mktemp()+".kicad_pcb"
+
+    def test_pcb_find_module(self):
+        reference = kc('board list P1 list list FindModule callargs GetReference call delist')
+        self.assertEqual(reference,'P1')
+        # module = self.pcb.FindModule('P1')
+        # self.assertEqual(module.GetReference(),'P1')
+
+    def test_pcb_get_track_count(self):
+    # :persist newboard "Elements Create a new empty board and make it the current board." pcbnew list BOARD call delist Board spush ;
+    # : newtrack "Elements Create bare, undefined track on current board" pcbnew list board list list TRACK callargs board list swap list Add callargs ;
+    
+        # new board
+        pcb = kc('clear pcbnew list BOARD call delist Board spush board')
+
+        num = kc('list GetNumSegmTrack call delist')
+        self.assertEqual(num,0)
+        
+        # Creates a new track
+        kc('clear pcbnew list board list list TRACK callargs')
+        
+        # Adds track to Board
+        kc('Board scopy list swap list Add callargs')
+        
+        # Obtain the number of tracks on this board 
+        num = kc('board list GetNumSegmTrack call delist')
+        self.assertEqual(num,1)
+
+        #kc(':persist newadd "Elements [TYPE PARENT] Add create a element of TYPE (TRACK, PAD) and add it to the PARENT." pcbnew list swap board list list swap stack')
+        # Creates a new track
+        # Adds track to Board
+        kc('clear pcbnew list board list list TRACK callargs')
+        kc('board list swap list Add callargs')
+        num = kc('board list GetNumSegmTrack call delist')
+        self.assertEqual(num,2)
+
+        # pcb = BOARD()
+
+        # self.assertEqual(pcb.GetNumSegmTrack(),0)
+
+        # track0 = TRACK(pcb)
+        # pcb.Add(track0)
+        # self.assertEqual(pcb.GetNumSegmTrack(),1)
+
+        # track1 = TRACK(pcb)
+        # pcb.Add(track1)
+        # self.assertEqual(pcb.GetNumSegmTrack(),2)
+
+    def test_pcb_bounding_box(self):
+        kc(':persist newboard "Elements Create a new empty board and make it the current board." pcbnew list BOARD call delist Board spush ;')
+        pcb = kc('clear newboard board')
+        track = kc('clear 0.5 mm t param F.Cu l param 10,10,20,30 mm '
+                        'drawpoly delist delist')
+        wval, hval = kc('list GetClearance call '
+                        'copy append copy 30,-10,0.5 mm append sum swap '
+                        '20,-10,0.5 mm append sum',returnval=-1)
+                        
+        #             float is because integer doesn't compare to float in assertAlmostEqual----+
+        #             ilist is to create a list from the wxRect---------------------------+     |         
+        #             copy is to keep bb reference in memory----------v                   v     v
+        height, width = kc('board list ComputeBoundingBox call GetSize call delist ilist float')
+        
+        #height, width = bounding_box.GetSize()
+        self.assertAlmostEqual(ToMM(height), ToMM(hval), 2)
+        self.assertAlmostEqual(ToMM(width ), ToMM(wval), 2)
+
+        # pcb = BOARD()
+        # track = TRACK(pcb)
+        # pcb.Add(track)
+
+        # track.SetStartEnd(wxPointMM(10.0, 10.0),
+                         # wxPointMM(20.0, 30.0))
+        
+        # track.SetStart(wxPointMM(10.0, 10.0))
+        # track.SetEnd  (wxPointMM(20.0, 30.0))
+
+        # track.SetWidth(FromMM(0.5))
+
+        #!!! THIS FAILS? == 0.0 x 0.0 ??
+        height, width = ToMM(pcb.ComputeBoundingBox().GetSize())
+        # bounding_box = pcb.ComputeBoundingBox()
+        # height, width = ToMM(bounding_box.GetSize())
+
+        clearance = ToMM(track.GetClearance()*2)
+        self.assertAlmostEqual(width,  (30-10) + 0.5 + clearance, 2)
+        self.assertAlmostEqual(height, (20-10) + 0.5 + clearance, 2)
+
+    def test_pcb_get_pad(self):
+        pcb = kc('newboard board')
+        # pcb = BOARD()
+        module = kc('MODULE swap newadd')
+        #MODULE board list copy pcbnew list swap list 3 pick callargs 1 pick 1 pick list Add callargs pop swap pop swap pop delist
+        # module = MODULE(pcb)
+        # pcb.Add(module)
+        pad = kc('D_PAD swap newadd') 
+        
+        #pad = D_PAD(module)
+        #kc('list list Add callargs pop pop')
+        #module.Add(pad)
+# newboard board MODULE swap newadd delist D_PAD swap newadd delist
+        try:
+            pad.SetShape(PAD_SHAPE_OVAL) # 5.x nightly
+        except:
+            pad.SetShape(PAD_OVAL) # 4.0.7
+        pad.SetSize(wxSizeMM(2.0, 3.0))
+        pad.SetPosition(wxPointMM(0,0))
+        
+        # easy case
+        p1 = pcb.GetPad(wxPointMM(0,0))
+
+        # top side
+        p2 = pcb.GetPad(wxPointMM(0.9,0.0))
+
+        # bottom side
+        p3 = pcb.GetPad(wxPointMM(0,1.4))
+
+        # TODO: get pad == p1 evaluated as true instead
+        #       of relying in the internal C++ object pointer
+        self.assertEqual(pad.this, p1.this)
+        self.assertEqual(pad.this, p2.this)
+        self.assertEqual(pad.this, p3.this)
+
+    def test_pcb_save_and_load(self):
+        pcb = BOARD()
+        pcb.GetTitleBlock().SetTitle(self.TITLE)
+        pcb.GetTitleBlock().SetComment1(self.COMMENT1)
+        result = SaveBoard(self.FILENAME,pcb)
+        self.assertTrue(result)
+        
+        pcb2 = LoadBoard(self.FILENAME)
+        self.assertNotEqual(pcb2,None)
+
+        tb = pcb2.GetTitleBlock()
+        self.assertEqual(tb.GetTitle(),self.TITLE)
+        self.assertEqual(tb.GetComment1(),self.COMMENT1)
+
+        os.remove(self.FILENAME)
+
+    def test_pcb_layer_name_set_get(self):
+        pcb = kc('newboard board list 31 int list %s list append list SetLayerName callargs board'%BACK_COPPER)
+        # pcb = BOARD()
+        # pcb.SetLayerName(31, BACK_COPPER)
+        self.assertEqual(pcb.GetLayerName(31), BACK_COPPER)
+
+    def test_pcb_layer_name_set_get2(self):
+        pcb = BOARD()
+        pcb.SetLayerName(31, BACK_COPPER)
+        self.assertEqual(pcb.GetLayerName(31), BACK_COPPER)
+
+    def test_pcb_layer_id_get(self):
+        # pcb = BOARD()
+        pcb = kc('newboard board')
+        b_cu_id = kc('%s layernums delist'%B_CU)
+
+        #b_cu_id = pcb.GetLayerID(B_CU)
+        #pcb.SetLayerName(b_cu_id, NEW_NAME)
+        kc('%d,%s'%(b_cu_id,NEW_NAME))
+        kc('board list swap int list SetLayerName callargs pop')
+
+        # ensure we can get the ID for the new name
+        self.assertEqual(pcb.GetLayerID(NEW_NAME), b_cu_id)
+
+        # ensure we can get to the ID via the STD name too
+        self.assertEqual(pcb.GetLayerID(B_CU), b_cu_id)
+
+    #def test_interactive(self):
+    # 	code.interact(local=locals())
+
+if __name__ == '__main__':
+    unittest.main()

+ 279 - 0
kicommand/wxpointutil.py

@@ -0,0 +1,279 @@
+import math
+import pcbnew
+    
+class wxPointUtil:
+    """A variety of utilities and geometric calculations for
+       operating on wxPoint objects. Will work on other objects with
+       x,y attributes"""
+       
+    atts=('x','y','z')
+    d=[]
+    # 
+    # Possible functions to implement for point class: 
+    # __add__(), __radd__(), __iadd__(), __mul__(), __rmul__() and __imul__()
+    # 
+        
+    @staticmethod
+    def dot_other(v,w):
+        return v[0]*w[1] - v[1]*w[0]	
+    @staticmethod
+    def dot(v,w):
+        """return the dot product of point and w"""
+        return v[0]*w[0] - v[1]*w[1]	
+    @staticmethod
+    def distance2(v,w):
+        """return the distance squared between point and w"""
+        #sub=w-v
+        wvx = w[0] - v[0]
+        wvy = w[1] - v[1]
+        return wvx*wvx+wvy*wvy #abs(wxPointUtil.dot(sub,sub))
+    @staticmethod
+    def distance(v,w):
+        """return the distance between point and w"""
+        p = v - w
+        return (p[0]*p[0]+p[1]*p[1])**(1/2.0)
+        
+    # Vector functions
+    @staticmethod
+    def scale(w,factor):
+        """ scale (multiply) the point x and y by a specific factor"""
+        # self[0] *= factor
+        # self[1] *= factor
+        return w.__class__(float(w[0])*factor,float(w[1])*factor)
+    
+    @staticmethod
+    def mag(w):
+        return math.sqrt(w[0]*w[0]+w[1]*w[1])
+        
+    # @staticmethod
+    # def unit(w):
+        # """return unit vector in same angle as w"""
+        # return wxPointUtil.scale(w,1/wxPointUtil.mag(w))
+        
+    @staticmethod
+    def rotatexy(w,radians):
+        """rotates an x,y vector by a radians"""
+        s=math.sin(radians)
+        c=math.cos(radians)
+        return w.__class__(w[0]*c - w[1]*s, w[0]*s + w[1]*c)
+        
+    @staticmethod
+    def topolar(w):
+        """returns polar coordinates in radians"""
+        return sqrt(math.pow(w[0],2),math.pow(w[1],2)), math.atan(w[1]/w[0])
+        
+    @staticmethod
+    def toxy(r,theta):
+        return r*math.cos(theta),r*math.sin(theta)
+
+    @staticmethod
+    def towxPoint(r,theta):
+        return pcbnew.wxPoint(r*math.cos(theta),r*math.sin(theta))
+    
+    @staticmethod
+    def projection_axis(v, axis):
+        """Project the point onto axis specified by w.
+           w must be a vector on the unit circle (for example: (1,0) or (0,1)
+           to project on the x axis or y axis, respectively)"""
+           
+        # Consider the line extending the segment,
+        # parameterized as v + t (w - v).
+        # We find projection of point p onto the line. 
+        # It falls where t = [(p-v) . (w-v)] / |w-v|^2
+        t = wxPointUtil.dot(v,axis);
+        return t
+        
+    # v,w are points defining the line segment
+    @staticmethod
+    def projection_line(p, v, w):
+        """project point onto the line segment v,w"""
+        # Return minimum distance between line segment vw and point p
+        # Consider the line extending the segment,
+        # parameterized as v + t (w - v).
+        # We find projection of point p onto the line. 
+        # It falls where t = [(p-v) . (w-v)] / |w-v|^2
+        # We clamp t from [0,1] to handle points outside the segment vw.
+        # if w[0] == v[0] and w[1] == v[1]:
+            # return self.distance(w);   # v == w case
+
+        #print "divisor=",w.distance(v)
+        wv=w-v
+        wvx = w[0] - v[0]
+        wvy = w[1] - v[1]
+        pvx = p[0] - v[0]
+        pvy = p[1] - v[1]
+        #t=0.5
+        t = max(0, min(1, abs(pvx*wvx+pvy*wvy) / float(wvx*wvx+wvy*wvy)));
+        #t = max(0, min(1, wxPointUtil.dot(p - v,wv) / float(wxPointUtil.distance2(w,v))));
+        projection = v + wxPointUtil.scale(wv,t);  # Projection falls on the segment
+        return projection
+    
+    @staticmethod
+    def normal(w):
+        return w.__class__(-w[1],w[0])
+        # or (w[1],-w[0])
+    def normal_old(v, w):
+        """NOT FINISHED
+           get normals of line formed with point w 
+           This is the left normal if w is clockwise of self 
+           This is the right normal if w is counter-clockwise of self"""
+        w[0] - v[0], 
+        w[1] - v[1]
+    
+    # var normals:Vector.<Vector2d> = new Vector.<Vector2d>
+    # for (var i:int = 1; i < dots.length-1; i++) 
+    # {
+        # var currentNormal:Vector2d = new Vector2d(
+            # dots[i + 1][0] - dots[i][0], 
+            # dots[i + 1][1] - dots[i][1]
+        # ).normL //left normals
+        # normals.push(currentNormal);
+    # }
+    # normals.push(
+        # new Vector2d(
+            # dots[1][0] - dots[dots.length-1][0], 
+            # dots[1][1] - dots[dots.length-1][1]
+        # ).normL
+    # )
+    # return normals;
+
+    @staticmethod
+    def mindistance2(u, v, w):
+        """Return minimum distance squared between point and line segment v,w.
+           Perhaps obviously, this is faster than mindistance because sqrt()
+           is not called."""
+        #L2 = wxPointUtil.distance2(v,w)
+        if w[0] == v[0] and w[1] == v[1]:
+        #if L2 == 0.0:
+            return wxPointUtil.distance2(u,w);   # v == w case
+        return wxPointUtil.distance2(u,wxPointUtil.projection_line(u,v,w))        
+        
+    @staticmethod
+    def mindistance(u, v, w):
+        """return minimum distance squared between point and line segment v,w"""
+        L2 = wxPointUtil.distance2(w,v)
+        #if w[0] == v[0] and w[1] == v[1]:
+        if L2 == 0.0:
+            return wxPointUtil.distance(u,w);   # v == w case
+        return wxPointUtil.distance(u,wxPointUtil.projection_line(u,v,w))
+        
+        # L2 = v.distance2(w);  # i.e. |w-v|^2 -  avoid a sqrt
+        # if (L2 == 0.0):
+            # return p.distance(w);   # v == w case
+        # return p.distance(self.projection_line(v,w));
+        
+        # p = self
+        # # Return minimum distance between line segment vw and point p
+        # L2 = self.distance2(v, w);  # i.e. |w-v|^2 -  avoid a sqrt
+        # if (L2 == 0.0):
+            # return p.distance(v);   # v == w case
+        # # Consider the line extending the segment,
+        # # parameterized as v + t (w - v).
+        # # We find projection of point p onto the line. 
+        # # It falls where t = [(p-v) . (w-v)] / |w-v|^2
+        # # We clamp t from [0,1] to handle points outside the segment vw.
+        # t = max(0, min(1, (p - v).dot(w - v) / float(L2)));
+        # # SavePrint = "L2 %d; t %.3f"%(L2,t)
+        
+        # #t = max(0, min(1, (v - p).dot(v - w) / float(L2)));
+        # projection = v + (w-v).scale(t);  # Projection falls on the segment
+        # return p.distance(projection);
+                
+    #https://stackoverflow.com/questions/2272179/a-simple-algorithm-for-polygon-intersection
+    # NB: The algorithm only works for convex polygons, specified in either clockwise, or counterclockwise order.
+
+    # 1)For each edge in both polygons, check if it can be used as a separating line. If so, you are done: No intersection.
+    # 2) If no separation line was found, you have an intersection
+
+    @staticmethod
+    def check_polygons_intersecting(poly_a, poly_b,closed=True):
+        """Returns boolean indicating whether the indicated polygons are intersecting.
+           closed=True indicates the last point is equal to the first point.
+           if closed=False, the first and last point are checked as if they represent
+           the last polygon edge."""
+        for polygon in (poly_a, poly_b):
+            #print "\nPolygon",
+
+            # This loop is assuming last point is not the repeated first point:
+            # for i1 in range(len(polygon)):
+                # i2 = (i1 + 1) % len(polygon)
+                
+            # This loop assumes the last point is the repeated first point to form closed polygon:
+            # for i1 in range(len(polygon)-1):
+                # i2 = (i1 + 1)
+                
+            # This loop combines both loops above:
+            for i1 in range(len(polygon)-1*closed):
+                i2 = (i1 + 1) % len(polygon)
+                
+                #print("i1={} i2={}".format(polygon[i1], i2))
+                p1 = polygon[i1]
+                p2 = polygon[i2]
+
+                normal_old = pcbnew.wxPoint(p2[1] - p1[1], p1[0] - p2[0])
+
+                minA, maxA, minB, maxB = (None,) * 4
+
+                for p in poly_a:
+                    projected = normal[0] * p[0] + normal[1] * p[1]
+
+                    if not minA or projected < minA:
+                        minA = projected
+                    if not maxA or projected > maxA:
+                        maxA = projected
+
+                for p in poly_b:
+                    projected = normal[0] * p[0] + normal[1] * p[1]
+
+                    if not minB or projected < minB:
+                        minB = projected
+                    if not maxB or projected > maxB:
+                        maxB = projected
+
+                #print("maxA={} minB={} -- maxB={} minA={}".format(maxA, minB, maxB, minA))
+                if maxA < minB or maxB < minA:
+                    return False
+                #print(" Nope\n")
+
+        return True
+        
+    # To find orientation of ordered triplet (p, q, r).
+    # The function returns following values
+    # 0 --> p, q and r are colinear
+    # 1 --> Clockwise
+    # 2 --> Counterclockwise
+    # sign = lambda x: x and (1, -1)[x < 0]
+    
+    # Get leftmost point
+    # i, value = min(enumerate(vector), key=attrgetter('x'))
+    # nextpoint = vector[(i+1)%len(vector)]
+    # @staticmethod
+    # def orientation(p, q, r)
+    # {
+        # int val = (q[1] - p[1]) * (r[0] - q[0]) -
+                  # (q[0] - p[0]) * (r[1] - q[1]);
+     
+        # if (val == 0) return 0;  // colinear
+        # return (val > 0)? 1: 2; // clock or counterclock wise
+    # }
+    
+    @staticmethod
+    def convex_hull(self,line,vector):
+        """NOT IMPLEMENTED.
+           Currently returns bounding box, best used on orthogonal.
+           Return the convex hull of point list vector
+           A fast algorithm using Jarvis's Algorithm (aka Wrapping)."""
+        minx = vector[0][0]
+        miny = vector[0][1]
+        maxx = minx
+        maxy = miny
+        for v in vector:
+            minx = min(minx,v[0])
+            maxx = max(minx,v[0])
+            miny = min(miny,v[1])
+            maxy = max(miny,v[1])           
+        return (
+            pcbnew.wxPoint(minx,maxy), # upper left
+            pcbnew.wxPoint(maxx,maxy), # upper right
+            pcbnew.wxPoint(maxx,miny), # lower right
+            pcbnew.wxPoint(minx,miny)) # lower left