From 479af2a7a8c88758673f28020125559a1b37ab87 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Mon, 1 Dec 2014 15:54:33 +0100 Subject: [PATCH] Pcbnew, export Solder masks in Gerber Format: fix not working export when the solder mask minimal width is not 0 (the exported shapes were the same as if the vule = 0) with boost version >= 1.56 This is due to the fact the boost::pylygon function resize ( a inflate/deflate function) used for calculations does not work with boost version >= 1.56. Use Clipper inflate/deflate function instead. It is faster and works fine. --- ...board_items_to_polygon_shape_transform.cpp | 17 ++--- pcbnew/class_zone.cpp | 11 ++++ pcbnew/class_zone.h | 8 +++ pcbnew/event_handlers_tracks_vias_sizes.cpp | 18 +++--- pcbnew/plot_board_layers.cpp | 62 ++++++++++++++----- 5 files changed, 77 insertions(+), 39 deletions(-) diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index 4c98c8c77c..020c5d6b8a 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -580,7 +580,10 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer ClipperLib::Paths shapeWithClearance; for( int ii = 0; ii < 4; ii++ ) + { + corners[ii] += PadShapePos; outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y ); + } ClipperLib::ClipperOffset offset_engine; // Prepare an offset (inflate) transform, with edges connected by arcs @@ -600,19 +603,7 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer offset_engine.Execute( shapeWithClearance, rounding_radius ); // get new outline (only one polygon is expected) - // For info, ClipperLib uses long long to handle integer coordinates - ClipperLib::Path& polygon = shapeWithClearance[0]; - - for( unsigned jj = 0; jj < polygon.size(); jj++ ) - { - corner_position.x = int( polygon[jj].X ); - corner_position.y = int( polygon[jj].Y ); - corner_position += PadShapePos; - CPolyPt polypoint( corner_position.x, corner_position.y ); - aCornerBuffer.Append( polypoint ); - } - - aCornerBuffer.CloseLastContour(); + aCornerBuffer.ImportFrom( shapeWithClearance ); } break; } diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 40ccb300a4..6acefe36c7 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -898,3 +898,14 @@ wxString ZONE_CONTAINER::GetSelectMenuText() const return msg; } + + +/* Copy polygons stored in aKiPolyList to m_FilledPolysList + * The previous m_FilledPolysList contents is replaced. + */ +void ZONE_CONTAINER::CopyPolygonsFromClipperPathsToFilledPolysList( + ClipperLib::Paths& aClipperPolyList ) +{ + m_FilledPolysList.RemoveAllContours(); + m_FilledPolysList.ImportFrom( aClipperPolyList ); +} diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index ee8fdbecdf..87d9727085 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -305,6 +305,14 @@ public: */ void CopyPolygonsFromKiPolygonListToFilledPolysList( KI_POLYGON_SET& aKiPolyList ); + /** + * Function CopyPolygonsFromClipperPathsToFilledPolysList + * Copy polygons stored in aKiPolyList to m_FilledPolysList + * The previous m_FilledPolysList contents is replaced. + * @param aClipperPolyList = a ClipperLib::Paths containing polygons. + */ + void CopyPolygonsFromClipperPathsToFilledPolysList( ClipperLib::Paths& aClipperPolyList ); + /** * Function CopyPolygonsFromFilledPolysListToKiPolygonList * Copy polygons from m_FilledPolysList to aKiPolyList diff --git a/pcbnew/event_handlers_tracks_vias_sizes.cpp b/pcbnew/event_handlers_tracks_vias_sizes.cpp index 21e8d4a000..3361f4b790 100644 --- a/pcbnew/event_handlers_tracks_vias_sizes.cpp +++ b/pcbnew/event_handlers_tracks_vias_sizes.cpp @@ -41,9 +41,7 @@ #include -/** - * Function Tracks_and_Vias_Size_Event - * Event handler for tracks and vias size selection (and some options) +/* Event handler for tracks and vias size selection (and some options) * relative to toolbars and popup events */ void PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event( wxCommandEvent& event ) @@ -51,11 +49,11 @@ void PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event( wxCommandEvent& event ) int ii; int id = event.GetId(); -/* Note: none of these events require aborting the current command (if any) - * (like move, edit or block command) - * so we do not test for a current command in progress and call - * m_canvas->m_endMouseCaptureCallback( m_canvas, &dc ); - */ + /* Note: none of these events require aborting the current command (if any) + * (like move, edit or block command) + * so we do not test for a current command in progress and call + * m_canvas->m_endMouseCaptureCallback( m_canvas, &dc ); + */ switch( id ) { case ID_AUX_TOOLBAR_PCB_SELECT_AUTO_WIDTH: @@ -142,5 +140,7 @@ void PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event( wxCommandEvent& event ) }*/ //+hp //Refresh canvas, that we can see changes instantly. I use this because it dont,t throw mouse up-left corner. - m_canvas->Refresh(); + + if( m_canvas->IsMouseCaptured() ) + m_canvas->Refresh(); } diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 8e412f50f3..6d1f397aba 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -773,12 +773,25 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, zone->TransformOutlinesShapeWithClearanceToPolygon( bufferPolys, inflate, true ); + zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys, + 0, true ); } + // To avoid a lot of code, use a ZONE_CONTAINER + // to handle and plot polygons, because our polygons look exactly like + // filled areas in zones + // Note, also this code is not optimized: it creates a lot of copy/duplicate data + // However it is not complex, and fast enough for plot purposes (copy/convert data + // is only a very small calculation time for these calculations) + ZONE_CONTAINER zone( aBoard ); + zone.SetArcSegmentCount( 32 ); + zone.SetMinThickness( 0 ); // trace polygons only + zone.SetLayer ( layer ); + // Now: - // 1 - merge areas which are intersecting, i.e. remove gaps + // 1 - merge polygons which are intersecting, i.e. remove gaps // having a thickness < aMinThickness - // 2 - deflate resulting areas by aMinThickness/2 + // 2 - deflate resulting polygons by aMinThickness/2 KI_POLYGON_SET areasToMerge; bufferPolys.ExportTo( areasToMerge ); KI_POLYGON_SET initialAreas; @@ -788,29 +801,44 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, // = aMinThickness/2, shapes too close ( dist < aMinThickness ) // will be merged, because they are overlapping KI_POLYGON_SET areas; - areas |= areasToMerge; + areas |= areasToMerge; // Populates with merged polygons // Deflate: remove the extra margin, to create the actual shapes // Here I am using polygon:resize, because this function creates better shapes // than deflate algo. - // Use here deflate with arc creation and 18 segments per circle to create arcs - // In boost polygon (at least v 1.54 and previous) in very rare cases resize crashes - // with 16 segments (perhaps related to 45 degrees pads). So using 18 segments - // is a workaround to try to avoid these crashes - areas = resize( areas, -inflate , true, 18 ); + // Use here deflate made by Clipper, because: + // Clipper is (by far) faster and better, event using arcs to deflate shapes + // boost::polygon < 1.56 polygon resize function sometimes crashes when deflating using arcs + // boost::polygon >=1.56 polygon resize function just does not work + // Note also we combine polygons using boost::polygon, which works better than Clipper, + // especially with zones using holes linked to main outlines by overlapping segments + CPOLYGONS_LIST tmp; + tmp.ImportFrom( areas ); - // Resize slightly changes shapes. So *ensure* initial shapes are kept + // Deflate area using Clipper, better than boost::polygon + ClipperLib::Paths areasDeflate; + tmp.ExportTo( areasDeflate ); + + // Deflate areas: they will have the right size after deflate + ClipperLib::ClipperOffset offset_engine; + circleToSegmentsCount = 16; + offset_engine.ArcTolerance = (double)inflate / 3.14 / circleToSegmentsCount; + offset_engine.AddPaths( areasDeflate, ClipperLib::jtRound, ClipperLib::etClosedPolygon ); + offset_engine.Execute( areasDeflate, -inflate ); + + // Combine the current areas to initial areas. This is mandatory because + // inflate/deflate transform is not perfect, and we want the initial areas perfectly kept + tmp.RemoveAllContours(); + tmp.ImportFrom( areasDeflate ); + areas.clear(); + tmp.ExportTo( areas ); + + // Resize slightly changes shapes (the transform is not perfect). + // So *ensure* initial shapes are kept areas |= initialAreas; - // To avoid a lot of code, use a ZONE_CONTAINER - // to plot polygons, because they are exactly like - // filled areas in zones - ZONE_CONTAINER zone( aBoard ); - zone.SetArcSegmentCount( 32 ); - zone.SetMinThickness( 0 ); // trace polygons only - zone.SetLayer ( layer ); - zone.CopyPolygonsFromKiPolygonListToFilledPolysList( areas ); + itemplotter.PlotFilledAreas( &zone ); }