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;
}
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:
// 0-$2/2-$4
@ -102,22 +103,15 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
break;
case PUSHPARM:
// a defered value: get the actual parameter from the aDcode
if( aDcode ) // should be always true here
// a defered value: get the actual parameter from the aperture macro
if( aApertureMacro ) // should be always true here
{
if( item.GetIndex() <= aDcode->GetParamCount() )
{
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() );
}
// Get the actual value
curr_value = aApertureMacro->GetLocalParamValue( item.GetIndex() );
}
else
{
wxFAIL_MSG( wxT( "AM_PARAM::GetValue(): NULL param aDcode" ) );
wxFAIL_MSG( wxT( "AM_PARAM::GetValue(): NULL param aApertureMacro" ) );
}
ops.emplace_back( curr_value );
@ -129,10 +123,8 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
break;
default:
wxFAIL_MSG( wxString::Format( wxT( "AM_PARAM::GetValue(): dcode %d prm %d/%d: "
"unexpected type %d" ),
aDcode ? aDcode->m_Num_Dcode : -1, ii,
m_paramStack.size(), item.GetType() ) );
wxFAIL_MSG( wxString::Format( wxT( "AM_PARAM::GetValue(): unexpected prm type %d" ),
item.GetType() ) );
break;
}
}
@ -142,6 +134,7 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
return result;
}
/**
* add an operator/operand to the current stack
* 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, 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

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.
@ -75,7 +75,7 @@ bool AM_PRIMITIVE::IsAMPrimitiveExposureOn( const D_CODE* aDcode ) const
case AMP_OUTLINE:
case AMP_POLYGON:
// 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;
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
const int seg_per_circle = 64; // Number of segments to approximate a circle
void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
SHAPE_POLY_SET& aShapeBuffer )
{
// Draw the primitive shape for flashed items.
@ -100,7 +96,7 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
static std::vector<VECTOR2I> polybuffer;
polybuffer.clear();
const D_CODE* tool = aDcode;
aApertMacro->EvalLocalParams( *this );
switch( m_Primitive_id )
{
@ -112,12 +108,12 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* <rotation> is a optional parameter: rotation from origin.
* type is not stored in parameters list, so the first parameter is exposure
*/
ConvertShapeToPolygon( tool, polybuffer );
ConvertShapeToPolygon( aApertMacro, polybuffer );
// shape rotation (if any):
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() )
{
@ -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 is not stored in parameters list, so the first parameter is exposure
*/
ConvertShapeToPolygon( tool, polybuffer );
ConvertShapeToPolygon( aApertMacro, polybuffer );
// 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() )
{
@ -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 is not stored in parameters list, so the first parameter is exposure
*/
ConvertShapeToPolygon( tool, polybuffer );
ConvertShapeToPolygon( aApertMacro, polybuffer );
// 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() )
{
@ -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 is not stored in parameters list, so the first parameter is exposure
*/
ConvertShapeToPolygon( tool, polybuffer );
ConvertShapeToPolygon( aApertMacro, polybuffer );
// 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() )
{
@ -210,12 +206,12 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
* on.
*/
std::vector<VECTOR2I> subshape_poly;
VECTOR2I center( mapPt( m_Params[0].GetValue( tool ),
m_Params[1].GetValue( tool ), m_GerbMetric ) );
ConvertShapeToPolygon( tool, subshape_poly );
VECTOR2I center( mapPt( m_Params[0].GetValueFromMacro( aApertMacro ),
m_Params[1].GetValueFromMacro( aApertMacro ), m_GerbMetric ) );
ConvertShapeToPolygon( aApertMacro, subshape_poly );
// 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.
// 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
* parameter is pos.x.
*/
int outerDiam = scaletoIU( m_Params[2].GetValue( tool ), m_GerbMetric );
int penThickness = scaletoIU( m_Params[3].GetValue( tool ), m_GerbMetric );
int gap = scaletoIU( m_Params[4].GetValue( tool ), m_GerbMetric );
int numCircles = KiROUND( m_Params[5].GetValue( tool ) );
int outerDiam = scaletoIU( m_Params[2].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int penThickness = scaletoIU( m_Params[3].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int gap = scaletoIU( m_Params[4].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int numCircles = KiROUND( m_Params[5].GetValueFromMacro( aApertMacro ) );
// Adjust the allowed approx error to convert arcs to segments:
int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
// Draw circles @ position pos.x, pos.y given by the tool:
VECTOR2I center( mapPt( m_Params[0].GetValue( tool ), m_Params[1].GetValue( tool ),
m_GerbMetric ) );
VECTOR2I center( mapPt( m_Params[0].GetValueFromMacro( aApertMacro ),
m_Params[1].GetValueFromMacro( aApertMacro ), m_GerbMetric ) );
// adjust outerDiam by this on each nested circle
int diamAdjust = ( gap + penThickness ) * 2;
@ -292,9 +288,9 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
}
// 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++ )
{
@ -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
*/
// 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
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;
// Read points.
@ -340,9 +336,9 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( const D_CODE* aDcode,
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++;
pos.y = scaletoIU( m_Params[prm_idx].GetValue( tool ), m_GerbMetric );
pos.y = scaletoIU( m_Params[prm_idx].GetValueFromMacro( aApertMacro ), m_GerbMetric );
prm_idx++;
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 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:
ConvertShapeToPolygon( tool, polybuffer );
ConvertShapeToPolygon( aApertMacro, polybuffer );
// 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++ )
{
@ -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 )
{
const D_CODE* tool = aDcode;
switch( m_Primitive_id )
{
case AMP_CIRCLE:
@ -423,17 +418,19 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
* <rotation> is a optional parameter: rotation from origin.
* 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),
// so skip it
if( radius <= 0 )
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 );
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 )
{
@ -450,11 +447,11 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
case AMP_LINE2:
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 =
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 =
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;
int len = KiROUND( EuclideanNorm( delta ) );
@ -485,9 +482,9 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
case AMP_LINE_CENTER:
{
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 =
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:
pos.x -= size.x / 2;
@ -505,9 +502,9 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const D_CODE* aDcode,
case AMP_LINE_LOWER_LEFT:
{
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 =
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:
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.
// m_Params = center.x (unused here), center.y (unused here), outside diam, inside diam,
// crosshair thickness.
int outerRadius = scaletoIU( m_Params[2].GetValue( tool ), m_GerbMetric ) / 2;
int innerRadius = scaletoIU( m_Params[3].GetValue( tool ), m_GerbMetric ) / 2;
int outerRadius = scaletoIU( m_Params[2].GetValueFromMacro( aApertMacro ), m_GerbMetric ) / 2;
int innerRadius = scaletoIU( m_Params[3].GetValueFromMacro( aApertMacro ), m_GerbMetric ) / 2;
// Safety checks to guarantee no divide-by-zero
outerRadius = std::max( 1, outerRadius );
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 );
// 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
// polygon because circles can be drawn easily
int crossHairThickness = scaletoIU( m_Params[6].GetValue( tool ), m_GerbMetric );
int crossHairLength = scaletoIU( m_Params[7].GetValue( tool ), m_GerbMetric );
int crossHairThickness = scaletoIU( m_Params[6].GetValueFromMacro( aApertMacro ), m_GerbMetric );
int crossHairLength = scaletoIU( m_Params[7].GetValueFromMacro( aApertMacro ), m_GerbMetric );
// Create cross. First create 1/4 of the shape.
// 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
{
int vertexcount = KiROUND( m_Params[1].GetValue( tool ) );
int radius = scaletoIU( m_Params[4].GetValue( tool ), m_GerbMetric ) / 2;
int vertexcount = KiROUND( m_Params[1].GetValueFromMacro( aApertMacro ) );
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
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
* 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
* 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 aShapePos is the actual shape position.
*/
#if 0
void ConvertBasicShapeToPolygon( const D_CODE* aDcode,
SHAPE_POLY_SET& aShapeBuffer );
#endif
void ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
SHAPE_POLY_SET& aShapeBuffer );
private:
/**
@ -141,7 +144,8 @@ private:
* 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.
*/
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 <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 )
{
@ -57,20 +106,21 @@ SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* a
SHAPE_POLY_SET holeBuffer;
m_shape.RemoveAllContours();
D_CODE * dcode = aParent->GetDcodeDescr();
D_CODE* dcode = aParent->GetDcodeDescr();
InitLocalParams( dcode );
for( AM_PRIMITIVE& prim_macro : m_primitivesList )
{
if( prim_macro.m_Primitive_id == AMP_COMMENT )
continue;
if( prim_macro.IsAMPrimitiveExposureOn( dcode ) )
if( prim_macro.IsAMPrimitiveExposureOn( this ) )
{
prim_macro.ConvertBasicShapeToPolygon( dcode, m_shape );
prim_macro.ConvertBasicShapeToPolygon( this, m_shape );
}
else
{
prim_macro.ConvertBasicShapeToPolygon( dcode, holeBuffer );
prim_macro.ConvertBasicShapeToPolygon( this, holeBuffer );
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;
}
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
{
public:
APERTURE_MACRO() :
m_paramLevelEval( 0 )
{}
/**
* Usually, parameters are defined inside the aperture primitive using immediate mode or
* deferred mode.
@ -82,14 +85,37 @@ public:
*/
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.
*
* 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.
* @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,
const VECTOR2I& aShapePos );
@ -125,6 +151,20 @@ private:
*/
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
};

View File

@ -105,6 +105,7 @@ public:
* Return a parameter stored in parameter list.
*
* @param aIdx is the index of parameter.
* for n parameters from the Dcode definition, aIdx = 1 .. n, not 0
*/
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_POLY:
{
if( code )
{
if( code->m_Polygon.OutlineCount() == 0 )
@ -331,7 +330,6 @@ const BOX2I GERBER_DRAW_ITEM::GetBoundingBox() const
}
break;
}
case GBR_SEGMENT:
{
@ -861,12 +859,7 @@ bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
}
case GBR_SPOT_MACRO:
{
// 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 );
}
return m_AbsolutePolygon.Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
case GBR_SEGMENT:
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 )
{
if( aParent->m_AbsolutePolygon.OutlineCount() == 0 )
{
D_CODE* code = aParent->GetDcodeDescr();
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 )
m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth );
if( !aFilled )
{
for( int i = 0; i < macroShape->OutlineCount(); i++ )
m_gal->DrawPolyline( macroShape->COutline( i ) );
for( int i = 0; i < polyset.OutlineCount(); i++ )
m_gal->DrawPolyline( polyset.COutline( i ) );
}
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.
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 )
{