Use rendered text to generate bounding box for knockout text.

Don't open-code knockout text shape generation in several different
places.

Make sure triangulated knockout text gets clearance added when
specified.

Collapse duplicated footprint text item plot routine (they're no
longer any different from plotting pcb text items).

(cherry picked from commit c71cf21e2f)
This commit is contained in:
Jeff Young 2023-05-28 17:20:11 +01:00
parent ae0534cbb4
commit 214f785c97
22 changed files with 286 additions and 404 deletions

View File

@ -348,7 +348,7 @@ private:
PCB_LAYER_ID aLayerId );
void addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aDstContainer,
const BOARD_ITEM* aOwner );
const BOARD_ITEM* aItem );
void addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner );

View File

@ -64,7 +64,7 @@
void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContainer,
const BOARD_ITEM* aOwner )
const BOARD_ITEM* aItem )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
@ -74,34 +74,25 @@ void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContaine
if( !font )
font = KIFONT::FONT::GetFont( wxEmptyString, aText->IsBold(), aText->IsItalic() );
if( aOwner && aOwner->IsKnockout() )
if( aItem && aItem->IsKnockout() )
{
SHAPE_POLY_SET knockouts;
CALLBACK_GAL callback_gal( empty_opts,
// Polygon callback
[&]( const SHAPE_LINE_CHAIN& aPoly )
{
knockouts.AddOutline( aPoly );
} );
attrs.m_StrokeWidth = aText->GetEffectiveTextPenWidth();
attrs.m_Angle = aText->GetDrawRotation();
callback_gal.SetIsFill( font->IsOutline() );
callback_gal.SetIsStroke( font->IsStroke() );
callback_gal.SetLineWidth( attrs.m_StrokeWidth );
font->Draw( &callback_gal, aText->GetShownText( true ), aText->GetDrawPos(), attrs );
int maxError = m_board->GetDesignSettings().m_MaxError;
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5 +
GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
if( aItem->Type() == PCB_FP_TEXT_T )
{
static_cast<const FP_TEXT*>( aItem )->TransformTextToPolySet( finalPoly, 0, maxError,
ERROR_INSIDE );
}
else if( aItem->Type() == PCB_TEXT_T )
{
static_cast<const PCB_TEXT*>( aItem )->TransformTextToPolySet( finalPoly, 0, maxError,
ERROR_INSIDE );
}
ConvertPolygonToTriangles( finalPoly, *aContainer, m_biuTo3Dunits, *aOwner );
// Do not call finalPoly.Fracture() here: ConvertPolygonToTriangles() call it
// if needed, and Fracture() called twice can create bad results and is useless
ConvertPolygonToTriangles( finalPoly, *aContainer, m_biuTo3Dunits, *aItem );
}
else
{
@ -120,19 +111,19 @@ void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContaine
{
// Cannot add segments that have the same start and end point
aContainer->Add( new FILLED_CIRCLE_2D( pt1_3DU, penWidth_3DU / 2,
*aOwner ) );
*aItem ) );
}
else
{
aContainer->Add( new ROUND_SEGMENT_2D( pt1_3DU, pt2_3DU, penWidth_3DU,
*aOwner ) );
*aItem ) );
}
},
// Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
{
aContainer->Add( new TRIANGLE_2D( TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
TO_SFVEC2F( aPt3 ), *aOwner ) );
TO_SFVEC2F( aPt3 ), *aItem ) );
} );
attrs.m_Angle = aText->GetDrawRotation();

View File

@ -649,7 +649,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
{
PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
text->TransformTextToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
text->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
break;
}
@ -657,7 +657,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
{
PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
textbox->TransformTextToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
textbox->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
break;
}
@ -958,7 +958,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
{
PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
text->TransformTextToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
text->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
break;
}
@ -966,7 +966,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
{
PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
textbox->TransformTextToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
textbox->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
break;
}

View File

@ -990,41 +990,6 @@ int EDA_TEXT::Compare( const EDA_TEXT* aOther ) const
}
void EDA_TEXT::TransformBoundingBoxToPolygon( SHAPE_POLY_SET* aBuffer, int aClearance ) const
{
if( GetText().Length() == 0 )
return;
VECTOR2I corners[4]; // Buffer of polygon corners
BOX2I rect = GetTextBox();
// TrueType bounding boxes aren't guaranteed to include all descenders, diacriticals, etc.
// Since we use this for zone knockouts and DRC, we need something more accurate.
if( getDrawFont()->IsOutline() )
rect = GetEffectiveTextShape( false, false )->BBox();
rect.Inflate( aClearance );
corners[0].x = rect.GetOrigin().x;
corners[0].y = rect.GetOrigin().y;
corners[1].y = corners[0].y;
corners[1].x = rect.GetRight();
corners[2].x = corners[1].x;
corners[2].y = rect.GetBottom();
corners[3].y = corners[2].y;
corners[3].x = corners[0].x;
aBuffer->NewOutline();
for( VECTOR2I& corner : corners )
{
RotatePoint( corner, GetDrawPos(), GetDrawRotation() );
aBuffer->Append( corner.x, corner.y );
}
}
bool EDA_TEXT::ValidateHyperlink( const wxString& aURL )
{
if( aURL.IsEmpty() || IsGotoPageHref( aURL ) )

View File

@ -231,19 +231,6 @@ public:
void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset,
const COLOR4D& aColor, OUTLINE_MODE aDisplay_mode = FILLED );
/**
* Convert the text bounding box to a rectangular polygon depending on the text
* orientation, the bounding box is not always horizontal or vertical
*
* Used in filling zones calculations
* Circles and arcs are approximated by segments
*
* @param aBuffer a buffer to store the polygon.
* @param aClearance the clearance around the text bounding box
* to the real clearance value (usually near from 1.0).
*/
void TransformBoundingBoxToPolygon( SHAPE_POLY_SET* aBuffer, int aClearance ) const;
/**
* build a list of segments (SHAPE_SEGMENT) to describe a text shape.
* @param aTriangulate: true to build also the triangulation of each shape

View File

@ -2388,7 +2388,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer,
case PCB_TEXT_T:
{
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
text->TransformTextToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
text->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
break;
}
@ -2400,7 +2400,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer,
textbox->PCB_SHAPE::TransformShapeToPolygon( aOutlines, aLayer, 0, maxError,
ERROR_INSIDE );
// plot text
textbox->TransformTextToPolySet( aOutlines, aLayer, 0, maxError, ERROR_INSIDE );
textbox->TransformTextToPolySet( aOutlines, 0, maxError, ERROR_INSIDE );
break;
}

View File

@ -167,8 +167,8 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* aItem )
{
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
text->TransformTextToPolySet( *solderMask->GetFill( layer ), layer,
m_webWidth / 2, m_maxError, ERROR_OUTSIDE );
text->TransformTextToPolySet( *solderMask->GetFill( layer ), m_webWidth / 2,
m_maxError, ERROR_OUTSIDE );
m_itemTree->Insert( aItem, layer, m_largestClearance );
}
@ -182,8 +182,8 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* aItem )
{
const FP_TEXT* text = static_cast<const FP_TEXT*>( aItem );
text->TransformTextToPolySet( *solderMask->GetFill( layer ), layer,
m_webWidth / 2, m_maxError, ERROR_OUTSIDE );
text->TransformTextToPolySet( *solderMask->GetFill( layer ), m_webWidth / 2,
m_maxError, ERROR_OUTSIDE );
m_itemTree->Insert( aItem, layer, m_largestClearance );
}

View File

@ -2079,13 +2079,13 @@ double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLEC
{
const FP_TEXT* text = static_cast<const FP_TEXT*>( aItem );
text->TransformTextToPolySet( poly, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE );
text->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE );
}
else if( aItem->Type() == PCB_FP_TEXTBOX_T )
{
const FP_TEXTBOX* tb = static_cast<const FP_TEXTBOX*>( aItem );
tb->TransformTextToPolySet( poly, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE );
tb->TransformTextToPolySet( poly, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE );
}
else if( aItem->Type() == PCB_SHAPE_T )
{
@ -2881,7 +2881,7 @@ void FOOTPRINT::TransformFPShapesToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_I
}
for( const FP_TEXT* text : texts )
text->TransformTextToPolySet( aBuffer, aLayer, aClearance, aError, aErrorLoc );
text->TransformTextToPolySet( aBuffer, aClearance, aError, aErrorLoc );
}

View File

@ -438,29 +438,48 @@ std::shared_ptr<SHAPE> FP_TEXT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING
{
if( IsKnockout() )
{
SHAPE_POLY_SET knockouts;
SHAPE_POLY_SET poly;
TransformTextToPolySet( knockouts, aLayer, 0, GetBoard()->GetDesignSettings().m_MaxError,
ERROR_INSIDE );
TransformTextToPolySet( poly, 0, GetBoard()->GetDesignSettings().m_MaxError, ERROR_INSIDE );
SHAPE_POLY_SET finalPoly;
int strokeWidth = GetEffectiveTextPenWidth();
VECTOR2I fontSize = GetTextSize();
int margin = strokeWidth * 1.5 + GetKnockoutTextMargin( fontSize, strokeWidth );
TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
return std::make_shared<SHAPE_POLY_SET>( finalPoly );
return std::make_shared<SHAPE_POLY_SET>( poly );
}
return GetEffectiveTextShape();
}
void FP_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc ) const
void FP_TEXT::buildBoundingHull( SHAPE_POLY_SET* aBuffer, const SHAPE_POLY_SET& aRenderedText,
int aClearance ) const
{
SHAPE_POLY_SET poly( aRenderedText );
poly.Rotate( -GetDrawRotation(), GetDrawPos() );
BOX2I rect = poly.BBox( aClearance );
VECTOR2I corners[4];
corners[0].x = rect.GetOrigin().x;
corners[0].y = rect.GetOrigin().y;
corners[1].y = corners[0].y;
corners[1].x = rect.GetRight();
corners[2].x = corners[1].x;
corners[2].y = rect.GetBottom();
corners[3].y = corners[2].y;
corners[3].x = corners[0].x;
aBuffer->NewOutline();
for( VECTOR2I& corner : corners )
{
RotatePoint( corner, GetDrawPos(), GetDrawRotation() );
aBuffer->Append( corner.x, corner.y );
}
}
void FP_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
KIFONT::FONT* font = getDrawFont();
@ -469,22 +488,21 @@ void FP_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLay
// The polygonal shape of a text can have many basic shapes, so combining these shapes can
// be very useful to create a final shape with a lot less vertices to speedup calculations.
// Simplify shapes is not usually always efficient, but in this case it is.
SHAPE_POLY_SET buffer;
SHAPE_POLY_SET textShape;
CALLBACK_GAL callback_gal( empty_opts,
// Stroke callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
{
TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth + ( 2 * aClearance ), aError,
ERROR_INSIDE );
TransformOvalToPolygon( textShape, aPt1, aPt2, penWidth, aError, aErrorLoc );
},
// Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
{
buffer.NewOutline();
textShape.NewOutline();
for( const VECTOR2I& point : { aPt1, aPt2, aPt3 } )
buffer.Append( point.x, point.y );
textShape.Append( point.x, point.y );
} );
TEXT_ATTRIBUTES attrs = GetAttributes();
@ -492,22 +510,22 @@ void FP_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLay
font->Draw( &callback_gal, GetShownText( true ), GetTextPos(), attrs );
buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
textShape.Simplify( SHAPE_POLY_SET::PM_FAST );
if( IsKnockout() )
{
TEXT_ATTRIBUTES attrs = GetAttributes();
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5
+ GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
int margin = GetKnockoutTextMargin( attrs.m_Size, penWidth );
TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( buffer, SHAPE_POLY_SET::PM_FAST );
buildBoundingHull( &finalPoly, textShape, margin + aClearance );
finalPoly.BooleanSubtract( textShape, SHAPE_POLY_SET::PM_FAST );
aBuffer.Append( finalPoly );
}
else
{
aBuffer.Append( buffer );
aBuffer.Append( textShape );
}
}
@ -515,10 +533,11 @@ void FP_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLay
void FP_TEXT::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth ) const
{
SHAPE_POLY_SET buffer;
SHAPE_POLY_SET poly;
EDA_TEXT::TransformBoundingBoxToPolygon( &buffer, aClearance );
aBuffer.Append( buffer );
TransformTextToPolySet( poly, 0, GetBoard()->GetDesignSettings().m_MaxError, ERROR_INSIDE );
buildBoundingHull( &aBuffer, poly, aClearance );
}

View File

@ -159,8 +159,8 @@ public:
int aError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth ) const override;
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc ) const;
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const;
// @copydoc BOARD_ITEM::GetEffectiveShape
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
@ -189,6 +189,15 @@ public:
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
/**
* Build a nominally rectangular bounding box for the rendered text. (It's not a BOX2I
* because it will be a diamond shape for non-cardinally rotated text.)
*/
void buildBoundingHull( SHAPE_POLY_SET* aBuffer, const SHAPE_POLY_SET& aRenderedText,
int aClearance ) const;
private:
TEXT_TYPE m_Type; ///< 0=ref, 1=val, etc.

View File

@ -451,8 +451,8 @@ std::shared_ptr<SHAPE> FP_TEXTBOX::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASH
}
void FP_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
int aClearance, int aError, ERROR_LOC aErrorLoc ) const
void FP_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
KIFONT::FONT* font = getDrawFont();
@ -469,8 +469,7 @@ void FP_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID a
// Stroke callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
{
TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth + ( 2 * aClearance ), aError,
ERROR_INSIDE );
TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth, aError, aErrorLoc );
},
// Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
@ -481,10 +480,7 @@ void FP_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID a
buffer.Append( point.x, point.y );
} );
TEXT_ATTRIBUTES attrs = GetAttributes();
attrs.m_Angle = GetDrawRotation();
font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), attrs );
font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), GetAttributes() );
buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
aBuffer.Append( buffer );

View File

@ -107,8 +107,8 @@ public:
int aError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth = false ) const override;
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc ) const;
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const;
// @copydoc BOARD_ITEM::GetEffectiveShape
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,

View File

@ -1992,29 +1992,8 @@ void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
if( aText->IsKnockout() )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
SHAPE_POLY_SET knockouts;
CALLBACK_GAL callback_gal( empty_opts,
// Polygon callback
[&]( const SHAPE_LINE_CHAIN& aPoly )
{
knockouts.AddOutline( aPoly );
} );
attrs.m_StrokeWidth = getLineThickness( aText->GetEffectiveTextPenWidth() );
callback_gal.SetIsFill( font->IsOutline() );
callback_gal.SetIsStroke( font->IsStroke() );
callback_gal.SetLineWidth( attrs.m_StrokeWidth );
font->Draw( &callback_gal, resolvedText, aText->GetDrawPos(), attrs );
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5
+ GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
aText->TransformTextToPolySet( finalPoly, 0, m_maxError, ERROR_INSIDE );
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
m_gal->SetIsStroke( false );
@ -2179,29 +2158,8 @@ void PCB_PAINTER::draw( const FP_TEXT* aText, int aLayer )
if( aText->IsKnockout() )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
SHAPE_POLY_SET knockouts;
CALLBACK_GAL callback_gal( empty_opts,
// Polygon callback
[&]( const SHAPE_LINE_CHAIN& aPoly )
{
knockouts.AddOutline( aPoly );
} );
attrs.m_StrokeWidth = getLineThickness( aText->GetEffectiveTextPenWidth() );
callback_gal.SetIsFill( font->IsOutline() );
callback_gal.SetIsStroke( font->IsStroke() );
callback_gal.SetLineWidth( attrs.m_StrokeWidth );
font->Draw( &callback_gal, resolvedText, aText->GetDrawPos(), attrs );
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5
+ GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
aText->TransformTextToPolySet( finalPoly, 0, m_maxError, ERROR_INSIDE );
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
m_gal->SetIsStroke( false );

View File

@ -159,18 +159,12 @@ const BOX2I PCB_TEXT::GetBoundingBox() const
bool PCB_TEXT::TextHitTest( const VECTOR2I& aPoint, int aAccuracy ) const
{
int accuracy = aAccuracy;
if( IsKnockout() )
{
SHAPE_POLY_SET poly;
accuracy += GetKnockoutTextMargin( GetTextSize(), GetTextThickness() );
TransformBoundingBoxToPolygon( &poly, getKnockoutMargin());
return poly.Collide( aPoint, aAccuracy );
}
else
{
return EDA_TEXT::TextHitTest( aPoint, aAccuracy );
}
return EDA_TEXT::TextHitTest( aPoint, accuracy );
}
@ -272,29 +266,48 @@ std::shared_ptr<SHAPE> PCB_TEXT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHIN
{
if( IsKnockout() )
{
SHAPE_POLY_SET knockouts;
SHAPE_POLY_SET poly;
TransformTextToPolySet( knockouts, aLayer, 0, GetBoard()->GetDesignSettings().m_MaxError,
ERROR_INSIDE );
TransformTextToPolySet( poly, 0, GetBoard()->GetDesignSettings().m_MaxError, ERROR_INSIDE );
SHAPE_POLY_SET finalPoly;
int strokeWidth = GetEffectiveTextPenWidth();
VECTOR2I fontSize = GetTextSize();
int margin = strokeWidth * 1.5 + GetKnockoutTextMargin( fontSize, strokeWidth );
TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
return std::make_shared<SHAPE_POLY_SET>( finalPoly );
return std::make_shared<SHAPE_POLY_SET>( poly );
}
return GetEffectiveTextShape();
}
void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
int aClearance, int aError, ERROR_LOC aErrorLoc ) const
void PCB_TEXT::buildBoundingHull( SHAPE_POLY_SET* aBuffer, const SHAPE_POLY_SET& aRenderedText,
int aClearance ) const
{
SHAPE_POLY_SET poly( aRenderedText );
poly.Rotate( -GetDrawRotation(), GetDrawPos() );
BOX2I rect = poly.BBox( aClearance );
VECTOR2I corners[4];
corners[0].x = rect.GetOrigin().x;
corners[0].y = rect.GetOrigin().y;
corners[1].y = corners[0].y;
corners[1].x = rect.GetRight();
corners[2].x = corners[1].x;
corners[2].y = rect.GetBottom();
corners[3].y = corners[2].y;
corners[3].x = corners[0].x;
aBuffer->NewOutline();
for( VECTOR2I& corner : corners )
{
RotatePoint( corner, GetDrawPos(), GetDrawRotation() );
aBuffer->Append( corner.x, corner.y );
}
}
void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
KIFONT::FONT* font = getDrawFont();
@ -303,43 +316,45 @@ void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLa
// The polygonal shape of a text can have many basic shapes, so combining these shapes can
// be very useful to create a final shape with a lot less vertices to speedup calculations.
// Simplify shapes is not usually always efficient, but in this case it is.
SHAPE_POLY_SET buffer;
SHAPE_POLY_SET textShape;
CALLBACK_GAL callback_gal( empty_opts,
// Stroke callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
{
TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth + ( 2 * aClearance ),
aError, ERROR_INSIDE );
TransformOvalToPolygon( textShape, aPt1, aPt2, penWidth, aError, aErrorLoc );
},
// Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
{
buffer.NewOutline();
textShape.NewOutline();
for( const VECTOR2I& point : { aPt1, aPt2, aPt3 } )
buffer.Append( point.x, point.y );
textShape.Append( point.x, point.y );
} );
font->Draw( &callback_gal, GetShownText( true ), GetTextPos(), GetAttributes() );
TEXT_ATTRIBUTES attrs = GetAttributes();
attrs.m_Angle = GetDrawRotation();
buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
font->Draw( &callback_gal, GetShownText( true ), GetTextPos(), attrs );
textShape.Simplify( SHAPE_POLY_SET::PM_FAST );
if( IsKnockout() )
{
TEXT_ATTRIBUTES attrs = GetAttributes();
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5
+ GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
int margin = GetKnockoutTextMargin( attrs.m_Size, penWidth );
TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( buffer, SHAPE_POLY_SET::PM_FAST );
buildBoundingHull( &finalPoly, textShape, margin + aClearance );
finalPoly.BooleanSubtract( textShape, SHAPE_POLY_SET::PM_FAST );
aBuffer.Append( finalPoly );
}
else
{
aBuffer.Append( buffer );
if( aClearance > 0 )
textShape.Inflate( aClearance, aClearance );
aBuffer.Append( textShape );
}
}
@ -348,7 +363,11 @@ void PCB_TEXT::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aL
int aClearance, int aError, ERROR_LOC aErrorLoc,
bool aIgnoreLineWidth ) const
{
EDA_TEXT::TransformBoundingBoxToPolygon( &aBuffer, aClearance );
SHAPE_POLY_SET poly;
TransformTextToPolySet( poly, 0, GetBoard()->GetDesignSettings().m_MaxError, ERROR_INSIDE );
buildBoundingHull( &aBuffer, poly, aClearance );
}

View File

@ -119,8 +119,8 @@ public:
* @aClearance = the clearance around the text
* @aError = the maximum error to allow when approximating curves
*/
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc ) const;
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const;
void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc,
@ -148,6 +148,13 @@ public:
#endif
protected:
/**
* Build a nominally rectangular bounding box for the rendered text. (It's not a BOX2I
* because it will be a diamond shape for non-cardinally rotated text.)
*/
void buildBoundingHull( SHAPE_POLY_SET* aBuffer, const SHAPE_POLY_SET& aRenderedText,
int aClearance ) const;
virtual void swapData( BOARD_ITEM* aImage ) override;
int getKnockoutMargin() const;

View File

@ -438,8 +438,8 @@ std::shared_ptr<SHAPE> PCB_TEXTBOX::GetEffectiveShape( PCB_LAYER_ID aLayer, FLAS
}
void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
int aClearance, int aError, ERROR_LOC aErrorLoc ) const
void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
KIFONT::FONT* font = getDrawFont();
@ -456,8 +456,7 @@ void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID
// Stroke callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
{
TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth + ( 2 * aClearance ), aError,
ERROR_INSIDE );
TransformOvalToPolygon( buffer, aPt1, aPt2, penWidth, aError, aErrorLoc );
},
// Triangulation callback
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
@ -470,7 +469,11 @@ void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID
font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), GetAttributes() );
buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
if( aClearance > 0 )
buffer.Inflate( aClearance, aClearance );
else
buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
aBuffer.Append( buffer );
}

View File

@ -112,8 +112,8 @@ public:
* @aClearance = the clearance around the text
* @aError = the maximum error to allow when approximating curves
*/
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc ) const;
void TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc ) const;
void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc,

View File

@ -28,6 +28,8 @@
#include <pcb_plot_params.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
#include <board.h>
#include <board_design_settings.h>
#include <board_item.h>
class PLOTTER;
@ -40,8 +42,6 @@ class FP_SHAPE;
class PCB_TARGET;
class FP_TEXT;
class ZONE;
class BOARD;
class BOARD_ITEM;
class REPORTER;
class wxFileName;
@ -61,6 +61,7 @@ public:
{
m_plotter = aPlotter;
m_board = aBoard;
m_maxError = aBoard->GetDesignSettings().m_MaxError;
}
/**
@ -80,7 +81,6 @@ public:
void SetLayerSet( LSET aLayerMask ) { m_layerMask = aLayerMask; }
void PlotFootprintGraphicItems( const FOOTPRINT* aFootprint );
void PlotFootprintShape( const FP_SHAPE* aShape );
void PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4D& aColor );
/*
* Reference, Value, and other fields are plotted only if the corresponding option is enabled.
@ -92,7 +92,8 @@ public:
void PlotPcbTarget( const PCB_TARGET* aMire );
void PlotFilledAreas( const ZONE* aZone, PCB_LAYER_ID aLayer,
const SHAPE_POLY_SET& aPolysList );
void PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer, bool aIsKnockout );
void PlotPcbText( const EDA_TEXT* aText, const BOARD_ITEM* aItem, PCB_LAYER_ID aLayer,
bool aIsKnockout );
void PlotPcbShape( const PCB_SHAPE* aShape );
/**
@ -139,6 +140,7 @@ private:
PLOTTER* m_plotter;
BOARD* m_board;
int m_maxError; // For use when approximating shapes as polygons
LSET m_layerMask;
};

View File

@ -854,10 +854,10 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
return;
// add shapes with their exact mask layer size in initialPolys
aText.TransformTextToPolySet( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
aText.TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas
aText.TransformTextToPolySet( areas, layer, inflate, maxError, ERROR_OUTSIDE );
aText.TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
};
// Generate polygons with arcs inside the shape or exact shape to minimize shape changes
@ -939,10 +939,10 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
// add shapes with their exact mask layer size in initialPolys
text->TransformTextToPolySet( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
text->TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas
text->TransformTextToPolySet( areas, layer, inflate, maxError, ERROR_OUTSIDE );
text->TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
}
else
{

View File

@ -297,13 +297,13 @@ void BRDITEMS_PLOTTER::PlotPad( const PAD* aPad, const COLOR4D& aColor, OUTLINE_
void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
{
const FP_TEXT* textItem = &aFootprint->Reference();
int textLayer = textItem->GetLayer();
PCB_LAYER_ID textLayer = textItem->GetLayer();
// Reference and value are specific items, not in graphic items list
if( GetPlotReference() && m_layerMask[textLayer]
&& ( textItem->IsVisible() || GetPlotInvisibleText() ) )
{
PlotFootprintTextItem( textItem, getColor( textLayer ) );
PlotPcbText( textItem, textItem, textLayer, textItem->IsKnockout() );
}
textItem = &aFootprint->Value();
@ -312,7 +312,7 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
if( GetPlotValue() && m_layerMask[textLayer]
&& ( textItem->IsVisible() || GetPlotInvisibleText() ) )
{
PlotFootprintTextItem( textItem, getColor( textLayer ) );
PlotPcbText( textItem, textItem, textLayer, textItem->IsKnockout() );
}
for( const BOARD_ITEM* item : aFootprint->GraphicalItems() )
@ -339,7 +339,7 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
if( textItem->GetText() == wxT( "${VALUE}" ) && !GetPlotValue() )
continue;
PlotFootprintTextItem( textItem, getColor( textLayer ) );
PlotPcbText( textItem, textItem, textLayer, textItem->IsKnockout() );
}
}
@ -355,14 +355,14 @@ void BRDITEMS_PLOTTER::PlotPcbGraphicItem( const BOARD_ITEM* item )
case PCB_TEXT_T:
{
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
PlotPcbText( text, text->GetLayer(), text->IsKnockout() );
PlotPcbText( text, text, text->GetLayer(), text->IsKnockout() );
break;
}
case PCB_TEXTBOX_T:
{
const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
PlotPcbText( textbox, textbox->GetLayer(), textbox->IsKnockout() );
PlotPcbText( textbox, textbox, textbox->GetLayer(), textbox->IsKnockout() );
PlotPcbShape( textbox );
break;
}
@ -392,84 +392,6 @@ void BRDITEMS_PLOTTER::PlotBoardGraphicItems()
}
void BRDITEMS_PLOTTER::PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4D& aColor )
{
COLOR4D color = aColor;
if( aColor == COLOR4D::WHITE )
color = COLOR4D( LIGHTGRAY );
m_plotter->SetColor( color );
// calculate some text parameters :
//VECTOR2I size = aText->GetTextSize();
VECTOR2I pos = aText->GetTextPos();
int thickness = aText->GetEffectiveTextPenWidth();
KIFONT::FONT* font = aText->GetFont();
if( !font )
{
font = KIFONT::FONT::GetFont( m_plotter->RenderSettings()
? m_plotter->RenderSettings()->GetDefaultFont()
: wxString( wxEmptyString ),
aText->IsBold(), aText->IsItalic() );
}
// Non bold texts thickness is clamped at 1/6 char size by the low level draw function.
// but in Pcbnew we do not manage bold texts and thickness up to 1/4 char size
// (like bold text) and we manage the thickness.
// So we set bold flag to true
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
attrs.m_StrokeWidth = thickness;
attrs.m_Angle = aText->GetDrawRotation();
attrs.m_Bold = true;
attrs.m_Multiline = false;
GBR_METADATA gbr_metadata;
if( IsCopperLayer( aText->GetLayer() ) )
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONCONDUCTOR );
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP );
const FOOTPRINT* parent = static_cast<const FOOTPRINT*> ( aText->GetParent() );
gbr_metadata.SetCmpReference( parent->GetReference() );
m_plotter->SetCurrentLineWidth( thickness );
if( aText->IsKnockout() )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
SHAPE_POLY_SET knockouts;
CALLBACK_GAL callback_gal( empty_opts,
// Polygon callback
[&]( const SHAPE_LINE_CHAIN& aPoly )
{
knockouts.AddOutline( aPoly );
} );
callback_gal.SetIsFill( font->IsOutline() );
callback_gal.SetIsStroke( font->IsStroke() );
font->Draw( &callback_gal, aText->GetShownText( true ), aText->GetDrawPos(), attrs );
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5
+ GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
for( int ii = 0; ii < finalPoly.OutlineCount(); ++ii )
m_plotter->PlotPoly( finalPoly.Outline( ii ), FILL_T::FILLED_SHAPE, 0, &gbr_metadata );
}
else
{
m_plotter->PlotText( pos, aColor, aText->GetShownText( true ), attrs, font, &gbr_metadata );
}
}
void BRDITEMS_PLOTTER::PlotDimension( const PCB_DIMENSION_BASE* aDim )
{
if( !m_layerMask[aDim->GetLayer()] )
@ -486,7 +408,7 @@ void BRDITEMS_PLOTTER::PlotDimension( const PCB_DIMENSION_BASE* aDim )
// the white items are not seen on a white paper or screen
m_plotter->SetColor( color != WHITE ? color : LIGHTGRAY);
PlotPcbText( aDim, aDim->GetLayer(), false );
PlotPcbText( aDim, aDim, aDim->GetLayer(), false );
for( const std::shared_ptr<SHAPE>& shape : aDim->GetShapes() )
{
@ -604,7 +526,7 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItems( const FOOTPRINT* aFootprint )
if( m_layerMask[ textbox->GetLayer() ] )
{
PlotPcbText( textbox, textbox->GetLayer(), textbox->IsKnockout() );
PlotPcbText( textbox, textbox, textbox->GetLayer(), textbox->IsKnockout() );
PlotFootprintShape( textbox );
}
@ -826,7 +748,8 @@ void BRDITEMS_PLOTTER::PlotFootprintShape( const FP_SHAPE* aShape )
#include <font/stroke_font.h>
void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer, bool aIsKnockout )
void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, const BOARD_ITEM* aItem,
PCB_LAYER_ID aLayer, bool aIsKnockout )
{
KIFONT::FONT* font = aText->GetFont();
@ -869,26 +792,19 @@ void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer,
if( aIsKnockout )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
SHAPE_POLY_SET knockouts;
CALLBACK_GAL callback_gal( empty_opts,
// Polygon callback
[&]( const SHAPE_LINE_CHAIN& aPoly )
{
knockouts.AddOutline( aPoly );
} );
callback_gal.SetIsFill( font->IsOutline() );
callback_gal.SetIsStroke( font->IsStroke() );
font->Draw( &callback_gal, shownText, aText->GetDrawPos(), attrs );
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5
+ GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
if( aItem->Type() == PCB_FP_TEXT_T )
{
static_cast<const FP_TEXT*>( aItem )->TransformTextToPolySet( finalPoly, 0, m_maxError,
ERROR_INSIDE );
}
else if( aItem->Type() == PCB_TEXT_T )
{
static_cast<const PCB_TEXT*>( aItem )->TransformTextToPolySet( finalPoly, 0, m_maxError,
ERROR_INSIDE );
}
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
for( int ii = 0; ii < finalPoly.OutlineCount(); ++ii )

View File

@ -1281,65 +1281,40 @@ bool PNS_KICAD_IFACE_BASE::syncTextItem( PNS::NODE* aWorld, EDA_TEXT* aText, PCB
if( !IsCopperLayer( aLayer ) )
return false;
BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( aText );
PCB_LAYER_ID layer = boardItem->GetLayer();
int maxError = m_board->GetDesignSettings().m_MaxError;
std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
solid->SetLayer( aLayer );
solid->SetNet( -1 );
solid->SetParent( dynamic_cast<BOARD_ITEM*>( aText ) );
solid->SetShape( shape ); // takes ownership
solid->SetParent( boardItem );
PCB_TEXT* pcb_text = dynamic_cast<PCB_TEXT*>( aText );
SHAPE_POLY_SET cornerBuffer;
if( pcb_text && pcb_text->IsKnockout() )
if( boardItem->Type() == PCB_FP_TEXT_T )
{
TEXT_ATTRIBUTES attrs = pcb_text->GetAttributes();
SHAPE_POLY_SET buffer;
int margin = attrs.m_StrokeWidth * 1.5
+ GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
pcb_text->TransformBoundingBoxToPolygon( &buffer, margin );
// buffer should contain a single rectangular polygon
if( !buffer.OutlineCount() )
return false;
SHAPE_SIMPLE* rectShape = new SHAPE_SIMPLE;
for( int ii = 0; ii < buffer.Outline(0).PointCount(); ii++ )
{
VECTOR2I point = buffer.Outline(0).CPoint(ii);
rectShape->Append( point );
}
solid->SetShape( rectShape ); // takes ownership
static_cast<FP_TEXT*>( boardItem )->TransformShapeToPolygon( cornerBuffer, layer, 0,
maxError, ERROR_OUTSIDE, false );
}
else
else if( boardItem->Type() == PCB_TEXT_T )
{
solid->SetShape( aText->GetEffectiveTextShape()->Clone() );
static_cast<PCB_TEXT*>( boardItem )->TransformShapeToPolygon( cornerBuffer, layer, 0,
maxError, ERROR_OUTSIDE );
}
solid->SetRoutable( false );
if( !cornerBuffer.OutlineCount() )
return false;
for( const VECTOR2I& pt : cornerBuffer.Outline( 0 ).CPoints() )
shape->Append( pt );
aWorld->Add( std::move( solid ) );
return true;
/* A coarser (but faster) method:
SHAPE_POLY_SET outline;
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
aText->TransformBoundingBoxToPolygon( &outline, 0 );
for( auto iter = outline.CIterate( 0 ); iter; iter++ )
shape->Append( *iter );
solid->SetShape( shape );
solid->SetLayer( aLayer );
solid->SetNet( -1 );
solid->SetParent( nullptr );
solid->SetRoutable( false );
aWorld->Add( std::move( solid ) );
return true;
*/
}

View File

@ -815,41 +815,76 @@ void ZONE_FILLER::addHoleKnockout( PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap,
bool aIgnoreLineWidth, SHAPE_POLY_SET& aHoles )
{
EDA_TEXT* text = nullptr;
switch( aItem->Type() )
{
case PCB_TEXT_T: text = static_cast<PCB_TEXT*>( aItem ); break;
case PCB_TEXTBOX_T: text = static_cast<PCB_TEXTBOX*>( aItem ); break;
case PCB_FP_TEXT_T: text = static_cast<FP_TEXT*>( aItem ); break;
case PCB_FP_TEXTBOX_T: text = static_cast<FP_TEXTBOX*>( aItem ); break;
default: break;
case PCB_FP_TEXT_T:
{
FP_TEXT* text = static_cast<FP_TEXT*>( aItem );
if( text->IsVisible() )
{
if( text->IsKnockout() )
{
int antiGap = -m_maxError * 2; // Don't leave gaps around knockout text
text->TransformShapeToPolygon( aHoles, aLayer, antiGap, m_maxError, ERROR_OUTSIDE,
aIgnoreLineWidth );
}
else
{
text->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE,
aIgnoreLineWidth );
}
}
break;
}
if( text )
aGap += GetKnockoutTextMargin( text->GetTextSize(), text->GetTextThickness() );
switch( aItem->Type() )
{
case PCB_SHAPE_T:
case PCB_TEXT_T:
case PCB_TEXTBOX_T:
{
PCB_TEXT* text = static_cast<PCB_TEXT*>( aItem );
if( text->IsVisible() )
{
if( text->IsKnockout() )
{
int antiGap = -m_maxError * 2; // Don't leave gaps around knockout text
text->TransformShapeToPolygon( aHoles, aLayer, antiGap, m_maxError, ERROR_OUTSIDE );
}
else
{
text->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE );
}
}
break;
}
case PCB_FP_TEXTBOX_T:
case PCB_FP_SHAPE_T:
{
FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( aItem );
if( textbox->IsVisible() )
textbox->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE );
break;
}
case PCB_TEXTBOX_T:
{
PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( aItem );
if( textbox->IsVisible() )
textbox->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE );
break;
}
case PCB_SHAPE_T:
case PCB_TARGET_T:
aItem->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE,
aIgnoreLineWidth );
break;
case PCB_FP_TEXT_T:
if( text->IsVisible() )
{
aItem->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE,
aIgnoreLineWidth );
}
break;
default:
break;
}