CHANGED: Copper zones can be on more than one layer
Fixes https://gitlab.com/kicad/code/kicad/-/issues/1963
This commit is contained in:
parent
0b34cea3d5
commit
0d4ee39f75
|
@ -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,
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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++ )
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 ) ) )
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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) )
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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" );
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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++;
|
||||||
} );
|
} );
|
||||||
|
|
Loading…
Reference in New Issue