From 75b08e49cf22c6a888608e4862beef51c3ee5ce2 Mon Sep 17 00:00:00 2001 From: Jean-Samuel Reynaud Date: Tue, 31 Jan 2017 18:38:03 +0100 Subject: [PATCH] Add 2 python action plugins in demos --- .../action_menu_add_automatic_border.py | 247 ++++++++++++++++++ .../action_menu_text_by_date.py | 59 +++++ 2 files changed, 306 insertions(+) create mode 100644 demos/python_scripts_examples/action_menu_add_automatic_border.py create mode 100644 demos/python_scripts_examples/action_menu_text_by_date.py diff --git a/demos/python_scripts_examples/action_menu_add_automatic_border.py b/demos/python_scripts_examples/action_menu_add_automatic_border.py new file mode 100644 index 0000000000..ad71c8ff67 --- /dev/null +++ b/demos/python_scripts_examples/action_menu_add_automatic_border.py @@ -0,0 +1,247 @@ +# add_automatic_border.py +# +# Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +# + +from pcbnew import * +import re +import datetime + + +class add_automatic_border( ActionPlugin ): + """ + add_automatic_border: An other sample plugin as an example of ActionPlugin + Build PCB edges to include all PCB elements + How to use: + - add all your modules/track/area/text... + - Call the plugin + - An including PCB edge will be created automaticaly + """ + + def defaults( self ): + """ + Method defaults must be redefined + self.name should be the menu label to use + self.category should be the category (not yet used) + self.description should be a comprehensive description + of the plugin + """ + self.name = "Add or update automatic PCB edges" + self.category = "Modify PCB" + self.description = "Automaticaly add or update edges on an existing PCB" + # Offset between existing elements and edge we will add/update (fixed at 2.54mm) + self.offset = FromMM( 2.54 ) + # Attach to a grid step (fixed at 2.54mm) + self.grid = FromMM( 2.54 ) + + def min( self, a, b ): + """ + Method min: Found min between a and b even is one is None + """ + if a is None: + return b + if b is None: + return a + if a < b: + return a + return b + + def max( self, a, b ): + """ + Method max: Found max between a and b even is one is None + """ + if a is None: + return b + if b is None: + return a + if a > b: + return a + return b + + def Run( self ): + """ + Method Run is called by Action menu + """ + pcb = GetBoard() + # Find including area on min/max x/y + min_x = None + max_x = None + min_y = None + max_y = None + + # Enum all area + for i in range( pcb.GetAreaCount() ): + min_x = self.min( min_x, pcb.GetArea( i ).GetBoundingBox().GetX() ) + min_y = self.min( min_y, pcb.GetArea( i ).GetBoundingBox().GetY() ) + max_x = self.max( max_x, \ + pcb.GetArea( i ).GetBoundingBox().GetX() \ + + pcb.GetArea( i ).GetBoundingBox().GetWidth() ) + max_y = self.max( max_y, \ + pcb.GetArea( i ).GetBoundingBox().GetY() \ + + pcb.GetArea( i ).GetBoundingBox().GetHeight() ) + + # Same with track + for track in pcb.GetTracks(): + min_x = self.min( min_x, track.GetStart().x ) + min_y = self.min( min_y, track.GetStart().y ) + max_x = self.max( max_x, track.GetEnd().x ) + max_y = self.max( max_y, track.GetEnd().y ) + + min_x = self.min( min_x, track.GetEnd().x ) + min_y = self.min( min_y, track.GetEnd().y ) + max_x = self.max( max_x, track.GetStart().x ) + max_y = self.max( max_y, track.GetStart().y ) + + # Variable to store PCB edges we found + west = None + north = None + east = None + south = None + + for draw in pcb.GetDrawings(): + edge_candidate = False + # Detect if current drawing is a PCB edge + # and a candicate for north/south/east or west + if draw.GetClass() == 'DRAWSEGMENT' \ + and draw.GetLayer() == Edge_Cuts: + # Try candicate for east/west ? + if draw.GetStart().x == draw.GetEnd().x: + if west is None and east is None: + west = draw + edge_candidate = True + elif west is None: # east is not none + if draw.GetStart().x < east.GetStart().x: + west = draw + edge_candidate = True + else: + west = east + east = draw + edge_candidate = True + elif east is None: # west is not none + if draw.GetStart().x > west.GetStart().x: + east = draw + edge_candidate = True + else: + east = west + west = draw + edge_candidate = True + else: + None # west and east are already found... + + # Try candicate for north/south ? + if draw.GetStart().y == draw.GetEnd().y: + if north is None and south is None: + north = draw + edge_candidate = True + elif north is None: # south is not none + if draw.GetStart().y < south.GetStart().y: + north = draw + edge_candidate = True + else: + north = south + south = draw + edge_candidate = True + elif south is None: # north is not none + if draw.GetStart().y > north.GetStart().y: + south = draw + edge_candidate = True + else: + south = north + north = draw + edge_candidate = True + else: + None # north and south are already found... + # Not a edge candidate: use it to find including edges + if not edge_candidate: + bbox = draw.GetBoundingBox() + min_x = self.min( min_x, bbox.GetX() ) + min_y = self.min( min_y, bbox.GetY() ) + max_x = self.max( max_x, bbox.GetX() + bbox.GetWidth() ) + max_y = self.max( max_y, bbox.GetY() + bbox.GetHeight() ) + + # Same with modules: Find including area + for module in pcb.GetModules(): + bbox = module.GetBoundingBox() + min_x = self.min( min_x, bbox.GetX() ) + min_y = self.min( min_y, bbox.GetY() ) + max_x = self.max( max_x, bbox.GetX() + bbox.GetWidth() ) + max_y = self.max( max_y, bbox.GetY() + bbox.GetHeight() ) + + # Add a space between including area and edge (3mm) + min_x = min_x - self.offset + min_y = min_y - self.offset + max_x = max_x + self.offset + max_y = max_y + self.offset + + # Fix on the defined grid + min_x = min_x - (min_x % self.grid) + min_y = min_y - (min_y % self.grid) + if ( max_x % self.grid ) != 0: + max_x = max_x - (max_x % self.grid) + self.grid + if ( max_y % self.grid ) != 0: + max_y = max_y - (max_y % self.grid) + self.grid + + # Add or update all edges + need_add = False + if west is None: + need_add = True + west = DRAWSEGMENT() + west.SetLayer( Edge_Cuts ) + + west.SetStart( wxPoint( min_x, min_y ) ) + west.SetEnd( wxPoint( min_x, max_y ) ) + if need_add: + pcb.Add( west ) + + need_add = False + if north is None: + need_add = True + north = DRAWSEGMENT() + north.SetLayer( Edge_Cuts ) + + north.SetStart( wxPoint( min_x, min_y ) ) + north.SetEnd( wxPoint( max_x, min_y ) ) + if need_add: + pcb.Add( north ) + + need_add = False + if east is None: + need_add = True + east = DRAWSEGMENT() + east.SetLayer( Edge_Cuts ) + + east.SetStart( wxPoint( max_x, min_y ) ) + east.SetEnd( wxPoint( max_x, max_y ) ) + if need_add: + pcb.Add( east ) + + need_add = False + if south is None: + need_add = True + south = DRAWSEGMENT() + south.SetLayer( Edge_Cuts ) + + south.SetStart( wxPoint( min_x, max_y ) ) + south.SetEnd( wxPoint( max_x, max_y ) ) + if need_add: + pcb.Add( south ) + + +# Register the action +add_automatic_border().register() diff --git a/demos/python_scripts_examples/action_menu_text_by_date.py b/demos/python_scripts_examples/action_menu_text_by_date.py new file mode 100644 index 0000000000..6e96530211 --- /dev/null +++ b/demos/python_scripts_examples/action_menu_text_by_date.py @@ -0,0 +1,59 @@ +# text_by_date.py +# +# Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +# + +import pcbnew +import re +import datetime + + +class text_by_date( pcbnew.ActionPlugin ): + """ + test_by_date: A sample plugin as an example of ActionPlugin + Add the date to any text field of the board where the content is '$date$' + How to use: + - Add a text on your board with the content '$date$' + - Call the plugin + - Automaticaly the date will be added to the text (format YYYY-MM-DD) + """ + + def defaults( self ): + """ + Method defaults must be redefined + self.name should be the menu label to use + self.category should be the category (not yet used) + self.description should be a comprehensive description + of the plugin + """ + self.name = "Add date on PCB" + self.category = "Modify PCB" + self.description = "Automaticaly add date on an existing PCB" + + def Run( self ): + pcb = pcbnew.GetBoard() + for draw in pcb.m_Drawings: + if draw.GetClass() == 'PTEXT': + txt = re.sub( "\$date\$ [0-9]{4}-[0-9]{2}-[0-9]{2}", + "$date$", draw.GetText() ) + if txt == "$date$": + draw.SetText( "$date$ %s"%datetime.date.today() ) + + +text_by_date().register()