Move SHAPE_POLY_SET::Inflate's error spec from a seg-count to a max-deviation.

1) Also reorders parameters to make sure the compiler helps out.

2) This also makes it harder to mess up the discrepency between
   BOX2I/wxRECT/etc::Inflate() and SHAPE_POLY_SET::Inflate.

3) Also fixes a couple of bugs where the corner strategy was passed
   in as a segCount.

4) Also fixes a couple of bugs where the error wasn't forced to the
   outside to match the ERROR_LOCATION.

5) Also fixes a couple of bugs where the seg count was specified
   without regard to an already passed-in max deviation
This commit is contained in:
Jeff Young 2023-05-29 15:28:48 +01:00
parent 7f250870fe
commit 65e53b8ecd
14 changed files with 83 additions and 81 deletions

View File

@ -438,7 +438,7 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aCo
if( !poly.IsEmpty() ) if( !poly.IsEmpty() )
{ {
if( clearance.x ) if( clearance.x )
poly.Inflate( clearance.x, 32 ); poly.Inflate( clearance.x, SHAPE_POLY_SET::ROUND_ALL_CORNERS, maxError );
// Add the PAD polygon // Add the PAD polygon
ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad ); ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad );

View File

@ -1002,19 +1002,19 @@ public:
* the outline. * the outline.
* *
* @param aAmount is the number of units to offset edges. * @param aAmount is the number of units to offset edges.
* @param aCircleSegCount is the number of segments per 360 degrees to use in curve approx
* @param aCornerStrategy #ALLOW_ACUTE_CORNERS to preserve all angles, * @param aCornerStrategy #ALLOW_ACUTE_CORNERS to preserve all angles,
* #CHAMFER_ACUTE_CORNERS to chop angles less than 90°, * #CHAMFER_ACUTE_CORNERS to chop angles less than 90°,
* #ROUND_ACUTE_CORNERS to round off angles less than 90°, * #ROUND_ACUTE_CORNERS to round off angles less than 90°,
* #ROUND_ALL_CORNERS to round regardless of angles * #ROUND_ALL_CORNERS to round regardless of angles
* @param aMaxError is the allowable deviation when rounding corners with an approximated
* polygon
*/ */
void Inflate( int aAmount, int aCircleSegCount, void Inflate( int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError,
CORNER_STRATEGY aCornerStrategy = ROUND_ALL_CORNERS, bool aSimplify = false ); bool aSimplify = false );
void Deflate( int aAmount, int aCircleSegmentsCount, void Deflate( int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError )
CORNER_STRATEGY aCornerStrategy = CHAMFER_ALL_CORNERS )
{ {
Inflate( -aAmount, aCircleSegmentsCount, aCornerStrategy ); Inflate( -aAmount, aCornerStrategy, aMaxError );
} }
/** /**

View File

@ -1096,13 +1096,15 @@ void SHAPE_POLY_SET::inflate2( int aAmount, int aCircleSegCount, CORNER_STRATEGY
} }
void SHAPE_POLY_SET::Inflate( int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, void SHAPE_POLY_SET::Inflate( int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError,
bool aSimplify ) bool aSimplify )
{ {
int segCount = GetArcToSegmentCount( aAmount, aMaxError, FULL_CIRCLE );
if( ADVANCED_CFG::GetCfg().m_UseClipper2 ) if( ADVANCED_CFG::GetCfg().m_UseClipper2 )
inflate2( aAmount, aCircleSegCount, aCornerStrategy, aSimplify ); inflate2( aAmount, segCount, aCornerStrategy, aSimplify );
else else
inflate1( aAmount, aCircleSegCount, aCornerStrategy ); inflate1( aAmount, segCount, aCornerStrategy );
} }

View File

@ -190,8 +190,9 @@ bool DRC_TEST_PROVIDER_TEXT_DIMS::Run()
if( glyphArea == 0 ) if( glyphArea == 0 )
continue; continue;
poly.Inflate( constraint.Value().Min() / 2, 16 ); poly.Inflate( constraint.Value().Min() / 2,
poly.Simplify( SHAPE_POLY_SET::PM_FAST ); SHAPE_POLY_SET::CHAMFER_ALL_CORNERS, ARC_LOW_DEF, true );
double resultingGlyphArea = poly.Area(); double resultingGlyphArea = poly.Area();
if( ( std::abs( resultingGlyphArea - glyphArea ) / glyphArea ) > 0.1 ) if( ( std::abs( resultingGlyphArea - glyphArea ) / glyphArea ) > 0.1 )

View File

@ -1952,13 +1952,13 @@ double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLEC
{ {
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem ); const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
text->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE ); text->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
} }
else if( aItem->Type() == PCB_TEXTBOX_T ) else if( aItem->Type() == PCB_TEXTBOX_T )
{ {
const PCB_TEXTBOX* tb = static_cast<const PCB_TEXTBOX*>( aItem ); const PCB_TEXTBOX* tb = static_cast<const PCB_TEXTBOX*>( aItem );
tb->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE ); tb->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_INSIDE );
} }
else if( aItem->Type() == PCB_SHAPE_T ) else if( aItem->Type() == PCB_SHAPE_T )
{ {
@ -2138,14 +2138,14 @@ void FOOTPRINT::BuildCourtyardCaches( OUTLINE_ERROR_HANDLER* aErrorHandler )
if( !list_front.size() && !list_back.size() ) if( !list_front.size() && !list_back.size() )
return; return;
int errorMax = pcbIUScale.mmToIU( 0.02 ); // max error for polygonization int maxError = pcbIUScale.mmToIU( 0.02 ); // max error for polygonization
int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt
if( ConvertOutlineToPolygon( list_front, m_courtyard_cache_front, errorMax, chainingEpsilon, if( ConvertOutlineToPolygon( list_front, m_courtyard_cache_front, maxError, chainingEpsilon,
true, aErrorHandler ) ) true, aErrorHandler ) )
{ {
// Touching courtyards, or courtyards -at- the clearance distance are legal. // Touching courtyards, or courtyards -at- the clearance distance are legal.
m_courtyard_cache_front.Inflate( -1, SHAPE_POLY_SET::CHAMFER_ACUTE_CORNERS ); m_courtyard_cache_front.Inflate( -1, SHAPE_POLY_SET::CHAMFER_ACUTE_CORNERS, maxError );
m_courtyard_cache_front.CacheTriangulation( false ); m_courtyard_cache_front.CacheTriangulation( false );
} }
@ -2154,11 +2154,11 @@ void FOOTPRINT::BuildCourtyardCaches( OUTLINE_ERROR_HANDLER* aErrorHandler )
SetFlags( MALFORMED_F_COURTYARD ); SetFlags( MALFORMED_F_COURTYARD );
} }
if( ConvertOutlineToPolygon( list_back, m_courtyard_cache_back, errorMax, chainingEpsilon, if( ConvertOutlineToPolygon( list_back, m_courtyard_cache_back, maxError, chainingEpsilon,
true, aErrorHandler ) ) true, aErrorHandler ) )
{ {
// Touching courtyards, or courtyards -at- the clearance distance are legal. // Touching courtyards, or courtyards -at- the clearance distance are legal.
m_courtyard_cache_back.Inflate( -1, SHAPE_POLY_SET::CHAMFER_ACUTE_CORNERS ); m_courtyard_cache_back.Inflate( -1, SHAPE_POLY_SET::CHAMFER_ACUTE_CORNERS, maxError );
m_courtyard_cache_back.CacheTriangulation( false ); m_courtyard_cache_back.CacheTriangulation( false );
} }

View File

@ -1592,7 +1592,7 @@ bool PAD::TransformHoleToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int a
void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance, void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
{ {
wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for pads." ) ); wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for pads." ) );
@ -1613,7 +1613,7 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
// Note: dx == dy is not guaranteed for circle pads in legacy boards // Note: dx == dy is not guaranteed for circle pads in legacy boards
if( dx == dy || ( GetShape() == PAD_SHAPE::CIRCLE ) ) if( dx == dy || ( GetShape() == PAD_SHAPE::CIRCLE ) )
{ {
TransformCircleToPolygon( aBuffer, padShapePos, dx + aClearance, aError, aErrorLoc, TransformCircleToPolygon( aBuffer, padShapePos, dx + aClearance, aMaxError, aErrorLoc,
pad_min_seg_per_circle_count ); pad_min_seg_per_circle_count );
} }
else else
@ -1624,7 +1624,7 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
RotatePoint( delta, m_orient ); RotatePoint( delta, m_orient );
TransformOvalToPolygon( aBuffer, padShapePos - delta, padShapePos + delta, TransformOvalToPolygon( aBuffer, padShapePos - delta, padShapePos + delta,
( half_width + aClearance ) * 2, aError, aErrorLoc, ( half_width + aClearance ) * 2, aMaxError, aErrorLoc,
pad_min_seg_per_circle_count ); pad_min_seg_per_circle_count );
} }
@ -1638,7 +1638,7 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
TransformTrapezoidToPolygon( outline, padShapePos, m_size, m_orient, ddx, ddy, aClearance, TransformTrapezoidToPolygon( outline, padShapePos, m_size, m_orient, ddx, ddy, aClearance,
aError, aErrorLoc ); aMaxError, aErrorLoc );
aBuffer.Append( outline ); aBuffer.Append( outline );
break; break;
} }
@ -1653,7 +1653,7 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
GetRoundRectCornerRadius(), GetRoundRectCornerRadius(),
doChamfer ? GetChamferRectRatio() : 0, doChamfer ? GetChamferRectRatio() : 0,
doChamfer ? GetChamferPositions() : 0, doChamfer ? GetChamferPositions() : 0,
aClearance, aError, aErrorLoc ); aClearance, aMaxError, aErrorLoc );
aBuffer.Append( outline ); aBuffer.Append( outline );
break; break;
} }
@ -1665,19 +1665,12 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
outline.Rotate( m_orient ); outline.Rotate( m_orient );
outline.Move( VECTOR2I( m_pos ) ); outline.Move( VECTOR2I( m_pos ) );
if( aClearance ) if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
{ {
int numSegs = std::max( GetArcToSegmentCount( aClearance, aError, FULL_CIRCLE ),
pad_min_seg_per_circle_count );
int clearance = aClearance;
if( aErrorLoc == ERROR_OUTSIDE ) if( aErrorLoc == ERROR_OUTSIDE )
{ aClearance += aMaxError;
int actual_error = CircleToEndSegmentDeltaRadius( clearance, numSegs );
clearance += GetCircleToPolyCorrection( actual_error );
}
outline.Inflate( clearance, numSegs ); outline.Inflate( aClearance, SHAPE_POLY_SET::ROUND_ALL_CORNERS, aMaxError );
outline.Fracture( SHAPE_POLY_SET::PM_FAST ); outline.Fracture( SHAPE_POLY_SET::PM_FAST );
} }

View File

@ -466,7 +466,7 @@ void PCB_TEXT::buildBoundingHull( SHAPE_POLY_SET* aBuffer, const SHAPE_POLY_SET&
} }
void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError, void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aMaxError,
ERROR_LOC aErrorLoc ) const ERROR_LOC aErrorLoc ) const
{ {
KIGFX::GAL_DISPLAY_OPTIONS empty_opts; KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
@ -485,7 +485,7 @@ void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance,
// Stroke callback // Stroke callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 ) [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
{ {
TransformOvalToPolygon( textShape, aPt1, aPt2, penWidth, aError, aErrorLoc ); TransformOvalToPolygon( textShape, aPt1, aPt2, penWidth, aMaxError, aErrorLoc );
}, },
// Triangulation callback // Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 ) [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
@ -511,11 +511,12 @@ void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance,
} }
else else
{ {
if( aClearance > 0 ) if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
{ {
// Number of segments to approximate a circle when inflating a polygon if( aErrorLoc == ERROR_OUTSIDE )
const int circleSegmentsCount = 16; aClearance += aMaxError;
textShape.Inflate( aClearance, circleSegmentsCount );
textShape.Inflate( aClearance, SHAPE_POLY_SET::ROUND_ALL_CORNERS, aMaxError );
} }
aBuffer.Append( textShape ); aBuffer.Append( textShape );
@ -524,12 +525,12 @@ void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance,
void PCB_TEXT::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, void PCB_TEXT::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
int aClearance, int aError, ERROR_LOC aErrorLoc, int aClearance, int aMaxError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth ) const bool aIgnoreLineWidth ) const
{ {
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
TransformTextToPolySet( poly, 0, GetBoard()->GetDesignSettings().m_MaxError, ERROR_INSIDE ); TransformTextToPolySet( poly, 0, aMaxError, aErrorLoc );
buildBoundingHull( &aBuffer, poly, aClearance ); buildBoundingHull( &aBuffer, poly, aClearance );
} }

View File

@ -137,13 +137,13 @@ public:
* Circles and arcs are approximated by segments. * Circles and arcs are approximated by segments.
* @param aBuffer SHAPE_POLY_SET to store the polygon corners * @param aBuffer SHAPE_POLY_SET to store the polygon corners
* @param aClearance the clearance around the text * @param aClearance the clearance around the text
* @param aError the maximum error to allow when approximating curves * @param aMaxError the maximum error to allow when approximating curves
*/ */
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError, void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aMaxError,
ERROR_LOC aErrorLoc ) const; ERROR_LOC aErrorLoc ) const;
void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance, void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc, int aMaxError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth = false ) const override; bool aIgnoreLineWidth = false ) const override;
// @copydoc BOARD_ITEM::GetEffectiveShape // @copydoc BOARD_ITEM::GetEffectiveShape

View File

@ -447,7 +447,7 @@ std::shared_ptr<SHAPE> PCB_TEXTBOX::GetEffectiveShape( PCB_LAYER_ID aLayer, FLAS
} }
void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError, void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aMaxError,
ERROR_LOC aErrorLoc ) const ERROR_LOC aErrorLoc ) const
{ {
KIGFX::GAL_DISPLAY_OPTIONS empty_opts; KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
@ -465,7 +465,7 @@ void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearanc
// Stroke callback // Stroke callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 ) [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
{ {
TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth, aError, aErrorLoc ); TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth, aMaxError, aErrorLoc );
}, },
// Triangulation callback // Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 ) [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
@ -478,17 +478,24 @@ void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearanc
font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), GetAttributes() ); font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), GetAttributes() );
if( aClearance > 0 ) if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
buffer.Inflate( aClearance, aClearance ); {
if( aErrorLoc == ERROR_OUTSIDE )
aClearance += aMaxError;
buffer.Inflate( aClearance, SHAPE_POLY_SET::ROUND_ALL_CORNERS, aMaxError, true );
}
else else
{
buffer.Simplify( SHAPE_POLY_SET::PM_FAST ); buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
}
aBuffer.Append( buffer ); aBuffer.Append( buffer );
} }
void PCB_TEXTBOX::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, void PCB_TEXTBOX::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
int aClearance, int aError, ERROR_LOC aErrorLoc, int aClearance, int aMaxError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth ) const bool aIgnoreLineWidth ) const
{ {
// Don't use PCB_SHAPE::TransformShapeToPolygon. We want to treat the textbox as filled even // Don't use PCB_SHAPE::TransformShapeToPolygon. We want to treat the textbox as filled even
@ -508,10 +515,10 @@ void PCB_TEXTBOX::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID
if( width > 0 ) if( width > 0 )
{ {
// Add in segments // Add in segments
TransformOvalToPolygon( aBuffer, pts[0], pts[1], width, aError, aErrorLoc ); TransformOvalToPolygon( aBuffer, pts[0], pts[1], width, aMaxError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[1], pts[2], width, aError, aErrorLoc ); TransformOvalToPolygon( aBuffer, pts[1], pts[2], width, aMaxError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[2], pts[3], width, aError, aErrorLoc ); TransformOvalToPolygon( aBuffer, pts[2], pts[3], width, aMaxError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[3], pts[0], width, aError, aErrorLoc ); TransformOvalToPolygon( aBuffer, pts[3], pts[0], width, aMaxError, aErrorLoc );
} }
} }
else if( GetShape() == SHAPE_T::POLY ) // Non-cardinally-rotated rect else if( GetShape() == SHAPE_T::POLY ) // Non-cardinally-rotated rect
@ -528,7 +535,7 @@ void PCB_TEXTBOX::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID
for( int ii = 0; ii < poly.SegmentCount(); ++ii ) for( int ii = 0; ii < poly.SegmentCount(); ++ii )
{ {
const SEG& seg = poly.GetSegment( ii ); const SEG& seg = poly.GetSegment( ii );
TransformOvalToPolygon( aBuffer, seg.A, seg.B, width, aError, aErrorLoc ); TransformOvalToPolygon( aBuffer, seg.A, seg.B, width, aMaxError, aErrorLoc );
} }
} }
} }

View File

@ -114,11 +114,11 @@ public:
* @param aClearance = the clearance around the text * @param aClearance = the clearance around the text
* @param aError = the maximum error to allow when approximating curves * @param aError = the maximum error to allow when approximating curves
*/ */
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError, void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aMaxError,
ERROR_LOC aErrorLoc ) const; ERROR_LOC aErrorLoc ) const;
void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance, void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc, int aMaxError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth = false ) const override; bool aIgnoreLineWidth = false ) const override;
// @copydoc BOARD_ITEM::GetEffectiveShape // @copydoc BOARD_ITEM::GetEffectiveShape

View File

@ -2139,7 +2139,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers()
{ {
fill = getPolySetFromCadstarShape( csCopper.Shape, -1 ); fill = getPolySetFromCadstarShape( csCopper.Shape, -1 );
fill.ClearArcs(); fill.ClearArcs();
fill.Inflate( copperWidth / 2, 32 ); fill.Inflate( copperWidth / 2, SHAPE_POLY_SET::ROUND_ALL_CORNERS, ARC_HIGH_DEF );
} }
if( pouredZone->HasFilledPolysForLayer( getKiCadLayer( csCopper.LayerID ) ) ) if( pouredZone->HasFilledPolysForLayer( getKiCadLayer( csCopper.LayerID ) ) )
@ -3033,10 +3033,7 @@ SHAPE_POLY_SET CADSTAR_PCB_ARCHIVE_LOADER::getPolySetFromCadstarShape( const SHA
polySet.ClearArcs(); polySet.ClearArcs();
if( aLineThickness > 0 ) if( aLineThickness > 0 )
{ polySet.Inflate( aLineThickness / 2, SHAPE_POLY_SET::ROUND_ALL_CORNERS, ARC_HIGH_DEF );
polySet.Inflate( aLineThickness / 2, 32,
SHAPE_POLY_SET::CORNER_STRATEGY::ROUND_ALL_CORNERS );
}
#ifdef DEBUG #ifdef DEBUG
for( int i = 0; i < polySet.OutlineCount(); ++i ) for( int i = 0; i < polySet.OutlineCount(); ++i )
@ -3730,7 +3727,8 @@ bool CADSTAR_PCB_ARCHIVE_LOADER::calculateZonePriorities( PCB_LAYER_ID& aLayer )
[&]( ZONE* aLowerZone, ZONE* aHigherZone ) -> double [&]( ZONE* aLowerZone, ZONE* aHigherZone ) -> double
{ {
SHAPE_POLY_SET intersectShape( *aHigherZone->Outline() ); SHAPE_POLY_SET intersectShape( *aHigherZone->Outline() );
intersectShape.Inflate( inflateValue( aLowerZone, aHigherZone ) , 32 ); intersectShape.Inflate( inflateValue( aLowerZone, aHigherZone ),
SHAPE_POLY_SET::ROUND_ALL_CORNERS, ARC_HIGH_DEF );
SHAPE_POLY_SET lowerZoneFill( *aLowerZone->GetFilledPolysList( aLayer ) ); SHAPE_POLY_SET lowerZoneFill( *aLowerZone->GetFilledPolysList( aLayer ) );
SHAPE_POLY_SET lowerZoneOutline( *aLowerZone->Outline() ); SHAPE_POLY_SET lowerZoneOutline( *aLowerZone->Outline() );
@ -3748,10 +3746,12 @@ bool CADSTAR_PCB_ARCHIVE_LOADER::calculateZonePriorities( PCB_LAYER_ID& aLayer )
[&]( ZONE* aZoneA, ZONE* aZoneB ) -> double [&]( ZONE* aZoneA, ZONE* aZoneB ) -> double
{ {
SHAPE_POLY_SET outLineA( *aZoneA->Outline() ); SHAPE_POLY_SET outLineA( *aZoneA->Outline() );
outLineA.Inflate( inflateValue( aZoneA, aZoneB ), 32 ); outLineA.Inflate( inflateValue( aZoneA, aZoneB ), SHAPE_POLY_SET::ROUND_ALL_CORNERS,
ARC_HIGH_DEF );
SHAPE_POLY_SET outLineB( *aZoneA->Outline() ); SHAPE_POLY_SET outLineB( *aZoneA->Outline() );
outLineB.Inflate( inflateValue( aZoneA, aZoneB ), 32 ); outLineB.Inflate( inflateValue( aZoneA, aZoneB ), SHAPE_POLY_SET::ROUND_ALL_CORNERS,
ARC_HIGH_DEF );
outLineA.BooleanIntersection( outLineB, SHAPE_POLY_SET::PM_FAST ); outLineA.BooleanIntersection( outLineB, SHAPE_POLY_SET::PM_FAST );

View File

@ -1492,7 +1492,8 @@ ZONE* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
// We trace the zone such that the copper is completely inside. // We trace the zone such that the copper is completely inside.
if( p.width.ToPcbUnits() > 0 ) if( p.width.ToPcbUnits() > 0 )
{ {
polygon.Inflate( p.width.ToPcbUnits() / 2, 32, SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS ); polygon.Inflate( p.width.ToPcbUnits() / 2, SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS,
ARC_HIGH_DEF );
polygon.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); polygon.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
} }
@ -2233,8 +2234,8 @@ void EAGLE_PLUGIN::packagePolygon( FOOTPRINT* aFootprint, wxXmlNode* aTree ) con
dwg->SetPolyPoints( pts ); dwg->SetPolyPoints( pts );
dwg->Rotate( { 0, 0 }, aFootprint->GetOrientation() ); dwg->Rotate( { 0, 0 }, aFootprint->GetOrientation() );
dwg->Move( aFootprint->GetPosition() ); dwg->Move( aFootprint->GetPosition() );
dwg->GetPolyShape().Inflate( p.width.ToPcbUnits() / 2, 32, dwg->GetPolyShape().Inflate( p.width.ToPcbUnits() / 2,
SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS ); SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS, ARC_HIGH_DEF );
} }
} }

View File

@ -1231,7 +1231,7 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer
if( aSmoothedPolyWithApron ) if( aSmoothedPolyWithApron )
{ {
SHAPE_POLY_SET poly = maxExtents->CloneDropTriangulation(); SHAPE_POLY_SET poly = maxExtents->CloneDropTriangulation();
poly.Inflate( m_ZoneMinThickness, 64 ); poly.Inflate( m_ZoneMinThickness, SHAPE_POLY_SET::ROUND_ALL_CORNERS, maxError );
*aSmoothedPolyWithApron = aSmoothedPoly; *aSmoothedPolyWithApron = aSmoothedPoly;
aSmoothedPolyWithApron->BooleanIntersection( poly, SHAPE_POLY_SET::PM_FAST ); aSmoothedPolyWithApron->BooleanIntersection( poly, SHAPE_POLY_SET::PM_FAST );
} }
@ -1292,12 +1292,10 @@ void ZONE::TransformSmoothedOutlineToPolygon( SHAPE_POLY_SET& aBuffer, int aClea
if( board ) if( board )
maxError = board->GetDesignSettings().m_MaxError; maxError = board->GetDesignSettings().m_MaxError;
int segCount = GetArcToSegmentCount( aClearance, maxError, FULL_CIRCLE );
if( aErrorLoc == ERROR_OUTSIDE ) if( aErrorLoc == ERROR_OUTSIDE )
aClearance += aMaxError; aClearance += maxError;
polybuffer.Inflate( aClearance, segCount ); polybuffer.Inflate( aClearance, SHAPE_POLY_SET::ROUND_ALL_CORNERS, maxError );
} }
polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST ); polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );

View File

@ -1391,7 +1391,6 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
// deflating/inflating. // deflating/inflating.
int half_min_width = aZone->GetMinThickness() / 2; int half_min_width = aZone->GetMinThickness() / 2;
int epsilon = pcbIUScale.mmToIU( 0.001 ); int epsilon = pcbIUScale.mmToIU( 0.001 );
int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, FULL_CIRCLE );
// Solid polygons are deflated and inflated during calculations. Deflating doesn't cause // Solid polygons are deflated and inflated during calculations. Deflating doesn't cause
// issues, but inflate is tricky as it can create excessively long and narrow spikes for // issues, but inflate is tricky as it can create excessively long and narrow spikes for
@ -1456,10 +1455,10 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
// Prune features that don't meet minimum-width criteria // Prune features that don't meet minimum-width criteria
if( half_min_width - epsilon > epsilon ) if( half_min_width - epsilon > epsilon )
{ {
testAreas.Deflate( half_min_width - epsilon, numSegs, fastCornerStrategy ); testAreas.Deflate( half_min_width - epsilon, fastCornerStrategy, m_maxError );
DUMP_POLYS_TO_COPPER_LAYER( testAreas, In5_Cu, wxT( "spoke-test-deflated" ) ); DUMP_POLYS_TO_COPPER_LAYER( testAreas, In5_Cu, wxT( "spoke-test-deflated" ) );
testAreas.Inflate( half_min_width - epsilon, numSegs, fastCornerStrategy ); testAreas.Inflate( half_min_width - epsilon, fastCornerStrategy, m_maxError );
DUMP_POLYS_TO_COPPER_LAYER( testAreas, In6_Cu, wxT( "spoke-test-reinflated" ) ); DUMP_POLYS_TO_COPPER_LAYER( testAreas, In6_Cu, wxT( "spoke-test-reinflated" ) );
} }
@ -1526,7 +1525,7 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
*/ */
if( half_min_width - epsilon > epsilon ) if( half_min_width - epsilon > epsilon )
aFillPolys.Deflate( half_min_width - epsilon, numSegs, fastCornerStrategy ); aFillPolys.Deflate( half_min_width - epsilon, fastCornerStrategy, m_maxError );
// Min-thickness is the web thickness. On the other hand, a blob min-thickness by // Min-thickness is the web thickness. On the other hand, a blob min-thickness by
// min-thickness is not useful. Since there's no obvious definition of web vs. blob, we // min-thickness is not useful. Since there's no obvious definition of web vs. blob, we
@ -1563,7 +1562,7 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
*/ */
if( half_min_width - epsilon > epsilon ) if( half_min_width - epsilon > epsilon )
aFillPolys.Inflate( half_min_width - epsilon, numSegs, cornerStrategy, true ); aFillPolys.Inflate( half_min_width - epsilon, cornerStrategy, m_maxError, true );
DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In15_Cu, wxT( "after-reinflating" ) ); DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In15_Cu, wxT( "after-reinflating" ) );
@ -1663,7 +1662,7 @@ bool ZONE_FILLER::fillNonCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer,
int epsilon = pcbIUScale.mmToIU( 0.001 ); int epsilon = pcbIUScale.mmToIU( 0.001 );
int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, FULL_CIRCLE ); int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, FULL_CIRCLE );
aFillPolys.Deflate( half_min_width - epsilon, numSegs ); aFillPolys.Deflate( half_min_width - epsilon, SHAPE_POLY_SET::CHAMFER_ALL_CORNERS, m_maxError );
// Remove the non filled areas due to the hatch pattern // Remove the non filled areas due to the hatch pattern
if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN ) if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
@ -1674,7 +1673,7 @@ bool ZONE_FILLER::fillNonCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer,
// Re-inflate after pruning of areas that don't meet minimum-width criteria // Re-inflate after pruning of areas that don't meet minimum-width criteria
if( half_min_width - epsilon > epsilon ) if( half_min_width - epsilon > epsilon )
aFillPolys.Inflate( half_min_width - epsilon, numSegs ); aFillPolys.Inflate( half_min_width - epsilon, SHAPE_POLY_SET::ROUND_ALL_CORNERS, m_maxError );
aFillPolys.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); aFillPolys.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
return true; return true;