Improve text hittesting in schematics.

Text has a fairly big bounding box to account for descenders, overbars,
etc., but it makes it feel too sloppy for hittesting.  This change
allows selection disambiguation to look at the actual strokes of the
text when deciding what's "closest".

Fixes https://gitlab.com/kicad/code/kicad/issues/9506
This commit is contained in:
Jeff Young 2021-11-01 21:05:30 +00:00
parent bf85ddd577
commit 40b4052ad4
6 changed files with 86 additions and 22 deletions

View File

@ -624,15 +624,15 @@ std::vector<wxPoint> EDA_TEXT::TransformToSegmentList() const
for( unsigned ii = 0; ii < strings_list.Count(); ii++ ) for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
{ {
wxString txt = strings_list.Item( ii ); wxString txt = strings_list.Item( ii );
GRText( nullptr, positions[ii], color, txt, GetDrawRotation(), size, GetHorizJustify(), GRText( nullptr, positions[ii], color, txt, GetDrawRotation(), size,
GetVertJustify(), penWidth, IsItalic(), forceBold, addTextSegmToBuffer, GetDrawHorizJustify(), GetDrawVertJustify(), penWidth, IsItalic(), forceBold,
&cornerBuffer ); addTextSegmToBuffer, &cornerBuffer );
} }
} }
else else
{ {
GRText( nullptr, GetTextPos(), color, GetShownText(), GetDrawRotation(), size, GRText( nullptr, GetDrawPos(), color, GetShownText(), GetDrawRotation(), size,
GetHorizJustify(), GetVertJustify(), penWidth, IsItalic(), forceBold, GetDrawHorizJustify(), GetDrawVertJustify(), penWidth, IsItalic(), forceBold,
addTextSegmToBuffer, &cornerBuffer ); addTextSegmToBuffer, &cornerBuffer );
} }
@ -653,12 +653,6 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( ) const
} }
double EDA_TEXT::GetDrawRotation() const
{
return GetTextAngle();
}
int EDA_TEXT::Compare( const EDA_TEXT* aOther ) const int EDA_TEXT::Compare( const EDA_TEXT* aOther ) const
{ {
#define TEST( a, b ) { if( a != b ) return a - b; } #define TEST( a, b ) { if( a != b ) return a - b; }

View File

@ -262,6 +262,46 @@ void SCH_FIELD::SwapData( SCH_ITEM* aItem )
} }
double SCH_FIELD::GetDrawRotation() const
{
// Calculate the text orientation according to the symbol orientation.
int orient = GetTextAngle();
if( m_parent && m_parent->Type() == SCH_SYMBOL_T )
{
SCH_SYMBOL* parentSymbol = static_cast<SCH_SYMBOL*>( m_parent );
if( parentSymbol && parentSymbol->GetTransform().y1 ) // Rotate symbol 90 degrees.
{
if( orient == TEXT_ANGLE_HORIZ )
orient = TEXT_ANGLE_VERT;
else
orient = TEXT_ANGLE_HORIZ;
}
}
return orient;
}
wxPoint SCH_FIELD::GetDrawPos() const
{
return GetBoundingBox().Centre();
}
EDA_TEXT_HJUSTIFY_T SCH_FIELD::GetDrawHorizJustify() const
{
return GR_TEXT_HJUSTIFY_CENTER;
}
EDA_TEXT_VJUSTIFY_T SCH_FIELD::GetDrawVertJustify() const
{
return GR_TEXT_VJUSTIFY_CENTER;
}
const EDA_RECT SCH_FIELD::GetBoundingBox() const const EDA_RECT SCH_FIELD::GetBoundingBox() const
{ {
// Calculate the text bounding box: // Calculate the text bounding box:

View File

@ -116,6 +116,14 @@ public:
wxString GetShownText( int aDepth = 0 ) const override; wxString GetShownText( int aDepth = 0 ) const override;
/**
* Adjusters to allow EDA_TEXT to draw/print/etc. text in absolute coords.
*/
double GetDrawRotation() const override;
wxPoint GetDrawPos() const override;
EDA_TEXT_HJUSTIFY_T GetDrawHorizJustify() const override;
EDA_TEXT_VJUSTIFY_T GetDrawVertJustify() const override;
const EDA_RECT GetBoundingBox() const override; const EDA_RECT GetBoundingBox() const override;
/** /**

View File

@ -1783,7 +1783,7 @@ SCH_SYMBOL& SCH_SYMBOL::operator=( const SCH_ITEM& aItem )
bool SCH_SYMBOL::HitTest( const wxPoint& aPosition, int aAccuracy ) const bool SCH_SYMBOL::HitTest( const wxPoint& aPosition, int aAccuracy ) const
{ {
EDA_RECT bBox = GetBodyBoundingBox(); EDA_RECT bBox = GetBoundingBox();
bBox.Inflate( aAccuracy ); bBox.Inflate( aAccuracy );
if( bBox.Contains( aPosition ) ) if( bBox.Contains( aPosition ) )

View File

@ -25,6 +25,7 @@
#include <bitmaps.h> #include <bitmaps.h>
#include <core/typeinfo.h> #include <core/typeinfo.h>
#include <core/kicad_algo.h> #include <core/kicad_algo.h>
#include <geometry/shape_compound.h>
#include <ee_actions.h> #include <ee_actions.h>
#include <ee_collectors.h> #include <ee_collectors.h>
#include <ee_selection_tool.h> #include <ee_selection_tool.h>
@ -1011,13 +1012,15 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
} }
// Find the closest item. (Note that at this point all hits are either exact or non-exact.) // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
wxPoint pos( aPos );
SEG poss( aPos, aPos );
EDA_ITEM* closest = nullptr; EDA_ITEM* closest = nullptr;
int closestDist = INT_MAX; int closestDist = INT_MAX / 2;
for( EDA_ITEM* item : collector ) for( EDA_ITEM* item : collector )
{ {
EDA_RECT bbox = item->GetBoundingBox(); EDA_RECT bbox = item->GetBoundingBox();
int dist; int dist = INT_MAX / 2;
if( exactHits.count( item ) ) if( exactHits.count( item ) )
{ {
@ -1027,23 +1030,39 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
break; break;
} }
wxPoint pos( aPos ); SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
SCH_LINE* line = dynamic_cast<SCH_LINE*>( item ); EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
if( line ) if( line )
{
dist = DistanceLinePoint( line->GetStartPoint(), line->GetEndPoint(), pos ); dist = DistanceLinePoint( line->GetStartPoint(), line->GetEndPoint(), pos );
}
else if( text )
{
text->GetEffectiveTextShape()->Collide( poss, closestDist, &dist );
}
else if( symbol )
{
bbox = symbol->GetBodyBoundingBox();
SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
if( bbox.Contains( pos ) )
dist = EuclideanNorm( bbox.GetCenter() - pos );
else
rect.Collide( poss, closestDist, &dist );
}
else else
dist = EuclideanNorm( bbox.GetCenter() - pos ) * 2; {
dist = EuclideanNorm( bbox.GetCenter() - pos );
}
} }
else else
{ {
SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() ); SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
rect.Collide( SEG( aPos, aPos ), collector.m_Threshold, &dist ); rect.Collide( poss, collector.m_Threshold, &dist );
} }
if( item->IsType( EE_COLLECTOR::FieldOwners ) )
dist += INT_MAX / 4;
if( dist < closestDist ) if( dist < closestDist )
{ {
closestDist = dist; closestDist = dist;

View File

@ -385,7 +385,10 @@ public:
*/ */
virtual void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const; virtual void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const;
virtual double GetDrawRotation() const; virtual double GetDrawRotation() const { return GetTextAngle(); }
virtual wxPoint GetDrawPos() const { return GetTextPos(); }
virtual EDA_TEXT_HJUSTIFY_T GetDrawHorizJustify() const { return GetHorizJustify(); };
virtual EDA_TEXT_VJUSTIFY_T GetDrawVertJustify() const { return GetVertJustify(); };
int Compare( const EDA_TEXT* aOther ) const; int Compare( const EDA_TEXT* aOther ) const;