Add support for non-cardianlly-rotated text boxes.

Also fixes a couple of bugs in text boxes in flipped footprints.

Fixes https://gitlab.com/kicad/code/kicad/issues/14112
This commit is contained in:
Jeff Young 2023-03-02 14:54:19 +00:00
parent 789bf6455a
commit 7638e23ff1
4 changed files with 127 additions and 57 deletions

View File

@ -282,6 +282,7 @@ void FP_SHAPE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
}
bool FP_SHAPE::IsParentFlipped() const
{
if( GetParent() && GetParent()->GetLayer() == B_Cu )
@ -289,11 +290,9 @@ bool FP_SHAPE::IsParentFlipped() const
return false;
}
void FP_SHAPE::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
{
// Mirror an edge of the footprint. the layer is not modified
// This is a footprint shape modification.
switch( GetShape() )
{
case SHAPE_T::ARC:
@ -340,6 +339,7 @@ void FP_SHAPE::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
SetDrawCoord();
}
void FP_SHAPE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
{
// We should rotate the relative coordinates, but to avoid duplicate code do the base class

View File

@ -33,6 +33,8 @@
#include <geometry/shape_compound.h>
#include <callback_gal.h>
#include <convert_basic_shapes_to_polygon.h>
#include <macros.h>
FP_TEXTBOX::FP_TEXTBOX( FOOTPRINT* aParentFootprint ) :
FP_SHAPE( aParentFootprint, SHAPE_T::RECT, PCB_FP_TEXTBOX_T ),
@ -131,12 +133,30 @@ void FP_TEXTBOX::SetRight( int aVal )
}
std::vector<VECTOR2I> FP_TEXTBOX::GetCorners() const
{
std::vector<VECTOR2I> pts = FP_SHAPE::GetCorners();
// SHAPE_T::POLY doesn't use the DrawCoord/LocalCoord architecture and instead stores fully
// resolved points (ie: relative to the board, not parent footprint).
if( GetShape() == SHAPE_T::POLY )
{
if( FOOTPRINT* parentFootprint = PCB_SHAPE::GetParentFootprint() )
{
for( VECTOR2I& pt : pts )
RotatePoint( pt, parentFootprint->GetPosition(), parentFootprint->GetOrientation() );
}
}
return pts;
}
EDA_ANGLE FP_TEXTBOX::GetDrawRotation() const
{
FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( m_parent );
EDA_ANGLE rotation = GetTextAngle();
EDA_ANGLE rotation = GetTextAngle();
if( parentFootprint )
if( FOOTPRINT* parentFootprint = PCB_SHAPE::GetParentFootprint() )
rotation += parentFootprint->GetOrientation();
rotation.Normalize();
@ -145,57 +165,57 @@ EDA_ANGLE FP_TEXTBOX::GetDrawRotation() const
}
std::vector<VECTOR2I> FP_TEXTBOX::GetAnchorAndOppositeCorner() const
std::vector<VECTOR2I> FP_TEXTBOX::GetNormalizedCorners() const
{
std::vector<VECTOR2I> pts;
std::vector<VECTOR2I> corners = GetCorners();
EDA_ANGLE textAngle( GetDrawRotation() );
textAngle.Normalize();
if( FOOTPRINT* parentFootprint = PCB_SHAPE::GetParentFootprint() )
{
if( parentFootprint->IsFlipped() )
std::swap( corners[1], corners[3] );
}
pts.emplace_back( corners[0] );
textAngle.Normalize();
if( textAngle < ANGLE_90 )
{
if( corners[1].y <= corners[0].y )
pts.emplace_back( corners[1] );
else
pts.emplace_back( corners[3] );
if( corners[1].y > corners[0].y )
std::swap( corners[1], corners[3] );
}
else if( textAngle < ANGLE_180 )
{
if( corners[1].x <= corners[0].x )
pts.emplace_back( corners[1] );
else
pts.emplace_back( corners[3] );
if( corners[1].x > corners[0].x )
std::swap( corners[1], corners[3] );
}
else if( textAngle < ANGLE_270 )
{
if( corners[1].y >= corners[0].y )
pts.emplace_back( corners[1] );
else
pts.emplace_back( corners[3] );
if( corners[1].y < corners[0].y )
std::swap( corners[1], corners[3] );
}
else
{
if( corners[1].x >= corners[0].x )
pts.emplace_back( corners[1] );
else
pts.emplace_back( corners[3] );
if( corners[1].x < corners[0].x )
std::swap( corners[1], corners[3] );
}
return pts;
return corners;
}
VECTOR2I FP_TEXTBOX::GetDrawPos() const
{
std::vector<VECTOR2I> corners = GetAnchorAndOppositeCorner();
std::vector<VECTOR2I> corners = GetNormalizedCorners();
GR_TEXT_H_ALIGN_T effectiveAlignment = GetHorizJustify();
VECTOR2I textAnchor;
VECTOR2I offset;
VECTOR2I vMargin;
VECTOR2I hMargin;
bool isFlipped = false;
if( IsMirrored() )
if( FOOTPRINT* parentFootprint = PCB_SHAPE::GetParentFootprint() )
isFlipped = parentFootprint->IsFlipped();
if( IsMirrored() != isFlipped )
{
switch( GetHorizJustify() )
{
@ -209,20 +229,21 @@ VECTOR2I FP_TEXTBOX::GetDrawPos() const
{
case GR_TEXT_H_ALIGN_LEFT:
textAnchor = corners[0];
offset = VECTOR2I( GetTextMargin(), GetTextMargin() );
vMargin = ( corners[2] - corners[1] ).Resize( GetTextMargin() );
hMargin = ( corners[1] - corners[0] ).Resize( GetTextMargin() );
break;
case GR_TEXT_H_ALIGN_CENTER:
textAnchor = ( corners[0] + corners[1] ) / 2;
offset = VECTOR2I( 0, GetTextMargin() );
vMargin = ( corners[2] - corners[1] ).Resize( GetTextMargin() );
break;
case GR_TEXT_H_ALIGN_RIGHT:
textAnchor = corners[1];
offset = VECTOR2I( -GetTextMargin(), GetTextMargin() );
vMargin = ( corners[2] - corners[1] ).Resize( GetTextMargin() );
hMargin = ( corners[0] - corners[1] ).Resize( GetTextMargin() );
break;
}
RotatePoint( offset, GetDrawRotation() );
return textAnchor + offset;
return textAnchor + hMargin + vMargin;
}
@ -265,6 +286,8 @@ void FP_TEXTBOX::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
void FP_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
{
FP_SHAPE::Flip( aCentre, aFlipLeftRight );
// flipping the footprint is relative to the X axis
if( aFlipLeftRight )
{
@ -277,8 +300,6 @@ void FP_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
SetTextAngle( ANGLE_180 - GetTextAngle() );
}
SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
if( ( GetLayerSet() & LSET::SideSpecificMask() ).any() )
SetMirrored( !IsMirrored() );
@ -409,7 +430,7 @@ wxString FP_TEXTBOX::GetShownText( int aDepth, bool aAllowExtraText ) const
}
KIFONT::FONT* font = getDrawFont();
std::vector<VECTOR2I> corners = GetAnchorAndOppositeCorner();
std::vector<VECTOR2I> corners = GetNormalizedCorners();
int colWidth = ( corners[1] - corners[0] ).EuclideanNorm();
colWidth -= GetTextMargin() * 2;
@ -477,22 +498,74 @@ void FP_TEXTBOX::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID
// Don't use FP_SHAPE::TransformShapeToPolygon. We want to treat the textbox as filled even
// if there's no background colour.
std::vector<VECTOR2I> pts = GetRectCorners();
aBuffer.NewOutline();
for( const VECTOR2I& pt : pts )
aBuffer.Append( pt );
int width = GetWidth() + ( 2 * aClearance );
if( width > 0 )
switch( m_shape )
{
// Add in segments
TransformOvalToPolygon( aBuffer, pts[0], pts[1], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[1], pts[2], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[2], pts[3], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[3], pts[0], width, aError, aErrorLoc );
case SHAPE_T::RECT:
{
std::vector<VECTOR2I> pts = GetRectCorners();
aBuffer.NewOutline();
for( const VECTOR2I& pt : pts )
aBuffer.Append( pt );
if( width > 0 )
{
// Add in segments
TransformOvalToPolygon( aBuffer, pts[0], pts[1], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[1], pts[2], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[2], pts[3], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[3], pts[0], width, aError, aErrorLoc );
}
break;
}
case SHAPE_T::POLY:
{
if( !IsPolyShapeValid() )
break;
// The polygon is expected to be a simple polygon; not self intersecting, no hole.
EDA_ANGLE orientation = getParentOrientation();
VECTOR2I offset = getParentPosition();
// Build the polygon with the actual position and orientation:
std::vector<VECTOR2I> poly;
DupPolyPointsList( poly );
for( VECTOR2I& point : poly )
{
RotatePoint( point, orientation );
point += offset;
}
aBuffer.NewOutline();
for( const VECTOR2I& point : poly )
aBuffer.Append( point.x, point.y );
if( width > 0 )
{
VECTOR2I pt1( poly[poly.size() - 1] );
for( const VECTOR2I& pt2 : poly )
{
if( pt2 != pt1 )
TransformOvalToPolygon( aBuffer, pt1, pt2, width, aError, aErrorLoc );
pt1 = pt2;
}
}
break;
}
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break;
}
}

View File

@ -84,7 +84,8 @@ public:
VECTOR2I GetDrawPos() const override;
std::vector<VECTOR2I> GetAnchorAndOppositeCorner() const;
std::vector<VECTOR2I> GetCorners() const override;
std::vector<VECTOR2I> GetNormalizedCorners() const;
void Move( const VECTOR2I& aMoveVector ) override;
@ -97,10 +98,6 @@ public:
*/
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis ) override;
// The Pos0 accessors are for footprint-relative coordinates.
void SetPos0( const VECTOR2I& aPos ) { m_Pos0 = aPos; SetDrawCoord(); }
const VECTOR2I& GetPos0() const { return m_Pos0; }
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override;

View File

@ -75,7 +75,7 @@ public:
* Return 4 corners for a rectangle or rotated rectangle (stored as a poly). Unimplemented
* for other shapes.
*/
std::vector<VECTOR2I> GetCorners() const;
virtual std::vector<VECTOR2I> GetCorners() const;
/**
* Allows items to return their visual center rather than their anchor. For some shapes this