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).
This commit is contained in:
Jeff Young 2023-05-28 17:20:11 +01:00
parent dacf0b2b96
commit c71cf21e2f
18 changed files with 138 additions and 272 deletions

View File

@ -74,29 +74,11 @@ void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContaine
if( aOwner && aOwner->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 );
SHAPE_POLY_SET finalPoly;
int margin = attrs.m_StrokeWidth * 1.5 +
GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
const PCB_TEXT* pcbText = static_cast<const PCB_TEXT*>( aOwner );
aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
pcbText->TransformTextToPolySet( finalPoly, 0, m_board->GetDesignSettings().m_MaxError,
ERROR_INSIDE );
// Do not call finalPoly.Fracture() here: ConvertPolygonToTriangles() call it
// if needed, and Fracture() called twice can create bad results and is useless

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

@ -982,36 +982,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();
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

@ -2382,7 +2382,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;
}
@ -2394,7 +2394,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,7 +167,7 @@ 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,
text->TransformTextToPolySet( *solderMask->GetFill( layer ),
m_webWidth / 2, m_maxError, ERROR_OUTSIDE );
m_itemTree->Insert( aItem, layer, m_largestClearance );

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 );
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_TEXTBOX_T )
{
const PCB_TEXTBOX* tb = static_cast<const PCB_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 )
{
@ -2747,7 +2747,7 @@ void FOOTPRINT::TransformFPShapesToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_I
}
for( const PCB_TEXT* text : texts )
text->TransformTextToPolySet( aBuffer, aLayer, aClearance, aError, aErrorLoc );
text->TransformTextToPolySet( aBuffer, aClearance, aError, aErrorLoc );
}

View File

@ -1973,28 +1973,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 = 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

@ -294,18 +294,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 );
}
@ -432,29 +426,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 = 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();
@ -466,41 +479,42 @@ 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(), attrs );
buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
textShape.Simplify( SHAPE_POLY_SET::PM_FAST );
if( IsKnockout() )
{
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 );
}
}
@ -509,7 +523,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

@ -139,8 +139,8 @@ public:
* @param aClearance the clearance around the text
* @param 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,
@ -178,6 +178,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

@ -447,8 +447,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();
@ -465,8 +465,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 )
@ -479,7 +478,11 @@ void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID
font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), GetAttributes() );
if( aClearance > 0 )
buffer.Inflate( aClearance, aClearance );
else
buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
aBuffer.Append( buffer );
}

View File

@ -114,8 +114,8 @@ public:
* @param aClearance = the clearance around the text
* @param 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 EDA_TEXT;
@ -39,8 +41,6 @@ class PCB_DIMENSION_BASE;
class FOOTPRINT;
class PCB_TARGET;
class ZONE;
class BOARD;
class BOARD_ITEM;
class REPORTER;
class wxFileName;
@ -60,6 +60,7 @@ public:
{
m_plotter = aPlotter;
m_board = aBoard;
m_maxError = aBoard->GetDesignSettings().m_MaxError;
}
/**
@ -137,6 +138,7 @@ private:
PLOTTER* m_plotter;
BOARD* m_board;
int m_maxError; // For use when approximating shapes as polygons
LSET m_layerMask;
};

View File

@ -848,10 +848,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
@ -934,10 +934,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

@ -294,13 +294,13 @@ void BRDITEMS_PLOTTER::PlotPad( const PAD* aPad, const COLOR4D& aColor, OUTLINE_
void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
{
const PCB_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, textLayer, textItem->IsKnockout() );
}
textItem = &aFootprint->Value();
@ -309,7 +309,7 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
if( GetPlotValue() && m_layerMask[textLayer]
&& ( textItem->IsVisible() || GetPlotInvisibleText() ) )
{
PlotFootprintTextItem( textItem, getColor( textLayer ) );
PlotPcbText( textItem, textLayer, textItem->IsKnockout() );
}
for( const BOARD_ITEM* item : aFootprint->GraphicalItems() )
@ -336,7 +336,7 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
if( textItem->GetText() == wxT( "${VALUE}" ) && !GetPlotValue() )
continue;
PlotFootprintTextItem( textItem, getColor( textLayer ) );
PlotPcbText( textItem, textLayer, textItem->IsKnockout() );
}
}
@ -389,84 +389,6 @@ void BRDITEMS_PLOTTER::PlotBoardGraphicItems()
}
void BRDITEMS_PLOTTER::PlotFootprintTextItem( const PCB_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 = aText->GetParentFootprint();
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()] )
@ -623,7 +545,7 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItems( const FOOTPRINT* aFootprint )
}
case PCB_TEXT_T:
// Plotted in PlotFootprintTextItem()
// Plotted in PlotFootprintTextItems()
break;
default:
@ -673,26 +595,10 @@ 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 );
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aText );
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 );
text->TransformTextToPolySet( finalPoly, 0, m_maxError, ERROR_INSIDE );
finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
for( int ii = 0; ii < finalPoly.OutlineCount(); ++ii )

View File

@ -1288,14 +1288,10 @@ bool PNS_KICAD_IFACE_BASE::syncTextItem( PNS::NODE* aWorld, PCB_TEXT* aText, PCB
solid->SetShape( shape ); // takes ownership
solid->SetRoutable( false );
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
int margin = 0;
SHAPE_POLY_SET cornerBuffer;
if( aText->IsKnockout() )
margin = GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
aText->TransformBoundingBoxToPolygon( &cornerBuffer, margin );
aText->TransformShapeToPolygon( cornerBuffer, aText->GetLayer(), 0,
m_board->GetDesignSettings().m_MaxError, ERROR_OUTSIDE );
if( !cornerBuffer.OutlineCount() )
return false;

View File

@ -786,7 +786,7 @@ SHAPE_POLY_SET CONVERT_TOOL::makePolysFromClosedGraphics( const std::deque<EDA_I
case PCB_TEXT_T:
{
PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
text->TransformTextToPolySet( poly, UNDEFINED_LAYER, 0, bds.m_MaxError, ERROR_INSIDE );
text->TransformTextToPolySet( poly, 0, bds.m_MaxError, ERROR_INSIDE );
text->SetFlags( SKIP_STRUCT );
break;
}

View File

@ -813,27 +813,42 @@ 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;
default: break;
case PCB_TEXT_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;
}
switch( aItem->Type() )
{
case PCB_SHAPE_T:
case PCB_TEXT_T:
case PCB_TEXTBOX_T:
case PCB_TARGET_T:
if( !text || text->IsVisible() )
{
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;
default: