Move remaining hard-coded segment counts

This removes the remaining hard-coded segments counts and replaces them
with the relative error calculation where the segments per arc is
determined by the maximum error we allow (smaller arcs = fewer segments)
This commit is contained in:
Seth Hillbrand 2019-05-14 05:39:34 -07:00
parent 8378f97a78
commit ddc6079ceb
34 changed files with 404 additions and 692 deletions

View File

@ -836,12 +836,9 @@ void CINFO3D_VISU::AddShapeWithClearanceToContainer( const DRAWSEGMENT* aDrawSeg
case S_CURVE: case S_CURVE:
case S_POLYGON: case S_POLYGON:
{ {
const int segcountforcircle = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
const double correctionFactor = GetCircleCorrectionFactor( segcountforcircle );
SHAPE_POLY_SET polyList; SHAPE_POLY_SET polyList;
aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aClearanceValue, aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aClearanceValue );
segcountforcircle, correctionFactor );
polyList.Simplify( SHAPE_POLY_SET::PM_FAST ); polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
@ -967,15 +964,7 @@ void CINFO3D_VISU::buildPadShapeThickOutlineAsSegments( const D_PAD* aPad,
// For other shapes, draw polygon outlines // For other shapes, draw polygon outlines
SHAPE_POLY_SET corners; SHAPE_POLY_SET corners;
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ) );
const int segcountforcircle = GetNrSegmentsCircle( glm::min( aPad->GetSize().x,
aPad->GetSize().y) );
const double correctionFactor = GetCircleCorrectionFactor( segcountforcircle );
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ),
// This two factors are only expected to be used if render an oval
segcountforcircle, correctionFactor );
// Add outlines as thick segments in polygon buffer // Add outlines as thick segments in polygon buffer
@ -992,15 +981,13 @@ void CINFO3D_VISU::buildPadShapeThickOutlineAsSegments( const D_PAD* aPad,
if( Is_segment_a_circle( start3DU, end3DU ) ) if( Is_segment_a_circle( start3DU, end3DU ) )
{ {
aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, aDstContainer->Add(
(aWidth / 2) * m_biuTo3Dunits, new CFILLEDCIRCLE2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits, *aPad ) );
*aPad ) );
} }
else else
{ {
aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, aDstContainer->Add(
aWidth * m_biuTo3Dunits, new CROUNDSEGMENT2D( start3DU, end3DU, aWidth * m_biuTo3Dunits, *aPad ) );
*aPad ) );
} }
} }
} }

View File

@ -140,17 +140,6 @@ void CINFO3D_VISU::destroyLayers()
void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter ) void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
{ {
// Number of segments to draw a circle using segments (used on countour zones
// and text copper elements )
const int segcountforcircle = 12;
const double correctionFactor = GetCircleCorrectionFactor( segcountforcircle );
// segments to draw a circle to build texts. Is is used only to build
// the shape of each segment of the stroke font, therefore no need to have
// many segments per circle.
const int segcountInStrokeFont = 12;
const double correctionFactorStroke = GetCircleCorrectionFactor( segcountInStrokeFont );
destroyLayers(); destroyLayers();
// Build Copper layers // Build Copper layers
@ -563,28 +552,16 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
// The hole in the body is inflated by copper thickness. // The hole in the body is inflated by copper thickness.
const int inflate = GetCopperThicknessBIU(); const int inflate = GetCopperThicknessBIU();
// we use the hole diameter to calculate the seg count.
// for round holes, padHole.x == padHole.y
// for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
const int diam = std::min( padHole.x, padHole.y );
if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED ) if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED )
{ {
pad->BuildPadDrillShapePolygon( m_through_outer_holes_poly, pad->BuildPadDrillShapePolygon( m_through_outer_holes_poly, inflate );
inflate,
GetNrSegmentsCircle( diam ) );
pad->BuildPadDrillShapePolygon( m_through_inner_holes_poly, pad->BuildPadDrillShapePolygon( m_through_inner_holes_poly, 0 );
0,
GetNrSegmentsCircle( diam ) );
} }
else else
{ {
// If not plated, no copper. // If not plated, no copper.
pad->BuildPadDrillShapePolygon( m_through_outer_holes_poly_NPTH, pad->BuildPadDrillShapePolygon( m_through_outer_holes_poly_NPTH, inflate );
inflate,
GetNrSegmentsCircle( diam ) );
} }
} }
} }
@ -656,11 +633,8 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
true ); true );
// Micro-wave modules may have items on copper layers // Micro-wave modules may have items on copper layers
module->TransformGraphicTextWithClearanceToPolygonSet( curr_layer_id, module->TransformGraphicTextWithClearanceToPolygonSet(
*layerPoly, curr_layer_id, *layerPoly, 0 );
0,
segcountforcircle,
correctionFactor );
transformGraphicModuleEdgeToPolygonSet( module, curr_layer_id, *layerPoly ); transformGraphicModuleEdgeToPolygonSet( module, curr_layer_id, *layerPoly );
} }
@ -749,29 +723,15 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
switch( item->Type() ) switch( item->Type() )
{ {
case PCB_LINE_T: case PCB_LINE_T:
{ ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly, 0 );
const int nrSegments =
GetNrSegmentsCircle( item->GetBoundingBox().GetSizeMax() );
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
*layerPoly,
0,
nrSegments,
GetCircleCorrectionFactor( nrSegments ) );
}
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( *layerPoly, 0 );
*layerPoly,
0,
segcountforcircle,
correctionFactor );
break; break;
default: default:
wxLogTrace( m_logTrace, wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
wxT( "createLayers: item type: %d not implemented" ),
item->Type() ); item->Type() );
break; break;
} }
@ -846,7 +806,7 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
auto layerContainer = m_layers_poly.find( zone->GetLayer() ); auto layerContainer = m_layers_poly.find( zone->GetLayer() );
if( layerContainer != m_layers_poly.end() ) if( layerContainer != m_layers_poly.end() )
zone->TransformSolidAreasShapesToPolygonSet( *layerContainer->second, segcountforcircle, correctionFactor ); zone->TransformSolidAreasShapesToPolygonSet( *layerContainer->second );
} }
} }
@ -1034,22 +994,11 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
switch( item->Type() ) switch( item->Type() )
{ {
case PCB_LINE_T: case PCB_LINE_T:
{ ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly, 0 );
const unsigned int nr_segments =
GetNrSegmentsCircle( item->GetBoundingBox().GetSizeMax() );
((DRAWSEGMENT*) item)->TransformShapeWithClearanceToPolygon( *layerPoly,
0,
nr_segments,
0.0 );
}
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:
((TEXTE_PCB*) item)->TransformShapeWithClearanceToPolygonSet( *layerPoly, ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( *layerPoly, 0 );
0,
segcountInStrokeFont,
1.0 );
break; break;
default: default:
@ -1072,24 +1021,16 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
if( !pad->IsOnLayer( curr_layer_id ) ) if( !pad->IsOnLayer( curr_layer_id ) )
continue; continue;
buildPadShapeThickOutlineAsSegments( pad, buildPadShapeThickOutlineAsSegments( pad, layerContainer, linewidth );
layerContainer,
linewidth );
} }
} }
else else
{ {
AddPadsShapesWithClearanceToContainer( module, AddPadsShapesWithClearanceToContainer(
layerContainer, module, layerContainer, curr_layer_id, 0, false );
curr_layer_id,
0,
false );
} }
AddGraphicsShapesWithClearanceToContainer( module, AddGraphicsShapesWithClearanceToContainer( module, layerContainer, curr_layer_id, 0 );
layerContainer,
curr_layer_id,
0 );
} }
@ -1112,20 +1053,12 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
} }
else else
{ {
transformPadsShapesWithClearanceToPolygon( module->PadsList(), transformPadsShapesWithClearanceToPolygon(
curr_layer_id, module->PadsList(), curr_layer_id, *layerPoly, 0, false );
*layerPoly,
0,
false );
} }
// On tech layers, use a poor circle approximation, only for texts (stroke font) // On tech layers, use a poor circle approximation, only for texts (stroke font)
module->TransformGraphicTextWithClearanceToPolygonSet( curr_layer_id, module->TransformGraphicTextWithClearanceToPolygonSet( curr_layer_id, *layerPoly, 0 );
*layerPoly,
0,
segcountInStrokeFont,
correctionFactorStroke,
segcountInStrokeFont );
// Add the remaining things with dynamic seg count for circles // Add the remaining things with dynamic seg count for circles
transformGraphicModuleEdgeToPolygonSet( module, curr_layer_id, *layerPoly ); transformGraphicModuleEdgeToPolygonSet( module, curr_layer_id, *layerPoly );
@ -1155,10 +1088,7 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter )
if( !zone->IsOnLayer( curr_layer_id ) ) if( !zone->IsOnLayer( curr_layer_id ) )
continue; continue;
zone->TransformSolidAreasShapesToPolygonSet( *layerPoly, zone->TransformSolidAreasShapesToPolygonSet( *layerPoly );
// Use the same segcount as stroke font
segcountInStrokeFont,
correctionFactorStroke );
} }
} }

View File

@ -823,13 +823,10 @@ void C3D_RENDER_OGL_LEGACY::generate_3D_Vias_and_Pads()
double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments ); double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments );
int correction = radius * ( correctionFactor - 1 ); int correction = radius * ( correctionFactor - 1 );
pad->BuildPadDrillShapePolygon( tht_outer_holes_poly, pad->BuildPadDrillShapePolygon(
copperThickness + correction, tht_outer_holes_poly, copperThickness + correction );
nrSegments );
pad->BuildPadDrillShapePolygon( tht_inner_holes_poly, pad->BuildPadDrillShapePolygon( tht_inner_holes_poly, correction );
correction,
nrSegments );
} }
} }
} }

View File

@ -34,7 +34,6 @@ set( GAL_SRCS
draw_panel_gal.cpp draw_panel_gal.cpp
gl_context_mgr.cpp gl_context_mgr.cpp
newstroke_font.cpp newstroke_font.cpp
origin_viewitem.cpp
painter.cpp painter.cpp
text_utils.cpp text_utils.cpp
worksheet_viewitem.cpp worksheet_viewitem.cpp
@ -322,7 +321,6 @@ set( COMMON_SRCS
getrunningmicrosecs.cpp getrunningmicrosecs.cpp
gr_basic.cpp gr_basic.cpp
grid_tricks.cpp grid_tricks.cpp
hash_eda.cpp
hotkey_store.cpp hotkey_store.cpp
hotkeys_basic.cpp hotkeys_basic.cpp
html_messagebox.cpp html_messagebox.cpp
@ -444,7 +442,9 @@ set( PCB_COMMON_SRCS
base_screen.cpp base_screen.cpp
eda_text.cpp eda_text.cpp
fp_lib_table.cpp fp_lib_table.cpp
hash_eda.cpp
lset.cpp lset.cpp
origin_viewitem.cpp
page_info.cpp page_info.cpp
pcb_keywords.cpp pcb_keywords.cpp
pcb_plot_params_keywords.cpp pcb_plot_params_keywords.cpp

View File

@ -28,7 +28,6 @@
* and their documentation (comments and keywords) * and their documentation (comments and keywords)
*/ */
#include <class_module.h>
#include <common.h> #include <common.h>
#include <fctsys.h> #include <fctsys.h>
#include <footprint_info.h> #include <footprint_info.h>

View File

@ -45,7 +45,6 @@
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
#include <limits> #include <limits>
#include <board_connected_item.h>
#include <memory> #include <memory>
using namespace hed; using namespace hed;

View File

@ -24,7 +24,6 @@
#include <preview_items/bright_box.h> #include <preview_items/bright_box.h>
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
#include <class_track.h>
using namespace KIGFX; using namespace KIGFX;

View File

@ -25,7 +25,8 @@
#include <tool/tool_event.h> #include <tool/tool_event.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <pcb_edit_frame.h> #include <draw_frame.h>
#include <eda_base_frame.h>
bool TOOL_BASE::IsToolActive() const bool TOOL_BASE::IsToolActive() const
{ {
@ -94,9 +95,8 @@ wxConfigBase* TOOL_SETTINGS::getConfigBase() const
if( !m_tool ) if( !m_tool )
return NULL; return NULL;
// fixme: make independent of pcbnew (post-stable) if( EDA_BASE_FRAME* frame = m_tool->getEditFrame<EDA_BASE_FRAME>() )
if( PCB_EDIT_FRAME* frame = m_tool->getEditFrame<PCB_EDIT_FRAME>() ) return frame->config();
return frame->GetSettings();
return NULL; return NULL;
} }

View File

@ -23,7 +23,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <pcb_edit_frame.h> #include <macros.h>
#include <trace_helpers.h> #include <trace_helpers.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
@ -33,6 +33,7 @@
#include <view/wx_view_controls.h> #include <view/wx_view_controls.h>
#include <class_draw_panel_gal.h> #include <class_draw_panel_gal.h>
#include <draw_frame.h>
#include <pcbnew_id.h> #include <pcbnew_id.h>
#include <core/optional.h> #include <core/optional.h>
@ -319,10 +320,10 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
// Sometimes there is no window that has the focus (it happens when another PCB_BASE_FRAME // Sometimes there is no window that has the focus (it happens when another PCB_BASE_FRAME
// is opened and is iconized on Windows). // is opened and is iconized on Windows).
// In this case, gives the focus to the parent PCB_BASE_FRAME (for an obscure reason, // In this case, gives the focus to the parent frame (for an obscure reason,
// when happens, the GAL canvas itself does not accept the focus) // when happens, the GAL canvas itself does not accept the focus)
if( wxWindow::FindFocus() == nullptr ) if( wxWindow::FindFocus() == nullptr )
static_cast<PCB_BASE_FRAME*>( m_toolMgr->GetEditFrame() )->SetFocus(); m_toolMgr->GetEditFrame()->SetFocus();
// Mouse handling // Mouse handling
// Note: wxEVT_LEFT_DOWN event must always be skipped. // Note: wxEVT_LEFT_DOWN event must always be skipped.

View File

@ -41,8 +41,8 @@
#include <tool/coroutine.h> #include <tool/coroutine.h>
#include <tool/action_manager.h> #include <tool/action_manager.h>
#include <pcb_edit_frame.h>
#include <class_draw_panel_gal.h> #include <class_draw_panel_gal.h>
#include <draw_frame.h>
/// Struct describing the current execution state of a TOOL /// Struct describing the current execution state of a TOOL
struct TOOL_MANAGER::TOOL_STATE struct TOOL_MANAGER::TOOL_STATE

View File

@ -17,15 +17,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <pcb_edit_frame.h>
#include <class_draw_panel_gal.h> #include <class_draw_panel_gal.h>
#include <view/view_controls.h> #include <draw_frame.h>
#include <view/view.h> #include <id.h>
#include <tool/tool_manager.h>
#include <tool/actions.h>
#include <tool/zoom_tool.h>
#include <preview_items/selection_area.h> #include <preview_items/selection_area.h>
#include <tool/actions.h>
#include <tool/tool_manager.h>
#include <tool/zoom_tool.h>
#include <view/view.h>
#include <view/view_controls.h>
ZOOM_TOOL::ZOOM_TOOL() : ZOOM_TOOL::ZOOM_TOOL() :

View File

@ -32,6 +32,7 @@
#include <base_struct.h> #include <base_struct.h>
#include <convert_to_biu.h>
#include <gr_basic.h> #include <gr_basic.h>
#include <layers_id_colors_and_visibility.h> #include <layers_id_colors_and_visibility.h>
@ -295,18 +296,12 @@ public:
* Circles and arcs are approximated by segments * Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon * @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad * @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aError = the maximum deviation from true circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
virtual void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, virtual void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue, int aClearanceValue, int aError = ARC_LOW_DEF, bool ignoreLineWidth = false ) const;
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth = false ) const;
}; };
#endif /* BOARD_ITEM_STRUCT_H */ #endif /* BOARD_ITEM_STRUCT_H */

View File

@ -181,13 +181,6 @@ protected:
*/ */
virtual bool doAutoSave(); virtual bool doAutoSave();
/**
* Return the wxConfigBase used in SaveSettings().
*
* This is overloaded in #KICAD_MANAGER_FRAME
*/
virtual wxConfigBase* config();
/** /**
* Return a SEARCH_STACK pertaining to entire program. * Return a SEARCH_STACK pertaining to entire program.
* *
@ -230,8 +223,14 @@ public:
void PrintMsg( const wxString& text ); void PrintMsg( const wxString& text );
/** /**
* Returns the wxConfigBase used in SaveSettings(), and is overloaded in
* KICAD_MANAGER_FRAME
*/
virtual wxConfigBase* config();
/**
* Function InstallPreferences
* Allow a frame to load its preference panels (if any) into the preferences dialog. * Allow a frame to load its preference panels (if any) into the preferences dialog.
*
* @param aParent a paged dialog into which the preference panels should be installed * @param aParent a paged dialog into which the preference panels should be installed
*/ */
virtual void InstallPreferences( PAGED_DIALOG* aParent ) { } virtual void InstallPreferences( PAGED_DIALOG* aParent ) { }

View File

@ -31,6 +31,8 @@
#ifndef ID_H_ #ifndef ID_H_
#define ID_H_ #define ID_H_
#include <wx/defs.h>
/** /**
* Common command IDs shared by more than one of the KiCad applications. * Common command IDs shared by more than one of the KiCad applications.
* *

View File

@ -61,12 +61,6 @@ struct TSEGM_2_POLY_PRMS {
}; };
TSEGM_2_POLY_PRMS prms; TSEGM_2_POLY_PRMS prms;
// The max error is the distance between the middle of a segment, and the circle
// for circle/arc to segment approximation.
// Warning: too small values can create very long calculation time in zone filling
// 0.05 to 0.01 mm is a reasonable value
double s_error_max = Millimeter2iu( 0.02 );
// This is a call back function, used by DrawGraphicText to draw the 3D text shape: // This is a call back function, used by DrawGraphicText to draw the 3D text shape:
static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData ) static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData )
{ {
@ -79,29 +73,22 @@ static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData )
void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aOutlines ) void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aOutlines )
{ {
// Number of segments to convert a circle to a polygon
const int segcountforcircle = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
double correctionFactor = GetCircletoPolyCorrectionFactor( segcountforcircle );
// convert tracks and vias: // convert tracks and vias:
for( TRACK* track = m_Track; track != NULL; track = track->Next() ) for( TRACK* track = m_Track; track != NULL; track = track->Next() )
{ {
if( !track->IsOnLayer( aLayer ) ) if( !track->IsOnLayer( aLayer ) )
continue; continue;
track->TransformShapeWithClearanceToPolygon( aOutlines, track->TransformShapeWithClearanceToPolygon( aOutlines, 0 );
0, segcountforcircle, correctionFactor );
} }
// convert pads // convert pads
for( MODULE* module = m_Modules; module != NULL; module = module->Next() ) for( MODULE* module = m_Modules; module != NULL; module = module->Next() )
{ {
module->TransformPadsShapesWithClearanceToPolygon( aLayer, module->TransformPadsShapesWithClearanceToPolygon( aLayer, aOutlines, 0 );
aOutlines, 0, segcountforcircle, correctionFactor );
// Micro-wave modules may have items on copper layers // Micro-wave modules may have items on copper layers
module->TransformGraphicShapesWithClearanceToPolygonSet( aLayer, module->TransformGraphicShapesWithClearanceToPolygonSet( aLayer, aOutlines, 0 );
aOutlines, 0, segcountforcircle, correctionFactor );
} }
// convert copper zones // convert copper zones
@ -111,8 +98,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_
PCB_LAYER_ID zonelayer = zone->GetLayer(); PCB_LAYER_ID zonelayer = zone->GetLayer();
if( zonelayer == aLayer ) if( zonelayer == aLayer )
zone->TransformSolidAreasShapesToPolygonSet( zone->TransformSolidAreasShapesToPolygonSet( aOutlines );
aOutlines, segcountforcircle, correctionFactor );
} }
// convert graphic items on copper layers (texts) // convert graphic items on copper layers (texts)
@ -124,13 +110,11 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_
switch( item->Type() ) switch( item->Type() )
{ {
case PCB_LINE_T: case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( aOutlines, 0 );
aOutlines, 0, segcountforcircle, correctionFactor );
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( aOutlines, 0 );
aOutlines, 0, segcountforcircle, correctionFactor );
break; break;
default: default:
@ -141,10 +125,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_
void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer, void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aMaxError,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool aSkipNPTHPadsWihNoCopper ) const bool aSkipNPTHPadsWihNoCopper ) const
{ {
D_PAD* pad = PadsList(); D_PAD* pad = PadsList();
@ -198,8 +179,7 @@ void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
break; break;
} }
pad->BuildPadShapePolygon( aCornerBuffer, margin, pad->BuildPadShapePolygon( aCornerBuffer, margin );
aCircleToSegmentsCount, aCorrectionFactor );
} }
} }
@ -214,14 +194,8 @@ void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
* the radius of circle approximated by segments is * the radius of circle approximated by segments is
* initial radius * aCorrectionFactor * initial radius * aCorrectionFactor
*/ */
void MODULE::TransformGraphicShapesWithClearanceToPolygonSet( void MODULE::TransformGraphicShapesWithClearanceToPolygonSet( PCB_LAYER_ID aLayer,
PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError, bool aIncludeText ) const
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
int aCircleToSegmentsCountForTexts,
bool aIncludeText ) const
{ {
std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
EDGE_MODULE* outline; EDGE_MODULE* outline;
@ -234,8 +208,7 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
{ {
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item ); TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
if( ( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer ) if( ( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer ) && text->IsVisible() )
&& text->IsVisible() )
texts.push_back( text ); texts.push_back( text );
break; break;
@ -247,8 +220,7 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
if( aLayer != UNDEFINED_LAYER && outline->GetLayer() != aLayer ) if( aLayer != UNDEFINED_LAYER && outline->GetLayer() != aLayer )
break; break;
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0, outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0, aError );
aCircleToSegmentsCount, aCorrectionFactor );
break; break;
default: default:
@ -268,16 +240,12 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
prms.m_cornerBuffer = &aCornerBuffer; prms.m_cornerBuffer = &aCornerBuffer;
// To allow optimization of circles approximated by segments,
// aCircleToSegmentsCountForTexts, when not 0, is used.
// if 0 (default value) the aCircleToSegmentsCount is used
prms.m_textCircle2SegmentCount = aCircleToSegmentsCountForTexts ?
aCircleToSegmentsCountForTexts : aCircleToSegmentsCount;
for( unsigned ii = 0; ii < texts.size(); ii++ ) for( unsigned ii = 0; ii < texts.size(); ii++ )
{ {
TEXTE_MODULE *textmod = texts[ii]; TEXTE_MODULE *textmod = texts[ii];
prms.m_textWidth = textmod->GetThickness() + ( 2 * aInflateValue ); prms.m_textWidth = textmod->GetThickness() + ( 2 * aInflateValue );
prms.m_textCircle2SegmentCount =
std::max( GetArcToSegmentCount( prms.m_textWidth / 2, aError, 360.0 ), 6 );
wxSize size = textmod->GetTextSize(); wxSize size = textmod->GetTextSize();
if( textmod->IsMirrored() ) if( textmod->IsMirrored() )
@ -296,12 +264,7 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
// Same as function TransformGraphicShapesWithClearanceToPolygonSet but // Same as function TransformGraphicShapesWithClearanceToPolygonSet but
// this only render text // this only render text
void MODULE::TransformGraphicTextWithClearanceToPolygonSet( void MODULE::TransformGraphicTextWithClearanceToPolygonSet(
PCB_LAYER_ID aLayer, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError ) const
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
int aCircleToSegmentsCountForTexts ) const
{ {
std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
@ -337,16 +300,12 @@ void MODULE::TransformGraphicTextWithClearanceToPolygonSet(
prms.m_cornerBuffer = &aCornerBuffer; prms.m_cornerBuffer = &aCornerBuffer;
// To allow optimization of circles approximated by segments,
// aCircleToSegmentsCountForTexts, when not 0, is used.
// if 0 (default value) the aCircleToSegmentsCount is used
prms.m_textCircle2SegmentCount = aCircleToSegmentsCountForTexts ?
aCircleToSegmentsCountForTexts : aCircleToSegmentsCount;
for( unsigned ii = 0; ii < texts.size(); ii++ ) for( unsigned ii = 0; ii < texts.size(); ii++ )
{ {
TEXTE_MODULE *textmod = texts[ii]; TEXTE_MODULE *textmod = texts[ii];
prms.m_textWidth = textmod->GetThickness() + ( 2 * aInflateValue ); prms.m_textWidth = textmod->GetThickness() + ( 2 * aInflateValue );
prms.m_textCircle2SegmentCount =
std::max( GetArcToSegmentCount( prms.m_textWidth / 2, aError, 360.0 ), 6 );
wxSize size = textmod->GetTextSize(); wxSize size = textmod->GetTextSize();
if( textmod->IsMirrored() ) if( textmod->IsMirrored() )
@ -361,24 +320,15 @@ void MODULE::TransformGraphicTextWithClearanceToPolygonSet(
} }
/* Function TransformSolidAreasShapesToPolygonSet
* Convert solid areas full shapes to polygon set
* (the full shape is the polygon area with a thick outline)
* Used in 3D view
* Arcs (ends of segments) are approximated by segments
* aCornerBuffer = a buffer to store the polygons
* aCircleToSegmentsCount = the number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to arcs radius to roughly
* keep arc radius when approximated by segments
*/
void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet( void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
SHAPE_POLY_SET& aCornerBuffer, SHAPE_POLY_SET& aCornerBuffer, int aError ) const
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
{ {
if( GetFilledPolysList().IsEmpty() ) if( GetFilledPolysList().IsEmpty() )
return; return;
int numSegs = std::max( GetArcToSegmentCount( GetMinThickness() / 2, aError, 360.0 ), 6 );
// add filled areas polygons // add filled areas polygons
aCornerBuffer.Append( m_FilledPolysList ); aCornerBuffer.Append( m_FilledPolysList );
@ -392,24 +342,15 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
const VECTOR2I& a = path.CPoint( j ); const VECTOR2I& a = path.CPoint( j );
const VECTOR2I& b = path.CPoint( j + 1 ); const VECTOR2I& b = path.CPoint( j + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ), TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ),
aCircleToSegmentsCount, wxPoint( b.x, b.y ), numSegs, GetMinThickness() );
GetMinThickness() );
} }
} }
} }
/**
* Function TransformBoundingBoxWithClearanceToPolygon
* Convert the text bounding box to a rectangular polygon
* Used in filling zones calculations
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the text bounding box
*/
void EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon( void EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon(
SHAPE_POLY_SET* aCornerBuffer, SHAPE_POLY_SET* aCornerBuffer, int aClearanceValue ) const
int aClearanceValue ) const
{ {
// Oh dear. When in UTF-8 mode, wxString puts string iterators in a linked list, and // Oh dear. When in UTF-8 mode, wxString puts string iterators in a linked list, and
// that linked list is not thread-safe. // that linked list is not thread-safe.
@ -455,10 +396,7 @@ void EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon(
*/ */
void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet( void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet(
SHAPE_POLY_SET& aCornerBuffer, SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError ) const
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
{ {
wxSize size = GetTextSize(); wxSize size = GetTextSize();
@ -467,7 +405,8 @@ void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet(
prms.m_cornerBuffer = &aCornerBuffer; prms.m_cornerBuffer = &aCornerBuffer;
prms.m_textWidth = GetThickness() + ( 2 * aClearanceValue ); prms.m_textWidth = GetThickness() + ( 2 * aClearanceValue );
prms.m_textCircle2SegmentCount = aCircleToSegmentsCount; prms.m_textCircle2SegmentCount =
std::max( GetArcToSegmentCount( prms.m_textWidth / 2, aError, 360.0 ), 6 );
COLOR4D color = COLOR4D::BLACK; // not actually used, but needed by DrawGraphicText COLOR4D color = COLOR4D::BLACK; // not actually used, but needed by DrawGraphicText
if( IsMultilineAllowed() ) if( IsMultilineAllowed() )
@ -499,61 +438,39 @@ void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet(
} }
/** void DRAWSEGMENT::TransformShapeWithClearanceToPolygon(
* Function TransformShapeWithClearanceToPolygon SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approxiamted by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization
*/
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth ) const
{ {
// The full width of the lines to create: // The full width of the lines to create:
int linewidth = ignoreLineWidth ? 0 : m_Width; int linewidth = ignoreLineWidth ? 0 : m_Width;
linewidth += 2 * aClearanceValue; linewidth += 2 * aClearanceValue;
int numSegs = std::max( GetArcToSegmentCount( linewidth / 2, aError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
// Creating a reliable clearance shape for circles and arcs is not so easy, due to // Creating a reliable clearance shape for circles and arcs is not so easy, due to
// the error created by segment approximation. // the error created by segment approximation.
// for a cicle this is not so hard: create a polygon from a circle slightly bigger: // for a circle this is not so hard: create a polygon from a circle slightly bigger:
// thickness = linewidth + s_error_max, and radius = initial radius + s_error_max/2 // thickness = linewidth + s_error_max, and radius = initial radius + s_error_max/2
// giving a shape with a suitable internal radius and external radius // giving a shape with a suitable internal radius and external radius
// For an arc this is more tricky: TODO // For an arc this is more tricky: TODO
if( m_Shape == S_CIRCLE || m_Shape == S_ARC )
{
int segCount = GetArcToSegmentCount( GetRadius(), s_error_max, 360.0 );
if( segCount > aCircleToSegmentsCount )
aCircleToSegmentsCount = segCount;
}
switch( m_Shape ) switch( m_Shape )
{ {
case S_CIRCLE: case S_CIRCLE:
TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius() + (s_error_max/2), TransformRingToPolygon(
aCircleToSegmentsCount, linewidth + s_error_max ) ; aCornerBuffer, GetCenter(), GetRadius(), numSegs, correction * linewidth );
break; break;
case S_ARC: case S_ARC:
TransformArcToPolygon( aCornerBuffer, GetCenter(), TransformArcToPolygon(
GetArcStart(), m_Angle, aCornerBuffer, GetCenter(), GetArcStart(), m_Angle, numSegs, linewidth );
aCircleToSegmentsCount, linewidth );
break; break;
case S_SEGMENT: case S_SEGMENT:
TransformOvalClearanceToPolygon( aCornerBuffer, m_Start, m_End, linewidth, TransformOvalClearanceToPolygon(
aCircleToSegmentsCount, aCorrectionFactor ); aCornerBuffer, m_Start, m_End, linewidth, numSegs, correction );
break; break;
case S_POLYGON: case S_POLYGON:
@ -583,12 +500,12 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
{ {
for( size_t ii = 1; ii < poly.size(); ii++ ) for( size_t ii = 1; ii < poly.size(); ii++ )
{ {
TransformOvalClearanceToPolygon( aCornerBuffer, poly[ii - 1], poly[ii], TransformOvalClearanceToPolygon(
linewidth, aCircleToSegmentsCount, aCorrectionFactor ); aCornerBuffer, poly[ii - 1], poly[ii], linewidth, numSegs, correction );
} }
TransformOvalClearanceToPolygon( aCornerBuffer, poly.back(), poly.front(), TransformOvalClearanceToPolygon(
linewidth, aCircleToSegmentsCount, aCorrectionFactor ); aCornerBuffer, poly.back(), poly.front(), linewidth, numSegs, correction );
break; break;
} }
@ -612,8 +529,8 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
if( corner2 != corner1 ) if( corner2 != corner1 )
{ {
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, TransformRoundedEndsSegmentToPolygon(
corner1, corner2, aCircleToSegmentsCount, linewidth ); aCornerBuffer, corner1, corner2, numSegs, linewidth );
} }
corner1 = corner2; corner1 = corner2;
@ -631,8 +548,8 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
for( unsigned ii = 1; ii < poly.size(); ii++ ) for( unsigned ii = 1; ii < poly.size(); ii++ )
{ {
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, TransformRoundedEndsSegmentToPolygon(
poly[ii-1], poly[ii], aCircleToSegmentsCount, linewidth ); aCornerBuffer, poly[ii - 1], poly[ii], numSegs, linewidth );
} }
} }
break; break;
@ -643,66 +560,34 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
} }
/** void TRACK::TransformShapeWithClearanceToPolygon(
* Function TransformShapeWithClearanceToPolygon SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization
*/
void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth ) const
{ {
wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." ); wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." );
int radius = ( m_Width / 2 ) + aClearanceValue;
int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
switch( Type() ) switch( Type() )
{ {
case PCB_VIA_T: case PCB_VIA_T:
{ {
int radius = (m_Width / 2) + aClearanceValue; radius = KiROUND( radius * correction );
radius = KiROUND( radius * aCorrectionFactor ); TransformCircleToPolygon( aCornerBuffer, m_Start, radius, numSegs );
TransformCircleToPolygon( aCornerBuffer, m_Start, radius, aCircleToSegmentsCount );
} }
break; break;
default: default:
TransformOvalClearanceToPolygon( aCornerBuffer, m_Start, m_End, TransformOvalClearanceToPolygon( aCornerBuffer, m_Start, m_End,
m_Width + ( 2 * aClearanceValue), m_Width + ( 2 * aClearanceValue ), numSegs, correction );
aCircleToSegmentsCount,
aCorrectionFactor );
break; break;
} }
} }
/* Function TransformShapeWithClearanceToPolygon void D_PAD::TransformShapeWithClearanceToPolygon(
* Convert the pad shape to a closed polygon SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
* Used in filling zones calculations and 3D view generation
* Circles and arcs are approximated by segments
* aCornerBuffer = a SHAPE_POLY_SET to store the polygon corners
* aClearanceValue = the clearance around the pad
* aCircleToSegmentsCount = the number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization
*/
void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth ) const
{ {
wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for pads." ); wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for pads." );
@ -716,9 +601,12 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
switch( GetShape() ) switch( GetShape() )
{ {
case PAD_SHAPE_CIRCLE: case PAD_SHAPE_CIRCLE:
dx = KiROUND( dx * aCorrectionFactor ); {
TransformCircleToPolygon( aCornerBuffer, padShapePos, dx, int numSegs = std::max( GetArcToSegmentCount( dx, aError, 360.0 ), 6 );
aCircleToSegmentsCount ); double correction = GetCircletoPolyCorrectionFactor( numSegs );
dx = KiROUND( dx * correction );
TransformCircleToPolygon( aCornerBuffer, padShapePos, dx, numSegs );
}
break; break;
case PAD_SHAPE_OVAL: case PAD_SHAPE_OVAL:
@ -737,11 +625,13 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
width = dy * 2; width = dy * 2;
} }
int numSegs = std::max( GetArcToSegmentCount( width / 2, aError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
RotatePoint( &shape_offset, angle ); RotatePoint( &shape_offset, angle );
wxPoint start = padShapePos - shape_offset; wxPoint start = padShapePos - shape_offset;
wxPoint end = padShapePos + shape_offset; wxPoint end = padShapePos + shape_offset;
TransformOvalClearanceToPolygon( aCornerBuffer, start, end, width, TransformOvalClearanceToPolygon( aCornerBuffer, start, end, width, numSegs, correction );
aCircleToSegmentsCount, aCorrectionFactor );
} }
break; break;
@ -760,8 +650,11 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
outline.Append( corners[ii].x, corners[ii].y ); outline.Append( corners[ii].x, corners[ii].y );
} }
int rounding_radius = int( aClearanceValue * aCorrectionFactor ); int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ), 6 );
outline.Inflate( rounding_radius, aCircleToSegmentsCount ); double correction = GetCircletoPolyCorrectionFactor( numSegs );
int rounding_radius = KiROUND( aClearanceValue * correction );
outline.Inflate( rounding_radius, numSegs );
aCornerBuffer.Append( outline ); aCornerBuffer.Append( outline );
} }
@ -771,18 +664,20 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
case PAD_SHAPE_ROUNDRECT: case PAD_SHAPE_ROUNDRECT:
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
int clearance = int( aClearanceValue * aCorrectionFactor ); int radius = GetRoundRectCornerRadius() + aClearanceValue;
int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
int clearance = KiROUND( aClearanceValue * correction );
int rounding_radius = GetRoundRectCornerRadius() + clearance; int rounding_radius = GetRoundRectCornerRadius() + clearance;
wxSize shapesize( m_Size ); wxSize shapesize( m_Size );
shapesize.x += clearance*2; shapesize.x += clearance*2;
shapesize.y += clearance*2; shapesize.y += clearance*2;
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT; bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
TransformRoundChamferedRectToPolygon( outline, padShapePos, shapesize, angle, TransformRoundChamferedRectToPolygon( outline, padShapePos, shapesize, angle,
rounding_radius, rounding_radius, doChamfer ? GetChamferRectRatio() : 0.0,
doChamfer ? GetChamferRectRatio() : 0.0, doChamfer ? GetChamferPositions() : 0, numSegs );
doChamfer ? GetChamferPositions() : 0,
aCircleToSegmentsCount );
aCornerBuffer.Append( outline ); aCornerBuffer.Append( outline );
} }
@ -790,12 +685,14 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
case PAD_SHAPE_CUSTOM: case PAD_SHAPE_CUSTOM:
{ {
int clearance = KiROUND( aClearanceValue * aCorrectionFactor ); int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
int clearance = KiROUND( aClearanceValue * correction );
SHAPE_POLY_SET outline; // Will contain the corners in board coordinates SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
outline.Append( m_customShapeAsPolygon ); outline.Append( m_customShapeAsPolygon );
CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() ); CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
outline.Simplify( SHAPE_POLY_SET::PM_FAST ); outline.Simplify( SHAPE_POLY_SET::PM_FAST );
outline.Inflate( clearance, aCircleToSegmentsCount ); outline.Inflate( clearance, numSegs );
outline.Fracture( SHAPE_POLY_SET::PM_FAST ); outline.Fracture( SHAPE_POLY_SET::PM_FAST );
aCornerBuffer.Append( outline ); aCornerBuffer.Append( outline );
} }
@ -812,9 +709,8 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
* Note: for Round and oval pads this function is equivalent to * Note: for Round and oval pads this function is equivalent to
* TransformShapeWithClearanceToPolygon, but not for other shapes * TransformShapeWithClearanceToPolygon, but not for other shapes
*/ */
void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer, void D_PAD::BuildPadShapePolygon(
wxSize aInflateValue, int aSegmentsPerCircle, SHAPE_POLY_SET& aCornerBuffer, wxSize aInflateValue, int aError ) const
double aCorrectionFactor ) const
{ {
wxPoint corners[4]; wxPoint corners[4];
wxPoint padShapePos = ShapePos(); /* Note: for pad having a shape offset, wxPoint padShapePos = ShapePos(); /* Note: for pad having a shape offset,
@ -834,8 +730,7 @@ void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
// a wxSize to inflate the pad size // a wxSize to inflate the pad size
D_PAD dummy( *this ); D_PAD dummy( *this );
dummy.SetSize( GetSize() + aInflateValue + aInflateValue ); dummy.SetSize( GetSize() + aInflateValue + aInflateValue );
dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, 0, dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, 0 );
aSegmentsPerCircle, aCorrectionFactor );
} }
break; break;
@ -856,21 +751,15 @@ void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
// for a custom shape, that is in fact a polygon (with holes), we can use only a inflate value. // for a custom shape, that is in fact a polygon (with holes), we can use only a inflate value.
// so use ( aInflateValue.x + aInflateValue.y ) / 2 as polygon inflate value. // so use ( aInflateValue.x + aInflateValue.y ) / 2 as polygon inflate value.
// (different values for aInflateValue.x and aInflateValue.y has no sense for a custom pad) // (different values for aInflateValue.x and aInflateValue.y has no sense for a custom pad)
TransformShapeWithClearanceToPolygon( aCornerBuffer, TransformShapeWithClearanceToPolygon(
( aInflateValue.x + aInflateValue.y ) / 2, aCornerBuffer, ( aInflateValue.x + aInflateValue.y ) / 2 );
aSegmentsPerCircle, aCorrectionFactor );
break; break;
} }
} }
/*
* Function BuildPadDrillShapePolygon bool D_PAD::BuildPadDrillShapePolygon(
* Build the Corner list of the polygonal drill shape, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError ) const
* depending on shape pad hole and orientation
* return false if the pad has no hole, true otherwise
*/
bool D_PAD::BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue, int aSegmentsPerCircle ) const
{ {
wxSize drillsize = GetDrillSize(); wxSize drillsize = GetDrillSize();
@ -879,8 +768,9 @@ bool D_PAD::BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
if( drillsize.x == drillsize.y ) // usual round hole if( drillsize.x == drillsize.y ) // usual round hole
{ {
TransformCircleToPolygon( aCornerBuffer, GetPosition(), int radius = ( drillsize.x / 2 ) + aInflateValue;
(drillsize.x / 2) + aInflateValue, aSegmentsPerCircle ); int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 );
TransformCircleToPolygon( aCornerBuffer, GetPosition(), radius, numSegs );
} }
else // Oblong hole else // Oblong hole
{ {
@ -890,9 +780,10 @@ bool D_PAD::BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
GetOblongDrillGeometry( start, end, width ); GetOblongDrillGeometry( start, end, width );
width += aInflateValue * 2; width += aInflateValue * 2;
int numSegs = std::max( GetArcToSegmentCount( width / 2, aError, 360.0 ), 6 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, TransformRoundedEndsSegmentToPolygon(
GetPosition() + start, GetPosition() + end, aSegmentsPerCircle, width ); aCornerBuffer, GetPosition() + start, GetPosition() + end, numSegs, width );
} }
return true; return true;
@ -907,8 +798,7 @@ bool D_PAD::BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
* @param aThermalGap = gap in thermal shape * @param aThermalGap = gap in thermal shape
* @param aCopperThickness = stubs thickness in thermal shape * @param aCopperThickness = stubs thickness in thermal shape
* @param aMinThicknessValue = min copper thickness allowed * @param aMinThicknessValue = min copper thickness allowed
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aError = maximum error allowed when approximating arcs
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* @param aThermalRot = for rond pads the rotation of thermal stubs (450 usually for 45 deg.) * @param aThermalRot = for rond pads the rotation of thermal stubs (450 usually for 45 deg.)
*/ */
@ -931,16 +821,13 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aThermalGap, int aThermalGap,
int aCopperThickness, int aCopperThickness,
int aMinThicknessValue, int aMinThicknessValue,
int aCircleToSegmentsCount, int aError,
double aCorrectionFactor,
double aThermalRot ) double aThermalRot )
{ {
wxPoint corner, corner_end; wxPoint corner, corner_end;
wxSize copper_thickness;
wxPoint padShapePos = aPad.ShapePos(); // Note: for pad having a shape offset, wxPoint padShapePos = aPad.ShapePos(); // Note: for pad having a shape offset,
// the pad position is NOT the shape position // the pad position is NOT the shape position
wxSize copper_thickness;
double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree
/* Keep in account the polygon outline thickness /* Keep in account the polygon outline thickness
* aThermalGap must be increased by aMinThicknessValue/2 because drawing external outline * aThermalGap must be increased by aMinThicknessValue/2 because drawing external outline
@ -984,8 +871,12 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
// The pattern roughtly is a 90 deg arc pie // The pattern roughtly is a 90 deg arc pie
std::vector <wxPoint> corners_buffer; std::vector <wxPoint> corners_buffer;
int numSegs = std::max( GetArcToSegmentCount( dx + aThermalGap, aError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
double delta = 3600.0 / numSegs;
// Radius of outer arcs of the shape corrected for arc approximation by lines // Radius of outer arcs of the shape corrected for arc approximation by lines
int outer_radius = KiROUND( (dx + aThermalGap) * aCorrectionFactor ); int outer_radius = KiROUND( ( dx + aThermalGap ) * correction );
// Crosspoint of thermal spoke sides, the first point of polygon buffer // Crosspoint of thermal spoke sides, the first point of polygon buffer
corners_buffer.push_back( wxPoint( copper_thickness.x / 2, copper_thickness.y / 2 ) ); corners_buffer.push_back( wxPoint( copper_thickness.x / 2, copper_thickness.y / 2 ) );
@ -1006,7 +897,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
( (double) corner.x * corner.x ) ) ); ( (double) corner.x * corner.x ) ) );
RotatePoint( &corner, 90 ); // 9 degrees is the spoke fillet size RotatePoint( &corner, 90 ); // 9 degrees is the spoke fillet size
// calculate the ending point of the outter arc // calculate the ending point of the outer arc
corner_end.x = corner.y; corner_end.x = corner.y;
corner_end.y = corner.x; corner_end.y = corner.x;
@ -1074,6 +965,10 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
// Radius of outer arcs of the shape: // Radius of outer arcs of the shape:
int outer_radius = dy; // The radius of the outer arc is radius end + aThermalGap int outer_radius = dy; // The radius of the outer arc is radius end + aThermalGap
int numSegs = std::max( GetArcToSegmentCount( outer_radius, aError, 360.0 ), 6 );
double delta = 3600.0 / numSegs;
// Some coordinate fiddling, depending on the shape offset direction // Some coordinate fiddling, depending on the shape offset direction
shape_offset = wxPoint( deltasize, 0 ); shape_offset = wxPoint( deltasize, 0 );
@ -1236,11 +1131,13 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint arc_start_point( -(aThermalGap / 4 + copper_thickness.x / 2) , -dy ); wxPoint arc_start_point( -(aThermalGap / 4 + copper_thickness.x / 2) , -dy );
corners_buffer.push_back( arc_start_point ); corners_buffer.push_back( arc_start_point );
int rounding_radius = KiROUND( aThermalGap * aCorrectionFactor ); // Corner rounding radius int numSegs = std::max( GetArcToSegmentCount( aThermalGap, aError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
int rounding_radius = KiROUND( aThermalGap * correction ); // Corner rounding radius
// Calculate arc angle parameters. // Calculate arc angle parameters.
// the start angle id near 900 decidegrees, the final angle is near 1800.0 decidegrees. // the start angle id near 900 decidegrees, the final angle is near 1800.0 decidegrees.
double arc_increment = 3600.0 / aCircleToSegmentsCount; double arc_increment = 3600.0 / numSegs;
// the arc_angle_start is 900.0 or slighly more, depending on the actual arc starting point // the arc_angle_start is 900.0 or slighly more, depending on the actual arc starting point
double arc_angle_start = atan2( -arc_start_point.y -corner_origin_pos.y, arc_start_point.x - corner_origin_pos.x ) * 1800/M_PI; double arc_angle_start = atan2( -arc_start_point.y -corner_origin_pos.y, arc_start_point.x - corner_origin_pos.x ) * 1800/M_PI;
@ -1319,8 +1216,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
EDA_RECT bbox = aPad.GetBoundingBox(); EDA_RECT bbox = aPad.GetBoundingBox();
int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() ); int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() );
aPad.TransformShapeWithClearanceToPolygon( antipad, aThermalGap, aPad.TransformShapeWithClearanceToPolygon( antipad, aThermalGap );
aCircleToSegmentsCount, aCorrectionFactor );
SHAPE_POLY_SET stub; // A basic stub ( a rectangle) SHAPE_POLY_SET stub; // A basic stub ( a rectangle)
SHAPE_POLY_SET stubs; // the full stubs shape SHAPE_POLY_SET stubs; // the full stubs shape
@ -1388,11 +1284,8 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
} }
} }
void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon(
int aClearanceValue, SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth ) const
{ {
wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for zones." ); wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for zones." );

View File

@ -140,11 +140,8 @@ void BOARD_ITEM::SwapData( BOARD_ITEM* aImage )
} }
void BOARD_ITEM::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void BOARD_ITEM::TransformShapeWithClearanceToPolygon(
int aClearanceValue, SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth ) const
{ {
wxASSERT_MSG( false, "Called TransformShapeWithClearanceToPolygon() on unsupported BOARD_ITEM." ); wxASSERT_MSG( false, "Called TransformShapeWithClearanceToPolygon() on unsupported BOARD_ITEM." );
}; };

View File

@ -31,9 +31,10 @@
#define CLASS_DRAWSEGMENT_H_ #define CLASS_DRAWSEGMENT_H_
#include <class_board_item.h> #include <class_board_item.h>
#include <common.h>
#include <convert_to_biu.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
#include <trigo.h> #include <trigo.h>
#include <common.h>
#include <geometry/shape_poly_set.h> #include <geometry/shape_poly_set.h>
@ -246,18 +247,12 @@ public:
* Circles and arcs are approximated by segments * Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon * @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad * @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aError = the maximum deviation from a true arc
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue,
int aClearanceValue, int aError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override;
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth = false ) const override;
virtual wxString GetSelectMenuText( EDA_UNITS_T aUnits ) const override; virtual wxString GetSelectMenuText( EDA_UNITS_T aUnits ) const override;

View File

@ -32,13 +32,14 @@
#define MODULE_H_ #define MODULE_H_
#include <list> #include <board_item_container.h>
#include <class_board_item.h>
#include <collectors.h>
#include <convert_to_biu.h>
#include <dlist.h> #include <dlist.h>
#include <layers_id_colors_and_visibility.h> // ALL_LAYERS definition. #include <layers_id_colors_and_visibility.h> // ALL_LAYERS definition.
#include <class_board_item.h>
#include <board_item_container.h>
#include <collectors.h>
#include <lib_id.h> #include <lib_id.h>
#include <list>
#include <class_text_mod.h> #include <class_text_mod.h>
#include "zones.h" #include "zones.h"
@ -351,12 +352,7 @@ public:
* @param aCornerBuffer = the buffer to store polygons * @param aCornerBuffer = the buffer to store polygons
* @param aInflateValue = an additionnal size to add to pad shapes * @param aInflateValue = an additionnal size to add to pad shapes
* aInflateValue = 0 to have the exact pad size * aInflateValue = 0 to have the exact pad size
* @param aCircleToSegmentsCount = number of segments to generate a circle * @param aMaxError = Maximum deviation from true for arcs
* @param aCorrectionFactor = the correction to apply to a circle radius
* to approximate a circle by the polygon.
* if aCorrectionFactor = 1.0, the polygon is inside the circle
* the radius of circle approximated by segments is
* initial radius * aCorrectionFactor
* @param aSkipNPTHPadsWihNoCopper = if true, do not add a NPTH pad shape, * @param aSkipNPTHPadsWihNoCopper = if true, do not add a NPTH pad shape,
* if the shape has same size and position as the hole. Usually, these * if the shape has same size and position as the hole. Usually, these
* pads are not drawn on copper layers, because there is actually no copper * pads are not drawn on copper layers, because there is actually no copper
@ -365,10 +361,7 @@ public:
* default = false * default = false
*/ */
void TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer, void TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aMaxError = ARC_HIGH_DEF,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool aSkipNPTHPadsWihNoCopper = false ) const; bool aSkipNPTHPadsWihNoCopper = false ) const;
/** /**
@ -381,41 +374,25 @@ public:
* @param aCornerBuffer = the buffer to store polygons * @param aCornerBuffer = the buffer to store polygons
* @param aInflateValue = a value to inflate shapes * @param aInflateValue = a value to inflate shapes
* aInflateValue = 0 to have the exact shape size * aInflateValue = 0 to have the exact shape size
* @param aCircleToSegmentsCount = number of segments to generate a circle * @param aError = Maximum error between true arc and polygon approx
* @param aCorrectionFactor = the correction to apply to a circle radius * @param aIncludeText = True to transform text shapes
* to approximate a circle by the polygon.
* if aCorrectionFactor = 1.0, the polygon is inside the circle
* the radius of circle approximated by segments is
* initial radius * aCorrectionFactor
* @param aCircleToSegmentsCountForTexts = number of segments to generate
* a circle when building the texts polygonal shapes of the stroke font
* if 0, use the aCircleToSegmentsCount value
*/ */
void TransformGraphicShapesWithClearanceToPolygonSet( PCB_LAYER_ID aLayer, void TransformGraphicShapesWithClearanceToPolygonSet( PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError = ARC_HIGH_DEF,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
int aCircleToSegmentsCountForTexts = 0,
bool aIncludeText = true ) const; bool aIncludeText = true ) const;
/** /**
* @brief TransformGraphicTextWithClearanceToPolygonSet * @brief TransformGraphicTextWithClearanceToPolygonSet
* This function is the same as TransformGraphicShapesWithClearanceToPolygonSet * This function is the same as TransformGraphicShapesWithClearanceToPolygonSet
* but only generate text * but only generate text
* @param aLayer * @param aLayer = the layer to consider, or UNDEFINED_LAYER to consider all
* @param aCornerBuffer * @param aCornerBuffer = the buffer to store polygons
* @param aInflateValue * @param aInflateValue = a value to inflate shapes
* @param aCircleToSegmentsCount * aInflateValue = 0 to have the exact shape size
* @param aCorrectionFactor * @param aError = Maximum error between true arc and polygon approx
* @param aCircleToSegmentsCountForTexts
*/ */
void TransformGraphicTextWithClearanceToPolygonSet( PCB_LAYER_ID aLayer, void TransformGraphicTextWithClearanceToPolygonSet( PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError = ARC_HIGH_DEF ) const;
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
int aCircleToSegmentsCountForTexts = 0 ) const;
/** /**
* Function DrawEdgesOnly * Function DrawEdgesOnly

View File

@ -35,8 +35,9 @@
#include <base_units.h> #include <base_units.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <view/view.h> #include <geometry/geometry_utils.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <view/view.h>
#include <class_board.h> #include <class_board.h>
#include <class_module.h> #include <class_module.h>
@ -936,7 +937,8 @@ bool D_PAD::HitTest( const wxPoint& aPosition, int aAccuracy ) const
{ {
// Check for hit in polygon // Check for hit in polygon
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF; int segmentToCircleCount = std::max<int>(
GetArcToSegmentCount( GetRoundRectCornerRadius(), ARC_HIGH_DEF, 360.0 ), 3 );
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT; bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
TransformRoundChamferedRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient, TransformRoundChamferedRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient,

View File

@ -30,13 +30,14 @@
#ifndef PAD_H_ #ifndef PAD_H_
#define PAD_H_ #define PAD_H_
#include <pcbnew.h>
#include <class_board_item.h>
#include <board_connected_item.h>
#include <pad_shapes.h>
#include <geometry/shape_poly_set.h>
#include <config_params.h> // PARAM_CFG_ARRAY
#include "zones.h" #include "zones.h"
#include <board_connected_item.h>
#include <class_board_item.h>
#include <config_params.h> // PARAM_CFG_ARRAY
#include <convert_to_biu.h>
#include <geometry/shape_poly_set.h>
#include <pad_shapes.h>
#include <pcbnew.h>
class DRAWSEGMENT; class DRAWSEGMENT;
@ -312,8 +313,7 @@ public:
* (default = 32) * (default = 32)
* Note: The corners coordinates are relative to the pad position, orientation 0, * Note: The corners coordinates are relative to the pad position, orientation 0,
*/ */
bool MergePrimitivesAsPolygon( SHAPE_POLY_SET * aMergedPolygon = NULL, bool MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon = NULL );
int aCircleToSegmentsCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
/** /**
* clear the basic shapes list * clear the basic shapes list
@ -443,18 +443,12 @@ public:
* Circles and arcs are approximated by segments * Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon * @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad * @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aMaxError = Maximum error from true when converting arcs
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue,
int aClearanceValue, int aMaxError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override;
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth = false ) const override;
/** /**
* Function GetClearance * Function GetClearance
@ -576,14 +570,10 @@ public:
* value > 0: inflate, < 0 deflate, = 0 : no change * value > 0: inflate, < 0 deflate, = 0 : no change
* the clearance can have different values for x and y directions * the clearance can have different values for x and y directions
* (relative to the pad) * (relative to the pad)
* @param aSegmentsPerCircle = number of segments to approximate a circle * @param aError = Maximum deviation of an arc from the polygon segment
* (used for round and oblong shapes only (16 to 32 is a good value)
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* the pad size/clearance when the arcs are approximated by segments
*/ */
void BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer, void BuildPadShapePolygon(
wxSize aInflateValue, int aSegmentsPerCircle, SHAPE_POLY_SET& aCornerBuffer, wxSize aInflateValue, int aError = ARC_HIGH_DEF ) const;
double aCorrectionFactor ) const;
/** /**
* Function BuildPadDrillShapePolygon * Function BuildPadDrillShapePolygon
@ -592,12 +582,11 @@ public:
* @param aCornerBuffer = a buffer to fill. * @param aCornerBuffer = a buffer to fill.
* @param aInflateValue = the clearance or margin value. * @param aInflateValue = the clearance or margin value.
* value > 0: inflate, < 0 deflate, = 0 : no change * value > 0: inflate, < 0 deflate, = 0 : no change
* @param aSegmentsPerCircle = number of segments to approximate a circle * @param aError = Maximum deviation of an arc from the polygon approximation
* (used for round and oblong shapes only(16 to 32 is a good value)
* @return false if the pad has no hole, true otherwise * @return false if the pad has no hole, true otherwise
*/ */
bool BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer, bool BuildPadDrillShapePolygon(
int aInflateValue, int aSegmentsPerCircle ) const; SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError = ARC_HIGH_DEF ) const;
/** /**
* Function BuildSegmentFromOvalShape * Function BuildSegmentFromOvalShape
@ -832,8 +821,7 @@ private:
*/ */
int boundingRadius() const; int boundingRadius() const;
bool buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, bool buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError );
int aCircleToSegmentsCount );
private: // Private variable members: private: // Private variable members:

View File

@ -105,15 +105,10 @@ public:
* Circles and arcs are approximated by segments * Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon * @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the text * @param aClearanceValue = the clearance around the text
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aError = deviation from true arc position to segment approx
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/ */
void TransformShapeWithClearanceToPolygonSet( SHAPE_POLY_SET& aCornerBuffer, void TransformShapeWithClearanceToPolygonSet(
int aClearanceValue, SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError = ARC_HIGH_DEF ) const;
int aCircleToSegmentsCount,
double aCorrectionFactor ) const;
wxString GetSelectMenuText( EDA_UNITS_T aUnits ) const override; wxString GetSelectMenuText( EDA_UNITS_T aUnits ) const override;

View File

@ -31,10 +31,11 @@
#define CLASS_TRACK_H #define CLASS_TRACK_H
#include <pcbnew.h>
#include <class_board_item.h>
#include <board_connected_item.h> #include <board_connected_item.h>
#include <class_board_item.h>
#include <convert_to_biu.h>
#include <pcb_display_options.h> #include <pcb_display_options.h>
#include <pcbnew.h>
#include <trigo.h> #include <trigo.h>
@ -199,18 +200,12 @@ public:
* Circles (vias) and arcs (ends of tracks) are approximated by segments * Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon * @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad * @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aError = the maximum deviation from true circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue,
int aClearanceValue, int aError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override;
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth = false ) const override;
/** /**
* Function IsPointOnEnds * Function IsPointOnEnds
* returns STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if * returns STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if

View File

@ -28,16 +28,17 @@
* @brief Implementation of class to handle copper zones. * @brief Implementation of class to handle copper zones.
*/ */
#include <fctsys.h>
#include <trigo.h>
#include <pcb_screen.h>
#include <class_drawpanel.h>
#include <kicad_string.h>
#include <richio.h>
#include <macros.h>
#include <pcb_base_frame.h>
#include <msgpanel.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <class_drawpanel.h>
#include <fctsys.h>
#include <geometry/geometry_utils.h>
#include <kicad_string.h>
#include <macros.h>
#include <msgpanel.h>
#include <pcb_base_frame.h>
#include <pcb_screen.h>
#include <richio.h>
#include <trigo.h>
#include <convert_to_biu.h> #include <convert_to_biu.h>
#include <class_board.h> #include <class_board.h>
@ -1304,12 +1305,7 @@ bool ZONE_CONTAINER::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly ) const
break; break;
case ZONE_SETTINGS::SMOOTHING_FILLET: case ZONE_SETTINGS::SMOOTHING_FILLET:
// Note: we're now using m_ArcToSegmentsCount only as a hint to determine accuracy
// vs. speed.
if( m_ArcToSegmentsCount > SEGMENT_COUNT_CROSSOVER )
aSmoothedPoly = m_Poly->Fillet( m_cornerRadius, ARC_HIGH_DEF ); aSmoothedPoly = m_Poly->Fillet( m_cornerRadius, ARC_HIGH_DEF );
else
aSmoothedPoly = m_Poly->Fillet( m_cornerRadius, ARC_LOW_DEF );
break; break;
default: default:
@ -1353,8 +1349,10 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
// Calculate the polygon with clearance // Calculate the polygon with clearance
// holes are linked to the main outline, so only one polygon is created. // holes are linked to the main outline, so only one polygon is created.
if( clearance ) if( clearance )
polybuffer.Inflate( clearance, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF ); {
int segCount = std::max( GetArcToSegmentCount( clearance, ARC_HIGH_DEF, 360.0 ), 3 );
polybuffer.Inflate( clearance, segCount );
}
polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST ); polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );
aCornerBuffer.Append( polybuffer ); aCornerBuffer.Append( polybuffer );
} }

View File

@ -297,13 +297,10 @@ public:
* Used in 3D view * Used in 3D view
* Arcs (ends of segments) are approximated by segments * Arcs (ends of segments) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygons * @param aCornerBuffer = a buffer to store the polygons
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aError = Maximum error allowed between true arc and polygon approx
* @param aCorrectionFactor = the correction to apply to arcs radius to roughly
* keep arc radius when approximated by segments
*/ */
void TransformSolidAreasShapesToPolygonSet( SHAPE_POLY_SET& aCornerBuffer, void TransformSolidAreasShapesToPolygonSet(
int aCircleToSegmentsCount, SHAPE_POLY_SET& aCornerBuffer, int aError = ARC_HIGH_DEF ) const;
double aCorrectionFactor ) const;
/** /**
* Function TransformOutlinesShapeWithClearanceToPolygon * Function TransformOutlinesShapeWithClearanceToPolygon
@ -330,18 +327,12 @@ public:
* Circles and arcs are approximated by segments * Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon * @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad * @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aError = the maximum deviation from true circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue,
int aClearanceValue, int aError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override;
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool ignoreLineWidth = false ) const override;
/** /**
* Function HitTestForCorner * Function HitTestForCorner

View File

@ -1136,13 +1136,8 @@ void DRC::testCopperDrawItem( DRAWSEGMENT* aItem )
if( pad->GetParent() == aItem->GetParent() ) if( pad->GetParent() == aItem->GetParent() )
continue; continue;
const int segmentCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
double correctionFactor = GetCircletoPolyCorrectionFactor( segmentCount );
SHAPE_POLY_SET padOutline; SHAPE_POLY_SET padOutline;
pad->TransformShapeWithClearanceToPolygon( padOutline, pad->GetClearance( NULL ) );
// We incorporate "minDist" into the pad's outline
pad->TransformShapeWithClearanceToPolygon( padOutline, pad->GetClearance( NULL ),
segmentCount, correctionFactor );
for( const auto& itemSeg : itemShape ) for( const auto& itemSeg : itemShape )
{ {
@ -1219,13 +1214,10 @@ void DRC::testCopperTextItem( BOARD_ITEM* aTextItem )
if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) ) if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) )
continue; continue;
const int segmentCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
double correctionFactor = GetCircletoPolyCorrectionFactor( segmentCount );
SHAPE_POLY_SET padOutline; SHAPE_POLY_SET padOutline;
int minDist = textWidth/2 + pad->GetClearance( NULL ); int minDist = textWidth/2 + pad->GetClearance( NULL );
pad->TransformShapeWithClearanceToPolygon( padOutline, 0, pad->TransformShapeWithClearanceToPolygon( padOutline, 0 );
segmentCount, correctionFactor );
for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
{ {

View File

@ -1142,9 +1142,8 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P
case PAD_SHAPE_CUSTOM: case PAD_SHAPE_CUSTOM:
{ {
SHAPE_POLY_SET polySet; SHAPE_POLY_SET polySet;
int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
std::vector< wxRealPoint > cornerList; std::vector< wxRealPoint > cornerList;
aPad->MergePrimitivesAsPolygon( &polySet, segmentToCircleCount ); aPad->MergePrimitivesAsPolygon( &polySet );
for( int cnt = 0; cnt < polySet.OutlineCount(); ++cnt ) for( int cnt = 0; cnt < polySet.OutlineCount(); ++cnt )
{ {

View File

@ -200,8 +200,7 @@ void D_PAD::DeletePrimitivesList()
} }
bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError )
int aCircleToSegmentsCount )
{ {
SHAPE_POLY_SET aux_polyset; SHAPE_POLY_SET aux_polyset;
@ -221,33 +220,42 @@ bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon,
for( unsigned ii = 1; ii < poly.size(); ii++ ) for( unsigned ii = 1; ii < poly.size(); ii++ )
{ {
TransformRoundedEndsSegmentToPolygon( aux_polyset, int numSegs = std::max(
poly[ii-1], poly[ii], aCircleToSegmentsCount, bshape.m_Thickness ); GetArcToSegmentCount( bshape.m_Thickness / 2, aError, 360.0 ), 6 );
TransformRoundedEndsSegmentToPolygon(
aux_polyset, poly[ii - 1], poly[ii], numSegs, bshape.m_Thickness );
} }
break; break;
} }
case S_SEGMENT: // usual segment : line with rounded ends case S_SEGMENT: // usual segment : line with rounded ends
TransformRoundedEndsSegmentToPolygon( aux_polyset, {
bshape.m_Start, bshape.m_End, aCircleToSegmentsCount, bshape.m_Thickness ); int numSegs =
std::max( GetArcToSegmentCount( bshape.m_Thickness / 2, aError, 360.0 ), 6 );
TransformRoundedEndsSegmentToPolygon(
aux_polyset, bshape.m_Start, bshape.m_End, numSegs, bshape.m_Thickness );
break; break;
}
case S_ARC: // Arc with rounded ends case S_ARC: // Arc with rounded ends
TransformArcToPolygon( aux_polyset, {
bshape.m_Start, bshape.m_End, bshape.m_ArcAngle, int radius = KiROUND( EuclideanNorm( ( bshape.m_Start - bshape.m_End ) ) );
aCircleToSegmentsCount, bshape.m_Thickness ); int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 );
TransformArcToPolygon( aux_polyset, bshape.m_Start, bshape.m_End, bshape.m_ArcAngle,
numSegs, bshape.m_Thickness );
break; break;
}
case S_CIRCLE: // ring or circle case S_CIRCLE: // ring or circle
{
int numSegs = std::max( GetArcToSegmentCount( bshape.m_Radius, aError, 360.0 ), 6 );
if( bshape.m_Thickness ) // ring if( bshape.m_Thickness ) // ring
TransformRingToPolygon( aux_polyset, TransformRingToPolygon(
bshape.m_Start, bshape.m_Radius, aux_polyset, bshape.m_Start, bshape.m_Radius, numSegs, bshape.m_Thickness );
aCircleToSegmentsCount, bshape.m_Thickness ) ;
else // Filled circle else // Filled circle
TransformCircleToPolygon( aux_polyset, TransformCircleToPolygon( aux_polyset, bshape.m_Start, bshape.m_Radius, numSegs );
bshape.m_Start, bshape.m_Radius,
aCircleToSegmentsCount ) ;
break; break;
}
case S_POLYGON: // polygon case S_POLYGON: // polygon
if( bshape.m_Poly.size() < 2 ) if( bshape.m_Poly.size() < 2 )
@ -268,7 +276,9 @@ bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon,
polyset.Append( poly[ii].x, poly[ii].y ); polyset.Append( poly[ii].x, poly[ii].y );
} }
polyset.Inflate( bshape.m_Thickness/2, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF ); int numSegs = std::max(
GetArcToSegmentCount( bshape.m_Thickness / 2, aError, 360.0 ), 6 );
polyset.Inflate( bshape.m_Thickness / 2, numSegs );
aux_polyset.Append( polyset ); aux_polyset.Append( polyset );
} }
@ -300,8 +310,7 @@ bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon,
* return true if OK, false in there is more than one polygon * return true if OK, false in there is more than one polygon
* in aMergedPolygon * in aMergedPolygon
*/ */
bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon, bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon )
int aCircleToSegmentsCount )
{ {
// if aMergedPolygon == NULL, use m_customShapeAsPolygon as target // if aMergedPolygon == NULL, use m_customShapeAsPolygon as target
@ -316,19 +325,23 @@ bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon,
{ {
default: default:
case PAD_SHAPE_CIRCLE: case PAD_SHAPE_CIRCLE:
TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0,0 ), GetSize().x/2, {
aCircleToSegmentsCount ); int numSegs = std::max( GetArcToSegmentCount( GetSize().x / 2, ARC_HIGH_DEF, 360.0 ), 6 );
TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0, 0 ), GetSize().x / 2, numSegs );
break; break;
}
case PAD_SHAPE_RECT: case PAD_SHAPE_RECT:
{ {
SHAPE_RECT rect( -GetSize().x/2, -GetSize().y/2, GetSize().x, GetSize().y ); SHAPE_RECT rect( -GetSize().x / 2, -GetSize().y / 2, GetSize().x, GetSize().y );
aMergedPolygon->AddOutline( rect.Outline() ); aMergedPolygon->AddOutline( rect.Outline() );
}
break; break;
} }
}
if ( !buildCustomPadPolygon( aMergedPolygon, aCircleToSegmentsCount ) ) if( !buildCustomPadPolygon( aMergedPolygon, ARC_HIGH_DEF ) )
return false; return false;
m_boundingRadius = -1; // The current bouding radius is no more valid. m_boundingRadius = -1; // The current bouding radius is no more valid.
@ -364,7 +377,7 @@ bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos )
{ {
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
if ( !buildCustomPadPolygon( &poly, ARC_APPROX_SEGMENTS_COUNT_LOW_DEF ) ) if( !buildCustomPadPolygon( &poly, ARC_LOW_DEF ) )
return false; return false;
const int minSteps = 10; const int minSteps = 10;

View File

@ -28,20 +28,20 @@
* @file class_pad_draw_functions.cpp * @file class_pad_draw_functions.cpp
*/ */
#include <fctsys.h> #include <class_board.h>
#include <gr_basic.h>
#include <common.h>
#include <trigo.h>
#include <pcb_screen.h>
#include <class_drawpanel.h> #include <class_drawpanel.h>
#include <common.h>
#include <convert_basic_shapes_to_polygon.h>
#include <draw_graphic_text.h> #include <draw_graphic_text.h>
#include <fctsys.h>
#include <geometry/geometry_utils.h>
#include <gr_basic.h>
#include <layers_id_colors_and_visibility.h> #include <layers_id_colors_and_visibility.h>
#include <pcb_edit_frame.h> #include <pcb_edit_frame.h>
#include <pcbnew_id.h> // ID_TRACK_BUTT #include <pcb_screen.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <class_board.h> #include <pcbnew_id.h> // ID_TRACK_BUTT
#include <convert_basic_shapes_to_polygon.h> #include <trigo.h>
/* uncomment this line to show this pad with its specfic size and color /* uncomment this line to show this pad with its specfic size and color
@ -420,7 +420,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
if( aDrawInfo.m_PadClearance ) if( aDrawInfo.m_PadClearance )
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
TransformShapeWithClearanceToPolygon( outline, aDrawInfo.m_PadClearance, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF, 1.0 ); TransformShapeWithClearanceToPolygon( outline, aDrawInfo.m_PadClearance );
// Draw the polygon: Inflate creates only one convex polygon // Draw the polygon: Inflate creates only one convex polygon
if( outline.OutlineCount() > 0 ) if( outline.OutlineCount() > 0 )
@ -527,11 +527,12 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
CustomShapeAsPolygonToBoardPosition( &outline, pad_pos, GetOrientation() ); CustomShapeAsPolygonToBoardPosition( &outline, pad_pos, GetOrientation() );
SHAPE_LINE_CHAIN* poly; SHAPE_LINE_CHAIN* poly;
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
if( aDrawInfo.m_Mask_margin.x ) if( aDrawInfo.m_Mask_margin.x )
outline.InflateWithLinkedHoles( aDrawInfo.m_Mask_margin.x, {
segmentToCircleCount, SHAPE_POLY_SET::PM_FAST ); int numSegs = GetArcToSegmentCount( aDrawInfo.m_Mask_margin.x, ARC_HIGH_DEF, 360.0 );
outline.InflateWithLinkedHoles(
aDrawInfo.m_Mask_margin.x, numSegs, SHAPE_POLY_SET::PM_FAST );
}
// Draw the polygon: only one polygon is expected // Draw the polygon: only one polygon is expected
// However we provide a multi polygon shape drawing // However we provide a multi polygon shape drawing
@ -550,8 +551,9 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
SHAPE_POLY_SET clearance_outline; SHAPE_POLY_SET clearance_outline;
clearance_outline.Append( outline ); clearance_outline.Append( outline );
clearance_outline.InflateWithLinkedHoles( aDrawInfo.m_PadClearance, int numSegs = GetArcToSegmentCount( aDrawInfo.m_PadClearance, ARC_HIGH_DEF, 360.0 );
segmentToCircleCount, SHAPE_POLY_SET::PM_FAST ); clearance_outline.InflateWithLinkedHoles(
aDrawInfo.m_PadClearance, numSegs, SHAPE_POLY_SET::PM_FAST );
for( int jj = 0; jj < clearance_outline.OutlineCount(); ++jj ) for( int jj = 0; jj < clearance_outline.OutlineCount(); ++jj )
{ {
@ -565,6 +567,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
} }
} }
} }
break; break;
} }
} }

View File

@ -40,8 +40,9 @@
#include <pcb_painter.h> #include <pcb_painter.h>
#include <pcb_display_options.h> #include <pcb_display_options.h>
#include <gal/graphics_abstraction_layer.h>
#include <convert_basic_shapes_to_polygon.h> #include <convert_basic_shapes_to_polygon.h>
#include <gal/graphics_abstraction_layer.h>
#include <geometry/geometry_utils.h>
#include <geometry/shape_line_chain.h> #include <geometry/shape_line_chain.h>
using namespace KIGFX; using namespace KIGFX;
@ -845,11 +846,11 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
outline.Append( aPad->GetCustomShapeAsPolygon() ); outline.Append( aPad->GetCustomShapeAsPolygon() );
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
// outline polygon can have holes linked to the main outline. // outline polygon can have holes linked to the main outline.
// So use InflateWithLinkedHoles(), not Inflate() that can create // So use InflateWithLinkedHoles(), not Inflate() that can create
// bad shapes if custom_margin is < 0 // bad shapes if custom_margin is < 0
outline.InflateWithLinkedHoles( custom_margin, segmentToCircleCount, SHAPE_POLY_SET::PM_FAST ); int numSegs = std::max( GetArcToSegmentCount( custom_margin, ARC_HIGH_DEF, 360.0 ), 6 );
outline.InflateWithLinkedHoles( custom_margin, numSegs, SHAPE_POLY_SET::PM_FAST );
m_gal->DrawPolygon( outline ); m_gal->DrawPolygon( outline );
} }
else else
@ -900,8 +901,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|| aLayer == LAYER_PADS_TH ) ) || aLayer == LAYER_PADS_TH ) )
{ {
SHAPE_POLY_SET polySet; SHAPE_POLY_SET polySet;
constexpr int SEGCOUNT = 64; aPad->TransformShapeWithClearanceToPolygon( polySet, aPad->GetClearance() );
aPad->TransformShapeWithClearanceToPolygon( polySet, aPad->GetClearance(), SEGCOUNT, 1.0 );
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth ); m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
m_gal->SetIsStroke( true ); m_gal->SetIsStroke( true );
m_gal->SetIsFill( false ); m_gal->SetIsFill( false );

View File

@ -450,12 +450,12 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
D_PAD dummy( *pad ); D_PAD dummy( *pad );
SHAPE_POLY_SET shape; SHAPE_POLY_SET shape;
pad->MergePrimitivesAsPolygon( &shape, 64 ); pad->MergePrimitivesAsPolygon( &shape );
// shape polygon can have holes linked to the main outline. // shape polygon can have holes linked to the main outline.
// So use InflateWithLinkedHoles(), not Inflate() that can create // So use InflateWithLinkedHoles(), not Inflate() that can create
// bad shapes if margin.x is < 0 // bad shapes if margin.x is < 0
shape.InflateWithLinkedHoles( margin.x, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF, int numSegs = std::max( GetArcToSegmentCount( margin.x, ARC_HIGH_DEF, 360.0 ), 6 );
SHAPE_POLY_SET::PM_FAST ); shape.InflateWithLinkedHoles( margin.x, numSegs, SHAPE_POLY_SET::PM_FAST );
dummy.DeletePrimitivesList(); dummy.DeletePrimitivesList();
dummy.AddPrimitive( shape, 0 ); dummy.AddPrimitive( shape, 0 );
dummy.MergePrimitivesAsPolygon(); dummy.MergePrimitivesAsPolygon();
@ -801,21 +801,13 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
SHAPE_POLY_SET areas; // Contains shapes to plot SHAPE_POLY_SET areas; // Contains shapes to plot
SHAPE_POLY_SET initialPolys; // Contains exact shapes to plot SHAPE_POLY_SET initialPolys; // Contains exact shapes to plot
/* calculates the coeff to compensate radius reduction of holes clearance
* due to the segment approx ( 1 /cos( PI/circleToSegmentsCount )
*/
int circleToSegmentsCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
double correction = GetCircletoPolyCorrectionFactor( circleToSegmentsCount );
// Plot pads // Plot pads
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
{ {
// add shapes with exact size // add shapes with exact size
module->TransformPadsShapesWithClearanceToPolygon( layer, module->TransformPadsShapesWithClearanceToPolygon( layer, initialPolys, 0 );
initialPolys, 0, circleToSegmentsCount, correction );
// add shapes inflated by aMinThickness/2 // add shapes inflated by aMinThickness/2
module->TransformPadsShapesWithClearanceToPolygon( layer, module->TransformPadsShapesWithClearanceToPolygon( layer, areas, inflate );
areas, inflate, circleToSegmentsCount, correction );
} }
// Plot vias on solder masks, if aPlotOpt.GetPlotViaOnMaskLayer() is true, // Plot vias on solder masks, if aPlotOpt.GetPlotViaOnMaskLayer() is true,
@ -846,12 +838,8 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
if( !( via_set & aLayerMask ).any() ) if( !( via_set & aLayerMask ).any() )
continue; continue;
via->TransformShapeWithClearanceToPolygon( areas, via_margin, via->TransformShapeWithClearanceToPolygon( areas, via_margin );
circleToSegmentsCount, via->TransformShapeWithClearanceToPolygon( initialPolys, via_clearance );
correction );
via->TransformShapeWithClearanceToPolygon( initialPolys, via_clearance,
circleToSegmentsCount,
correction );
} }
} }
@ -869,10 +857,8 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
if( zone->GetLayer() != layer ) if( zone->GetLayer() != layer )
continue; continue;
zone->TransformOutlinesShapeWithClearanceToPolygon( areas, zone->TransformOutlinesShapeWithClearanceToPolygon( areas, inflate + zone_margin, false );
inflate+zone_margin, false ); zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys, zone_margin, false );
zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys,
zone_margin, false );
} }
// To avoid a lot of code, use a ZONE_CONTAINER // To avoid a lot of code, use a ZONE_CONTAINER
@ -885,9 +871,10 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
zone.SetArcSegmentCount( ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF ); zone.SetArcSegmentCount( ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
zone.SetMinThickness( 0 ); // trace polygons only zone.SetMinThickness( 0 ); // trace polygons only
zone.SetLayer ( layer ); zone.SetLayer ( layer );
int numSegs = std::max( GetArcToSegmentCount( inflate, ARC_HIGH_DEF, 360.0 ), 6 );
areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST ); areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
areas.Inflate( -inflate, circleToSegmentsCount ); areas.Inflate( -inflate, numSegs );
// Combine the current areas to initial areas. This is mandatory because // 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 // inflate/deflate transform is not perfect, and we want the initial areas perfectly kept

View File

@ -201,7 +201,7 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl
case PAD_SHAPE_CUSTOM: case PAD_SHAPE_CUSTOM:
{ {
SHAPE_POLY_SET polygons; SHAPE_POLY_SET polygons;
aPad->MergePrimitivesAsPolygon(&polygons, 64 ); aPad->MergePrimitivesAsPolygon( &polygons );
if( polygons.OutlineCount() == 0 ) if( polygons.OutlineCount() == 0 )
break; break;

View File

@ -616,9 +616,7 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
case PAD_SHAPE_ROUNDRECT: case PAD_SHAPE_ROUNDRECT:
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
const int segmentToCircleCount = 64; aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ) );
aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ), segmentToCircleCount, 1.0 );
// TransformRoundRectToPolygon creates only one convex polygon // TransformRoundRectToPolygon creates only one convex polygon
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 ); SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
@ -711,9 +709,7 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
case PAD_SHAPE_ROUNDRECT: case PAD_SHAPE_ROUNDRECT:
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF; aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ) );
aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ),
segmentToCircleCount, 1.0 );
// TransformRoundRectToPolygon creates only one convex polygon // TransformRoundRectToPolygon creates only one convex polygon
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 ); SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );

View File

@ -74,10 +74,9 @@ private:
}; };
extern void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer, extern void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer, const D_PAD& aPad,
const D_PAD& aPad, int aThermalGap, int aCopperThickness, int aThermalGap, int aCopperThickness, int aMinThicknessValue, int aError,
int aMinThicknessValue, int aCircleToSegmentsCount, double aThermalRot );
double aCorrectionFactor, double aThermalRot );
static double s_thermalRot = 450; // angle of stubs in thermal reliefs for round pads static double s_thermalRot = 450; // angle of stubs in thermal reliefs for round pads
static const bool s_DumpZonesWhenFilling = false; static const bool s_DumpZonesWhenFilling = false;
@ -138,7 +137,8 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
} }
std::atomic<size_t> nextItem( 0 ); std::atomic<size_t> nextItem( 0 );
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(), toFill.size() ); size_t parallelThreadCount =
std::min<size_t>( std::thread::hardware_concurrency(), aZones.size() );
std::vector<std::future<size_t>> returns( parallelThreadCount ); std::vector<std::future<size_t>> returns( parallelThreadCount );
auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
@ -218,12 +218,18 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
} }
} }
// Zones with no net can have areas outside the board cutouts. // Zones with no net can have areas outside the board cutouts.
// Please, use only this clipping for no-net zones: this is a very time consumming // By definition, the island has all points outside the outline, so we only
// calculation (x 5 in a test case if made for all zones), mainly due to poly.Fracture // need to check one point for each island
else if( clip_to_brd_outlines ) else if( clip_to_brd_outlines )
{ {
poly.BooleanIntersection( boardOutline, SHAPE_POLY_SET::PM_FAST ); for( auto idx : zone.m_islands )
poly.Fracture( SHAPE_POLY_SET::PM_FAST ); {
if( poly.Polygon( idx ).empty()
|| !boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
{
poly.DeletePolygon( idx );
}
}
} }
zone.m_zone->SetFilledPolysList( poly ); zone.m_zone->SetFilledPolysList( poly );
@ -326,20 +332,6 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone, void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
SHAPE_POLY_SET& aFeatures ) const SHAPE_POLY_SET& aFeatures ) const
{ {
// Set the number of segments in arc approximations
// Since we can no longer edit the segment count in pcbnew, we set
// the fill to our high-def count to avoid jagged knock-outs
// However, if the user has edited their zone to increase the segment count,
// we keep this preference
int segsPerCircle = std::max( aZone->GetArcSegmentCount(), ARC_APPROX_SEGMENTS_COUNT_HIGH_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 / segsPerCircle / 2)
* correctionFactor is 1 /cos( PI/segsPerCircle )
*/
double correctionFactor = GetCircletoPolyCorrectionFactor( segsPerCircle );
aFeatures.RemoveAllContours(); aFeatures.RemoveAllContours();
int zone_clearance = aZone->GetClearance(); int zone_clearance = aZone->GetClearance();
@ -428,9 +420,12 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
// the pad shape in zone can be its convex hull or // the pad shape in zone can be its convex hull or
// the shape itself // the shape itself
SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() ); SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
outline.Inflate( KiROUND( clearance * correctionFactor ), segsPerCircle ); int numSegs = std::max(
pad->CustomShapeAsPolygonToBoardPosition( &outline, GetArcToSegmentCount( clearance, ARC_HIGH_DEF, 360.0 ), 6 );
pad->GetPosition(), pad->GetOrientation() ); double correction = GetCircletoPolyCorrectionFactor( numSegs );
outline.Inflate( KiROUND( clearance * correction ), numSegs );
pad->CustomShapeAsPolygonToBoardPosition(
&outline, pad->GetPosition(), pad->GetOrientation() );
if( pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL ) if( pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
{ {
@ -446,10 +441,7 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
aFeatures.Append( outline ); aFeatures.Append( outline );
} }
else else
pad->TransformShapeWithClearanceToPolygon( aFeatures, pad->TransformShapeWithClearanceToPolygon( aFeatures, clearance );
clearance,
segsPerCircle,
correctionFactor );
} }
continue; continue;
@ -477,10 +469,13 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
{ {
// the pad shape in zone can be its convex hull or // the pad shape in zone can be its convex hull or
// the shape itself // the shape itself
int numSegs =
std::max( GetArcToSegmentCount( gap, ARC_HIGH_DEF, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() ); SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
outline.Inflate( KiROUND( gap * correctionFactor ), segsPerCircle ); outline.Inflate( KiROUND( gap * correction ), numSegs );
pad->CustomShapeAsPolygonToBoardPosition( &outline, pad->CustomShapeAsPolygonToBoardPosition(
pad->GetPosition(), pad->GetOrientation() ); &outline, pad->GetPosition(), pad->GetOrientation() );
std::vector<wxPoint> convex_hull; std::vector<wxPoint> convex_hull;
BuildConvexHull( convex_hull, outline ); BuildConvexHull( convex_hull, outline );
@ -491,8 +486,7 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
aFeatures.Append( convex_hull[ii] ); aFeatures.Append( convex_hull[ii] );
} }
else else
pad->TransformShapeWithClearanceToPolygon( aFeatures, pad->TransformShapeWithClearanceToPolygon( aFeatures, gap );
gap, segsPerCircle, correctionFactor );
} }
} }
} }
@ -515,8 +509,7 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
if( item_boundingbox.Intersects( zone_boundingbox ) ) if( item_boundingbox.Intersects( zone_boundingbox ) )
{ {
int clearance = std::max( zone_clearance, item_clearance ); int clearance = std::max( zone_clearance, item_clearance );
track->TransformShapeWithClearanceToPolygon( aFeatures, track->TransformShapeWithClearanceToPolygon( aFeatures, clearance );
clearance, segsPerCircle, correctionFactor );
} }
} }
@ -549,7 +542,7 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
{ {
case PCB_LINE_T: case PCB_LINE_T:
static_cast<DRAWSEGMENT*>( aItem )->TransformShapeWithClearanceToPolygon( static_cast<DRAWSEGMENT*>( aItem )->TransformShapeWithClearanceToPolygon(
aFeatures, zclearance, segsPerCircle, correctionFactor, ignoreLineWidth ); aFeatures, zclearance, ARC_HIGH_DEF, ignoreLineWidth );
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:
@ -559,7 +552,7 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
case PCB_MODULE_EDGE_T: case PCB_MODULE_EDGE_T:
static_cast<EDGE_MODULE*>( aItem )->TransformShapeWithClearanceToPolygon( static_cast<EDGE_MODULE*>( aItem )->TransformShapeWithClearanceToPolygon(
aFeatures, zclearance, segsPerCircle, correctionFactor, ignoreLineWidth ); aFeatures, zclearance, ARC_HIGH_DEF, ignoreLineWidth );
break; break;
case PCB_MODULE_TEXT_T: case PCB_MODULE_TEXT_T:
@ -667,12 +660,9 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
if( item_boundingbox.Intersects( zone_boundingbox ) ) if( item_boundingbox.Intersects( zone_boundingbox ) )
{ {
CreateThermalReliefPadPolygon( aFeatures, CreateThermalReliefPadPolygon( aFeatures, *pad, thermalGap,
*pad, thermalGap, aZone->GetThermalReliefCopperBridge( pad ), aZone->GetMinThickness(),
aZone->GetThermalReliefCopperBridge( pad ), ARC_HIGH_DEF, s_thermalRot );
aZone->GetMinThickness(),
segsPerCircle,
correctionFactor, s_thermalRot );
} }
} }
} }
@ -717,19 +707,16 @@ void ZONE_FILLER::computeRawFilledAreas( const ZONE_CONTAINER* aZone,
std::unique_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO( std::unique_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO(
s_DumpZonesWhenFilling ? "zones_dump.txt" : "", SHAPE_FILE_IO::IOM_APPEND ) ); s_DumpZonesWhenFilling ? "zones_dump.txt" : "", SHAPE_FILE_IO::IOM_APPEND ) );
// Set the number of segments in arc approximations
int segsPerCircle = std::max( aZone->GetArcSegmentCount(), ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
/* calculates the coeff to compensate radius reduction of holes clearance
*/
double correctionFactor = GetCircletoPolyCorrectionFactor( segsPerCircle );
if( s_DumpZonesWhenFilling ) if( s_DumpZonesWhenFilling )
dumper->BeginGroup( "clipper-zone" ); dumper->BeginGroup( "clipper-zone" );
SHAPE_POLY_SET solidAreas = aSmoothedOutline; SHAPE_POLY_SET solidAreas = aSmoothedOutline;
solidAreas.Inflate( -outline_half_thickness, segsPerCircle ); int numSegs =
std::max( GetArcToSegmentCount( outline_half_thickness, ARC_HIGH_DEF, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs );
solidAreas.Inflate( -outline_half_thickness, numSegs );
solidAreas.Simplify( SHAPE_POLY_SET::PM_FAST ); solidAreas.Simplify( SHAPE_POLY_SET::PM_FAST );
SHAPE_POLY_SET holes; SHAPE_POLY_SET holes;
@ -788,9 +775,8 @@ void ZONE_FILLER::computeRawFilledAreas( const ZONE_CONTAINER* aZone,
if( aZone->GetNetCode() > 0 ) if( aZone->GetNetCode() > 0 )
{ {
buildUnconnectedThermalStubsPolygonList( thermalHoles, aZone, solidAreas, buildUnconnectedThermalStubsPolygonList(
correctionFactor, s_thermalRot ); thermalHoles, aZone, solidAreas, correction, s_thermalRot );
} }
// remove copper areas corresponding to not connected stubs // remove copper areas corresponding to not connected stubs
@ -853,7 +839,9 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol
} }
else else
{ {
aFinalPolys.Inflate( -aZone->GetMinThickness() / 2, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF ); int numSegs = std::max(
GetArcToSegmentCount( aZone->GetMinThickness() / 2, ARC_HIGH_DEF, 360.0 ), 6 );
aFinalPolys.Inflate( -aZone->GetMinThickness() / 2, numSegs );
// Remove the non filled areas due to the hatch pattern // Remove the non filled areas due to the hatch pattern
if( aZone->GetFillMode() == ZFM_HATCH_PATTERN ) if( aZone->GetFillMode() == ZFM_HATCH_PATTERN )

View File

@ -46,12 +46,7 @@ void process( const BOARD_CONNECTED_ITEM* item, int net )
SHAPE_POLY_SET pset; SHAPE_POLY_SET pset;
const int segsPerCircle = 64; item->TransformShapeWithClearanceToPolygon( pset, 1, ARC_HIGH_DEF );
double correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );
item->TransformShapeWithClearanceToPolygon( pset, 1, segsPerCircle, correctionFactor );
SHAPE_FILE_IO shapeIo; // default = stdout SHAPE_FILE_IO shapeIo; // default = stdout
shapeIo.Write( &pset ); shapeIo.Write( &pset );