diff --git a/common/base_struct.cpp b/common/base_struct.cpp index 153f3ab999..6b8bbabdd4 100644 --- a/common/base_struct.cpp +++ b/common/base_struct.cpp @@ -792,6 +792,8 @@ static struct EDA_ITEM_DESC .Map( PCB_VIA_T, _( "Via" ) ) .Map( PCB_MARKER_T, _( "Board Marker" ) ) .Map( PCB_DIM_ALIGNED_T, _( "Aligned Dimension" ) ) + .Map( PCB_DIM_ORTHOGONAL_T, _( "Orthogonal Dimension" ) ) + .Map( PCB_DIM_CENTER_T, _( "Center Dimension" ) ) .Map( PCB_DIM_LEADER_T, _( "Leader" ) ) .Map( PCB_TARGET_T, _( "Target" ) ) .Map( PCB_ZONE_AREA_T, _( "Zone" ) ) diff --git a/common/pcb.keywords b/common/pcb.keywords index dd4e2493f1..eb3b6987da 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -184,6 +184,8 @@ np_thru_hole offset opacity options +orientation +orthogonal other_layers_line_width other_layers_text_dims oval diff --git a/pcbnew/class_dimension.cpp b/pcbnew/class_dimension.cpp index 1fdf6bbebd..4c08065223 100644 --- a/pcbnew/class_dimension.cpp +++ b/pcbnew/class_dimension.cpp @@ -456,8 +456,8 @@ static struct DIMENSION_DESC } _DIMENSION_DESC; -ALIGNED_DIMENSION::ALIGNED_DIMENSION( BOARD_ITEM* aParent ) : - DIMENSION( aParent, PCB_DIM_ALIGNED_T ), +ALIGNED_DIMENSION::ALIGNED_DIMENSION( BOARD_ITEM* aParent, KICAD_T aType ) : + DIMENSION( aParent, aType ), m_height( 0 ) { // To preserve look of old dimensions, initialize extension height based on default arrow length @@ -634,6 +634,176 @@ void ALIGNED_DIMENSION::updateText() } +ORTHOGONAL_DIMENSION::ORTHOGONAL_DIMENSION( BOARD_ITEM* aParent ) : + ALIGNED_DIMENSION( aParent, PCB_DIM_ORTHOGONAL_T ) +{ + // To preserve look of old dimensions, initialize extension height based on default arrow length + m_extensionHeight = static_cast( m_arrowLength * std::sin( DEG2RAD( s_arrowAngle ) ) ); +} + + +EDA_ITEM* ORTHOGONAL_DIMENSION::Clone() const +{ + return new ORTHOGONAL_DIMENSION( *this ); +} + + +void ORTHOGONAL_DIMENSION::SwapData( BOARD_ITEM* aImage ) +{ + assert( aImage->Type() == PCB_DIM_ORTHOGONAL_T ); + + m_shapes.clear(); + static_cast( aImage )->m_shapes.clear(); + + std::swap( *static_cast( this ), + *static_cast( aImage ) ); + + Update(); +} + + +BITMAP_DEF ORTHOGONAL_DIMENSION::GetMenuImage() const +{ + return add_orthogonal_dimension_xpm; +} + + +void ORTHOGONAL_DIMENSION::updateGeometry() +{ + m_shapes.clear(); + + int measurement = ( m_orientation == DIR::HORIZONTAL ? m_end.x - m_start.x : + m_end.y - m_start.y ); + m_measuredValue = KiROUND( std::abs( measurement ) ); + + VECTOR2I extension; + + if( m_orientation == DIR::HORIZONTAL ) + extension = VECTOR2I( 0, m_height ); + else + extension = VECTOR2I( m_height, 0 ); + + // Add first extension line + int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight; + + VECTOR2I extStart( m_start ); + extStart += extension.Resize( m_extensionOffset ); + + addShape( new SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) ); + + // Add crossbar + VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height ); + m_crossBarStart = m_start + wxPoint( crossBarDistance ); + + if( m_orientation == DIR::HORIZONTAL ) + m_crossBarEnd = wxPoint( m_end.x, m_crossBarStart.y ); + else + m_crossBarEnd = wxPoint( m_crossBarStart.x, m_end.y ); + + // Add second extension line (m_end to crossbar end) + if( m_orientation == DIR::HORIZONTAL ) + extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y ); + else + extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 ); + + extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight; + + extStart = VECTOR2I( m_crossBarEnd ); + extStart -= extension.Resize( m_extensionHeight ); + + addShape( new SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) ); + + // Update text after calculating crossbar position but before adding crossbar lines + updateText(); + + // Now that we have the text updated, we can determine how to draw the crossbar. + // First we need to create an appropriate bounding polygon to collide with + EDA_RECT textBox = m_text.GetTextBox().Inflate( m_text.GetTextWidth() / 2, + m_text.GetEffectiveTextPenWidth() ); + + SHAPE_POLY_SET polyBox; + polyBox.NewOutline(); + polyBox.Append( textBox.GetOrigin() ); + polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y ); + polyBox.Append( textBox.GetEnd() ); + polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y ); + polyBox.Rotate( -m_text.GetTextAngleRadians(), textBox.GetCenter() ); + + // The ideal crossbar, if the text doesn't collide + SEG crossbar( m_crossBarStart, m_crossBarEnd ); + + // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides + bool containsA = polyBox.Contains( crossbar.A ); + bool containsB = polyBox.Contains( crossbar.B ); + + OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar ); + OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false ); + + if( endpointA ) + m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) ); + + if( endpointB ) + m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) ); + + if( !containsA && !containsB && !endpointA && !endpointB ) + m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) ); + + // Add arrows + VECTOR2I crossBarAngle( m_crossBarEnd - m_crossBarStart ); + VECTOR2I arrowEnd( m_arrowLength, 0 ); + + double arrowRotPos = crossBarAngle.Angle() + DEG2RAD( s_arrowAngle ); + double arrowRotNeg = crossBarAngle.Angle() - DEG2RAD( s_arrowAngle ); + + m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, + m_crossBarStart + wxPoint( arrowEnd.Rotate( arrowRotPos ) ) ) ); + + m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, + m_crossBarStart + wxPoint( arrowEnd.Rotate( arrowRotNeg ) ) ) ); + + m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, + m_crossBarEnd - wxPoint( arrowEnd.Rotate( arrowRotPos ) ) ) ); + + m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, + m_crossBarEnd - wxPoint( arrowEnd.Rotate( arrowRotNeg ) ) ) ); +} + + +void ORTHOGONAL_DIMENSION::updateText() +{ + VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 ); + + if( m_textPosition == DIM_TEXT_POSITION::OUTSIDE ) + { + int textOffsetDistance = m_text.GetEffectiveTextPenWidth() + m_text.GetTextHeight(); + + double rotation = sign( m_height ) * DEG2RAD( -90 ); + VECTOR2I textOffset = crossbarCenter.Rotate( rotation ).Resize( textOffsetDistance ); + textOffset += crossbarCenter; + + m_text.SetTextPos( m_crossBarStart + wxPoint( textOffset ) ); + } + else if( m_textPosition == DIM_TEXT_POSITION::INLINE ) + { + m_text.SetTextPos( m_crossBarStart + wxPoint( crossbarCenter ) ); + } + + if( m_keepTextAligned ) + { + double textAngle = 3600 - RAD2DECIDEG( crossbarCenter.Angle() ); + + NORMALIZE_ANGLE_POS( textAngle ); + + if( textAngle > 900 && textAngle < 2700 ) + textAngle -= 1800; + + m_text.SetTextAngle( textAngle ); + } + + DIMENSION::updateText(); +} + + LEADER::LEADER( BOARD_ITEM* aParent ) : DIMENSION( aParent, PCB_DIM_LEADER_T ), m_textFrame( DIM_TEXT_FRAME::NONE ) diff --git a/pcbnew/class_dimension.h b/pcbnew/class_dimension.h index a77292c5df..2a7b816c44 100644 --- a/pcbnew/class_dimension.h +++ b/pcbnew/class_dimension.h @@ -347,6 +347,7 @@ protected: */ class ALIGNED_DIMENSION : public DIMENSION { +protected: // Geometry int m_height; ///< Perpendicular distance from features to crossbar int m_extensionHeight; ///< Length of extension lines past the crossbar @@ -355,7 +356,7 @@ class ALIGNED_DIMENSION : public DIMENSION wxPoint m_crossBarEnd; ///< Crossbar end control point public: - ALIGNED_DIMENSION( BOARD_ITEM* aParent ); + ALIGNED_DIMENSION( BOARD_ITEM* aParent, KICAD_T aType = PCB_DIM_ALIGNED_T ); // Do not create a copy constructor & operator=. // The ones generated by the compiler are adequate. @@ -418,6 +419,59 @@ protected: }; +/** + * An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the + * X or Y axes, and the measurement is only taken in the X or Y direction. + */ +class ORTHOGONAL_DIMENSION : public ALIGNED_DIMENSION +{ +public: + enum class DIR + { + HORIZONTAL, // Aligned with x-axis + VERTICAL // Aligned with y-axis + }; + +private: + // Geometry + DIR m_orientation; ///< What axis to lock the dimension line to + +public: + ORTHOGONAL_DIMENSION( BOARD_ITEM* aParent ); + + ~ORTHOGONAL_DIMENSION() = default; + + static inline bool ClassOf( const EDA_ITEM* aItem ) + { + return aItem && PCB_DIM_ORTHOGONAL_T == aItem->Type(); + } + + EDA_ITEM* Clone() const override; + + void SwapData( BOARD_ITEM* aImage ) override; + + BITMAP_DEF GetMenuImage() const override; + + /** + * Sets the orientation of the dimension line (so, perpendicular to the feature lines) + * @param aOrientation is the orientation the dimension should take + */ + void SetOrientation( DIR aOrientation ) { m_orientation = aOrientation; } + DIR GetOrientation() const { return m_orientation; } + + wxString GetClass() const override + { + return wxT( "ORTHOGONAL_DIMENSION" ); + } + +protected: + + void updateGeometry() override; + + void updateText() override; +}; + + /** * A leader is a dimension-like object pointing to a specific point. * diff --git a/pcbnew/collectors.cpp b/pcbnew/collectors.cpp index dd5de65f60..8afc43b878 100644 --- a/pcbnew/collectors.cpp +++ b/pcbnew/collectors.cpp @@ -71,6 +71,8 @@ const KICAD_T GENERAL_COLLECTOR::BoardLevelItems[] = { PCB_TEXT_T, PCB_LINE_T, PCB_DIM_ALIGNED_T, + PCB_DIM_ORTHOGONAL_T, + PCB_DIM_CENTER_T, PCB_DIM_LEADER_T, PCB_TARGET_T, PCB_VIA_T, @@ -88,6 +90,8 @@ const KICAD_T GENERAL_COLLECTOR::AllButZones[] = { PCB_TEXT_T, PCB_LINE_T, PCB_DIM_ALIGNED_T, + PCB_DIM_ORTHOGONAL_T, + PCB_DIM_CENTER_T, PCB_DIM_LEADER_T, PCB_TARGET_T, PCB_VIA_T, @@ -171,6 +175,8 @@ const KICAD_T GENERAL_COLLECTOR::Zones[] = { const KICAD_T GENERAL_COLLECTOR::Dimensions[] = { PCB_DIM_ALIGNED_T, PCB_DIM_LEADER_T, + PCB_DIM_ORTHOGONAL_T, + PCB_DIM_CENTER_T, EOT }; diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 56f9dc3fbc..fc1f1e2950 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -664,9 +664,10 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const { - ALIGNED_DIMENSION* aligned = dynamic_cast( aDimension ); - CENTER_DIMENSION* center = dynamic_cast( aDimension ); - LEADER* leader = dynamic_cast( aDimension ); + ALIGNED_DIMENSION* aligned = dynamic_cast( aDimension ); + ORTHOGONAL_DIMENSION* ortho = dynamic_cast( aDimension ); + CENTER_DIMENSION* center = dynamic_cast( aDimension ); + LEADER* leader = dynamic_cast( aDimension ); m_out->Print( aNestLevel, "(dimension" ); @@ -676,6 +677,8 @@ void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const m_out->Print( 0, " (type leader)" ); else if( aDimension->Type() == PCB_DIM_CENTER_T ) m_out->Print( 0, " (type center)" ); + else if( aDimension->Type() == PCB_DIM_ORTHOGONAL_T ) + m_out->Print( 0, " (type orthogonal)" ); else wxFAIL_MSG( wxT( "Cannot format unknown dimension type!" ) ); @@ -695,6 +698,10 @@ void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const m_out->Print( aNestLevel+1, "(height %s)\n", FormatInternalUnits( aligned->GetHeight() ).c_str() ); + if( ortho ) + m_out->Print( aNestLevel+1, "(orientation %d)\n", + static_cast( ortho->GetOrientation() ) ); + if( !center ) { Format( &aDimension->Text(), aNestLevel + 1 ); diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h index 609f2ea20d..3b39d56d98 100644 --- a/pcbnew/kicad_plugin.h +++ b/pcbnew/kicad_plugin.h @@ -85,7 +85,8 @@ class TEXTE_PCB; //#define SEXPR_BOARD_FILE_VERSION 20200829 // Remove library name from exported footprints //#define SEXPR_BOARD_FILE_VERSION 20200909 // Change DIMENSION format //#define SEXPR_BOARD_FILE_VERSION 20200913 // Add leader dimension -#define SEXPR_BOARD_FILE_VERSION 20200916 // Add center dimension +//#define SEXPR_BOARD_FILE_VERSION 20200916 // Add center dimension +#define SEXPR_BOARD_FILE_VERSION 20200921 // Add orthogonal dimension #define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag diff --git a/pcbnew/menubar_pcb_editor.cpp b/pcbnew/menubar_pcb_editor.cpp index e0fa3b5ebd..3a7d6926cd 100644 --- a/pcbnew/menubar_pcb_editor.cpp +++ b/pcbnew/menubar_pcb_editor.cpp @@ -321,6 +321,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() placeMenu->AppendSeparator(); placeMenu->Add( PCB_ACTIONS::drawAlignedDimension ); + placeMenu->Add( PCB_ACTIONS::drawOrthogonalDimension ); placeMenu->Add( PCB_ACTIONS::drawCenterDimension ); placeMenu->Add( PCB_ACTIONS::drawLeader ); diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 010ecea937..46b066a4f6 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -742,6 +742,7 @@ void PCB_EDIT_FRAME::setupUIConditions() CURRENT_EDIT_TOOL( PCB_ACTIONS::drawPolygon ); CURRENT_EDIT_TOOL( PCB_ACTIONS::placeText ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawAlignedDimension ); + CURRENT_EDIT_TOOL( PCB_ACTIONS::drawOrthogonalDimension ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawCenterDimension ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawLeader ); CURRENT_EDIT_TOOL( PCB_ACTIONS::placeTarget ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 74e95fdff0..475c9cb4b4 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2383,6 +2383,10 @@ DIMENSION* PCB_PARSER::parseDIMENSION() dimension = std::make_unique( nullptr ); break; + case T_orthogonal: + dimension = std::make_unique( nullptr ); + break; + case T_leader: dimension = std::make_unique( nullptr ); break; @@ -2458,7 +2462,8 @@ DIMENSION* PCB_PARSER::parseDIMENSION() case T_height: { - wxCHECK_MSG( dimension->Type() == PCB_DIM_ALIGNED_T, nullptr, + wxCHECK_MSG( dimension->Type() == PCB_DIM_ALIGNED_T || + dimension->Type() == PCB_DIM_ORTHOGONAL_T, nullptr, wxT( "Invalid height token" ) ); ALIGNED_DIMENSION* aligned = static_cast( dimension.get() ); aligned->SetHeight( parseBoardUnits( "dimension height value" ) ); @@ -2466,6 +2471,19 @@ DIMENSION* PCB_PARSER::parseDIMENSION() break; } + case T_orientation: + { + wxCHECK_MSG( dimension->Type() == PCB_DIM_ORTHOGONAL_T, nullptr, + wxT( "Invalid orientation token" ) ); + ORTHOGONAL_DIMENSION* ortho = static_cast( dimension.get() ); + + int orientation = parseInt( "orthogonal dimension orientation" ); + orientation = std::max( 0, std::min( 1, orientation ) ); + ortho->SetOrientation( static_cast( orientation ) ); + NeedRIGHT(); + break; + } + case T_format: { for( token = NextTok(); token != T_RIGHT; token = NextTok() ) @@ -2562,9 +2580,8 @@ DIMENSION* PCB_PARSER::parseDIMENSION() case T_extension_height: { - wxCHECK_MSG( dimension->Type() == PCB_DIM_ALIGNED_T, nullptr, - wxT( "Invalid extension_height token" ) ); - ALIGNED_DIMENSION* aligned = static_cast( dimension.get() ); + ALIGNED_DIMENSION* aligned = dynamic_cast( dimension.get() ); + wxCHECK_MSG( aligned, nullptr, wxT( "Invalid extension_height token" ) ); aligned->SetExtensionHeight( parseBoardUnits( "extension height" ) ); NeedRIGHT(); break; diff --git a/pcbnew/swig/board_item.i b/pcbnew/swig/board_item.i index f0c90e1f83..6a23d175cb 100644 --- a/pcbnew/swig/board_item.i +++ b/pcbnew/swig/board_item.i @@ -49,6 +49,7 @@ %{ class TEXTE_PCB; class ALIGNED_DIMENSION; +class ORTHOGONAL_DIMENSION; class LEADER; class CENTER_DIMENSION; class MODULE; @@ -70,22 +71,23 @@ class PCB_TARGET; extern "C" { #endif -static TEXTE_PCB* Cast_to_TEXTE_PCB( BOARD_ITEM* ); -static ALIGNED_DIMENSION* Cast_to_ALIGNED_DIMENSION( BOARD_ITEM* ); -static LEADER* Cast_to_LEADER( BOARD_ITEM* ); -static CENTER_DIMENSION* Cast_to_CENTER_DIMENSION( BOARD_ITEM* ); -static MODULE* Cast_to_MODULE( BOARD_ITEM* ); -static PCB_GROUP* Cast_to_PCB_GROUP( BOARD_ITEM* ); -static TEXTE_MODULE* Cast_to_TEXTE_MODULE( BOARD_ITEM* ); -static DRAWSEGMENT* Cast_to_DRAWSEGMENT( BOARD_ITEM* ); -static MARKER_PCB* Cast_to_MARKER_PCB( BOARD_ITEM* ); -static BOARD* Cast_to_BOARD( BOARD_ITEM* ); -static EDGE_MODULE* Cast_to_EDGE_MODULE( BOARD_ITEM* ); -static D_PAD* Cast_to_D_PAD( BOARD_ITEM* ); -static TRACK* Cast_to_TRACK( BOARD_ITEM* ); -static VIA* Cast_to_VIA( BOARD_ITEM* ); -static ZONE_CONTAINER* Cast_to_ZONE_CONTAINER( BOARD_ITEM* ); -static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* ); +static TEXTE_PCB* Cast_to_TEXTE_PCB( BOARD_ITEM* ); +static ALIGNED_DIMENSION* Cast_to_ALIGNED_DIMENSION( BOARD_ITEM* ); +static ORTHOGONAL_DIMENSION* Cast_to_ORTHOGONAL_DIMENSION( BOARD_ITEM* ); +static LEADER* Cast_to_LEADER( BOARD_ITEM* ); +static CENTER_DIMENSION* Cast_to_CENTER_DIMENSION( BOARD_ITEM* ); +static MODULE* Cast_to_MODULE( BOARD_ITEM* ); +static PCB_GROUP* Cast_to_PCB_GROUP( BOARD_ITEM* ); +static TEXTE_MODULE* Cast_to_TEXTE_MODULE( BOARD_ITEM* ); +static DRAWSEGMENT* Cast_to_DRAWSEGMENT( BOARD_ITEM* ); +static MARKER_PCB* Cast_to_MARKER_PCB( BOARD_ITEM* ); +static BOARD* Cast_to_BOARD( BOARD_ITEM* ); +static EDGE_MODULE* Cast_to_EDGE_MODULE( BOARD_ITEM* ); +static D_PAD* Cast_to_D_PAD( BOARD_ITEM* ); +static TRACK* Cast_to_TRACK( BOARD_ITEM* ); +static VIA* Cast_to_VIA( BOARD_ITEM* ); +static ZONE_CONTAINER* Cast_to_ZONE_CONTAINER( BOARD_ITEM* ); +static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* ); #ifdef __cplusplus } // extern "C" @@ -93,22 +95,23 @@ static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* ); %} -static TEXTE_PCB* Cast_to_TEXTE_PCB( BOARD_ITEM* ); -static ALIGNED_DIMENSION* Cast_to_ALIGNED_DIMENSION( BOARD_ITEM* ); -static LEADER* Cast_to_LEADER( BOARD_ITEM* ); -static CENTER_DIMENSION* Cast_to_CENTER_DIMENSION( BOARD_ITEM* ); -static MODULE* Cast_to_MODULE( BOARD_ITEM* ); -static PCB_GROUP* Cast_to_PCB_GROUP( BOARD_ITEM* ); -static TEXTE_MODULE* Cast_to_TEXTE_MODULE( BOARD_ITEM* ); -static DRAWSEGMENT* Cast_to_DRAWSEGMENT( BOARD_ITEM* ); -static MARKER_PCB* Cast_to_MARKER_PCB( BOARD_ITEM* ); -static BOARD* Cast_to_BOARD( BOARD_ITEM* ); -static EDGE_MODULE* Cast_to_EDGE_MODULE( BOARD_ITEM* ); -static D_PAD* Cast_to_D_PAD( BOARD_ITEM* ); -static TRACK* Cast_to_TRACK( BOARD_ITEM* ); -static VIA* Cast_to_VIA( BOARD_ITEM* ); -static ZONE_CONTAINER* Cast_to_ZONE_CONTAINER( BOARD_ITEM* ); -static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* ); +static TEXTE_PCB* Cast_to_TEXTE_PCB( BOARD_ITEM* ); +static ALIGNED_DIMENSION* Cast_to_ALIGNED_DIMENSION( BOARD_ITEM* ); +static ORTHOGONAL_DIMENSION* Cast_to_ORTHOGONAL_DIMENSION( BOARD_ITEM* ); +static LEADER* Cast_to_LEADER( BOARD_ITEM* ); +static CENTER_DIMENSION* Cast_to_CENTER_DIMENSION( BOARD_ITEM* ); +static MODULE* Cast_to_MODULE( BOARD_ITEM* ); +static PCB_GROUP* Cast_to_PCB_GROUP( BOARD_ITEM* ); +static TEXTE_MODULE* Cast_to_TEXTE_MODULE( BOARD_ITEM* ); +static DRAWSEGMENT* Cast_to_DRAWSEGMENT( BOARD_ITEM* ); +static MARKER_PCB* Cast_to_MARKER_PCB( BOARD_ITEM* ); +static BOARD* Cast_to_BOARD( BOARD_ITEM* ); +static EDGE_MODULE* Cast_to_EDGE_MODULE( BOARD_ITEM* ); +static D_PAD* Cast_to_D_PAD( BOARD_ITEM* ); +static TRACK* Cast_to_TRACK( BOARD_ITEM* ); +static VIA* Cast_to_VIA( BOARD_ITEM* ); +static ZONE_CONTAINER* Cast_to_ZONE_CONTAINER( BOARD_ITEM* ); +static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* ); %extend BOARD_ITEM @@ -129,6 +132,8 @@ static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* ); return Cast_to_LEADER(self) elif ct=="CENTER_DIMENSION": return Cast_to_CENTER_DIMENSION(self) + elif ct=="ORTHOGONAL_DIMENSION": + return Cast_to_ORTHOGONAL_DIMENSION(self) elif ct=="DRAWSEGMENT": return Cast_to_DRAWSEGMENT(self) elif ct=="MGRAPHIC": @@ -177,20 +182,21 @@ static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* ); // classes and therefore will C++ compile due to the respective headers which will go into // the %header section. See section 5.6.2 of SWIG 3.0 documentation. %wrapper %{ -static TEXTE_PCB* Cast_to_TEXTE_PCB( BOARD_ITEM* self ) { return dynamic_cast(self); } -static ALIGNED_DIMENSION* Cast_to_ALIGNED_DIMENSION( BOARD_ITEM* self ) { return dynamic_cast(self); } -static LEADER* Cast_to_LEADER( BOARD_ITEM* self ) { return dynamic_cast(self); } -static CENTER_DIMENSION* Cast_to_CENTER_DIMENSION( BOARD_ITEM* self ) { return dynamic_cast(self); } -static MODULE* Cast_to_MODULE( BOARD_ITEM* self ) { return dynamic_cast(self); } -static PCB_GROUP* Cast_to_PCB_GROUP( BOARD_ITEM* self ) { return dynamic_cast(self); } -static TEXTE_MODULE* Cast_to_TEXTE_MODULE( BOARD_ITEM* self ) { return dynamic_cast(self); } -static DRAWSEGMENT* Cast_to_DRAWSEGMENT( BOARD_ITEM* self ) { return dynamic_cast(self); } -static MARKER_PCB* Cast_to_MARKER_PCB( BOARD_ITEM* self ) { return dynamic_cast(self); } -static BOARD* Cast_to_BOARD( BOARD_ITEM* self ) { return dynamic_cast(self); } -static EDGE_MODULE* Cast_to_EDGE_MODULE( BOARD_ITEM* self ) { return dynamic_cast(self); } -static D_PAD* Cast_to_D_PAD( BOARD_ITEM* self ) { return dynamic_cast(self); } -static TRACK* Cast_to_TRACK( BOARD_ITEM* self ) { return dynamic_cast(self); } -static VIA* Cast_to_VIA( BOARD_ITEM* self ) { return dynamic_cast(self); } -static ZONE_CONTAINER* Cast_to_ZONE_CONTAINER( BOARD_ITEM* self ) { return dynamic_cast(self); } -static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* self ) { return dynamic_cast(self); } +static TEXTE_PCB* Cast_to_TEXTE_PCB( BOARD_ITEM* self ) { return dynamic_cast(self); } +static ALIGNED_DIMENSION* Cast_to_ALIGNED_DIMENSION( BOARD_ITEM* self ) { return dynamic_cast(self); } +static ORTHOGONAL_DIMENSION* Cast_to_ORTHOGONAL_DIMENSION( BOARD_ITEM* self ) { return dynamic_cast(self); } +static LEADER* Cast_to_LEADER( BOARD_ITEM* self ) { return dynamic_cast(self); } +static CENTER_DIMENSION* Cast_to_CENTER_DIMENSION( BOARD_ITEM* self ) { return dynamic_cast(self); } +static MODULE* Cast_to_MODULE( BOARD_ITEM* self ) { return dynamic_cast(self); } +static PCB_GROUP* Cast_to_PCB_GROUP( BOARD_ITEM* self ) { return dynamic_cast(self); } +static TEXTE_MODULE* Cast_to_TEXTE_MODULE( BOARD_ITEM* self ) { return dynamic_cast(self); } +static DRAWSEGMENT* Cast_to_DRAWSEGMENT( BOARD_ITEM* self ) { return dynamic_cast(self); } +static MARKER_PCB* Cast_to_MARKER_PCB( BOARD_ITEM* self ) { return dynamic_cast(self); } +static BOARD* Cast_to_BOARD( BOARD_ITEM* self ) { return dynamic_cast(self); } +static EDGE_MODULE* Cast_to_EDGE_MODULE( BOARD_ITEM* self ) { return dynamic_cast(self); } +static D_PAD* Cast_to_D_PAD( BOARD_ITEM* self ) { return dynamic_cast(self); } +static TRACK* Cast_to_TRACK( BOARD_ITEM* self ) { return dynamic_cast(self); } +static VIA* Cast_to_VIA( BOARD_ITEM* self ) { return dynamic_cast(self); } +static ZONE_CONTAINER* Cast_to_ZONE_CONTAINER( BOARD_ITEM* self ) { return dynamic_cast(self); } +static PCB_TARGET* Cast_to_PCB_TARGET( BOARD_ITEM* self ) { return dynamic_cast(self); } %} diff --git a/pcbnew/toolbars_pcb_editor.cpp b/pcbnew/toolbars_pcb_editor.cpp index 6aea39a62f..b6597d185c 100644 --- a/pcbnew/toolbars_pcb_editor.cpp +++ b/pcbnew/toolbars_pcb_editor.cpp @@ -380,6 +380,7 @@ void PCB_EDIT_FRAME::ReCreateVToolbar() m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::drawAlignedDimension, ACTION_TOOLBAR::TOGGLE ); // TODO: re-insert when we have a multi-select tool button + // m_drawToolBar->Add( PCB_ACTIONS::drawOrthogonalDimension, ACTION_TOOLBAR::TOGGLE ); // m_drawToolBar->Add( PCB_ACTIONS::drawCenterDimension, ACTION_TOOLBAR::TOGGLE ); // m_drawToolBar->Add( PCB_ACTIONS::drawLeader, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::placeTarget, ACTION_TOOLBAR::TOGGLE ); diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index afc27f9662..d4e47015ee 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -731,19 +731,29 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) layer = Dwgs_User; // Init the new item attributes + auto setMeasurementAttributes = + [&]( DIMENSION* aDim ) + { + aDim->SetUnitsMode( boardSettings.m_DimensionUnitsMode ); + aDim->SetUnitsFormat( boardSettings.m_DimensionUnitsFormat ); + aDim->SetPrecision( boardSettings.m_DimensionPrecision ); + aDim->SetSuppressZeroes( boardSettings.m_DimensionSuppressZeroes ); + aDim->SetTextPositionMode( boardSettings.m_DimensionTextPosition ); + aDim->SetKeepTextAligned( boardSettings.m_DimensionKeepTextAligned ); + + if( boardSettings.m_DimensionUnitsMode == DIM_UNITS_MODE::AUTOMATIC ) + aDim->SetUnits( m_frame->GetUserUnits(), false ); + }; + if( originalEvent.IsAction( &PCB_ACTIONS::drawAlignedDimension ) ) { dimension = new ALIGNED_DIMENSION( m_board ); - - dimension->SetUnitsMode( boardSettings.m_DimensionUnitsMode ); - dimension->SetUnitsFormat( boardSettings.m_DimensionUnitsFormat ); - dimension->SetPrecision( boardSettings.m_DimensionPrecision ); - dimension->SetSuppressZeroes( boardSettings.m_DimensionSuppressZeroes ); - dimension->SetTextPositionMode( boardSettings.m_DimensionTextPosition ); - dimension->SetKeepTextAligned( boardSettings.m_DimensionKeepTextAligned ); - - if( boardSettings.m_DimensionUnitsMode == DIM_UNITS_MODE::AUTOMATIC ) - dimension->SetUnits( m_frame->GetUserUnits(), false ); + setMeasurementAttributes( dimension ); + } + else if( originalEvent.IsAction( &PCB_ACTIONS::drawOrthogonalDimension ) ) + { + dimension = new ORTHOGONAL_DIMENSION( m_board ); + setMeasurementAttributes( dimension ); } else if( originalEvent.IsAction( &PCB_ACTIONS::drawCenterDimension ) ) { @@ -863,10 +873,32 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) ); aligned->SetHeight( height ); } - else if( dimension->Type() != PCB_DIM_CENTER_T ) + else if( dimension->Type() == PCB_DIM_ORTHOGONAL_T ) { - wxASSERT( dimension->Type() == PCB_DIM_LEADER_T ); + ORTHOGONAL_DIMENSION* ortho = static_cast( dimension ); + BOX2I bounds( dimension->GetStart(), + dimension->GetEnd() - dimension->GetStart() ); + VECTOR2I direction( cursorPos - bounds.Centre() ); + bool vert = std::abs( direction.y ) < std::abs( direction.x ); + + // Only change the orientation when we move outside the bounds + if( !bounds.Contains( cursorPos ) ) + { + ortho->SetOrientation( vert ? ORTHOGONAL_DIMENSION::DIR::VERTICAL : + ORTHOGONAL_DIMENSION::DIR::HORIZONTAL ); + } + else + { + vert = ortho->GetOrientation() == ORTHOGONAL_DIMENSION::DIR::VERTICAL; + } + + VECTOR2I heightVector( cursorPos - dimension->GetStart() ); + ortho->SetHeight( vert ? heightVector.x : heightVector.y ); + } + else if( dimension->Type() == PCB_DIM_LEADER_T ) + { + // Leader: SET_HEIGHT actually sets the text position directly VECTOR2I lineVector( cursorPos - dimension->GetEnd() ); dimension->Text().SetPosition( wxPoint( VECTOR2I( dimension->GetEnd() ) + GetVectorSnapped45( lineVector ) ) ); @@ -2176,6 +2208,7 @@ void DRAWING_TOOL::setTransitions() Go( &DRAWING_TOOL::DrawCircle, PCB_ACTIONS::drawCircle.MakeEvent() ); Go( &DRAWING_TOOL::DrawArc, PCB_ACTIONS::drawArc.MakeEvent() ); Go( &DRAWING_TOOL::DrawDimension, PCB_ACTIONS::drawAlignedDimension.MakeEvent() ); + Go( &DRAWING_TOOL::DrawDimension, PCB_ACTIONS::drawOrthogonalDimension.MakeEvent() ); Go( &DRAWING_TOOL::DrawDimension, PCB_ACTIONS::drawCenterDimension.MakeEvent() ); Go( &DRAWING_TOOL::DrawDimension, PCB_ACTIONS::drawLeader.MakeEvent() ); Go( &DRAWING_TOOL::DrawZone, PCB_ACTIONS::drawZone.MakeEvent() ); diff --git a/pcbnew/tools/grid_helper.cpp b/pcbnew/tools/grid_helper.cpp index f5c47caf45..c95d1bc0de 100644 --- a/pcbnew/tools/grid_helper.cpp +++ b/pcbnew/tools/grid_helper.cpp @@ -547,6 +547,7 @@ void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bo } case PCB_DIM_ALIGNED_T: + case PCB_DIM_ORTHOGONAL_T: { const ALIGNED_DIMENSION* dim = static_cast( aItem ); addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem ); diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 7d4dc5a512..7e8852ac4e 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -127,6 +127,11 @@ TOOL_ACTION PCB_ACTIONS::drawCenterDimension( "pcbnew.InteractiveDrawing.centerD _( "Add Center Dimension" ), _( "Add a center dimension" ), add_center_dimension_xpm, AF_ACTIVATE ); +TOOL_ACTION PCB_ACTIONS::drawOrthogonalDimension( "pcbnew.InteractiveDrawing.orthogonalDimension", + AS_GLOBAL, 0, "", + _( "Add Orthogonal Dimension" ), _( "Add an orthogonal dimension" ), + add_orthogonal_dimension_xpm, AF_ACTIVATE ); + TOOL_ACTION PCB_ACTIONS::drawLeader( "pcbnew.InteractiveDrawing.leader", AS_GLOBAL, 0, "", _( "Add Leader" ), _( "Add a leader dimension" ), diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 93e341395f..a5c2495b80 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -144,6 +144,7 @@ public: static TOOL_ACTION placeText; static TOOL_ACTION drawAlignedDimension; static TOOL_ACTION drawCenterDimension; + static TOOL_ACTION drawOrthogonalDimension; static TOOL_ACTION drawLeader; static TOOL_ACTION drawZone; static TOOL_ACTION drawVia; diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp index 629fcf4e5f..43dfba4001 100644 --- a/pcbnew/tools/point_editor.cpp +++ b/pcbnew/tools/point_editor.cpp @@ -245,6 +245,7 @@ public: break; case PCB_DIM_ALIGNED_T: + case PCB_DIM_ORTHOGONAL_T: { const ALIGNED_DIMENSION* dimension = static_cast( aItem ); @@ -254,11 +255,16 @@ public: points->AddPoint( dimension->GetCrossbarStart() ); points->AddPoint( dimension->GetCrossbarEnd() ); - // Dimension height setting - edit points should move only along the feature lines - points->Point( DIM_CROSSBARSTART ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARSTART ), - points->Point( DIM_START ) ) ); - points->Point( DIM_CROSSBAREND ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBAREND ), - points->Point( DIM_END ) ) ); + if( aItem->Type() == PCB_DIM_ALIGNED_T ) + { + // Dimension height setting - edit points should move only along the feature lines + points->Point( DIM_CROSSBARSTART ) + .SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARSTART ), + points->Point( DIM_START ) ) ); + points->Point( DIM_CROSSBAREND ) + .SetConstraint( new EC_LINE( points->Point( DIM_CROSSBAREND ), + points->Point( DIM_END ) ) ); + } break; } @@ -1336,6 +1342,52 @@ void POINT_EDITOR::updateItem() const break; } + case PCB_DIM_ORTHOGONAL_T: + { + ORTHOGONAL_DIMENSION* dimension = static_cast( item ); + + BOX2I bounds( dimension->GetStart(), + dimension->GetEnd() - dimension->GetStart() ); + + VECTOR2I direction( m_editedPoint->GetPosition() - bounds.Centre() ); + bool vert = std::abs( direction.y ) < std::abs( direction.x ); + VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetStart() ); + + if( isModified( m_editPoints->Point( DIM_CROSSBARSTART ) ) || + isModified( m_editPoints->Point( DIM_CROSSBAREND ) ) ) + { + // Only change the orientation when we move outside the bounds + if( !bounds.Contains( m_editedPoint->GetPosition() ) ) + { + dimension->SetOrientation( vert ? ORTHOGONAL_DIMENSION::DIR::VERTICAL : + ORTHOGONAL_DIMENSION::DIR::HORIZONTAL ); + } + + vert = dimension->GetOrientation() == ORTHOGONAL_DIMENSION::DIR::VERTICAL; + + dimension->SetHeight( vert ? featureLine.x : featureLine.y ); + } + else if( isModified( m_editPoints->Point( DIM_START ) ) ) + { + dimension->SetStart( wxPoint( m_editedPoint->GetPosition().x, + m_editedPoint->GetPosition().y ) ); + } + else if( isModified( m_editPoints->Point( DIM_END ) ) ) + { + dimension->SetEnd( wxPoint( m_editedPoint->GetPosition().x, + m_editedPoint->GetPosition().y ) ); + } + else if( isModified( m_editPoints->Point(DIM_TEXT ) ) ) + { + // Force manual mode if we weren't already in it + dimension->SetTextPositionMode( DIM_TEXT_POSITION::MANUAL ); + dimension->Text().SetPosition( wxPoint( m_editedPoint->GetPosition() ) ); + dimension->Update(); + } + + break; + } + case PCB_DIM_CENTER_T: { CENTER_DIMENSION* dimension = static_cast( item ); @@ -1601,6 +1653,7 @@ void POINT_EDITOR::updatePoints() } case PCB_DIM_ALIGNED_T: + case PCB_DIM_ORTHOGONAL_T: { const ALIGNED_DIMENSION* dimension = static_cast( item );