Gerbview: Aperture Macro: handle overwriting of variables

Gerbview did not handle redefinition of variable like $3 = $3 / 2
This redefinition is sometimes found in Gerber files.
This is a long standing issue now fixed.
Fixes #7222
https://gitlab.com/kicad/code/kicad/issues/7222
This commit is contained in:
jean-pierre charras 2023-02-11 12:00:02 +01:00
parent eb240fda9a
commit 54b4f0e673
10 changed files with 183 additions and 124 deletions

View File

@ -69,7 +69,8 @@ bool AM_PARAM::IsImmediate() const
return is_immediate; return is_immediate;
} }
double AM_PARAM::GetValue( const D_CODE* aDcode ) const
double AM_PARAM::GetValueFromMacro( APERTURE_MACRO* aApertureMacro ) const
{ {
// In macros, actual values are sometimes given by an expression like: // In macros, actual values are sometimes given by an expression like:
// 0-$2/2-$4 // 0-$2/2-$4
@ -102,22 +103,15 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
break; break;
case PUSHPARM: case PUSHPARM:
// a defered value: get the actual parameter from the aDcode // a defered value: get the actual parameter from the aperture macro
if( aDcode ) // should be always true here if( aApertureMacro ) // should be always true here
{ {
if( item.GetIndex() <= aDcode->GetParamCount() ) // Get the actual value
{ curr_value = aApertureMacro->GetLocalParamValue( item.GetIndex() );
curr_value = aDcode->GetParam( item.GetIndex() );
}
else // Get parameter from local param definition
{
const APERTURE_MACRO * am_parent = aDcode->GetMacro();
curr_value = am_parent->GetLocalParam( aDcode, item.GetIndex() );
}
} }
else else
{ {
wxFAIL_MSG( wxT( "AM_PARAM::GetValue(): NULL param aDcode" ) ); wxFAIL_MSG( wxT( "AM_PARAM::GetValue(): NULL param aApertureMacro" ) );
} }
ops.emplace_back( curr_value ); ops.emplace_back( curr_value );
@ -129,10 +123,8 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
break; break;
default: default:
wxFAIL_MSG( wxString::Format( wxT( "AM_PARAM::GetValue(): dcode %d prm %d/%d: " wxFAIL_MSG( wxString::Format( wxT( "AM_PARAM::GetValue(): unexpected prm type %d" ),
"unexpected type %d" ), item.GetType() ) );
aDcode ? aDcode->m_Num_Dcode : -1, ii,
m_paramStack.size(), item.GetType() ) );
break; break;
} }
} }
@ -142,6 +134,7 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
return result; return result;
} }
/** /**
* add an operator/operand to the current stack * add an operator/operand to the current stack
* aType = NOP, PUSHVALUE, PUSHPARM, ADD, SUB, MUL, DIV, EQUATE * aType = NOP, PUSHVALUE, PUSHPARM, ADD, SUB, MUL, DIV, EQUATE

View File

@ -295,7 +295,7 @@ public:
void PushOperator( parm_item_type aType, double aValue ); void PushOperator( parm_item_type aType, double aValue );
void PushOperator( parm_item_type aType, int aValue = 0); void PushOperator( parm_item_type aType, int aValue = 0);
double GetValue( const D_CODE* aDcode ) const; double GetValueFromMacro( APERTURE_MACRO* aApertureMacro ) const;
/** /**
* Test if this AM_PARAM holds an immediate parameter or is a pointer into a parameter held * Test if this AM_PARAM holds an immediate parameter or is a pointer into a parameter held

View File

@ -55,7 +55,7 @@ static VECTOR2I mapPt( double x, double y, bool isMetric )
} }
bool AM_PRIMITIVE::IsAMPrimitiveExposureOn( const D_CODE* aDcode ) const bool AM_PRIMITIVE::IsAMPrimitiveExposureOn( APERTURE_MACRO* aApertMacro ) const
{ {
/* /*
* Some but not all primitives use the first parameter as an exposure control. * Some but not all primitives use the first parameter as an exposure control.
@ -75,7 +75,7 @@ bool AM_PRIMITIVE::IsAMPrimitiveExposureOn( const D_CODE* aDcode ) const
case AMP_OUTLINE: case AMP_OUTLINE:
case AMP_POLYGON: case AMP_POLYGON:
// All have an exposure parameter and can return a value (0 or 1) // All have an exposure parameter and can return a value (0 or 1)
return m_Params[0].GetValue( aDcode ) != 0; return m_Params[0].GetValueFromMacro( aApertMacro ) != 0;
break; break;
case AMP_THERMAL: // Exposure is always on case AMP_THERMAL: // Exposure is always on
@ -88,11 +88,7 @@ bool AM_PRIMITIVE::IsAMPrimitiveExposureOn( const D_CODE* aDcode ) const
} }
// TODO(snh): Remove hard coded count void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
const int seg_per_circle = 64; // Number of segments to approximate a circle
void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
SHAPE_POLY_SET& aShapeBuffer ) SHAPE_POLY_SET& aShapeBuffer )
{ {
// Draw the primitive shape for flashed items. // Draw the primitive shape for flashed items.
@ -100,7 +96,7 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
static std::vector<VECTOR2I> polybuffer; static std::vector<VECTOR2I> polybuffer;
polybuffer.clear(); polybuffer.clear();
const D_CODE* tool = aDcode; aApertMacro->EvalLocalParams( *this );
switch( m_Primitive_id ) switch( m_Primitive_id )
{ {
@ -112,12 +108,12 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* <rotation> is a optional parameter: rotation from origin. * <rotation> is a optional parameter: rotation from origin.
* type is not stored in parameters list, so the first parameter is exposure * type is not stored in parameters list, so the first parameter is exposure
*/ */
ConvertShapeToPolygon( tool, polybuffer ); ConvertShapeToPolygon( aApertMacro, polybuffer );
// shape rotation (if any): // shape rotation (if any):
if( m_Params.size() >= 5 ) if( m_Params.size() >= 5 )
{ {
EDA_ANGLE rotation( m_Params[4].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[4].GetValueFromMacro( aApertMacro ), DEGREES_T );
if( !rotation.IsZero() ) if( !rotation.IsZero() )
{ {
@ -141,10 +137,10 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* type (2), exposure, width, start.x, start.y, end.x, end.y, rotation * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
* type is not stored in parameters list, so the first parameter is exposure * type is not stored in parameters list, so the first parameter is exposure
*/ */
ConvertShapeToPolygon( tool, polybuffer ); ConvertShapeToPolygon( aApertMacro, polybuffer );
// shape rotation: // shape rotation:
EDA_ANGLE rotation( m_Params[6].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[6].GetValueFromMacro( aApertMacro ), DEGREES_T );
if( !rotation.IsZero() ) if( !rotation.IsZero() )
{ {
@ -165,10 +161,10 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* type (21), exposure, ,width, height, center pos.x, center pos.y, rotation * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
* type is not stored in parameters list, so the first parameter is exposure * type is not stored in parameters list, so the first parameter is exposure
*/ */
ConvertShapeToPolygon( tool, polybuffer ); ConvertShapeToPolygon( aApertMacro, polybuffer );
// shape rotation: // shape rotation:
EDA_ANGLE rotation( m_Params[5].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[5].GetValueFromMacro( aApertMacro ), DEGREES_T );
if( !rotation.IsZero() ) if( !rotation.IsZero() )
{ {
@ -186,10 +182,10 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
* type is not stored in parameters list, so the first parameter is exposure * type is not stored in parameters list, so the first parameter is exposure
*/ */
ConvertShapeToPolygon( tool, polybuffer ); ConvertShapeToPolygon( aApertMacro, polybuffer );
// shape rotation: // shape rotation:
EDA_ANGLE rotation( m_Params[5].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[5].GetValueFromMacro( aApertMacro ), DEGREES_T );
if( !rotation.IsZero() ) if( !rotation.IsZero() )
{ {
@ -210,12 +206,12 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* on. * on.
*/ */
std::vector<VECTOR2I> subshape_poly; std::vector<VECTOR2I> subshape_poly;
VECTOR2I center( mapPt( m_Params[0].GetValue( tool ), VECTOR2I center( mapPt( m_Params[0].GetValueFromMacro( aApertMacro ),
m_Params[1].GetValue( tool ), m_GerbMetric ) ); m_Params[1].GetValueFromMacro( aApertMacro ), m_GerbMetric ) );
ConvertShapeToPolygon( tool, subshape_poly ); ConvertShapeToPolygon( aApertMacro, subshape_poly );
// shape rotation: // shape rotation:
EDA_ANGLE rotation( m_Params[5].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[5].GetValueFromMacro( aApertMacro ), DEGREES_T );
// Because a thermal shape has 4 identical sub-shapes, only one is created in subshape_poly. // Because a thermal shape has 4 identical sub-shapes, only one is created in subshape_poly.
// We must draw 4 sub-shapes rotated by 90 deg // We must draw 4 sub-shapes rotated by 90 deg
@ -256,17 +252,17 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* crosshair len, rotation. The type is not stored in parameters list, so the first * crosshair len, rotation. The type is not stored in parameters list, so the first
* parameter is pos.x. * parameter is pos.x.
*/ */
int outerDiam = scaletoIU( m_Params[2].GetValue( tool ), m_GerbMetric ); int outerDiam = scaletoIU( m_Params[2].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int penThickness = scaletoIU( m_Params[3].GetValue( tool ), m_GerbMetric ); int penThickness = scaletoIU( m_Params[3].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int gap = scaletoIU( m_Params[4].GetValue( tool ), m_GerbMetric ); int gap = scaletoIU( m_Params[4].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int numCircles = KiROUND( m_Params[5].GetValue( tool ) ); int numCircles = KiROUND( m_Params[5].GetValueFromMacro( aApertMacro ) );
// Adjust the allowed approx error to convert arcs to segments: // Adjust the allowed approx error to convert arcs to segments:
int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
// Draw circles @ position pos.x, pos.y given by the tool: // Draw circles @ position pos.x, pos.y given by the tool:
VECTOR2I center( mapPt( m_Params[0].GetValue( tool ), m_Params[1].GetValue( tool ), VECTOR2I center( mapPt( m_Params[0].GetValueFromMacro( aApertMacro ),
m_GerbMetric ) ); m_Params[1].GetValueFromMacro( aApertMacro ), m_GerbMetric ) );
// adjust outerDiam by this on each nested circle // adjust outerDiam by this on each nested circle
int diamAdjust = ( gap + penThickness ) * 2; int diamAdjust = ( gap + penThickness ) * 2;
@ -292,9 +288,9 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
} }
// Draw the cross: // Draw the cross:
ConvertShapeToPolygon( tool, polybuffer ); ConvertShapeToPolygon( aApertMacro, polybuffer );
EDA_ANGLE rotation( m_Params[8].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[8].GetValueFromMacro( aApertMacro ), DEGREES_T );
for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
{ {
@ -325,11 +321,11 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* type is not stored in parameters list, so the first parameter is exposure * type is not stored in parameters list, so the first parameter is exposure
*/ */
// m_Params[0] is the exposure and m_Params[1] is the corners count after the first corner // m_Params[0] is the exposure and m_Params[1] is the corners count after the first corner
int numCorners = (int) m_Params[1].GetValue( tool ); int numCorners = (int) m_Params[1].GetValueFromMacro( aApertMacro );
// the shape rotation is the last param of list, after corners // the shape rotation is the last param of list, after corners
int last_prm = m_Params.size() - 1; int last_prm = m_Params.size() - 1;
EDA_ANGLE rotation( m_Params[last_prm].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[last_prm].GetValueFromMacro( aApertMacro ), DEGREES_T );
VECTOR2I pos; VECTOR2I pos;
// Read points. // Read points.
@ -340,9 +336,9 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
for( int i = 0; i <= numCorners; ++i ) for( int i = 0; i <= numCorners; ++i )
{ {
pos.x = scaletoIU( m_Params[prm_idx].GetValue( tool ), m_GerbMetric ); pos.x = scaletoIU( m_Params[prm_idx].GetValueFromMacro( aApertMacro ), m_GerbMetric );
prm_idx++; prm_idx++;
pos.y = scaletoIU( m_Params[prm_idx].GetValue( tool ), m_GerbMetric ); pos.y = scaletoIU( m_Params[prm_idx].GetValueFromMacro( aApertMacro ), m_GerbMetric );
prm_idx++; prm_idx++;
polybuffer.push_back(pos); polybuffer.push_back(pos);
@ -373,13 +369,14 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation
* type is not stored in parameters list, so the first parameter is exposure * type is not stored in parameters list, so the first parameter is exposure
*/ */
VECTOR2I curPos( mapPt( m_Params[2].GetValue( tool ), m_Params[3].GetValue( tool ), m_GerbMetric ) ); VECTOR2I curPos( mapPt( m_Params[2].GetValueFromMacro( aApertMacro ),
m_Params[3].GetValueFromMacro( aApertMacro ), m_GerbMetric ) );
// Creates the shape: // Creates the shape:
ConvertShapeToPolygon( tool, polybuffer ); ConvertShapeToPolygon( aApertMacro, polybuffer );
// rotate polygon // rotate polygon
EDA_ANGLE rotation( m_Params[5].GetValue( tool ), DEGREES_T ); EDA_ANGLE rotation( m_Params[5].GetValueFromMacro( aApertMacro ), DEGREES_T );
for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
{ {
@ -408,11 +405,9 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
} }
void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode, void AM_PRIMITIVE::ConvertShapeToPolygon( APERTURE_MACRO* aApertMacro,
std::vector<VECTOR2I>& aBuffer ) std::vector<VECTOR2I>& aBuffer )
{ {
const D_CODE* tool = aDcode;
switch( m_Primitive_id ) switch( m_Primitive_id )
{ {
case AMP_CIRCLE: case AMP_CIRCLE:
@ -423,17 +418,19 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
* <rotation> is a optional parameter: rotation from origin. * <rotation> is a optional parameter: rotation from origin.
* type is not stored in parameters list, so the first parameter is exposure * type is not stored in parameters list, so the first parameter is exposure
*/ */
int radius = scaletoIU( m_Params[1].GetValue( tool ), m_GerbMetric ) / 2; int radius = scaletoIU( m_Params[1].GetValueFromMacro( aApertMacro ), m_GerbMetric ) / 2;
// A circle primitive can have a 0 size (for instance when used in roundrect macro), // A circle primitive can have a 0 size (for instance when used in roundrect macro),
// so skip it // so skip it
if( radius <= 0 ) if( radius <= 0 )
break; break;
VECTOR2I center = mapPt( m_Params[2].GetValue( tool ), m_Params[3].GetValue( tool ), VECTOR2I center = mapPt( m_Params[2].GetValueFromMacro( aApertMacro ), m_Params[3].GetValueFromMacro( aApertMacro ),
m_GerbMetric ); m_GerbMetric );
VECTOR2I corner; VECTOR2I corner;
EDA_ANGLE delta = ANGLE_360 / seg_per_circle; // rot angle in 0.1 degree
const int seg_per_circle = 64; // Number of segments to approximate a circle
EDA_ANGLE delta = ANGLE_360 / seg_per_circle;
for( EDA_ANGLE angle = ANGLE_0; angle < ANGLE_360; angle += delta ) for( EDA_ANGLE angle = ANGLE_0; angle < ANGLE_360; angle += delta )
{ {
@ -450,11 +447,11 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
case AMP_LINE2: case AMP_LINE2:
case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation) case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
{ {
int width = scaletoIU( m_Params[1].GetValue( tool ), m_GerbMetric ); int width = scaletoIU( m_Params[1].GetValueFromMacro( aApertMacro ), m_GerbMetric );
VECTOR2I start = VECTOR2I start =
mapPt( m_Params[2].GetValue( tool ), m_Params[3].GetValue( tool ), m_GerbMetric ); mapPt( m_Params[2].GetValueFromMacro( aApertMacro ), m_Params[3].GetValueFromMacro( aApertMacro ), m_GerbMetric );
VECTOR2I end = VECTOR2I end =
mapPt( m_Params[4].GetValue( tool ), m_Params[5].GetValue( tool ), m_GerbMetric ); mapPt( m_Params[4].GetValueFromMacro( aApertMacro ), m_Params[5].GetValueFromMacro( aApertMacro ), m_GerbMetric );
VECTOR2I delta = end - start; VECTOR2I delta = end - start;
int len = KiROUND( EuclideanNorm( delta ) ); int len = KiROUND( EuclideanNorm( delta ) );
@ -485,9 +482,9 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
case AMP_LINE_CENTER: case AMP_LINE_CENTER:
{ {
VECTOR2I size = VECTOR2I size =
mapPt( m_Params[1].GetValue( tool ), m_Params[2].GetValue( tool ), m_GerbMetric ); mapPt( m_Params[1].GetValueFromMacro( aApertMacro ), m_Params[2].GetValueFromMacro( aApertMacro ), m_GerbMetric );
VECTOR2I pos = VECTOR2I pos =
mapPt( m_Params[3].GetValue( tool ), m_Params[4].GetValue( tool ), m_GerbMetric ); mapPt( m_Params[3].GetValueFromMacro( aApertMacro ), m_Params[4].GetValueFromMacro( aApertMacro ), m_GerbMetric );
// Build poly: // Build poly:
pos.x -= size.x / 2; pos.x -= size.x / 2;
@ -505,9 +502,9 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
case AMP_LINE_LOWER_LEFT: case AMP_LINE_LOWER_LEFT:
{ {
VECTOR2I size = VECTOR2I size =
mapPt( m_Params[1].GetValue( tool ), m_Params[2].GetValue( tool ), m_GerbMetric ); mapPt( m_Params[1].GetValueFromMacro( aApertMacro ), m_Params[2].GetValueFromMacro( aApertMacro ), m_GerbMetric );
VECTOR2I lowerLeft = VECTOR2I lowerLeft =
mapPt( m_Params[3].GetValue( tool ), m_Params[4].GetValue( tool ), m_GerbMetric ); mapPt( m_Params[3].GetValueFromMacro( aApertMacro ), m_Params[4].GetValueFromMacro( aApertMacro ), m_GerbMetric );
// Build poly: // Build poly:
aBuffer.push_back( lowerLeft ); aBuffer.push_back( lowerLeft );
@ -526,14 +523,14 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
// this first rotated by 90, 180 and 270 deg. // this first rotated by 90, 180 and 270 deg.
// m_Params = center.x (unused here), center.y (unused here), outside diam, inside diam, // m_Params = center.x (unused here), center.y (unused here), outside diam, inside diam,
// crosshair thickness. // crosshair thickness.
int outerRadius = scaletoIU( m_Params[2].GetValue( tool ), m_GerbMetric ) / 2; int outerRadius = scaletoIU( m_Params[2].GetValueFromMacro( aApertMacro ), m_GerbMetric ) / 2;
int innerRadius = scaletoIU( m_Params[3].GetValue( tool ), m_GerbMetric ) / 2; int innerRadius = scaletoIU( m_Params[3].GetValueFromMacro( aApertMacro ), m_GerbMetric ) / 2;
// Safety checks to guarantee no divide-by-zero // Safety checks to guarantee no divide-by-zero
outerRadius = std::max( 1, outerRadius ); outerRadius = std::max( 1, outerRadius );
innerRadius = std::max( 1, innerRadius ); innerRadius = std::max( 1, innerRadius );
int halfthickness = scaletoIU( m_Params[4].GetValue( tool ), m_GerbMetric ) / 2; int halfthickness = scaletoIU( m_Params[4].GetValueFromMacro( aApertMacro ), m_GerbMetric ) / 2;
EDA_ANGLE angle_start( asin( (double) halfthickness / innerRadius ), RADIANS_T ); EDA_ANGLE angle_start( asin( (double) halfthickness / innerRadius ), RADIANS_T );
// Draw shape in the first quadrant (X and Y > 0) // Draw shape in the first quadrant (X and Y > 0)
@ -582,8 +579,8 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
{ {
// A cross hair with n concentric circles. Only the cross is built as // A cross hair with n concentric circles. Only the cross is built as
// polygon because circles can be drawn easily // polygon because circles can be drawn easily
int crossHairThickness = scaletoIU( m_Params[6].GetValue( tool ), m_GerbMetric ); int crossHairThickness = scaletoIU( m_Params[6].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int crossHairLength = scaletoIU( m_Params[7].GetValue( tool ), m_GerbMetric ); int crossHairLength = scaletoIU( m_Params[7].GetValueFromMacro( aApertMacro ), m_GerbMetric );
// Create cross. First create 1/4 of the shape. // Create cross. First create 1/4 of the shape.
// Others point are the same, rotated by 90, 180 and 270 deg // Others point are the same, rotated by 90, 180 and 270 deg
@ -616,8 +613,8 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
case AMP_POLYGON: // Creates a regular polygon case AMP_POLYGON: // Creates a regular polygon
{ {
int vertexcount = KiROUND( m_Params[1].GetValue( tool ) ); int vertexcount = KiROUND( m_Params[1].GetValueFromMacro( aApertMacro ) );
int radius = scaletoIU( m_Params[4].GetValue( tool ), m_GerbMetric ) / 2; int radius = scaletoIU( m_Params[4].GetValueFromMacro( aApertMacro ), m_GerbMetric ) / 2;
// rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis // rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis
if( vertexcount < 3 ) if( vertexcount < 3 )

View File

@ -117,18 +117,21 @@ public:
* In a aperture macro shape, a basic primitive with exposure off is a hole in the shape * In a aperture macro shape, a basic primitive with exposure off is a hole in the shape
* it is NOT a negative shape * it is NOT a negative shape
*/ */
bool IsAMPrimitiveExposureOn( const D_CODE* aDcode ) const; bool IsAMPrimitiveExposureOn( APERTURE_MACRO* aApertMacro ) const;
/** /**
* Generate the polygonal shape of the primitive shape of an aperture * Generate the polygonal shape of the primitive shape of an aperture
* macro instance. * macro instance.
* *
* @param aParent is the parent GERBER_DRAW_ITEM which is actually drawn. * @param aApertMacro is the aperture macro using this primitive.
* @param aShapeBuffer is a SHAPE_POLY_SET to put the shape converted to a polygon. * @param aShapeBuffer is a SHAPE_POLY_SET to put the shape converted to a polygon.
* @param aShapePos is the actual shape position.
*/ */
#if 0
void ConvertBasicShapeToPolygon( const D_CODE* aDcode, void ConvertBasicShapeToPolygon( const D_CODE* aDcode,
SHAPE_POLY_SET& aShapeBuffer ); SHAPE_POLY_SET& aShapeBuffer );
#endif
void ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
SHAPE_POLY_SET& aShapeBuffer );
private: private:
/** /**
@ -141,7 +144,8 @@ private:
* converted because circles are very easy to draw (no rotation problem) so convert * converted because circles are very easy to draw (no rotation problem) so convert
* them in polygons and draw them as polygons is not a good idea. * them in polygons and draw them as polygons is not a good idea.
*/ */
void ConvertShapeToPolygon( const D_CODE* aDcode, std::vector<VECTOR2I>& aBuffer ); //void ConvertShapeToPolygon( const D_CODE* aDcode, std::vector<VECTOR2I>& aBuffer );
void ConvertShapeToPolygon( APERTURE_MACRO* aApertMacroe, std::vector<VECTOR2I>& aBuffer );
}; };

View File

@ -32,6 +32,55 @@
#include <aperture_macro.h> #include <aperture_macro.h>
#include <gerber_draw_item.h> #include <gerber_draw_item.h>
void APERTURE_MACRO::InitLocalParams( const D_CODE* aDcode )
{
// store the initial values coming from aDcode into m_localParamValues
// for n parameters, they are local params $1 to $n
m_localParamValues.clear();
// Note: id_param = 1... n, not 0
for( unsigned id_param = 1; id_param <= aDcode->GetParamCount(); id_param++ )
m_localParamValues[id_param] = aDcode->GetParam( id_param );
m_paramLevelEval = 0;
}
void APERTURE_MACRO::EvalLocalParams( const AM_PRIMITIVE& aPrimitive )
{
// Evaluate m_localParamValues from current m_paramLevelEval to
// aPrimitive.m_LocalParamLevel
// if m_paramLevelEval >= m_LocalParamLevel, do nothing: the
// m_localParamValues are already up to date
if( m_paramLevelEval >= aPrimitive.m_LocalParamLevel )
return;
for( ; m_paramLevelEval < aPrimitive.m_LocalParamLevel; m_paramLevelEval++ )
{
AM_PARAM& am_param = m_localParamStack.at( m_paramLevelEval );
int prm_index = am_param.GetIndex();
double value = am_param.GetValueFromMacro( this );
// if am_param value is not yet stored in m_localParamValues, add it.
// if it is already in m_localParamValues, update its value;
m_localParamValues[ prm_index ] = value;
}
}
double APERTURE_MACRO::GetLocalParamValue( int aIndex )
{
// return the local param value stored in m_localParamValues
// if not existing, returns 0
if( m_localParamValues.find( aIndex ) != m_localParamValues.end() )
return m_localParamValues[ aIndex ];
return 0.0;
}
void APERTURE_MACRO::AddPrimitiveToList( AM_PRIMITIVE& aPrimitive ) void APERTURE_MACRO::AddPrimitiveToList( AM_PRIMITIVE& aPrimitive )
{ {
@ -57,20 +106,21 @@ SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* a
SHAPE_POLY_SET holeBuffer; SHAPE_POLY_SET holeBuffer;
m_shape.RemoveAllContours(); m_shape.RemoveAllContours();
D_CODE * dcode = aParent->GetDcodeDescr(); D_CODE* dcode = aParent->GetDcodeDescr();
InitLocalParams( dcode );
for( AM_PRIMITIVE& prim_macro : m_primitivesList ) for( AM_PRIMITIVE& prim_macro : m_primitivesList )
{ {
if( prim_macro.m_Primitive_id == AMP_COMMENT ) if( prim_macro.m_Primitive_id == AMP_COMMENT )
continue; continue;
if( prim_macro.IsAMPrimitiveExposureOn( dcode ) ) if( prim_macro.IsAMPrimitiveExposureOn( this ) )
{ {
prim_macro.ConvertBasicShapeToPolygon( dcode, m_shape ); prim_macro.ConvertBasicShapeToPolygon( this, m_shape );
} }
else else
{ {
prim_macro.ConvertBasicShapeToPolygon( dcode, holeBuffer ); prim_macro.ConvertBasicShapeToPolygon( this, holeBuffer );
if( holeBuffer.OutlineCount() ) // we have a new hole in shape: remove the hole if( holeBuffer.OutlineCount() ) // we have a new hole in shape: remove the hole
{ {
@ -105,27 +155,3 @@ SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* a
return &m_shape; return &m_shape;
} }
double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const
{
// find parameter descr.
const AM_PARAM * param = nullptr;
for( unsigned ii = 0; ii < m_localParamStack.size(); ii ++ )
{
if( m_localParamStack[ii].GetIndex() == aParamId )
{
param = &m_localParamStack[ii];
break;
}
}
if ( param == nullptr ) // not found
return 0.0;
// Evaluate parameter
double value = param->GetValue( aDcode );
return value;
}

View File

@ -68,6 +68,9 @@ class SHAPE_POLY_SET;
class APERTURE_MACRO class APERTURE_MACRO
{ {
public: public:
APERTURE_MACRO() :
m_paramLevelEval( 0 )
{}
/** /**
* Usually, parameters are defined inside the aperture primitive using immediate mode or * Usually, parameters are defined inside the aperture primitive using immediate mode or
* deferred mode. * deferred mode.
@ -82,14 +85,37 @@ public:
*/ */
double GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const; double GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const;
/**
* Init m_localParamValues to a initial values coming from aDcode and
* clear m_paramLevelEval
* must be called once before trying to build the aperture macro shape
* corresponding to aDcode
*/
void InitLocalParams( const D_CODE* aDcode );
/**
* Evaluate m_localParamValues from current m_paramLevelEval to
* aPrimitive m_LocalParamLevel
* if m_paramLevelEval >= m_LocalParamLevel, do nothing
* after call, m_paramLevelEval = m_LocalParamLevel
*/
void EvalLocalParams( const AM_PRIMITIVE& aPrimitive );
/**
* @return the local param value stored in m_localParamValues
* @param aIndex is the param Id (from $n)
* if not found, returns 0
*/
double GetLocalParamValue( int aIndex );
/** /**
* Calculate the primitive shape for flashed items. * Calculate the primitive shape for flashed items.
* *
* When an item is flashed, this is the shape of the item. * When an item is flashed, this is the shape of the item.
* *
* @param aParent is the parent #GERBER_DRAW_ITEM which is actually drawn.
* @return the shape of the item. * @return the shape of the item.
* @param aParent is the parent #GERBER_DRAW_ITEM which is actually drawn.
* @param aShapePos is the position of the shape to build.
*/ */
SHAPE_POLY_SET* GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent, SHAPE_POLY_SET* GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent,
const VECTOR2I& aShapePos ); const VECTOR2I& aShapePos );
@ -125,6 +151,20 @@ private:
*/ */
AM_PARAMS m_localParamStack; AM_PARAMS m_localParamStack;
/**
* m_localParamValues is the current value of local parameters after evaluation
* the key is the local param id (from $n) and the value is double
*/
std::map<int, double> m_localParamValues;
/**
* the current level of local param values evaluation
* when a primitive is evaluated, if its m_LocalParamLevel is smaller than
* m_paramLevelEval, all local params must be evaluated from current m_paramLevelEval
* upto m_LocalParamLevel before use in this primitive
*/
int m_paramLevelEval;
SHAPE_POLY_SET m_shape; ///< The shape of the item, calculated by GetApertureMacroShape SHAPE_POLY_SET m_shape; ///< The shape of the item, calculated by GetApertureMacroShape
}; };

View File

@ -105,6 +105,7 @@ public:
* Return a parameter stored in parameter list. * Return a parameter stored in parameter list.
* *
* @param aIdx is the index of parameter. * @param aIdx is the index of parameter.
* for n parameters from the Dcode definition, aIdx = 1 .. n, not 0
*/ */
double GetParam( unsigned aIdx ) const double GetParam( unsigned aIdx ) const
{ {

View File

@ -320,7 +320,6 @@ const BOX2I GERBER_DRAW_ITEM::GetBoundingBox() const
case GBR_SPOT_MACRO: case GBR_SPOT_MACRO:
case GBR_SPOT_POLY: case GBR_SPOT_POLY:
{
if( code ) if( code )
{ {
if( code->m_Polygon.OutlineCount() == 0 ) if( code->m_Polygon.OutlineCount() == 0 )
@ -331,7 +330,6 @@ const BOX2I GERBER_DRAW_ITEM::GetBoundingBox() const
} }
break; break;
}
case GBR_SEGMENT: case GBR_SEGMENT:
{ {
@ -861,12 +859,7 @@ bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
} }
case GBR_SPOT_MACRO: case GBR_SPOT_MACRO:
{ return m_AbsolutePolygon.Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
// Aperture macro polygons are already in absolute coordinates
SHAPE_POLY_SET* p =
GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start );
return p->Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
}
case GBR_SEGMENT: case GBR_SEGMENT:
case GBR_CIRCLE: case GBR_CIRCLE:

View File

@ -566,21 +566,26 @@ void GERBVIEW_PAINTER::drawFlashedShape( GERBER_DRAW_ITEM* aItem, bool aFilled )
void GERBVIEW_PAINTER::drawApertureMacro( GERBER_DRAW_ITEM* aParent, bool aFilled ) void GERBVIEW_PAINTER::drawApertureMacro( GERBER_DRAW_ITEM* aParent, bool aFilled )
{ {
if( aParent->m_AbsolutePolygon.OutlineCount() == 0 )
{
D_CODE* code = aParent->GetDcodeDescr(); D_CODE* code = aParent->GetDcodeDescr();
APERTURE_MACRO* macro = code->GetMacro(); APERTURE_MACRO* macro = code->GetMacro();
SHAPE_POLY_SET* macroShape = macro->GetApertureMacroShape( aParent, aParent->m_Start ); aParent->m_AbsolutePolygon = *macro->GetApertureMacroShape( aParent, aParent->m_Start );
}
SHAPE_POLY_SET& polyset = aParent->m_AbsolutePolygon;
if( !gvconfig()->m_Display.m_DisplayPolygonsFill ) if( !gvconfig()->m_Display.m_DisplayPolygonsFill )
m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth ); m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth );
if( !aFilled ) if( !aFilled )
{ {
for( int i = 0; i < macroShape->OutlineCount(); i++ ) for( int i = 0; i < polyset.OutlineCount(); i++ )
m_gal->DrawPolyline( macroShape->COutline( i ) ); m_gal->DrawPolyline( polyset.COutline( i ) );
} }
else else
{ {
m_gal->DrawPolygon( *macroShape ); m_gal->DrawPolygon( polyset );
} }
} }

View File

@ -1132,7 +1132,7 @@ bool GERBER_FILE_IMAGE::ReadApertureMacro( char *aBuff, unsigned int aBuffSize,
// in advance, i.e. be immediate. // in advance, i.e. be immediate.
wxASSERT( prim.m_Params[1].IsImmediate() ); wxASSERT( prim.m_Params[1].IsImmediate() );
paramCount = (int) prim.m_Params[1].GetValue( nullptr ) * 2 + 1; paramCount = (int) prim.m_Params[1].GetValueFromMacro( nullptr ) * 2 + 1;
for( int jj = 0; jj < paramCount && *aText != '*'; ++jj ) for( int jj = 0; jj < paramCount && *aText != '*'; ++jj )
{ {