pcbnew: new zone filling algorithm using ClipperLib. Possibility to fall back to the old one

This commit is contained in:
Tomasz wlostowski 2015-06-12 17:13:18 +02:00 committed by Maciej Suminski
parent feaa403266
commit eba3a55bb2
11 changed files with 569 additions and 138 deletions

View File

@ -72,8 +72,6 @@ void SHAPE_FILE_IO::EndGroup()
void SHAPE_FILE_IO::Write( const SHAPE *aShape, const std::string aName )
{
printf("write %p f %p\n", aShape, m_file );
if(!m_file)
return;

View File

@ -330,8 +330,10 @@ public:
* BuildFilledSolidAreasPolygons() call this function just after creating the
* filled copper area polygon (without clearance areas
* @param aPcb: the current board
* _NG version uses SHAPE_POLY_SET instead of Boost.Polygon
*/
void AddClearanceAreasPolygonsToPolysList( BOARD* aPcb );
void AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb );
/**
@ -578,7 +580,10 @@ public:
#endif
private:
void buildFeatureHoleList( BOARD* aPcb, CPOLYGONS_LIST& aFeatures );
CPolyLine* m_Poly; ///< Outline of the zone.
CPolyLine* m_smoothedPoly; // Corner-smoothed version of m_Poly
int m_cornerSmoothingType;

View File

@ -95,6 +95,10 @@ void DIALOG_GENERALOPTIONS::init()
m_MagneticPadOptCtrl->SetSelection( g_MagneticPadOption );
m_MagneticTrackOptCtrl->SetSelection( g_MagneticTrackOption );
m_UseOldZoneFillingAlgo->SetValue ( g_UseOldZoneFillingAlgo );
m_DumpZonesWhenFilling->SetValue ( g_DumpZonesWhenFilling );
}
@ -143,6 +147,8 @@ void DIALOG_GENERALOPTIONS::OnOkClick( wxCommandEvent& event )
g_TwoSegmentTrackBuild = m_Track_DoubleSegm_Ctrl->GetValue();
g_MagneticPadOption = m_MagneticPadOptCtrl->GetSelection();
g_MagneticTrackOption = m_MagneticTrackOptCtrl->GetSelection();
g_UseOldZoneFillingAlgo = m_UseOldZoneFillingAlgo->GetValue();
g_DumpZonesWhenFilling = m_DumpZonesWhenFilling->GetValue();
EndModal( wxID_OK );
}

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 8 2012)
// C++ code generated with wxFormBuilder (version Jun 6 2014)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -176,7 +176,23 @@ DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE(
sbSizer2PAN->Add( m_AutoPANOpt, 0, wxALL, 5 );
bRightSizer->Add( sbSizer2PAN, 1, wxALL|wxEXPAND, 5 );
bRightSizer->Add( sbSizer2PAN, 1, wxEXPAND, 5 );
wxStaticBoxSizer* sbSizer2Adv;
sbSizer2Adv = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Advanced/Developer") ), wxVERTICAL );
m_UseOldZoneFillingAlgo = new wxCheckBox( this, wxID_ANY, _("Use legacy zone filling algorithm"), wxDefaultPosition, wxDefaultSize, 0 );
m_UseOldZoneFillingAlgo->SetToolTip( _("Keep the cursor at its current location when zooming") );
sbSizer2Adv->Add( m_UseOldZoneFillingAlgo, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
m_DumpZonesWhenFilling = new wxCheckBox( this, wxID_ANY, _("Dump zone geometry to files when filling"), wxDefaultPosition, wxDefaultSize, 0 );
m_DumpZonesWhenFilling->SetToolTip( _("Use middle mouse button dragging to pan") );
sbSizer2Adv->Add( m_DumpZonesWhenFilling, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
bRightSizer->Add( sbSizer2Adv, 1, wxALL|wxEXPAND, 5 );
bSizerUpper->Add( bRightSizer, 0, wxALL|wxEXPAND, 5 );
@ -203,6 +219,7 @@ DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE(
// Connect Events
m_MiddleButtonPANOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnMiddleBtnPanEnbl ), NULL, this );
m_DumpZonesWhenFilling->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnMiddleBtnPanEnbl ), NULL, this );
m_sdbSizerCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnCancelClick ), NULL, this );
m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnOkClick ), NULL, this );
}
@ -211,6 +228,7 @@ DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::~DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE(
{
// Disconnect Events
m_MiddleButtonPANOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnMiddleBtnPanEnbl ), NULL, this );
m_DumpZonesWhenFilling->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnMiddleBtnPanEnbl ), NULL, this );
m_sdbSizerCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnCancelClick ), NULL, this );
m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE::OnOkClick ), NULL, this );

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="11" />
<FileVersion major="1" minor="13" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
@ -20,8 +20,10 @@
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_enum">1</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
@ -573,6 +575,7 @@
<event name="OnSize"></event>
<event name="OnSpinCtrl"></event>
<event name="OnSpinCtrlText"></event>
<event name="OnTextEnter"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
@ -743,6 +746,7 @@
<event name="OnSize"></event>
<event name="OnSpinCtrl"></event>
<event name="OnSpinCtrlText"></event>
<event name="OnTextEnter"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
@ -1745,7 +1749,7 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
@ -1843,11 +1847,11 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="0">
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -1931,11 +1935,11 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="0">
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -2019,11 +2023,11 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="0">
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -2109,6 +2113,196 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="0">
<property name="id">wxID_ANY</property>
<property name="label">Advanced/Developer</property>
<property name="minimum_size"></property>
<property name="name">sbSizer2Adv</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Use legacy zone filling algorithm</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_UseOldZoneFillingAlgo</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip">Keep the cursor at its current location when zooming</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Dump zone geometry to files when filling</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_DumpZonesWhenFilling</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip">Use middle mouse button dragging to pan</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox">OnMiddleBtnPanEnbl</event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 8 2012)
// C++ code generated with wxFormBuilder (version Jun 6 2014)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -78,6 +78,8 @@ class DIALOG_GENERALOPTIONS_BOARDEDITOR_BASE : public DIALOG_SHIM
wxCheckBox* m_MiddleButtonPANOpt;
wxCheckBox* m_OptMiddleButtonPanLimited;
wxCheckBox* m_AutoPANOpt;
wxCheckBox* m_UseOldZoneFillingAlgo;
wxCheckBox* m_DumpZonesWhenFilling;
wxStaticLine* m_staticline1;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;

View File

@ -93,6 +93,9 @@ wxString g_DocModulesFileName = wxT( "footprints_doc/footprints.pdf" );
*/
DLIST<TRACK> g_CurrentTrackList;
bool g_UseOldZoneFillingAlgo = false;
bool g_DumpZonesWhenFilling = false;
namespace PCB {
static struct IFACE : public KIFACE_I

View File

@ -93,6 +93,9 @@ extern bool g_TwoSegmentTrackBuild;
extern int g_MagneticPadOption;
extern int g_MagneticTrackOption;
extern bool g_UseOldZoneFillingAlgo;
extern bool g_DumpZonesWhenFilling;
extern wxPoint g_Offset_Module; // Offset trace when moving footprint.
/// List of segments of the trace currently being drawn.

View File

@ -234,7 +234,7 @@ void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const
}
case SH_CONVEX:
case SH_POLYGON:
case SH_POLY_SET:
case SH_COMPOUND:
break; // Not yet in use
}

View File

@ -104,10 +104,15 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST*
m_FilledPolysList.RemoveAllContours();
if( IsOnCopperLayer() )
AddClearanceAreasPolygonsToPolysList( aPcb );
{
if(g_UseOldZoneFillingAlgo)
AddClearanceAreasPolygonsToPolysList( aPcb );
else
AddClearanceAreasPolygonsToPolysList_NG( aPcb );
}
else
{
int margin = m_ZoneMinThickness / 2;
int margin = m_ZoneMinThickness / 2;
m_smoothedPoly->m_CornersList.InflateOutline(m_FilledPolysList, -margin, true );
}

View File

@ -45,6 +45,7 @@
*/
#include <cmath>
#include <sstream>
#include <fctsys.h>
#include <polygons_defs.h>
@ -58,11 +59,16 @@
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <class_zone.h>
#include <project.h>
#include <pcbnew.h>
#include <zones.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_file_io.h>
#include <boost/foreach.hpp>
extern void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer,
BOARD* aPcb, ZONE_CONTAINER* aZone,
@ -84,116 +90,28 @@ extern void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
// Local Variables:
static double s_thermalRot = 450; // angle of stubs in thermal reliefs for round pads
// how many segments are used to create a polygon from a circle:
static int s_CircleToSegmentsCount = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF; /* default value. the real value will be changed to
* ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF
* if m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF
*/
double s_Correction; /* mult coeff used to enlarge rounded and oval pads (and vias)
* because the segment approximation for arcs and circles
* create a smaller gap than a true circle
*/
/**
* Function AddClearanceAreasPolygonsToPolysList
* Supports a min thickness area constraint.
* Add non copper areas polygons (pads and tracks with clearance)
* to the filled copper area found
* in BuildFilledPolysListData after calculating filled areas in a zone
* Non filled copper areas are pads and track and their clearance areas
* The filled copper area must be computed just before.
* BuildFilledPolysListData() call this function just after creating the
* filled copper area polygon (without clearance areas)
* to do that this function:
* 1 - Creates the main outline (zone outline) using a correction to shrink the resulting area
* with m_ZoneMinThickness/2 value.
* The result is areas with a margin of m_ZoneMinThickness/2
* When drawing outline with segments having a thickness of m_ZoneMinThickness, the
* outlines will match exactly the initial outlines
* 3 - Add all non filled areas (pads, tracks) in group B with a clearance of m_Clearance +
* m_ZoneMinThickness/2
* in a buffer
* - If Thermal shapes are wanted, add non filled area, in order to create these thermal shapes
* 4 - calculates the polygon A - B
* 5 - put resulting list of polygons (filled areas) in m_FilledPolysList
* This zone contains pads with the same net.
* 6 - Remove insulated copper islands
* 7 - If Thermal shapes are wanted, remove unconnected stubs in thermal shapes:
* creates a buffer of polygons corresponding to stubs to remove
* sub them to the filled areas.
* Remove new insulated copper islands
*/
void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, CPOLYGONS_LIST& aFeatures )
{
int segsPerCircle;
double correctionFactor;
// Set the number of segments in arc approximations
if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF )
s_CircleToSegmentsCount = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
else
s_CircleToSegmentsCount = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;
/* calculates the coeff to compensate radius reduction of holes clearance
* due to the segment approx.
* For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
* s_Correction is 1 /cos( PI/s_CircleToSegmentsCount )
*/
s_Correction = 1.0 / cos( M_PI / s_CircleToSegmentsCount );
correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );
// this is a place to store holes (i.e. tracks, pads ... areas as polygons outlines)
// static to avoid unnecessary memory allocation when filling many zones.
static CPOLYGONS_LIST cornerBufferPolysToSubstract;
cornerBufferPolysToSubstract.RemoveAllContours();
aFeatures.RemoveAllContours();
// This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2
KI_POLYGON_SET polyset_zone_solid_areas;
int outline_half_thickness = m_ZoneMinThickness / 2;
/* First, creates the main polygon (i.e. the filled area using only one outline)
* to reserve a m_ZoneMinThickness/2 margin around the outlines and holes
* this margin is the room to redraw outlines with segments having a width set to
* m_ZoneMinThickness
* so m_ZoneMinThickness is the min thickness of the filled zones areas
* the main polygon is stored in polyset_zone_solid_areas
*/
#if 0
m_smoothedPoly->m_CornersList.ExportTo( polyset_zone_solid_areas );
if( polyset_zone_solid_areas.size() == 0 )
return;
// Extract holes (cutout areas) and add them to the hole buffer
KI_POLYGON_SET outlineHoles;
while( polyset_zone_solid_areas.size() > 1 )
{
outlineHoles.push_back( polyset_zone_solid_areas.back() );
polyset_zone_solid_areas.pop_back();
}
// deflate main outline reserve room for thick outline
polyset_zone_solid_areas -= outline_half_thickness;
// inflate outline holes
if( outlineHoles.size() )
outlineHoles += outline_half_thickness;
if( outlineHoles.size() )
cornerBufferPolysToSubstract.ImportFrom( outlineHoles );
#else
CPOLYGONS_LIST tmp;
m_smoothedPoly->m_CornersList.InflateOutline( tmp, -outline_half_thickness, true );
tmp.ExportTo( polyset_zone_solid_areas );
if( polyset_zone_solid_areas.size() == 0 )
return;
#endif
/* Calculates the clearance value that meet DRC requirements
* from m_ZoneClearance and clearance from the corresponding netclass
* We have a "local" clearance in zones because most of time
* clearance between a zone and others items is bigger than the netclass clearance
* this is more true for small clearance values
* Note also the "local" clearance is used for clearance between non copper items
* or items like texts on copper layers
*/
int zone_clearance = std::max( m_ZoneClearance, GetClearance() );
zone_clearance += outline_half_thickness;
@ -266,10 +184,10 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
if( item_boundingbox.Intersects( zone_boundingbox ) )
{
int clearance = std::max( zone_clearance, item_clearance );
pad->TransformShapeWithClearanceToPolygon( cornerBufferPolysToSubstract,
pad->TransformShapeWithClearanceToPolygon( aFeatures,
clearance,
s_CircleToSegmentsCount,
s_Correction );
segsPerCircle,
correctionFactor );
}
continue;
@ -284,10 +202,10 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
if( item_boundingbox.Intersects( zone_boundingbox ) )
{
pad->TransformShapeWithClearanceToPolygon( cornerBufferPolysToSubstract,
pad->TransformShapeWithClearanceToPolygon( aFeatures,
gap,
s_CircleToSegmentsCount,
s_Correction );
segsPerCircle,
correctionFactor );
}
}
}
@ -310,10 +228,10 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
if( item_boundingbox.Intersects( zone_boundingbox ) )
{
int clearance = std::max( zone_clearance, item_clearance );
track->TransformShapeWithClearanceToPolygon( cornerBufferPolysToSubstract,
track->TransformShapeWithClearanceToPolygon( aFeatures,
clearance,
s_CircleToSegmentsCount,
s_Correction );
segsPerCircle,
correctionFactor );
}
}
@ -336,8 +254,8 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
if( item_boundingbox.Intersects( zone_boundingbox ) )
{
( (EDGE_MODULE*) item )->TransformShapeWithClearanceToPolygon(
cornerBufferPolysToSubstract, zone_clearance,
s_CircleToSegmentsCount, s_Correction );
aFeatures, zone_clearance,
segsPerCircle, correctionFactor );
}
}
}
@ -352,13 +270,13 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
{
case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
cornerBufferPolysToSubstract,
zone_clearance, s_CircleToSegmentsCount, s_Correction );
aFeatures,
zone_clearance, segsPerCircle, correctionFactor );
break;
case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformBoundingBoxWithClearanceToPolygon(
cornerBufferPolysToSubstract, zone_clearance );
aFeatures, zone_clearance );
break;
default:
@ -409,7 +327,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
}
zone->TransformOutlinesShapeWithClearanceToPolygon(
cornerBufferPolysToSubstract,
aFeatures,
min_clearance, use_net_clearance );
}
@ -438,26 +356,304 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
if( item_boundingbox.Intersects( zone_boundingbox ) )
{
CreateThermalReliefPadPolygon( cornerBufferPolysToSubstract,
CreateThermalReliefPadPolygon( aFeatures,
*pad, thermalGap,
GetThermalReliefCopperBridge( pad ),
m_ZoneMinThickness,
s_CircleToSegmentsCount,
s_Correction, s_thermalRot );
segsPerCircle,
correctionFactor, s_thermalRot );
}
}
}
}
static const SHAPE_POLY_SET convertPolyListToPolySet(const CPOLYGONS_LIST& aList)
{
SHAPE_POLY_SET rv;
unsigned corners_count = aList.GetCornersCount();
// Enter main outline: this is the first contour
unsigned ic = 0;
if(!corners_count)
return rv;
while( ic < corners_count )
{
rv.NewOutline( );
while( ic < corners_count )
{
rv.AppendVertex( aList.GetX(ic), aList.GetY(ic) );
if( aList.IsEndContour( ic ) )
break;
ic++;
}
ic++;
}
return rv;
}
static const CPOLYGONS_LIST convertPolySetToPolyList(const SHAPE_POLY_SET& aPolyset)
{
CPOLYGONS_LIST list;
CPolyPt corner, firstCorner;
for( int ii = 0; ii < aPolyset.OutlineCount(); ii++ )
{
for( int jj = 0; jj < aPolyset.VertexCount(ii); jj++ )
{
VECTOR2I v = aPolyset.GetVertex( jj, ii );
corner.x = v.x;
corner.y = v.y;
corner.end_contour = false;
if(!jj)
firstCorner = corner;
list.AddCorner( corner );
}
firstCorner.end_contour = true;
list.AddCorner( firstCorner );
}
return list;
}
static const SHAPE_POLY_SET convertBoostToPolySet ( const KI_POLYGON_SET& aSet )
{
SHAPE_POLY_SET rv;
BOOST_FOREACH ( const KI_POLYGON &poly, aSet )
{
rv.NewOutline();
for ( KI_POLYGON::iterator_type corner = poly.begin(); corner != poly.end(); ++ corner )
{
rv.AppendVertex ( corner->x(), corner->y() );
}
}
return rv;
}
/**
* Function AddClearanceAreasPolygonsToPolysList
* Supports a min thickness area constraint.
* Add non copper areas polygons (pads and tracks with clearance)
* to the filled copper area found
* in BuildFilledPolysListData after calculating filled areas in a zone
* Non filled copper areas are pads and track and their clearance areas
* The filled copper area must be computed just before.
* BuildFilledPolysListData() call this function just after creating the
* filled copper area polygon (without clearance areas)
* to do that this function:
* 1 - Creates the main outline (zone outline) using a correction to shrink the resulting area
* with m_ZoneMinThickness/2 value.
* The result is areas with a margin of m_ZoneMinThickness/2
* When drawing outline with segments having a thickness of m_ZoneMinThickness, the
* outlines will match exactly the initial outlines
* 3 - Add all non filled areas (pads, tracks) in group B with a clearance of m_Clearance +
* m_ZoneMinThickness/2
* in a buffer
* - If Thermal shapes are wanted, add non filled area, in order to create these thermal shapes
* 4 - calculates the polygon A - B
* 5 - put resulting list of polygons (filled areas) in m_FilledPolysList
* This zone contains pads with the same net.
* 6 - Remove insulated copper islands
* 7 - If Thermal shapes are wanted, remove unconnected stubs in thermal shapes:
* creates a buffer of polygons corresponding to stubs to remove
* sub them to the filled areas.
* Remove new insulated copper islands
*/
void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
{
int segsPerCircle;
double correctionFactor;
int outline_half_thickness = m_ZoneMinThickness / 2;
std::auto_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO( "zones_dump.txt", true ) );
// Set the number of segments in arc approximations
if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF )
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
else
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;
/* calculates the coeff to compensate radius reduction of holes clearance
* due to the segment approx.
* For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
* s_Correction is 1 /cos( PI/s_CircleToSegmentsCount )
*/
correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );
CPOLYGONS_LIST tmp;
if(g_DumpZonesWhenFilling)
dumper->BeginGroup("clipper-zone");
m_smoothedPoly->m_CornersList.InflateOutline( tmp, -outline_half_thickness, true );
SHAPE_POLY_SET solidAreas = convertPolyListToPolySet( tmp );
if(g_DumpZonesWhenFilling)
dumper->Write ( &solidAreas, "solid-areas" );
tmp.RemoveAllContours();
buildFeatureHoleList( aPcb, tmp );
SHAPE_POLY_SET holes = convertPolyListToPolySet( tmp );
if(g_DumpZonesWhenFilling)
dumper->Write ( &holes, "feature-holes" );
holes.Simplify();
if (g_DumpZonesWhenFilling)
dumper->Write ( &holes, "feature-holes-postsimplify" );
solidAreas.Subtract ( holes );
if (g_DumpZonesWhenFilling)
dumper->Write ( &solidAreas, "solid-areas-minus-holes" );
m_FilledPolysList.RemoveAllContours();
SHAPE_POLY_SET fractured = solidAreas;
fractured.Fracture();
if (g_DumpZonesWhenFilling)
dumper->Write ( &fractured, "fractured" );
m_FilledPolysList = convertPolySetToPolyList( fractured );
if (g_DumpZonesWhenFilling)
{
SHAPE_POLY_SET dupa = convertPolyListToPolySet ( m_FilledPolysList );
dumper->Write ( &dupa, "verify-conv" );
}
// Remove insulated islands:
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
tmp.RemoveAllContours();
// Test thermal stubs connections and add polygons to remove unconnected stubs.
// (this is a refinement for thermal relief shapes)
if( GetNetCode() > 0 )
BuildUnconnectedThermalStubsPolygonList( tmp, aPcb, this,
correctionFactor, s_thermalRot );
// remove copper areas corresponding to not connected stubs
if( tmp.GetCornersCount() )
{
SHAPE_POLY_SET thermalHoles = convertPolyListToPolySet ( tmp );
thermalHoles.Simplify();
// Remove unconnected stubs
solidAreas.Subtract ( thermalHoles );
if (g_DumpZonesWhenFilling)
dumper->Write ( &thermalHoles, "thermal-holes" );
// put these areas in m_FilledPolysList
m_FilledPolysList.RemoveAllContours();
SHAPE_POLY_SET fractured = solidAreas;
fractured.Fracture();
if (g_DumpZonesWhenFilling)
dumper->Write ( &fractured, "fractured" );
m_FilledPolysList = convertPolySetToPolyList( fractured );
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
}
if(g_DumpZonesWhenFilling)
dumper->EndGroup();
}
void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
{
int segsPerCircle;
double correctionFactor;
std::auto_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO( "zones_dump.txt", true ) );
if(g_DumpZonesWhenFilling)
dumper->BeginGroup("boost-zone");
// Set the number of segments in arc approximations
if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF )
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
else
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;
/* calculates the coeff to compensate radius reduction of holes clearance
* due to the segment approx.
* For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
* s_Correction is 1 /cos( PI/s_CircleToSegmentsCount )
*/
correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );
// this is a place to store holes (i.e. tracks, pads ... areas as polygons outlines)
// static to avoid unnecessary memory allocation when filling many zones.
CPOLYGONS_LIST cornerBufferPolysToSubstract;
// This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2
KI_POLYGON_SET polyset_zone_solid_areas;
int outline_half_thickness = m_ZoneMinThickness / 2;
/* First, creates the main polygon (i.e. the filled area using only one outline)
* to reserve a m_ZoneMinThickness/2 margin around the outlines and holes
* this margin is the room to redraw outlines with segments having a width set to
* m_ZoneMinThickness
* so m_ZoneMinThickness is the min thickness of the filled zones areas
* the main polygon is stored in polyset_zone_solid_areas
*/
CPOLYGONS_LIST tmp;
m_smoothedPoly->m_CornersList.InflateOutline( tmp, -outline_half_thickness, true );
tmp.ExportTo( polyset_zone_solid_areas );
if( polyset_zone_solid_areas.size() == 0 )
return;
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "solid-areas" );
buildFeatureHoleList( aPcb, cornerBufferPolysToSubstract );
// cornerBufferPolysToSubstract contains polygons to substract.
// polyset_zone_solid_areas contains the main filled area
// Calculate now actual solid areas
if( cornerBufferPolysToSubstract.GetCornersCount() > 0 )
{
KI_POLYGON_SET polyset_holes;
cornerBufferPolysToSubstract.ExportTo( polyset_holes );
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_holes ), "feature-holes" );
// Remove holes from initial area.:
polyset_zone_solid_areas -= polyset_holes;
}
}
// put solid areas in m_FilledPolysList:
m_FilledPolysList.RemoveAllContours();
@ -474,7 +670,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
// (this is a refinement for thermal relief shapes)
if( GetNetCode() > 0 )
BuildUnconnectedThermalStubsPolygonList( cornerBufferPolysToSubstract, aPcb, this,
s_Correction, s_thermalRot );
correctionFactor, s_thermalRot );
// remove copper areas corresponding to not connected stubs
if( cornerBufferPolysToSubstract.GetCornersCount() )
@ -482,6 +678,9 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
KI_POLYGON_SET polyset_holes;
cornerBufferPolysToSubstract.ExportTo( polyset_holes );
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_holes ), "thermal-holes" );
// Remove unconnected stubs
polyset_zone_solid_areas -= polyset_holes;
@ -493,6 +692,10 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
}
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "complete" );
cornerBufferPolysToSubstract.RemoveAllContours();
}
@ -502,9 +705,3 @@ void ZONE_CONTAINER::CopyPolygonsFromKiPolygonListToFilledPolysList( KI_POLYGON_
m_FilledPolysList.RemoveAllContours();
m_FilledPolysList.ImportFrom( aKiPolyList );
}
void ZONE_CONTAINER::CopyPolygonsFromFilledPolysListToKiPolygonList( KI_POLYGON_SET& aKiPolyList )
{
m_FilledPolysList.ExportTo( aKiPolyList );
}