Pcbnew: fix a bug in filling zone algo, only when using boost::polygon. Gerbview: preparing enhancements.

This commit is contained in:
jean-pierre charras 2010-12-01 08:51:21 +01:00
commit 0134da4c9f
8 changed files with 396 additions and 199 deletions

View File

@ -23,6 +23,7 @@ set(DIALOGS_SRCS
set(GERBVIEW_SRCS
block.cpp
class_am_param.cpp
class_aperture_macro.cpp
class_GERBER.cpp
class_gerber_draw_item.cpp

101
gerbview/class_am_param.cpp Normal file
View File

@ -0,0 +1,101 @@
/*****************/
/* am_param.cpp */
/*****************/
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 1992-2010 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2010 Kicad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "class_am_param.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.
*/
double AM_PARAM::GetValue( const D_CODE* aDcode ) const
{
if( IsImmediate() )
return value;
else
{
// 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
{
wxASSERT( GetIndex() <= aDcode->GetParamCount() );
return 0.0;
}
}
}
/**
* Function ReadParam
* Read one aperture macro parameter
* a parameter can be:
* a number
* 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..
* 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
*/
bool AM_PARAM::ReadParam( char*& aText )
{
bool found = false;
if( *aText == '$' ) // value defined later, in aperture description
{
++aText;
SetIndex( ReadInt( aText, false ) );
found = true;
}
else
{
SetValue( ReadDouble( aText, false ) );
found = true;
}
// Skip extra characters and separator
while( *aText && (*aText != ',') && (*aText != '*') )
aText++;
if( *aText == ',' )
aText++;
return found;
}

174
gerbview/class_am_param.h Normal file
View File

@ -0,0 +1,174 @@
/*****************/
/* am_param.h */
/*****************/
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 1992-2010 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2010 Kicad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _AM_PARAM_H_
#define _AM_PARAM_H_
/*
* An aperture macro defines a complex shape and is a list of aperture primitives.
* Each aperture primitive defines a simple shape (circle, rect, regular polygon...)
* Inside a given aperture primitive, a fixed list of parameters defines info
* about the shape: size, thickness, number of vertex ...
*
* 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
*
* Actual values of a parameter can also be the result of an arithmetic operation.
*
* Here is some examples:
* An immediate value:
* 3.5
* A deferend value:
* $2 means: replace me by the second value given in the ADD command
* Actual value as arithmetic calculation:
* $2/2+1
*
* 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
*
* Some examples of aperture macro definition
* A simple definition, no parameters:
* %AMMOIRE10*
* 6,0,0,0.350000,0.005,0.050,3,0.005,0.400000,0.0*%
* Example of instanciation:
* %ADD19THERM19*%
*
* A simple definition, one parameter:
* %AMCIRCLE*
* 1,1,$1,0,0*
* Example of instanciation:
* %ADD11CIRCLE,.5*%
*
* A definition, with parameters and arithmetic operations:
* %AMVECTOR*
* 2,1,$1,0,0,$2+1,$3,-135*%
* Example of instanciation:
* %ADD12VECTOR,0.05X0X0*%
*
* A more complicated aperture macro definition, with parameters and arihmetic operations:
* %AMRNDREC*
* 0 this is a comment*
* 21,1,$1+$1,$2+$2-$3-$3,0,0,0*
* 21,1,$1+$1-$3-$3,$2+$2,0,0,0*
* 1,1,$3+$3,$1-$3,$2-$3*
* 1,1,$3+$3,$3-$1,$2-$3*
* 1,1,$3+$3,$1-$3,$3-$2*
* 1,1,$3+$3,$3-$1,$3-$2*%
* Example of instanciation:
*
* A more complicated sample of aperture macro definition:
* G04 Rectangular Thermal Macro, params: W/2, H/2, T/2 *
* %AMRECTHERM*
* $4=$3/2*
* 21,1,$1-$3,$2-$3,0-$1/2-$4,0-$2/2-$4,0*
* 21,1,$1-$3,$2-$3,0-$1/2-$4,$2/2+$4,0*
* 21,1,$1-$3,$2-$3,$1/2+$4,0-$2/2-$4,0*
* 21,1,$1-$3,$2-$3,$1/2+$4,$2/2+$4,0*%
* Example of instanciation:
* %ADD28RECTHERM,0.035591X0.041496X0.005000*%
*/
#include <vector>
#include "dcode.h"
/**
* 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
{
public: AM_PARAM() :
index( -1 ),
value( 0.0 )
{}
double GetValue( const D_CODE* aDcode ) const;
void SetValue( double aValue )
{
value = aValue;
index = -1;
}
/**
* Function IsImmediate
* tests if this AM_PARAM holds an immediate parameter or is a pointer
* into a parameter held by an owning D_CODE.
*/
bool IsImmediate() const { return index == -1; }
unsigned GetIndex() const
{
return (unsigned) index;
}
void SetIndex( int aIndex )
{
index = aIndex;
}
/**
* Function ReadParam
* Read one aperture macro parameter
* a parameter can be:
* a number
* 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..
* 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
*/
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;
#endif // _AM_PARAM_H_

View File

@ -34,7 +34,18 @@
#include <set>
#include "base_struct.h"
#include "class_am_param.h"
/*
* An aperture macro defines a complex shape and is a list of aperture primitives.
* Each aperture primitive defines a simple shape (circle, rect, regular polygon...)
* Inside a given aperture primitive, a fixed list of parameters defines info
* about the shape: size, thickness, number of vertex ...
*
* 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
*/
/**
* Enum AM_PRIMITIVE_ID
@ -68,13 +79,12 @@ class AM_PRIMITIVE
{
public:
AM_PRIMITIVE_ID primitive_id; ///< The primitive type
DCODE_PARAMS params; ///< A sequence of parameters used by
AM_PARAMS params; ///< A sequence of parameters used by
// the primitive
bool m_GerbMetric; // units for this primitive:
// false = Inches, true = metric
public:
AM_PRIMITIVE( bool aGerbMetric, AM_PRIMITIVE_ID aId = AMP_UNKNOWN )
public: AM_PRIMITIVE( bool aGerbMetric, AM_PRIMITIVE_ID aId = AMP_UNKNOWN )
{
primitive_id = aId;
m_GerbMetric = aGerbMetric;
@ -88,7 +98,7 @@ public:
* returns the first parameter in integer form. Some but not all primitives
* use the first parameter as an exposure control.
*/
int GetExposure( GERBER_DRAW_ITEM* aParent ) const;
int GetExposure( GERBER_DRAW_ITEM* aParent ) const;
/**
* Function mapExposure
@ -131,7 +141,7 @@ public:
* @param aParent = the parent GERBER_DRAW_ITEM which is actually drawn
* @return a dimension, or -1 if no dim to calculate
*/
int GetShapeDim( GERBER_DRAW_ITEM* aParent );
int GetShapeDim( GERBER_DRAW_ITEM* aParent );
private:
@ -183,7 +193,7 @@ struct APERTURE_MACRO
* @param aParent = the parent GERBER_DRAW_ITEM which is actually drawn
* @return a dimension, or -1 if no dim to calculate
*/
int GetShapeDim( GERBER_DRAW_ITEM* aParent );
int GetShapeDim( GERBER_DRAW_ITEM* aParent );
};

View File

@ -31,7 +31,7 @@
#define _DCODE_H_
#include <vector>
#include <set>
//#include <set>
#include "base_struct.h"
class GERBER_DRAW_ITEM;
@ -67,62 +67,6 @@ enum APERTURE_DEF_HOLETYPE {
#define TOOLS_MAX_COUNT (LAST_DCODE + 1)
class APERTURE_MACRO;
class D_CODE;
/**
* Class DCODE_PARAM
* holds a parameter for a DCODE or 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 DCODE_PARAM
{
public:
DCODE_PARAM() :
index( -1 ),
value( 0.0 )
{}
double GetValue( const D_CODE* aDcode ) const;
void SetValue( double aValue )
{
value = aValue;
index = -1;
}
/**
* Function IsImmediate
* tests if this DCODE_PARAM holds an immediate parameter or is a pointer
* into a parameter held by an owning D_CODE.
*/
bool IsImmediate() const { return index == -1; }
unsigned GetIndex() const
{
return (unsigned) index;
}
void SetIndex( int aIndex )
{
index = aIndex;
}
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<DCODE_PARAM> DCODE_PARAMS;
/**
@ -131,16 +75,14 @@ typedef std::vector<DCODE_PARAM> DCODE_PARAMS;
*/
class D_CODE
{
friend class DCODE_PARAM;
private:
APERTURE_MACRO* m_Macro; ///< no ownership, points to
// GERBER.m_aperture_macros element
/**
* parameters used only when this D_CODE holds a reference to an aperture
* macro, and these parameters would customize the macro.
*/
DCODE_PARAMS m_am_params;
std::vector<double> m_am_params;
std::vector <wxPoint> m_PolyCorners; /* Polygon used to draw APT_POLYGON shape and some other
* complex shapes which are converted to polygon
@ -164,13 +106,37 @@ public:
~D_CODE();
void Clear_D_CODE_Data();
/**
* AppendParam()
* Add a parameter to the D_CODE parameter list.
* used to customize the corresponding aperture macro
*/
void AppendParam( double aValue )
{
DCODE_PARAM param;
m_am_params.push_back( aValue );
}
param.SetValue( aValue );
/**
* GetParamCount()
* Returns the number of parameters stored in parameter list.
*/
unsigned GetParamCount() const
{
return m_am_params.size();
}
m_am_params.push_back( param );
/**
* GetParam()
* Returns a parameter stored in parameter list.
* @param aIdx = index of parameter
*/
double GetParam( unsigned aIdx ) const
{
wxASSERT( aIdx <= m_am_params.size() );
if( aIdx <= m_am_params.size() )
return m_am_params[aIdx - 1];
else
return 0;
}
@ -245,26 +211,4 @@ public:
};
inline double DCODE_PARAM::GetValue( const D_CODE* aDcode ) const
{
if( IsImmediate() )
return value;
else
{
// the first one was numbered 1, not zero, as in $1, see page 19 of spec.
unsigned ndx = GetIndex() - 1;
wxASSERT( aDcode );
// get the parameter from the aDcode
if( ndx < aDcode->m_am_params.size() )
return aDcode->m_am_params[ndx].GetValue( NULL );
else
{
wxASSERT( GetIndex() - 1 < aDcode->m_am_params.size() );
return 0.0;
}
}
}
#endif // ifndef _DCODE_H_

View File

@ -201,3 +201,48 @@ wxPoint GERBER_IMAGE::ReadIJCoord( char*& Text )
m_IJPos = pos;
return pos;
}
// Helper functions:
/**
* Function ReadInt
* reads an int from an ASCII character buffer. If there is a comma after the
* int, then skip over that.
* @param text A reference to a character pointer from which bytes are read
* and the pointer is advanced for each byte read.
* @param aSkipSeparator = true (default) to skip comma
* @return int - The int read in.
*/
int ReadInt( char*& text, bool aSkipSeparator = true )
{
int ret = (int) strtol( text, &text, 10 );
if( *text == ',' || isspace( *text ) )
if( aSkipSeparator )
++text;
return ret;
}
/**
* Function ReadDouble
* reads a double from an ASCII character buffer. If there is a comma after
* the double, then skip over that.
* @param text A reference to a character pointer from which the ASCII double
* is read from and the pointer advanced for each character read.
* @param aSkipSeparator = true (default) to skip comma
* @return double
*/
double ReadDouble( char*& text, bool aSkipSeparator = true )
{
double ret = strtod( text, &text );
if( *text == ',' || isspace( *text ) )
if( aSkipSeparator )
++text;
return ret;
}

View File

@ -5,14 +5,14 @@
#include "fctsys.h"
#include "common.h"
//#include "macros.h"
#include "gerbview.h"
#include "class_GERBER.h"
#define CODE( x, y ) ( ( (x) << 8 ) + (y) )
extern int ReadInt( char*& text, bool aSkipSeparator = true );
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
// Helper function to read a primitive macro param (TODO: make it DCODE_PARAM function)
static bool ReadMacroParam( DCODE_PARAM& aParam, char*& aText );
#define CODE( x, y ) ( ( (x) << 8 ) + (y) )
// See rs274xrevd_e.pdf, table 1: RS-274X parameters order of entry
// in gerber files, when a coordinate is given (like X78Y600 or I0J80):
@ -92,48 +92,6 @@ static int ReadXCommand( char*& text )
}
/**
* Function ReadInt
* reads an int from an ASCII character buffer. If there is a comma after the
* int, then skip over that.
* @param text A reference to a character pointer from which bytes are read
* and the pointer is advanced for each byte read.
* @param aSkipSeparator = true (default) to skip comma
* @return int - The int read in.
*/
static int ReadInt( char*& text, bool aSkipSeparator = true )
{
int ret = (int) strtol( text, &text, 10 );
if( *text == ',' || isspace( *text ) )
if( aSkipSeparator )
++text;
return ret;
}
/**
* Function ReadDouble
* reads a double from an ASCII character buffer. If there is a comma after
* the double, then skip over that.
* @param text A reference to a character pointer from which the ASCII double
* is read from and the pointer advanced for each character read.
* @param aSkipSeparator = true (default) to skip comma
* @return double
*/
static double ReadDouble( char*& text, bool aSkipSeparator = true )
{
double ret = strtod( text, &text );
if( *text == ',' || isspace( *text ) )
if( aSkipSeparator )
++text;
return ret;
}
bool GERBER_IMAGE::ReadRS274XCommand( char buff[GERBER_BUFZ], char*& text )
{
bool ok = true;
@ -952,14 +910,14 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
int i;
for( i = 0; i < paramCount && *text && *text != '*'; ++i )
{
prim.params.push_back( DCODE_PARAM() );
prim.params.push_back( AM_PARAM() );
DCODE_PARAM& param = prim.params.back();
AM_PARAM& param = prim.params.back();
text = GetNextLine( buff, text, gerber_file );
if( text == NULL) // End of File
return false;
ReadMacroParam( param, text );
param.ReadParam( text );
}
if( i < paramCount )
@ -984,14 +942,14 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
for( int i = 0; i < paramCount && *text != '*'; ++i )
{
prim.params.push_back( DCODE_PARAM() );
prim.params.push_back( AM_PARAM() );
DCODE_PARAM& param = prim.params.back();
AM_PARAM& param = prim.params.back();
text = GetNextLine( buff, text, gerber_file );
if( text == NULL ) // End of File
return false;
ReadMacroParam( param, text );
param.ReadParam( text );
}
}
@ -1003,37 +961,3 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
return true;
}
/**
* Function ReadMacroParam
* Read one aperture macro parameter
* a parameter can be:
* a number
* 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..
* Parameters are separated by a comma ( of finish by *)
* Return if a param is read, or false
*/
static bool ReadMacroParam( DCODE_PARAM& aParam, char*& aText )
{
bool found = false;
if( *aText == '$' ) // value defined later, in aperture description
{
++aText;
aParam.SetIndex( ReadInt( aText, false ) );
found = true;
}
else
{
aParam.SetValue( ReadDouble( aText, false ) );
found = true;
}
// Skip extra characters and separator
while( *aText && (*aText != ',') && (*aText != '*') )
aText++;
if( *aText == ',' )
aText++;
return found;
}

View File

@ -193,7 +193,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
nextpad = pad->Next(); // pad pointer can be modified by next code, so calculate the next pad here
if( !pad->IsOnLayer( GetLayer() ) )
{
/* Test fo pads that are on top or bottom only and have a hole.
/* Test for pads that are on top or bottom only and have a hole.
* There are curious pads but they can be used for some components that are inside the
* board (in fact inside the hole. Some photo diodes and Leds are like this)
*/
@ -363,30 +363,28 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb );
// Now we remove all unused thermal stubs.
#define REMOVE_UNUSED_THERMAL_STUBS // Can be commented to skip unused thermal stubs calculations
#ifdef REMOVE_UNUSED_THERMAL_STUBS
// Test thermal stubs connections and add polygons to remove unconnected stubs.
cornerBufferPolysToSubstract.clear();
BuildUnconnectedThermalStubsPolygonList( cornerBufferPolysToSubstract, aPcb, this, s_Correction, s_thermalRot );
/* remove copper areas */
if( cornerBufferPolysToSubstract.size() )
if( m_PadOption == THERMAL_PAD )
{
KPolygonSet polyset_holes;
AddPolygonCornersToKPolygonList( cornerBufferPolysToSubstract, polyset_holes );
polyset_zone_solid_areas -= polyset_holes;
cornerBufferPolysToSubstract.clear();
// Test thermal stubs connections and add polygons to remove unconnected stubs.
BuildUnconnectedThermalStubsPolygonList( cornerBufferPolysToSubstract, aPcb, this, s_Correction, s_thermalRot );
/* put these areas in m_FilledPolysList */
m_FilledPolysList.clear();
CopyPolygonsFromKPolygonListToFilledPolysList( this, polyset_zone_solid_areas );
if( GetNet() > 0 )
Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb );
/* remove copper areas */
if( cornerBufferPolysToSubstract.size() )
{
KPolygonSet polyset_holes;
AddPolygonCornersToKPolygonList( cornerBufferPolysToSubstract, polyset_holes );
polyset_zone_solid_areas -= polyset_holes;
/* put these areas in m_FilledPolysList */
m_FilledPolysList.clear();
CopyPolygonsFromKPolygonListToFilledPolysList( this, polyset_zone_solid_areas );
if( GetNet() > 0 )
Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb );
}
}
#endif // REMOVE_UNUSED_THERMAL_STUBS
cornerBufferPolysToSubstract.clear();
}
void AddPolygonCornersToKPolygonList( std::vector <CPolyPt>&