diff --git a/api/proto/board/board_types.proto b/api/proto/board/board_types.proto index 2d7d857914..02212c6387 100644 --- a/api/proto/board/board_types.proto +++ b/api/proto/board/board_types.proto @@ -599,9 +599,89 @@ message Zone kiapi.common.types.LockedState locked = 12; } +// An aligned dimension is drawn parallel to the line segment between the start and end points +message AlignedDimensionAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 end = 2; + + // Perpendicular distance from dimension endpoints to crossbar + kiapi.common.types.Distance height = 3; + + // Length of extension lines past the crossbar + kiapi.common.types.Distance extension_height = 4; +} + +// An orthogonal dimension is drawn parallel to the X or Y axis of the coordinate system +message OrthogonalDimensionAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 end = 2; + + // Perpendicular distance from dimension endpoints to crossbar + kiapi.common.types.Distance height = 3; + + // Length of extension lines past the crossbar + kiapi.common.types.Distance extension_height = 4; + + // Which axis the dimension is parallel to + kiapi.common.types.AxisAlignment alignment = 5; +} + +message RadialDimensionAttributes +{ + // The center of the dimensioned circle or arc + kiapi.common.types.Vector2 center = 1; + + // A point on the radius of the circle or arc + kiapi.common.types.Vector2 radius_point = 2; + + // The distance from radius_point to draw the first segment of the leader line. + // The second segment is drawn from the end of the first segment to the text position. + kiapi.common.types.Distance leader_length = 3; +} + +// The style of the optional frame applied to dimension text +enum DimensionTextBorderStyle +{ + DTBS_UNKNOWN = 0; + DTBS_NONE = 1; + DTBS_RECTANGLE = 2; + DTBS_CIRCLE = 3; + DTBS_ROUNDRECT = 4; +} + +message LeaderDimensionAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 end = 2; + DimensionTextBorderStyle border_style = 3; +} + +message CenterDimensionAttributes +{ + kiapi.common.types.Vector2 center = 1; + + // A point on the end of one of the four radial spokes drawn from the center point + kiapi.common.types.Vector2 end = 2; +} + +// A dimension in KiCad is a special type of text object. +// To know the visual appearance of the dimension as rendered by KiCad, use GetTextAsShapes message Dimension { - // TODO + kiapi.common.types.KIID id = 1; + kiapi.common.types.LockedState locked = 2; + BoardLayer layer = 3; + kiapi.common.types.Text text = 4; + + oneof dimension_style { + AlignedDimensionAttributes aligned = 5; + OrthogonalDimensionAttributes orthogonal = 6; + RadialDimensionAttributes radial = 7; + LeaderDimensionAttributes leader = 8; + CenterDimensionAttributes center = 9; + } } message ReferenceImage @@ -626,12 +706,6 @@ message Field BoardText text = 3; } -message Model3D -{ - // TODO -} - - enum FootprintMountingStyle { FMS_UNKNOWN = 0; @@ -640,7 +714,6 @@ enum FootprintMountingStyle FMS_UNSPECIFIED = 3; } - message FootprintAttributes { string description = 1; diff --git a/api/proto/common/types/base_types.proto b/api/proto/common/types/base_types.proto index 445db81684..a9666a47f9 100644 --- a/api/proto/common/types/base_types.proto +++ b/api/proto/common/types/base_types.proto @@ -431,3 +431,10 @@ message TitleBlockInfo string comment8 = 12; string comment9 = 13; } + +enum AxisAlignment +{ + AA_UNKNOWN = 0; + AA_X_AXIS = 1; + AA_Y_AXIS = 2; +} diff --git a/pcbnew/api/api_handler_pcb.cpp b/pcbnew/api/api_handler_pcb.cpp index d503fda39e..34f3f6f6bf 100644 --- a/pcbnew/api/api_handler_pcb.cpp +++ b/pcbnew/api/api_handler_pcb.cpp @@ -274,6 +274,22 @@ HANDLER_RESULT API_HANDLER_PCB::handleCreateUpdateItemsIntern continue; } + if( type == PCB_DIMENSION_T ) + { + board::types::Dimension dimension; + anyItem.UnpackTo( &dimension ); + + switch( dimension.dimension_style_case() ) + { + case board::types::Dimension::kAligned: type = PCB_DIM_ALIGNED_T; break; + case board::types::Dimension::kOrthogonal: type = PCB_DIM_ORTHOGONAL_T; break; + case board::types::Dimension::kRadial: type = PCB_DIM_RADIAL_T; break; + case board::types::Dimension::kLeader: type = PCB_DIM_LEADER_T; break; + case board::types::Dimension::kCenter: type = PCB_DIM_CENTER_T; break; + case board::types::Dimension::DIMENSION_STYLE_NOT_SET: break; + } + } + HANDLER_RESULT> creationResult = createItemForType( *type, container ); diff --git a/pcbnew/api/api_pcb_enums.cpp b/pcbnew/api/api_pcb_enums.cpp index 6031885005..8372ddcb51 100644 --- a/pcbnew/api/api_pcb_enums.cpp +++ b/pcbnew/api/api_pcb_enums.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -441,4 +442,39 @@ TEARDROP_TYPE FromProtoEnum( types::TeardropType aValue ) } } + +template<> +types::DimensionTextBorderStyle ToProtoEnum( DIM_TEXT_BORDER aValue ) +{ + switch( aValue ) + { + case DIM_TEXT_BORDER::NONE: return types::DimensionTextBorderStyle::DTBS_NONE; + case DIM_TEXT_BORDER::RECTANGLE: return types::DimensionTextBorderStyle::DTBS_RECTANGLE; + case DIM_TEXT_BORDER::CIRCLE: return types::DimensionTextBorderStyle::DTBS_CIRCLE; + case DIM_TEXT_BORDER::ROUNDRECT: return types::DimensionTextBorderStyle::DTBS_ROUNDRECT; + + default: + wxCHECK_MSG( false, types::DimensionTextBorderStyle::DTBS_UNKNOWN, + "Unhandled case in ToProtoEnum"); + } +} + + +template<> +DIM_TEXT_BORDER FromProtoEnum( types::DimensionTextBorderStyle aValue ) +{ + switch( aValue ) + { + case types::DimensionTextBorderStyle::DTBS_NONE: return DIM_TEXT_BORDER::NONE; + case types::DimensionTextBorderStyle::DTBS_RECTANGLE: return DIM_TEXT_BORDER::RECTANGLE; + case types::DimensionTextBorderStyle::DTBS_CIRCLE: return DIM_TEXT_BORDER::CIRCLE; + case types::DimensionTextBorderStyle::DTBS_ROUNDRECT: return DIM_TEXT_BORDER::ROUNDRECT; + + default: + wxCHECK_MSG( false, DIM_TEXT_BORDER::NONE, + "Unhandled case in FromProtoEnum" ); + } +} + + // Adding something new here? Add it to test_api_enums.cpp! diff --git a/pcbnew/pcb_dimension.cpp b/pcbnew/pcb_dimension.cpp index f84ae11d12..3be55cab35 100644 --- a/pcbnew/pcb_dimension.cpp +++ b/pcbnew/pcb_dimension.cpp @@ -39,6 +39,9 @@ #include #include #include +#include +#include +#include static const int INWARD_ARROW_LENGTH_TO_HEAD_RATIO = 2; @@ -250,6 +253,50 @@ double PCB_DIMENSION_BASE::Similarity( const BOARD_ITEM& aOther ) const } +void PCB_DIMENSION_BASE::Serialize( google::protobuf::Any &aContainer ) const +{ + using namespace kiapi::common; + kiapi::board::types::Dimension dimension; + + dimension.mutable_id()->set_value( m_Uuid.AsStdString() ); + dimension.set_layer( ToProtoEnum( GetLayer() ) ); + dimension.set_locked( IsLocked() ? types::LockedState::LS_LOCKED + : types::LockedState::LS_UNLOCKED ); + + google::protobuf::Any any; + EDA_TEXT::Serialize( any ); + any.UnpackTo( dimension.mutable_text() ); + + types::Text* text = dimension.mutable_text(); + PackVector2( *text->mutable_position(), GetPosition() ); + + aContainer.PackFrom( dimension ); +} + + +bool PCB_DIMENSION_BASE::Deserialize( const google::protobuf::Any &aContainer ) +{ + using namespace kiapi::common; + kiapi::board::types::Dimension dimension; + + if( !aContainer.UnpackTo( &dimension ) ) + return false; + + SetLayer( FromProtoEnum( dimension.layer() ) ); + const_cast( m_Uuid ) = KIID( dimension.id().value() ); + SetLocked( dimension.locked() == types::LockedState::LS_LOCKED ); + + google::protobuf::Any any; + any.PackFrom( dimension.text() ); + EDA_TEXT::Deserialize( any ); + + const types::Text& text = dimension.text(); + SetPosition( UnpackVector2( text.position() ) ); + + return true; +} + + void PCB_DIMENSION_BASE::drawAnArrow( VECTOR2I startPoint, EDA_ANGLE anAngle, int aLength ) { if( aLength ) diff --git a/pcbnew/pcb_dimension.h b/pcbnew/pcb_dimension.h index bf1415bc0f..0817d2fd4e 100644 --- a/pcbnew/pcb_dimension.h +++ b/pcbnew/pcb_dimension.h @@ -120,6 +120,9 @@ class PCB_DIMENSION_BASE : public PCB_TEXT public: PCB_DIMENSION_BASE( BOARD_ITEM* aParent, KICAD_T aType = PCB_DIMENSION_T ); + void Serialize( google::protobuf::Any &aContainer ) const override; + bool Deserialize( const google::protobuf::Any &aContainer ) override; + /** * The dimension's origin is the first feature point for the dimension. Every dimension has * one or more feature points, so every dimension has at least an origin. diff --git a/qa/data/pcbnew/api_kitchen_sink.kicad_pcb b/qa/data/pcbnew/api_kitchen_sink.kicad_pcb index 09b3a2e10d..df8c410b2c 100644 --- a/qa/data/pcbnew/api_kitchen_sink.kicad_pcb +++ b/qa/data/pcbnew/api_kitchen_sink.kicad_pcb @@ -1,5 +1,5 @@ (kicad_pcb - (version 20241030) + (version 20241129) (generator "pcbnew") (generator_version "8.99") (general @@ -10,22 +10,22 @@ (layers (0 "F.Cu" signal) (2 "B.Cu" signal) - (9 "F.Adhes" user) - (11 "B.Adhes" user) + (9 "F.Adhes" user "F.Adhesive") + (11 "B.Adhes" user "B.Adhesive") (13 "F.Paste" user) (15 "B.Paste" user) - (5 "F.SilkS" user) - (7 "B.SilkS" user) + (5 "F.SilkS" user "F.Silkscreen") + (7 "B.SilkS" user "B.Silkscreen") (1 "F.Mask" user) (3 "B.Mask" user) - (17 "Dwgs.User" user) - (19 "Cmts.User" user) - (21 "Eco1.User" user) - (23 "Eco2.User" user) + (17 "Dwgs.User" user "User.Drawings") + (19 "Cmts.User" user "User.Comments") + (21 "Eco1.User" user "User.Eco1") + (23 "Eco2.User" user "User.Eco2") (25 "Edge.Cuts" user) (27 "Margin" user) - (31 "F.CrtYd" user) - (29 "B.CrtYd" user) + (31 "F.CrtYd" user "F.Courtyard") + (29 "B.CrtYd" user "B.Courtyard") (35 "F.Fab" user) (33 "B.Fab" user) (39 "User.1" signal) @@ -468,7 +468,7 @@ (width 0.05) (type solid) ) - (fill none) + (fill no) (layer "Edge.Cuts") (uuid "052086a7-98a9-4ea1-bdee-ad673fb3a26c") ) @@ -481,7 +481,7 @@ (width 0.05) (type solid) ) - (fill none) + (fill no) (layer "Edge.Cuts") (uuid "98ab137c-f925-4075-af50-4ac8fe13c14d") ) @@ -492,7 +492,7 @@ (width 0.05) (type default) ) - (fill none) + (fill no) (layer "Edge.Cuts") (uuid "b27945e5-32fe-454b-ad80-b75cae1194e1") ) @@ -503,7 +503,7 @@ (width 0.05) (type default) ) - (fill none) + (fill no) (layer "Edge.Cuts") (uuid "e1699138-73b7-4cfd-aec1-5bee869795d9") ) @@ -514,7 +514,7 @@ (width 1.87) (type solid) ) - (fill none) + (fill no) (layer "B.Fab") (uuid "01315513-10cc-4984-96ac-98682589967a") ) @@ -525,7 +525,7 @@ (width 0.1) (type dash_dot_dot) ) - (fill none) + (fill no) (layer "B.Fab") (uuid "2e68cc14-52eb-4276-b39c-c502b042bc91") ) @@ -543,12 +543,12 @@ (gr_circle (center 106.5 48.5) (end 108.5 49) - (locked yes) (stroke (width 0.177) (type default) ) - (fill none) + (fill no) + (locked yes) (layer "B.Fab") (uuid "b5d27e62-c3ee-43b4-a859-5e626272bf9c") ) @@ -559,7 +559,7 @@ (width 0) (type solid) ) - (fill solid) + (fill yes) (layer "B.Fab") (uuid "cb2af193-349d-4651-a0c1-5d028759a9f3") ) @@ -615,6 +615,197 @@ (type dot) ) ) + (dimension + (type aligned) + (layer "F.SilkS") + (uuid "0bc42083-d926-4194-a819-d6be9c0115b7") + (pts + (xy 119.75 76.25) (xy 119.75 82.5) + ) + (height -5.5) + (format + (prefix "") + (suffix "") + (units 1) + (units_format 1) + (precision 1) + ) + (style + (thickness 0.1) + (arrow_length 1.27) + (text_position_mode 2) + (arrow_direction outward) + (extension_height 0.58642) + (extension_offset 0.5) + ) + (gr_text "246.1 mils" + (at 126 79 0) + (layer "F.SilkS") + (uuid "0bc42083-d926-4194-a819-d6be9c0115b7") + (effects + (font + (size 1 1) + (thickness 0.1) + ) + ) + ) + ) + (dimension + (type aligned) + (layer "F.SilkS") + (uuid "53a9c653-d0ab-4671-bb3c-e68323561710") + (pts + (xy 119.75 76.25) (xy 93.25 78.75) + ) + (height 2.5229) + (format + (prefix "") + (suffix "") + (units 3) + (units_format 1) + (precision 4) + ) + (style + (thickness 0.1) + (arrow_length 1.27) + (text_position_mode 2) + (arrow_direction outward) + (extension_height 0.58642) + (extension_offset 0.5) + (keep_text_aligned yes) + ) + (gr_text "26.6177 mm" + (at 106.159728 75 5.38931176) + (layer "F.SilkS") + (uuid "53a9c653-d0ab-4671-bb3c-e68323561710") + (effects + (font + (size 1 1) + (thickness 0.1) + ) + ) + ) + ) + (dimension + (type leader) + (layer "F.SilkS") + (uuid "7d932562-7662-47a4-b0f3-f405d4e7fd17") + (pts + (xy 109.5 89) (xy 113.25 85.75) + ) + (format + (prefix "") + (suffix "") + (units 0) + (units_format 0) + (precision 4) + (override_value "Leader") + ) + (style + (thickness 0.1) + (arrow_length 1.27) + (text_position_mode 0) + (text_frame 1) + (extension_offset 0.5) + ) + (gr_text "Leader" + (at 119 85.75 0) + (layer "F.SilkS") + (uuid "7d932562-7662-47a4-b0f3-f405d4e7fd17") + (effects + (font + (size 1 1) + (thickness 0.1) + ) + ) + ) + ) + (dimension + (type center) + (layer "F.SilkS") + (uuid "6c3890f3-95ec-403d-a195-7e14eaa0059b") + (pts + (xy 106.5 90.75) (xy 106.5 87.25) + ) + (style + (thickness 0.1) + (arrow_length 1.27) + (text_position_mode 0) + (extension_offset 0.5) + (keep_text_aligned yes) + ) + ) + (dimension + (type radial) + (layer "F.SilkS") + (uuid "32a22a4a-ae09-4c8c-9323-a332622fcb7d") + (pts + (xy 115 93.5) (xy 113.25 94.75) + ) + (leader_length 3.81) + (format + (prefix "R ") + (suffix "") + (units 3) + (units_format 1) + (precision 4) + ) + (style + (thickness 0.1) + (arrow_length 1.27) + (text_position_mode 0) + (extension_offset 0.5) + (keep_text_aligned yes) + ) + (gr_text "R 2.1506 mm" + (at 97.449675 96.964518 0) + (layer "F.SilkS") + (uuid "32a22a4a-ae09-4c8c-9323-a332622fcb7d") + (effects + (font + (size 1 1) + (thickness 0.1) + ) + ) + ) + ) + (dimension + (type orthogonal) + (layer "F.Cu") + (uuid "11ccce8d-b920-43bc-a797-25f3df207d00") + (pts + (xy 93.25 78.75) (xy 119.75 76.25) + ) + (height 3.75) + (orientation 0) + (format + (prefix "") + (suffix "") + (units 3) + (units_format 1) + (precision 4) + ) + (style + (thickness 0.2) + (arrow_length 1.27) + (text_position_mode 0) + (arrow_direction outward) + (extension_height 0.58642) + (extension_offset 0.5) + (keep_text_aligned yes) + ) + (gr_text "26.5000 mm" + (at 106.5 80.7 0) + (layer "F.Cu") + (uuid "11ccce8d-b920-43bc-a797-25f3df207d00") + (effects + (font + (size 1.5 1.5) + (thickness 0.3) + ) + ) + ) + ) (segment (start 88.3 63.2) (end 90.65 60.85) diff --git a/qa/tests/api/test_api_enums.cpp b/qa/tests/api/test_api_enums.cpp index 54984289ba..3069f2cb91 100644 --- a/qa/tests/api/test_api_enums.cpp +++ b/qa/tests/api/test_api_enums.cpp @@ -34,6 +34,7 @@ // Board-specific #include +#include #include #include #include @@ -213,4 +214,9 @@ BOOST_AUTO_TEST_CASE( TeardropType ) testEnums(); } +BOOST_AUTO_TEST_CASE( DimensionTextBorderStyle ) +{ + testEnums(); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/qa/tests/api/test_api_proto.cpp b/qa/tests/api/test_api_proto.cpp index 33f5cadf77..8cb1c4f9a5 100644 --- a/qa/tests/api/test_api_proto.cpp +++ b/qa/tests/api/test_api_proto.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -46,8 +47,8 @@ struct PROTO_TEST_FIXTURE }; -template -void testProtoFromKiCadObject( KiCadClass* aInput ) +template +void testProtoFromKiCadObject( KiCadClass* aInput, ParentClass* aParent ) { BOOST_TEST_CONTEXT( aInput->GetFriendlyName() << ": " << aInput->m_Uuid.AsStdString() ) { @@ -61,6 +62,8 @@ void testProtoFromKiCadObject( KiCadClass* aInput ) "Any message did not unpack into the requested type" ); KiCadClass output( *static_cast( aInput->Clone() ) ); + // Not yet + //KiCadClass output( aParent ); bool deserializeResult = false; BOOST_REQUIRE_NO_THROW( deserializeResult = output.Deserialize( any ) ); @@ -94,15 +97,15 @@ BOOST_FIXTURE_TEST_CASE( BoardTypes, PROTO_TEST_FIXTURE ) switch( track->Type() ) { case PCB_TRACE_T: - testProtoFromKiCadObject( track ); + testProtoFromKiCadObject( track, m_board.get() ); break; case PCB_ARC_T: - testProtoFromKiCadObject( track ); + testProtoFromKiCadObject( track, m_board.get() ); break; case PCB_VIA_T: - testProtoFromKiCadObject( track ); + testProtoFromKiCadObject( track, m_board.get() ); break; default: @@ -111,16 +114,46 @@ BOOST_FIXTURE_TEST_CASE( BoardTypes, PROTO_TEST_FIXTURE ) } for( FOOTPRINT* footprint : m_board->Footprints() ) - testProtoFromKiCadObject( footprint ); + testProtoFromKiCadObject( footprint, m_board.get() ); for( ZONE* zone : m_board->Zones() ) - testProtoFromKiCadObject( zone ); + testProtoFromKiCadObject( zone, m_board.get() ); - // TODO(JE) Shapes + for( BOARD_ITEM* item : m_board->Drawings() ) + { + switch( item->Type() ) + { + case PCB_DIM_ALIGNED_T: + testProtoFromKiCadObject( + static_cast( item ), m_board.get() ); + break; - // TODO(JE) Text + case PCB_DIM_ORTHOGONAL_T: + testProtoFromKiCadObject( + static_cast( item ), m_board.get() ); + break; - // TODO(JE) Dimensions + case PCB_DIM_CENTER_T: + testProtoFromKiCadObject( + static_cast( item ), m_board.get() ); + break; + + case PCB_DIM_LEADER_T: + testProtoFromKiCadObject( + static_cast( item ), m_board.get() ); + break; + + case PCB_DIM_RADIAL_T: + testProtoFromKiCadObject( + static_cast( item ), m_board.get() ); + break; + + default: break; + } + // TODO(JE) Shapes + + // TODO(JE) Text + } } @@ -133,7 +166,8 @@ BOOST_FIXTURE_TEST_CASE( Padstacks, PROTO_TEST_FIXTURE ) switch( track->Type() ) { case PCB_VIA_T: - testProtoFromKiCadObject( static_cast( track ) ); + testProtoFromKiCadObject( static_cast( track ), + m_board.get() ); break; default: @@ -142,7 +176,7 @@ BOOST_FIXTURE_TEST_CASE( Padstacks, PROTO_TEST_FIXTURE ) } for( FOOTPRINT* footprint : m_board->Footprints() ) - testProtoFromKiCadObject( footprint ); + testProtoFromKiCadObject( footprint, m_board.get() ); } BOOST_AUTO_TEST_SUITE_END()