Give up on trying to calculate text bounding boxes.
It results in too many hacks strewn through the code. Just draw the text and measure it. Fixes https://gitlab.com/kicad/code/kicad/-/issues/14803
This commit is contained in:
parent
6e127829f8
commit
768fbf5af2
|
@ -525,100 +525,35 @@ BOX2I EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
|||
return m_bounding_box_cache;
|
||||
}
|
||||
|
||||
// We've tried a gazillion different ways of calculating bounding boxes for text; all of them
|
||||
// fail in one case or another and we end up with compensation hacks strewed throughout the
|
||||
// code. So I'm pulling the plug on it; we're just going to draw the damn text and see how
|
||||
// big it is.
|
||||
BOX2I bbox;
|
||||
wxArrayString strings;
|
||||
wxString text = GetShownText( true );
|
||||
int thickness = GetEffectiveTextPenWidth();
|
||||
|
||||
if( IsMultilineAllowed() )
|
||||
{
|
||||
wxStringSplit( text, strings, '\n' );
|
||||
|
||||
if( strings.GetCount() ) // GetCount() == 0 for void strings with multilines allowed
|
||||
{
|
||||
if( aLine >= 0 && ( aLine < static_cast<int>( strings.GetCount() ) ) )
|
||||
text = strings.Item( aLine );
|
||||
else
|
||||
text = strings.Item( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the H and V size
|
||||
BOX2I strokeBBox;
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
KIFONT::FONT* font = getDrawFont();
|
||||
VECTOR2D fontSize( GetTextSize() );
|
||||
bool bold = IsBold();
|
||||
bool italic = IsItalic();
|
||||
VECTOR2I extents = font->StringBoundaryLimits( text, fontSize, thickness, bold, italic );
|
||||
int overbarOffset = 0;
|
||||
|
||||
// Creates bounding box (rectangle) for horizontal, left and top justified text. The
|
||||
// bounding box will be moved later according to the actual text options
|
||||
VECTOR2I textsize = VECTOR2I( extents.x, extents.y );
|
||||
VECTOR2I pos = drawPos;
|
||||
|
||||
if( IsMultilineAllowed() && aLine > 0 && aLine < (int) strings.GetCount() )
|
||||
pos.y -= KiROUND( aLine * font->GetInterline( fontSize.y ) );
|
||||
|
||||
if( text.Contains( wxT( "~{" ) ) )
|
||||
overbarOffset = extents.y / 14;
|
||||
|
||||
if( aInvertY )
|
||||
pos.y = -pos.y;
|
||||
|
||||
bbox.SetOrigin( pos );
|
||||
|
||||
// for multiline texts and aLine < 0, merge all rectangles (aLine == -1 signals all lines)
|
||||
if( IsMultilineAllowed() && aLine < 0 && strings.GetCount() )
|
||||
CALLBACK_GAL callback_gal(
|
||||
empty_opts,
|
||||
// Stroke callback
|
||||
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
|
||||
{
|
||||
for( unsigned ii = 1; ii < strings.GetCount(); ii++ )
|
||||
strokeBBox.Merge( aPt1 );
|
||||
strokeBBox.Merge( aPt2 );
|
||||
},
|
||||
// Outline callback
|
||||
[&]( const SHAPE_LINE_CHAIN& aPoly )
|
||||
{
|
||||
text = strings.Item( ii );
|
||||
extents = font->StringBoundaryLimits( text, fontSize, thickness, bold, italic );
|
||||
textsize.x = std::max( textsize.x, extents.x );
|
||||
}
|
||||
bbox.Merge( aPoly.BBox() );
|
||||
} );
|
||||
|
||||
// interline spacing is only *between* lines, so total height is the height of the first
|
||||
// line plus the interline distance (with interline spacing) for all subsequent lines
|
||||
textsize.y += KiROUND( ( strings.GetCount() - 1 ) * font->GetInterline( fontSize.y ) );
|
||||
}
|
||||
font->Draw( &callback_gal, GetShownText( true ), drawPos, GetAttributes() );
|
||||
|
||||
bbox.SetSize( textsize );
|
||||
|
||||
/*
|
||||
* At this point the rectangle origin is the text origin (m_Pos). This is correct only for
|
||||
* left and top justified, non-mirrored, non-overbarred texts. Recalculate for all others.
|
||||
*/
|
||||
int italicOffset = IsItalic() ? KiROUND( fontSize.y * ITALIC_TILT ) : 0;
|
||||
|
||||
switch( GetHorizJustify() )
|
||||
if( strokeBBox.GetSizeMax() > 0 )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT:
|
||||
if( IsMirrored() )
|
||||
bbox.SetX( bbox.GetX() - ( bbox.GetWidth() - italicOffset ) );
|
||||
break;
|
||||
|
||||
case GR_TEXT_H_ALIGN_CENTER:
|
||||
bbox.SetX( bbox.GetX() - ( bbox.GetWidth() - italicOffset ) / 2 );
|
||||
break;
|
||||
|
||||
case GR_TEXT_H_ALIGN_RIGHT:
|
||||
if( !IsMirrored() )
|
||||
bbox.SetX( bbox.GetX() - ( bbox.GetWidth() - italicOffset ) );
|
||||
break;
|
||||
}
|
||||
|
||||
switch( GetVertJustify() )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP:
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_CENTER:
|
||||
bbox.SetY( bbox.GetY() - ( bbox.GetHeight() + overbarOffset ) / 2 );
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_BOTTOM:
|
||||
bbox.SetY( bbox.GetY() - ( bbox.GetHeight() + overbarOffset ) );
|
||||
break;
|
||||
strokeBBox.Inflate( GetTextThickness() / 2 );
|
||||
bbox.Merge( strokeBBox );
|
||||
}
|
||||
|
||||
bbox.Normalize(); // Make h and v sizes always >= 0
|
||||
|
@ -954,11 +889,6 @@ void EDA_TEXT::TransformBoundingBoxToPolygon( SHAPE_POLY_SET* aBuffer, int aClea
|
|||
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;
|
||||
|
|
|
@ -97,13 +97,10 @@ inline void InferBold( TEXT_ATTRIBUTES* aAttrs )
|
|||
|
||||
/**
|
||||
* Returns the margin for knocking out text.
|
||||
*
|
||||
* Note that this is not a perfect calculation as fonts (especially outline fonts) vary greatly
|
||||
* in how well ascender and descender heights are enforced.
|
||||
*/
|
||||
inline int GetKnockoutTextMargin( const VECTOR2I& aSize, int aThickness )
|
||||
{
|
||||
return std::max( KiROUND( aThickness / 2 ), KiROUND( aSize.y / 7.0 ) );
|
||||
return std::max( KiROUND( aThickness / 2 ), KiROUND( aSize.y / 9.0 ) );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1991,8 +1991,7 @@ void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
|
|||
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 );
|
||||
int margin = GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
|
||||
|
||||
aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
|
||||
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
|
||||
|
|
|
@ -261,10 +261,7 @@ void PCB_TEXT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_IT
|
|||
|
||||
int PCB_TEXT::getKnockoutMargin() const
|
||||
{
|
||||
VECTOR2I textSize( GetTextWidth(), GetTextHeight() );
|
||||
int thickness = GetTextThickness();
|
||||
|
||||
return thickness * 1.5 + GetKnockoutTextMargin( textSize, thickness );
|
||||
return GetKnockoutTextMargin( VECTOR2I( GetTextWidth(), GetTextHeight() ), GetTextThickness() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -449,7 +446,7 @@ std::shared_ptr<SHAPE> PCB_TEXT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHIN
|
|||
SHAPE_POLY_SET finalPoly;
|
||||
int strokeWidth = GetEffectiveTextPenWidth();
|
||||
VECTOR2I fontSize = GetTextSize();
|
||||
int margin = strokeWidth * 1.5 + GetKnockoutTextMargin( fontSize, strokeWidth );
|
||||
int margin = GetKnockoutTextMargin( fontSize, strokeWidth );
|
||||
|
||||
TransformBoundingBoxToPolygon( &finalPoly, margin );
|
||||
finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
|
||||
|
|
|
@ -500,6 +500,7 @@ void PCB_PLUGIN::formatRenderCache( const EDA_TEXT* aText, int aNestLevel ) cons
|
|||
m_out->Print( aNestLevel + 1, ")\n" );
|
||||
} );
|
||||
|
||||
callback_gal.SetLineWidth( aText->GetTextThickness() );
|
||||
callback_gal.DrawGlyphs( *cache );
|
||||
|
||||
m_out->Print( aNestLevel, ")\n" );
|
||||
|
|
|
@ -1289,11 +1289,11 @@ bool PNS_KICAD_IFACE_BASE::syncTextItem( PNS::NODE* aWorld, PCB_TEXT* aText, PCB
|
|||
solid->SetRoutable( false );
|
||||
|
||||
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
||||
int margin = KiROUND( attrs.m_StrokeWidth / 2 );
|
||||
int margin = 0;
|
||||
SHAPE_POLY_SET cornerBuffer;
|
||||
|
||||
if( aText->IsKnockout() )
|
||||
margin += attrs.m_StrokeWidth + GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
|
||||
margin = GetKnockoutTextMargin( attrs.m_Size, attrs.m_StrokeWidth );
|
||||
|
||||
aText->TransformBoundingBoxToPolygon( &cornerBuffer, margin );
|
||||
|
||||
|
|
|
@ -822,9 +822,6 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap,
|
|||
default: break;
|
||||
}
|
||||
|
||||
if( text )
|
||||
aGap += GetKnockoutTextMargin( text->GetTextSize(), text->GetTextThickness() );
|
||||
|
||||
switch( aItem->Type() )
|
||||
{
|
||||
case PCB_SHAPE_T:
|
||||
|
|
Loading…
Reference in New Issue