diff --git a/common/drawing_sheet/ds_painter.cpp b/common/drawing_sheet/ds_painter.cpp index baea6e5a62..88cc97dfda 100644 --- a/common/drawing_sheet/ds_painter.cpp +++ b/common/drawing_sheet/ds_painter.cpp @@ -253,7 +253,10 @@ void KIGFX::DS_PAINTER::draw( const DS_DRAW_ITEM_POLYPOLYGONS* aItem, int aLayer void KIGFX::DS_PAINTER::draw( const DS_DRAW_ITEM_TEXT* aItem, int aLayer ) const { - KIFONT::FONT* font = aItem->GetFont(); + KIFONT::FONT* font = aItem->GetFont(); + wxString shownText( aItem->GetShownText( true ) ); + VECTOR2I text_offset = aItem->GetTextPos(); + TEXT_ATTRIBUTES attrs = aItem->GetAttributes(); if( !font ) { @@ -266,11 +269,25 @@ void KIGFX::DS_PAINTER::draw( const DS_DRAW_ITEM_TEXT* aItem, int aLayer ) const m_gal->SetStrokeColor( color ); m_gal->SetFillColor( color ); - TEXT_ATTRIBUTES attrs = aItem->GetAttributes(); attrs.m_StrokeWidth = std::max( aItem->GetEffectiveTextPenWidth(), m_renderSettings.GetDefaultPenWidth() ); - font->Draw( m_gal, aItem->GetShownText( true ), aItem->GetTextPos(), attrs ); + std::vector>* cache = nullptr; + + if( font->IsOutline() ) + cache = aItem->GetRenderCache( font, shownText, text_offset ); + + if( cache ) + { + m_gal->SetLineWidth( attrs.m_StrokeWidth ); + m_gal->DrawGlyphs( *cache ); + } + else + { + m_gal->SetIsFill( font->IsOutline() ); + m_gal->SetIsStroke( font->IsStroke() ); + font->Draw( m_gal, shownText, text_offset, attrs ); + } } diff --git a/common/eda_text.cpp b/common/eda_text.cpp index d43ef79657..5cc2e269d2 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -395,6 +395,9 @@ void EDA_TEXT::SetTextY( int aY ) void EDA_TEXT::Offset( const VECTOR2I& aOffset ) { + if( aOffset.x == 0 && aOffset.y == 0 ) + return; + m_pos += aOffset; for( std::unique_ptr& glyph : m_render_cache ) @@ -463,7 +466,7 @@ std::vector>* EDA_TEXT::GetRenderCache( const KIFONT::FONT* aFont, const wxString& forResolvedText, const VECTOR2I& aOffset ) const { - if( getDrawFont()->IsOutline() ) + if( aFont->IsOutline() ) { EDA_ANGLE resolvedAngle = GetDrawRotation(); @@ -533,6 +536,8 @@ BOX2I EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const BOX2I strokeBBox; KIGFX::GAL_DISPLAY_OPTIONS empty_opts; KIFONT::FONT* font = getDrawFont(); + wxString shownText( GetShownText( true ) ); + TEXT_ATTRIBUTES attrs = GetAttributes(); CALLBACK_GAL callback_gal( empty_opts, @@ -548,7 +553,7 @@ BOX2I EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const bbox.Merge( aPoly.BBox() ); } ); - font->Draw( &callback_gal, GetShownText( true ), drawPos, GetAttributes() ); + font->Draw( &callback_gal, shownText, drawPos, attrs ); if( strokeBBox.GetSizeMax() > 0 ) { @@ -806,12 +811,23 @@ std::shared_ptr EDA_TEXT::GetEffectiveTextShape( bool aTriangula KIGFX::GAL_DISPLAY_OPTIONS empty_opts; KIFONT::FONT* font = getDrawFont(); int penWidth = GetEffectiveTextPenWidth(); + wxString shownText( GetShownText( true ) ); + VECTOR2I drawPos = GetDrawPos(); TEXT_ATTRIBUTES attrs = GetAttributes(); + std::vector>* cache = nullptr; + if( aUseTextRotation ) + { attrs.m_Angle = GetDrawRotation(); + + if( font->IsOutline() ) + cache = GetRenderCache( font, shownText, drawPos ); + } else + { attrs.m_Angle = ANGLE_0; + } if( aTriangulate ) { @@ -833,7 +849,10 @@ std::shared_ptr EDA_TEXT::GetEffectiveTextShape( bool aTriangula shape->AddShape( triShape ); } ); - font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), attrs ); + if( cache ) + callback_gal.DrawGlyphs( *cache ); + else + font->Draw( &callback_gal, shownText, drawPos, attrs ); } else { @@ -850,7 +869,10 @@ std::shared_ptr EDA_TEXT::GetEffectiveTextShape( bool aTriangula shape->AddShape( aPoly.Clone() ); } ); - font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), attrs ); + if( cache ) + callback_gal.DrawGlyphs( *cache ); + else + font->Draw( &callback_gal, shownText, drawPos, attrs ); } return shape; diff --git a/common/font/outline_font.cpp b/common/font/outline_font.cpp index cbc33ee493..6f27bc30d9 100644 --- a/common/font/outline_font.cpp +++ b/common/font/outline_font.cpp @@ -362,6 +362,9 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox, VECTOR2I cursor( 0, 0 ); + if( aGlyphs ) + aGlyphs->reserve( glyphCount ); + for( unsigned int i = 0; i < glyphCount; i++ ) { // Don't process glyphs that were already included in a previous cluster @@ -403,6 +406,8 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox, GLYPH_POINTS points = c.m_Points; SHAPE_LINE_CHAIN shape; + shape.ReservePoints( points.size() ); + for( const VECTOR2D& v : points ) { VECTOR2D pt( v + cursor ); @@ -447,13 +452,6 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox, } } - // FONT TODO we might not want to do Fracture() here; - // knockout text (eg. silkscreen labels with a background) will - // need to do that after the contours have been turned into holes - // and vice versa - if( glyph->HasHoles() ) - glyph->Fracture( SHAPE_POLY_SET::PM_FAST ); // FONT TODO verify aFastMode - aGlyphs->push_back( std::move( glyph ) ); } diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 9b3e506cfb..00b4da76b7 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -2804,15 +2805,31 @@ void OPENGL_GAL::DrawGlyphs( const std::vector>& // Optimized path for stroke fonts that pre-reserves glyph triangles. int triangleCount = 0; + if( aGlyphs.size() > 2 ) + { + thread_pool& tp = GetKiCadThreadPool(); + + tp.push_loop( aGlyphs.size(), + [&]( const int a, const int b) + { + for( int ii = a; ii < b; ++ii ) + { + auto glyph = static_cast( aGlyphs.at( ii ).get() ); + + // Only call CacheTriangulation() if it has never been done before. + // Otherwise we'll hash the triangulation to see if it has been edited, + // and all our glpyh editing ops update the triangulation anyway. + if( glyph->TriangulatedPolyCount() == 0 ) + glyph->CacheTriangulation( false ); + } + } ); + tp.wait_for_tasks(); + } + for( const std::unique_ptr& glyph : aGlyphs ) { const auto& outlineGlyph = static_cast( *glyph ); - // Only call CacheTriangulation if it has never been done before. Otherwise we'll hash - // the triangulation to see if it has been edited, and glyphs after creation are read-only. - if( outlineGlyph.TriangulatedPolyCount() == 0 ) - const_cast( outlineGlyph ).CacheTriangulation( false ); - for( unsigned int i = 0; i < outlineGlyph.TriangulatedPolyCount(); i++ ) { const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = diff --git a/eeschema/lib_text.cpp b/eeschema/lib_text.cpp index 04a00ebb53..0672ef19da 100644 --- a/eeschema/lib_text.cpp +++ b/eeschema/lib_text.cpp @@ -133,6 +133,9 @@ void LIB_TEXT::MoveTo( const VECTOR2I& newPosition ) void LIB_TEXT::NormalizeJustification( bool inverse ) { + if( GetHorizJustify() == GR_TEXT_H_ALIGN_CENTER && GetVertJustify() == GR_TEXT_V_ALIGN_CENTER ) + return; + VECTOR2I delta( 0, 0 ); BOX2I bbox = GetTextBox(); diff --git a/eeschema/tools/ee_selection_tool.cpp b/eeschema/tools/ee_selection_tool.cpp index 9fcae7f20f..bc1320a3df 100644 --- a/eeschema/tools/ee_selection_tool.cpp +++ b/eeschema/tools/ee_selection_tool.cpp @@ -1147,7 +1147,7 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const } } - text->GetEffectiveTextShape()->Collide( poss, closestDist, &dist ); + text->GetEffectiveTextShape( false )->Collide( poss, closestDist, &dist ); } else if( symbol ) { diff --git a/libs/kimath/include/geometry/shape_line_chain.h b/libs/kimath/include/geometry/shape_line_chain.h index 33c170b928..7e8cf6fc34 100644 --- a/libs/kimath/include/geometry/shape_line_chain.h +++ b/libs/kimath/include/geometry/shape_line_chain.h @@ -485,6 +485,14 @@ public: */ long long int Length() const; + /** + * Allocate a number of points all at once (for performance). + */ + void ReservePoints( size_t aSize ) + { + m_points.reserve( aSize ); + } + /** * Append a new point at the end of the line chain. * diff --git a/libs/kimath/src/bezier_curves.cpp b/libs/kimath/src/bezier_curves.cpp index e37f428b29..a52304c162 100644 --- a/libs/kimath/src/bezier_curves.cpp +++ b/libs/kimath/src/bezier_curves.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -46,8 +46,10 @@ BEZIER_POLY::BEZIER_POLY( const VECTOR2I& aStart, const VECTOR2I& aCtrl1, BEZIER_POLY::BEZIER_POLY( const std::vector& aControlPoints ) { - for( unsigned ii = 0; ii < aControlPoints.size(); ++ii ) - m_ctrlPts.emplace_back( VECTOR2I( aControlPoints[ii] ) ); + m_ctrlPts.reserve( aControlPoints.size() ); + + for( const VECTOR2I& pt : aControlPoints ) + m_ctrlPts.emplace_back( pt ); m_minSegLen = 0.0; } @@ -59,8 +61,10 @@ void BEZIER_POLY::GetPoly( std::vector& aOutput, int aMinSegLen, int a std::vector buffer; GetPoly( buffer, double( aMinSegLen ), aMaxSegCount ); - for( unsigned ii = 0; ii < buffer.size(); ++ii ) - aOutput.emplace_back( VECTOR2I( int( buffer[ii].x ), int( buffer[ii].y ) ) ); + aOutput.reserve( buffer.size() ); + + for( const VECTOR2D& pt : buffer ) + aOutput.emplace_back( VECTOR2I( (int) pt.x, (int) pt.y ) ); } @@ -70,7 +74,8 @@ void BEZIER_POLY::GetPoly( std::vector& aOutput, double aMinSegLen, in // FIXME Brute force method, use a better (recursive?) algorithm // with a max error value. // to optimize the number of segments - double dt = 1.0 / aMaxSegCount; + double dt = 1.0 / aMaxSegCount; + VECTOR2D::extended_type minSegLen_sq = aMinSegLen * aMinSegLen; aOutput.clear(); aOutput.push_back( m_ctrlPts[0] ); @@ -96,10 +101,10 @@ void BEZIER_POLY::GetPoly( std::vector& aOutput, double aMinSegLen, in // a minimal filter on the length of the segment being created: // The offset from last point: - VECTOR2D delta = vertex - aOutput.back(); - double dist = delta.EuclideanNorm(); + VECTOR2D delta = vertex - aOutput.back(); + VECTOR2D::extended_type dist_sq = delta.SquaredEuclideanNorm(); - if( dist > aMinSegLen ) + if( dist_sq > minSegLen_sq ) aOutput.push_back( vertex ); } } diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp index 8c521f3493..9c511cf0a3 100644 --- a/libs/kimath/src/geometry/shape_poly_set.cpp +++ b/libs/kimath/src/geometry/shape_poly_set.cpp @@ -2824,10 +2824,7 @@ void SHAPE_POLY_SET::CacheTriangulation( bool aPartition, bool aSimplify ) tmpSet.ClearArcs(); - if( tmpSet.HasHoles() || tmpSet.IsSelfIntersecting() ) - tmpSet.Fracture( PM_FAST ); - else if( aSimplify ) - tmpSet.Simplify( PM_FAST ); + tmpSet.Fracture( PM_FAST ); m_triangulationValid = triangulate( tmpSet, -1, m_triangulatedPolys ); }