From 0cca2a0ad2ac8558b38e1a62e03215c9fabe6353 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Mon, 28 Sep 2020 15:36:52 +0200 Subject: [PATCH] Rect, Round Rect, Oval, Trapezoid (rotated) pads now use flashed apertures. Complex shapes are plot using regions. The old code is still available, just in case... --- common/plotters/GERBER_plotter.cpp | 305 +++++++++++++++++++++--- common/plotters/gbr_plotter_apertures.h | 74 +++--- common/plotters/plotter_gerber.h | 35 ++- pcbnew/plot_brditems_plotter.cpp | 21 +- 4 files changed, 368 insertions(+), 67 deletions(-) diff --git a/common/plotters/GERBER_plotter.cpp b/common/plotters/GERBER_plotter.cpp index e661d24120..80805247fb 100644 --- a/common/plotters/GERBER_plotter.cpp +++ b/common/plotters/GERBER_plotter.cpp @@ -33,9 +33,14 @@ #include #include "plotter_gerber.h" +#include "gbr_plotter_aperture_macros.h" #include +// if GBR_USE_MACROS is defined, pads having a shape that is not a Gerber primitive +// will use a macro when possible +// Old code will be removed after more tests +#define GBR_USE_MACROS GERBER_PLOTTER::GERBER_PLOTTER() { @@ -64,8 +69,12 @@ void GERBER_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, wxASSERT( aMirror == false ); m_plotMirror = false; plotOffset = aOffset; - wxASSERT( aScale == 1 ); // aScale parameter is not used in Gerber - plotScale = 1; // Plot scale is *always* 1.0 + wxASSERT( aScale == 1 ); // aScale parameter is not used in Gerber + plotScale = 1; // Plot scale is *always* 1.0 + m_hasApertureRoundRect = false; // true is at least one round rect aperture is in use + m_hasApertureRotOval = false; // true is at least one oval rotated aperture is in use + m_hasApertureRotRect = false; // true is at least one rect. rotated aperture is in use + m_hasApertureOutline = false; // true is at least one rotated rect/trapezoid aperture is in use m_IUsPerDecimil = aIusPerDecimil; // gives now a default value to iuPerDeviceUnit (because the units of the caller is now known) @@ -228,9 +237,17 @@ bool GERBER_PLOTTER::StartPlot() // Set initial interpolation mode: always G01 (linear): fputs( "G01*\n", outputFile ); - // Set aperture list starting point: + // Add aperture list start point fputs( "G04 APERTURE LIST*\n", outputFile ); + // Give a minimal value to the default pen size, used to plot items in sketch mode + if( m_renderSettings ) + { + const int pen_min = 0.1 * m_IUsPerDecimil * 10000 / 25.4; // for min width = 0.1 mm + m_renderSettings->SetDefaultPenWidth( std::max( m_renderSettings->GetDefaultPenWidth(), + pen_min ) ); + } + return true; } @@ -260,6 +277,27 @@ bool GERBER_PLOTTER::EndPlot() if( substr && strcmp( substr, "G04 APERTURE LIST*" ) == 0 ) { + // Add aperture list macro: + if( m_hasApertureRoundRect | m_hasApertureRotOval || + m_hasApertureOutline || m_hasApertureRotRect ) + { + fputs( "G04 Aperture macros list*\n", outputFile ); + + if( m_hasApertureRoundRect ) + fputs( APER_MACRO_ROUNDRECT_HEADER, outputFile ); + + if( m_hasApertureRotOval ) + fputs( APER_MACRO_HORIZ_OVAL_HEADER, outputFile ); + + if( m_hasApertureRotRect ) + fputs( APER_MACRO_ROT_RECT_HEADER, outputFile ); + + if( m_hasApertureOutline ) + fputs( APER_MACRO_OUTLINE4P_HEADER, outputFile ); + + fputs( "G04 Aperture macros list end*\n", outputFile ); + } + writeApertureList(); fputs( "G04 APERTURE END LIST*\n", outputFile ); } @@ -279,19 +317,19 @@ void GERBER_PLOTTER::SetCurrentLineWidth( int aWidth, void* aData ) if( aWidth == DO_NOT_SET_LINE_WIDTH ) return; else if( aWidth == USE_DEFAULT_LINE_WIDTH ) - aWidth = m_renderSettings->GetDefaultPenWidth(); + aWidth = m_renderSettings->GetDefaultPenWidth(); wxASSERT_MSG( aWidth >= 0, "Plotter called to set negative pen width" ); GBR_METADATA* gbr_metadata = static_cast( aData ); int aperture_attribute = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( wxSize( aWidth, aWidth ), APERTURE::AT_PLOTTING, aperture_attribute ); + selectAperture( wxSize( aWidth, aWidth ), 0, 0.0, APERTURE::AT_PLOTTING, aperture_attribute ); currentPenWidth = aWidth; } -int GERBER_PLOTTER::GetOrCreateAperture( const wxSize& aSize, +int GERBER_PLOTTER::GetOrCreateAperture( const wxSize& aSize, int aRadius, double aRotDegree, APERTURE::APERTURE_TYPE aType, int aApertureAttribute ) { int last_D_code = 9; @@ -303,6 +341,7 @@ int GERBER_PLOTTER::GetOrCreateAperture( const wxSize& aSize, last_D_code = tool->m_DCode; if( (tool->m_Type == aType) && (tool->m_Size == aSize) && + (tool->m_Radius == aRadius) && (tool->m_Rotation == aRotDegree) && (tool->m_ApertureAttribute == aApertureAttribute) ) return idx; } @@ -311,6 +350,8 @@ int GERBER_PLOTTER::GetOrCreateAperture( const wxSize& aSize, APERTURE new_tool; new_tool.m_Size = aSize; new_tool.m_Type = aType; + new_tool.m_Radius = aRadius; + new_tool.m_Rotation = aRotDegree; new_tool.m_DCode = last_D_code + 1; new_tool.m_ApertureAttribute = aApertureAttribute; @@ -320,13 +361,63 @@ int GERBER_PLOTTER::GetOrCreateAperture( const wxSize& aSize, } -void GERBER_PLOTTER::selectAperture( const wxSize& aSize, +int GERBER_PLOTTER::GetOrCreateAperture( const std::vector& aCorners, double aRotDegree, + APERTURE::APERTURE_TYPE aType, int aApertureAttribute ) +{ + int last_D_code = 9; + + // Search an existing aperture + for( int idx = 0; idx < (int)m_apertures.size(); ++idx ) + { + APERTURE* tool = &m_apertures[idx]; + last_D_code = tool->m_DCode; + + if( (tool->m_Type == aType) && (tool->m_Corners.size() == aCorners.size() ) && + (tool->m_ApertureAttribute == aApertureAttribute) ) + { + // A candidate is found. the corner lists must be the same + bool is_same = true; + + for( size_t ii = 0; ii < aCorners.size(); ii++ ) + { + if( aCorners[ii] != m_apertures[m_currentApertureIdx].m_Corners[ii] ) + { + is_same = false; + break; + } + } + + if( is_same ) + return idx; + } + } + + // Allocate a new aperture + APERTURE new_tool; + + new_tool.m_Corners = aCorners; + new_tool.m_Size = wxSize( 0, 0 ); // Not used + new_tool.m_Type = aType; + new_tool.m_Radius = 0; // Not used + new_tool.m_Rotation = aRotDegree; + new_tool.m_DCode = last_D_code + 1; + new_tool.m_ApertureAttribute = aApertureAttribute; + + m_apertures.push_back( new_tool ); + + return m_apertures.size() - 1; +} + + +void GERBER_PLOTTER::selectAperture( const wxSize& aSize, int aRadius, double aRotDegree, APERTURE::APERTURE_TYPE aType, int aApertureAttribute ) { bool change = ( m_currentApertureIdx < 0 ) || ( m_apertures[m_currentApertureIdx].m_Type != aType ) || - ( m_apertures[m_currentApertureIdx].m_Size != aSize ); + ( m_apertures[m_currentApertureIdx].m_Size != aSize ) || + ( m_apertures[m_currentApertureIdx].m_Radius != aRadius ) || + ( m_apertures[m_currentApertureIdx].m_Rotation != aRotDegree ); if( !change ) change = m_apertures[m_currentApertureIdx].m_ApertureAttribute != aApertureAttribute; @@ -334,7 +425,41 @@ void GERBER_PLOTTER::selectAperture( const wxSize& aSize, if( change ) { // Pick an existing aperture or create a new one - m_currentApertureIdx = GetOrCreateAperture( aSize, aType, aApertureAttribute ); + m_currentApertureIdx = GetOrCreateAperture( aSize, aRadius, aRotDegree, + aType, aApertureAttribute ); + fprintf( outputFile, "D%d*\n", m_apertures[m_currentApertureIdx].m_DCode ); + } +} + + +void GERBER_PLOTTER::selectAperture( const std::vector& aCorners, double aRotDegree, + APERTURE::APERTURE_TYPE aType, int aApertureAttribute ) +{ + bool change = ( m_currentApertureIdx < 0 ) || + ( m_apertures[m_currentApertureIdx].m_Type != aType ) || + ( m_apertures[m_currentApertureIdx].m_Corners.size() != aCorners.size() ) || + ( m_apertures[m_currentApertureIdx].m_Rotation != aRotDegree ); + + if( !change ) // Compare corner lists + { + for( size_t ii = 0; ii < aCorners.size(); ii++ ) + { + if( aCorners[ii] != m_apertures[m_currentApertureIdx].m_Corners[ii] ) + { + change = true; + break; + } + } + } + + if( !change ) + change = m_apertures[m_currentApertureIdx].m_ApertureAttribute != aApertureAttribute; + + if( change ) + { + // Pick an existing aperture or create a new one + m_currentApertureIdx = GetOrCreateAperture( aCorners, aRotDegree, + aType, aApertureAttribute ); fprintf( outputFile, "D%d*\n", m_apertures[m_currentApertureIdx].m_DCode ); } } @@ -350,17 +475,15 @@ void GERBER_PLOTTER::selectAperture( int aDiameter, double aPolygonRotation, wxASSERT( aType>= APERTURE::APERTURE_TYPE::AT_REGULAR_POLY3 && aType <= APERTURE::APERTURE_TYPE::AT_REGULAR_POLY12 ); - // To use selectAperture( size, ... ) calculate a equivalent aperture size: - // for AT_REGULAR_POLYxx the parameter APERTURE::m_Size contains - // aDiameter (in m_Size.x) and aPolygonRotation in 1/1000 degree (in m_Size.y) wxSize size( aDiameter, (int)( aPolygonRotation * 1000.0 ) ); - selectAperture( size, aType, aApertureAttribute ); + selectAperture( wxSize( 0, 0), aDiameter/2, aPolygonRotation, aType, aApertureAttribute ); } void GERBER_PLOTTER::writeApertureList() { wxASSERT( outputFile ); char cbuf[1024]; + std::string buffer; bool useX1StructuredComment = false; @@ -386,7 +509,8 @@ void GERBER_PLOTTER::writeApertureList() useX1StructuredComment ).c_str(), outputFile ); } - char* text = cbuf + sprintf( cbuf, "%%ADD%d", tool.m_DCode ); + sprintf( cbuf, "%%ADD%d", tool.m_DCode ); + buffer = cbuf; /* Please note: the Gerber specs for mass parameters say that exponential syntax is *not* allowed and the decimal point should @@ -398,20 +522,20 @@ void GERBER_PLOTTER::writeApertureList() switch( tool.m_Type ) { case APERTURE::AT_CIRCLE: - sprintf( text, "C,%#f*%%\n", tool.GetDiameter() * fscale ); + sprintf( cbuf, "C,%#f*%%\n", tool.GetDiameter() * fscale ); break; case APERTURE::AT_RECT: - sprintf( text, "R,%#fX%#f*%%\n", tool.m_Size.x * fscale, + sprintf( cbuf, "R,%#fX%#f*%%\n", tool.m_Size.x * fscale, tool.m_Size.y * fscale ); break; case APERTURE::AT_PLOTTING: - sprintf( text, "C,%#f*%%\n", tool.m_Size.x * fscale ); + sprintf( cbuf, "C,%#f*%%\n", tool.m_Size.x * fscale ); break; case APERTURE::AT_OVAL: - sprintf( text, "O,%#fX%#f*%%\n", tool.m_Size.x * fscale, + sprintf( cbuf, "O,%#fX%#f*%%\n", tool.m_Size.x * fscale, tool.m_Size.y * fscale ); break; @@ -426,12 +550,53 @@ void GERBER_PLOTTER::writeApertureList() case APERTURE::AT_REGULAR_POLY10: case APERTURE::AT_REGULAR_POLY11: case APERTURE::AT_REGULAR_POLY12: - sprintf( text, "P,%#fX%dX%#f*%%\n", tool.GetDiameter() * fscale, - tool.GetVerticeCount(), tool.GetRotation() ); + sprintf( cbuf, "P,%#fX%dX%#f*%%\n", tool.GetDiameter() * fscale, + tool.GetRegPolyVerticeCount(), tool.GetRotation() ); + break; + + case APERTURE::AM_ROUND_RECT: // Aperture macro for round rect pads + sprintf( cbuf, "%s,%#fX%#fX%#fX%#f*%%\n", APER_MACRO_ROUNDRECT_NAME, + tool.m_Size.x * fscale, tool.m_Size.y * fscale, + tool.m_Radius * fscale, tool.m_Rotation ); + break; + + case APERTURE::AM_ROT_RECT: // Aperture macro for rotated rect pads + sprintf( cbuf, "%s,%#fX%#fX%#f*%%\n", APER_MACRO_ROT_RECT_NAME, + tool.m_Size.x * fscale, tool.m_Size.y * fscale, + tool.m_Rotation ); + break; + + case APERTURE::APER_MACRO_OUTLINE4P: // Aperture macro for trapezoid pads + wxASSERT( tool.m_Corners.size() == 4 ); + + sprintf( cbuf, "%s,", APER_MACRO_OUTLINE4P_NAME ); + buffer += cbuf; + + // Output all corners (should be 4 corners) + // Remember: the Y coordinate must be negated, due to the fact in Pcbnew + // the Y axis is from top to bottom + for( size_t ii = 0; ii < tool.m_Corners.size(); ii++ ) + { + sprintf( cbuf, "%#fX%#fX", + tool.m_Corners[ii].x * fscale, -tool.m_Corners[ii].y * fscale ); + buffer += cbuf; + } + + // close outline and output rotation + sprintf( cbuf, "%#f*%%\n", tool.m_Rotation ); + break; + + case APERTURE::AM_ROTATED_OVAL: // Aperture macro for rotated oval pads + // (not rotated is a primitive) + // m_Size.x = lenght; m_Size.y = width + sprintf( cbuf, "%s,%#fX%#fX%#f*%%\n", APER_MACRO_HORIZ_OVAL_NAME, + tool.m_Size.x * fscale, tool.m_Size.y * fscale, + tool.m_Rotation ); break; } - fputs( cbuf, outputFile ); + buffer += cbuf; + fputs( buffer.c_str(), outputFile ); m_apertureAttribute = attribute; @@ -731,6 +896,8 @@ void GERBER_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_ if( gbr_metadata ) formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); + Circle( pos, diametre - currentPenWidth, NO_FILL, DO_NOT_SET_LINE_WIDTH ); } else @@ -738,7 +905,7 @@ void GERBER_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_ DPOINT pos_dev = userToDeviceCoordinates( pos ); int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( size, APERTURE::AT_CIRCLE, aperture_attrib ); + selectAperture( size, 0, 0.0, APERTURE::AT_CIRCLE, aperture_attrib ); if( gbr_metadata ) formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); @@ -764,7 +931,7 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub DPOINT pos_dev = userToDeviceCoordinates( pos ); int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( size, APERTURE::AT_OVAL, aperture_attrib ); + selectAperture( size, 0, 0.0, APERTURE::AT_OVAL, aperture_attrib ); if( gbr_metadata ) formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); @@ -776,11 +943,35 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub { if( trace_mode == FILLED ) { + #ifdef GBR_USE_MACROS + m_hasApertureRotOval = true; + // We are using a aperture macro that expect size.y < size.x + // i.e draw a horizontal line for rotation = 0.0 + // size.x = length, size.y = width + if( size.x < size.y ) + { + std::swap( size.x, size.y ); + orient += 900; + + if( orient > 1800 ) + orient -= 1800; + } + + DPOINT pos_dev = userToDeviceCoordinates( pos ); + int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; + selectAperture( size, 0, orient/10.0, APERTURE::AM_ROTATED_OVAL, aperture_attrib ); + + if( gbr_metadata ) + formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + + emitDcode( pos_dev, 3 ); + #else // Draw the oval as round rect pad with a radius = 50% min size) // In gerber file, it will be drawn as a region with arcs, and can be // detected as pads (similar to a flashed pad) FlashPadRoundRect( pos, aSize, std::min( aSize.x, aSize.y ) /2, orient, FILLED, aData ); + #endif } else // Non filled shape: plot outlines: { @@ -823,17 +1014,18 @@ void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize, if( gbr_metadata ) formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - Rect( wxPoint( pos.x - (size.x - currentPenWidth) / 2, - pos.y - (size.y - currentPenWidth) / 2 ), - wxPoint( pos.x + (size.x - currentPenWidth) / 2, - pos.y + (size.y - currentPenWidth) / 2 ), + SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); + Rect( wxPoint( pos.x - (size.x - GetCurrentLineWidth()) / 2, + pos.y - (size.y - GetCurrentLineWidth()) / 2 ), + wxPoint( pos.x + (size.x - GetCurrentLineWidth()) / 2, + pos.y + (size.y - GetCurrentLineWidth()) / 2 ), NO_FILL, GetCurrentLineWidth() ); } else { DPOINT pos_dev = userToDeviceCoordinates( pos ); int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( size, APERTURE::AT_RECT, aperture_attrib ); + selectAperture( size, 0, 0.0, APERTURE::AT_RECT, aperture_attrib ); if( gbr_metadata ) formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); @@ -842,8 +1034,25 @@ void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize, } break; - default: // plot pad shape as Gerber region + default: + #ifdef GBR_USE_MACROS + if( trace_mode != SKETCH ) { + m_hasApertureRotRect = true; + DPOINT pos_dev = userToDeviceCoordinates( pos ); + int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; + selectAperture( size, 0, orient/10.0, APERTURE::AM_ROT_RECT, aperture_attrib ); + + if( gbr_metadata ) + formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + + emitDcode( pos_dev, 3 ); + + break; + } + #endif + { + // plot pad shape as Gerber region wxPoint coord[4]; // coord[0] is assumed the lower left // coord[1] is assumed the upper left @@ -897,6 +1106,19 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS } else { + #ifdef GBR_USE_MACROS + m_hasApertureRoundRect = true; + + DPOINT pos_dev = userToDeviceCoordinates( aPadPos ); + int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; + selectAperture( aSize, aCornerRadius, aOrient/10.0, + APERTURE::AM_ROUND_RECT, aperture_attrib ); + + if( gbr_metadata ) + formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + + emitDcode( pos_dev, 3 ); + #else // A Pad RoundRect is plotted as a Gerber region. // Initialize region metadata: bool clearTA_AperFunction = false; // true if a TA.AperFunction is used @@ -920,14 +1142,11 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS if( clearTA_AperFunction ) { if( m_useX2format ) - { fputs( "%TD.AperFunction*%\n", outputFile ); - } else - { fputs( "G04 #@! TD.AperFunction*\n", outputFile ); - } } + #endif } } @@ -1106,8 +1325,6 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData ) { - // TODO: use Aperture macro and flash it - // polygon corners list std::vector cornerList = { aCorners[0], aCorners[1], aCorners[2], aCorners[3] }; @@ -1128,9 +1345,25 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo metadata = *gbr_metadata; if( aTrace_Mode == SKETCH ) - PlotPoly( cornerList, NO_FILL, DO_NOT_SET_LINE_WIDTH, &metadata ); + PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), &metadata ); else + #ifdef GBR_USE_MACROS + { + m_hasApertureOutline = true; + DPOINT pos_dev = userToDeviceCoordinates( aPadPos ); + // polygon corners list + std::vector corners = { aCorners[0], aCorners[1], aCorners[2], aCorners[3] }; + int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; + selectAperture( corners, aPadOrient/10.0, APERTURE::APER_MACRO_OUTLINE4P, aperture_attrib ); + + if( gbr_metadata ) + formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + + emitDcode( pos_dev, 3 ); + } + #else PlotGerberRegion( cornerList, &metadata ); + #endif } diff --git a/common/plotters/gbr_plotter_apertures.h b/common/plotters/gbr_plotter_apertures.h index 45c0a2341c..bda5717265 100644 --- a/common/plotters/gbr_plotter_apertures.h +++ b/common/plotters/gbr_plotter_apertures.h @@ -36,6 +36,8 @@ * regular polygon * * We need round apertures to plot lines, so we also defined a aperture type for plotting + * + * Other aperture types are aperture macros */ #define FIRST_DCODE_VALUE 10 // D_CODE < 10 is a command, D_CODE >= 10 is a tool @@ -43,21 +45,26 @@ class APERTURE { public: enum APERTURE_TYPE { - AT_CIRCLE = 1, // round aperture, to flash pads - AT_RECT = 2, // rect aperture, to flash pads - AT_PLOTTING = 3, // round aperture, to plot lines - AT_OVAL = 4, // oval aperture, to flash pads - AT_REGULAR_POLY = 5,// Regular polygon (n vertices, n = 3 .. 12, with rotation) - AT_REGULAR_POLY3, // Regular polygon 3 vertices, with rotation - AT_REGULAR_POLY4, // Regular polygon 4 vertices, with rotation - AT_REGULAR_POLY5, // Regular polygon 5 vertices, with rotation - AT_REGULAR_POLY6, // Regular polygon 6 vertices, with rotation - AT_REGULAR_POLY7, // Regular polygon 7 vertices, with rotation - AT_REGULAR_POLY8, // Regular polygon 8 vertices, with rotation - AT_REGULAR_POLY9, // Regular polygon 9 vertices, with rotation - AT_REGULAR_POLY10, // Regular polygon 10 vertices, with rotation - AT_REGULAR_POLY11, // Regular polygon 11 vertices, with rotation - AT_REGULAR_POLY12, // Regular polygon 12 vertices, with rotation + AT_CIRCLE = 1, // round aperture, to flash pads + AT_RECT = 2, // rect aperture, to flash pads + AT_PLOTTING = 3, // round aperture, to plot lines + AT_OVAL = 4, // oval aperture, to flash pads + AT_REGULAR_POLY = 5, // Regular polygon (n vertices, n = 3 .. 12, with rotation) + AT_REGULAR_POLY3, // Regular polygon 3 vertices, with rotation + AT_REGULAR_POLY4, // Regular polygon 4 vertices, with rotation + AT_REGULAR_POLY5, // Regular polygon 5 vertices, with rotation + AT_REGULAR_POLY6, // Regular polygon 6 vertices, with rotation + AT_REGULAR_POLY7, // Regular polygon 7 vertices, with rotation + AT_REGULAR_POLY8, // Regular polygon 8 vertices, with rotation + AT_REGULAR_POLY9, // Regular polygon 9 vertices, with rotation + AT_REGULAR_POLY10, // Regular polygon 10 vertices, with rotation + AT_REGULAR_POLY11, // Regular polygon 11 vertices, with rotation + AT_REGULAR_POLY12, // Regular polygon 12 vertices, with rotation + AM_ROUND_RECT, // Aperture macro for round rect pads + AM_ROT_RECT, // Aperture macro for rotated rect pads + APER_MACRO_OUTLINE4P, // Aperture macro for trapezoid pads (outline with 4 corners) + AM_ROTATED_OVAL // Aperture macro for rotated oval pads + // (not rotated uses a primitive) }; void SetSize( const wxSize& aSize ) @@ -72,15 +79,21 @@ public: void SetDiameter( int aDiameter ) { - m_Size.x = aDiameter; + m_Radius = aDiameter/2; } int GetDiameter() { - return m_Size.x; + // For round primitive, the diameter is the m_Size.x ot m_Size.y + if( m_Type == AT_CIRCLE || m_Type == AT_PLOTTING ) + return m_Size.x; + + // For rounded shapes (macro apertures), return m_Radius * 2 + // but usually they use the radius (m_Radius) + return m_Radius*2; } - void SetVerticeCount( int aCount ) + void SetRegPolyVerticeCount( int aCount ) { if( aCount < 3 ) aCount = 3; @@ -90,31 +103,38 @@ public: m_Type = (APERTURE_TYPE)(AT_REGULAR_POLY3 - 3 + aCount); } - int GetVerticeCount() + int GetRegPolyVerticeCount() { return m_Type - AT_REGULAR_POLY3 + 3; } void SetRotation( double aRotDegree ) { - // The rotation is stored in 1/1000 degree - m_Size.y = int( aRotDegree * 1000.0 ); + // The rotation is stored in degree + m_Rotation = aRotDegree; } double GetRotation() { - // The rotation is stored in 1/1000 degree - return m_Size.y / 1000.0; + // The rotation is stored in degree + return m_Rotation; } - // Type ( Line, rect , circulaire , ovale poly 3 to 12 vertices ) + // Type ( Line, rect , circulaire , ovale poly 3 to 12 vertices, aperture macro ) APERTURE_TYPE m_Type; - // horiz and Vert size, or diameter and rotation for regular polygon - // The diameter (for circle and polygons) is stored in m_Size.x - // the rotation is stored in m_Size.y in 1/1000 degree + // horiz and Vert size wxSize m_Size; + // list of corners for polygon shape + std::vector m_Corners; + + // Radius for polygon and round rect shape + int m_Radius; + + // Rotation in degrees + double m_Rotation; + // code number ( >= 10 ) int m_DCode; diff --git a/common/plotters/plotter_gerber.h b/common/plotters/plotter_gerber.h index 40b48318a8..a9586beb0e 100644 --- a/common/plotters/plotter_gerber.h +++ b/common/plotters/plotter_gerber.h @@ -200,11 +200,25 @@ public: * @return a index to the aperture in aperture list which meets the size and type of tool * if the aperture does not exist, it is created and entered in aperture list * @param aSize = the size of tool + * @param aRadius = the radius used for some shapes tool (oval, roundrect macros) + * @param aRotDegree = the rotation of tool (primitives round, oval rect accept only 0.0) * @param aType = the type ( shape ) of tool * @param aApertureAttribute = an aperture attribute of the tool (a tool can have onlu one attribute) * 0 = no specific attribute */ - int GetOrCreateAperture( const wxSize& aSize, + int GetOrCreateAperture( const wxSize& aSize, int aRadius, double aRotDegree, + APERTURE::APERTURE_TYPE aType, int aApertureAttribute ); + + /** + * @return a index to the aperture in aperture list which meets the data and type of tool + * if the aperture does not exist, it is created and entered in aperture list + * @param aCorners = the corner list + * @param aRotDegree = the rotation of tool + * @param aType = the type ( shape ) of tool that can manage a list of corners (polygon) + * @param aApertureAttribute = an aperture attribute of the tool (a tool can have onlu one attribute) + * 0 = no specific attribute + */ + int GetOrCreateAperture( const std::vector& aCorners, double aRotDegree, APERTURE::APERTURE_TYPE aType, int aApertureAttribute ); protected: @@ -237,7 +251,8 @@ protected: * size, type and attributes. * write the DCode selection on gerber file */ - void selectAperture( const wxSize& aSize, APERTURE::APERTURE_TYPE aType, + void selectAperture( const wxSize& aSize, int aRadius, double aRotDegree, + APERTURE::APERTURE_TYPE aType, int aApertureAttribute ); /** * Pick an existing aperture or create a new one, matching the @@ -245,7 +260,17 @@ protected: * It apply only to apertures with type = AT_REGULAR_POLY3 to AT_REGULAR_POLY12 * write the DCode selection on gerber file */ - void selectAperture( int aDiameter, double aPolygonRotation, + void selectAperture( const std::vector& aCorners, double aPolygonRotation, + APERTURE::APERTURE_TYPE aType, int aApertureAttribute ); + + /** + * Pick an existing aperture or create a new one, matching the + * corner list, aRotDegree, type and attributes. + * It apply only to apertures managing a polygon that differs from AT_REGULAR_POLY3 + * to AT_REGULAR_POLY12 (for instance APER_MACRO_TRAPEZOID ) + * write the DCode selection on gerber file + */ + void selectAperture( int aDiameter, double aRotDegree, APERTURE::APERTURE_TYPE aType, int aApertureAttribute ); /** @@ -294,6 +319,10 @@ protected: std::vector m_apertures; // The list of available apertures int m_currentApertureIdx; // The index of the current aperture in m_apertures + bool m_hasApertureRoundRect; // true is at least one round rect aperture is in use + bool m_hasApertureRotOval; // true is at least one oval rotated aperture is in use + bool m_hasApertureRotRect; // true is at least one rect. rotated aperture is in use + bool m_hasApertureOutline; // true is at least one outline (free polygon) aperture is in use bool m_gerberUnitInch; // true if the gerber units are inches, false for mm int m_gerberUnitFmt; // number of digits in mantissa. diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 016638f157..5a10d1d6b9 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -236,8 +236,27 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl aPad->GetOrientation(), aPlotMode, &gbr_metadata ); break; - default: case PAD_SHAPE_TRAPEZOID: + { + // Build the pad polygon in coordinates relative to the pad + // (i.e. for a pad at pos 0,0, rot 0.0). Needed to use aperture macros, + // to be able to create a pattern common to all trapezoid pads having the same shape + wxPoint coord[4]; + // Order is lower left, lower right, upper right, upper left + wxSize half_size = aPad->GetSize()/2; + wxSize trap_delta = aPad->GetDelta()/2; + + coord[0] = wxPoint( -half_size.x - trap_delta.y, half_size.y + trap_delta.x ); + coord[1] = wxPoint( half_size.x + trap_delta.y, half_size.y - trap_delta.x ); + coord[2] = wxPoint( half_size.x - trap_delta.y, -half_size.y + trap_delta.x ); + coord[3] = wxPoint( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x ); + + m_plotter->FlashPadTrapez( shape_pos, coord, aPad->GetOrientation(), aPlotMode, + &gbr_metadata ); + } + break; + + default: case PAD_SHAPE_CHAMFERED_RECT: case PAD_SHAPE_CUSTOM: {