← Back to team overview

kicad-developers team mailing list archive

[PATCH] Multilayer keepout zones

 

Attached is a patchset that allows keepout zones to "exist" on multiple
copper layers. This means you can specify a keepout zone for the entire
copper stack (or parts thereof).


Features:

If a keepout zone is specified as multiple layers, the .kicad_mod file
output is adjusted slightly, it will write "(layers F.Cu In1.Cu B.Cu)" e.g.
instead of "(layer F.Cu"). If a single layer is selected, it saves as it
would have previously.

Rendering is working in legacy and GAL and seems to work as expected for
various combinations of layer visibility.

Zone cutout (where it intersects the keepout) occurs on for each layer that
the keepout intersects a copper plane.

DRC violations (pads and tracks inside keepout) work for all layers on
which the keepout exists.

Screenshot:

https://i.imgur.com/0JHt3S8.png

As this patch set touches a lot of files, I'd appreciate some feedback!

My longer term idea is to integrate keepout zones into module (footprint)
files, with the ability to select from a combination of

a) F.Cu
b) Inner.Cu (all internal copper)
c) B.Cu

Let me know if you spot any bugs or glitches!

Oliver
From 1d1110d6afb0194668fc32f02822639d53d1a0be Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Fri, 22 Sep 2017 10:20:20 +1000
Subject: [PATCH 1/9] Enable multi-layer for keepout zones

- Load / save from PCB file correctly
- Doesn't display properly yet
- Keepout only actually applies to one layer (for now)
---
 common/lset.cpp                                    |   1 +
 include/class_board_item.h                         |   2 +-
 pcbnew/class_zone.cpp                              | 158 ++++++++++++++++++++-
 pcbnew/class_zone.h                                |  13 ++
 pcbnew/class_zone_settings.cpp                     |  15 +-
 pcbnew/class_zone_settings.h                       |   2 +
 pcbnew/dialogs/dialog_keepout_area_properties.cpp  |  32 ++++-
 .../dialog_keepout_area_properties_base.cpp        |   6 +-
 .../dialog_keepout_area_properties_base.fbp        |   4 +-
 .../dialogs/dialog_keepout_area_properties_base.h  |   2 +-
 pcbnew/kicad_plugin.cpp                            |  10 +-
 pcbnew/kicad_plugin.h                              |   3 +-
 pcbnew/pcb_parser.cpp                              |   8 +-
 13 files changed, 236 insertions(+), 20 deletions(-)

diff --git a/common/lset.cpp b/common/lset.cpp
index d0a58d9..9550198 100644
--- a/common/lset.cpp
+++ b/common/lset.cpp
@@ -563,6 +563,7 @@ LSET FlipLayerMask( LSET aMask, int aCopperLayersCount )
 
             for( int ii = 0; ii < innerLayerCnt; ii++ )
             {
+                //TODO there is a problem with this code
                 if( internalMask[innerLayerCnt - ii + In1_Cu] )
                     newMask.set( ii + In1_Cu );
                 else
diff --git a/include/class_board_item.h b/include/class_board_item.h
index a7b03fe..9cbbb13 100644
--- a/include/class_board_item.h
+++ b/include/class_board_item.h
@@ -129,7 +129,7 @@ public:
      * Function GetLayer
      * returns the primary layer this item is on.
      */
-    PCB_LAYER_ID GetLayer() const { return m_Layer; }
+    virtual PCB_LAYER_ID GetLayer() const { return m_Layer; }
 
     /**
      * Function GetLayerSet
diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index 6e558d5..a523575 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -176,6 +176,70 @@ const wxPoint& ZONE_CONTAINER::GetPosition() const
 }
 
 
+PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
+{
+    // Testing only
+    if( GetIsKeepout() )
+    {
+        std::cout << "GetLayer() called for keepout!" << std::endl;
+    }
+
+    return BOARD_ITEM::GetLayer();
+}
+
+
+void ZONE_CONTAINER::SetLayer( PCB_LAYER_ID aLayer )
+{
+    SetLayerSet( LSET( aLayer ) );
+
+    m_Layer = aLayer;
+}
+
+
+void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
+{
+    if( aLayerSet.count() == 0 )
+    {
+        return;
+    }
+
+    if( GetIsKeepout() )
+    {
+        // Keepouts can only exist on copper layers
+        m_layerSet = aLayerSet & LSET::AllCuMask();
+
+        std::cout << "Setting layers of keepout: " << aLayerSet.FmtBin() << std::endl;
+    }
+
+    // Set the single layer to the first selected layer
+    m_Layer = aLayerSet.Seq()[0];
+}
+
+
+LSET ZONE_CONTAINER::GetLayerSet() const
+{
+    if( GetIsKeepout() )
+    {
+        return m_layerSet;
+    }
+    else
+    {
+        return LSET( m_Layer );
+    }
+}
+
+
+bool ZONE_CONTAINER::IsOnLayer( PCB_LAYER_ID aLayer ) const
+{
+    if( GetIsKeepout() )
+    {
+        return m_layerSet.test( aLayer );
+    }
+
+    return BOARD_ITEM::IsOnLayer( aLayer );
+}
+
+
 void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode,
                            const wxPoint& offset )
 {
@@ -188,10 +252,75 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
 
-    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );
+    std::cout << "Drawing zone container" << std::endl;
+
+    PCB_LAYER_ID draw_layer = UNDEFINED_LAYER;
+
+    /* Keepout zones can exist on multiple layers
+     * Thus, determining which color to use to render them is a bit tricky.
+     * In descending order of priority:
+     *
+     * 1. If in GR_HIGHLIGHT mode:
+     *   a. If zone is on selected layer, use layer color!
+     *   b. Else, use grey
+     * 1. Not in GR_HIGHLIGHT mode
+     *   a. If zone is on selected layer, use layer color
+     *   b. Else, use color of top-most (visible) layer
+     *
+     */
+    if( GetIsKeepout() )
+    {
+        // At least one layer must be provided!
+        assert( GetLayerSet().count() > 0 );
+
+        // If none of the keepout layers are actually visible, return
+        LSET layers = GetLayerSet() & brd->GetVisibleLayers();
 
-    if( brd->IsLayerVisible( m_Layer ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
-        return;
+        // Not on any visible layer?
+        if( layers.count() == 0 && !( aDrawMode & GR_HIGHLIGHT ) )
+        {
+            std::cout << "No visible layers found" << std::endl;
+            return;
+        }
+
+        // Is keepout zone present on the selected layer?
+        if( layers.test( curr_layer ) )
+        {
+            draw_layer = curr_layer;
+            std::cout << "Selecting color of selected layer" << std::endl;
+        }
+        else
+        {
+            std::cout << "Selecting color of first visible layer";
+
+            // Select the first (top) visible layer
+            if( layers.count() > 0 )
+            {
+                draw_layer = layers.Seq()[0];
+            }
+            else
+            {
+                draw_layer = GetLayerSet().Seq()[0];
+            }
+        }
+
+    }
+    /* Non-keepout zones are easier to deal with
+     */
+    else
+    {
+        if( brd->IsLayerVisible( GetLayer() ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
+        {
+            std::cout << "Not on visible layer" << std::endl;
+            return;
+        }
+
+        draw_layer = GetLayer();
+    }
+
+    assert( draw_layer != UNDEFINED_LAYER );
+
+    auto color = frame->Settings().Colors().GetLayerColor( draw_layer );
 
     GRSetDrawMode( DC, aDrawMode );
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
@@ -199,11 +328,15 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
     if( displ_opts->m_ContrastModeDisplay )
     {
         if( !IsOnLayer( curr_layer ) )
+        {
             color = COLOR4D( DARKDARKGRAY );
+        }
     }
 
     if( ( aDrawMode & GR_HIGHLIGHT ) && !( aDrawMode & GR_AND ) )
+    {
         color.SetToLegacyHighlightColor();
+    }
 
     color.a = 0.588;
 
@@ -242,6 +375,9 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
 void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
                                      wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset )
 {
+
+    std::cout << "DrawFilledArea" << std::endl;
+
     static std::vector <wxPoint> CornersBuffer;
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
 
@@ -262,9 +398,9 @@ void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
     PCB_LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
-    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );
+    auto color = frame->Settings().Colors().GetLayerColor( GetLayer() );
 
-    if( brd->IsLayerVisible( m_Layer ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
+    if( brd->IsLayerVisible( GetLayer() ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
         return;
 
     GRSetDrawMode( DC, aDrawMode );
@@ -389,7 +525,7 @@ void ZONE_CONTAINER::DrawWhileCreateOutline( EDA_DRAW_PANEL* panel, wxDC* DC,
     PCB_LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
-    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );
+    auto color = frame->Settings().Colors().GetLayerColor( GetLayer() );
 
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
 
@@ -789,7 +925,15 @@ void ZONE_CONTAINER::Flip( const wxPoint& aCentre )
 {
     Mirror( aCentre );
     int copperLayerCount = GetBoard()->GetCopperLayerCount();
-    SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
+
+    if( GetIsKeepout() )
+    {
+        SetLayerSet( FlipLayerMask( GetLayerSet(), copperLayerCount ) );
+    }
+    else
+    {
+        SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
+    }
 }
 
 
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index 0352cc7..5468ab3 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -120,6 +120,10 @@ public:
 
     void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) override;
 
+    void SetLayerSet( LSET aLayerSet );
+
+    virtual LSET GetLayerSet() const override;
+
     /**
      * Function Draw
      * Draws the zone outline.
@@ -178,9 +182,16 @@ public:
      */
     bool IsOnCopperLayer() const
     {
+        //TODO fixme!
         return  IsCopperLayer( GetLayer() );
     }
 
+    virtual void SetLayer( PCB_LAYER_ID aLayer ) override;
+
+    virtual PCB_LAYER_ID GetLayer() const override;
+
+    virtual bool IsOnLayer( PCB_LAYER_ID ) const override;
+
     /// How to fill areas: 0 = use filled polygons, 1 => fill with segments.
     void SetFillMode( int aFillMode )                   { m_FillMode = aFillMode; }
     int GetFillMode() const                             { return m_FillMode; }
@@ -725,6 +736,8 @@ private:
     int                   m_cornerSmoothingType;
     unsigned int          m_cornerRadius;
 
+    LSET                  m_layerSet;
+
     /* Priority: when a zone outline is inside and other zone, if its priority is higher
      * the other zone priority, it will be created inside.
      * if priorities are equal, a DRC error is set
diff --git a/pcbnew/class_zone_settings.cpp b/pcbnew/class_zone_settings.cpp
index 806d442..f64573e 100644
--- a/pcbnew/class_zone_settings.cpp
+++ b/pcbnew/class_zone_settings.cpp
@@ -77,7 +77,6 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
     m_ZoneClearance      = aSource.GetZoneClearance();
     m_ZoneMinThickness   = aSource.GetMinThickness();
     m_NetcodeSelection   = aSource.GetNetCode();
-    m_CurrentZone_Layer  = aSource.GetLayer();
     m_Zone_HatchingStyle = aSource.GetHatchStyle();
     m_ArcToSegmentsCount = aSource.GetArcSegmentCount();
     m_ThermalReliefGap = aSource.GetThermalReliefGap();
@@ -90,6 +89,9 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
     m_keepoutDoNotAllowVias = aSource.GetDoNotAllowVias();
     m_keepoutDoNotAllowTracks = aSource.GetDoNotAllowTracks();
 
+    m_CurrentZone_Layer  = aSource.GetLayer();
+    m_Layers = aSource.GetLayerSet();
+
     return *this;
 }
 
@@ -114,7 +116,16 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c
     {
         aTarget.SetPriority( m_ZonePriority );
         aTarget.SetNetCode( m_NetcodeSelection );
-        aTarget.SetLayer( m_CurrentZone_Layer );
+
+        // Keepout zones can have multiple layers
+        if( m_isKeepout )
+        {
+            aTarget.SetLayerSet( m_Layers );
+        }
+        else
+        {
+            aTarget.SetLayer( m_CurrentZone_Layer );
+        }
     }
 
     // call SetHatch last, because hatch lines will be rebuilt,
diff --git a/pcbnew/class_zone_settings.h b/pcbnew/class_zone_settings.h
index d7977e9..e5a69bc 100644
--- a/pcbnew/class_zone_settings.h
+++ b/pcbnew/class_zone_settings.h
@@ -64,6 +64,8 @@ public:
     int  m_ZoneMinThickness;            ///< Min thickness value in filled areas
     int  m_NetcodeSelection;            ///< Net code selection for the current zone
 
+    LSET m_Layers;
+
     PCB_LAYER_ID    m_CurrentZone_Layer;    ///< Layer used to create the current zone
 
     /// Option to show the zone area (outlines only, short hatches or full hatches
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties.cpp b/pcbnew/dialogs/dialog_keepout_area_properties.cpp
index 987a025..4c6f1b0 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties.cpp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties.cpp
@@ -89,7 +89,7 @@ private:
 
 
 #define LAYER_BITMAP_SIZE_X     20
-#define LAYER_BITMAP_SIZE_Y     10
+#define LAYER_BITMAP_SIZE_Y     15
 
 ZONE_EDIT_T InvokeKeepoutAreaEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings )
 {
@@ -155,6 +155,7 @@ void DIALOG_KEEPOUT_AREA_PROPERTIES::initDialog()
 
     // Build copper layer list and append to layer widget
     LSET show = LSET::AllCuMask( board->GetCopperLayerCount() );
+
     int imgIdx = 0;
 
     for( LSEQ cu_stack = show.UIOrder();  cu_stack;  ++cu_stack, imgIdx++ )
@@ -173,7 +174,15 @@ void DIALOG_KEEPOUT_AREA_PROPERTIES::initDialog()
                 m_LayerSelectionCtrl->GetItemCount(), msg, imgIdx );
 
         if( m_zonesettings.m_CurrentZone_Layer == layer )
+        {
+            //m_LayerSelectionCtrl->Select( itemIndex );
+        }
+
+        if( m_zonesettings.m_Layers.test( layer ) )
+        {
             m_LayerSelectionCtrl->Select( itemIndex );
+        }
+
     }
 
     m_LayerSelectionCtrl->SetColumnWidth( 0, wxLIST_AUTOSIZE);
@@ -213,6 +222,25 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::AcceptOptionsForKeepOut()
         return false;
     }
 
+    // Copy the layers across
+    LSET layers;
+
+    for( int ii = 0; ii < m_LayerSelectionCtrl->GetItemCount(); ii++ )
+    {
+        if( m_LayerSelectionCtrl->IsSelected( ii ) )
+        {
+            layers.set( ToLAYER_ID( m_layerId[ii] ) );
+        }
+    }
+
+    if( layers.count() == 0 )
+    {
+        DisplayError( NULL, _( "No layers selected." ) );
+        return false;
+    }
+
+    m_zonesettings.m_Layers = layers;
+
     // Get the layer selection for this zone
     int ii = m_LayerSelectionCtrl->GetFirstSelected();
 
@@ -224,6 +252,8 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::AcceptOptionsForKeepOut()
 
     m_zonesettings.m_CurrentZone_Layer = ToLAYER_ID( m_layerId[ii] );
 
+    // Set zone layers
+
     switch( m_OutlineAppearanceCtrl->GetSelection() )
     {
     case 0:
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
index 19b3f38..e177580 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version May  6 2016)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -26,11 +26,11 @@ DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWind
 	wxBoxSizer* m_layersListSizer;
 	m_layersListSizer = new wxBoxSizer( wxVERTICAL );
 	
-	m_staticTextLayerSelection = new wxStaticText( this, wxID_ANY, _("Layer:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextLayerSelection = new wxStaticText( this, wxID_ANY, _("Keepout Zone Layers"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextLayerSelection->Wrap( -1 );
 	m_layersListSizer->Add( m_staticTextLayerSelection, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
 	
-	m_LayerSelectionCtrl = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ALIGN_LEFT|wxLC_NO_HEADER|wxLC_REPORT|wxLC_SINGLE_SEL );
+	m_LayerSelectionCtrl = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ALIGN_LEFT|wxLC_HRULES|wxLC_NO_HEADER|wxLC_REPORT );
 	m_layersListSizer->Add( m_LayerSelectionCtrl, 1, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
 	
 	
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
index e6a1a2f..15261d1 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
@@ -143,7 +143,7 @@
                                         <property name="gripper">0</property>
                                         <property name="hidden">0</property>
                                         <property name="id">wxID_ANY</property>
-                                        <property name="label">Layer:</property>
+                                        <property name="label">Keepout Zone Layers</property>
                                         <property name="max_size"></property>
                                         <property name="maximize_button">0</property>
                                         <property name="maximum_size"></property>
@@ -243,7 +243,7 @@
                                         <property name="resize">Resizable</property>
                                         <property name="show">1</property>
                                         <property name="size"></property>
-                                        <property name="style">wxLC_ALIGN_LEFT|wxLC_NO_HEADER|wxLC_REPORT|wxLC_SINGLE_SEL</property>
+                                        <property name="style">wxLC_ALIGN_LEFT|wxLC_HRULES|wxLC_NO_HEADER|wxLC_REPORT</property>
                                         <property name="subclass">wxListView; </property>
                                         <property name="toolbar_pane">0</property>
                                         <property name="tooltip"></property>
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.h b/pcbnew/dialogs/dialog_keepout_area_properties_base.h
index 36f5194..aee5e07 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.h
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version May  6 2016)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp
index b633eb5..c1d76d3 100644
--- a/pcbnew/kicad_plugin.cpp
+++ b/pcbnew/kicad_plugin.cpp
@@ -1609,7 +1609,15 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
                   aZone->GetIsKeepout() ? 0 : m_mapping->Translate( aZone->GetNetCode() ),
                   m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetname() ).c_str() );
 
-    formatLayer( aZone );
+    // Keepout zones can exist on multiple layers
+    if( aZone->GetIsKeepout() && aZone->GetLayerSet().count() > 1 )
+    {
+        formatLayers( aZone->GetLayerSet() );
+    }
+    else
+    {
+        formatLayer( aZone );
+    }
 
     m_out->Print( 0, " (tstamp %lX)", (unsigned long) aZone->GetTimeStamp() );
 
diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h
index 5953416..80f1d58 100644
--- a/pcbnew/kicad_plugin.h
+++ b/pcbnew/kicad_plugin.h
@@ -43,7 +43,8 @@ class NETINFO_MAPPING;
 //                                              // went to 32 Cu layers from 16.
 //#define SEXPR_BOARD_FILE_VERSION    20160815  // differential pair settings per net class
 //#define SEXPR_BOARD_FILE_VERSION    20170123  // EDA_TEXT refactor, moved 'hide'
-#define SEXPR_BOARD_FILE_VERSION      20170920  // long pad names and custom pad shape
+//#define SEXPR_BOARD_FILE_VERSION    20170920  // long pad names and custom pad shape
+#define SEXPR_BOARD_FILE_VERSION      20170922  // Keepout zones can exist on multiple layers
 
 #define CTL_STD_LAYER_NAMES         (1 << 0)    ///< Use English Standard layer names
 #define CTL_OMIT_NETS               (1 << 1)    ///< Omit pads net names (useless in library)
diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp
index 2661982..d7b1bd4 100644
--- a/pcbnew/pcb_parser.cpp
+++ b/pcbnew/pcb_parser.cpp
@@ -2825,6 +2825,12 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER()
             NeedRIGHT();
             break;
 
+        case T_layers:
+            // If multiple layers are specified, it is a keepout zone
+            zone->SetIsKeepout( true );
+            zone->SetLayerSet( parseBoardItemLayersAsMask() );
+            break;
+
         case T_tstamp:
             zone->SetTimeStamp( parseHex() );
             NeedRIGHT();
@@ -3075,7 +3081,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER()
             break;
 
         default:
-            Expecting( "net, layer, tstamp, hatch, priority, connect_pads, min_thickness, "
+            Expecting( "net, layer/layers, tstamp, hatch, priority, connect_pads, min_thickness, "
                        "fill, polygon, filled_polygon, or fill_segments" );
         }
     }
-- 
2.7.4

From 0e787a8d379be455977e0736ce26e354a56f1239 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Fri, 22 Sep 2017 15:18:05 +1000
Subject: [PATCH 2/9] Multi-layer zone rendering for GAL

---
 pcbnew/class_zone.cpp  | 47 +++++++++++++++++++++++++++++++++++++++++------
 pcbnew/class_zone.h    |  8 +++-----
 pcbnew/pcb_painter.cpp | 12 +++++++++---
 pcbnew/pcb_painter.h   |  2 +-
 4 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index a523575..54e516e 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -188,6 +188,19 @@ PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
 }
 
 
+bool ZONE_CONTAINER::IsOnCopperLayer() const
+{
+    if( GetIsKeepout() )
+    {
+        return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
+    }
+    else
+    {
+        return IsCopperLayer( GetLayer() );
+    }
+}
+
+
 void ZONE_CONTAINER::SetLayer( PCB_LAYER_ID aLayer )
 {
     SetLayerSet( LSET( aLayer ) );
@@ -207,8 +220,6 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
     {
         // Keepouts can only exist on copper layers
         m_layerSet = aLayerSet & LSET::AllCuMask();
-
-        std::cout << "Setting layers of keepout: " << aLayerSet.FmtBin() << std::endl;
     }
 
     // Set the single layer to the first selected layer
@@ -228,6 +239,26 @@ LSET ZONE_CONTAINER::GetLayerSet() const
     }
 }
 
+void ZONE_CONTAINER::ViewGetLayers( int aLayers[], int& aCount ) const
+{
+    if( GetIsKeepout() )
+    {
+        LSEQ layers = m_layerSet.Seq();
+
+        for( unsigned int idx = 0; idx < layers.size(); idx++ )
+        {
+            aLayers[idx] = layers[idx];
+        }
+
+        aCount = layers.size();
+    }
+    else
+    {
+        aLayers[0] = m_Layer;
+        aCount = 1;
+    }
+}
+
 
 bool ZONE_CONTAINER::IsOnLayer( PCB_LAYER_ID aLayer ) const
 {
@@ -252,10 +283,16 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
 
-    std::cout << "Drawing zone container" << std::endl;
-
     PCB_LAYER_ID draw_layer = UNDEFINED_LAYER;
 
+    LSET layers = GetLayerSet() & brd->GetVisibleLayers();
+
+    // If there are no visible layers and the zone is not highlighted, return
+    if( layers.count() == 0 && !( aDrawMode & GR_HIGHLIGHT ) )
+    {
+        return;
+    }
+
     /* Keepout zones can exist on multiple layers
      * Thus, determining which color to use to render them is a bit tricky.
      * In descending order of priority:
@@ -376,8 +413,6 @@ void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
                                      wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset )
 {
 
-    std::cout << "DrawFilledArea" << std::endl;
-
     static std::vector <wxPoint> CornersBuffer;
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
 
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index 5468ab3..d3e93b0 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -180,11 +180,7 @@ public:
      * Function IsOnCopperLayer
      * @return true if this zone is on a copper layer, false if on a technical layer
      */
-    bool IsOnCopperLayer() const
-    {
-        //TODO fixme!
-        return  IsCopperLayer( GetLayer() );
-    }
+    bool IsOnCopperLayer() const;
 
     virtual void SetLayer( PCB_LAYER_ID aLayer ) override;
 
@@ -192,6 +188,8 @@ public:
 
     virtual bool IsOnLayer( PCB_LAYER_ID ) const override;
 
+    virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;
+
     /// How to fill areas: 0 = use filled polygons, 1 => fill with segments.
     void SetFillMode( int aFillMode )                   { m_FillMode = aFillMode; }
     int GetFillMode() const                             { return m_FillMode; }
diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp
index 3a0e82d..0ab04ca 100644
--- a/pcbnew/pcb_painter.cpp
+++ b/pcbnew/pcb_painter.cpp
@@ -294,7 +294,7 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
         break;
 
     case PCB_ZONE_AREA_T:
-        draw( static_cast<const ZONE_CONTAINER*>( item ) );
+        draw( static_cast<const ZONE_CONTAINER*>( item ), aLayer );
         break;
 
     case PCB_DIMENSION_T:
@@ -1075,9 +1075,15 @@ void PCB_PAINTER::draw( const MODULE* aModule, int aLayer )
 }
 
 
-void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone )
+void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
 {
-    const COLOR4D& color = m_pcbSettings.GetColor( aZone, aZone->GetLayer() );
+
+    if( !aZone->IsOnLayer( (PCB_LAYER_ID) aLayer ) )
+    {
+        return;
+    }
+
+    const COLOR4D& color = m_pcbSettings.GetColor( aZone, aLayer );
     std::deque<VECTOR2D> corners;
     PCB_RENDER_SETTINGS::DISPLAY_ZONE_MODE displayMode = m_pcbSettings.m_displayZone;
 
diff --git a/pcbnew/pcb_painter.h b/pcbnew/pcb_painter.h
index 895e57e..86b1eef 100644
--- a/pcbnew/pcb_painter.h
+++ b/pcbnew/pcb_painter.h
@@ -201,7 +201,7 @@ protected:
     void draw( const TEXTE_PCB* aText, int aLayer );
     void draw( const TEXTE_MODULE* aText, int aLayer );
     void draw( const MODULE* aModule, int aLayer );
-    void draw( const ZONE_CONTAINER* aZone );
+    void draw( const ZONE_CONTAINER* aZone, int aLayer );
     void draw( const DIMENSION* aDimension, int aLayer );
     void draw( const PCB_TARGET* aTarget );
     void draw( const MARKER_PCB* aMarker );
-- 
2.7.4

From ec08fcf1dc2006297894238234711c94fd787f0b Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 11:59:40 +1000
Subject: [PATCH 3/9] Enable multi-layer selection for keepout zones in GAL

---
 pcbnew/class_zone.cpp           | 11 -----------
 pcbnew/tools/selection_tool.cpp | 39 +++++++++++++++++++++++++++++++++------
 2 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index 54e516e..9343ec1 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -178,12 +178,6 @@ const wxPoint& ZONE_CONTAINER::GetPosition() const
 
 PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
 {
-    // Testing only
-    if( GetIsKeepout() )
-    {
-        std::cout << "GetLayer() called for keepout!" << std::endl;
-    }
-
     return BOARD_ITEM::GetLayer();
 }
 
@@ -316,7 +310,6 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
         // Not on any visible layer?
         if( layers.count() == 0 && !( aDrawMode & GR_HIGHLIGHT ) )
         {
-            std::cout << "No visible layers found" << std::endl;
             return;
         }
 
@@ -324,12 +317,9 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
         if( layers.test( curr_layer ) )
         {
             draw_layer = curr_layer;
-            std::cout << "Selecting color of selected layer" << std::endl;
         }
         else
         {
-            std::cout << "Selecting color of first visible layer";
-
             // Select the first (top) visible layer
             if( layers.count() > 0 )
             {
@@ -348,7 +338,6 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
     {
         if( brd->IsLayerVisible( GetLayer() ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
         {
-            std::cout << "Not on visible layer" << std::endl;
             return;
         }
 
diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp
index 210dbb1..ed5aae7 100644
--- a/pcbnew/tools/selection_tool.cpp
+++ b/pcbnew/tools/selection_tool.cpp
@@ -34,6 +34,7 @@ using namespace std::placeholders;
 #include <class_module.h>
 #include <class_pcb_text.h>
 #include <class_drawsegment.h>
+#include <class_zone.h>
 
 #include <wxPcbStruct.h>
 #include <collectors.h>
@@ -1382,15 +1383,17 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
     // Is high contrast mode enabled?
     bool highContrast = getView()->GetPainter()->GetSettings()->GetHighContrast();
 
+    int layers[KIGFX::VIEW::VIEW_MAX_LAYERS], layers_count;
+
+    // Filter out items that do not belong to active layers
+    const std::set<unsigned int>& activeLayers = getView()->GetPainter()->
+                                                 GetSettings()->GetActiveLayers();
+
+    aItem->ViewGetLayers( layers, layers_count );
+
     if( highContrast )
     {
         bool onActive = false;          // Is the item on any of active layers?
-        int layers[KIGFX::VIEW::VIEW_MAX_LAYERS], layers_count;
-
-        // Filter out items that do not belong to active layers
-        const std::set<unsigned int>& activeLayers = getView()->GetPainter()->
-                                                     GetSettings()->GetActiveLayers();
-        aItem->ViewGetLayers( layers, layers_count );
 
         for( int i = 0; i < layers_count; ++i )
         {
@@ -1402,11 +1405,35 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
         }
 
         if( !onActive ) // We do not want to select items that are in the background
+        {
             return false;
+        }
     }
 
     switch( aItem->Type() )
     {
+    case PCB_ZONE_AREA_T:
+        // Keepout zones can exist on multiple layers!
+        {
+            auto* zone = static_cast<const ZONE_CONTAINER*>( aItem );
+
+            if( zone && zone->GetIsKeepout() )
+            {
+                auto zoneLayers = zone->GetLayerSet().Seq();
+
+                for( unsigned int i = 0; i < zoneLayers.size(); i++ )
+                {
+                    if( board()->IsLayerVisible( zoneLayers[i] ) )
+                    {
+                        return true;
+                    }
+                }
+
+                // No active layers selected!
+                return false;
+            }
+        }
+        break;
     case PCB_VIA_T:
         {
             // For vias it is enough if only one of layers is visible
-- 
2.7.4

From 10d4371643e818df3b58927437c469b04e0d7008 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 14:53:34 +1000
Subject: [PATCH 4/9] DRC checks for keepout zones work on all layers

---
 pcbnew/class_zone.cpp       |  8 ++++++++
 pcbnew/class_zone.h         |  6 ++++++
 pcbnew/drc.cpp              | 15 +++++++++++----
 pcbnew/zones_by_polygon.cpp | 17 +++++++++++++----
 4 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index 9343ec1..d2148e7 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -195,6 +195,14 @@ bool ZONE_CONTAINER::IsOnCopperLayer() const
 }
 
 
+bool ZONE_CONTAINER::CommonLayerExists( const LSET aLayerSet ) const
+{
+    auto common = GetLayerSet() & aLayerSet;
+
+    return common.size() > 0;
+}
+
+
 void ZONE_CONTAINER::SetLayer( PCB_LAYER_ID aLayer )
 {
     SetLayerSet( LSET( aLayer ) );
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index d3e93b0..57c5dbd 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -182,6 +182,12 @@ public:
      */
     bool IsOnCopperLayer() const;
 
+    /**
+     * Function CommonLayerExist
+     * Test if this zone shares a common layer with the given layer set
+     */
+    bool CommonLayerExists( const LSET aLayerSet ) const;
+
     virtual void SetLayer( PCB_LAYER_ID aLayer ) override;
 
     virtual PCB_LAYER_ID GetLayer() const override;
diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp
index 6213be9..c271fea 100644
--- a/pcbnew/drc.cpp
+++ b/pcbnew/drc.cpp
@@ -621,7 +621,9 @@ void DRC::testKeepoutAreas()
         ZONE_CONTAINER* area = m_pcb->GetArea( ii );
 
         if( !area->GetIsKeepout() )
+        {
             continue;
+        }
 
         for( TRACK* segm = m_pcb->m_Track; segm != NULL; segm = segm->Next() )
         {
@@ -630,7 +632,8 @@ void DRC::testKeepoutAreas()
                 if( ! area->GetDoNotAllowTracks()  )
                     continue;
 
-                if( segm->GetLayer() != area->GetLayer() )
+                // Ignore if the keepout zone is not on the same layer
+                if( !area->IsOnLayer( segm->GetLayer() ) )
                     continue;
 
                 if( area->Outline()->Distance( SEG( segm->GetStart(), segm->GetEnd() ),
@@ -646,7 +649,9 @@ void DRC::testKeepoutAreas()
                 if( ! area->GetDoNotAllowVias()  )
                     continue;
 
-                if( ! ((VIA*)segm)->IsOnLayer( area->GetLayer() ) )
+                auto viaLayers = segm->GetLayerSet();
+
+                if( !area->CommonLayerExists( viaLayers ) )
                     continue;
 
                 if( area->Outline()->Distance( segm->GetPosition() ) < segm->GetWidth()/2 )
@@ -801,7 +806,7 @@ bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg )
             if( ! area->GetDoNotAllowTracks()  )
                 continue;
 
-            if( aRefSeg->GetLayer() != area->GetLayer() )
+            if( !area->IsOnLayer( aRefSeg->GetLayer() ) )
                 continue;
 
             if( area->Outline()->Distance( SEG( aRefSeg->GetStart(), aRefSeg->GetEnd() ),
@@ -817,7 +822,9 @@ bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg )
             if( ! area->GetDoNotAllowVias()  )
                 continue;
 
-            if( ! ((VIA*)aRefSeg)->IsOnLayer( area->GetLayer() ) )
+            auto viaLayers = aRefSeg->GetLayerSet();
+
+            if( !area->CommonLayerExists( viaLayers ) )
                 continue;
 
             if( area->Outline()->Distance( aRefSeg->GetPosition() ) < aRefSeg->GetWidth()/2 )
diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp
index d8e4623..545e072 100644
--- a/pcbnew/zones_by_polygon.cpp
+++ b/pcbnew/zones_by_polygon.cpp
@@ -127,11 +127,20 @@ void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone )
 
     // If the new zone is on the same layer as the the initial zone,
     // do nothing
-    if( success && ( aZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+    if( success )
     {
-        DisplayErrorMessage( this,
-            _( "The duplicated zone cannot be on the same layer as the original zone." ) );
-        success = false;
+        if( aZone->GetIsKeepout() && ( aZone->GetLayerSet() == zoneSettings.m_Layers ) )
+        {
+            DisplayErrorMessage(
+                        this, _( "The duplicated zone cannot be on the same layers as the original zone." ) );
+            success = false;
+        }
+        else if( !aZone->GetIsKeepout() && ( aZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+        {
+            DisplayErrorMessage(
+                    this, _(  "The duplicated zone cannot be on the same layer as the original zone." ) );
+            success = false;
+        }
     }
 
     if( success )
-- 
2.7.4

From 36163cc529738ee4cf227c90915711e3d00925c4 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 15:20:20 +1000
Subject: [PATCH 5/9] Fixed bug in FlipLayerMask

- Offset for internal copper layers was incorrect
---
 common/lset.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/common/lset.cpp b/common/lset.cpp
index 9550198..1352e9c 100644
--- a/common/lset.cpp
+++ b/common/lset.cpp
@@ -563,8 +563,7 @@ LSET FlipLayerMask( LSET aMask, int aCopperLayersCount )
 
             for( int ii = 0; ii < innerLayerCnt; ii++ )
             {
-                //TODO there is a problem with this code
-                if( internalMask[innerLayerCnt - ii + In1_Cu] )
+                if( internalMask[innerLayerCnt - ii] )
                     newMask.set( ii + In1_Cu );
                 else
                     newMask.reset( ii + In1_Cu );
-- 
2.7.4

From cd6dc79ce07127299e1fa041b0fd3a4626a22f8d Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 16:34:40 +1000
Subject: [PATCH 6/9] Fixed bug in FlipLayerMask

- Offset for internal copper layers was incorrect
- Incorrect mask was used
---
 common/lset.cpp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/common/lset.cpp b/common/lset.cpp
index 1352e9c..b7d7cb5 100644
--- a/common/lset.cpp
+++ b/common/lset.cpp
@@ -554,19 +554,25 @@ LSET FlipLayerMask( LSET aMask, int aCopperLayersCount )
 
     if( aCopperLayersCount >= 4 )   // Internal layers exist
     {
-        LSET internalMask = aMask & ~LSET::InternalCuMask();
+        LSET internalMask = aMask & LSET::InternalCuMask();
 
         if( internalMask != LSET::InternalCuMask() )
-        {   // the mask does not include all internal layers. Therefore
+        {
+            // the mask does not include all internal layers. Therefore
             // the flipped mask for internal copper layers must be built
+
             int innerLayerCnt = aCopperLayersCount -2;
 
             for( int ii = 0; ii < innerLayerCnt; ii++ )
             {
                 if( internalMask[innerLayerCnt - ii] )
+                {
                     newMask.set( ii + In1_Cu );
+                }
                 else
+                {
                     newMask.reset( ii + In1_Cu );
+                }
             }
         }
     }
-- 
2.7.4

From a0c320f0f916a96b84a610d3e2afd6f19cc63fba Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 17:24:03 +1000
Subject: [PATCH 7/9] Zone keepout exclusion now works on multiple layers!

---
 pcbnew/tools/pcb_editor_control.cpp                     | 17 +++++++++++++----
 pcbnew/zones_by_polygon_fill_functions.cpp              |  2 ++
 .../zones_convert_brd_items_to_polygons_with_Boost.cpp  |  3 ++-
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp
index a91a548..08c675b 100644
--- a/pcbnew/tools/pcb_editor_control.cpp
+++ b/pcbnew/tools/pcb_editor_control.cpp
@@ -912,11 +912,20 @@ int PCB_EDITOR_CONTROL::ZoneDuplicate( const TOOL_EVENT& aEvent )
 
     // If the new zone is on the same layer as the the initial zone,
     // do nothing
-    if( success && ( oldZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+    if( success )
     {
-        DisplayError( m_frame,
-            _( "The duplicated zone cannot be on the same layer as the original zone." ) );
-        success = false;
+        if( oldZone->GetIsKeepout() && ( oldZone->GetLayerSet() == zoneSettings.m_Layers ) )
+        {
+            DisplayError(
+                    m_frame, _( "The duplicated keepout zone cannot be on the same layers as the original zone." ) );
+            success = false;
+        }
+        else if( !oldZone->GetIsKeepout() && ( oldZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+        {
+            DisplayError(
+                    m_frame, _( "The duplicated zone cannot be on the same layer as the original zone." ) );
+            success = false;
+        }
     }
 
     // duplicate the zone
diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp
index 32a4458..7651753 100644
--- a/pcbnew/zones_by_polygon_fill_functions.cpp
+++ b/pcbnew/zones_by_polygon_fill_functions.cpp
@@ -160,6 +160,8 @@ int PCB_EDIT_FRAME::Fill_All_Zones( wxWindow * aActiveWindow, bool aVerbose )
     for( ii = 0; ii < areaCount; ii++ )
     {
         ZONE_CONTAINER* zoneContainer = GetBoard()->GetArea( ii );
+
+        // Keepout zones are not filled
         if( zoneContainer->GetIsKeepout() )
             continue;
 
diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
index 91ee93b..343d43c 100644
--- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
+++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
@@ -363,7 +363,8 @@ void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeature
     {
         ZONE_CONTAINER* zone = GetBoard()->GetArea( ii );
 
-        if( zone->GetLayer() != GetLayer() )
+        // If the zones share no common layers
+        if( !CommonLayerExists( zone->GetLayerSet() ) )
             continue;
 
         if( !zone->GetIsKeepout() && zone->GetPriority() <= GetPriority() )
-- 
2.7.4


Follow ups