Gerbview: Added support for complex definitions of parameters (like $3=$2+5/2) in aperture macros and primitives macro.
This commit is contained in:
commit
8c4075216e
|
@ -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 <jean-pierre.charras@gipsa-lab.inpg.fr>
|
||||
================================================================================
|
||||
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 <stambaughw@verizon.net>
|
||||
================================================================================
|
||||
++EESchema
|
||||
|
|
|
@ -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.
|
||||
* 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 );
|
||||
AM_PARAM_ITEM item = m_paramStack[ii];
|
||||
switch( item.GetType() )
|
||||
{
|
||||
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( ndx <= aDcode->GetParamCount() )
|
||||
return aDcode->GetParam( ndx );
|
||||
else
|
||||
if( aDcode && item.GetIndex() <= aDcode->GetParamCount() )
|
||||
curr_value = aDcode->GetParam( item.GetIndex() );
|
||||
else // Get parameter from local param definition
|
||||
{
|
||||
wxASSERT( GetIndex() <= aDcode->GetParamCount() );
|
||||
return 0.0;
|
||||
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 )
|
||||
{
|
||||
switch( *aText )
|
||||
{
|
||||
case ',':
|
||||
aText++;
|
||||
// fall through
|
||||
case 0: // EOL
|
||||
case '*': // Terminator in a gerber command
|
||||
end = true;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
aText++;
|
||||
break;
|
||||
|
||||
case '$':
|
||||
// defered value defined later, in ADD command which define defered parameters
|
||||
++aText;
|
||||
SetIndex( ReadInt( aText, false ) );
|
||||
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
|
||||
{
|
||||
SetValue( ReadDouble( aText, false ) );
|
||||
{ // seems the sign of a value
|
||||
dvalue = ReadDouble( aText, false );
|
||||
PushOperator( PUSHVALUE, dvalue );
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
|
||||
// Skip extra characters and separator
|
||||
while( *aText && (*aText != ',') && (*aText != '*') )
|
||||
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;
|
||||
|
||||
if( *aText == ',' )
|
||||
aText++;
|
||||
default:
|
||||
dvalue = ReadDouble( aText, false );
|
||||
PushOperator( PUSHVALUE, dvalue );
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
|
|
@ -103,50 +103,151 @@
|
|||
#include <vector>
|
||||
|
||||
#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<AM_PARAM_ITEM> 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_PARAM> AM_PARAMS;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,6 +173,26 @@ 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.
|
||||
|
|
|
@ -146,7 +146,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
APERTURE_MACRO* GetMacro() { return m_Macro; }
|
||||
APERTURE_MACRO* GetMacro() const { return m_Macro; }
|
||||
|
||||
/**
|
||||
* Function ShowApertureType
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ typedef boost::ulong_long_type polygon_ulong_long_type;
|
|||
#include <boost/mpl/or.hpp>
|
||||
#else
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#define BOOST_POLYGON_MSVC
|
||||
#endif
|
||||
#ifdef __ICC
|
||||
|
@ -290,7 +290,7 @@ namespace boost { namespace polygon{
|
|||
|
||||
template <typename T>
|
||||
struct gtl_if {
|
||||
#ifdef WIN32
|
||||
#ifdef BOOST_POLYGON_MSVC
|
||||
typedef gtl_no type;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue