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
(cherry picked from commit 7638e23ff1
)
This commit is contained in:
parent
d311915f9d
commit
e17dc25bba
|
@ -282,6 +282,7 @@ void FP_SHAPE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
||||||
SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
|
SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FP_SHAPE::IsParentFlipped() const
|
bool FP_SHAPE::IsParentFlipped() const
|
||||||
{
|
{
|
||||||
if( GetParent() && GetParent()->GetLayer() == B_Cu )
|
if( GetParent() && GetParent()->GetLayer() == B_Cu )
|
||||||
|
@ -289,11 +290,9 @@ bool FP_SHAPE::IsParentFlipped() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FP_SHAPE::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
|
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() )
|
switch( GetShape() )
|
||||||
{
|
{
|
||||||
case SHAPE_T::ARC:
|
case SHAPE_T::ARC:
|
||||||
|
@ -340,6 +339,7 @@ void FP_SHAPE::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
|
||||||
SetDrawCoord();
|
SetDrawCoord();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FP_SHAPE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
|
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
|
// We should rotate the relative coordinates, but to avoid duplicate code do the base class
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include <geometry/shape_compound.h>
|
#include <geometry/shape_compound.h>
|
||||||
#include <callback_gal.h>
|
#include <callback_gal.h>
|
||||||
#include <convert_basic_shapes_to_polygon.h>
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
|
#include <macros.h>
|
||||||
|
|
||||||
|
|
||||||
FP_TEXTBOX::FP_TEXTBOX( FOOTPRINT* aParentFootprint ) :
|
FP_TEXTBOX::FP_TEXTBOX( FOOTPRINT* aParentFootprint ) :
|
||||||
FP_SHAPE( aParentFootprint, SHAPE_T::RECT, PCB_FP_TEXTBOX_T ),
|
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
|
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 += parentFootprint->GetOrientation();
|
||||||
|
|
||||||
rotation.Normalize();
|
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();
|
std::vector<VECTOR2I> corners = GetCorners();
|
||||||
EDA_ANGLE textAngle( GetDrawRotation() );
|
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( textAngle < ANGLE_90 )
|
||||||
{
|
{
|
||||||
if( corners[1].y <= corners[0].y )
|
if( corners[1].y > corners[0].y )
|
||||||
pts.emplace_back( corners[1] );
|
std::swap( corners[1], corners[3] );
|
||||||
else
|
|
||||||
pts.emplace_back( corners[3] );
|
|
||||||
}
|
}
|
||||||
else if( textAngle < ANGLE_180 )
|
else if( textAngle < ANGLE_180 )
|
||||||
{
|
{
|
||||||
if( corners[1].x <= corners[0].x )
|
if( corners[1].x > corners[0].x )
|
||||||
pts.emplace_back( corners[1] );
|
std::swap( corners[1], corners[3] );
|
||||||
else
|
|
||||||
pts.emplace_back( corners[3] );
|
|
||||||
}
|
}
|
||||||
else if( textAngle < ANGLE_270 )
|
else if( textAngle < ANGLE_270 )
|
||||||
{
|
{
|
||||||
if( corners[1].y >= corners[0].y )
|
if( corners[1].y < corners[0].y )
|
||||||
pts.emplace_back( corners[1] );
|
std::swap( corners[1], corners[3] );
|
||||||
else
|
|
||||||
pts.emplace_back( corners[3] );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( corners[1].x >= corners[0].x )
|
if( corners[1].x < corners[0].x )
|
||||||
pts.emplace_back( corners[1] );
|
std::swap( corners[1], corners[3] );
|
||||||
else
|
|
||||||
pts.emplace_back( corners[3] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pts;
|
return corners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2I FP_TEXTBOX::GetDrawPos() const
|
VECTOR2I FP_TEXTBOX::GetDrawPos() const
|
||||||
{
|
{
|
||||||
std::vector<VECTOR2I> corners = GetAnchorAndOppositeCorner();
|
std::vector<VECTOR2I> corners = GetNormalizedCorners();
|
||||||
GR_TEXT_H_ALIGN_T effectiveAlignment = GetHorizJustify();
|
GR_TEXT_H_ALIGN_T effectiveAlignment = GetHorizJustify();
|
||||||
VECTOR2I textAnchor;
|
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() )
|
switch( GetHorizJustify() )
|
||||||
{
|
{
|
||||||
|
@ -209,20 +229,21 @@ VECTOR2I FP_TEXTBOX::GetDrawPos() const
|
||||||
{
|
{
|
||||||
case GR_TEXT_H_ALIGN_LEFT:
|
case GR_TEXT_H_ALIGN_LEFT:
|
||||||
textAnchor = corners[0];
|
textAnchor = corners[0];
|
||||||
offset = VECTOR2I( GetTextMargin(), GetTextMargin() );
|
vMargin = ( corners[2] - corners[1] ).Resize( GetTextMargin() );
|
||||||
|
hMargin = ( corners[1] - corners[0] ).Resize( GetTextMargin() );
|
||||||
break;
|
break;
|
||||||
case GR_TEXT_H_ALIGN_CENTER:
|
case GR_TEXT_H_ALIGN_CENTER:
|
||||||
textAnchor = ( corners[0] + corners[1] ) / 2;
|
textAnchor = ( corners[0] + corners[1] ) / 2;
|
||||||
offset = VECTOR2I( 0, GetTextMargin() );
|
vMargin = ( corners[2] - corners[1] ).Resize( GetTextMargin() );
|
||||||
break;
|
break;
|
||||||
case GR_TEXT_H_ALIGN_RIGHT:
|
case GR_TEXT_H_ALIGN_RIGHT:
|
||||||
textAnchor = corners[1];
|
textAnchor = corners[1];
|
||||||
offset = VECTOR2I( -GetTextMargin(), GetTextMargin() );
|
vMargin = ( corners[2] - corners[1] ).Resize( GetTextMargin() );
|
||||||
|
hMargin = ( corners[0] - corners[1] ).Resize( GetTextMargin() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RotatePoint( offset, GetDrawRotation() );
|
return textAnchor + hMargin + vMargin;
|
||||||
return textAnchor + offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -265,6 +286,8 @@ void FP_TEXTBOX::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
|
||||||
|
|
||||||
void FP_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
void FP_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
||||||
{
|
{
|
||||||
|
FP_SHAPE::Flip( aCentre, aFlipLeftRight );
|
||||||
|
|
||||||
// flipping the footprint is relative to the X axis
|
// flipping the footprint is relative to the X axis
|
||||||
if( aFlipLeftRight )
|
if( aFlipLeftRight )
|
||||||
{
|
{
|
||||||
|
@ -277,8 +300,6 @@ void FP_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
||||||
SetTextAngle( ANGLE_180 - GetTextAngle() );
|
SetTextAngle( ANGLE_180 - GetTextAngle() );
|
||||||
}
|
}
|
||||||
|
|
||||||
SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
|
|
||||||
|
|
||||||
if( ( GetLayerSet() & LSET::SideSpecificMask() ).any() )
|
if( ( GetLayerSet() & LSET::SideSpecificMask() ).any() )
|
||||||
SetMirrored( !IsMirrored() );
|
SetMirrored( !IsMirrored() );
|
||||||
|
|
||||||
|
@ -409,7 +430,7 @@ wxString FP_TEXTBOX::GetShownText( int aDepth, bool aAllowExtraText ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
KIFONT::FONT* font = getDrawFont();
|
KIFONT::FONT* font = getDrawFont();
|
||||||
std::vector<VECTOR2I> corners = GetAnchorAndOppositeCorner();
|
std::vector<VECTOR2I> corners = GetNormalizedCorners();
|
||||||
int colWidth = ( corners[1] - corners[0] ).EuclideanNorm();
|
int colWidth = ( corners[1] - corners[0] ).EuclideanNorm();
|
||||||
|
|
||||||
colWidth -= GetTextMargin() * 2;
|
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
|
// Don't use FP_SHAPE::TransformShapeToPolygon. We want to treat the textbox as filled even
|
||||||
// if there's no background colour.
|
// 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 );
|
int width = GetWidth() + ( 2 * aClearance );
|
||||||
|
|
||||||
if( width > 0 )
|
switch( m_shape )
|
||||||
{
|
{
|
||||||
// Add in segments
|
case SHAPE_T::RECT:
|
||||||
TransformOvalToPolygon( aBuffer, pts[0], pts[1], width, aError, aErrorLoc );
|
{
|
||||||
TransformOvalToPolygon( aBuffer, pts[1], pts[2], width, aError, aErrorLoc );
|
std::vector<VECTOR2I> pts = GetRectCorners();
|
||||||
TransformOvalToPolygon( aBuffer, pts[2], pts[3], width, aError, aErrorLoc );
|
|
||||||
TransformOvalToPolygon( aBuffer, pts[3], pts[0], width, aError, aErrorLoc );
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,8 @@ public:
|
||||||
|
|
||||||
VECTOR2I GetDrawPos() const override;
|
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;
|
void Move( const VECTOR2I& aMoveVector ) override;
|
||||||
|
|
||||||
|
@ -97,10 +98,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis ) override;
|
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;
|
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
|
||||||
|
|
||||||
bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override;
|
bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override;
|
||||||
|
|
|
@ -75,7 +75,7 @@ public:
|
||||||
* Return 4 corners for a rectangle or rotated rectangle (stored as a poly). Unimplemented
|
* Return 4 corners for a rectangle or rotated rectangle (stored as a poly). Unimplemented
|
||||||
* for other shapes.
|
* 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
|
* Allows items to return their visual center rather than their anchor. For some shapes this
|
||||||
|
|
Loading…
Reference in New Issue