Support mirroring on the board too.

Also fixes a few bugs in FP item mirroring.

Fixes https://gitlab.com/kicad/code/kicad/issues/2168
This commit is contained in:
Jeff Young 2022-09-22 15:05:06 +01:00
parent f75266d130
commit 897135a4f0
15 changed files with 152 additions and 102 deletions

View File

@ -68,26 +68,13 @@ public:
void SetArcGeometry0( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd );
/**
* Move an edge of the footprint.
* This is a footprint shape modification.
* (should be only called by a footprint editing function)
*/
void Move( const VECTOR2I& aMoveVector ) override;
/**
* Mirror an edge of the footprint.
* Do not change the layer
* This is a footprint shape modification.
* (should be only called by a footprint editing function)
* Mirror horizontally or vertically. Do not change the layer.
*/
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis );
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis ) override;
/**
* Rotate an edge of the footprint.
* This is a footprint shape modification.
* (should be only called by a footprint editing function )
*/
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
/**

View File

@ -163,12 +163,22 @@ bool FP_TEXT::IsParentFlipped() const
void FP_TEXT::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
{
// the position is mirrored, but the text itself is not mirrored
// the position and justification are mirrored, but not the text itself
if( aMirrorAroundXAxis )
{
if( GetTextAngle() == ANGLE_VERTICAL )
SetHorizJustify( (GR_TEXT_H_ALIGN_T) -GetHorizJustify() );
SetTextY( ::MIRRORVAL( GetTextPos().y, aCentre.y ) );
}
else
{
if( GetTextAngle() == ANGLE_HORIZONTAL )
SetHorizJustify( (GR_TEXT_H_ALIGN_T) -GetHorizJustify() );
SetTextX( ::MIRRORVAL( GetTextPos().x, aCentre.x ) );
}
SetLocalCoord();
}

View File

@ -100,8 +100,6 @@ public:
*/
void KeepUpright( const EDA_ANGLE& aOldOrientation, const EDA_ANGLE& aNewOrientation );
/// Rotate text, in footprint editor
/// (for instance in footprint rotation transform)
void Rotate( const VECTOR2I& aOffset, const EDA_ANGLE& aAngle ) override;
/// Flip entity during footprint flip
@ -109,17 +107,15 @@ public:
bool IsParentFlipped() const;
/// Mirror text position in footprint editing
/// the text itself is not mirrored, and the layer not modified,
/// only position is mirrored.
/// (use Flip to change layer to its paired and mirror the text in fp editor).
/**
* Mirror text position. Do not mirror the text itself, or change its layer.
*/
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis );
/// move text in move transform, in footprint editor
void Move( const VECTOR2I& aMoveVector ) override;
/// @deprecated it seems (but the type is used to 'protect'
// reference and value from deletion, and for identification)
/// @deprecated it seems (but the type is used to 'protect' reference and value from deletion,
/// and for identification)
void SetType( TEXT_TYPE aType ) { m_Type = aType; }
TEXT_TYPE GetType() const { return m_Type; }
@ -169,7 +165,7 @@ public:
// @copydoc BOARD_ITEM::GetEffectiveShape
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override;
FLASHING aFlash = FLASHING::DEFAULT ) const override;
wxString GetClass() const override
{

View File

@ -22,15 +22,12 @@
*/
#include <pcb_edit_frame.h>
#include <base_units.h>
#include <bitmaps.h>
#include <board.h>
#include <board_design_settings.h>
#include <core/mirror.h>
#include <footprint.h>
#include <fp_textbox.h>
#include <settings/settings_manager.h>
#include <trigo.h>
#include <string_utils.h>
#include <painter.h>
#include <geometry/shape_compound.h>
@ -288,14 +285,15 @@ void FP_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
void FP_TEXTBOX::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
{
// the position is mirrored, but the text itself is not mirrored
// the position is mirrored, but not the text (or its justification)
FP_SHAPE::Mirror( aCentre, aMirrorAroundXAxis );
if( aMirrorAroundXAxis )
SetTextY( ::MIRRORVAL( GetTextPos().y, aCentre.y ) );
else
SetTextX( ::MIRRORVAL( GetTextPos().x, aCentre.x ) );
BOX2I rect( m_start0, m_end0 - m_start0 );
rect.Normalize();
m_start0 = VECTOR2I( rect.GetLeft(), rect.GetTop() );
m_end0 = VECTOR2I( rect.GetRight(), rect.GetBottom() );
SetLocalCoord();
SetDrawCoord();
}

View File

@ -88,18 +88,14 @@ public:
void Move( const VECTOR2I& aMoveVector ) override;
/// Rotate text, in footprint editor
/// (for instance in footprint rotation transform)
void Rotate( const VECTOR2I& aOffset, const EDA_ANGLE& aAngle ) override;
/// Flip entity during footprint flip
void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override;
/// Mirror text position in footprint editing
/// the text itself is not mirrored, and the layer not modified,
/// only position is mirrored.
/// (use Flip to change layer to its paired and mirror the text in fp editor).
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis );
/**
* Mirror the textbox's position, but not the text (or its justification).
*/
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(); }
@ -108,7 +104,6 @@ public:
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 BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, PCB_LAYER_ID aLayer,

View File

@ -25,6 +25,8 @@
*/
#include <bitmaps.h>
#include <core/mirror.h>
#include <macros.h>
#include <pcb_edit_frame.h>
#include <board_design_settings.h>
#include <footprint.h>
@ -32,7 +34,6 @@
#include <geometry/shape_compound.h>
#include <pcb_shape.h>
#include <pcb_painter.h>
#include "macros.h"
PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T aItemType, SHAPE_T aShapeType ) :
BOARD_ITEM( aParent, aItemType ),
@ -196,6 +197,53 @@ void PCB_SHAPE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
}
void PCB_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:
case SHAPE_T::SEGMENT:
case SHAPE_T::RECT:
case SHAPE_T::CIRCLE:
case SHAPE_T::BEZIER:
if( aMirrorAroundXAxis )
{
MIRROR( m_start.y, aCentre.y );
MIRROR( m_end.y, aCentre.y );
MIRROR( m_arcCenter.y, aCentre.y );
MIRROR( m_bezierC1.y, aCentre.y );
MIRROR( m_bezierC2.y, aCentre.y );
}
else
{
MIRROR( m_start.x, aCentre.x );
MIRROR( m_end.x, aCentre.x );
MIRROR( m_arcCenter.x, aCentre.x );
MIRROR( m_bezierC1.x, aCentre.x );
MIRROR( m_bezierC2.x, aCentre.x );
}
if( GetShape() == SHAPE_T::ARC )
std::swap( m_start, m_end );
if( GetShape() == SHAPE_T::BEZIER )
RebuildBezierToSegmentsPointsList( GetWidth() );
break;
case SHAPE_T::POLY:
m_poly.Mirror( !aMirrorAroundXAxis, aMirrorAroundXAxis, aCentre );
break;
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
}
}
FOOTPRINT* PCB_SHAPE::GetParentFootprint() const
{
return dynamic_cast<FOOTPRINT*>( BOARD_ITEM::GetParentFootprint() );

View File

@ -116,6 +116,8 @@ public:
virtual void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override;
virtual void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis );
void Scale( double aScale );
/**

View File

@ -211,6 +211,27 @@ void PCB_TEXT::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
}
void PCB_TEXT::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
{
// the position and justification are mirrored, but not the text itself
if( aMirrorAroundXAxis )
{
if( GetTextAngle() == ANGLE_VERTICAL )
SetHorizJustify( (GR_TEXT_H_ALIGN_T) -GetHorizJustify() );
SetTextY( MIRRORVAL( GetTextPos().y, aCentre.y ) );
}
else
{
if( GetTextAngle() == ANGLE_HORIZONTAL )
SetHorizJustify( (GR_TEXT_H_ALIGN_T) -GetHorizJustify() );
SetTextX( MIRRORVAL( GetTextPos().x, aCentre.x ) );
}
}
void PCB_TEXT::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
{
if( aFlipLeftRight )

View File

@ -90,6 +90,8 @@ public:
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis );
void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override;
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
@ -102,9 +104,6 @@ public:
return TextHitTest( aPosition, aAccuracy );
}
/**
* @copydoc BOARD_ITEM::HitTest(const BOX2I& aRect, bool aContained, int aAccuracy ) const
*/
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override
{
return TextHitTest( aRect, aContained, aAccuracy );

View File

@ -34,7 +34,7 @@
#include <geometry/shape_compound.h>
#include <callback_gal.h>
#include <convert_basic_shapes_to_polygon.h>
#include "macros.h"
#include <macros.h>
PCB_TEXTBOX::PCB_TEXTBOX( BOARD_ITEM* parent ) :
@ -355,6 +355,18 @@ void PCB_TEXTBOX::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
}
void PCB_TEXTBOX::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis )
{
// the position is mirrored, but not the text (or its justification)
PCB_SHAPE::Mirror( aCentre, aMirrorAroundXAxis );
BOX2I rect( m_start, m_end - m_start );
rect.Normalize();
m_start = VECTOR2I( rect.GetLeft(), rect.GetTop() );
m_end = VECTOR2I( rect.GetRight(), rect.GetBottom() );
}
void PCB_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
{
if( aFlipLeftRight )

View File

@ -91,6 +91,8 @@ public:
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis ) override;
void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override;
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
@ -123,16 +125,14 @@ public:
// @copydoc BOARD_ITEM::GetEffectiveShape
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override;
FLASHING aFlash = FLASHING::DEFAULT ) const override;
wxString GetSelectMenuText( UNITS_PROVIDER* aUnitsProvider ) const override;
BITMAPS GetMenuImage() const override;
///< @copydoc VIEW_ITEM::ViewGetLOD
double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override;
// Virtual function
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;

View File

@ -264,6 +264,8 @@ void PCB_EDIT_FRAME::ReCreateHToolbar()
m_mainToolBar->AddScaledSeparator( this );
m_mainToolBar->Add( PCB_ACTIONS::rotateCcw );
m_mainToolBar->Add( PCB_ACTIONS::rotateCw );
m_mainToolBar->Add( PCB_ACTIONS::mirrorV );
m_mainToolBar->Add( PCB_ACTIONS::mirrorH );
m_mainToolBar->Add( PCB_ACTIONS::group );
m_mainToolBar->Add( PCB_ACTIONS::ungroup );
m_mainToolBar->Add( PCB_ACTIONS::lock );

View File

@ -31,6 +31,10 @@
#include <footprint.h>
#include <fp_shape.h>
#include <fp_textbox.h>
#include <pcb_group.h>
#include <pcb_target.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <collectors.h>
#include <pcb_edit_frame.h>
#include <drawing_sheet/ds_proxy_view_item.h>
@ -60,8 +64,6 @@ using namespace std::placeholders;
#include <dialogs/dialog_track_via_properties.h>
#include <dialogs/dialog_unit_entry.h>
#include <board_commit.h>
#include <pcb_group.h>
#include <pcb_target.h>
#include <zone_filler.h>
const unsigned int EDIT_TOOL::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
@ -197,8 +199,8 @@ bool EDIT_TOOL::Init()
menu.AddItem( PCB_ACTIONS::rotateCcw, SELECTION_CONDITIONS::NotEmpty );
menu.AddItem( PCB_ACTIONS::rotateCw, SELECTION_CONDITIONS::NotEmpty );
menu.AddItem( PCB_ACTIONS::flip, SELECTION_CONDITIONS::NotEmpty );
menu.AddItem( PCB_ACTIONS::mirrorH, inFootprintEditor && SELECTION_CONDITIONS::NotEmpty );
menu.AddItem( PCB_ACTIONS::mirrorV, inFootprintEditor && SELECTION_CONDITIONS::NotEmpty );
menu.AddItem( PCB_ACTIONS::mirrorH, SELECTION_CONDITIONS::NotEmpty );
menu.AddItem( PCB_ACTIONS::mirrorV, SELECTION_CONDITIONS::NotEmpty );
menu.AddItem( PCB_ACTIONS::swap, SELECTION_CONDITIONS::MoreThan( 1 ) );
menu.AddItem( PCB_ACTIONS::properties, propertiesCondition );
@ -1316,15 +1318,19 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
switch( item->Type() )
{
case PCB_FP_SHAPE_T:
case PCB_SHAPE_T:
case PCB_FP_TEXT_T:
case PCB_TEXT_T:
case PCB_FP_TEXTBOX_T:
case PCB_TEXTBOX_T:
case PCB_FP_ZONE_T:
case PCB_ZONE_T:
case PCB_PAD_T:
// Only create undo entry for items on the board
if( !item->IsNew() && !IsFootprintEditor() )
m_commit->Modify( item );
break;
default:
continue;
}
@ -1333,43 +1339,38 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
switch( item->Type() )
{
case PCB_FP_SHAPE_T:
{
FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
shape->Mirror( mirrorPoint, mirrorAroundXaxis );
case PCB_SHAPE_T:
static_cast<PCB_SHAPE*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
break;
}
case PCB_FP_ZONE_T:
{
FP_ZONE* zone = static_cast<FP_ZONE*>( item );
zone->Mirror( mirrorPoint, mirrorLeftRight );
case PCB_ZONE_T:
static_cast<FP_ZONE*>( item )->Mirror( mirrorPoint, mirrorLeftRight );
break;
}
case PCB_FP_TEXT_T:
{
FP_TEXT* text = static_cast<FP_TEXT*>( item );
text->Mirror( mirrorPoint, mirrorAroundXaxis );
static_cast<FP_TEXT*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
break;
case PCB_TEXT_T:
static_cast<PCB_TEXT*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
break;
}
case PCB_FP_TEXTBOX_T:
{
FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( item );
textbox->Mirror( mirrorPoint, mirrorAroundXaxis );
static_cast<FP_TEXTBOX*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
break;
case PCB_TEXTBOX_T:
static_cast<PCB_TEXTBOX*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
break;
}
case PCB_PAD_T:
{
PAD* pad = static_cast<PAD*>( item );
if( mirrorLeftRight )
mirrorPadX( *pad, mirrorPoint );
mirrorPadX( *static_cast<PAD*>( item ), mirrorPoint );
else
mirrorPadY( *pad, mirrorPoint );
mirrorPadY( *static_cast<PAD*>( item ), mirrorPoint );
break;
}
default:
// it's likely the commit object is wrong if you get here

View File

@ -99,8 +99,7 @@ ZONE::~ZONE()
void ZONE::InitDataFromSrcInCopyCtor( const ZONE& aZone )
{
// members are expected non initialize in this.
// InitDataFromSrcInCopyCtor() is expected to be called
// only from a copy constructor.
// InitDataFromSrcInCopyCtor() is expected to be called only from a copy constructor.
// Copy only useful EDA_ITEM flags:
m_flags = aZone.m_flags;
@ -249,14 +248,6 @@ bool ZONE::IsOnCopperLayer() const
}
bool ZONE::CommonLayerExists( const LSET aLayerSet ) const
{
LSET common = GetLayerSet() & aLayerSet;
return common.count() > 0;
}
void ZONE::SetLayer( PCB_LAYER_ID aLayer )
{
SetLayerSet( LSET( aLayer ) );
@ -290,12 +281,6 @@ void ZONE::SetLayerSet( LSET aLayerSet )
}
LSET ZONE::GetLayerSet() const
{
return m_layerSet;
}
void ZONE::ViewGetLayers( int aLayers[], int& aCount ) const
{
LSEQ layers = m_layerSet.Seq();
@ -653,7 +638,6 @@ void ZONE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
void ZONE::Mirror( const VECTOR2I& aMirrorRef, bool aMirrorLeftRight )
{
// ZONEs mirror about the x-axis (why?!?)
m_Poly->Mirror( aMirrorLeftRight, !aMirrorLeftRight, aMirrorRef );
HatchBorder();

View File

@ -112,7 +112,7 @@ public:
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
void SetLayerSet( LSET aLayerSet ) override;
virtual LSET GetLayerSet() const override;
virtual LSET GetLayerSet() const override { return m_layerSet; }
wxString GetZoneName() const { return m_zoneName; }
void SetZoneName( const wxString& aName ) { m_zoneName = aName; }
@ -150,11 +150,6 @@ public:
*/
bool IsOnCopperLayer() const override;
/**
* Test if this zone shares a common layer with the given layer set.
*/
bool CommonLayerExists( const LSET aLayerSet ) const;
virtual void SetLayer( PCB_LAYER_ID aLayer ) override;
virtual PCB_LAYER_ID GetLayer() const override;