Merge ~ross-schlaikjer/kicad:footprint-keepouts into ~kicad-product-committers/kicad:master

Proposed by Ross Schlaikjer
Status: Merged
Merge reported by: jean-pierre charras
Merged at revision: 97a18d2f2ba8f0ba6d58557a7c2f6ae9b94ac6a3
Proposed branch: ~ross-schlaikjer/kicad:footprint-keepouts
Merge into: ~kicad-product-committers/kicad:master
Diff against target: 854 lines (+302/-62)
23 files modified
include/base_struct.h (+19/-0)
include/commit.h (+3/-3)
pcbnew/board_commit.cpp (+24/-0)
pcbnew/board_commit.h (+4/-0)
pcbnew/board_item_container.h (+21/-0)
pcbnew/class_board.cpp (+23/-0)
pcbnew/class_board.h (+6/-4)
pcbnew/class_module.cpp (+80/-0)
pcbnew/class_module.h (+11/-3)
pcbnew/class_zone.cpp (+5/-5)
pcbnew/class_zone.h (+1/-1)
pcbnew/collectors.cpp (+4/-13)
pcbnew/footprint_editor_utils.cpp (+32/-0)
pcbnew/kicad_plugin.cpp (+4/-0)
pcbnew/kicad_plugin.h (+2/-1)
pcbnew/menubar_footprint_editor.cpp (+7/-6)
pcbnew/pcb_parser.cpp (+18/-8)
pcbnew/pcb_parser.h (+2/-1)
pcbnew/toolbars_footprint_editor.cpp (+13/-11)
pcbnew/tools/drc.cpp (+4/-2)
pcbnew/tools/selection_tool.cpp (+15/-0)
pcbnew/tools/zone_create_helper.cpp (+3/-2)
pcbnew/zone_filler.cpp (+1/-2)
Reviewer Review Type Date Requested Status
Seth Hillbrand Approve
Review via email: mp+361410@code.launchpad.net

Commit message

This changeset adds support for specifying keep-out zones inside of footprints.

It is based off of the incomplete changeset by Oliver Walters, which was pulled from his exchange from Jean-Pierre Charras here: https://lists.launchpad.net/kicad-developers/msg31280.html

This does necessitate a version bump for the module format in order to allow zones to be present.

Description of the change

The following features have been added:

- Keepout zones can now be defined in the footprint editor, and can be applied to any combination of copper layers.
- DRC respects keepout zones defined in footprints
- Keepouts defined in footprints are taken into account when generating copper pours.

I am fairly confident in the functionality of this changeset, but would appreciate a review from someone more familiar with the KiCad codebase to ensure it follows the current best practices.

To post a comment you must log in.
Revision history for this message
Wayne Stambaugh (stambaughw) wrote :

We are in feature freeze for 5.1 so no new changes are permitted until v6 opens for development. Once 5.1 is released, we can review and consider merging this merge request.

Revision history for this message
Seth Hillbrand (sethh) wrote :

@Ross-

Could you rebase your changeset to the current master so that we can review this now that v6 is open for development?

A couple changes I see needed:
- Please use the DECL_DEQ_FOR_SWIG instead of the dlist
- Instead of hotkey definition, please use the hotkey actions
- Code formatting (use tools/check_coding.sh)

Revision history for this message
Jeff Young (jeyjey) wrote :

@Ross, I've got some time to help out with this. If you could rebase on the current master and incorporate the comments that would be great. If you have any questions (or don't have time to do it) let me know.

(Probably better to use the developer's email list than do it here, as I'm more likely to see it there.)

97a18d2... by Ross Schlaikjer

Add keepout zones in footprints

This changeset allows the creation of keepout zones in footprints.
This necessitates a change to the pcbnew file format version.

Revision history for this message
Ross Schlaikjer (ross-schlaikjer) wrote :

@Jeff,

Thanks for the review. I've finally had enough time to go through and rebuild this PR against current master. If you wouldn't mind taking another look that would be great. I've applied for membership to the developer's email list, so if that comes through we can move the conversation there if that's easier for you.

@Seth,

About the code formatting - if I go through and run clang-format on the changed files, there are a large number of collateral changes - is this acceptable? Or should I go through, clang-format, and then only add the changes to code I have already changed?

Thanks.

Revision history for this message
Seth Hillbrand (sethh) wrote :

@Ross-

The collateral (I assume that this is re-ordering headers) is fine. This reflects our long-term plan but we haven't gone through all files specifically to do this, so it comes up as we edit.

Please squash these into a single commit for pushing to the main branch.

Thanks again!

Revision history for this message
Ross Schlaikjer (ross-schlaikjer) wrote :

Turns out that the extra changes I was seeing were due to me running a bare `clang-format` as opposed to a `git clang-format`, which gives a different result even with the same style file.

Changes have been formatted with `git clang-format master` and squashed.

Revision history for this message
Seth Hillbrand (sethh) wrote :

I gave this a run and it's basically ready. I attached a few minor comments to fix below.

The biggest issue I find is that once the footprint is placed in pcbnew, the keepout zone is not treated as part of the footprint. That is to say, it can be moved independently of the footprint and selecting it does not select the footprint itself. This should be compared with the polygon tool for reference to expected behavior.

Once that last issue is addressed, I think this is ready to merge, barring other dev comments. Nice work!

review: Needs Fixing
Revision history for this message
Ross Schlaikjer (ross-schlaikjer) wrote :

Hi Seth,

Thanks for the review. I've squashed your smaller review comments in, but I'm having trouble finding where the move tool handles the case where the item is part of a module - do you have any pointers on where to look in the codebase / what keywords to grep for?

Revision history for this message
Seth Hillbrand (sethh) wrote :

Hi Ross-

Sure thing! You are actually looking for where items get selected (not moved). The logic is that you cannot select just the _part_ of the footprint, you want to select the footprint object itself. As long as your footprint hittest includes the zone, you just need to exclude the zone from the possible selections. This is in SELECTION_TOOL::Selectable()

Revision history for this message
Ross Schlaikjer (ross-schlaikjer) wrote :

Seth,

Alright, finally had a chance to finish this up. Keepouts specified in footprints are now treated like polygons for selection and can't be independently modified on the PCB.
Thanks for your help.

Revision history for this message
Seth Hillbrand (sethh) wrote :

This looks good to me. Thanks Ross! Any objections to this patch?

review: Approve
Revision history for this message
Oliver (schrodingersgat) wrote :

Ross, I'm very excited that you have taken up the baton on this one!

Revision history for this message
Ian McInerney (imcinerney) wrote :
Revision history for this message
Ross Schlaikjer (ross-schlaikjer) wrote :

And it looks like they fixed some bugs / missing functionality as well. Apologies for not being able to get to those in time! I very much appreciate the hard work, thank you all for helping to get this feature added.

Revision history for this message
Wayne Stambaugh (stambaughw) wrote :

@JP, did you intend to merge this? The status wasn't set to approved yet so I'm curious if you did some more testing to confirm if there are any other issues. I trust your judgement but the merge just came as a bit of a surprise. If everything is good to go, please set the status of the merge request to merged so it gets closed out. Thanks.

Revision history for this message
jean-pierre charras (jp-charras) wrote :

@Wayne, I merged this a few time ago, with a *lot* of fixes and added missing features.

I forgot to set the status to merged.
I just updated it now.

Revision history for this message
Wayne Stambaugh (stambaughw) wrote :

@JP, thanks for fixing and merging this and thank you @Ross for you contribution to KiCad. This knocks out one of the road map tasks for V6!

Revision history for this message
Ian McInerney (imcinerney) wrote :

Does this fully close out the associated wishlist item [1] for this?

[1] https://bugs.launchpad.net/kicad/+bug/1081846

Revision history for this message
Wayne Stambaugh (stambaughw) wrote :

I think the status of lp:1081846 can be changed to "Fix Committed".

Revision history for this message
Ian McInerney (imcinerney) wrote :

Sounds good. I just switched it over to "Fix Committed".

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/include/base_struct.h b/include/base_struct.h
2index e0c6db6..bf60b05 100644
3--- a/include/base_struct.h
4+++ b/include/base_struct.h
5@@ -451,6 +451,25 @@ public:
6 }
7
8 /**
9+ * @copydoc SEARCH_RESULT IterateForward( EDA_ITEM*, INSPECTOR, void*, const KICAD_T )
10+ *
11+ * This changes first parameter to avoid the DList and use std::vector instead
12+ */
13+ template <class T>
14+ static SEARCH_RESULT IterateForward(
15+ std::vector<T>& aList, INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
16+ {
17+ for( auto it : aList )
18+ {
19+ if( static_cast<EDA_ITEM*>( it )->Visit( inspector, testData, scanTypes )
20+ == SEARCH_QUIT )
21+ return SEARCH_QUIT;
22+ }
23+
24+ return SEARCH_CONTINUE;
25+ }
26+
27+ /**
28 * Function GetClass
29 * returns the class name.
30 * @return wxString
31diff --git a/include/commit.h b/include/commit.h
32index 9498a51..5b8927e 100644
33--- a/include/commit.h
34+++ b/include/commit.h
35@@ -123,11 +123,11 @@ public:
36
37
38 ///> Adds a change of the item aItem of type aChangeType to the change list.
39- COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType );
40+ virtual COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType );
41
42- COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType );
43+ virtual COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType );
44
45- COMMIT& Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO_T aModFlag = UR_UNSPECIFIED );
46+ virtual COMMIT& Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO_T aModFlag = UR_UNSPECIFIED );
47
48 ///> Executes the changes.
49 virtual void Push( const wxString& aMessage = wxT( "A commit" ),
50diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp
51index 82ba02a..ed09984 100644
52--- a/pcbnew/board_commit.cpp
53+++ b/pcbnew/board_commit.cpp
54@@ -56,6 +56,30 @@ BOARD_COMMIT::~BOARD_COMMIT()
55 {
56 }
57
58+COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType )
59+{
60+ // if aItem belongs a footprint, the full footprint will be saved
61+ // because undo/redo does not handle "sub items" modifications
62+ if( aItem && aItem->Type() != PCB_MODULE_T && aChangeType == CHT_MODIFY )
63+ {
64+ EDA_ITEM* item = aItem->GetParent();
65+
66+ if( item && item->Type() == PCB_MODULE_T ) // means aItem belongs a footprint
67+ aItem = item;
68+ }
69+
70+ return COMMIT::Stage( aItem, aChangeType );
71+}
72+
73+COMMIT& BOARD_COMMIT::Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType )
74+{
75+ return COMMIT::Stage( container, aChangeType );
76+}
77+
78+COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO_T aModFlag )
79+{
80+ return COMMIT::Stage( aItems, aModFlag );
81+}
82
83 void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool aSetDirtyBit )
84 {
85diff --git a/pcbnew/board_commit.h b/pcbnew/board_commit.h
86index 45fe90b..1f90b5c 100644
87--- a/pcbnew/board_commit.h
88+++ b/pcbnew/board_commit.h
89@@ -46,6 +46,10 @@ public:
90 bool aCreateUndoEntry = true, bool aSetDirtyBit = true ) override;
91
92 virtual void Revert() override;
93+ COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType ) override;
94+ COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType ) override;
95+ COMMIT& Stage(
96+ const PICKED_ITEMS_LIST& aItems, UNDO_REDO_T aModFlag = UR_UNSPECIFIED ) override;
97
98 private:
99 TOOL_MANAGER* m_toolMgr;
100diff --git a/pcbnew/board_item_container.h b/pcbnew/board_item_container.h
101index aa967b0..0d3869b 100644
102--- a/pcbnew/board_item_container.h
103+++ b/pcbnew/board_item_container.h
104@@ -28,6 +28,7 @@
105 #define BOARD_ITEM_CONTAINER_H
106
107 #include <class_board_item.h>
108+#include <zone_settings.h>
109
110 enum ADD_MODE { ADD_INSERT, ADD_APPEND };
111
112@@ -63,6 +64,26 @@ public:
113 Remove( aItem );
114 delete aItem;
115 }
116+
117+ /**
118+ * @brief Fetch the zone settings for this container
119+ */
120+ const ZONE_SETTINGS& GetZoneSettings() const
121+ {
122+ return m_zoneSettings;
123+ }
124+
125+ /**
126+ * @brief Set the zone settings for this container
127+ * @param aSettings new Zone settings for this container
128+ */
129+ void SetZoneSettings( const ZONE_SETTINGS& aSettings )
130+ {
131+ m_zoneSettings = aSettings;
132+ }
133+
134+private:
135+ ZONE_SETTINGS m_zoneSettings;
136 };
137
138 #endif /* BOARD_ITEM_CONTAINER_H */
139diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp
140index 26d4b3d..2ce34c8 100644
141--- a/pcbnew/class_board.cpp
142+++ b/pcbnew/class_board.cpp
143@@ -1519,6 +1519,29 @@ MODULE* BOARD::GetFootprint( const wxPoint& aPosition, PCB_LAYER_ID aActiveLayer
144 return NULL;
145 }
146
147+std::list<ZONE_CONTAINER*> BOARD::GetZoneList( bool aIncludeZonesInFootprints )
148+{
149+ std::list<ZONE_CONTAINER*> zones;
150+
151+ for( int ii = 0; ii < GetAreaCount(); ii++ )
152+ {
153+ zones.push_back( GetArea( ii ) );
154+ }
155+
156+ if( aIncludeZonesInFootprints )
157+ {
158+ for( MODULE* mod : m_modules )
159+ {
160+ for( ZONE_CONTAINER* zone : mod->Zones() )
161+ {
162+ zones.push_back( zone );
163+ }
164+ }
165+ }
166+
167+ return zones;
168+}
169+
170
171 ZONE_CONTAINER* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode,
172 PCB_LAYER_ID aLayer, wxPoint aStartPointPosition, int aHatch )
173diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h
174index 25bc1f7..919bd18 100644
175--- a/pcbnew/class_board.h
176+++ b/pcbnew/class_board.h
177@@ -192,7 +192,6 @@ private:
178 std::shared_ptr<CONNECTIVITY_DATA> m_connectivity;
179
180 BOARD_DESIGN_SETTINGS m_designSettings;
181- ZONE_SETTINGS m_zoneSettings;
182 PCB_GENERAL_SETTINGS* m_generalSettings; ///< reference only; I have no ownership
183 PAGE_INFO m_paper;
184 TITLE_BLOCK m_titles; ///< text in lower right of screen and plots
185@@ -561,9 +560,6 @@ public:
186 TITLE_BLOCK& GetTitleBlock() { return m_titles; }
187 void SetTitleBlock( const TITLE_BLOCK& aTitleBlock ) { m_titles = aTitleBlock; }
188
189- const ZONE_SETTINGS& GetZoneSettings() const { return m_zoneSettings; }
190- void SetZoneSettings( const ZONE_SETTINGS& aSettings ) { m_zoneSettings = aSettings; }
191-
192 wxString GetSelectMenuText( EDA_UNITS_T aUnits ) const override;
193
194 /**
195@@ -949,6 +945,12 @@ public:
196 }
197
198 /**
199+ * Function GetZoneList
200+ * @return a std::list of pointers to all board zones (possibly including zones in footprints)
201+ */
202+ std::list<ZONE_CONTAINER*> GetZoneList( bool aIncludeZonesInFootprints = false );
203+
204+ /**
205 * Function GetAreaCount
206 * @return int - The number of Areas or ZONE_CONTAINER.
207 */
208diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp
209index 06ce251..416fc0d 100644
210--- a/pcbnew/class_module.cpp
211+++ b/pcbnew/class_module.cpp
212@@ -108,6 +108,10 @@ MODULE::MODULE( const MODULE& aModule ) :
213 Add( new D_PAD( *pad ) );
214 }
215
216+ // Copy auxiliary data: Zones
217+ for( auto item : aModule.Zones() )
218+ Add( static_cast<ZONE_CONTAINER*>( item->Clone() ) );
219+
220 // Copy auxiliary data: Drawings
221 for( auto item : aModule.GraphicalItems() )
222 {
223@@ -152,6 +156,11 @@ MODULE::~MODULE()
224
225 m_pads.clear();
226
227+ for( auto p : m_zones )
228+ delete p;
229+
230+ m_zones.clear();
231+
232 for( auto d : m_drawings )
233 delete d;
234
235@@ -197,6 +206,14 @@ MODULE& MODULE::operator=( const MODULE& aOther )
236 Add( new D_PAD( *pad ) );
237 }
238
239+ // Copy auxiliary data: Zones
240+ m_zones.clear();
241+
242+ for( auto item : aOther.Zones() )
243+ {
244+ Add( static_cast<ZONE_CONTAINER*>( item->Clone() ) );
245+ }
246+
247 // Copy auxiliary data: Drawings
248 m_drawings.clear();
249
250@@ -261,6 +278,13 @@ void MODULE::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
251 m_pads.push_front( static_cast<D_PAD*>( aBoardItem ) );
252 break;
253
254+ case PCB_ZONE_AREA_T:
255+ if( aMode == ADD_APPEND )
256+ m_zones.push_back( static_cast<ZONE_CONTAINER*>( aBoardItem ) );
257+ else
258+ m_zones.insert( m_zones.begin(), static_cast<ZONE_CONTAINER*>( aBoardItem ) );
259+ break;
260+
261 default:
262 {
263 wxString msg;
264@@ -313,6 +337,18 @@ void MODULE::Remove( BOARD_ITEM* aBoardItem )
265
266 break;
267
268+ case PCB_ZONE_AREA_T:
269+ for( auto it = m_zones.begin(); it != m_zones.end(); ++it )
270+ {
271+ if( *it == static_cast<ZONE_CONTAINER*>( aBoardItem ) )
272+ {
273+ m_zones.erase( it );
274+ break;
275+ }
276+ }
277+
278+ break;
279+
280 default:
281 {
282 wxString msg;
283@@ -329,6 +365,9 @@ void MODULE::Print( PCB_BASE_FRAME* aFrame, wxDC* aDC, const wxPoint& aOffset )
284 for( auto pad : m_pads )
285 pad->Print( aFrame, aDC, aOffset );
286
287+ for( auto zone : m_zones )
288+ zone->Print( aFrame, aDC, aOffset );
289+
290 BOARD* brd = GetBoard();
291
292 // Draw graphic items
293@@ -385,6 +424,9 @@ EDA_RECT MODULE::GetFootprintRect() const
294 for( auto pad : m_pads )
295 area.Merge( pad->GetBoundingBox() );
296
297+ for( auto zone : m_zones )
298+ area.Merge( zone->GetBoundingBox() );
299+
300 return area;
301 }
302
303@@ -590,6 +632,12 @@ bool MODULE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) co
304 return true;
305 }
306
307+ for( auto zone : m_zones )
308+ {
309+ if( zone->HitTest( arect, false, 0 ) )
310+ return true;
311+ }
312+
313 for( auto item : m_drawings )
314 {
315 if( item->HitTest( arect, false, 0 ) )
316@@ -742,6 +790,11 @@ SEARCH_RESULT MODULE::Visit( INSPECTOR inspector, void* testData, const KICAD_T
317 ++p;
318 break;
319
320+ case PCB_ZONE_AREA_T:
321+ result = IterateForward<ZONE_CONTAINER*>( m_zones, inspector, testData, p );
322+ ++p;
323+ break;
324+
325 case PCB_MODULE_TEXT_T:
326 result = inspector( m_Reference, testData );
327
328@@ -819,6 +872,9 @@ void MODULE::RunOnChildren( const std::function<void (BOARD_ITEM*)>& aFunction )
329 for( auto pad : m_pads )
330 aFunction( static_cast<BOARD_ITEM*>( pad ) );
331
332+ for( auto zone : m_zones )
333+ aFunction( static_cast<ZONE_CONTAINER*>( zone ) );
334+
335 for( auto drawing : m_drawings )
336 aFunction( static_cast<BOARD_ITEM*>( drawing ) );
337
338@@ -1023,6 +1079,10 @@ void MODULE::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
339 for( auto pad : m_pads )
340 pad->Flip( m_Pos, false );
341
342+ // Mirror zones to other side of board.
343+ for( auto zone : m_zones )
344+ zone->Flip( m_Pos, aFlipLeftRight );
345+
346 // Mirror reference and value.
347 m_Reference->Flip( m_Pos, false );
348 m_Value->Flip( m_Pos, false );
349@@ -1068,6 +1128,9 @@ void MODULE::SetPosition( const wxPoint& newpos )
350 pad->SetPosition( pad->GetPosition() + delta );
351 }
352
353+ for( auto zone : m_zones )
354+ zone->Move( delta );
355+
356 for( auto item : m_drawings )
357 {
358 switch( item->Type() )
359@@ -1167,6 +1230,11 @@ void MODULE::SetOrientation( double newangle )
360 pad->SetDrawCoord();
361 }
362
363+ for( auto zone : m_zones )
364+ {
365+ zone->Rotate( GetPosition(), angleChange );
366+ }
367+
368 // Update of the reference and value.
369 m_Reference->SetDrawCoord();
370 m_Value->SetDrawCoord();
371@@ -1193,6 +1261,7 @@ BOARD_ITEM* MODULE::Duplicate( const BOARD_ITEM* aItem,
372 {
373 BOARD_ITEM* new_item = NULL;
374 D_PAD* new_pad = NULL;
375+ ZONE_CONTAINER* new_zone = NULL;
376
377 switch( aItem->Type() )
378 {
379@@ -1207,6 +1276,17 @@ BOARD_ITEM* MODULE::Duplicate( const BOARD_ITEM* aItem,
380 break;
381 }
382
383+ case PCB_ZONE_AREA_T:
384+ {
385+ new_zone = new ZONE_CONTAINER( *static_cast<const ZONE_CONTAINER*>( aItem ) );
386+
387+ if( aAddToModule )
388+ m_zones.push_back( new_zone );
389+
390+ new_item = new_zone;
391+ break;
392+ }
393+
394 case PCB_MODULE_TEXT_T:
395 {
396 const TEXTE_MODULE* old_text = static_cast<const TEXTE_MODULE*>( aItem );
397diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h
398index 2b3eee9..3e09bd6 100644
399--- a/pcbnew/class_module.h
400+++ b/pcbnew/class_module.h
401@@ -41,8 +41,9 @@
402 #include <lib_id.h>
403 #include <list>
404
405-#include <class_text_mod.h>
406 #include "zones.h"
407+#include <class_text_mod.h>
408+#include <class_zone.h>
409
410 #include <core/iterators.h>
411
412@@ -105,6 +106,7 @@ class MODULE_3D_SETTINGS
413
414 DECL_DEQ_FOR_SWIG( PADS, D_PAD* )
415 DECL_DEQ_FOR_SWIG( DRAWINGS, BOARD_ITEM* )
416+DECL_VEC_FOR_SWIG( ZONE_CONTAINERS, ZONE_CONTAINER* )
417 DECL_DEQ_FOR_SWIG( MODULES, MODULE* )
418
419 class MODULE : public BOARD_ITEM_CONTAINER
420@@ -177,6 +179,11 @@ public:
421 return m_drawings;
422 }
423
424+ const ZONE_CONTAINERS& Zones() const
425+ {
426+ return m_zones;
427+ }
428+
429 const DRAWINGS& GraphicalItems() const
430 {
431 return m_drawings;
432@@ -662,8 +669,9 @@ public:
433 #endif
434
435 private:
436- DRAWINGS m_drawings; // BOARD_ITEMs for drawings on the board, owned by pointer.
437- PADS m_pads; // D_PAD items, owned by pointer
438+ DRAWINGS m_drawings; // BOARD_ITEMs for drawings on the board, owned by pointer.
439+ PADS m_pads; // D_PAD items, owned by pointer
440+ ZONE_CONTAINERS m_zones; // ZONE items, owned by pointer
441 std::list<MODULE_3D_SETTINGS> m_3D_Drawings; // Linked list of 3D models.
442
443 double m_Orient; // Orientation in tenths of a degree, 900=90.0 degrees.
444diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
445index ee91511..970f35e 100644
446--- a/pcbnew/class_zone.cpp
447+++ b/pcbnew/class_zone.cpp
448@@ -42,8 +42,8 @@
449 #include <polygon_test_point_inside.h>
450
451
452-ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) :
453- BOARD_CONNECTED_ITEM( aBoard, PCB_ZONE_AREA_T )
454+ZONE_CONTAINER::ZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
455+ : BOARD_CONNECTED_ITEM( aParent, PCB_ZONE_AREA_T )
456 {
457 m_CornerSelection = nullptr; // no corner is selected
458 m_IsFilled = false; // fill status : true when the zone is filled
459@@ -67,14 +67,14 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) :
460 SetLocalFlags( 0 ); // flags tempoarry used in zone calculations
461 m_Poly = new SHAPE_POLY_SET(); // Outlines
462 m_FilledPolysUseThickness = true; // set the "old" way to build filled polygon areas (before 6.0.x)
463- aBoard->GetZoneSettings().ExportSetting( *this );
464+ aParent->GetZoneSettings().ExportSetting( *this );
465
466 m_needRefill = false; // True only after some edition.
467 }
468
469
470-ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone ) :
471- BOARD_CONNECTED_ITEM( aZone )
472+ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone )
473+ : BOARD_CONNECTED_ITEM( aZone.GetParent(), PCB_ZONE_AREA_T )
474 {
475 // Should the copy be on the same net?
476 SetNetCode( aZone.GetNetCode() );
477diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
478index 22f7b00..9a5fa86 100644
479--- a/pcbnew/class_zone.h
480+++ b/pcbnew/class_zone.h
481@@ -63,7 +63,7 @@ public:
482 */
483 typedef enum HATCH_STYLE { NO_HATCH, DIAGONAL_FULL, DIAGONAL_EDGE } HATCH_STYLE;
484
485- ZONE_CONTAINER( BOARD* parent );
486+ ZONE_CONTAINER( BOARD_ITEM_CONTAINER* parent );
487
488 ZONE_CONTAINER( const ZONE_CONTAINER& aZone );
489 ZONE_CONTAINER& operator=( const ZONE_CONTAINER &aOther );
490diff --git a/pcbnew/collectors.cpp b/pcbnew/collectors.cpp
491index 4760bbb..91be17c 100644
492--- a/pcbnew/collectors.cpp
493+++ b/pcbnew/collectors.cpp
494@@ -107,21 +107,12 @@ const KICAD_T GENERAL_COLLECTOR::PadsOrTracks[] = {
495 };
496
497
498-const KICAD_T GENERAL_COLLECTOR::ModulesAndTheirItems[] = {
499- PCB_MODULE_TEXT_T,
500- PCB_MODULE_EDGE_T,
501- PCB_PAD_T,
502- PCB_MODULE_T,
503- EOT
504-};
505+const KICAD_T GENERAL_COLLECTOR::ModulesAndTheirItems[] = { PCB_MODULE_TEXT_T, PCB_MODULE_EDGE_T,
506+ PCB_PAD_T, PCB_MODULE_T, PCB_ZONE_AREA_T, EOT };
507
508
509-const KICAD_T GENERAL_COLLECTOR::ModuleItems[] = {
510- PCB_MODULE_TEXT_T,
511- PCB_MODULE_EDGE_T,
512- PCB_PAD_T,
513- EOT
514-};
515+const KICAD_T GENERAL_COLLECTOR::ModuleItems[] = { PCB_MODULE_TEXT_T, PCB_MODULE_EDGE_T, PCB_PAD_T,
516+ PCB_ZONE_AREA_T, EOT };
517
518
519 const KICAD_T GENERAL_COLLECTOR::Tracks[] = {
520diff --git a/pcbnew/footprint_editor_utils.cpp b/pcbnew/footprint_editor_utils.cpp
521index 35f1909..c85748d 100644
522--- a/pcbnew/footprint_editor_utils.cpp
523+++ b/pcbnew/footprint_editor_utils.cpp
524@@ -385,6 +385,38 @@ void FOOTPRINT_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem )
525 InstallGraphicItemPropertiesDialog( aItem );
526 break;
527
528+ case PCB_ZONE_AREA_T:
529+ {
530+ ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( aItem );
531+ bool success = false;
532+ if( zone )
533+ {
534+ ZONE_SETTINGS zoneSettings;
535+ zoneSettings << *zone;
536+ if( zone->GetIsKeepout() )
537+ {
538+ success = InvokeKeepoutAreaEditor( this, &zoneSettings );
539+ }
540+ else if( zone->IsOnCopperLayer() )
541+ {
542+ success = InvokeCopperZonesEditor( this, &zoneSettings );
543+ }
544+ else
545+ {
546+ success = InvokeNonCopperZonesEditor( this, &zoneSettings );
547+ }
548+
549+ if( success )
550+ {
551+ BOARD_COMMIT commit( this );
552+ commit.Modify( zone );
553+ commit.Push( _( "Edit Zone" ) );
554+ zoneSettings.ExportSetting( *zone );
555+ }
556+ }
557+ }
558+ break;
559+
560 default:
561 break;
562 }
563diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp
564index 22a6ef3..b80c195 100644
565--- a/pcbnew/kicad_plugin.cpp
566+++ b/pcbnew/kicad_plugin.cpp
567@@ -1140,6 +1140,10 @@ void PCB_IO::format( MODULE* aModule, int aNestLevel ) const
568 for( auto pad : aModule->Pads() )
569 format( pad, aNestLevel+1 );
570
571+ // Save zones.
572+ for( auto zone : aModule->Zones() )
573+ format( zone, aNestLevel + 1 );
574+
575 // Save 3D info.
576 auto bs3D = aModule->Models().begin();
577 auto es3D = aModule->Models().end();
578diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h
579index a9d6eeb..81fc723 100644
580--- a/pcbnew/kicad_plugin.h
581+++ b/pcbnew/kicad_plugin.h
582@@ -62,7 +62,8 @@ class TEXTE_PCB;
583 //#define SEXPR_BOARD_FILE_VERSION 20190421 // curves in custom pads
584 //#define SEXPR_BOARD_FILE_VERSION 20190516 // Remove segment count from zones
585 //#define SEXPR_BOARD_FILE_VERSION 20190605 // Add layer defaults
586-#define SEXPR_BOARD_FILE_VERSION 20190905 // Add board physical stackup info in setup section
587+//#define SEXPR_BOARD_FILE_VERSION 20190905 // Add board physical stackup info in setup section
588+#define SEXPR_BOARD_FILE_VERSION 20190907 // Keepout areas in footprints
589
590 #define CTL_STD_LAYER_NAMES (1 << 0) ///< Use English Standard layer names
591 #define CTL_OMIT_NETS (1 << 1) ///< Omit pads net names (useless in library)
592diff --git a/pcbnew/menubar_footprint_editor.cpp b/pcbnew/menubar_footprint_editor.cpp
593index c9ee37f..60a9d83 100644
594--- a/pcbnew/menubar_footprint_editor.cpp
595+++ b/pcbnew/menubar_footprint_editor.cpp
596@@ -228,15 +228,16 @@ void FOOTPRINT_EDIT_FRAME::ReCreateMenuBar()
597 placeMenu->AddItem( PCB_ACTIONS::placePad, haveFootprintCondition );
598
599 placeMenu->AddSeparator();
600- placeMenu->AddItem( PCB_ACTIONS::placeText, haveFootprintCondition );
601- placeMenu->AddItem( PCB_ACTIONS::drawArc, haveFootprintCondition );
602- placeMenu->AddItem( PCB_ACTIONS::drawCircle, haveFootprintCondition );
603- placeMenu->AddItem( PCB_ACTIONS::drawLine, haveFootprintCondition );
604+ placeMenu->AddItem( PCB_ACTIONS::placeText, haveFootprintCondition );
605+ placeMenu->AddItem( PCB_ACTIONS::drawArc, haveFootprintCondition );
606+ placeMenu->AddItem( PCB_ACTIONS::drawCircle, haveFootprintCondition );
607+ placeMenu->AddItem( PCB_ACTIONS::drawLine, haveFootprintCondition );
608 placeMenu->AddItem( PCB_ACTIONS::drawPolygon, haveFootprintCondition );
609+ placeMenu->AddItem( PCB_ACTIONS::drawZoneKeepout, haveFootprintCondition );
610
611 placeMenu->AddSeparator();
612- placeMenu->AddItem( PCB_ACTIONS::setAnchor, haveFootprintCondition );
613- placeMenu->AddItem( ACTIONS::gridSetOrigin, haveFootprintCondition );
614+ placeMenu->AddItem( PCB_ACTIONS::setAnchor, haveFootprintCondition );
615+ placeMenu->AddItem( ACTIONS::gridSetOrigin, haveFootprintCondition );
616
617 placeMenu->Resolve();
618
619diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp
620index fba802e..a314519 100644
621--- a/pcbnew/pcb_parser.cpp
622+++ b/pcbnew/pcb_parser.cpp
623@@ -74,6 +74,7 @@ void PCB_PARSER::init()
624 }
625
626 m_layerMasks[ "*.Cu" ] = LSET::AllCuMask();
627+ m_layerMasks["*In.Cu"] = LSET::InternalCuMask();
628 m_layerMasks[ "F&B.Cu" ] = LSET( 2, F_Cu, B_Cu );
629 m_layerMasks[ "*.Adhes" ] = LSET( 2, B_Adhes, F_Adhes );
630 m_layerMasks[ "*.Paste" ] = LSET( 2, B_Paste, F_Paste );
631@@ -590,7 +591,7 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
632 break;
633
634 case T_zone:
635- m_board->Add( parseZONE_CONTAINER(), ADD_APPEND );
636+ m_board->Add( parseZONE_CONTAINER( m_board ), ADD_APPEND );
637 break;
638
639 case T_target:
640@@ -2511,12 +2512,21 @@ MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
641 module->Add3DModel( parse3DModel() );
642 break;
643
644+ case T_zone:
645+ {
646+ ZONE_CONTAINER* zone = parseZONE_CONTAINER( module.get() );
647+ module->Add( zone, ADD_APPEND );
648+ }
649+ break;
650+
651 default:
652- Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
653- "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
654- "solder_paste_margin, solder_paste_ratio, clearance, "
655- "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
656- "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, or model" );
657+ Expecting(
658+ "locked, placed, tedit, tstamp, at, descr, tags, path, "
659+ "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
660+ "solder_paste_margin, solder_paste_ratio, clearance, "
661+ "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
662+ "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, "
663+ "zone, or model" );
664 }
665 }
666
667@@ -3390,7 +3400,7 @@ VIA* PCB_PARSER::parseVIA()
668 }
669
670
671-ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER()
672+ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
673 {
674 wxCHECK_MSG( CurTok() == T_zone, NULL,
675 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
676@@ -3407,7 +3417,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER()
677 // bigger scope since each filled_polygon is concatenated in here
678 SHAPE_POLY_SET pts;
679
680- std::unique_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) );
681+ std::unique_ptr<ZONE_CONTAINER> zone( new ZONE_CONTAINER( aParent ) );
682
683 zone->SetPriority( 0 );
684
685diff --git a/pcbnew/pcb_parser.h b/pcbnew/pcb_parser.h
686index 0cbfd3c..92b7a99 100644
687--- a/pcbnew/pcb_parser.h
688+++ b/pcbnew/pcb_parser.h
689@@ -41,6 +41,7 @@
690
691 class BOARD;
692 class BOARD_ITEM;
693+class BOARD_ITEM_CONTAINER;
694 class D_PAD;
695 class BOARD_DESIGN_SETTINGS;
696 class DIMENSION;
697@@ -156,7 +157,7 @@ class PCB_PARSER : public PCB_LEXER
698 bool parseD_PAD_option( D_PAD* aPad );
699 TRACK* parseTRACK();
700 VIA* parseVIA();
701- ZONE_CONTAINER* parseZONE_CONTAINER();
702+ ZONE_CONTAINER* parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent );
703 PCB_TARGET* parsePCB_TARGET();
704 BOARD* parseBOARD();
705
706diff --git a/pcbnew/toolbars_footprint_editor.cpp b/pcbnew/toolbars_footprint_editor.cpp
707index 370350c..374dd9a 100644
708--- a/pcbnew/toolbars_footprint_editor.cpp
709+++ b/pcbnew/toolbars_footprint_editor.cpp
710@@ -53,7 +53,7 @@ void FOOTPRINT_EDIT_FRAME::ReCreateHToolbar()
711 #ifdef KICAD_SCRIPTING
712 m_mainToolBar->Add( PCB_ACTIONS::createFootprint );
713 #endif
714-
715+
716 if( IsCurrentFPFromBoard() )
717 m_mainToolBar->Add( PCB_ACTIONS::saveToBoard );
718 else
719@@ -129,18 +129,19 @@ void FOOTPRINT_EDIT_FRAME::ReCreateVToolbar()
720 m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE );
721
722 KiScaledSeparator( m_drawToolBar, this );
723- m_drawToolBar->Add( PCB_ACTIONS::placePad, ACTION_TOOLBAR::TOGGLE );
724- m_drawToolBar->Add( PCB_ACTIONS::drawLine, ACTION_TOOLBAR::TOGGLE );
725- m_drawToolBar->Add( PCB_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE );
726- m_drawToolBar->Add( PCB_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE );
727- m_drawToolBar->Add( PCB_ACTIONS::drawPolygon, ACTION_TOOLBAR::TOGGLE );
728- m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE );
729- m_drawToolBar->Add( ACTIONS::deleteTool, ACTION_TOOLBAR::TOGGLE );
730+ m_drawToolBar->Add( PCB_ACTIONS::placePad, ACTION_TOOLBAR::TOGGLE );
731+ m_drawToolBar->Add( PCB_ACTIONS::drawLine, ACTION_TOOLBAR::TOGGLE );
732+ m_drawToolBar->Add( PCB_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE );
733+ m_drawToolBar->Add( PCB_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE );
734+ m_drawToolBar->Add( PCB_ACTIONS::drawPolygon, ACTION_TOOLBAR::TOGGLE );
735+ m_drawToolBar->Add( PCB_ACTIONS::drawZoneKeepout, ACTION_TOOLBAR::TOGGLE );
736+ m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE );
737+ m_drawToolBar->Add( ACTIONS::deleteTool, ACTION_TOOLBAR::TOGGLE );
738
739 KiScaledSeparator( m_drawToolBar, this );
740- m_drawToolBar->Add( PCB_ACTIONS::setAnchor, ACTION_TOOLBAR::TOGGLE );
741- m_drawToolBar->Add( PCB_ACTIONS::gridSetOrigin, ACTION_TOOLBAR::TOGGLE );
742- m_drawToolBar->Add( ACTIONS::measureTool, ACTION_TOOLBAR::TOGGLE );
743+ m_drawToolBar->Add( PCB_ACTIONS::setAnchor, ACTION_TOOLBAR::TOGGLE );
744+ m_drawToolBar->Add( PCB_ACTIONS::gridSetOrigin, ACTION_TOOLBAR::TOGGLE );
745+ m_drawToolBar->Add( ACTIONS::measureTool, ACTION_TOOLBAR::TOGGLE );
746
747 m_drawToolBar->Realize();
748 }
749@@ -205,6 +206,7 @@ void FOOTPRINT_EDIT_FRAME::SyncToolbars()
750 TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawCircle );
751 TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawArc );
752 TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawPolygon );
753+ TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawZoneKeepout );
754 TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::placeText );
755 TOGGLE_TOOL( m_drawToolBar, ACTIONS::deleteTool );
756 TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::setAnchor );
757diff --git a/pcbnew/tools/drc.cpp b/pcbnew/tools/drc.cpp
758index c651699..d569588 100644
759--- a/pcbnew/tools/drc.cpp
760+++ b/pcbnew/tools/drc.cpp
761@@ -882,10 +882,12 @@ void DRC::testZones()
762
763 void DRC::testKeepoutAreas()
764 {
765+ // Get a list of all zones to inspect, from both board and footprints
766+ std::list<ZONE_CONTAINER*> areasToInspect = m_pcb->GetZoneList( true );
767+
768 // Test keepout areas for vias, tracks and pads inside keepout areas
769- for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ )
770+ for( ZONE_CONTAINER* area : areasToInspect )
771 {
772- ZONE_CONTAINER* area = m_pcb->GetArea( ii );
773
774 if( !area->GetIsKeepout() )
775 continue;
776diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp
777index 58482c9..fbd2078 100644
778--- a/pcbnew/tools/selection_tool.cpp
779+++ b/pcbnew/tools/selection_tool.cpp
780@@ -1461,6 +1461,14 @@ bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
781 switch( aItem->Type() )
782 {
783 case PCB_ZONE_AREA_T:
784+ {
785+ // Check to see if this keepout is part of a footprint
786+ // If it is, and we are not editing the footprint, it should not be selectable
787+ const bool zoneInFootprint =
788+ aItem->GetParent() != nullptr && aItem->GetParent()->Type() == PCB_MODULE_T;
789+ if( zoneInFootprint && !m_editModules && !checkVisibilityOnly )
790+ return false;
791+
792 // Keepout zones can exist on multiple layers!
793 {
794 auto* zone = static_cast<const ZONE_CONTAINER*>( aItem );
795@@ -1481,6 +1489,7 @@ bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
796 return false;
797 }
798 }
799+ }
800 break;
801
802 case PCB_TRACE_T:
803@@ -1543,6 +1552,12 @@ bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
804 return true;
805 }
806
807+ for( auto zone : module->Zones() )
808+ {
809+ if( Selectable( zone, true ) )
810+ return true;
811+ }
812+
813 return false;
814 }
815
816diff --git a/pcbnew/tools/zone_create_helper.cpp b/pcbnew/tools/zone_create_helper.cpp
817index 321858f..f210874 100644
818--- a/pcbnew/tools/zone_create_helper.cpp
819+++ b/pcbnew/tools/zone_create_helper.cpp
820@@ -51,8 +51,9 @@ ZONE_CREATE_HELPER::~ZONE_CREATE_HELPER()
821
822 std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createNewZone( bool aKeepout )
823 {
824- auto& frame = *m_tool.getEditFrame<PCB_BASE_FRAME>();
825+ auto& frame = *m_tool.getEditFrame<PCB_BASE_EDIT_FRAME>();
826 auto& board = *m_tool.getModel<BOARD>();
827+ BOARD_ITEM_CONTAINER* parent = m_tool.m_frame->GetModel();
828 KIGFX::VIEW_CONTROLS* controls = m_tool.GetManager()->GetViewControls();
829
830 // Get the current default settings for zones
831@@ -84,7 +85,7 @@ std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createNewZone( bool aKeepout
832 controls->WarpCursor( controls->GetCursorPosition(), true );
833 }
834
835- auto newZone = std::make_unique<ZONE_CONTAINER>( &board );
836+ auto newZone = std::make_unique<ZONE_CONTAINER>( parent );
837
838 // Apply the selected settings
839 zoneInfo.ExportSetting( *newZone );
840diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp
841index 750cf6e..fded744 100644
842--- a/pcbnew/zone_filler.cpp
843+++ b/pcbnew/zone_filler.cpp
844@@ -620,9 +620,8 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
845
846 // Add zones outlines having an higher priority and keepout
847 //
848- for( int ii = 0; ii < m_board->GetAreaCount(); ii++ )
849+ for( ZONE_CONTAINER* zone : m_board->GetZoneList( true ) )
850 {
851- ZONE_CONTAINER* zone = m_board->GetArea( ii );
852
853 // If the zones share no common layers
854 if( !aZone->CommonLayerExists( zone->GetLayerSet() ) )

Subscribers

People subscribed via source and target branches

to status/vote changes: