diff --git a/common/eda_text.cpp b/common/eda_text.cpp index cb065d3ef0..d43ef79657 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -525,100 +525,35 @@ BOX2I EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const return m_bounding_box_cache; } - BOX2I bbox; - wxArrayString strings; - wxString text = GetShownText( true ); - int thickness = GetEffectiveTextPenWidth(); + // 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; + BOX2I strokeBBox; + KIGFX::GAL_DISPLAY_OPTIONS empty_opts; + KIFONT::FONT* font = getDrawFont(); - if( IsMultilineAllowed() ) + CALLBACK_GAL callback_gal( + empty_opts, + // Stroke callback + [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 ) + { + strokeBBox.Merge( aPt1 ); + strokeBBox.Merge( aPt2 ); + }, + // Outline callback + [&]( const SHAPE_LINE_CHAIN& aPoly ) + { + bbox.Merge( aPoly.BBox() ); + } ); + + font->Draw( &callback_gal, GetShownText( true ), drawPos, GetAttributes() ); + + if( strokeBBox.GetSizeMax() > 0 ) { - wxStringSplit( text, strings, '\n' ); - - if( strings.GetCount() ) // GetCount() == 0 for void strings with multilines allowed - { - if( aLine >= 0 && ( aLine < static_cast( strings.GetCount() ) ) ) - text = strings.Item( aLine ); - else - text = strings.Item( 0 ); - } - } - - // calculate the H and V size - 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() ) - { - for( unsigned ii = 1; ii < strings.GetCount(); ii++ ) - { - text = strings.Item( ii ); - extents = font->StringBoundaryLimits( text, fontSize, thickness, bold, italic ); - textsize.x = std::max( textsize.x, extents.x ); - } - - // 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 ) ); - } - - 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() ) - { - 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; diff --git a/include/gr_text.h b/include/gr_text.h index 843a035673..ace03b6490 100644 --- a/include/gr_text.h +++ b/include/gr_text.h @@ -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 ) ); } diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index bf387121ba..0e613bd7a3 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -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 ); diff --git a/pcbnew/pcb_text.cpp b/pcbnew/pcb_text.cpp index 9d30efa320..4801ca6be0 100644 --- a/pcbnew/pcb_text.cpp +++ b/pcbnew/pcb_text.cpp @@ -261,10 +261,7 @@ void PCB_TEXT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector 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 ); diff --git a/pcbnew/plugins/kicad/pcb_plugin.cpp b/pcbnew/plugins/kicad/pcb_plugin.cpp index 8726b1dd35..e1d6aa5210 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.cpp +++ b/pcbnew/plugins/kicad/pcb_plugin.cpp @@ -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" ); diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index c20878dd74..527f93860e 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -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 ); diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index b6f275a76b..21ed248aa4 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -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: