Gerber, aperture macros: use different apertures primitives in macro defs.

To avoid issues with broken Gerber readers use aperture macros with shapes
without rotation when more than one primitive is required.
In many gerber readers, rotation of a set of primitives is broken
(do not follow Gerber requirements)
This commit is contained in:
jean-pierre charras 2020-10-05 20:34:33 +02:00
parent 728c207105
commit 61f1f7d948
4 changed files with 87 additions and 47 deletions

View File

@ -40,7 +40,10 @@
// 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 only after many tests
// #define GBR_USE_MACROS
#define GBR_USE_MACROS_FOR_ROUNDRECT
#define GBR_USE_MACROS_FOR_TRAPEZOID
#define GBR_USE_MACROS_FOR_ROTATED_OVAL
#define GBR_USE_MACROS_FOR_ROTATED_RECT
GERBER_PLOTTER::GERBER_PLOTTER()
{
@ -293,7 +296,7 @@ bool GERBER_PLOTTER::EndPlot()
fputs( APER_MACRO_ROUNDRECT_HEADER, outputFile );
if( m_hasApertureRotOval )
fputs( APER_MACRO_HORIZ_OVAL_HEADER, outputFile );
fputs( APER_MACRO_SHAPE_OVAL_HEADER, outputFile );
if( m_hasApertureRotRect )
fputs( APER_MACRO_ROT_RECT_HEADER, outputFile );
@ -561,9 +564,34 @@ void GERBER_PLOTTER::writeApertureList()
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 );
{
// The aperture macro needs coordinates of the centers of the 4 corners
std::vector<VECTOR2I> corners;
wxSize half_size( tool.m_Size.x/2-tool.m_Radius, tool.m_Size.y/2-tool.m_Radius );
corners.emplace_back( -half_size.x, -half_size.y );
corners.emplace_back( half_size.x, -half_size.y );
corners.emplace_back( half_size.x, half_size.y );
corners.emplace_back( -half_size.x, half_size.y );
// Rotate the corner coordinates:
for( int ii = 0; ii < 4; ii++ )
RotatePoint( corners[ii], tool.m_Rotation*10.0 );
sprintf( cbuf, "%s,%#fX", APER_MACRO_ROUNDRECT_NAME,
tool.m_Radius * fscale );
buffer += cbuf;
// Add each corner
for( int ii = 0; ii < 4; ii++ )
{
sprintf( cbuf, "%#fX%#fX",
corners[ii].x * fscale, corners[ii].y * fscale );
buffer += cbuf;
}
sprintf( cbuf, "0*%%\n" );
}
break;
case APERTURE::AM_ROT_RECT: // Aperture macro for rotated rect pads
@ -594,10 +622,20 @@ void GERBER_PLOTTER::writeApertureList()
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 );
// m_Size.x = lenght; m_Size.y = width, and the macro aperure expects
// the position of ends
{
VECTOR2I start( tool.m_Size.x/2, 0 );
VECTOR2I end( -tool.m_Size.x/2, 0 );
RotatePoint( start, tool.m_Rotation*10.0 );
RotatePoint( end, tool.m_Rotation*10.0 );
sprintf( cbuf, "%s,%#fX%#fX%#fX%#fX%#fX0*%%\n", APER_MACRO_SHAPE_OVAL_NAME,
tool.m_Size.y * fscale, // width
start.x * fscale, -start.y * fscale,
end.x * fscale, -end.y * fscale );
}
break;
}
@ -949,7 +987,7 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub
{
if( trace_mode == FILLED )
{
#ifdef GBR_USE_MACROS
#ifdef GBR_USE_MACROS_FOR_ROTATED_OVAL
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
@ -1041,7 +1079,7 @@ void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize,
break;
default:
#ifdef GBR_USE_MACROS
#ifdef GBR_USE_MACROS_FOR_ROTATED_RECT
if( trace_mode != SKETCH )
{
m_hasApertureRotRect = true;
@ -1112,7 +1150,7 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
}
else
{
#ifdef GBR_USE_MACROS
#ifdef GBR_USE_MACROS_FOR_ROUNDRECT
m_hasApertureRoundRect = true;
DPOINT pos_dev = userToDeviceCoordinates( aPadPos );
@ -1353,7 +1391,7 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo
if( aTrace_Mode == SKETCH )
PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), &metadata );
else
#ifdef GBR_USE_MACROS
#ifdef GBR_USE_MACROS_FOR_TRAPEZOID
{
m_hasApertureOutline = true;
DPOINT pos_dev = userToDeviceCoordinates( aPadPos );

View File

@ -26,27 +26,28 @@
#pragma once
// A aperture macro to define a rounded rect pad shape
// In many gerber readers, the rotation of the full shape is broken
// so we are using primitives that does not need a rotation
#define APER_MACRO_ROUNDRECT_NAME "RoundRect"
#define APER_MACRO_ROUNDRECT_HEADER \
"%AMRoundRect*\n\
0 Rectangle with rounded corners, with rotation*\n\
0 The origin of the aperture is its center*\n\
0 $1 X-size*\n\
0 $2 Y-size*\n\
0 $3 Rounding radius*\n\
0 $4 Rotation angle, in degrees counterclockwise*\n\
0 Add two overlapping rectangle primitives as box body*\n\
21,1,$1,$2-$3-$3,0,0,$4*\n\
21,1,$1-$3-$3,$2,0,0,$4*\n\
0 Rectangle with rounded corners*\n\
0 $1 Rounding radius*\n\
0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners*\n\
0 Add a 4 corners polygon primitive as box body*\n\
4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0*\n\
0 Add four circle primitives for the rounded corners*\n\
$5=$1/2*\n\
$6=$2/2*\n\
$7=2x$3*\n\
1,1,$7,$5-$3,$6-$3,$4*\n\
1,1,$7,-$5+$3,$6-$3,$4*\n\
1,1,$7,-$5+$3,-$6+$3,$4*\n\
1,1,$7,$5-$3,-$6+$3,$4*%\n"
1,1,$1+$1,$2,$3,0*\n\
1,1,$1+$1,$4,$5,0*\n\
1,1,$1+$1,$6,$7,0*\n\
1,1,$1+$1,$8,$9,0*\n\
0 Add four rect primitives between the rounded corners*\n\
20,1,$1+$1,$2,$3,$4,$5,0*\n\
20,1,$1+$1,$4,$5,$6,$7,0*\n\
20,1,$1+$1,$6,$7,$8,$9,0*\n\
20,1,$1+$1,$8,$9,$2,$3,0*\
%\n"
// A aperture macro to define a rotated rect pad shape
#define APER_MACRO_ROT_RECT_NAME "RotRect"
@ -63,23 +64,25 @@ $7=2x$3*\n\
// A aperture macro to define a oval pad shape
#define APER_MACRO_HORIZ_OVAL_NAME "HorizOval"
// In many gerber readers, the rotation of the full shape is broken
// so we are using a primitive that does not need a rotation to be
// plotted
#define APER_MACRO_SHAPE_OVAL_NAME "HorizOval"
#define APER_MACRO_HORIZ_OVAL_HEADER \
#define APER_MACRO_SHAPE_OVAL_HEADER \
"%AMHorizOval*\n\
0 Thick line with rounded ends, with rotation*\n\
0 The origin of the aperture is its center*\n\
0 $1 length (X dim)*\n\
0 $2 width (Y dim)*\n\
0 $3 Rotation angle, in degrees counterclockwise*\n\
0 Add horizontal line*\n\
21,1,$1-$2,$2,0,0,$3*\n\
0 Add two circle primitives for the rounded ends*\n\
$4=($1-$2)/2*\n\
1,1,$2,$4,0,$3*\n\
1,1,$2,-$4,0,$3*%\n"
0 Thick line with rounded ends*\n\
0 $1 width*\n\
0 $2 $3 position (X,Y) of the first rounded end (center of the circle)*\n\
0 $4 $5 position (X,Y) of the second rounded end (center of the circle)*\n\
0 Add line between two ends*\n\
20,1,$1,$2,$3,$4,$5,0*\n\
0 Add two circle primitives to create the rounded ends*\n\
1,1,$1,$2,$3,0*\n\
1,1,$1,$4,$5,0*%\n"
// A aperture macro to define a trapezoid (polygon) by 4 corners
// and a rotation angle
#define APER_MACRO_OUTLINE4P_NAME "Outline4P"
#define APER_MACRO_OUTLINE4P_HEADER \

View File

@ -29,7 +29,7 @@
#include <am_param.h>
#include <am_primitive.h>
#include <macros.h>
//#include <macros.h>
#include <wx/debug.h>

View File

@ -35,8 +35,6 @@
#include <gerbview.h>
#include <gerber_file_image.h>
#include <gr_basic.h>
/**
* Function scaletoIU
@ -281,8 +279,8 @@ void AM_PRIMITIVE::DrawBasicShape( const GERBER_DRAW_ITEM* aParent,
case AMP_MOIRE:
{
/* Moir<EFBFBD>, Primitive Code 6
* The moir<EFBFBD> primitive is a cross hair centered on concentric rings (annuli).
/* Moire, Primitive Code 6
* The moire primitive is a cross hair centered on concentric rings (annuli).
* Exposure is always on.
*/
curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
@ -365,6 +363,7 @@ void AM_PRIMITIVE::DrawBasicShape( const GERBER_DRAW_ITEM* aParent,
// * the polygon is always closed,
// * therefore the last XY coordinate is the same as the first
int prm_idx = 2; // params[2] is the first X coordinate
for( int i = 0; i <= numCorners; ++i )
{
pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );