diff --git a/common/pcb.keywords b/common/pcb.keywords index 741644fc71..ac46c1840c 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -146,6 +146,7 @@ gr_poly gr_rect gr_text gr_text_box +gr_vector hatch hatch_thickness hatch_gap diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index a3acc8893b..f03bdc376d 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -1192,7 +1192,10 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer ) { if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::RECTANGLE ) { - position = aPad->GetPosition() + primitive->GetCenter(); + position = primitive->GetCenter(); + RotatePoint( position, aPad->GetOrientation() ); + position += aPad->ShapePos(); + padsize.x = abs( primitive->GetBotRight().x - primitive->GetTopLeft().x ); padsize.y = abs( primitive->GetBotRight().y - primitive->GetTopLeft().y ); @@ -1736,10 +1739,24 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer ) case SHAPE_T::SEGMENT: if( aShape->IsProxyItem() ) { - m_gal->SetIsFill( false ); - m_gal->SetIsStroke( true ); + std::vector pts; + VECTOR2I offset = ( aShape->GetEnd() - aShape->GetStart() ).Perpendicular(); + offset = offset.Resize( thickness / 2 ); + + pts.push_back( aShape->GetStart() + offset ); + pts.push_back( aShape->GetStart() - offset ); + pts.push_back( aShape->GetEnd() - offset ); + pts.push_back( aShape->GetEnd() + offset ); + m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth ); - m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness ); + m_gal->DrawLine( pts[0], pts[1] ); + m_gal->DrawLine( pts[1], pts[2] ); + m_gal->DrawLine( pts[2], pts[3] ); + m_gal->DrawLine( pts[3], pts[0] ); + m_gal->DrawLine( ( pts[0] + pts[1] ) / 2, ( pts[1] + pts[2] ) / 2 ); + m_gal->DrawLine( ( pts[1] + pts[2] ) / 2, ( pts[2] + pts[3] ) / 2 ); + m_gal->DrawLine( ( pts[2] + pts[3] ) / 2, ( pts[3] + pts[0] ) / 2 ); + m_gal->DrawLine( ( pts[3] + pts[0] ) / 2, ( pts[0] + pts[1] ) / 2 ); } else if( outline_mode ) { diff --git a/pcbnew/plugins/kicad/pcb_parser.cpp b/pcbnew/plugins/kicad/pcb_parser.cpp index 1617ef4b05..350d3745a0 100644 --- a/pcbnew/plugins/kicad/pcb_parser.cpp +++ b/pcbnew/plugins/kicad/pcb_parser.cpp @@ -2520,7 +2520,7 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE( BOARD_ITEM* aParent ) CurTok() == T_fp_rect || CurTok() == T_fp_line || CurTok() == T_fp_poly || CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve || CurTok() == T_gr_rect || CurTok() == T_gr_bbox || CurTok() == T_gr_line || - CurTok() == T_gr_poly, nullptr, + CurTok() == T_gr_poly || CurTok() == T_gr_vector, nullptr, wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_SHAPE." ) ); T token; @@ -2720,6 +2720,7 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE( BOARD_ITEM* aParent ) NeedRIGHT(); break; + case T_gr_vector: case T_gr_line: case T_fp_line: // Default PCB_SHAPE type is S_SEGMENT. @@ -4590,6 +4591,14 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent ) break; } + case T_gr_vector: + { + PCB_SHAPE* spokeTemplate = parsePCB_SHAPE( nullptr ); + spokeTemplate->SetIsProxyItem(); + pad->AddPrimitive( spokeTemplate ); + break; + } + default: Expecting( "gr_line, gr_arc, gr_circle, gr_curve, gr_rect, gr_bbox or gr_poly" ); break; diff --git a/pcbnew/plugins/kicad/pcb_plugin.cpp b/pcbnew/plugins/kicad/pcb_plugin.cpp index f74274d693..61ca98d891 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.cpp +++ b/pcbnew/plugins/kicad/pcb_plugin.cpp @@ -1698,9 +1698,18 @@ void PCB_PLUGIN::format( const PAD* aPad, int aNestLevel ) const switch( primitive->GetShape() ) { case SHAPE_T::SEGMENT: - m_out->Print( nested_level, "(gr_line (start %s) (end %s)", - formatInternalUnits( primitive->GetStart() ).c_str(), - formatInternalUnits( primitive->GetEnd() ).c_str() ); + if( primitive->IsProxyItem() ) + { + m_out->Print( nested_level, "(gr_vector (start %s) (end %s)", + formatInternalUnits( primitive->GetStart() ).c_str(), + formatInternalUnits( primitive->GetEnd() ).c_str() ); + } + else + { + m_out->Print( nested_level, "(gr_line (start %s) (end %s)", + formatInternalUnits( primitive->GetStart() ).c_str(), + formatInternalUnits( primitive->GetEnd() ).c_str() ); + } break; case SHAPE_T::RECTANGLE: @@ -1757,7 +1766,8 @@ void PCB_PLUGIN::format( const PAD* aPad, int aNestLevel ) const break; } - m_out->Print( 0, " (width %s)", formatInternalUnits( primitive->GetWidth() ).c_str() ); + if( !primitive->IsProxyItem() ) + m_out->Print( 0, " (width %s)", formatInternalUnits( primitive->GetWidth() ).c_str() ); // The filled flag represents if a solid fill is present on circles, // rectangles and polygons diff --git a/pcbnew/plugins/kicad/pcb_plugin.h b/pcbnew/plugins/kicad/pcb_plugin.h index 5a00d8eef9..ab3390c105 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.h +++ b/pcbnew/plugins/kicad/pcb_plugin.h @@ -139,7 +139,8 @@ class PCB_PLUGIN; // forward decl //#define SEXPR_BOARD_FILE_VERSION 20230620 // PCB Fields //#define SEXPR_BOARD_FILE_VERSION 20230730 // Connectivity for graphic shapes //#define SEXPR_BOARD_FILE_VERSION 20230825 // Textbox explicit border flag -#define SEXPR_BOARD_FILE_VERSION 20230906 // Multiple image type support in files +//#define SEXPR_BOARD_FILE_VERSION 20230906 // Multiple image type support in files +#define SEXPR_BOARD_FILE_VERSION 20230913 // Custom-shaped-pad spoke templates #define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag #define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 16ba2c3b71..b0601b8ab9 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -1858,6 +1858,11 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer, SEG seg( primitive->GetStart(), primitive->GetEnd() ); SHAPE_LINE_CHAIN::INTERSECTIONS intersections; + RotatePoint( seg.A, pad->GetOrientation() ); + RotatePoint( seg.B, pad->GetOrientation() ); + seg.A += pad->ShapePos(); + seg.B += pad->ShapePos(); + // Make sure seg.A is the origin if( !pad->GetEffectivePolygon()->Contains( seg.A ) ) seg.Reverse();