From 54b4f0e673c5c761541a7c79687f418e27ed3288 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 11 Feb 2023 12:00:02 +0100 Subject: [PATCH] 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 --- gerbview/am_param.cpp | 29 ++++----- gerbview/am_param.h | 2 +- gerbview/am_primitive.cpp | 107 +++++++++++++++++----------------- gerbview/am_primitive.h | 12 ++-- gerbview/aperture_macro.cpp | 84 +++++++++++++++++--------- gerbview/aperture_macro.h | 44 +++++++++++++- gerbview/dcode.h | 1 + gerbview/gerber_draw_item.cpp | 9 +-- gerbview/gerbview_painter.cpp | 17 ++++-- gerbview/rs274x.cpp | 2 +- 10 files changed, 183 insertions(+), 124 deletions(-) diff --git a/gerbview/am_param.cpp b/gerbview/am_param.cpp index 69549fd7ae..2b41f0d182 100644 --- a/gerbview/am_param.cpp +++ b/gerbview/am_param.cpp @@ -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 diff --git a/gerbview/am_param.h b/gerbview/am_param.h index 7eaf6ee397..30035121ef 100644 --- a/gerbview/am_param.h +++ b/gerbview/am_param.h @@ -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 diff --git a/gerbview/am_primitive.cpp b/gerbview/am_primitive.cpp index 39240c2ec8..37afe673da 100644 --- a/gerbview/am_primitive.cpp +++ b/gerbview/am_primitive.cpp @@ -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 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, * 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 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& 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, * 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 ) diff --git a/gerbview/am_primitive.h b/gerbview/am_primitive.h index a644c78647..a0b5b2ea1b 100644 --- a/gerbview/am_primitive.h +++ b/gerbview/am_primitive.h @@ -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& aBuffer ); + //void ConvertShapeToPolygon( const D_CODE* aDcode, std::vector& aBuffer ); + void ConvertShapeToPolygon( APERTURE_MACRO* aApertMacroe, std::vector& aBuffer ); }; diff --git a/gerbview/aperture_macro.cpp b/gerbview/aperture_macro.cpp index dbf2a1af5f..45f6d841bb 100644 --- a/gerbview/aperture_macro.cpp +++ b/gerbview/aperture_macro.cpp @@ -32,6 +32,55 @@ #include #include +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 ) { @@ -52,25 +101,26 @@ AM_PARAM& APERTURE_MACRO::GetLastLocalParamDefFromStack() SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent, - const VECTOR2I& aShapePos ) + const VECTOR2I& aShapePos ) { 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; -} diff --git a/gerbview/aperture_macro.h b/gerbview/aperture_macro.h index c6ef86bf21..9260fdb766 100644 --- a/gerbview/aperture_macro.h +++ b/gerbview/aperture_macro.h @@ -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,17 +85,40 @@ 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 ); + const VECTOR2I& aShapePos ); /** * The name of the aperture macro as defined like %AMVB_RECTANGLE* (name is VB_RECTANGLE) @@ -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 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 }; diff --git a/gerbview/dcode.h b/gerbview/dcode.h index b7a36734a1..94b3ba18a1 100644 --- a/gerbview/dcode.h +++ b/gerbview/dcode.h @@ -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 { diff --git a/gerbview/gerber_draw_item.cpp b/gerbview/gerber_draw_item.cpp index bf6fe03e1b..169e42912f 100644 --- a/gerbview/gerber_draw_item.cpp +++ b/gerbview/gerber_draw_item.cpp @@ -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: diff --git a/gerbview/gerbview_painter.cpp b/gerbview/gerbview_painter.cpp index 0dc73fe6a9..3ec714bd9c 100644 --- a/gerbview/gerbview_painter.cpp +++ b/gerbview/gerbview_painter.cpp @@ -566,21 +566,26 @@ void GERBVIEW_PAINTER::drawFlashedShape( GERBER_DRAW_ITEM* aItem, bool aFilled ) void GERBVIEW_PAINTER::drawApertureMacro( GERBER_DRAW_ITEM* aParent, bool aFilled ) { - D_CODE* code = aParent->GetDcodeDescr(); - APERTURE_MACRO* macro = code->GetMacro(); - SHAPE_POLY_SET* macroShape = macro->GetApertureMacroShape( aParent, aParent->m_Start ); + if( aParent->m_AbsolutePolygon.OutlineCount() == 0 ) + { + D_CODE* code = aParent->GetDcodeDescr(); + APERTURE_MACRO* macro = code->GetMacro(); + 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 ); } } diff --git a/gerbview/rs274x.cpp b/gerbview/rs274x.cpp index c4d28886f1..e7a1336e80 100644 --- a/gerbview/rs274x.cpp +++ b/gerbview/rs274x.cpp @@ -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 ) {