CHANGED: Copper zones can be on more than one layer

Fixes https://gitlab.com/kicad/code/kicad/-/issues/1963
This commit is contained in:
Jon Evans 2020-06-23 22:19:08 -04:00
parent 0b34cea3d5
commit 0d4ee39f75
36 changed files with 671 additions and 492 deletions

View File

@ -708,7 +708,7 @@ void BOARD_ADAPTER::AddSolidAreasShapesToContainer( const ZONE_CONTAINER* aZoneC
PCB_LAYER_ID aLayerId ) PCB_LAYER_ID aLayerId )
{ {
// Copy the polys list because we have to simplify it // Copy the polys list because we have to simplify it
SHAPE_POLY_SET polyList = SHAPE_POLY_SET( aZoneContainer->GetFilledPolysList() ); SHAPE_POLY_SET polyList = SHAPE_POLY_SET( aZoneContainer->GetFilledPolysList( aLayerId ) );
// This convert the poly in outline and holes // This convert the poly in outline and holes
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits, Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,

View File

@ -682,6 +682,16 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
if( aStatusReporter ) if( aStatusReporter )
aStatusReporter->Report( _( "Create zones" ) ); aStatusReporter->Report( _( "Create zones" ) );
std::vector<std::pair<const ZONE_CONTAINER*, PCB_LAYER_ID>> zones;
for( size_t i = 0; i < m_board->GetAreaCount(); i++ )
{
const ZONE_CONTAINER* zone = m_board->GetArea( i );
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
zones.emplace_back( std::make_pair( zone, layer ) );
}
// Add zones objects // Add zones objects
// ///////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////
std::atomic<size_t> nextZone( 0 ); std::atomic<size_t> nextZone( 0 );
@ -693,19 +703,20 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
std::thread t = std::thread( [&]() std::thread t = std::thread( [&]()
{ {
for( size_t areaId = nextZone.fetch_add( 1 ); for( size_t areaId = nextZone.fetch_add( 1 );
areaId < static_cast<size_t>( m_board->GetAreaCount() ); areaId < zones.size();
areaId = nextZone.fetch_add( 1 ) ) areaId = nextZone.fetch_add( 1 ) )
{ {
const ZONE_CONTAINER* zone = m_board->GetArea( areaId ); const ZONE_CONTAINER* zone = zones[areaId].first;
if( zone == nullptr ) if( zone == nullptr )
break; break;
auto layerContainer = m_layers_container2D.find( zone->GetLayer() ); PCB_LAYER_ID layer = zones[areaId].second;
auto layerContainer = m_layers_container2D.find( layer );
if( layerContainer != m_layers_container2D.end() ) if( layerContainer != m_layers_container2D.end() )
AddSolidAreasShapesToContainer( zone, layerContainer->second, AddSolidAreasShapesToContainer( zone, layerContainer->second, layer );
zone->GetLayer() );
} }
threadsFinished++; threadsFinished++;
@ -733,10 +744,13 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
if( zone == nullptr ) if( zone == nullptr )
break; break;
auto layerContainer = m_layers_poly.find( zone->GetLayer() ); for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
auto layerContainer = m_layers_poly.find( layer );
if( layerContainer != m_layers_poly.end() ) if( layerContainer != m_layers_poly.end() )
zone->TransformSolidAreasShapesToPolygonSet( *layerContainer->second ); zone->TransformSolidAreasShapesToPolygonSet( layer, *layerContainer->second );
}
} }
} }
@ -1010,7 +1024,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
if( !zone->IsOnLayer( curr_layer_id ) ) if( !zone->IsOnLayer( curr_layer_id ) )
continue; continue;
zone->TransformSolidAreasShapesToPolygonSet( *layerPoly ); zone->TransformSolidAreasShapesToPolygonSet( curr_layer_id, *layerPoly );
} }
} }

View File

@ -89,10 +89,9 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_
for( int ii = 0; ii < GetAreaCount(); ii++ ) for( int ii = 0; ii < GetAreaCount(); ii++ )
{ {
ZONE_CONTAINER* zone = GetArea( ii ); ZONE_CONTAINER* zone = GetArea( ii );
PCB_LAYER_ID zonelayer = zone->GetLayer();
if( zonelayer == aLayer ) if( zone->GetLayerSet().test( aLayer ) )
zone->TransformSolidAreasShapesToPolygonSet( aOutlines ); zone->TransformSolidAreasShapesToPolygonSet( aLayer, aOutlines );
} }
// convert graphic items on copper layers (texts) // convert graphic items on copper layers (texts)
@ -242,14 +241,17 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet( PCB_LAYER_ID aLaye
} }
void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet( SHAPE_POLY_SET& aCornerBuffer, void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet( PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer,
int aError ) const int aError ) const
{ {
if( GetFilledPolysList().IsEmpty() ) if( !m_FilledPolysList.count( aLayer ) || m_FilledPolysList.at( aLayer ).IsEmpty() )
return; return;
const SHAPE_POLY_SET& polys = m_FilledPolysList.at( aLayer );
// add filled areas polygons // add filled areas polygons
aCornerBuffer.Append( m_FilledPolysList ); aCornerBuffer.Append( polys );
auto board = GetBoard(); auto board = GetBoard();
int maxError = ARC_HIGH_DEF; int maxError = ARC_HIGH_DEF;
@ -257,9 +259,9 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet( SHAPE_POLY_SET& aCor
maxError = board->GetDesignSettings().m_MaxError; maxError = board->GetDesignSettings().m_MaxError;
// add filled areas outlines, which are drawn with thick lines // add filled areas outlines, which are drawn with thick lines
for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ ) for( int i = 0; i < polys.OutlineCount(); i++ )
{ {
const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( i ); const SHAPE_LINE_CHAIN& path = polys.COutline( i );
for( int j = 0; j < path.PointCount(); j++ ) for( int j = 0; j < path.PointCount(); j++ )
{ {
@ -652,8 +654,16 @@ void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCorn
int aClearanceValue, int aError, int aClearanceValue, int aError,
bool ignoreLineWidth ) const bool ignoreLineWidth ) const
{ {
wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for zones." ); // Now that zones are multilayer, we cannot implement this without a layer argument.
// But, at the time of adding multilayer zones, this is never called for zones anyway
// so let's just disable it and fail.
wxFAIL_MSG( "TransformShapeWithClearanceToPolygon is not supported for zones" );
aCornerBuffer = m_FilledPolysList; #if 0
if( !m_FilledPolysList.count( aLayer ) )
return;
aCornerBuffer = m_FilledPolysList.at( aLayer );
aCornerBuffer.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); aCornerBuffer.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
#endif
} }

View File

@ -1216,31 +1216,6 @@ int BOARD::SortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount )
} }
ZONE_CONTAINER* BOARD::HitTestForAnyFilledArea( const wxPoint& aRefPos, PCB_LAYER_ID aStartLayer,
PCB_LAYER_ID aEndLayer, int aNetCode )
{
if( aEndLayer < 0 )
aEndLayer = aStartLayer;
if( aEndLayer < aStartLayer )
std::swap( aEndLayer, aStartLayer );
for( ZONE_CONTAINER* area : m_ZoneDescriptorList )
{
if( area->GetLayer() < aStartLayer || area->GetLayer() > aEndLayer )
continue;
if( aNetCode >= 0 && area->GetNetCode() != aNetCode )
continue;
if( area->HitTestFilledArea( aRefPos ) )
return area;
}
return NULL;
}
int BOARD::SetAreasNetCodesFromNetNames() int BOARD::SetAreasNetCodesFromNetNames()
{ {
int error_count = 0; int error_count = 0;

View File

@ -855,21 +855,6 @@ public:
/* Copper Areas handling */ /* Copper Areas handling */
/*************************/ /*************************/
/**
* Function HitTestForAnyFilledArea
* tests if the given wxPoint is within the bounds of a filled area of this zone.
* the test is made on zones on layer from aStartLayer to aEndLayer
* @param aRefPos A wxPoint to test
* @param aStartLayer the first layer to test
* @param aEndLayer the last layer to test
* @param aNetCode = the netcode used to filter zones (-1 to to test all zones)
* @return ZONE_CONTAINER* return a pointer to the ZONE_CONTAINER found, else NULL
*/
ZONE_CONTAINER* HitTestForAnyFilledArea( const wxPoint& aRefPos,
PCB_LAYER_ID aStartLayer,
PCB_LAYER_ID aEndLayer,
int aNetCode );
/** /**
* Function SetAreasNetCodesFromNetNames * Function SetAreasNetCodesFromNetNames
* Set the .m_NetCode member of all copper areas, according to the area Net Name * Set the .m_NetCode member of all copper areas, according to the area Net Name

View File

@ -30,6 +30,7 @@
#include <pcb_screen.h> #include <pcb_screen.h>
#include <class_board.h> #include <class_board.h>
#include <class_zone.h> #include <class_zone.h>
#include <pcb_edit_frame.h> // current layer for msgpanel
#include <math_for_graphics.h> #include <math_for_graphics.h>
#include <settings/color_settings.h> #include <settings/color_settings.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
@ -63,6 +64,7 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent, bool aInModule )
SetLocalFlags( 0 ); // flags tempoarry used in zone calculations SetLocalFlags( 0 ); // flags tempoarry used in zone calculations
m_Poly = new SHAPE_POLY_SET(); // Outlines m_Poly = new SHAPE_POLY_SET(); // Outlines
m_FilledPolysUseThickness = true; // set the "old" way to build filled polygon areas (before 6.0.x) m_FilledPolysUseThickness = true; // set the "old" way to build filled polygon areas (before 6.0.x)
m_removeIslands = true;
aParent->GetZoneSettings().ExportSetting( *this ); aParent->GetZoneSettings().ExportSetting( *this );
m_needRefill = false; // True only after some edition. m_needRefill = false; // True only after some edition.
@ -192,10 +194,20 @@ EDA_ITEM* ZONE_CONTAINER::Clone() const
bool ZONE_CONTAINER::UnFill() bool ZONE_CONTAINER::UnFill()
{ {
bool change = ( !m_FilledPolysList.IsEmpty() || m_FillSegmList.size() > 0 ); bool change = false;
for( std::pair<PCB_LAYER_ID, SHAPE_POLY_SET> pair : m_FilledPolysList )
{
change |= !pair.second.IsEmpty();
pair.second.RemoveAllContours();
}
for( std::pair<PCB_LAYER_ID, ZONE_SEGMENT_FILL> pair : m_FillSegmList )
{
change |= !pair.second.empty();
pair.second.clear();
}
m_FilledPolysList.RemoveAllContours();
m_FillSegmList.clear();
m_IsFilled = false; m_IsFilled = false;
return change; return change;
@ -216,14 +228,7 @@ PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
bool ZONE_CONTAINER::IsOnCopperLayer() const bool ZONE_CONTAINER::IsOnCopperLayer() const
{ {
if( GetIsKeepout() )
{
return ( m_layerSet & LSET::AllCuMask() ).count() > 0; return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
}
else
{
return IsCopperLayer( GetLayer() );
}
} }
@ -255,12 +260,24 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
return; return;
if( m_layerSet != aLayerSet ) if( m_layerSet != aLayerSet )
{
SetNeedRefill( true ); SetNeedRefill( true );
UnFill();
for( PCB_LAYER_ID layer : aLayerSet.Seq() )
{
m_FillSegmList[layer] = {};
m_FilledPolysList[layer] = {};
m_RawPolysList[layer] = {};
m_filledPolysHash[layer] = {};
}
}
m_layerSet = aLayerSet; m_layerSet = aLayerSet;
// Set the single layer parameter. // Set the single layer parameter.
// For keepout zones that can be on many layers, this parameter does not have // For zones that can be on many layers, this parameter does not have
// really meaning and is a bit arbitrary if more than one layer is set. // really meaning and is a bit arbitrary if more than one layer is set.
// But many functions are using it. // But many functions are using it.
// So we need to initialize it to a reasonable value. // So we need to initialize it to a reasonable value.
@ -274,43 +291,24 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
LSET ZONE_CONTAINER::GetLayerSet() const LSET ZONE_CONTAINER::GetLayerSet() const
{ {
// TODO - Enable multi-layer zones for all zone types
// not just keepout zones
if( GetIsKeepout() )
{
return m_layerSet; return m_layerSet;
}
else
{
return LSET( m_Layer );
}
} }
void ZONE_CONTAINER::ViewGetLayers( int aLayers[], int& aCount ) const void ZONE_CONTAINER::ViewGetLayers( int aLayers[], int& aCount ) const
{ {
if( GetIsKeepout() )
{
LSEQ layers = m_layerSet.Seq(); LSEQ layers = m_layerSet.Seq();
for( unsigned int idx = 0; idx < layers.size(); idx++ ) for( unsigned int idx = 0; idx < layers.size(); idx++ )
aLayers[idx] = layers[idx]; aLayers[idx] = layers[idx];
aCount = layers.size(); aCount = layers.size();
}
else
{
aLayers[0] = m_Layer;
aCount = 1;
}
} }
bool ZONE_CONTAINER::IsOnLayer( PCB_LAYER_ID aLayer ) const bool ZONE_CONTAINER::IsOnLayer( PCB_LAYER_ID aLayer ) const
{ {
if( GetIsKeepout() )
return m_layerSet.test( aLayer ); return m_layerSet.test( aLayer );
return BOARD_ITEM::IsOnLayer( aLayer );
} }
@ -538,9 +536,12 @@ int ZONE_CONTAINER::GetLocalClearance( wxString* aSource ) const
} }
bool ZONE_CONTAINER::HitTestFilledArea( const wxPoint& aRefPos ) const bool ZONE_CONTAINER::HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint& aRefPos ) const
{ {
return m_FilledPolysList.Contains( VECTOR2I( aRefPos.x, aRefPos.y ) ); if( !m_FilledPolysList.count( aLayer ) )
return false;
return m_FilledPolysList.at( aLayer ).Contains( VECTOR2I( aRefPos.x, aRefPos.y ) );
} }
@ -642,7 +643,21 @@ void ZONE_CONTAINER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
aList.emplace_back( _( "Priority" ), msg, BLUE ); aList.emplace_back( _( "Priority" ), msg, BLUE );
} }
aList.emplace_back( _( "Layer" ), LayerMaskDescribe( GetBoard(), m_layerSet ), DARKGREEN ); wxString layerDesc;
int count = 0;
for( PCB_LAYER_ID layer : m_layerSet.Seq() )
{
if( count == 0 )
layerDesc = GetBoard()->GetLayerName( layer );
count++;
}
if( count > 1 )
layerDesc.Printf( _( "%s and %d more" ), layerDesc, count - 1 );
aList.emplace_back( _( "Layer" ), layerDesc, DARKGREEN );
if( !m_zoneName.empty() ) if( !m_zoneName.empty() )
aList.emplace_back( _( "Name" ), m_zoneName, DARKMAGENTA ); aList.emplace_back( _( "Name" ), m_zoneName, DARKMAGENTA );
@ -671,9 +686,19 @@ void ZONE_CONTAINER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
msg.Printf( wxT( "%d" ), (int) m_HatchLines.size() ); msg.Printf( wxT( "%d" ), (int) m_HatchLines.size() );
aList.emplace_back( MSG_PANEL_ITEM( _( "Hatch Lines" ), msg, BLUE ) ); aList.emplace_back( MSG_PANEL_ITEM( _( "Hatch Lines" ), msg, BLUE ) );
if( !m_FilledPolysList.IsEmpty() ) PCB_LAYER_ID layer = m_Layer;
// NOTE: This brings in dependence on PCB_EDIT_FRAME to the qa tests, which isn't ideal.
// TODO: Figure out a way for items to know the active layer without the whole edit frame?
#if 0
if( PCB_EDIT_FRAME* pcbframe = dynamic_cast<PCB_EDIT_FRAME*>( aFrame ) )
if( m_FilledPolysList.count( pcbframe->GetActiveLayer() ) )
layer = pcbframe->GetActiveLayer();
#endif
if( !m_FilledPolysList.at( layer ).IsEmpty() )
{ {
msg.Printf( wxT( "%d" ), m_FilledPolysList.TotalVertices() ); msg.Printf( wxT( "%d" ), m_FilledPolysList.at( layer ).TotalVertices() );
aList.emplace_back( MSG_PANEL_ITEM( _( "Corner Count" ), msg, BLUE ) ); aList.emplace_back( MSG_PANEL_ITEM( _( "Corner Count" ), msg, BLUE ) );
} }
} }
@ -688,13 +713,17 @@ void ZONE_CONTAINER::Move( const wxPoint& offset )
Hatch(); Hatch();
m_FilledPolysList.Move( offset ); for( std::pair<PCB_LAYER_ID, SHAPE_POLY_SET> pair : m_FilledPolysList )
pair.second.Move( offset );
for( SEG& seg : m_FillSegmList ) for( std::pair<PCB_LAYER_ID, ZONE_SEGMENT_FILL> pair : m_FillSegmList )
{
for( SEG& seg : pair.second )
{ {
seg.A += VECTOR2I( offset ); seg.A += VECTOR2I( offset );
seg.B += VECTOR2I( offset ); seg.B += VECTOR2I( offset );
} }
}
} }
@ -723,16 +752,20 @@ void ZONE_CONTAINER::Rotate( const wxPoint& centre, double angle )
Hatch(); Hatch();
/* rotate filled areas: */ /* rotate filled areas: */
m_FilledPolysList.Rotate( angle, VECTOR2I( centre ) ); for( std::pair<PCB_LAYER_ID, SHAPE_POLY_SET> pair : m_FilledPolysList )
pair.second.Rotate( angle, VECTOR2I( centre ) );
for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ ) for( std::pair<PCB_LAYER_ID, ZONE_SEGMENT_FILL> pair : m_FillSegmList )
{ {
wxPoint a( m_FillSegmList[ic].A ); for( SEG& seg : pair.second )
{
wxPoint a( seg.A );
RotatePoint( &a, centre, angle ); RotatePoint( &a, centre, angle );
m_FillSegmList[ic].A = a; seg.A = a;
wxPoint b( m_FillSegmList[ic].B ); wxPoint b( seg.B );
RotatePoint( &b, centre, angle ); RotatePoint( &b, centre, angle );
m_FillSegmList[ic].B = a; seg.B = a;
}
} }
} }
@ -756,9 +789,12 @@ void ZONE_CONTAINER::Mirror( const wxPoint& aMirrorRef, bool aMirrorLeftRight )
Hatch(); Hatch();
m_FilledPolysList.Mirror( aMirrorLeftRight, !aMirrorLeftRight, VECTOR2I( aMirrorRef ) ); for( std::pair<PCB_LAYER_ID, SHAPE_POLY_SET> pair : m_FilledPolysList )
pair.second.Mirror( aMirrorLeftRight, !aMirrorLeftRight, VECTOR2I( aMirrorRef ) );
for( SEG& seg : m_FillSegmList ) for( std::pair<PCB_LAYER_ID, ZONE_SEGMENT_FILL> pair : m_FillSegmList )
{
for( SEG& seg : pair.second )
{ {
if( aMirrorLeftRight ) if( aMirrorLeftRight )
{ {
@ -771,6 +807,7 @@ void ZONE_CONTAINER::Mirror( const wxPoint& aMirrorRef, bool aMirrorLeftRight )
MIRROR( seg.B.y, aMirrorRef.y ); MIRROR( seg.B.y, aMirrorRef.y );
} }
} }
}
} }
@ -862,7 +899,21 @@ wxString ZONE_CONTAINER::GetSelectMenuText( EDA_UNITS aUnits ) const
else else
text << GetNetnameMsg(); text << GetNetnameMsg();
return wxString::Format( _( "Zone Outline %s on %s" ), text, GetLayerName() ); wxString layerDesc;
int count = 0;
for( PCB_LAYER_ID layer : m_layerSet.Seq() )
{
if( count == 0 )
layerDesc = GetBoard()->GetLayerName( layer );
count++;
}
if( count > 1 )
layerDesc.Printf( _( "%s and %d more" ), layerDesc, count - 1 );
return wxString::Format( _( "Zone Outline %s on %s" ), text, layerDesc );
} }
@ -1087,7 +1138,8 @@ void ZONE_CONTAINER::SwapData( BOARD_ITEM* aImage )
void ZONE_CONTAINER::CacheTriangulation() void ZONE_CONTAINER::CacheTriangulation()
{ {
m_FilledPolysList.CacheTriangulation(); for( std::pair<PCB_LAYER_ID, SHAPE_POLY_SET> pair : m_FilledPolysList )
pair.second.CacheTriangulation();
} }
@ -1183,13 +1235,18 @@ double ZONE_CONTAINER::CalculateFilledArea()
// Iterate over each outline polygon in the zone and then iterate over // Iterate over each outline polygon in the zone and then iterate over
// each hole it has to compute the total area. // each hole it has to compute the total area.
for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ ) for( std::pair<PCB_LAYER_ID, SHAPE_POLY_SET> pair : m_FilledPolysList )
{ {
m_area += m_FilledPolysList.Outline( i ).Area(); SHAPE_POLY_SET& poly = pair.second;
for( int j = 0; j < m_FilledPolysList.HoleCount( i ); j++ ) for( int i = 0; i < poly.OutlineCount(); i++ )
{ {
m_area -= m_FilledPolysList.Hole( i, j ).Area(); m_area += poly.Outline( i ).Area();
for( int j = 0; j < poly.HoleCount( i ); j++ )
{
m_area -= poly.Hole( i, j ).Area();
}
} }
} }

View File

@ -250,8 +250,17 @@ public:
int GetLocalFlags() const { return m_localFlgs; } int GetLocalFlags() const { return m_localFlgs; }
void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; } void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; }
ZONE_SEGMENT_FILL& FillSegments() { return m_FillSegmList; } ZONE_SEGMENT_FILL& FillSegments( PCB_LAYER_ID aLayer )
const ZONE_SEGMENT_FILL& FillSegments() const { return m_FillSegmList; } {
wxASSERT( m_FillSegmList.count( aLayer ) );
return m_FillSegmList.at( aLayer );
}
const ZONE_SEGMENT_FILL& FillSegments( PCB_LAYER_ID aLayer ) const
{
wxASSERT( m_FillSegmList.count( aLayer ) );
return m_FillSegmList.at( aLayer );
}
SHAPE_POLY_SET* Outline() { return m_Poly; } SHAPE_POLY_SET* Outline() { return m_Poly; }
const SHAPE_POLY_SET* Outline() const { return const_cast< SHAPE_POLY_SET* >( m_Poly ); } const SHAPE_POLY_SET* Outline() const { return const_cast< SHAPE_POLY_SET* >( m_Poly ); }
@ -269,10 +278,11 @@ public:
/** /**
* Function HitTestFilledArea * Function HitTestFilledArea
* tests if the given wxPoint is within the bounds of a filled area of this zone. * tests if the given wxPoint is within the bounds of a filled area of this zone.
* @param aLayer is the layer to test on
* @param aRefPos A wxPoint to test * @param aRefPos A wxPoint to test
* @return bool - true if a hit, else false * @return bool - true if a hit, else false
*/ */
bool HitTestFilledArea( const wxPoint& aRefPos ) const; bool HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint& aRefPos ) const;
/** /**
* Tests if the given point is contained within a cutout of the zone. * Tests if the given point is contained within a cutout of the zone.
@ -305,10 +315,11 @@ public:
* (the full shape is the polygon area with a thick outline) * (the full shape is the polygon area with a thick outline)
* Used in 3D view * Used in 3D view
* Arcs (ends of segments) are approximated by segments * Arcs (ends of segments) are approximated by segments
* @param aLayer is the layer of the zone to retrieve
* @param aCornerBuffer = a buffer to store the polygons * @param aCornerBuffer = a buffer to store the polygons
* @param aError = Maximum error allowed between true arc and polygon approx * @param aError = Maximum error allowed between true arc and polygon approx
*/ */
void TransformSolidAreasShapesToPolygonSet( void TransformSolidAreasShapesToPolygonSet( PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer, int aError = ARC_HIGH_DEF ) const; SHAPE_POLY_SET& aCornerBuffer, int aError = ARC_HIGH_DEF ) const;
/** /**
@ -334,14 +345,16 @@ public:
* Convert the zone shape to a closed polygon * Convert the zone shape to a closed polygon
* Used in filling zones calculations * Used in filling zones calculations
* Circles and arcs are approximated by segments * Circles and arcs are approximated by segments
* @param aLayer is the layer of the filled zone to retrieve
* @param aCornerBuffer = a buffer to store the polygon * @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad * @param aClearanceValue = the clearance around the pad
* @param aError = the maximum deviation from true circle * @param aError = the maximum deviation from true circle
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override; int aClearanceValue, int aError = ARC_HIGH_DEF,
bool ignoreLineWidth = false ) const override;
/** /**
* Function HitTestForCorner * Function HitTestForCorner
@ -568,7 +581,8 @@ public:
*/ */
void ClearFilledPolysList() void ClearFilledPolysList()
{ {
m_FilledPolysList.RemoveAllContours(); for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
pair.second.RemoveAllContours();
} }
/** /**
@ -576,9 +590,10 @@ public:
* returns a reference to the list of filled polygons. * returns a reference to the list of filled polygons.
* @return Reference to the list of filled polygons. * @return Reference to the list of filled polygons.
*/ */
const SHAPE_POLY_SET& GetFilledPolysList() const const SHAPE_POLY_SET& GetFilledPolysList( PCB_LAYER_ID aLayer ) const
{ {
return m_FilledPolysList; wxASSERT( m_FilledPolysList.count( aLayer ) );
return m_FilledPolysList.at( aLayer );
} }
/** (re)create a list of triangles that "fill" the solid areas. /** (re)create a list of triangles that "fill" the solid areas.
@ -590,18 +605,18 @@ public:
* Function SetFilledPolysList * Function SetFilledPolysList
* sets the list of filled polygons. * sets the list of filled polygons.
*/ */
void SetFilledPolysList( SHAPE_POLY_SET& aPolysList ) void SetFilledPolysList( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aPolysList )
{ {
m_FilledPolysList = aPolysList; m_FilledPolysList[aLayer] = aPolysList;
} }
/** /**
* Function SetFilledPolysList * Function SetFilledPolysList
* sets the list of filled polygons. * sets the list of filled polygons.
*/ */
void SetRawPolysList( SHAPE_POLY_SET& aPolysList ) void SetRawPolysList( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aPolysList )
{ {
m_RawPolysList = aPolysList; m_RawPolysList[aLayer] = aPolysList;
} }
@ -643,14 +658,15 @@ public:
void AddPolygon( const SHAPE_LINE_CHAIN& aPolygon ); void AddPolygon( const SHAPE_LINE_CHAIN& aPolygon );
void SetFillSegments( const ZONE_SEGMENT_FILL& aSegments ) void SetFillSegments( PCB_LAYER_ID aLayer, const ZONE_SEGMENT_FILL& aSegments )
{ {
m_FillSegmList = aSegments; m_FillSegmList[aLayer] = aSegments;
} }
SHAPE_POLY_SET& RawPolysList() SHAPE_POLY_SET& RawPolysList( PCB_LAYER_ID aLayer )
{ {
return m_RawPolysList; wxASSERT( m_RawPolysList.count( aLayer ) );
return m_RawPolysList.at( aLayer );
} }
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;
@ -685,6 +701,9 @@ public:
void SetDoNotAllowPads( bool aEnable ) { m_doNotAllowPads = aEnable; } void SetDoNotAllowPads( bool aEnable ) { m_doNotAllowPads = aEnable; }
void SetDoNotAllowFootprints( bool aEnable ) { m_doNotAllowFootprints = aEnable; } void SetDoNotAllowFootprints( bool aEnable ) { m_doNotAllowFootprints = aEnable; }
bool GetRemoveIslands() const { return m_removeIslands; }
void SetRemoveIslands( bool aRemove ) { m_removeIslands = aRemove; }
/** /**
* Hatch related methods * Hatch related methods
*/ */
@ -740,13 +759,25 @@ public:
/** @return the hash value previously calculated by BuildHashValue(). /** @return the hash value previously calculated by BuildHashValue().
* used in zone filling calculations * used in zone filling calculations
*/ */
MD5_HASH GetHashValue() { return m_filledPolysHash; } MD5_HASH GetHashValue( PCB_LAYER_ID aLayer )
{
if( !m_filledPolysHash.count( aLayer ) )
return MD5_HASH();
return m_filledPolysHash.at( aLayer );
}
/** Build the hash value of m_FilledPolysList, and store it internally /** Build the hash value of m_FilledPolysList, and store it internally
* in m_filledPolysHash. * in m_filledPolysHash.
* Used in zone filling calculations, to know if m_FilledPolysList is up to date. * Used in zone filling calculations, to know if m_FilledPolysList is up to date.
*/ */
void BuildHashValue() { m_filledPolysHash = m_FilledPolysList.GetHash(); } void BuildHashValue( PCB_LAYER_ID aLayer )
{
if( !m_FilledPolysList.count( aLayer ) )
return;
m_filledPolysHash[aLayer] = m_FilledPolysList.at( aLayer ).GetHash();
}
@ -797,6 +828,9 @@ protected:
int m_ZoneMinThickness; ///< Minimum thickness value in filled areas. int m_ZoneMinThickness; ///< Minimum thickness value in filled areas.
bool m_FilledPolysUseThickness; ///< outline of filled polygons have thickness. bool m_FilledPolysUseThickness; ///< outline of filled polygons have thickness.
/// True if isolated copper (islands) should be removed after fill (default)
bool m_removeIslands;
/** True when a zone was filled, false after deleting the filled areas. */ /** True when a zone was filled, false after deleting the filled areas. */
bool m_IsFilled; bool m_IsFilled;
@ -845,7 +879,7 @@ protected:
/** Segments used to fill the zone (#m_FillMode ==1 ), when fill zone by segment is used. /** Segments used to fill the zone (#m_FillMode ==1 ), when fill zone by segment is used.
* In this case the segments have #m_ZoneMinThickness width. * In this case the segments have #m_ZoneMinThickness width.
*/ */
ZONE_SEGMENT_FILL m_FillSegmList; std::map<PCB_LAYER_ID, ZONE_SEGMENT_FILL> m_FillSegmList;
/* set of filled polygons used to draw a zone as a filled area. /* set of filled polygons used to draw a zone as a filled area.
* from outlines (m_Poly) but unlike m_Poly these filled polygons have no hole * from outlines (m_Poly) but unlike m_Poly these filled polygons have no hole
@ -855,10 +889,11 @@ protected:
* connecting "holes" with external main outline. In complex cases an outline * connecting "holes" with external main outline. In complex cases an outline
* described by m_Poly can have many filled areas * described by m_Poly can have many filled areas
*/ */
SHAPE_POLY_SET m_FilledPolysList; std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_FilledPolysList;
SHAPE_POLY_SET m_RawPolysList; std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_RawPolysList;
MD5_HASH m_filledPolysHash; // A hash value used in zone filling calculations
// to see if the filled areas are up to date /// A hash value used in zone filling calculations to see if the filled areas are up to date
std::map<PCB_LAYER_ID, MD5_HASH> m_filledPolysHash;
ZONE_HATCH_STYLE m_hatchStyle; // hatch style, see enum above ZONE_HATCH_STYLE m_hatchStyle; // hatch style, see enum above
int m_hatchPitch; // for DIAGONAL_EDGE, distance between 2 hatch lines int m_hatchPitch; // for DIAGONAL_EDGE, distance between 2 hatch lines

View File

@ -431,7 +431,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
if( zone->HitTestForCorner( m_RefPos, accuracy * 2 ) if( zone->HitTestForCorner( m_RefPos, accuracy * 2 )
|| zone->HitTestForEdge( m_RefPos, accuracy ) || zone->HitTestForEdge( m_RefPos, accuracy )
|| ( testFill && zone->HitTestFilledArea( m_RefPos ) ) ) || ( testFill && zone->HitTestFilledArea( layer, m_RefPos ) ) )
{ {
Append( item ); Append( item );
goto exit; goto exit;
@ -495,7 +495,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
if( zone->HitTestForCorner( m_RefPos, accuracy * 2 ) if( zone->HitTestForCorner( m_RefPos, accuracy * 2 )
|| zone->HitTestForEdge( m_RefPos, accuracy ) || zone->HitTestForEdge( m_RefPos, accuracy )
|| ( testFill && zone->HitTestFilledArea( m_RefPos ) ) ) || ( testFill && zone->HitTestFilledArea( layer, m_RefPos ) ) )
{ {
Append2nd( item ); Append2nd( item );
goto exit; goto exit;

View File

@ -181,8 +181,9 @@ bool CN_CONNECTIVITY_ALGO::Add( BOARD_ITEM* aItem )
m_itemMap[zone] = ITEM_MAP_ENTRY(); m_itemMap[zone] = ITEM_MAP_ENTRY();
for( auto zitem : m_itemList.Add( zone ) ) for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
m_itemMap[zone].Link(zitem); for( auto zitem : m_itemList.Add( zone, layer ) )
m_itemMap[zone].Link( zitem );
break; break;
} }
@ -518,9 +519,11 @@ void CN_CONNECTIVITY_ALGO::PropagateNets( BOARD_COMMIT* aCommit )
} }
void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands ) void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone,
PCB_LAYER_ID aLayer,
std::vector<int>& aIslands )
{ {
if( aZone->GetFilledPolysList().IsEmpty() ) if( aZone->GetFilledPolysList( aLayer ).IsEmpty() )
return; return;
aIslands.clear(); aIslands.clear();
@ -536,7 +539,7 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std
{ {
for( auto z : *cluster ) for( auto z : *cluster )
{ {
if( z->Parent() == aZone ) if( z->Parent() == aZone && z->Layer() == aLayer )
{ {
aIslands.push_back( static_cast<CN_ZONE*>(z)->SubpolyIndex() ); aIslands.push_back( static_cast<CN_ZONE*>(z)->SubpolyIndex() );
} }
@ -554,15 +557,23 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLAT
for ( auto& z : aZones ) for ( auto& z : aZones )
{ {
if( !z.m_zone->GetFilledPolysList().IsEmpty() ) for( PCB_LAYER_ID layer : z.m_zone->GetLayerSet().Seq() )
{
if( !z.m_zone->GetFilledPolysList( layer ).IsEmpty() )
{
Add( z.m_zone ); Add( z.m_zone );
break;
}
}
} }
m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK ); m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK );
for ( auto& zone : aZones ) for ( auto& zone : aZones )
{ {
if( zone.m_zone->GetFilledPolysList().IsEmpty() ) PCB_LAYER_ID layer = zone.m_layer;
if( zone.m_zone->GetFilledPolysList( layer ).IsEmpty() )
continue; continue;
for( const auto& cluster : m_connClusters ) for( const auto& cluster : m_connClusters )
@ -571,10 +582,8 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLAT
{ {
for( auto z : *cluster ) for( auto z : *cluster )
{ {
if( z->Parent() == zone.m_zone ) if( z->Parent() == zone.m_zone && z->Layer() == layer )
{ zone.m_islands.push_back( static_cast<CN_ZONE*>( z )->SubpolyIndex() );
zone.m_islands.push_back( static_cast<CN_ZONE*>(z)->SubpolyIndex() );
}
} }
} }
} }
@ -643,10 +652,15 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE* aZoneA, CN_ZONE* aZoneB )
if( aZoneB == aZoneA || refParent == testedParent ) if( aZoneB == aZoneA || refParent == testedParent )
return; return;
if( aZoneA->Layer() != aZoneB->Layer() )
return;
if( aZoneB->Net() != aZoneA->Net() ) if( aZoneB->Net() != aZoneA->Net() )
return; // we only test zones belonging to the same net return; // we only test zones belonging to the same net
const auto& outline = refParent->GetFilledPolysList().COutline( aZoneA->SubpolyIndex() ); PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aZoneA->Layer() );
const auto& outline = refParent->GetFilledPolysList( layer ).COutline( aZoneA->SubpolyIndex() );
for( int i = 0; i < outline.PointCount(); i++ ) for( int i = 0; i < outline.PointCount(); i++ )
{ {
@ -658,7 +672,8 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE* aZoneA, CN_ZONE* aZoneB )
} }
} }
const auto& outline2 = testedParent->GetFilledPolysList().COutline( aZoneB->SubpolyIndex() ); const auto& outline2 =
testedParent->GetFilledPolysList( layer ).COutline( aZoneB->SubpolyIndex() );
for( int i = 0; i < outline2.PointCount(); i++ ) for( int i = 0; i < outline2.PointCount(); i++ )
{ {

View File

@ -243,7 +243,8 @@ public:
*/ */
void PropagateNets( BOARD_COMMIT* aCommit = nullptr ); void PropagateNets( BOARD_COMMIT* aCommit = nullptr );
void FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands ); void FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
std::vector<int>& aIslands );
/** /**
* Finds the copper islands that are not connected to a net. These are added to * Finds the copper islands that are not connected to a net. These are added to

View File

@ -235,7 +235,10 @@ int CONNECTIVITY_DATA::GetNetCount() const
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone,
std::vector<int>& aIslands ) std::vector<int>& aIslands )
{ {
// TODO(JE) ZONES
#if 0
m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands ); m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands );
#endif
} }
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones ) void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )

View File

@ -60,13 +60,21 @@ struct CN_DISJOINT_NET_ENTRY
VECTOR2I anchorA, anchorB; VECTOR2I anchorA, anchorB;
}; };
/**
* A structure used for filling a copper zone on one layer.
* Multilayer zones will have one of these for each active layer.
*/
struct CN_ZONE_ISOLATED_ISLAND_LIST struct CN_ZONE_ISOLATED_ISLAND_LIST
{ {
CN_ZONE_ISOLATED_ISLAND_LIST( ZONE_CONTAINER* aZone ) : CN_ZONE_ISOLATED_ISLAND_LIST( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer ) :
m_zone( aZone ) m_zone( aZone ),
m_layer( aLayer )
{} {}
ZONE_CONTAINER* m_zone; ZONE_CONTAINER* m_zone;
PCB_LAYER_ID m_layer;
std::vector<int> m_islands; std::vector<int> m_islands;
}; };

View File

@ -162,7 +162,7 @@ int CN_ZONE::AnchorCount() const
return 0; return 0;
const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() ); const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() );
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex ); const auto& outline = zone->GetFilledPolysList( m_layer ).COutline( m_subpolyIndex );
return outline.PointCount() ? 1 : 0; return outline.PointCount() ? 1 : 0;
} }
@ -173,8 +173,8 @@ const VECTOR2I CN_ZONE::GetAnchor( int n ) const
if( !Valid() ) if( !Valid() )
return VECTOR2I(); return VECTOR2I();
const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() ); const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() );
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex ); const auto& outline = zone->GetFilledPolysList( m_layer ).COutline( m_subpolyIndex );
return outline.CPoint( 0 ); return outline.CPoint( 0 );
} }
@ -265,22 +265,22 @@ CN_ITEM* CN_LIST::Add( ARC* aArc )
return item; return item;
} }
const std::vector<CN_ITEM*> CN_LIST::Add( ZONE_CONTAINER* zone ) const std::vector<CN_ITEM*> CN_LIST::Add( ZONE_CONTAINER* zone, PCB_LAYER_ID aLayer )
{ {
const auto& polys = zone->GetFilledPolysList(); const auto& polys = zone->GetFilledPolysList( aLayer );
std::vector<CN_ITEM*> rv; std::vector<CN_ITEM*> rv;
for( int j = 0; j < polys.OutlineCount(); j++ ) for( int j = 0; j < polys.OutlineCount(); j++ )
{ {
CN_ZONE* zitem = new CN_ZONE( zone, false, j ); CN_ZONE* zitem = new CN_ZONE( zone, aLayer, false, j );
const auto& outline = zone->GetFilledPolysList().COutline( j ); const auto& outline = zone->GetFilledPolysList( aLayer ).COutline( j );
for( int k = 0; k < outline.PointCount(); k++ ) for( int k = 0; k < outline.PointCount(); k++ )
zitem->AddAnchor( outline.CPoint( k ) ); zitem->AddAnchor( outline.CPoint( k ) );
m_items.push_back( zitem ); m_items.push_back( zitem );
zitem->SetLayer( zone->GetLayer() ); zitem->SetLayer( aLayer );
addItemtoTree( zitem ); addItemtoTree( zitem );
rv.push_back( zitem ); rv.push_back( zitem );
SetDirty(); SetDirty();
@ -360,7 +360,8 @@ bool CN_ANCHOR::IsDangling() const
{ {
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item->Parent() ); ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item->Parent() );
if( zone->HitTestFilledArea( (wxPoint) Pos() ) ) if( zone->HitTestFilledArea( static_cast<PCB_LAYER_ID>( item->Layer() ),
static_cast<wxPoint>( Pos() ) ) )
connected_count++; connected_count++;
} }
else if( item->Parent()->HitTest( (wxPoint) Pos() ) ) else if( item->Parent()->HitTest( (wxPoint) Pos() ) )
@ -384,7 +385,8 @@ int CN_ANCHOR::ConnectedItemsCount() const
{ {
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item->Parent() ); ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item->Parent() );
if( zone->HitTestFilledArea( wxPoint( Pos().x, Pos().y ) ) ) if( zone->HitTestFilledArea( static_cast<PCB_LAYER_ID>( item->Layer() ),
wxPoint( Pos().x, Pos().y ) ) )
connected_count++; connected_count++;
} }
else if( item->Parent()->HitTest( wxPoint( Pos().x, Pos().y ) ) ) else if( item->Parent()->HitTest( wxPoint( Pos().x, Pos().y ) ) )

View File

@ -352,11 +352,12 @@ typedef std::shared_ptr<CN_ITEM> CN_ITEM_PTR;
class CN_ZONE : public CN_ITEM class CN_ZONE : public CN_ITEM
{ {
public: public:
CN_ZONE( ZONE_CONTAINER* aParent, bool aCanChangeNet, int aSubpolyIndex ) : CN_ZONE( ZONE_CONTAINER* aParent, PCB_LAYER_ID aLayer, bool aCanChangeNet, int aSubpolyIndex ) :
CN_ITEM( aParent, aCanChangeNet ), CN_ITEM( aParent, aCanChangeNet ),
m_subpolyIndex( aSubpolyIndex ) m_subpolyIndex( aSubpolyIndex ),
m_layer( aLayer )
{ {
SHAPE_LINE_CHAIN outline = aParent->GetFilledPolysList().COutline( aSubpolyIndex ); SHAPE_LINE_CHAIN outline = aParent->GetFilledPolysList( aLayer ).COutline( aSubpolyIndex );
outline.SetClosed( true ); outline.SetClosed( true );
outline.Simplify(); outline.Simplify();
@ -396,6 +397,7 @@ private:
std::vector<VECTOR2I> m_testOutlinePoints; std::vector<VECTOR2I> m_testOutlinePoints;
std::unique_ptr<POLY_GRID_PARTITION> m_cachedPoly; std::unique_ptr<POLY_GRID_PARTITION> m_cachedPoly;
int m_subpolyIndex; int m_subpolyIndex;
PCB_LAYER_ID m_layer;
}; };
class CN_LIST class CN_LIST
@ -500,7 +502,7 @@ public:
CN_ITEM* Add( VIA* via ); CN_ITEM* Add( VIA* via );
const std::vector<CN_ITEM*> Add( ZONE_CONTAINER* zone ); const std::vector<CN_ITEM*> Add( ZONE_CONTAINER* zone, PCB_LAYER_ID aLayer );
}; };
class CN_CLUSTER class CN_CLUSTER

View File

@ -444,19 +444,10 @@ void DIALOG_COPPER_ZONE::OnLayerSelection( wxDataViewEvent& event )
int row = m_layers->ItemToRow( event.GetItem() ); int row = m_layers->ItemToRow( event.GetItem() );
if( m_layers->GetToggleValue( row, 0 ) )
{
wxVariant layerID; wxVariant layerID;
m_layers->GetValue( layerID, row, 2 ); m_layers->GetValue( layerID, row, 2 );
m_settings.m_CurrentZone_Layer = ToLAYER_ID( layerID.GetInteger() ); m_settings.m_Layers.set( ToLAYER_ID( layerID.GetInteger() ),
m_layers->GetToggleValue( row, 0 ) );
// Turn all other checkboxes off.
for( int ii = 0; ii < m_layers->GetItemCount(); ++ii )
{
if( ii != row )
m_layers->SetToggleValue( false, ii, 0 );
}
}
} }

View File

@ -194,20 +194,11 @@ void DIALOG_NON_COPPER_ZONES_EDITOR::OnLayerSelection( wxDataViewEvent& event )
return; return;
int row = m_layers->ItemToRow( event.GetItem() ); int row = m_layers->ItemToRow( event.GetItem() );
bool val = m_layers->GetToggleValue( row, 0 );
if( m_layers->GetToggleValue( row, 0 ) )
{
wxVariant layerID; wxVariant layerID;
m_layers->GetValue( layerID, row, 2 ); m_layers->GetValue( layerID, row, 2 );
m_settings.m_CurrentZone_Layer = ToLAYER_ID( layerID.GetInteger() ); m_settings.m_Layers.set( ToLAYER_ID( layerID.GetInteger() ), val );
// Turn all other checkboxes off.
for( int ii = 0; ii < m_layers->GetItemCount(); ++ii )
{
if( ii != row )
m_layers->SetToggleValue( false, ii, 0 );
}
}
} }

View File

@ -1394,8 +1394,10 @@ wxPoint DRC::GetLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone )
{ {
SHAPE_POLY_SET* conflictOutline; SHAPE_POLY_SET* conflictOutline;
PCB_LAYER_ID l = aTrack->GetLayer();
if( aConflictZone->IsFilled() ) if( aConflictZone->IsFilled() )
conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList() ); conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList( l ) );
else else
conflictOutline = aConflictZone->Outline(); conflictOutline = aConflictZone->Outline();

View File

@ -574,10 +574,12 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
for( ZONE_CONTAINER* zone : m_pcb->Zones() ) for( ZONE_CONTAINER* zone : m_pcb->Zones() )
{ {
if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() ) if( !( refLayerSet & zone->GetLayerSet() ).any() || zone->GetIsKeepout() )
continue; continue;
if( !( refLayerSet & zone->GetLayerSet() ).any() ) for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
if( zone->GetFilledPolysList( layer ).IsEmpty() )
continue; continue;
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
@ -586,7 +588,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource ); int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource );
int widths = refSegWidth / 2; int widths = refSegWidth / 2;
int center2centerAllowed = minClearance + widths; int center2centerAllowed = minClearance + widths;
SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() ); SHAPE_POLY_SET* outline =
const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList( layer ) );
SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg ); SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg );
@ -613,6 +616,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
} }
} }
} }
}
/***********************************************/ /***********************************************/
/* Phase 4: test DRC with to board edge */ /* Phase 4: test DRC with to board edge */

View File

@ -271,7 +271,7 @@ bool DRC_KEEPOUT_TESTER::checkPads( MODULE* aModule )
slotEnd += pad->GetPosition(); slotEnd += pad->GetPosition();
SEG slotSeg( slotStart, slotEnd ); SEG slotSeg( slotStart, slotEnd );
SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &m_zone->GetFilledPolysList() ); SHAPE_POLY_SET* outline = m_zone->Outline();
SEG::ecoord center2center_sq = outline->SquaredDistance( slotSeg ); SEG::ecoord center2center_sq = outline->SquaredDistance( slotSeg );
if( center2center_sq <= SEG::Square( slotWidth) ) if( center2center_sq <= SEG::Square( slotWidth) )

View File

@ -447,8 +447,10 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
} }
else if( ZONE_CONTAINER* zone = dyn_cast<ZONE_CONTAINER*>( item ) ) else if( ZONE_CONTAINER* zone = dyn_cast<ZONE_CONTAINER*>( item ) )
{ {
const auto layerName = m_board->GetLayerName( zone->GetLayer() ); for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
SHAPE_POLY_SET filledShape = zone->GetFilledPolysList(); {
const auto layerName = m_board->GetLayerName( layer );
SHAPE_POLY_SET filledShape = zone->GetFilledPolysList( layer );
filledShape.Simplify( SHAPE_POLY_SET::PM_FAST ); filledShape.Simplify( SHAPE_POLY_SET::PM_FAST );
@ -458,7 +460,8 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
auto p0 = outl.CPoint( 0 ); auto p0 = outl.CPoint( 0 );
m_out->Print( 1, "{POLYGON T=POUR L=\"%s\" ID=%d X=%.10f Y=%.10f\n", m_out->Print( 1, "{POLYGON T=POUR L=\"%s\" ID=%d X=%.10f Y=%.10f\n",
(const char*) layerName.c_str(), m_polyId, iu2hyp( p0.x ), iu2hyp( p0.y ) ); (const char*) layerName.c_str(), m_polyId, iu2hyp( p0.x ),
iu2hyp( p0.y ) );
for( int v = 0; v < outl.PointCount(); v++ ) for( int v = 0; v < outl.PointCount(); v++ )
{ {
@ -474,8 +477,8 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
const auto& holeShape = filledShape.CHole( i, h ); const auto& holeShape = filledShape.CHole( i, h );
auto ph0 = holeShape.CPoint( 0 ); auto ph0 = holeShape.CPoint( 0 );
m_out->Print( 1, "{POLYVOID ID=%d X=%.10f Y=%.10f\n", m_polyId, iu2hyp( ph0.x ), m_out->Print( 1, "{POLYVOID ID=%d X=%.10f Y=%.10f\n", m_polyId,
iu2hyp( ph0.y ) ); iu2hyp( ph0.x ), iu2hyp( ph0.y ) );
for( int v = 0; v < holeShape.PointCount(); v++ ) for( int v = 0; v < holeShape.PointCount(); v++ )
{ {
@ -484,7 +487,8 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
iu2hyp( holeShape.CPoint( v ).y ) ); iu2hyp( holeShape.CPoint( v ).y ) );
} }
m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n", iu2hyp( ph0.x ), iu2hyp( ph0.y ) ); m_out->Print(
2, "(LINE X=%.10f Y=%.10f)\n", iu2hyp( ph0.x ), iu2hyp( ph0.y ) );
m_out->Print( 1, "}\n" ); m_out->Print( 1, "}\n" );
} }
@ -492,6 +496,7 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
} }
} }
} }
}
return true; return true;
} }

View File

@ -1023,9 +1023,11 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
{ {
ZONE_CONTAINER* zone = aPcb->GetArea( ii ); ZONE_CONTAINER* zone = aPcb->GetArea( ii );
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
VRML_LAYER* vl; VRML_LAYER* vl;
if( !GetLayer( aModel, zone->GetLayer(), &vl ) ) if( !GetLayer( aModel, layer, &vl ) )
continue; continue;
// fixme: this modifies the board where it shouldn't, but I don't have the time // fixme: this modifies the board where it shouldn't, but I don't have the time
@ -1037,7 +1039,7 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
filler.Fill( { zone } ); filler.Fill( { zone } );
} }
const SHAPE_POLY_SET& poly = zone->GetFilledPolysList(); const SHAPE_POLY_SET& poly = zone->GetFilledPolysList( layer );
for( int i = 0; i < poly.OutlineCount(); i++ ) for( int i = 0; i < poly.OutlineCount(); i++ )
{ {
@ -1047,15 +1049,15 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
for( int j = 0; j < outline.PointCount(); j++ ) for( int j = 0; j < outline.PointCount(); j++ )
{ {
if( !vl->AddVertex( seg, (double)outline.CPoint( j ).x * BOARD_SCALE, if( !vl->AddVertex( seg, (double) outline.CPoint( j ).x * BOARD_SCALE,
-((double)outline.CPoint( j ).y * BOARD_SCALE ) ) ) -( (double) outline.CPoint( j ).y * BOARD_SCALE ) ) )
throw( std::runtime_error( vl->GetError() ) ); throw( std::runtime_error( vl->GetError() ) );
} }
vl->EnsureWinding( seg, false ); vl->EnsureWinding( seg, false );
} }
} }
}
} }

View File

@ -1981,7 +1981,9 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
} }
// Save the PolysList (filled areas) // Save the PolysList (filled areas)
const SHAPE_POLY_SET& fv = aZone->GetFilledPolysList(); for( PCB_LAYER_ID layer : aZone->GetLayerSet().Seq() )
{
const SHAPE_POLY_SET& fv = aZone->GetFilledPolysList( layer );
newLine = 0; newLine = 0;
if( !fv.IsEmpty() ) if( !fv.IsEmpty() )
@ -1994,19 +1996,20 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
if( new_polygon ) if( new_polygon )
{ {
newLine = 0; newLine = 0;
m_out->Print( aNestLevel+1, "(filled_polygon\n" ); m_out->Print( aNestLevel + 1, "(filled_polygon\n" );
m_out->Print( aNestLevel+2, "(pts\n" ); m_out->Print( aNestLevel + 2, "(layer %s)\n",
TO_UTF8( BOARD::GetStandardLayerName( layer ) ) );
m_out->Print( aNestLevel + 2, "(pts\n" );
new_polygon = false; new_polygon = false;
is_closed = false; is_closed = false;
} }
if( newLine == 0 ) if( newLine == 0 )
m_out->Print( aNestLevel+3, "(xy %s %s)", m_out->Print( aNestLevel + 3, "(xy %s %s)",
FormatInternalUnits( it->x ).c_str(), FormatInternalUnits( it->x ).c_str(),
FormatInternalUnits( it->y ).c_str() ); FormatInternalUnits( it->y ).c_str() );
else else
m_out->Print( 0, " (xy %s %s)", m_out->Print( 0, " (xy %s %s)", FormatInternalUnits( it->x ).c_str(),
FormatInternalUnits( it->x ) .c_str(),
FormatInternalUnits( it->y ).c_str() ); FormatInternalUnits( it->y ).c_str() );
if( newLine < 4 ) if( newLine < 4 )
@ -2026,31 +2029,34 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
if( newLine != 0 ) if( newLine != 0 )
m_out->Print( 0, "\n" ); m_out->Print( 0, "\n" );
m_out->Print( aNestLevel+2, ")\n" ); m_out->Print( aNestLevel + 2, ")\n" );
m_out->Print( aNestLevel+1, ")\n" ); m_out->Print( aNestLevel + 1, ")\n" );
new_polygon = true; new_polygon = true;
} }
} }
if( !is_closed ) // Should not happen, but... if( !is_closed ) // Should not happen, but...
m_out->Print( aNestLevel+1, ")\n" ); m_out->Print( aNestLevel + 1, ")\n" );
} }
// Save the filling segments list // Save the filling segments list
const auto& segs = aZone->FillSegments(); const auto& segs = aZone->FillSegments( layer );
if( segs.size() ) if( segs.size() )
{ {
m_out->Print( aNestLevel+1, "(fill_segments\n" ); m_out->Print( aNestLevel + 1, "(fill_segments\n" );
m_out->Print( aNestLevel + 2, "(layer %s)\n",
TO_UTF8( BOARD::GetStandardLayerName( layer ) ) );
for( ZONE_SEGMENT_FILL::const_iterator it = segs.begin(); it != segs.end(); ++it ) for( ZONE_SEGMENT_FILL::const_iterator it = segs.begin(); it != segs.end(); ++it )
{ {
m_out->Print( aNestLevel+2, "(pts (xy %s) (xy %s))\n", m_out->Print( aNestLevel + 2, "(pts (xy %s) (xy %s))\n",
FormatInternalUnits( wxPoint( it->A ) ).c_str(), FormatInternalUnits( wxPoint( it->A ) ).c_str(),
FormatInternalUnits( wxPoint( it->B ) ).c_str() ); FormatInternalUnits( wxPoint( it->B ) ).c_str() );
} }
m_out->Print( aNestLevel+1, ")\n" ); m_out->Print( aNestLevel + 1, ")\n" );
}
} }
m_out->Print( aNestLevel, ")\n" ); m_out->Print( aNestLevel, ")\n" );

View File

@ -70,7 +70,7 @@ class TEXTE_PCB;
//#define SEXPR_BOARD_FILE_VERSION 20200512 // page -> paper //#define SEXPR_BOARD_FILE_VERSION 20200512 // page -> paper
//#define SEXPR_BOARD_FILE_VERSION 20200518 // save hole_to_hole_min //#define SEXPR_BOARD_FILE_VERSION 20200518 // save hole_to_hole_min
//#define SEXPR_BOARD_FILE_VERSION 20200614 // Add support for fp_rects and gr_rects //#define SEXPR_BOARD_FILE_VERSION 20200614 // Add support for fp_rects and gr_rects
#define SEXPR_BOARD_FILE_VERSION 20200623 // Add name property to zones #define SEXPR_BOARD_FILE_VERSION 20200623 // Multilayer zones and zone name property
#define CTL_STD_LAYER_NAMES (1 << 0) ///< Use English Standard layer names #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) #define CTL_OMIT_NETS (1 << 1) ///< Omit pads net names (useless in library)

View File

@ -2657,7 +2657,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER()
makeNewOutline = end_contour; makeNewOutline = end_contour;
} }
zc->SetFilledPolysList( polysList ); zc->SetFilledPolysList( zc->GetLayer(), polysList );
} }
else if( TESTLINE( "$FILLSEGMENTS" ) ) else if( TESTLINE( "$FILLSEGMENTS" ) )
@ -2673,7 +2673,8 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER()
BIU ex = biuParse( data, &data ); BIU ex = biuParse( data, &data );
BIU ey = biuParse( data ); BIU ey = biuParse( data );
zc->FillSegments().push_back( SEG( VECTOR2I( sx, sy ), VECTOR2I( ex, ey ) ) ); zc->FillSegments( zc->GetLayer() )
.push_back( SEG( VECTOR2I( sx, sy ), VECTOR2I( ex, ey ) ) );
} }
} }

View File

@ -1077,7 +1077,9 @@ void PCB_PAINTER::draw( const MODULE* aModule, int aLayer )
void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer ) void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
{ {
if( !aZone->IsOnLayer( (PCB_LAYER_ID) aLayer ) ) PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer );
if( !aZone->IsOnLayer( layer ) )
return; return;
const COLOR4D& color = m_pcbSettings.GetColor( aZone, aLayer ); const COLOR4D& color = m_pcbSettings.GetColor( aZone, aLayer );
@ -1119,7 +1121,7 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
// Draw the filling // Draw the filling
if( displayMode != PCB_RENDER_SETTINGS::DZ_HIDE_FILLED ) if( displayMode != PCB_RENDER_SETTINGS::DZ_HIDE_FILLED )
{ {
const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList(); const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList( layer );
if( polySet.OutlineCount() == 0 ) // Nothing to draw if( polySet.OutlineCount() == 0 ) // Nothing to draw
return; return;
@ -1143,7 +1145,6 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
m_gal->DrawPolygon( polySet ); m_gal->DrawPolygon( polySet );
} }
} }

View File

@ -3723,8 +3723,10 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
wxString netnameFromfile; // the zone net name find in file wxString netnameFromfile; // the zone net name find in file
// bigger scope since each filled_polygon is concatenated in here // bigger scope since each filled_polygon is concatenated in here
SHAPE_POLY_SET pts; std::map<PCB_LAYER_ID, SHAPE_POLY_SET> pts;
bool inModule = false; bool inModule = false;
PCB_LAYER_ID filledLayer;
bool addedFilledPolygons = false;
if( dynamic_cast<MODULE*>( aParent ) ) // The zone belongs a footprint if( dynamic_cast<MODULE*>( aParent ) ) // The zone belongs a footprint
inModule = true; inModule = true;
@ -3771,8 +3773,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
NeedRIGHT(); NeedRIGHT();
break; break;
case T_layers: // keyword for zones that can live on a set of layer case T_layers: // keyword for zones that can live on a set of layers
// currently: keepout zones
zone->SetLayerSet( parseBoardItemLayersAsMask() ); zone->SetLayerSet( parseBoardItemLayersAsMask() );
break; break;
@ -4069,17 +4070,40 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
NeedLEFT(); NeedLEFT();
token = NextTok(); token = NextTok();
if( token == T_layer )
{
filledLayer = parseBoardItemLayer();
NeedRIGHT();
token = NextTok();
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
}
else
{
filledLayer = zone->GetLayer();
}
if( token != T_pts ) if( token != T_pts )
Expecting( T_pts ); Expecting( T_pts );
pts.NewOutline(); if( !pts.count( filledLayer ) )
pts[filledLayer] = SHAPE_POLY_SET();
SHAPE_POLY_SET& poly = pts.at( filledLayer );
poly.NewOutline();
for( token = NextTok(); token != T_RIGHT; token = NextTok() ) for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{ {
pts.Append( parseXY() ); poly.Append( parseXY() );
} }
NeedRIGHT(); NeedRIGHT();
addedFilledPolygons |= !poly.IsEmpty();
} }
break; break;
@ -4094,6 +4118,22 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
token = NextTok(); token = NextTok();
if( token == T_layer )
{
filledLayer = parseBoardItemLayer();
NeedRIGHT();
token = NextTok();
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
}
else
{
filledLayer = zone->GetLayer();
}
if( token != T_pts ) if( token != T_pts )
Expecting( T_pts ); Expecting( T_pts );
@ -4102,7 +4142,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
segs.push_back( segment ); segs.push_back( segment );
} }
zone->SetFillSegments( segs ); zone->SetFillSegments( filledLayer, segs );
} }
break; break;
@ -4132,9 +4172,11 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
zone->SetHatch( hatchStyle, hatchPitch, true ); zone->SetHatch( hatchStyle, hatchPitch, true );
} }
if( !pts.IsEmpty() ) if( addedFilledPolygons )
{ {
zone->SetFilledPolysList( pts ); for( auto& pair : pts )
zone->SetFilledPolysList( pair.first, pair.second );
zone->CalculateFilledArea(); zone->CalculateFilledArea();
} }

View File

@ -479,23 +479,32 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
// Plot all zones of the same layer & net together so we don't end up with divots where // Plot all zones of the same layer & net together so we don't end up with divots where
// zones touch each other. // zones touch each other.
std::set<ZONE_CONTAINER*> plotted; std::set<std::pair<PCB_LAYER_ID, ZONE_CONTAINER*>> plotted;
for( ZONE_CONTAINER* zone : aBoard->Zones() ) for( ZONE_CONTAINER* zone : aBoard->Zones() )
{ {
if( !aLayerMask[ zone->GetLayer() ] || plotted.count( zone ) ) for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
auto pair = std::make_pair( layer, zone );
if( !aLayerMask[layer] || plotted.count( pair ) )
continue; continue;
plotted.insert( zone ); plotted.insert( pair );
SHAPE_POLY_SET aggregateArea = zone->GetFilledPolysList(); SHAPE_POLY_SET aggregateArea = zone->GetFilledPolysList( layer );
bool needFracture = false; // If 2 or more filled areas are combined, resulting bool needFracture = false; // If 2 or more filled areas are combined, resulting
// aggregateArea will be simplified and fractured // aggregateArea will be simplified and fractured
// (Long calculation time) // (Long calculation time)
for( ZONE_CONTAINER* candidate : aBoard->Zones() ) for( ZONE_CONTAINER* candidate : aBoard->Zones() )
{ {
if( !aLayerMask[ candidate->GetLayer() ] || plotted.count( candidate ) ) if( !candidate->IsOnLayer( layer ) )
continue;
auto candidate_pair = std::make_pair( layer, candidate );
if( plotted.count( candidate_pair ) )
continue; continue;
if( candidate->GetNetCode() != zone->GetNetCode() ) if( candidate->GetNetCode() != zone->GetNetCode() )
@ -510,12 +519,12 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
// Should not happens, because usually the same option is used for filling // Should not happens, because usually the same option is used for filling
continue; continue;
if( zone->GetFilledPolysUseThickness() && if( zone->GetFilledPolysUseThickness()
( candidate->GetMinThickness() != zone->GetMinThickness() ) ) && ( candidate->GetMinThickness() != zone->GetMinThickness() ) )
continue; continue;
plotted.insert( candidate ); plotted.insert( candidate_pair );
aggregateArea.Append( candidate->GetFilledPolysList() ); aggregateArea.Append( candidate->GetFilledPolysList( layer ) );
needFracture = true; needFracture = true;
} }
@ -527,6 +536,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
itemplotter.PlotFilledAreas( zone, aggregateArea ); itemplotter.PlotFilledAreas( zone, aggregateArea );
} }
}
aPlotter->EndBlock( NULL ); aPlotter->EndBlock( NULL );
// Adding drill marks, if required and if the plotter is able to plot them: // Adding drill marks, if required and if the plotter is able to plot them:

View File

@ -1774,7 +1774,8 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
for( ZONE_CONTAINER* zone : m_board->Zones() ) for( ZONE_CONTAINER* zone : m_board->Zones() )
{ {
if( zone->HitTestFilledArea( position ) ) for( PCB_LAYER_ID layer : LSET( zone->GetLayerSet() & lset ).Seq() )
if( zone->HitTestFilledArea( layer, position ) )
foundZones.push_back( zone ); foundZones.push_back( zone );
} }

View File

@ -1118,7 +1118,7 @@ int PCB_EDITOR_CONTROL::ZoneDuplicate( const TOOL_EVENT& aEvent )
// offset it a bit so it can more easily be picked. // offset it a bit so it can more easily be picked.
if( oldZone->GetIsKeepout() && ( oldZone->GetLayerSet() == zoneSettings.m_Layers ) ) if( oldZone->GetIsKeepout() && ( oldZone->GetLayerSet() == zoneSettings.m_Layers ) )
newZone->Move( wxPoint( IU_PER_MM, IU_PER_MM ) ); newZone->Move( wxPoint( IU_PER_MM, IU_PER_MM ) );
else if( !oldZone->GetIsKeepout() && ( oldZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) ) else if( !oldZone->GetIsKeepout() && zoneSettings.m_Layers.test( oldZone->GetLayer() ) )
newZone->Move( wxPoint( IU_PER_MM, IU_PER_MM ) ); newZone->Move( wxPoint( IU_PER_MM, IU_PER_MM ) );
commit.Add( newZone.release() ); commit.Add( newZone.release() );

View File

@ -1560,12 +1560,9 @@ bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
if( zoneInFootprint && !m_editModules && !checkVisibilityOnly ) if( zoneInFootprint && !m_editModules && !checkVisibilityOnly )
return false; return false;
// Keepout zones can exist on multiple layers! // zones can exist on multiple layers!
{ {
auto* zone = static_cast<const ZONE_CONTAINER*>( aItem ); auto* zone = static_cast<const ZONE_CONTAINER*>( aItem );
if( zone->GetIsKeepout() )
{
auto zoneLayers = zone->GetLayerSet().Seq(); auto zoneLayers = zone->GetLayerSet().Seq();
for( unsigned int i = 0; i < zoneLayers.size(); i++ ) for( unsigned int i = 0; i < zoneLayers.size(); i++ )
@ -1580,7 +1577,6 @@ bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
return false; return false;
} }
} }
}
break; break;
case PCB_TRACE_T: case PCB_TRACE_T:

View File

@ -58,7 +58,7 @@ std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createNewZone( bool aKeepout
// Get the current default settings for zones // Get the current default settings for zones
ZONE_SETTINGS zoneInfo = frame.GetZoneSettings(); ZONE_SETTINGS zoneInfo = frame.GetZoneSettings();
zoneInfo.m_CurrentZone_Layer = m_params.m_layer; zoneInfo.m_Layers.reset().set( m_params.m_layer ); // TODO(JE) multilayer defaults?
zoneInfo.m_NetcodeSelection = zoneInfo.m_NetcodeSelection =
board.GetHighLightNetCodes().empty() ? -1 : *board.GetHighLightNetCodes().begin(); board.GetHighLightNetCodes().empty() ? -1 : *board.GetHighLightNetCodes().begin();
zoneInfo.SetIsKeepout( m_params.m_keepout ); zoneInfo.SetIsKeepout( m_params.m_keepout );
@ -87,7 +87,8 @@ std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createNewZone( bool aKeepout
dialogResult = InvokeKeepoutAreaEditor( &frame, &zoneInfo ); dialogResult = InvokeKeepoutAreaEditor( &frame, &zoneInfo );
else else
{ {
if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) ) // TODO(JE) combine these dialogs?
if( ( zoneInfo.m_Layers & LSET::AllCuMask() ).any() )
dialogResult = InvokeCopperZonesEditor( &frame, &zoneInfo ); dialogResult = InvokeCopperZonesEditor( &frame, &zoneInfo );
else else
dialogResult = InvokeNonCopperZonesEditor( &frame, &zoneInfo ); dialogResult = InvokeNonCopperZonesEditor( &frame, &zoneInfo );

View File

@ -130,10 +130,13 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
// calculate the hash value for filled areas. it will be used later // calculate the hash value for filled areas. it will be used later
// to know if the current filled areas are up to date // to know if the current filled areas are up to date
zone->BuildHashValue(); for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
zone->BuildHashValue( layer );
// Add the zone to the list of zones to test or refill // Add the zone to the list of zones to test or refill
toFill.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST(zone) ); toFill.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST( zone, layer ) );
}
// Remove existing fill first to prevent drawing invalid polygons // Remove existing fill first to prevent drawing invalid polygons
// on some platforms // on some platforms
@ -151,13 +154,16 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ ) for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
{ {
PCB_LAYER_ID layer = toFill[i].m_layer;
ZONE_CONTAINER* zone = toFill[i].m_zone; ZONE_CONTAINER* zone = toFill[i].m_zone;
zone->SetFilledPolysUseThickness( filledPolyWithOutline );
SHAPE_POLY_SET rawPolys, finalPolys;
fillSingleZone( zone, rawPolys, finalPolys );
zone->SetRawPolysList( rawPolys ); zone->SetFilledPolysUseThickness( filledPolyWithOutline );
zone->SetFilledPolysList( finalPolys );
SHAPE_POLY_SET rawPolys, finalPolys;
fillSingleZone( zone, layer, rawPolys, finalPolys );
zone->SetRawPolysList( layer, rawPolys );
zone->SetFilledPolysList( layer, finalPolys );
zone->SetIsFilled( true ); zone->SetIsFilled( true );
if( m_progressReporter ) if( m_progressReporter )
@ -207,14 +213,13 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
for( auto& zone : toFill ) for( auto& zone : toFill )
{ {
std::sort( zone.m_islands.begin(), zone.m_islands.end(), std::greater<int>() ); std::sort( zone.m_islands.begin(), zone.m_islands.end(), std::greater<int>() );
SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList(); SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList( zone.m_layer );
// Remove solid areas outside the board cutouts and the insulated islands // Remove solid areas outside the board cutouts and the insulated islands
// only zones with net code > 0 can have insulated islands by definition // only zones with net code > 0 can have insulated islands by definition
if( zone.m_zone->GetNetCode() > 0 ) if( zone.m_zone->GetNetCode() > 0 && zone.m_zone->GetRemoveIslands() )
{ {
// solid areas outside the board cutouts are also removed, because they are usually // solid areas outside the board cutouts are also removed, because they are usually insulated islands
// insulated islands
for( auto idx : zone.m_islands ) for( auto idx : zone.m_islands )
{ {
poly.DeletePolygon( idx ); poly.DeletePolygon( idx );
@ -231,8 +236,8 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
{ {
for( int idx = 0; idx < poly.OutlineCount(); ) for( int idx = 0; idx < poly.OutlineCount(); )
{ {
if( poly.Polygon( idx ).empty() || if( poly.Polygon( idx ).empty()
!m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) ) || !m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
{ {
poly.DeletePolygon( idx ); poly.DeletePolygon( idx );
} }
@ -241,10 +246,10 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
} }
} }
zone.m_zone->SetFilledPolysList( poly ); zone.m_zone->SetFilledPolysList( zone.m_layer, poly );
zone.m_zone->CalculateFilledArea(); zone.m_zone->CalculateFilledArea();
if( aCheck && zone.m_zone->GetHashValue() != poly.GetHash() ) if( aCheck && zone.m_zone->GetHashValue( zone.m_layer ) != poly.GetHash() )
outOfDate = true; outOfDate = true;
} }
@ -468,7 +473,8 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidt
* Removes thermal reliefs from the shape for any pads connected to the zone. Does NOT add * Removes thermal reliefs from the shape for any pads connected to the zone. Does NOT add
* in spokes, which must be done later. * in spokes, which must be done later.
*/ */
void ZONE_FILLER::knockoutThermalReliefs( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aFill ) void ZONE_FILLER::knockoutThermalReliefs( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aFill )
{ {
SHAPE_POLY_SET holes; SHAPE_POLY_SET holes;
@ -488,7 +494,7 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE_CONTAINER* aZone, SHAPE_POL
// If the pad isn't on the current layer but has a hole, knock out a thermal relief // If the pad isn't on the current layer but has a hole, knock out a thermal relief
// for the hole. // for the hole.
if( !pad->IsOnLayer( aZone->GetLayer() ) ) if( !pad->IsOnLayer( aLayer ) )
{ {
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 ) if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
continue; continue;
@ -510,7 +516,8 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE_CONTAINER* aZone, SHAPE_POL
* Removes clearance from the shape for copper items which share the zone's layer but are * Removes clearance from the shape for copper items which share the zone's layer but are
* not connected to it. * not connected to it.
*/ */
void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aHoles ) void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aHoles )
{ {
static DRAWSEGMENT dummyEdge; static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts ); dummyEdge.SetLayer( Edge_Cuts );
@ -543,7 +550,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
{ {
for( auto pad : module->Pads() ) for( auto pad : module->Pads() )
{ {
if( !pad->IsOnLayer( aZone->GetLayer() ) ) if( !pad->IsOnLayer( aLayer ) )
{ {
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 ) if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
continue; continue;
@ -576,7 +583,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
// //
for( auto track : m_board->Tracks() ) for( auto track : m_board->Tracks() )
{ {
if( !track->IsOnLayer( aZone->GetLayer() ) ) if( !track->IsOnLayer( aLayer ) )
continue; continue;
if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) ) if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
@ -597,7 +604,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
[&]( BOARD_ITEM* aItem ) [&]( BOARD_ITEM* aItem )
{ {
// A item on the Edge_Cuts is always seen as on any layer: // A item on the Edge_Cuts is always seen as on any layer:
if( !aItem->IsOnLayer( aZone->GetLayer() ) && !aItem->IsOnLayer( Edge_Cuts ) ) if( !aItem->IsOnLayer( aLayer ) && !aItem->IsOnLayer( Edge_Cuts ) )
return; return;
if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) ) if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
@ -627,7 +634,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
{ {
// If the zones share no common layers // If the zones share no common layers
if( !aZone->CommonLayerExists( zone->GetLayerSet() ) ) if( !zone->GetLayerSet().test( aLayer ) )
continue; continue;
if( !zone->GetIsKeepout() && zone->GetPriority() <= aZone->GetPriority() ) if( !zone->GetIsKeepout() && zone->GetPriority() <= aZone->GetPriority() )
@ -668,7 +675,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
* 5 - Removes unconnected copper islands, deleting any affected spokes * 5 - Removes unconnected copper islands, deleting any affected spokes
* 6 - Adds in the remaining spokes * 6 - Adds in the remaining spokes
*/ */
void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
const SHAPE_POLY_SET& aSmoothedOutline, const SHAPE_POLY_SET& aSmoothedOutline,
std::set<VECTOR2I>* aPreserveCorners, std::set<VECTOR2I>* aPreserveCorners,
SHAPE_POLY_SET& aRawPolys, SHAPE_POLY_SET& aRawPolys,
@ -709,17 +716,17 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone,
if( s_DumpZonesWhenFilling ) if( s_DumpZonesWhenFilling )
dumper->BeginGroup( "clipper-zone" ); dumper->BeginGroup( "clipper-zone" );
knockoutThermalReliefs( aZone, aRawPolys ); knockoutThermalReliefs( aZone, aLayer, aRawPolys );
if( s_DumpZonesWhenFilling ) if( s_DumpZonesWhenFilling )
dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" ); dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" );
buildCopperItemClearances( aZone, clearanceHoles ); buildCopperItemClearances( aZone, aLayer, clearanceHoles );
if( s_DumpZonesWhenFilling ) if( s_DumpZonesWhenFilling )
dumper->Write( &aRawPolys, "clearance holes" ); dumper->Write( &aRawPolys, "clearance holes" );
buildThermalSpokes( aZone, thermalSpokes ); buildThermalSpokes( aZone, aLayer, thermalSpokes );
// Create a temporary zone that we can hit-test spoke-ends against. It's only temporary // Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
// because the "real" subtract-clearance-holes has to be done after the spokes are added. // because the "real" subtract-clearance-holes has to be done after the spokes are added.
@ -778,7 +785,7 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone,
// Now remove the non filled areas due to the hatch pattern // Now remove the non filled areas due to the hatch pattern
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN ) if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
addHatchFillTypeOnZone( aZone, aRawPolys ); addHatchFillTypeOnZone( aZone, aLayer, aRawPolys );
if( s_DumpZonesWhenFilling ) if( s_DumpZonesWhenFilling )
dumper->Write( &aRawPolys, "solid-areas-after-hatching" ); dumper->Write( &aRawPolys, "solid-areas-after-hatching" );
@ -817,8 +824,8 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone,
* The solid areas can be more than one on copper layers, and do not have holes * The solid areas can be more than one on copper layers, and do not have holes
* ( holes are linked by overlapping segments to the main outline) * ( holes are linked by overlapping segments to the main outline)
*/ */
bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPolys, bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aFinalPolys ) SHAPE_POLY_SET& aRawPolys, SHAPE_POLY_SET& aFinalPolys )
{ {
SHAPE_POLY_SET smoothedPoly; SHAPE_POLY_SET smoothedPoly;
std::set<VECTOR2I> colinearCorners; std::set<VECTOR2I> colinearCorners;
@ -834,7 +841,8 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol
if( aZone->IsOnCopperLayer() ) if( aZone->IsOnCopperLayer() )
{ {
computeRawFilledArea( aZone, smoothedPoly, &colinearCorners, aRawPolys, aFinalPolys ); computeRawFilledArea(
aZone, aLayer, smoothedPoly, &colinearCorners, aRawPolys, aFinalPolys );
} }
else else
{ {
@ -852,7 +860,7 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol
// Remove the non filled areas due to the hatch pattern // Remove the non filled areas due to the hatch pattern
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN ) if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
addHatchFillTypeOnZone( aZone, smoothedPoly ); addHatchFillTypeOnZone( aZone, aLayer, smoothedPoly );
// Re-inflate after pruning of areas that don't meet minimum-width criteria // Re-inflate after pruning of areas that don't meet minimum-width criteria
if( aZone->GetFilledPolysUseThickness() ) if( aZone->GetFilledPolysUseThickness() )
@ -877,7 +885,7 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol
/** /**
* Function buildThermalSpokes * Function buildThermalSpokes
*/ */
void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone, void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
std::deque<SHAPE_LINE_CHAIN>& aSpokesList ) std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
{ {
auto zoneBB = aZone->GetBoundingBox(); auto zoneBB = aZone->GetBoundingBox();
@ -898,7 +906,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone,
continue; continue;
// We currently only connect to pads, not pad holes // We currently only connect to pads, not pad holes
if( !pad->IsOnLayer( aZone->GetLayer() ) ) if( !pad->IsOnLayer( aLayer ) )
continue; continue;
int thermalReliefGap = aZone->GetThermalReliefGap( pad ); int thermalReliefGap = aZone->GetThermalReliefGap( pad );
@ -995,7 +1003,8 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone,
} }
void ZONE_FILLER::addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPolys ) void ZONE_FILLER::addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aRawPolys )
{ {
// Build grid: // Build grid:

View File

@ -51,9 +51,11 @@ private:
void addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidth, SHAPE_POLY_SET& aHoles ); void addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidth, SHAPE_POLY_SET& aHoles );
void knockoutThermalReliefs( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aFill ); void knockoutThermalReliefs( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aFill );
void buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aHoles ); void buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aHoles );
/** /**
* Function computeRawFilledArea * Function computeRawFilledArea
@ -66,7 +68,7 @@ private:
* filled copper area polygon (without clearance areas * filled copper area polygon (without clearance areas
* @param aPcb: the current board * @param aPcb: the current board
*/ */
void computeRawFilledArea( const ZONE_CONTAINER* aZone, void computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
const SHAPE_POLY_SET& aSmoothedOutline, const SHAPE_POLY_SET& aSmoothedOutline,
std::set<VECTOR2I>* aPreserveCorners, std::set<VECTOR2I>* aPreserveCorners,
SHAPE_POLY_SET& aRawPolys, SHAPE_POLY_SET& aFinalPolys ); SHAPE_POLY_SET& aRawPolys, SHAPE_POLY_SET& aFinalPolys );
@ -75,7 +77,8 @@ private:
* Function buildThermalSpokes * Function buildThermalSpokes
* Constructs a list of all thermal spokes for the given zone. * Constructs a list of all thermal spokes for the given zone.
*/ */
void buildThermalSpokes( const ZONE_CONTAINER* aZone, std::deque<SHAPE_LINE_CHAIN>& aSpokes ); void buildThermalSpokes( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
std::deque<SHAPE_LINE_CHAIN>& aSpokes );
/** /**
* Build the filled solid areas polygons from zone outlines (stored in m_Poly) * Build the filled solid areas polygons from zone outlines (stored in m_Poly)
@ -91,7 +94,7 @@ private:
* by aZone->GetMinThickness() / 2 to be drawn with a outline thickness = aZone->GetMinThickness() * by aZone->GetMinThickness() / 2 to be drawn with a outline thickness = aZone->GetMinThickness()
* aFinalPolys are polygons that will be drawn on screen and plotted * aFinalPolys are polygons that will be drawn on screen and plotted
*/ */
bool fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPolys, bool fillSingleZone( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aRawPolys,
SHAPE_POLY_SET& aFinalPolys ); SHAPE_POLY_SET& aFinalPolys );
/** /**
@ -101,7 +104,8 @@ private:
* @param aRawPolys: A reference to a SHAPE_POLY_SET buffer containing the initial * @param aRawPolys: A reference to a SHAPE_POLY_SET buffer containing the initial
* filled areas, and after adding the grid pattern, the modified filled areas with holes * filled areas, and after adding the grid pattern, the modified filled areas with holes
*/ */
void addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPolys ); void addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aRawPolys );
BOARD* m_board; BOARD* m_board;
SHAPE_POLY_SET m_boardOutline; // The board outlines, if exists SHAPE_POLY_SET m_boardOutline; // The board outlines, if exists

View File

@ -57,11 +57,12 @@ ZONE_SETTINGS::ZONE_SETTINGS()
m_HatchFillTypeSmoothingLevel = 0; // Grid pattern smoothing type. 0 = no smoothing m_HatchFillTypeSmoothingLevel = 0; // Grid pattern smoothing type. 0 = no smoothing
m_HatchFillTypeSmoothingValue = 0.1; // Grid pattern chamfer value relative to the gap value m_HatchFillTypeSmoothingValue = 0.1; // Grid pattern chamfer value relative to the gap value
m_NetcodeSelection = 0; // Net code selection for the current zone m_NetcodeSelection = 0; // Net code selection for the current zone
m_CurrentZone_Layer = F_Cu; // Layer used to create the current zone
m_Zone_HatchingStyle = m_Zone_HatchingStyle =
ZONE_HATCH_STYLE::DIAGONAL_EDGE; // Option to show the zone area (outlines only, ZONE_HATCH_STYLE::DIAGONAL_EDGE; // Option to show the zone area (outlines only,
//short hatches or full hatches //short hatches or full hatches
m_Layers.reset().set( F_Cu );
// thickness of the gap in thermal reliefs: // thickness of the gap in thermal reliefs:
m_ThermalReliefGap = Mils2iu( ZONE_THERMAL_RELIEF_GAP_MIL ); m_ThermalReliefGap = Mils2iu( ZONE_THERMAL_RELIEF_GAP_MIL );
// thickness of the copper bridge in thermal reliefs: // thickness of the copper bridge in thermal reliefs:
@ -74,6 +75,8 @@ ZONE_SETTINGS::ZONE_SETTINGS()
m_cornerSmoothingType = SMOOTHING_NONE; m_cornerSmoothingType = SMOOTHING_NONE;
m_cornerRadius = 0; m_cornerRadius = 0;
m_removeIslands = true;
SetIsKeepout( false ); SetIsKeepout( false );
SetDoNotAllowCopperPour( false ); SetDoNotAllowCopperPour( false );
SetDoNotAllowVias( true ); SetDoNotAllowVias( true );
@ -108,8 +111,8 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
m_keepoutDoNotAllowPads = aSource.GetDoNotAllowPads(); m_keepoutDoNotAllowPads = aSource.GetDoNotAllowPads();
m_keepoutDoNotAllowFootprints = aSource.GetDoNotAllowFootprints(); m_keepoutDoNotAllowFootprints = aSource.GetDoNotAllowFootprints();
m_Zone_45_Only = aSource.GetHV45(); m_Zone_45_Only = aSource.GetHV45();
m_removeIslands = aSource.GetRemoveIslands();
m_CurrentZone_Layer = aSource.GetLayer();
m_Layers = aSource.GetLayerSet(); m_Layers = aSource.GetLayerSet();
return *this; return *this;
@ -138,21 +141,15 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c
aTarget.SetDoNotAllowPads( GetDoNotAllowPads() ); aTarget.SetDoNotAllowPads( GetDoNotAllowPads() );
aTarget.SetDoNotAllowFootprints( GetDoNotAllowFootprints() ); aTarget.SetDoNotAllowFootprints( GetDoNotAllowFootprints() );
aTarget.SetHV45( m_Zone_45_Only ); aTarget.SetHV45( m_Zone_45_Only );
aTarget.SetRemoveIslands( GetRemoveIslands() );
if( aFullExport ) if( aFullExport )
{ {
aTarget.SetPriority( m_ZonePriority ); aTarget.SetPriority( m_ZonePriority );
// Keepout zones can have multiple layers and have no net
if( m_isKeepout )
{
aTarget.SetLayerSet( m_Layers ); aTarget.SetLayerSet( m_Layers );
}
else if( !m_isKeepout )
{
aTarget.SetNetCode( m_NetcodeSelection ); aTarget.SetNetCode( m_NetcodeSelection );
aTarget.SetLayer( m_CurrentZone_Layer );
}
} }
// call SetHatch last, because hatch lines will be rebuilt, // call SetHatch last, because hatch lines will be rebuilt,
@ -214,7 +211,7 @@ void ZONE_SETTINGS::SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME*
row.push_back( wxVariant( wxString::Format( "%i", layerID ) ) ); row.push_back( wxVariant( wxString::Format( "%i", layerID ) ) );
aList->AppendItem( row ); aList->AppendItem( row );
if( m_CurrentZone_Layer == layerID ) if( m_Layers.test( layerID ) )
aList->SetToggleValue( true, (unsigned) aList->GetItemCount() - 1, 0 ); aList->SetToggleValue( true, (unsigned) aList->GetItemCount() - 1, 0 );
} }

View File

@ -83,9 +83,7 @@ public:
int m_NetcodeSelection; ///< Net code selection for the current zone int m_NetcodeSelection; ///< Net code selection for the current zone
LSET m_Layers; LSET m_Layers; ///< Layers that this zone exists on
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 /// Option to show the zone area (outlines only, short hatches or full hatches
ZONE_HATCH_STYLE m_Zone_HatchingStyle; ZONE_HATCH_STYLE m_Zone_HatchingStyle;
@ -114,6 +112,7 @@ private:
bool m_keepoutDoNotAllowPads; bool m_keepoutDoNotAllowPads;
bool m_keepoutDoNotAllowFootprints; bool m_keepoutDoNotAllowFootprints;
bool m_removeIslands;
public: public:
ZONE_SETTINGS(); ZONE_SETTINGS();
@ -181,6 +180,9 @@ public:
void SetDoNotAllowTracks( bool aEnable ) { m_keepoutDoNotAllowTracks = aEnable; } void SetDoNotAllowTracks( bool aEnable ) { m_keepoutDoNotAllowTracks = aEnable; }
void SetDoNotAllowPads( bool aEnable ) { m_keepoutDoNotAllowPads = aEnable; } void SetDoNotAllowPads( bool aEnable ) { m_keepoutDoNotAllowPads = aEnable; }
void SetDoNotAllowFootprints( bool aEnable ) { m_keepoutDoNotAllowFootprints = aEnable; } void SetDoNotAllowFootprints( bool aEnable ) { m_keepoutDoNotAllowFootprints = aEnable; }
const bool GetRemoveIslands() const { return m_removeIslands; }
void SetRemoveIslands( bool aRemove ) { m_removeIslands = aRemove; }
}; };

View File

@ -236,12 +236,18 @@ int polygon_triangulation_main( int argc, char *argv[] )
areaId = zonesToTriangulate.fetch_add( 1 ) ) areaId = zonesToTriangulate.fetch_add( 1 ) )
{ {
auto zone = brd->GetArea( areaId ); auto zone = brd->GetArea( areaId );
SHAPE_POLY_SET poly = zone->GetFilledPolysList();
// NOTE: this could be refactored to do multiple layers from the same zone in
// parallel, but since the test case doesn't have any of these, I'm not bothering
// to do that right now.
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
SHAPE_POLY_SET poly = zone->GetFilledPolysList( layer );
poly.CacheTriangulation(); poly.CacheTriangulation();
(void) poly; (void) poly;
printf("zone %zu/%d\n", ( areaId + 1 ), brd->GetAreaCount() ); printf( "zone %zu/%d\n", ( areaId + 1 ), brd->GetAreaCount() );
#if 0 #if 0
PROF_COUNTER unfrac("unfrac"); PROF_COUNTER unfrac("unfrac");
poly.Unfracture( SHAPE_POLY_SET::PM_FAST ); poly.Unfracture( SHAPE_POLY_SET::PM_FAST );
@ -256,6 +262,7 @@ int polygon_triangulation_main( int argc, char *argv[] )
triangulate.Show(); triangulate.Show();
#endif #endif
} }
}
threadsFinished++; threadsFinished++;
} ); } );