diff --git a/CHANGELOG.txt b/CHANGELOG.txt index d1601660fb..2ba70c66c4 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,6 +4,20 @@ KiCad ChangeLog 2010 Please add newer entries at the top, list the date and your name with email address. +2010-dec-01, UPDATE Jean-Pierre Charras +================================================================================ +Gerbview: + Added support for complex definitions of parameters in aperture macros and primitives macro + (a complex definition in a parameter that is calculated by an arithmetical expression) + Gerbview should now have a decent support of Gerber language. + Currently only the obscure knockout command is not supported (I have no motivation to do that) + Other "bug": + scale in A and B axis is poorly supported: coordinates are scaled, but shapes can have problem: + fro instance, a circle is drawn as a circle when A and B scales are different, + and perhaps should be an ellipse. + On the other hand, Gerber doc is not clear about the meaning of A and B scale. + (Alas! Gerber doc is not clear about most of advanced commands) + 2010-nov-19 UPDATE Wayne Stambaugh ================================================================================ ++EESchema diff --git a/gerbview/class_am_param.cpp b/gerbview/class_am_param.cpp index b661e1c977..65feb88597 100644 --- a/gerbview/class_am_param.cpp +++ b/gerbview/class_am_param.cpp @@ -28,39 +28,126 @@ */ #include "class_am_param.h" +#include "class_aperture_macro.h" extern int ReadInt( char*& text, bool aSkipSeparator = true ); extern double ReadDouble( char*& text, bool aSkipSeparator = true ); -/*Class AM_PARAM - * holds a parameter for an "aperture macro" as defined within - * standard RS274X. The \a value field can be a constant, i.e. "immediate" - * parameter or it may not be used if this param is going to defer to the - * referencing aperture macro. In that case, the \a index field is an index - * into the aperture macro's parameters. +/* Class AM_PARAM + * holds a parameter value for an "aperture macro" as defined within + * standard RS274X. The parameter can be a constant, i.e. "immediate" parameter, + * or depend on some defered values, defined in a D_CODE, by the ADD command. + * Note the actual value could need an evaluation from an arithmetical expression + * items in the expression are stored in . + * A simple definition is just a value stored in one item in m_paramStack */ +AM_PARAM::AM_PARAM( ) +{ + m_index = -1; +} + +/** + * Function IsImmediate + * tests if this AM_PARAM holds an immediate parameter or has parameter + * held by an owning D_CODE. + */ +bool AM_PARAM::IsImmediate() const +{ + bool isimmediate = true; + for( unsigned ii = 0; ii < m_paramStack.size(); ii++ ) + { + if( m_paramStack[ii].IsDefered() ) + { // a defered value is found in operand list, + // so the parameter is not immediate + isimmediate = false; + break; + } + } + return isimmediate; +} double AM_PARAM::GetValue( const D_CODE* aDcode ) const { - if( IsImmediate() ) - return value; - else + double paramvalue = 0.0; + double curr_value = 0.0; + parm_item_type state = POPVALUE; + for( unsigned ii = 0; ii < m_paramStack.size(); ii++ ) { - // the first one was numbered 1, not zero, as in $1, see page 19 of spec. - unsigned ndx = GetIndex(); - wxASSERT( aDcode ); - - // get the parameter from the aDcode - if( ndx <= aDcode->GetParamCount() ) - return aDcode->GetParam( ndx ); - else + AM_PARAM_ITEM item = m_paramStack[ii]; + switch( item.GetType() ) { - wxASSERT( GetIndex() <= aDcode->GetParamCount() ); - return 0.0; + case ADD: + case SUB: + case MUL: + case DIV: // just an operator for next parameter value: store it + state = item.GetType(); + break; + + case PUSHPARM: + // get the parameter from the aDcode + if( aDcode && 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() ); + } + // Fall through + case PUSHVALUE: // a value is on the stack: + if( item.GetType() == PUSHVALUE ) + curr_value = item.GetValue(); + switch( state ) + { + case POPVALUE: + paramvalue = curr_value; + break; + + case ADD: + paramvalue += curr_value; + break; + + case SUB: + paramvalue -= curr_value; + break; + + case MUL: + paramvalue *= curr_value; + break; + + case DIV: + paramvalue /= curr_value; + break; + + default: + wxLogDebug( wxT( "AM_PARAM::GetValue() : unexpected operator\n" ) ); + break; + } + break; + + default: + wxLogDebug( wxT( "AM_PARAM::GetValue(): unexpected type\n" ) ); + break; } } + return paramvalue; } +/** + * add an operator/operand to the current stack + * aType = NOP, PUSHVALUE, PUSHPARM, ADD, SUB, MUL, DIV, EQUATE + * aValue required only for PUSHVALUE (double) or PUSHPARM (int) aType. + */ +void AM_PARAM::PushOperator( parm_item_type aType, double aValue ) +{ + AM_PARAM_ITEM item( aType, aValue); + m_paramStack.push_back( item ); +} + +void AM_PARAM::PushOperator( parm_item_type aType, int aValue ) +{ + AM_PARAM_ITEM item( aType, aValue); + m_paramStack.push_back( item ); +} /** * Function ReadParam @@ -70,6 +157,7 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const * a reference to an aperture definition parameter value: $1 ot $3 ... * a parameter definition can be complex and have operators between numbers and/or other parameter * like $1+3 or $2x2.. + * Note minus sign is not always an operator. It can be the sign of a value. * Parameters are separated by a comma ( of finish by *) * @param aText = pointer to the parameter to read. Will be modified to point to the next field * @return true if a param is read, or false @@ -77,25 +165,79 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const bool AM_PARAM::ReadParam( char*& aText ) { bool found = false; + int ivalue; + double dvalue; + bool end = false; - if( *aText == '$' ) // value defined later, in aperture description + while( !end ) { - ++aText; - SetIndex( ReadInt( aText, false ) ); - found = true; - } - else - { - SetValue( ReadDouble( aText, false ) ); - found = true; - } + switch( *aText ) + { + case ',': + aText++; + // fall through + case 0: // EOL + case '*': // Terminator in a gerber command + end = true; + break; - // Skip extra characters and separator - while( *aText && (*aText != ',') && (*aText != '*') ) - aText++; + case ' ': + aText++; + break; - if( *aText == ',' ) - aText++; + case '$': + // defered value defined later, in ADD command which define defered parameters + ++aText; + ivalue = ReadInt( aText, false ); + if( m_index < 1 ) + SetIndex( ivalue ); + PushOperator( PUSHPARM, ivalue ); + found = true; + break; + + case '/': + PushOperator( DIV ); + aText++; + break; + + case 'x': + case 'X': + PushOperator( MUL ); + aText++; + break; + + case '-': + case '+': + // Test if this is an operator between 2 params, or the sign of a value + if( m_paramStack.size() > 0 && !m_paramStack.back().IsOperator() ) + { // Seems an operator + PushOperator( *aText == '+' ? ADD : SUB ); + aText++; + } + else + { // seems the sign of a value + dvalue = ReadDouble( aText, false ); + PushOperator( PUSHVALUE, dvalue ); + found = true; + } + break; + + case '=': // A local definition found like $4=$3/2 + // At this point, one defered parameter is expected to be read. + // this parameter value (the index) is stored in m_index. + // The list of items is cleared + aText++; + m_paramStack.clear(); + found = false; + break; + + default: + dvalue = ReadDouble( aText, false ); + PushOperator( PUSHVALUE, dvalue ); + found = true; + break; + } + } return found; } diff --git a/gerbview/class_am_param.h b/gerbview/class_am_param.h index 681d5e9f68..d396cfd1d8 100644 --- a/gerbview/class_am_param.h +++ b/gerbview/class_am_param.h @@ -103,50 +103,151 @@ #include #include "dcode.h" +/* +Values of a parameter can be the result of an arithmetic operation, +between immediate values and defered value. +From an idea found in Gerbv, here is the way to evaluate a parameter. +a AM_PARAM_ITEM holds info about operands and operators in a parameter definition +( a AM_PARAM ) like $2+$2-$3-$3/2 + +There is no precedence defined in gerber RS274X, so actual value is calculated step to step. +Parameter definition is described by a very primitive assembler. +This "program "should describe how to calculate the parameter. +The assembler consist of 8 instruction intended for a stackbased machine. +The instructions are: +NOP, PUSHVALUE, PUSHPARM, ADD, SUB, MUL, DIV, EQUATE + +The instructions +---------------- +NOP : The no operation. This is the default instruction and are + added as a security measure. +PUSHVALUE : Pushes an arithmetical value on the stack. This machine only works with floats + on the stack. +PUSHPARM: Pushes a defered parameter onto the stack. Gerber aperture macros accepts + parameters to be set when later declared, so the same macro can + be used at several instances. Which parameter to be set is an integer + and starts with 1. definition is like $1 or $3 +ADD : The mathematical operation +. Takes the two uppermost values on the + the stack, adds them and pushes the result back onto the stack. +SUB : Same as ADD, but with -. +MUL : Same as ADD, but with *. +DIV : Same as ADD, but with /. +POPVALUE : used when evaluate the expression: store current calculated value +*/ + +enum parm_item_type +{ + NOP, PUSHVALUE, PUSHPARM, ADD, SUB, MUL, DIV, POPVALUE +}; /** * Class AM_PARAM - * holds a parameter for an "aperture macro" as defined within + * holds an operand for an AM_PARAM as defined within * standard RS274X. The \a value field can be a constant, i.e. "immediate" * parameter or it may not be used if this param is going to defer to the * referencing aperture macro. In that case, the \a index field is an index * into the aperture macro's parameters. */ -class AM_PARAM +class AM_PARAM_ITEM { -public: AM_PARAM() : - index( -1 ), - value( 0.0 ) - {} +private: + parm_item_type m_type; // the type of item + double m_dvalue; // the value, for PUSHVALUE type item + int m_ivalue; // the integer value, for PUSHPARM type item - double GetValue( const D_CODE* aDcode ) const; +public: + AM_PARAM_ITEM( parm_item_type aType = NOP, double aValue = 0.0) + { + m_type = aType; + m_dvalue = aValue; + m_ivalue = 0; + } + AM_PARAM_ITEM( parm_item_type aType = NOP, int aValue = 0) + { + m_type = aType; + m_dvalue = 0.0; + m_ivalue = aValue; + } void SetValue( double aValue ) { - value = aValue; - index = -1; + m_dvalue = aValue; } + double GetValue( ) const + { + return m_dvalue; + } + parm_item_type GetType() const + { + return m_type; + } + unsigned GetIndex() const + { + return (unsigned) m_ivalue; + } + bool IsOperator() const + { + return m_type == ADD || m_type == SUB || m_type == MUL || m_type == DIV; + } + bool IsOperand() const + { + return m_type == PUSHVALUE || m_type == PUSHPARM; + } + bool IsDefered() const + { + return m_type == PUSHPARM; + } +}; +/** + * Class AM_PARAM + * holds a parameter value for an "aperture macro" as defined within + * standard RS274X. The parameter can be a constant, i.e. "immediate" parameter, + * or depend on some defered values, defined in a D_CODE, by the ADD command. + * Note the actual value could need an evaluation from an arithmetical expression + * items in the expression are stored in . + * A simple definition is just a value stored in one item in m_paramStack + */ +class AM_PARAM +{ +private: + int m_index; // has meaning to define parameter local to an aperture macro + std::vector m_paramStack; // list of operands/operators to evalutate the actual value + // if a par def is $3/2, there are 3 items in stack: + // 3 (type PUSHPARM) , / (type DIV), 2 (type PUSHVALUE) + +public: + AM_PARAM(); + + /** + * function PushOperator + * add an operator/operand to the current stack + * @param aType = the type of item (NOP, PUSHVALUE, PUSHPARM, ADD, SUB, MUL, DIV, EQUATE) + * @param aValue = the item value, double for PUSHVALUE or int for PUSHPARM type. + */ + void PushOperator( parm_item_type aType, double aValue ); + void PushOperator( parm_item_type aType, int aValue = 0); + + double GetValue( const D_CODE* aDcode ) const; /** * Function IsImmediate * tests if this AM_PARAM holds an immediate parameter or is a pointer * into a parameter held by an owning D_CODE. + * @return true if the value is immediate, i.e. no defered value in operands used in its definition */ - bool IsImmediate() const { return index == -1; } + bool IsImmediate() const; unsigned GetIndex() const { - return (unsigned) index; + return (unsigned) m_index; } - void SetIndex( int aIndex ) { - index = aIndex; + m_index = aIndex; } - /** * Function ReadParam * Read one aperture macro parameter @@ -160,13 +261,6 @@ public: AM_PARAM() : * @return true if a param is read, or false */ bool ReadParam( char*& aText ); - -private: - int index; ///< if -1, then \a value field is an immediate value, - // else this is an index into parent's - // D_CODE.m_am_params. - double value; ///< if IsImmediate()==true then use the value, else - // not used. }; typedef std::vector AM_PARAMS; diff --git a/gerbview/class_aperture_macro.cpp b/gerbview/class_aperture_macro.cpp index e885131a7b..c6f61793a1 100644 --- a/gerbview/class_aperture_macro.cpp +++ b/gerbview/class_aperture_macro.cpp @@ -56,7 +56,6 @@ static wxPoint mapPt( double x, double y, bool isMetric ) return ret; } - /** * Function mapExposure * translates the first parameter from an aperture macro into a current @@ -762,3 +761,33 @@ int APERTURE_MACRO::GetShapeDim( GERBER_DRAW_ITEM* aParent ) return dim; } + + +/** + * function GetLocalParam + * Usually, parameters are defined inside the aperture primitive + * using immediate mode or defered mode. + * in defered mode the value is defined in a DCODE that want to use the aperture macro. + * But some parameters are defined outside the aperture primitive + * and are local to the aperture macro + * @return the value of a defered parameter defined inside the aperture macro + * @param aParamId = the param id (defined by $3 or $5 ..) to evaluate + */ +double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const +{ + // find parameter descr. + const AM_PARAM * param = NULL; + for( unsigned ii = 0; ii < m_localparamStack.size(); ii ++ ) + { + if( m_localparamStack[ii].GetIndex() == aParamId ) + { + param = &m_localparamStack[ii]; + break; + } + } + if ( param == NULL ) // not found + return 0.0; + // Evaluate parameter + double value = param->GetValue( aDcode ); + return value; +} diff --git a/gerbview/class_aperture_macro.h b/gerbview/class_aperture_macro.h index 18a7faccbe..9f04180348 100644 --- a/gerbview/class_aperture_macro.h +++ b/gerbview/class_aperture_macro.h @@ -45,6 +45,13 @@ * Each parameter can be an immediate value or a defered value. * When value is defered, it is defined when the aperture macro is instancied by * an ADD macro command + * Note also a defered parameter can be defined in aperture macro, + * but outside aperture primitives. Example + * %AMRECTHERM* + * $4=$3/2* parameter $4 is half value of parameter $3 + * 21,1,$1-$3,$2-$3,0-$1/2-$4,0-$2/2-$4,0* + * For the aperture primitive, parameters $1 to $3 will be defined in ADD command, + * and $4 is defined inside the macro */ /** @@ -83,7 +90,6 @@ public: // the primitive bool m_GerbMetric; // units for this primitive: // false = Inches, true = metric - public: AM_PRIMITIVE( bool aGerbMetric, AM_PRIMITIVE_ID aId = AMP_UNKNOWN ) { primitive_id = aId; @@ -167,7 +173,27 @@ struct APERTURE_MACRO wxString name; ///< The name of the aperture macro AM_PRIMITIVES primitives; ///< A sequence of AM_PRIMITIVEs + /* A defered parameter can be defined in aperture macro, + * but outside aperture primitives. Example + * %AMRECTHERM* + * $4=$3/2* parameter $4 is half value of parameter $3 + * m_localparamStack handle a list of local defered parameters + */ + AM_PARAMS m_localparamStack; + /** + * function GetLocalParam + * Usually, parameters are defined inside the aperture primitive + * using immediate mode or defered mode. + * in defered mode the value is defined in a DCODE that want to use the aperture macro. + * But some parameters are defined outside the aperture primitive + * and are local to the aperture macro + * @return the value of a defered parameter defined inside the aperture macro + * @param aParamId = the param id (defined by $3 or $5 ..) to evaluate + */ + double GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const; + + /** * Function DrawApertureMacroShape * Draw the primitive shape for flashed items. * When an item is flashed, this is the shape of the item diff --git a/gerbview/dcode.h b/gerbview/dcode.h index 01b0c6fd84..8df1c39076 100644 --- a/gerbview/dcode.h +++ b/gerbview/dcode.h @@ -146,7 +146,7 @@ public: } - APERTURE_MACRO* GetMacro() { return m_Macro; } + APERTURE_MACRO* GetMacro() const { return m_Macro; } /** * Function ShowApertureType diff --git a/gerbview/rs274x.cpp b/gerbview/rs274x.cpp index 63b61d663e..59bdc66054 100644 --- a/gerbview/rs274x.cpp +++ b/gerbview/rs274x.cpp @@ -837,12 +837,15 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ], // it can be: a parameter declaration like $1=$2/4 // or a digit (macro primitive selection) // all other symbols are illegal. - if( *text == '$' ) // parameter declaration, not yet supported + if( *text == '$' ) // local parameter declaration, inside the aperture macro { - msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": Operator $ not yet supported here, line: \"%s\"" ), - GetChars( am.name ), GetChars( CONV_FROM_UTF8( buff ) ) ); - ReportMessage( msg ); - primitive_type = AMP_COMMENT; + am.m_localparamStack.push_back( AM_PARAM() ); + AM_PARAM& param = am.m_localparamStack.back(); + text = GetNextLine( buff, text, gerber_file ); + if( text == NULL) // End of File + return false; + param.ReadParam( text ); + continue; } else if( !isdigit(*text) ) // Ill. symbol { diff --git a/include/boost/polygon/isotropy.hpp b/include/boost/polygon/isotropy.hpp index c7cda49a4f..59a480ce90 100644 --- a/include/boost/polygon/isotropy.hpp +++ b/include/boost/polygon/isotropy.hpp @@ -48,7 +48,7 @@ typedef boost::ulong_long_type polygon_ulong_long_type; #include #else -#ifdef WIN32 +#ifdef _WIN32 #define BOOST_POLYGON_MSVC #endif #ifdef __ICC @@ -290,7 +290,7 @@ namespace boost { namespace polygon{ template struct gtl_if { -#ifdef WIN32 +#ifdef BOOST_POLYGON_MSVC typedef gtl_no type; #endif }; diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp index b776a46b23..331711da25 100644 --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -1170,7 +1170,7 @@ namespace boost { namespace polygon{ //odd count implies boundary condition if(counts[0] % 2 || counts[1] % 2) return consider_touch; //an odd number of edges to the left implies interior pt - return counts[0] % 4 != 0; + return counts[winding(polygon) == COUNTERCLOCKWISE ? 0 : 1] % 4 != 0; } //TODO: refactor to expose as user APIs