diff --git a/pcbnew/fp_shape.cpp b/pcbnew/fp_shape.cpp index d7614055e2..50a165a25b 100644 --- a/pcbnew/fp_shape.cpp +++ b/pcbnew/fp_shape.cpp @@ -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 diff --git a/pcbnew/fp_textbox.cpp b/pcbnew/fp_textbox.cpp index 74fd47b8b6..ee0692a1b1 100644 --- a/pcbnew/fp_textbox.cpp +++ b/pcbnew/fp_textbox.cpp @@ -33,6 +33,8 @@ #include #include #include +#include + 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 FP_TEXTBOX::GetCorners() const +{ + std::vector 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( 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 FP_TEXTBOX::GetAnchorAndOppositeCorner() const +std::vector FP_TEXTBOX::GetNormalizedCorners() const { - std::vector pts; std::vector 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 corners = GetAnchorAndOppositeCorner(); + std::vector 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 corners = GetAnchorAndOppositeCorner(); + std::vector 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 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 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 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; } } diff --git a/pcbnew/fp_textbox.h b/pcbnew/fp_textbox.h index 1abf2a9239..4c4a79fe7e 100644 --- a/pcbnew/fp_textbox.h +++ b/pcbnew/fp_textbox.h @@ -84,7 +84,8 @@ public: VECTOR2I GetDrawPos() const override; - std::vector GetAnchorAndOppositeCorner() const; + std::vector GetCorners() const override; + std::vector 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& aList ) override; bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override; diff --git a/pcbnew/pcb_shape.h b/pcbnew/pcb_shape.h index a03ff6cef2..0273dbb474 100644 --- a/pcbnew/pcb_shape.h +++ b/pcbnew/pcb_shape.h @@ -75,7 +75,7 @@ public: * Return 4 corners for a rectangle or rotated rectangle (stored as a poly). Unimplemented * for other shapes. */ - std::vector GetCorners() const; + virtual std::vector GetCorners() const; /** * Allows items to return their visual center rather than their anchor. For some shapes this