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 )
|
||||
{
|
||||
// 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
|
||||
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
|
||||
|
|
|
@ -682,6 +682,16 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
|||
if( aStatusReporter )
|
||||
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
|
||||
// /////////////////////////////////////////////////////////////////////
|
||||
std::atomic<size_t> nextZone( 0 );
|
||||
|
@ -693,19 +703,20 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
|||
std::thread t = std::thread( [&]()
|
||||
{
|
||||
for( size_t areaId = nextZone.fetch_add( 1 );
|
||||
areaId < static_cast<size_t>( m_board->GetAreaCount() );
|
||||
areaId < zones.size();
|
||||
areaId = nextZone.fetch_add( 1 ) )
|
||||
{
|
||||
const ZONE_CONTAINER* zone = m_board->GetArea( areaId );
|
||||
const ZONE_CONTAINER* zone = zones[areaId].first;
|
||||
|
||||
if( zone == nullptr )
|
||||
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() )
|
||||
AddSolidAreasShapesToContainer( zone, layerContainer->second,
|
||||
zone->GetLayer() );
|
||||
AddSolidAreasShapesToContainer( zone, layerContainer->second, layer );
|
||||
}
|
||||
|
||||
threadsFinished++;
|
||||
|
@ -733,10 +744,13 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
|||
if( zone == nullptr )
|
||||
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() )
|
||||
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 ) )
|
||||
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++ )
|
||||
{
|
||||
ZONE_CONTAINER* zone = GetArea( ii );
|
||||
PCB_LAYER_ID zonelayer = zone->GetLayer();
|
||||
|
||||
if( zonelayer == aLayer )
|
||||
zone->TransformSolidAreasShapesToPolygonSet( aOutlines );
|
||||
if( zone->GetLayerSet().test( aLayer ) )
|
||||
zone->TransformSolidAreasShapesToPolygonSet( aLayer, aOutlines );
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
if( GetFilledPolysList().IsEmpty() )
|
||||
if( !m_FilledPolysList.count( aLayer ) || m_FilledPolysList.at( aLayer ).IsEmpty() )
|
||||
return;
|
||||
|
||||
const SHAPE_POLY_SET& polys = m_FilledPolysList.at( aLayer );
|
||||
|
||||
// add filled areas polygons
|
||||
aCornerBuffer.Append( m_FilledPolysList );
|
||||
aCornerBuffer.Append( polys );
|
||||
auto board = GetBoard();
|
||||
int maxError = ARC_HIGH_DEF;
|
||||
|
||||
|
@ -257,9 +259,9 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet( SHAPE_POLY_SET& aCor
|
|||
maxError = board->GetDesignSettings().m_MaxError;
|
||||
|
||||
// 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++ )
|
||||
{
|
||||
|
@ -652,8 +654,16 @@ void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCorn
|
|||
int aClearanceValue, int aError,
|
||||
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 );
|
||||
#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 error_count = 0;
|
||||
|
|
|
@ -855,21 +855,6 @@ public:
|
|||
/* 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
|
||||
* Set the .m_NetCode member of all copper areas, according to the area Net Name
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <pcb_screen.h>
|
||||
#include <class_board.h>
|
||||
#include <class_zone.h>
|
||||
#include <pcb_edit_frame.h> // current layer for msgpanel
|
||||
#include <math_for_graphics.h>
|
||||
#include <settings/color_settings.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
|
||||
m_Poly = new SHAPE_POLY_SET(); // Outlines
|
||||
m_FilledPolysUseThickness = true; // set the "old" way to build filled polygon areas (before 6.0.x)
|
||||
m_removeIslands = true;
|
||||
aParent->GetZoneSettings().ExportSetting( *this );
|
||||
|
||||
m_needRefill = false; // True only after some edition.
|
||||
|
@ -192,10 +194,20 @@ EDA_ITEM* ZONE_CONTAINER::Clone() const
|
|||
|
||||
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;
|
||||
|
||||
return change;
|
||||
|
@ -216,14 +228,7 @@ PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
|
|||
|
||||
bool ZONE_CONTAINER::IsOnCopperLayer() const
|
||||
{
|
||||
if( GetIsKeepout() )
|
||||
{
|
||||
return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IsCopperLayer( GetLayer() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -255,12 +260,24 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
|
|||
return;
|
||||
|
||||
if( m_layerSet != aLayerSet )
|
||||
{
|
||||
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;
|
||||
|
||||
// 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.
|
||||
// But many functions are using it.
|
||||
// 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
|
||||
{
|
||||
// TODO - Enable multi-layer zones for all zone types
|
||||
// not just keepout zones
|
||||
if( GetIsKeepout() )
|
||||
{
|
||||
return m_layerSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
return LSET( m_Layer );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ZONE_CONTAINER::ViewGetLayers( int aLayers[], int& aCount ) const
|
||||
{
|
||||
if( GetIsKeepout() )
|
||||
{
|
||||
LSEQ layers = m_layerSet.Seq();
|
||||
|
||||
for( unsigned int idx = 0; idx < layers.size(); idx++ )
|
||||
aLayers[idx] = layers[idx];
|
||||
|
||||
aCount = layers.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
aLayers[0] = m_Layer;
|
||||
aCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ZONE_CONTAINER::IsOnLayer( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
if( GetIsKeepout() )
|
||||
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( _( "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() )
|
||||
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() );
|
||||
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 ) );
|
||||
}
|
||||
}
|
||||
|
@ -688,13 +713,17 @@ void ZONE_CONTAINER::Move( const wxPoint& offset )
|
|||
|
||||
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.B += VECTOR2I( offset );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -723,16 +752,20 @@ void ZONE_CONTAINER::Rotate( const wxPoint& centre, double angle )
|
|||
Hatch();
|
||||
|
||||
/* 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 );
|
||||
m_FillSegmList[ic].A = a;
|
||||
wxPoint b( m_FillSegmList[ic].B );
|
||||
seg.A = a;
|
||||
wxPoint b( seg.B );
|
||||
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();
|
||||
|
||||
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 )
|
||||
{
|
||||
|
@ -771,6 +807,7 @@ void ZONE_CONTAINER::Mirror( const wxPoint& aMirrorRef, bool aMirrorLeftRight )
|
|||
MIRROR( seg.B.y, aMirrorRef.y );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -862,7 +899,21 @@ wxString ZONE_CONTAINER::GetSelectMenuText( EDA_UNITS aUnits ) const
|
|||
else
|
||||
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()
|
||||
{
|
||||
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
|
||||
// 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; }
|
||||
void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; }
|
||||
|
||||
ZONE_SEGMENT_FILL& FillSegments() { return m_FillSegmList; }
|
||||
const ZONE_SEGMENT_FILL& FillSegments() const { return m_FillSegmList; }
|
||||
ZONE_SEGMENT_FILL& FillSegments( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
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; }
|
||||
const SHAPE_POLY_SET* Outline() const { return const_cast< SHAPE_POLY_SET* >( m_Poly ); }
|
||||
|
@ -269,10 +278,11 @@ public:
|
|||
/**
|
||||
* Function HitTestFilledArea
|
||||
* 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
|
||||
* @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.
|
||||
|
@ -305,10 +315,11 @@ public:
|
|||
* (the full shape is the polygon area with a thick outline)
|
||||
* Used in 3D view
|
||||
* 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 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;
|
||||
|
||||
/**
|
||||
|
@ -334,14 +345,16 @@ public:
|
|||
* Convert the zone shape to a closed polygon
|
||||
* Used in filling zones calculations
|
||||
* 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 aClearanceValue = the clearance around the pad
|
||||
* @param aError = the maximum deviation from true circle
|
||||
* @param ignoreLineWidth = used for edge cut items where the line width is only
|
||||
* for visualization
|
||||
*/
|
||||
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue,
|
||||
int aError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override;
|
||||
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||
int aClearanceValue, int aError = ARC_HIGH_DEF,
|
||||
bool ignoreLineWidth = false ) const override;
|
||||
|
||||
/**
|
||||
* Function HitTestForCorner
|
||||
|
@ -568,7 +581,8 @@ public:
|
|||
*/
|
||||
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.
|
||||
* @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.
|
||||
|
@ -590,18 +605,18 @@ public:
|
|||
* Function SetFilledPolysList
|
||||
* 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
|
||||
* 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 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;
|
||||
|
@ -685,6 +701,9 @@ public:
|
|||
void SetDoNotAllowPads( bool aEnable ) { m_doNotAllowPads = aEnable; }
|
||||
void SetDoNotAllowFootprints( bool aEnable ) { m_doNotAllowFootprints = aEnable; }
|
||||
|
||||
bool GetRemoveIslands() const { return m_removeIslands; }
|
||||
void SetRemoveIslands( bool aRemove ) { m_removeIslands = aRemove; }
|
||||
|
||||
/**
|
||||
* Hatch related methods
|
||||
*/
|
||||
|
@ -740,13 +759,25 @@ public:
|
|||
/** @return the hash value previously calculated by BuildHashValue().
|
||||
* 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
|
||||
* in m_filledPolysHash.
|
||||
* 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.
|
||||
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. */
|
||||
bool m_IsFilled;
|
||||
|
||||
|
@ -845,7 +879,7 @@ protected:
|
|||
/** 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.
|
||||
*/
|
||||
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.
|
||||
* 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
|
||||
* described by m_Poly can have many filled areas
|
||||
*/
|
||||
SHAPE_POLY_SET m_FilledPolysList;
|
||||
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
|
||||
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_FilledPolysList;
|
||||
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_RawPolysList;
|
||||
|
||||
/// 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
|
||||
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 )
|
||||
|| zone->HitTestForEdge( m_RefPos, accuracy )
|
||||
|| ( testFill && zone->HitTestFilledArea( m_RefPos ) ) )
|
||||
|| ( testFill && zone->HitTestFilledArea( layer, m_RefPos ) ) )
|
||||
{
|
||||
Append( item );
|
||||
goto exit;
|
||||
|
@ -495,7 +495,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
|
|||
|
||||
if( zone->HitTestForCorner( m_RefPos, accuracy * 2 )
|
||||
|| zone->HitTestForEdge( m_RefPos, accuracy )
|
||||
|| ( testFill && zone->HitTestFilledArea( m_RefPos ) ) )
|
||||
|| ( testFill && zone->HitTestFilledArea( layer, m_RefPos ) ) )
|
||||
{
|
||||
Append2nd( item );
|
||||
goto exit;
|
||||
|
|
|
@ -181,8 +181,9 @@ bool CN_CONNECTIVITY_ALGO::Add( BOARD_ITEM* aItem )
|
|||
|
||||
m_itemMap[zone] = ITEM_MAP_ENTRY();
|
||||
|
||||
for( auto zitem : m_itemList.Add( zone ) )
|
||||
m_itemMap[zone].Link(zitem);
|
||||
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
|
||||
for( auto zitem : m_itemList.Add( zone, layer ) )
|
||||
m_itemMap[zone].Link( zitem );
|
||||
|
||||
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;
|
||||
|
||||
aIslands.clear();
|
||||
|
@ -536,7 +539,7 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std
|
|||
{
|
||||
for( auto z : *cluster )
|
||||
{
|
||||
if( z->Parent() == aZone )
|
||||
if( z->Parent() == aZone && z->Layer() == aLayer )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK );
|
||||
|
||||
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;
|
||||
|
||||
for( const auto& cluster : m_connClusters )
|
||||
|
@ -571,10 +582,8 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLAT
|
|||
{
|
||||
for( auto z : *cluster )
|
||||
{
|
||||
if( z->Parent() == zone.m_zone )
|
||||
{
|
||||
zone.m_islands.push_back( static_cast<CN_ZONE*>(z)->SubpolyIndex() );
|
||||
}
|
||||
if( z->Parent() == zone.m_zone && z->Layer() == layer )
|
||||
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 )
|
||||
return;
|
||||
|
||||
if( aZoneA->Layer() != aZoneB->Layer() )
|
||||
return;
|
||||
|
||||
if( aZoneB->Net() != aZoneA->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++ )
|
||||
{
|
||||
|
@ -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++ )
|
||||
{
|
||||
|
|
|
@ -243,7 +243,8 @@ public:
|
|||
*/
|
||||
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
|
||||
|
|
|
@ -235,7 +235,10 @@ int CONNECTIVITY_DATA::GetNetCount() const
|
|||
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone,
|
||||
std::vector<int>& aIslands )
|
||||
{
|
||||
// TODO(JE) ZONES
|
||||
#if 0
|
||||
m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands );
|
||||
#endif
|
||||
}
|
||||
|
||||
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )
|
||||
|
|
|
@ -60,13 +60,21 @@ struct CN_DISJOINT_NET_ENTRY
|
|||
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
|
||||
{
|
||||
CN_ZONE_ISOLATED_ISLAND_LIST( ZONE_CONTAINER* aZone ) :
|
||||
m_zone( aZone )
|
||||
CN_ZONE_ISOLATED_ISLAND_LIST( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer ) :
|
||||
m_zone( aZone ),
|
||||
m_layer( aLayer )
|
||||
{}
|
||||
|
||||
ZONE_CONTAINER* m_zone;
|
||||
|
||||
PCB_LAYER_ID m_layer;
|
||||
|
||||
std::vector<int> m_islands;
|
||||
};
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ int CN_ZONE::AnchorCount() const
|
|||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -173,8 +173,8 @@ const VECTOR2I CN_ZONE::GetAnchor( int n ) const
|
|||
if( !Valid() )
|
||||
return VECTOR2I();
|
||||
|
||||
const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
|
||||
const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() );
|
||||
const auto& outline = zone->GetFilledPolysList( m_layer ).COutline( m_subpolyIndex );
|
||||
|
||||
return outline.CPoint( 0 );
|
||||
}
|
||||
|
@ -265,22 +265,22 @@ CN_ITEM* CN_LIST::Add( ARC* aArc )
|
|||
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;
|
||||
|
||||
for( int j = 0; j < polys.OutlineCount(); j++ )
|
||||
{
|
||||
CN_ZONE* zitem = new CN_ZONE( zone, false, j );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( j );
|
||||
CN_ZONE* zitem = new CN_ZONE( zone, aLayer, false, j );
|
||||
const auto& outline = zone->GetFilledPolysList( aLayer ).COutline( j );
|
||||
|
||||
for( int k = 0; k < outline.PointCount(); k++ )
|
||||
zitem->AddAnchor( outline.CPoint( k ) );
|
||||
|
||||
m_items.push_back( zitem );
|
||||
zitem->SetLayer( zone->GetLayer() );
|
||||
zitem->SetLayer( aLayer );
|
||||
addItemtoTree( zitem );
|
||||
rv.push_back( zitem );
|
||||
SetDirty();
|
||||
|
@ -360,7 +360,8 @@ bool CN_ANCHOR::IsDangling() const
|
|||
{
|
||||
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++;
|
||||
}
|
||||
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() );
|
||||
|
||||
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++;
|
||||
}
|
||||
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
|
||||
{
|
||||
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 ),
|
||||
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.Simplify();
|
||||
|
@ -396,6 +397,7 @@ private:
|
|||
std::vector<VECTOR2I> m_testOutlinePoints;
|
||||
std::unique_ptr<POLY_GRID_PARTITION> m_cachedPoly;
|
||||
int m_subpolyIndex;
|
||||
PCB_LAYER_ID m_layer;
|
||||
};
|
||||
|
||||
class CN_LIST
|
||||
|
@ -500,7 +502,7 @@ public:
|
|||
|
||||
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
|
||||
|
|
|
@ -444,19 +444,10 @@ void DIALOG_COPPER_ZONE::OnLayerSelection( wxDataViewEvent& event )
|
|||
|
||||
int row = m_layers->ItemToRow( event.GetItem() );
|
||||
|
||||
if( m_layers->GetToggleValue( row, 0 ) )
|
||||
{
|
||||
wxVariant layerID;
|
||||
m_layers->GetValue( layerID, row, 2 );
|
||||
m_settings.m_CurrentZone_Layer = ToLAYER_ID( layerID.GetInteger() );
|
||||
|
||||
// Turn all other checkboxes off.
|
||||
for( int ii = 0; ii < m_layers->GetItemCount(); ++ii )
|
||||
{
|
||||
if( ii != row )
|
||||
m_layers->SetToggleValue( false, ii, 0 );
|
||||
}
|
||||
}
|
||||
m_settings.m_Layers.set( ToLAYER_ID( layerID.GetInteger() ),
|
||||
m_layers->GetToggleValue( row, 0 ) );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -194,20 +194,11 @@ void DIALOG_NON_COPPER_ZONES_EDITOR::OnLayerSelection( wxDataViewEvent& event )
|
|||
return;
|
||||
|
||||
int row = m_layers->ItemToRow( event.GetItem() );
|
||||
bool val = m_layers->GetToggleValue( row, 0 );
|
||||
|
||||
if( m_layers->GetToggleValue( row, 0 ) )
|
||||
{
|
||||
wxVariant layerID;
|
||||
m_layers->GetValue( layerID, row, 2 );
|
||||
m_settings.m_CurrentZone_Layer = ToLAYER_ID( layerID.GetInteger() );
|
||||
|
||||
// Turn all other checkboxes off.
|
||||
for( int ii = 0; ii < m_layers->GetItemCount(); ++ii )
|
||||
{
|
||||
if( ii != row )
|
||||
m_layers->SetToggleValue( false, ii, 0 );
|
||||
}
|
||||
}
|
||||
m_settings.m_Layers.set( ToLAYER_ID( layerID.GetInteger() ), val );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1394,8 +1394,10 @@ wxPoint DRC::GetLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone )
|
|||
{
|
||||
SHAPE_POLY_SET* conflictOutline;
|
||||
|
||||
PCB_LAYER_ID l = aTrack->GetLayer();
|
||||
|
||||
if( aConflictZone->IsFilled() )
|
||||
conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList() );
|
||||
conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList( l ) );
|
||||
else
|
||||
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() )
|
||||
{
|
||||
if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() )
|
||||
if( !( refLayerSet & zone->GetLayerSet() ).any() || zone->GetIsKeepout() )
|
||||
continue;
|
||||
|
||||
if( !( refLayerSet & zone->GetLayerSet() ).any() )
|
||||
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
|
||||
{
|
||||
if( zone->GetFilledPolysList( layer ).IsEmpty() )
|
||||
continue;
|
||||
|
||||
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 widths = refSegWidth / 2;
|
||||
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 );
|
||||
|
||||
|
@ -613,6 +616,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
/* Phase 4: test DRC with to board edge */
|
||||
|
|
|
@ -271,7 +271,7 @@ bool DRC_KEEPOUT_TESTER::checkPads( MODULE* aModule )
|
|||
slotEnd += pad->GetPosition();
|
||||
|
||||
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 );
|
||||
|
||||
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 ) )
|
||||
{
|
||||
const auto layerName = m_board->GetLayerName( zone->GetLayer() );
|
||||
SHAPE_POLY_SET filledShape = zone->GetFilledPolysList();
|
||||
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
|
||||
{
|
||||
const auto layerName = m_board->GetLayerName( layer );
|
||||
SHAPE_POLY_SET filledShape = zone->GetFilledPolysList( layer );
|
||||
|
||||
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 );
|
||||
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++ )
|
||||
{
|
||||
|
@ -474,8 +477,8 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
|
|||
const auto& holeShape = filledShape.CHole( i, h );
|
||||
auto ph0 = holeShape.CPoint( 0 );
|
||||
|
||||
m_out->Print( 1, "{POLYVOID ID=%d X=%.10f Y=%.10f\n", m_polyId, iu2hyp( ph0.x ),
|
||||
iu2hyp( ph0.y ) );
|
||||
m_out->Print( 1, "{POLYVOID ID=%d X=%.10f Y=%.10f\n", m_polyId,
|
||||
iu2hyp( ph0.x ), iu2hyp( ph0.y ) );
|
||||
|
||||
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 ) );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
|
@ -492,6 +496,7 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1023,9 +1023,11 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
|
|||
{
|
||||
ZONE_CONTAINER* zone = aPcb->GetArea( ii );
|
||||
|
||||
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
|
||||
{
|
||||
VRML_LAYER* vl;
|
||||
|
||||
if( !GetLayer( aModel, zone->GetLayer(), &vl ) )
|
||||
if( !GetLayer( aModel, layer, &vl ) )
|
||||
continue;
|
||||
|
||||
// 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 } );
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& poly = zone->GetFilledPolysList();
|
||||
const SHAPE_POLY_SET& poly = zone->GetFilledPolysList( layer );
|
||||
|
||||
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++ )
|
||||
{
|
||||
if( !vl->AddVertex( seg, (double)outline.CPoint( j ).x * BOARD_SCALE,
|
||||
-((double)outline.CPoint( j ).y * BOARD_SCALE ) ) )
|
||||
if( !vl->AddVertex( seg, (double) outline.CPoint( j ).x * BOARD_SCALE,
|
||||
-( (double) outline.CPoint( j ).y * BOARD_SCALE ) ) )
|
||||
throw( std::runtime_error( vl->GetError() ) );
|
||||
|
||||
}
|
||||
|
||||
vl->EnsureWinding( seg, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1981,7 +1981,9 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
|
|||
}
|
||||
|
||||
// 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;
|
||||
|
||||
if( !fv.IsEmpty() )
|
||||
|
@ -1994,19 +1996,20 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
|
|||
if( new_polygon )
|
||||
{
|
||||
newLine = 0;
|
||||
m_out->Print( aNestLevel+1, "(filled_polygon\n" );
|
||||
m_out->Print( aNestLevel+2, "(pts\n" );
|
||||
m_out->Print( aNestLevel + 1, "(filled_polygon\n" );
|
||||
m_out->Print( aNestLevel + 2, "(layer %s)\n",
|
||||
TO_UTF8( BOARD::GetStandardLayerName( layer ) ) );
|
||||
m_out->Print( aNestLevel + 2, "(pts\n" );
|
||||
new_polygon = false;
|
||||
is_closed = false;
|
||||
}
|
||||
|
||||
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->y ).c_str() );
|
||||
else
|
||||
m_out->Print( 0, " (xy %s %s)",
|
||||
FormatInternalUnits( it->x ) .c_str(),
|
||||
m_out->Print( 0, " (xy %s %s)", FormatInternalUnits( it->x ).c_str(),
|
||||
FormatInternalUnits( it->y ).c_str() );
|
||||
|
||||
if( newLine < 4 )
|
||||
|
@ -2026,31 +2029,34 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
|
|||
if( newLine != 0 )
|
||||
m_out->Print( 0, "\n" );
|
||||
|
||||
m_out->Print( aNestLevel+2, ")\n" );
|
||||
m_out->Print( aNestLevel+1, ")\n" );
|
||||
m_out->Print( aNestLevel + 2, ")\n" );
|
||||
m_out->Print( aNestLevel + 1, ")\n" );
|
||||
new_polygon = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( !is_closed ) // Should not happen, but...
|
||||
m_out->Print( aNestLevel+1, ")\n" );
|
||||
m_out->Print( aNestLevel + 1, ")\n" );
|
||||
}
|
||||
|
||||
// Save the filling segments list
|
||||
const auto& segs = aZone->FillSegments();
|
||||
const auto& segs = aZone->FillSegments( layer );
|
||||
|
||||
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 )
|
||||
{
|
||||
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->B ) ).c_str() );
|
||||
}
|
||||
|
||||
m_out->Print( aNestLevel+1, ")\n" );
|
||||
m_out->Print( aNestLevel + 1, ")\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 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 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_OMIT_NETS (1 << 1) ///< Omit pads net names (useless in library)
|
||||
|
|
|
@ -2657,7 +2657,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER()
|
|||
makeNewOutline = end_contour;
|
||||
}
|
||||
|
||||
zc->SetFilledPolysList( polysList );
|
||||
zc->SetFilledPolysList( zc->GetLayer(), polysList );
|
||||
}
|
||||
|
||||
else if( TESTLINE( "$FILLSEGMENTS" ) )
|
||||
|
@ -2673,7 +2673,8 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER()
|
|||
BIU ex = biuParse( data, &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 )
|
||||
{
|
||||
if( !aZone->IsOnLayer( (PCB_LAYER_ID) aLayer ) )
|
||||
PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer );
|
||||
|
||||
if( !aZone->IsOnLayer( layer ) )
|
||||
return;
|
||||
|
||||
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
|
||||
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
|
||||
return;
|
||||
|
@ -1143,7 +1145,6 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
|
|||
|
||||
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
|
||||
|
||||
// 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;
|
||||
PCB_LAYER_ID filledLayer;
|
||||
bool addedFilledPolygons = false;
|
||||
|
||||
if( dynamic_cast<MODULE*>( aParent ) ) // The zone belongs a footprint
|
||||
inModule = true;
|
||||
|
@ -3771,8 +3773,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
|
|||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_layers: // keyword for zones that can live on a set of layer
|
||||
// currently: keepout zones
|
||||
case T_layers: // keyword for zones that can live on a set of layers
|
||||
zone->SetLayerSet( parseBoardItemLayersAsMask() );
|
||||
break;
|
||||
|
||||
|
@ -4069,17 +4070,40 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
|
|||
NeedLEFT();
|
||||
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 )
|
||||
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() )
|
||||
{
|
||||
pts.Append( parseXY() );
|
||||
poly.Append( parseXY() );
|
||||
}
|
||||
|
||||
NeedRIGHT();
|
||||
|
||||
addedFilledPolygons |= !poly.IsEmpty();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -4094,6 +4118,22 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
|
|||
|
||||
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 )
|
||||
Expecting( T_pts );
|
||||
|
||||
|
@ -4102,7 +4142,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
|
|||
segs.push_back( segment );
|
||||
}
|
||||
|
||||
zone->SetFillSegments( segs );
|
||||
zone->SetFillSegments( filledLayer, segs );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -4132,9 +4172,11 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent )
|
|||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
// 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() )
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
// aggregateArea will be simplified and fractured
|
||||
// (Long calculation time)
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
continue;
|
||||
|
||||
if( zone->GetFilledPolysUseThickness() &&
|
||||
( candidate->GetMinThickness() != zone->GetMinThickness() ) )
|
||||
if( zone->GetFilledPolysUseThickness()
|
||||
&& ( candidate->GetMinThickness() != zone->GetMinThickness() ) )
|
||||
continue;
|
||||
|
||||
plotted.insert( candidate );
|
||||
aggregateArea.Append( candidate->GetFilledPolysList() );
|
||||
plotted.insert( candidate_pair );
|
||||
aggregateArea.Append( candidate->GetFilledPolysList( layer ) );
|
||||
needFracture = true;
|
||||
}
|
||||
|
||||
|
@ -527,6 +536,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
|
||||
itemplotter.PlotFilledAreas( zone, aggregateArea );
|
||||
}
|
||||
}
|
||||
aPlotter->EndBlock( NULL );
|
||||
|
||||
// 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() )
|
||||
{
|
||||
if( zone->HitTestFilledArea( position ) )
|
||||
for( PCB_LAYER_ID layer : LSET( zone->GetLayerSet() & lset ).Seq() )
|
||||
if( zone->HitTestFilledArea( layer, position ) )
|
||||
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.
|
||||
if( oldZone->GetIsKeepout() && ( oldZone->GetLayerSet() == zoneSettings.m_Layers ) )
|
||||
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 ) );
|
||||
|
||||
commit.Add( newZone.release() );
|
||||
|
|
|
@ -1560,12 +1560,9 @@ bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
|
|||
if( zoneInFootprint && !m_editModules && !checkVisibilityOnly )
|
||||
return false;
|
||||
|
||||
// Keepout zones can exist on multiple layers!
|
||||
// zones can exist on multiple layers!
|
||||
{
|
||||
auto* zone = static_cast<const ZONE_CONTAINER*>( aItem );
|
||||
|
||||
if( zone->GetIsKeepout() )
|
||||
{
|
||||
auto zoneLayers = zone->GetLayerSet().Seq();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
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
|
||||
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 =
|
||||
board.GetHighLightNetCodes().empty() ? -1 : *board.GetHighLightNetCodes().begin();
|
||||
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 );
|
||||
else
|
||||
{
|
||||
if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) )
|
||||
// TODO(JE) combine these dialogs?
|
||||
if( ( zoneInfo.m_Layers & LSET::AllCuMask() ).any() )
|
||||
dialogResult = InvokeCopperZonesEditor( &frame, &zoneInfo );
|
||||
else
|
||||
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
|
||||
// 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
|
||||
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
|
||||
// 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++ )
|
||||
{
|
||||
PCB_LAYER_ID layer = toFill[i].m_layer;
|
||||
ZONE_CONTAINER* zone = toFill[i].m_zone;
|
||||
zone->SetFilledPolysUseThickness( filledPolyWithOutline );
|
||||
SHAPE_POLY_SET rawPolys, finalPolys;
|
||||
fillSingleZone( zone, rawPolys, finalPolys );
|
||||
|
||||
zone->SetRawPolysList( rawPolys );
|
||||
zone->SetFilledPolysList( finalPolys );
|
||||
zone->SetFilledPolysUseThickness( filledPolyWithOutline );
|
||||
|
||||
SHAPE_POLY_SET rawPolys, finalPolys;
|
||||
fillSingleZone( zone, layer, rawPolys, finalPolys );
|
||||
|
||||
zone->SetRawPolysList( layer, rawPolys );
|
||||
zone->SetFilledPolysList( layer, finalPolys );
|
||||
zone->SetIsFilled( true );
|
||||
|
||||
if( m_progressReporter )
|
||||
|
@ -207,14 +213,13 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
|
|||
for( auto& zone : toFill )
|
||||
{
|
||||
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
|
||||
// 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
|
||||
// insulated islands
|
||||
// solid areas outside the board cutouts are also removed, because they are usually insulated islands
|
||||
for( auto idx : zone.m_islands )
|
||||
{
|
||||
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(); )
|
||||
{
|
||||
if( poly.Polygon( idx ).empty() ||
|
||||
!m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
|
||||
if( poly.Polygon( idx ).empty()
|
||||
|| !m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
|
||||
{
|
||||
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();
|
||||
|
||||
if( aCheck && zone.m_zone->GetHashValue() != poly.GetHash() )
|
||||
if( aCheck && zone.m_zone->GetHashValue( zone.m_layer ) != poly.GetHash() )
|
||||
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
|
||||
* 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;
|
||||
|
||||
|
@ -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
|
||||
// for the hole.
|
||||
if( !pad->IsOnLayer( aZone->GetLayer() ) )
|
||||
if( !pad->IsOnLayer( aLayer ) )
|
||||
{
|
||||
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
|
||||
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
|
||||
* 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;
|
||||
dummyEdge.SetLayer( Edge_Cuts );
|
||||
|
@ -543,7 +550,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
|
|||
{
|
||||
for( auto pad : module->Pads() )
|
||||
{
|
||||
if( !pad->IsOnLayer( aZone->GetLayer() ) )
|
||||
if( !pad->IsOnLayer( aLayer ) )
|
||||
{
|
||||
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
|
||||
continue;
|
||||
|
@ -576,7 +583,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
|
|||
//
|
||||
for( auto track : m_board->Tracks() )
|
||||
{
|
||||
if( !track->IsOnLayer( aZone->GetLayer() ) )
|
||||
if( !track->IsOnLayer( aLayer ) )
|
||||
continue;
|
||||
|
||||
if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
|
||||
|
@ -597,7 +604,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
|
|||
[&]( BOARD_ITEM* aItem )
|
||||
{
|
||||
// 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;
|
||||
|
||||
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( !aZone->CommonLayerExists( zone->GetLayerSet() ) )
|
||||
if( !zone->GetLayerSet().test( aLayer ) )
|
||||
continue;
|
||||
|
||||
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
|
||||
* 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,
|
||||
std::set<VECTOR2I>* aPreserveCorners,
|
||||
SHAPE_POLY_SET& aRawPolys,
|
||||
|
@ -709,17 +716,17 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone,
|
|||
if( s_DumpZonesWhenFilling )
|
||||
dumper->BeginGroup( "clipper-zone" );
|
||||
|
||||
knockoutThermalReliefs( aZone, aRawPolys );
|
||||
knockoutThermalReliefs( aZone, aLayer, aRawPolys );
|
||||
|
||||
if( s_DumpZonesWhenFilling )
|
||||
dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" );
|
||||
|
||||
buildCopperItemClearances( aZone, clearanceHoles );
|
||||
buildCopperItemClearances( aZone, aLayer, clearanceHoles );
|
||||
|
||||
if( s_DumpZonesWhenFilling )
|
||||
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
|
||||
// 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
|
||||
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
|
||||
addHatchFillTypeOnZone( aZone, aRawPolys );
|
||||
addHatchFillTypeOnZone( aZone, aLayer, aRawPolys );
|
||||
|
||||
if( s_DumpZonesWhenFilling )
|
||||
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
|
||||
* ( holes are linked by overlapping segments to the main outline)
|
||||
*/
|
||||
bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPolys,
|
||||
SHAPE_POLY_SET& aFinalPolys )
|
||||
bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET& aRawPolys, SHAPE_POLY_SET& aFinalPolys )
|
||||
{
|
||||
SHAPE_POLY_SET smoothedPoly;
|
||||
std::set<VECTOR2I> colinearCorners;
|
||||
|
@ -834,7 +841,8 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol
|
|||
|
||||
if( aZone->IsOnCopperLayer() )
|
||||
{
|
||||
computeRawFilledArea( aZone, smoothedPoly, &colinearCorners, aRawPolys, aFinalPolys );
|
||||
computeRawFilledArea(
|
||||
aZone, aLayer, smoothedPoly, &colinearCorners, aRawPolys, aFinalPolys );
|
||||
}
|
||||
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
|
||||
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
|
||||
if( aZone->GetFilledPolysUseThickness() )
|
||||
|
@ -877,7 +885,7 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol
|
|||
/**
|
||||
* 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 )
|
||||
{
|
||||
auto zoneBB = aZone->GetBoundingBox();
|
||||
|
@ -898,7 +906,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone,
|
|||
continue;
|
||||
|
||||
// We currently only connect to pads, not pad holes
|
||||
if( !pad->IsOnLayer( aZone->GetLayer() ) )
|
||||
if( !pad->IsOnLayer( aLayer ) )
|
||||
continue;
|
||||
|
||||
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:
|
||||
|
||||
|
|
|
@ -51,9 +51,11 @@ private:
|
|||
|
||||
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
|
||||
|
@ -66,7 +68,7 @@ private:
|
|||
* filled copper area polygon (without clearance areas
|
||||
* @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,
|
||||
std::set<VECTOR2I>* aPreserveCorners,
|
||||
SHAPE_POLY_SET& aRawPolys, SHAPE_POLY_SET& aFinalPolys );
|
||||
|
@ -75,7 +77,8 @@ private:
|
|||
* Function buildThermalSpokes
|
||||
* 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)
|
||||
|
@ -91,7 +94,7 @@ private:
|
|||
* by aZone->GetMinThickness() / 2 to be drawn with a outline thickness = aZone->GetMinThickness()
|
||||
* 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 );
|
||||
|
||||
/**
|
||||
|
@ -101,7 +104,8 @@ private:
|
|||
* @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
|
||||
*/
|
||||
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;
|
||||
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_HatchFillTypeSmoothingValue = 0.1; // Grid pattern chamfer value relative to the gap value
|
||||
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 =
|
||||
ZONE_HATCH_STYLE::DIAGONAL_EDGE; // Option to show the zone area (outlines only,
|
||||
//short hatches or full hatches
|
||||
|
||||
m_Layers.reset().set( F_Cu );
|
||||
|
||||
// thickness of the gap in thermal reliefs:
|
||||
m_ThermalReliefGap = Mils2iu( ZONE_THERMAL_RELIEF_GAP_MIL );
|
||||
// thickness of the copper bridge in thermal reliefs:
|
||||
|
@ -74,6 +75,8 @@ ZONE_SETTINGS::ZONE_SETTINGS()
|
|||
m_cornerSmoothingType = SMOOTHING_NONE;
|
||||
m_cornerRadius = 0;
|
||||
|
||||
m_removeIslands = true;
|
||||
|
||||
SetIsKeepout( false );
|
||||
SetDoNotAllowCopperPour( false );
|
||||
SetDoNotAllowVias( true );
|
||||
|
@ -108,8 +111,8 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
|
|||
m_keepoutDoNotAllowPads = aSource.GetDoNotAllowPads();
|
||||
m_keepoutDoNotAllowFootprints = aSource.GetDoNotAllowFootprints();
|
||||
m_Zone_45_Only = aSource.GetHV45();
|
||||
m_removeIslands = aSource.GetRemoveIslands();
|
||||
|
||||
m_CurrentZone_Layer = aSource.GetLayer();
|
||||
m_Layers = aSource.GetLayerSet();
|
||||
|
||||
return *this;
|
||||
|
@ -138,21 +141,15 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c
|
|||
aTarget.SetDoNotAllowPads( GetDoNotAllowPads() );
|
||||
aTarget.SetDoNotAllowFootprints( GetDoNotAllowFootprints() );
|
||||
aTarget.SetHV45( m_Zone_45_Only );
|
||||
aTarget.SetRemoveIslands( GetRemoveIslands() );
|
||||
|
||||
if( aFullExport )
|
||||
{
|
||||
aTarget.SetPriority( m_ZonePriority );
|
||||
|
||||
// Keepout zones can have multiple layers and have no net
|
||||
if( m_isKeepout )
|
||||
{
|
||||
aTarget.SetLayerSet( m_Layers );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if( !m_isKeepout )
|
||||
aTarget.SetNetCode( m_NetcodeSelection );
|
||||
aTarget.SetLayer( m_CurrentZone_Layer );
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ) ) );
|
||||
aList->AppendItem( row );
|
||||
|
||||
if( m_CurrentZone_Layer == layerID )
|
||||
if( m_Layers.test( layerID ) )
|
||||
aList->SetToggleValue( true, (unsigned) aList->GetItemCount() - 1, 0 );
|
||||
}
|
||||
|
||||
|
|
|
@ -83,9 +83,7 @@ public:
|
|||
|
||||
int m_NetcodeSelection; ///< Net code selection for the current zone
|
||||
|
||||
LSET m_Layers;
|
||||
|
||||
PCB_LAYER_ID m_CurrentZone_Layer; ///< Layer used to create the current zone
|
||||
LSET m_Layers; ///< Layers that this zone exists on
|
||||
|
||||
/// Option to show the zone area (outlines only, short hatches or full hatches
|
||||
ZONE_HATCH_STYLE m_Zone_HatchingStyle;
|
||||
|
@ -114,6 +112,7 @@ private:
|
|||
bool m_keepoutDoNotAllowPads;
|
||||
bool m_keepoutDoNotAllowFootprints;
|
||||
|
||||
bool m_removeIslands;
|
||||
|
||||
public:
|
||||
ZONE_SETTINGS();
|
||||
|
@ -181,6 +180,9 @@ public:
|
|||
void SetDoNotAllowTracks( bool aEnable ) { m_keepoutDoNotAllowTracks = aEnable; }
|
||||
void SetDoNotAllowPads( bool aEnable ) { m_keepoutDoNotAllowPads = 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 ) )
|
||||
{
|
||||
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();
|
||||
|
||||
(void) poly;
|
||||
printf("zone %zu/%d\n", ( areaId + 1 ), brd->GetAreaCount() );
|
||||
printf( "zone %zu/%d\n", ( areaId + 1 ), brd->GetAreaCount() );
|
||||
#if 0
|
||||
PROF_COUNTER unfrac("unfrac");
|
||||
poly.Unfracture( SHAPE_POLY_SET::PM_FAST );
|
||||
|
@ -256,6 +262,7 @@ int polygon_triangulation_main( int argc, char *argv[] )
|
|||
triangulate.Show();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
threadsFinished++;
|
||||
} );
|
||||
|
|
Loading…
Reference in New Issue