From eba3a55bb21cc7b34a507883e30a8d6fb79f8679 Mon Sep 17 00:00:00 2001 From: Tomasz wlostowski Date: Fri, 12 Jun 2015 17:13:18 +0200 Subject: [PATCH] pcbnew: new zone filling algorithm using ClipperLib. Possibility to fall back to the old one --- common/geometry/shape_file_io.cpp | 2 - pcbnew/class_zone.h | 5 + pcbnew/dialogs/dialog_general_options.cpp | 6 + ...ialog_general_options_BoardEditor_base.cpp | 22 +- ...ialog_general_options_BoardEditor_base.fbp | 210 ++++++++- .../dialog_general_options_BoardEditor_base.h | 4 +- pcbnew/pcbnew.cpp | 3 + pcbnew/pcbnew.h | 3 + pcbnew/router/router_preview_item.cpp | 2 +- pcbnew/zone_filling_algorithm.cpp | 9 +- ...nvert_brd_items_to_polygons_with_Boost.cpp | 441 +++++++++++++----- 11 files changed, 569 insertions(+), 138 deletions(-) diff --git a/common/geometry/shape_file_io.cpp b/common/geometry/shape_file_io.cpp index 59e0b0caf8..ddf3de2b6b 100644 --- a/common/geometry/shape_file_io.cpp +++ b/common/geometry/shape_file_io.cpp @@ -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; diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 3e20c91b98..be82b100d3 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -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; diff --git a/pcbnew/dialogs/dialog_general_options.cpp b/pcbnew/dialogs/dialog_general_options.cpp index 4c66d7e73e..2406a9ee13 100644 --- a/pcbnew/dialogs/dialog_general_options.cpp +++ b/pcbnew/dialogs/dialog_general_options.cpp @@ -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 ); } diff --git a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.cpp b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.cpp index 6a2daad28a..250d77a0d1 100644 --- a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.cpp +++ b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.cpp @@ -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 ); diff --git a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp index e4b73b36fa..225be7bf7f 100644 --- a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp +++ b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp @@ -1,6 +1,6 @@ - + C++ @@ -20,8 +20,10 @@ . 1 + 1 1 1 + UI 1 0 @@ -573,6 +575,7 @@ + @@ -743,6 +746,7 @@ + @@ -1745,7 +1749,7 @@ 5 - wxALL|wxEXPAND + wxEXPAND 1 wxID_ANY @@ -1843,11 +1847,11 @@ - + 5 wxLEFT|wxRIGHT|wxTOP 0 - + 1 1 1 @@ -1931,11 +1935,11 @@ - + 5 wxLEFT|wxRIGHT|wxTOP 0 - + 1 1 1 @@ -2019,11 +2023,11 @@ - + 5 wxALL 0 - + 1 1 1 @@ -2109,6 +2113,196 @@ + + 5 + wxALL|wxEXPAND + 1 + + wxID_ANY + Advanced/Developer + + sbSizer2Adv + wxVERTICAL + none + + + 5 + wxLEFT|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Use legacy zone filling algorithm + + 0 + + + 0 + + 1 + m_UseOldZoneFillingAlgo + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Keep the cursor at its current location when zooming + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxLEFT|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Dump zone geometry to files when filling + + 0 + + + 0 + + 1 + m_DumpZonesWhenFilling + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Use middle mouse button dragging to pan + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnMiddleBtnPanEnbl + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.h b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.h index b66bb0c3f7..bd6694bf89 100644 --- a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.h +++ b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.h @@ -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; diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index c589d9ce8f..c46928c3f2 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -93,6 +93,9 @@ wxString g_DocModulesFileName = wxT( "footprints_doc/footprints.pdf" ); */ DLIST g_CurrentTrackList; +bool g_UseOldZoneFillingAlgo = false; +bool g_DumpZonesWhenFilling = false; + namespace PCB { static struct IFACE : public KIFACE_I diff --git a/pcbnew/pcbnew.h b/pcbnew/pcbnew.h index 32329d727e..77fcd89af2 100644 --- a/pcbnew/pcbnew.h +++ b/pcbnew/pcbnew.h @@ -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. diff --git a/pcbnew/router/router_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index 06c99905b1..1e4974f554 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -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 } diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index 3779e7b433..400d977a69 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -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 ); } diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp index d527206a96..e5f2cac1fa 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp @@ -45,6 +45,7 @@ */ #include +#include #include #include @@ -58,11 +59,16 @@ #include #include #include +#include #include #include #include +#include +#include + +#include 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 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 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 ); -}