Commit 0cf91f46 authored by Garth Corral's avatar Garth Corral

Merge trunk @ 5308

parents 668c3b76 cf9a885c
...@@ -226,8 +226,8 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) ...@@ -226,8 +226,8 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
if( APPLE ) if( APPLE )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__ASSERTMACROS__ -mmacosx-version-min=10.5" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__ASSERTMACROS__" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__ASSERTMACROS__ -mmacosx-version-min=10.5" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__ASSERTMACROS__" )
# Allows .dylib relocation in the future - needed by fixbundle # Allows .dylib relocation in the future - needed by fixbundle
set( CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -headerpad_max_install_names") set( CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -headerpad_max_install_names")
...@@ -240,6 +240,12 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) ...@@ -240,6 +240,12 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
EXEC_PROGRAM( wx-config ARGS --cxx OUTPUT_VARIABLE CMAKE_CXX_COMPILER ) EXEC_PROGRAM( wx-config ARGS --cxx OUTPUT_VARIABLE CMAKE_CXX_COMPILER )
endif() endif()
# There seems to be no consistent behavior when -mmacosx-min-version is
# not specified, so force user to set minimum OSX version to build for
if( NOT CMAKE_OSX_DEPLOYMENT_TARGET )
message( FATAL_ERROR "Please specify target OS X version using -DCMAKE_OSX_DEPLOYMENT_TARGET=10.x" )
endif()
endif() endif()
endif( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) endif( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
......
...@@ -140,11 +140,8 @@ endif() ...@@ -140,11 +140,8 @@ endif()
if( APPLE ) if( APPLE )
# I set this to being compatible with wxWidgets set( BOOST_CXXFLAGS "cxxflags=-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -fno-common" )
# wxWidgets still using libstdc++ (gcc), meanwhile OSX set( BOOST_LINKFLAGS "linkflags=-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -fno-common" )
# has switched to libc++ (llvm) by default
set( BOOST_CXXFLAGS "cxxflags=-mmacosx-version-min=10.5 -fno-common" )
set( BOOST_LINKFLAGS "linkflags=-mmacosx-version-min=10.5 -fno-common" )
set( BOOST_TOOLSET "toolset=darwin" ) set( BOOST_TOOLSET "toolset=darwin" )
if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
......
Compiling KiCad on Apple Mac OS X Compiling KiCad on Apple Mac OS X
================================= =================================
Building on OSX is very similar to building on Linux. This document will provide Building on OS X is very similar to building on Linux. This document will provide
a complete walk-through on what to do but it will focus on OSX specific things. a complete walk-through on what to do but it will focus on OS X specific things.
See general documentation on non-OSX specific KiCad build switches, etc. See general documentation on non OS X specific KiCad build switches, etc.
Prerequisites Prerequisites
...@@ -24,6 +24,7 @@ Mandatory library dependencies needed to compile KiCad: ...@@ -24,6 +24,7 @@ Mandatory library dependencies needed to compile KiCad:
OR OR
wxPython - A blending of the wxWidgets C++ class library with the Python wxPython - A blending of the wxWidgets C++ class library with the Python
programming language programming language
* SWIG - Interface compiler (only needed for scripting/wxPython builds)
Optional library dependencies, depends on used KiCad features Optional library dependencies, depends on used KiCad features
* OpenSSL - The Open Source toolkit for SSL/TLS * OpenSSL - The Open Source toolkit for SSL/TLS
...@@ -31,7 +32,7 @@ Optional library dependencies, depends on used KiCad features ...@@ -31,7 +32,7 @@ Optional library dependencies, depends on used KiCad features
All tools (except XCode, of course) and all dependencies except wxWidgets/wxPython All tools (except XCode, of course) and all dependencies except wxWidgets/wxPython
can be compiled manually, but it is advised to install them using your favorite can be compiled manually, but it is advised to install them using your favorite
package manager for OSX like MacPorts or Homebrew. package manager for OS X like MacPorts or Homebrew.
Depending on the package manager the development packages of the library Depending on the package manager the development packages of the library
dependencies may have to be installed (usually something like <pkg>-dev or dependencies may have to be installed (usually something like <pkg>-dev or
<pkg>-devel). <pkg>-devel).
...@@ -44,7 +45,7 @@ automatically by KiCad build process. ...@@ -44,7 +45,7 @@ automatically by KiCad build process.
IMPORTANT: IMPORTANT:
At the moment you *must not* use a wxWidgets/wxPython version installed by any At the moment you *must not* use a wxWidgets/wxPython version installed by any
package manager. package manager.
KiCad on OSX needs overlay support and some other fixes, which are not yet KiCad on OS X needs overlay support and some other fixes, which are not yet
contained in mainline wxWidgets/wxPython sources and builds. contained in mainline wxWidgets/wxPython sources and builds.
If you don't use a patched wxWidgets you will get graphical artifacts (something If you don't use a patched wxWidgets you will get graphical artifacts (something
like a magnifying glass effect in the upper left corner of KiCad windows) or like a magnifying glass effect in the upper left corner of KiCad windows) or
...@@ -92,13 +93,15 @@ It is recommended to use the latest stable version. As of this writing this is ...@@ -92,13 +93,15 @@ It is recommended to use the latest stable version. As of this writing this is
There is a little helper script osx_build_wx.sh in kicad/scripts that does all There is a little helper script osx_build_wx.sh in kicad/scripts that does all
the patching/configuring/compiling of wxWidgets or wxPython for you. the patching/configuring/compiling of wxWidgets or wxPython for you.
Go to your working root "KiCad" and run: Go to your working root "KiCad" and for example run:
# kicad/scripts/osx_build_wx.sh wx-src wx-bin kicad "-j4" # kicad/scripts/osx_build_wx.sh wx-src wx-bin kicad 10.7 "-j4"
First parameter is the source folder of wxWidgets/wxPython, second parameter the First parameter is the source folder of wxWidgets/wxPython, second parameter the
target folder for compiled binaries, third parameter is the kicad folder, and target folder for compiled binaries, and third parameter is the kicad folder.
the last optional parameter are make options used during the build (in this The fourth parameter is the minimum OS X version you are building for (see the
case for building with 4 jobs in parallel). section about compiling KiCad for further notes on minimum OS X version).
The last parameter is optional and contains make options used during the build
(in this example for building with 4 jobs in parallel).
The script will automatically detect if you are compiling wxWidgets or wxPython. The script will automatically detect if you are compiling wxWidgets or wxPython.
NOTE: All paths are assumed to be relative to the current directory, i.e., the NOTE: All paths are assumed to be relative to the current directory, i.e., the
working root you are in. working root you are in.
...@@ -137,10 +140,8 @@ work: ...@@ -137,10 +140,8 @@ work:
--with-zlib=builtin \ --with-zlib=builtin \
--with-expat=builtin \ --with-expat=builtin \
--without-liblzma \ --without-liblzma \
--with-macosx-version-min=10.5 \ --with-macosx-version-min=<osxtarget> \
--enable-universal-binary=i386,x86_64 \ --enable-universal-binary=i386,x86_64 \
CPPFLAGS="-stdlib=libstdc++" \
LDFLAGS="-stdlib=libstdc++" \
CC=clang \ CC=clang \
CXX=clang++ CXX=clang++
If you know what you are doing, you can of course use different settings. If you know what you are doing, you can of course use different settings.
...@@ -157,6 +158,7 @@ Now, configure KiCad without scripting support: ...@@ -157,6 +158,7 @@ Now, configure KiCad without scripting support:
# cmake ../kicad \ # cmake ../kicad \
-DCMAKE_C_COMPILER=clang \ -DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \
-DwxWidgets_CONFIG_EXECUTABLE=../wx-bin/bin/wx-config \ -DwxWidgets_CONFIG_EXECUTABLE=../wx-bin/bin/wx-config \
-DKICAD_SCRIPTING=OFF \ -DKICAD_SCRIPTING=OFF \
-DKICAD_SCRIPTING_MODULES=OFF \ -DKICAD_SCRIPTING_MODULES=OFF \
...@@ -168,6 +170,7 @@ or, configure KiCad with scripting support: ...@@ -168,6 +170,7 @@ or, configure KiCad with scripting support:
# cmake ../kicad \ # cmake ../kicad \
-DCMAKE_C_COMPILER=clang \ -DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \
-DwxWidgets_CONFIG_EXECUTABLE=../wx-bin/bin/wx-config \ -DwxWidgets_CONFIG_EXECUTABLE=../wx-bin/bin/wx-config \
-DPYTHON_EXECUTABLE=`which python` \ -DPYTHON_EXECUTABLE=`which python` \
-DPYTHON_SITE_PACKAGE_PATH=`pwd`/../wx-bin/lib/python2.7/site-packages \ -DPYTHON_SITE_PACKAGE_PATH=`pwd`/../wx-bin/lib/python2.7/site-packages \
...@@ -182,6 +185,18 @@ been generated when compiling/installing wxPython. If you want to use a specific ...@@ -182,6 +185,18 @@ been generated when compiling/installing wxPython. If you want to use a specific
python, you can also specify it via "-DPYTHON_EXECUTABLE" instead of using python, you can also specify it via "-DPYTHON_EXECUTABLE" instead of using
`which python` (this one will just detect/use you default python). `which python` (this one will just detect/use you default python).
The parameter "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.x" is mandatory, you have to
specify the (minimum) OS X version you intend to build for. It is important that
at least wxWidgets/wxPython and KiCad (and boost, if you use an external build)
are built using the same or compatible settings. If not, you might get linker
errors, because this parameter influences which standard C++ library is being
used (libstdc++ vs. libc++).
If you don't know what to use and you are only building for your machine, just
set it to your current OS X version (e.g., MacPorts always builds this way).
Binaries built with a target OS X version <10.7 are known to show strange
behavior in some situations on recent systems (maybe because libc++ is standard
on everything >= 10.7 and problems arise due to mixing libstdc++/libc++).
Now KiCad is configured using default features/build-switches. To add Magic Now KiCad is configured using default features/build-switches. To add Magic
Trackpad pinch-to-zoom support, add -DUSE_OSX_MAGNIFY_EVENT=ON to the above. Trackpad pinch-to-zoom support, add -DUSE_OSX_MAGNIFY_EVENT=ON to the above.
See Documentation/compiling/build-config.txt for a list of all CMake options See Documentation/compiling/build-config.txt for a list of all CMake options
......
...@@ -548,6 +548,9 @@ int EDA_BASE_FRAME::ReadHotkeyConfigFile( const wxString& aFilename, ...@@ -548,6 +548,9 @@ int EDA_BASE_FRAME::ReadHotkeyConfigFile( const wxString& aFilename,
{ {
wxFile cfgfile( aFilename ); wxFile cfgfile( aFilename );
if( !cfgfile.IsOpened() ) // There is a problem to open file
return 0;
// get length // get length
cfgfile.SeekEnd(); cfgfile.SeekEnd();
wxFileOffset size = cfgfile.Tell(); wxFileOffset size = cfgfile.Tell();
......
...@@ -86,7 +86,7 @@ public: ...@@ -86,7 +86,7 @@ public:
wxBoxSizer* m_RightBoxSizer; wxBoxSizer* m_RightBoxSizer;
wxBoxSizer* m_RightOptionsBoxSizer; wxBoxSizer* m_RightOptionsBoxSizer;
wxBoxSizer* m_LowBoxSizer; wxBoxSizer* m_LowBoxSizer;
wxRadioBox* m_NetOption;
private: private:
wxString m_pageNetFmtName; wxString m_pageNetFmtName;
...@@ -104,14 +104,12 @@ public: ...@@ -104,14 +104,12 @@ public:
/** /**
* function GetPageNetFmtName * function GetPageNetFmtName
* @return the name of the netlist format for this page * @return the name of the netlist format for this page
* This is usually the page label. * This is also the page label.
* For the pcbnew netlist, this is "LegacyPcbnew"
* when the "old" format is selected
* and "PcbnewAdvanced" when the advanced format (S expr fmt)is selected
*/ */
const wxString GetPageNetFmtName(); const wxString GetPageNetFmtName()
{
void SetPageNetFmtName( const wxString &aName ) { m_pageNetFmtName = aName; } return m_pageNetFmtName;
}
}; };
...@@ -242,9 +240,6 @@ enum id_netlist { ...@@ -242,9 +240,6 @@ enum id_netlist {
#define NETLIST_USE_DEFAULT_NETNAME wxT( "NetlistUseDefaultNetname" ) #define NETLIST_USE_DEFAULT_NETNAME wxT( "NetlistUseDefaultNetname" )
#define NETLIST_PSPICE_USE_NETNAME wxT( "SpiceUseNetNames" ) #define NETLIST_PSPICE_USE_NETNAME wxT( "SpiceUseNetNames" )
#define NETLIST_PCBNEW_LEGACY wxT("LegacyPcbnew" )
#define NETLIST_PCBNEW_NEWFMT wxT("PcbnewAdvanced" )
BEGIN_EVENT_TABLE( NETLIST_DIALOG, NETLIST_DIALOG_BASE ) BEGIN_EVENT_TABLE( NETLIST_DIALOG, NETLIST_DIALOG_BASE )
EVT_BUTTON( ID_CREATE_NETLIST, NETLIST_DIALOG::GenNetlist ) EVT_BUTTON( ID_CREATE_NETLIST, NETLIST_DIALOG::GenNetlist )
...@@ -269,23 +264,15 @@ NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent, ...@@ -269,23 +264,15 @@ NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent,
m_AddSubPrefix = NULL; m_AddSubPrefix = NULL;
m_SpiceUseNetcodeAsNetname = NULL; m_SpiceUseNetcodeAsNetname = NULL;
m_ButtonCancel = NULL; m_ButtonCancel = NULL;
m_NetOption = NULL;
wxString netfmtName = ((NETLIST_DIALOG*)parent->GetParent())->m_NetFmtName; wxString netfmtName = ((NETLIST_DIALOG*)parent->GetParent())->m_NetFmtName;
int fmtOption = 1; // Default Pcbnew netlist fmt is advanced fmt
bool selected = m_pageNetFmtName == netfmtName; bool selected = m_pageNetFmtName == netfmtName;
// PCBNEW Format is a special type: // PCBNEW Format is a special type:
if( id_NetType == NET_TYPE_PCBNEW ) if( id_NetType == NET_TYPE_PCBNEW )
{ {
if( netfmtName.IsEmpty() || netfmtName == NETLIST_PCBNEW_NEWFMT )
selected = true; selected = true;
if( netfmtName == NETLIST_PCBNEW_LEGACY )
{
selected = true;
fmtOption = 0;
}
} }
...@@ -312,34 +299,9 @@ NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent, ...@@ -312,34 +299,9 @@ NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent,
_( "Default format" ) ); _( "Default format" ) );
m_LeftBoxSizer->Add( m_IsCurrentFormat, 0, wxGROW | wxALL, 5 ); m_LeftBoxSizer->Add( m_IsCurrentFormat, 0, wxGROW | wxALL, 5 );
m_IsCurrentFormat->SetValue( selected ); m_IsCurrentFormat->SetValue( selected );
if( id_NetType == NET_TYPE_PCBNEW )
{
wxString netlist_opt[2] = { _( "Legacy Format" ), _( "Advanced Format" ) };
m_NetOption = new wxRadioBox( this, -1, _( "Netlist Options:" ),
wxDefaultPosition, wxDefaultSize,
2, netlist_opt, 1,
wxRA_SPECIFY_COLS );
m_NetOption->SetSelection( fmtOption );
m_LeftBoxSizer->Add( m_NetOption, 0, wxGROW | wxALL, 5 );
}
} }
const wxString NETLIST_PAGE_DIALOG::GetPageNetFmtName()
{
// PCBNEW Format is a special type:
if( m_IdNetType == NET_TYPE_PCBNEW )
{
if( m_NetOption->GetSelection() )
return NETLIST_PCBNEW_NEWFMT;
else
return NETLIST_PCBNEW_LEGACY;
}
return m_pageNetFmtName;
}
NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) : NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) :
NETLIST_DIALOG_BASE( parent ) NETLIST_DIALOG_BASE( parent )
...@@ -599,7 +561,6 @@ void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event ) ...@@ -599,7 +561,6 @@ void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event )
break; break;
case NET_TYPE_PCBNEW: case NET_TYPE_PCBNEW:
if( currPage->m_NetOption->GetSelection() != 0 )
netlist_opt = NET_PCBNEW_USE_NEW_FORMAT; netlist_opt = NET_PCBNEW_USE_NEW_FORMAT;
break; break;
......
...@@ -146,7 +146,7 @@ void SCH_EDIT_FRAME::ReCreateHToolbar() ...@@ -146,7 +146,7 @@ void SCH_EDIT_FRAME::ReCreateHToolbar()
HELP_ANNOTATE ); HELP_ANNOTATE );
m_mainToolBar->AddTool( ID_GET_ERC, wxEmptyString, KiBitmap( erc_xpm ), m_mainToolBar->AddTool( ID_GET_ERC, wxEmptyString, KiBitmap( erc_xpm ),
_( "Perform electric rules check" ) ); _( "Perform electrical rule check" ) );
m_mainToolBar->AddTool( ID_GET_NETLIST, wxEmptyString, KiBitmap( netlist_xpm ), m_mainToolBar->AddTool( ID_GET_NETLIST, wxEmptyString, KiBitmap( netlist_xpm ),
_( "Generate netlist" ) ); _( "Generate netlist" ) );
......
...@@ -40,6 +40,7 @@ set( GERBVIEW_SRCS ...@@ -40,6 +40,7 @@ set( GERBVIEW_SRCS
class_gerber_draw_item.cpp class_gerber_draw_item.cpp
class_gerbview_layer_widget.cpp class_gerbview_layer_widget.cpp
class_gbr_layer_box_selector.cpp class_gbr_layer_box_selector.cpp
class_X2_gerber_attributes.cpp
controle.cpp controle.cpp
dcode.cpp dcode.cpp
draw_gerber_screen.cpp draw_gerber_screen.cpp
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#include <gerbview.h> #include <gerbview.h>
#include <gerbview_frame.h> #include <gerbview_frame.h>
#include <class_GERBER.h> #include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
#include <algorithm>
/** /**
...@@ -91,6 +94,7 @@ GERBER_IMAGE::GERBER_IMAGE( GERBVIEW_FRAME* aParent, int aLayer ) ...@@ -91,6 +94,7 @@ GERBER_IMAGE::GERBER_IMAGE( GERBVIEW_FRAME* aParent, int aLayer )
m_GraphicLayer = aLayer; // Graphic layer Number m_GraphicLayer = aLayer; // Graphic layer Number
m_Selected_Tool = FIRST_DCODE; m_Selected_Tool = FIRST_DCODE;
m_FileFunction = NULL; // file function parameters
ResetDefaultValues(); ResetDefaultValues();
...@@ -104,9 +108,9 @@ GERBER_IMAGE::~GERBER_IMAGE() ...@@ -104,9 +108,9 @@ GERBER_IMAGE::~GERBER_IMAGE()
for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ ) for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
{ {
delete m_Aperture_List[ii]; delete m_Aperture_List[ii];
// m_Aperture_List[ii] = NULL;
} }
delete m_FileFunction;
} }
/* /*
...@@ -158,6 +162,11 @@ void GERBER_IMAGE::ResetDefaultValues() ...@@ -158,6 +162,11 @@ void GERBER_IMAGE::ResetDefaultValues()
m_FileName.Empty(); m_FileName.Empty();
m_ImageName = wxT( "no name" ); // Image name from the IN command m_ImageName = wxT( "no name" ); // Image name from the IN command
m_ImageNegative = false; // true = Negative image m_ImageNegative = false; // true = Negative image
m_IsX2_file = false; // true only if a %TF, %TA or %TD command
delete m_FileFunction; // file function parameters
m_FileFunction = NULL;
m_MD5_value.Empty(); // MD5 value found in a %TF.MD5 command
m_PartString.Empty(); // string found in a %TF.Part command
m_hasNegativeItems = -1; // set to uninitialized m_hasNegativeItems = -1; // set to uninitialized
m_ImageJustifyOffset = wxPoint(0,0); // Image justify Offset m_ImageJustifyOffset = wxPoint(0,0); // Image justify Offset
m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false) m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
...@@ -361,3 +370,171 @@ void GERBER_IMAGE::DisplayImageInfo( void ) ...@@ -361,3 +370,171 @@ void GERBER_IMAGE::DisplayImageInfo( void )
m_Parent->AppendMsgPanel( _( "Image Justify Offset" ), msg, DARKRED ); m_Parent->AppendMsgPanel( _( "Image Justify Offset" ), msg, DARKRED );
} }
// GERBER_IMAGE_LIST is a helper class to handle a list of GERBER_IMAGE files
GERBER_IMAGE_LIST::GERBER_IMAGE_LIST()
{
m_GERBER_List.reserve( GERBER_DRAWLAYERS_COUNT );
for( unsigned layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
m_GERBER_List.push_back( NULL );
}
GERBER_IMAGE_LIST::~GERBER_IMAGE_LIST()
{
ClearList();
for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer )
{
delete m_GERBER_List[layer];
m_GERBER_List[layer] = NULL;
}
}
GERBER_IMAGE* GERBER_IMAGE_LIST::GetGbrImage( int aIdx )
{
if( (unsigned)aIdx < m_GERBER_List.size() )
return m_GERBER_List[aIdx];
return NULL;
}
/**
* creates a new, empty GERBER_IMAGE* at index aIdx
* or at the first free location if aIdx < 0
* @param aIdx = the location to use ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
* @return true if the index used, or -1 if no room to add image
*/
int GERBER_IMAGE_LIST::AddGbrImage( GERBER_IMAGE* aGbrImage, int aIdx )
{
int idx = aIdx;
if( idx < 0 )
{
for( idx = 0; idx < (int)m_GERBER_List.size(); idx++ )
{
if( !IsUsed( idx ) )
break;
}
}
if( idx >= (int)m_GERBER_List.size() )
return -1; // No room
m_GERBER_List[idx] = aGbrImage;
return idx;
}
// remove all loaded data in list, but do not delete empty images
// (can be reused)
void GERBER_IMAGE_LIST::ClearList()
{
for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer )
ClearImage( layer );
}
// remove the loaded data of image aIdx, but do not delete it
void GERBER_IMAGE_LIST::ClearImage( int aIdx )
{
if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() && m_GERBER_List[aIdx] )
{
m_GERBER_List[aIdx]->InitToolTable();
m_GERBER_List[aIdx]->ResetDefaultValues();
m_GERBER_List[aIdx]->m_InUse = false;
}
}
// Build a name for image aIdx which can be used in layers manager
const wxString GERBER_IMAGE_LIST::GetDisplayName( int aIdx )
{
wxString name;
GERBER_IMAGE* gerber = NULL;
if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() )
gerber = m_GERBER_List[aIdx];
if( IsUsed(aIdx ) )
{
if( gerber->m_FileFunction )
name.Printf( _( "Layer %d (%s, %s)" ), aIdx + 1,
GetChars( gerber->m_FileFunction->GetFileType() ),
GetChars( gerber->m_FileFunction->GetBrdLayerId() ) );
else
name.Printf( _( "Layer %d *" ), aIdx + 1 );
}
else
name.Printf( _( "Layer %d" ), aIdx + 1 );
return name;
}
// return true if image is used (loaded and not cleared)
bool GERBER_IMAGE_LIST::IsUsed( int aIdx )
{
if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() )
return m_GERBER_List[aIdx] != NULL && m_GERBER_List[aIdx]->m_InUse;
return false;
}
// Helper function, for std::sort.
// Sort loaded images by Z order priority, if they have the X2 FileFormat info
// returns true if the first argument (ref) is ordered before the second (test).
static bool sortZorder( const GERBER_IMAGE* const& ref, const GERBER_IMAGE* const& test )
{
if( !ref && !test )
return false; // do not change order: no criteria to sort items
if( !ref || !ref->m_InUse )
return false; // Not used: ref ordered after
if( !test || !test->m_InUse )
return true; // Not used: ref ordered before
if( !ref->m_FileFunction && !test->m_FileFunction )
return false; // do not change order: no criteria to sort items
if( !ref->m_FileFunction )
return false;
if( !test->m_FileFunction )
return true;
if( ref->m_FileFunction->GetZOrder() != test->m_FileFunction->GetZOrder() )
return ref->m_FileFunction->GetZOrder() > test->m_FileFunction->GetZOrder();
return ref->m_FileFunction->GetZSubOrder() > test->m_FileFunction->GetZSubOrder();
}
void GERBER_IMAGE_LIST::SortImagesByZOrder( GERBER_DRAW_ITEM* aDrawList )
{
std::sort( m_GERBER_List.begin(), m_GERBER_List.end(), sortZorder );
// The image order has changed.
// Graphic layer numbering must be updated to match the widgets layer order
// Store the old/new graphic layer info:
std::map <int, int> tab_lyr;
for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer )
{
if( m_GERBER_List[layer] )
{
tab_lyr[m_GERBER_List[layer]->m_GraphicLayer] = layer;
m_GERBER_List[layer]->m_GraphicLayer = layer ;
}
}
// update the graphic layer in items to draw
for( GERBER_DRAW_ITEM* item = aDrawList; item; item = item->Next() )
{
int layer = item->GetLayer();
item->SetLayer( tab_lyr[layer] );
}
}
// The global image list:
GERBER_IMAGE_LIST g_GERBER_List;
...@@ -61,6 +61,7 @@ class D_CODE; ...@@ -61,6 +61,7 @@ class D_CODE;
*/ */
class GERBER_IMAGE; class GERBER_IMAGE;
class X2_ATTRIBUTE_FILEFUNCTION;
class GERBER_LAYER class GERBER_LAYER
{ {
...@@ -104,6 +105,11 @@ public: ...@@ -104,6 +105,11 @@ public:
// (a file is loaded in it) // (a file is loaded in it)
wxString m_FileName; // Full File Name for this layer wxString m_FileName; // Full File Name for this layer
wxString m_ImageName; // Image name, from IN <name>* command wxString m_ImageName; // Image name, from IN <name>* command
bool m_IsX2_file; // true if a X2 gerber attribute was found in file
X2_ATTRIBUTE_FILEFUNCTION* m_FileFunction; // file function parameters, found in a %TF command
// or a G04
wxString m_MD5_value; // MD5 value found in a %TF.MD5 command
wxString m_PartString; // string found in a %TF.Part command
int m_GraphicLayer; // Graphic layer Number int m_GraphicLayer; // Graphic layer Number
bool m_ImageNegative; // true = Negative image bool m_ImageNegative; // true = Negative image
bool m_ImageJustifyXCenter; // Image Justify Center on X axis (default = false) bool m_ImageJustifyXCenter; // Image Justify Center on X axis (default = false)
...@@ -306,5 +312,67 @@ public: ...@@ -306,5 +312,67 @@ public:
void DisplayImageInfo( void ); void DisplayImageInfo( void );
}; };
/**
* @brief GERBER_IMAGE_LIST is a helper class to handle a list of GERBER_IMAGE files
* which are loaded and can be displayed
* there are 32 images max which can be loaded
*/
class GERBER_IMAGE_LIST
{
// the list of loaded images (1 image = 1 gerber file)
std::vector<GERBER_IMAGE*> m_GERBER_List;
public:
GERBER_IMAGE_LIST();
~GERBER_IMAGE_LIST();
//Accessor
GERBER_IMAGE* GetGbrImage( int aIdx );
/**
* Add a GERBER_IMAGE* at index aIdx
* or at the first free location if aIdx < 0
* @param aGbrImage = the image to add
* @param aIdx = the location to use ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
* @return true if the index used, or -1 if no room to add image
*/
int AddGbrImage( GERBER_IMAGE* aGbrImage, int aIdx );
/**
* remove all loaded data in list
*/
void ClearList();
/**
* remove the loaded data of image aIdx
* @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
*/
void ClearImage( int aIdx );
/**
* @return a name for image aIdx which can be used in layers manager
* and layer selector
* is is "Layer n" (n = aIdx+1), followed by file attribute info (if X2 format)
* @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
*/
const wxString GetDisplayName( int aIdx );
/**
* @return true if image is used (loaded and with items)
* @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
*/
bool IsUsed( int aIdx );
/**
* Sort loaded images by Z order priority, if they have the X2 FileFormat info
* @param aDrawList: the draw list associated to the gerber images
* (SortImagesByZOrder updates the graphic layer of these items)
*/
void SortImagesByZOrder( GERBER_DRAW_ITEM* aDrawList );
};
extern GERBER_IMAGE_LIST g_GERBER_List;
#endif // ifndef _CLASS_GERBER_H_ #endif // ifndef _CLASS_GERBER_H_
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2010-2014 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 1992-2014 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
*/
/**
* @file class_X2_gerber_attributes.cpp
*/
/*
* Manage the gerber extensions (attributes) in the new X2 version
* only few extensions are handled
* See http://www.ucamco.com/files/downloads/file/81/the_gerber_file_format_specification.pdf
*
* gerber attributes in the new X2 version look like:
* %TF.FileFunction,Copper,L1,Top*%
*
* Currently:
* .FileFunction .FileFunction Identifies the file’s function in the PCB.
* Other Standard Attributes, not yet used in Gerbview:
* .Part Identifies the part the file represents, e.g. a single PCB
* .MD5 Sets the MD5 file signature or checksum.
*/
#include <wx/log.h>
#include <class_X2_gerber_attributes.h>
/*
* class X2_ATTRIBUTE
* The attribute value consists of a number of substrings separated by a “,”
*/
X2_ATTRIBUTE::X2_ATTRIBUTE()
{
}
X2_ATTRIBUTE::~X2_ATTRIBUTE()
{
}
/* return the attribute name (for instance .FileFunction)
* which is given by TF command.
*/
const wxString& X2_ATTRIBUTE::GetAttribute()
{
return m_Prms.Item( 0 );
}
/* return a parameter
* aIdx = the index of the parameter
* aIdx = 0 is the parameter read after the TF function
* (the same as GetAttribute())
*/
const wxString& X2_ATTRIBUTE::GetPrm( int aIdx)
{
static const wxString dummy;
if( GetPrmCount() < aIdx && aIdx >= 0 )
return m_Prms.Item( aIdx );
return dummy;
}
// Debug function: pring using wxLogMessage le list of parameters
void X2_ATTRIBUTE::DbgListPrms()
{
wxLogMessage( wxT("prms count %d"), GetPrmCount() );
for( int ii = 0; ii < GetPrmCount(); ii++ )
wxLogMessage( m_Prms.Item( ii ) );
}
/*
* parse a TF command and fill m_Prms by the parameters found.
* aFile = a FILE* ptr to the current Gerber file.
* buff = the buffer containing current Gerber data (GERBER_BUFZ size)
* text = a pointer to the first char to read in Gerber data
*/
bool X2_ATTRIBUTE::ParseAttribCmd( FILE* aFile, char *aBuffer, int aBuffSize, char* &aText )
{
bool ok = true;
wxString data;
for( ; ; )
{
while( *aText )
{
switch( *aText )
{
case '%': // end of command
return ok; // success completion
case ' ':
case '\r':
case '\n':
aText++;
break;
case '*': // End of block
m_Prms.Add( data );
data.Empty();
aText++;
break;
case ',': // End of parameter
aText++;
m_Prms.Add( data );
data.Empty();
break;
default:
data.Append( *aText );
aText++;
break;
}
}
// end of current line, read another one.
if( aBuffer )
{
if( fgets( aBuffer, aBuffSize, aFile ) == NULL )
{
// end of file
ok = false;
break;
}
aText = aBuffer;
}
else
return ok;
}
return ok;
}
/*
* class X2_ATTRIBUTE_FILEFUNCTION ( from %TF.FileFunction in Gerber file)
* Example file function:
* %TF.FileFunction,Copper,L1,Top*%
* - Type. Such as copper, solder mask etc.
* - Position. Specifies where the file appears in the PCB layer structure.
* Corresponding position substring:
* Copper layer: L1, L2, L3...to indicate the layer position followed by Top, Inr or
* Bot. L1 is always the top copper layer. E.g. L2,Inr.
* Extra layer, e.g. solder mask: Top or Bot – defines the attachment of the layer.
* Drill/rout layer: E.g. 1,4 – where 1 is the start and 4 is the end copper layer. The
* pair 1,4 defines the span of the drill/rout file
* Optional index. This can be used in instances where for example there are two solder
* masks on the same side. The index counts from the PCB surface outwards.
*/
X2_ATTRIBUTE_FILEFUNCTION::X2_ATTRIBUTE_FILEFUNCTION( X2_ATTRIBUTE& aAttributeBase )
: X2_ATTRIBUTE()
{
m_Prms = aAttributeBase.GetPrms();
m_z_order = 0;
//ensure at least 5 parameters
while( GetPrmCount() < 5 )
m_Prms.Add( wxEmptyString );
set_Z_Order();
}
const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetFileType()
{
// the type of layer (Copper , Soldermask ... )
return m_Prms.Item( 1 );
}
const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetBrdLayerId()
{
// the brd layer identifier: Top, Bot, Ln
return m_Prms.Item( 2 );
}
const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetLabel()
{
// the filefunction label, if any
return m_Prms.Item( 3 );
}
// Initialize the z order priority of the current file, from its attributes
// this priority is the order of layers from top to bottom to draw/display gerber images
// Stack up is( from external copper layer to external)
// copper, then solder paste, then solder mask, then silk screen.
// and global stackup is Front (top) layers then internal copper layers then Back (bottom) layers
void X2_ATTRIBUTE_FILEFUNCTION::set_Z_Order()
{
m_z_order = -100; // low level
m_z_sub_order = 0;
if( GetFileType().IsSameAs( wxT( "Copper" ), false ) )
{
// Copper layer: the priority is the layer Id
m_z_order = 0;
wxString num = GetBrdLayerId().Mid( 1 );
long lnum;
if( num.ToLong( &lnum ) )
m_z_sub_order = -lnum;
}
if( GetFileType().IsSameAs( wxT( "Paste" ), false ) )
{
// solder paste layer: the priority is top then bottom
m_z_order = 1; // for top
if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) )
m_z_order = -m_z_order;
}
if( GetFileType().IsSameAs( wxT( "Soldermask" ), false ) )
{
// solder mask layer: the priority is top then bottom
m_z_order = 2; // for top
if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) )
m_z_order = -m_z_order;
}
if( GetFileType().IsSameAs( wxT( "Legend" ), false ) )
{
// Silk screen layer: the priority is top then bottom
m_z_order = 3; // for top
if( GetFileType().IsSameAs( wxT( "Legend" ), false ) )
if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) )
m_z_order = -m_z_order;
}
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2010-2014 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 1992-2014 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
*/
/**
* @file class_X2_gerber_attributes.h
*/
#ifndef _CLASS_X2_GERBER_ATTRIBUTE_H_
#define _CLASS_X2_GERBER_ATTRIBUTE_H_
/*
* Manage the gerber extensions (attributes) in the new X2 version
* only few extensions are handled
* See http://www.ucamco.com/files/downloads/file/81/the_gerber_file_format_specification.pdf
*
* gerber attributes in the new X2 version look like:
* %TF.FileFunction,Copper,L1,Top*%
*
* Currently:
* .FileFunction .FileFunction Identifies the file’s function in the PCB.
* Other Standard Attributes, not yet used in Gerbview:
* .Part Identifies the part the file represents, e.g. a single PCB
* .MD5 Sets the MD5 file signature or checksum.
*/
#include <wx/arrstr.h>
/**
* class X2_ATTRIBUTE
* The attribute value consists of a number of substrings separated by a “,”
*/
class X2_ATTRIBUTE
{
protected:
wxArrayString m_Prms; ///< the list of parameters (after TF) in gbr file
///< the first one is the attribute name,
///< if starting by '.'
public:
X2_ATTRIBUTE();
~X2_ATTRIBUTE();
/**
* @return the parameters list read in TF command.
*/
wxArrayString& GetPrms() { return m_Prms; }
/**
* @return a parameter read in TF command.
* @param aIdx = the index of the parameter
* aIdx = 0 is the parameter read after the TF function
* (the same as GetAttribute())
*/
const wxString& GetPrm( int aIdx );
/**
* @return the attribute name (for instance .FileFunction)
* which is given by TF command (i.e. the first parameter read).
*/
const wxString& GetAttribute();
/**
* @return the number of parameters read in TF command.
*/
int GetPrmCount() { return int( m_Prms.GetCount() ); }
/**
* parse a TF command terminated with a % and fill m_Prms
* by the parameters found.
* @param aFile = a FILE* ptr to the current Gerber file.
* @param aBuffer = the buffer containing current Gerber data (can be null)
* @param aBuffSize = the size of the buffer
* @param aText = a pointer to the first char to read from Gerber data stored in aBuffer
* After parsing, text points the last char of the command line ('%') (X2 mode)
* or the end of line if the line does not contain '%' or aBuffer == NULL (X1 mode)
* @return true if no error.
*/
bool ParseAttribCmd( FILE* aFile, char *aBuffer, int aBuffSize, char* &aText );
/**
* Debug function: pring using wxLogMessage le list of parameters
*/
void DbgListPrms();
/**
* return true if the attribute is .FileFunction
*/
bool IsFileFunction()
{
return GetAttribute().IsSameAs( wxT(".FileFunction"), false );
}
/**
* return true if the attribute is .MD5
*/
bool IsFileMD5()
{
return GetAttribute().IsSameAs( wxT(".MD5"), false );
}
/**
* return true if the attribute is .Part
*/
bool IsFilePart()
{
return GetAttribute().IsSameAs( wxT(".Part"), false );
}
};
/**
* class X2_ATTRIBUTE_FILEFUNCTION ( from %TF.FileFunction in Gerber file)
* Example file function:
* %TF.FileFunction,Copper,L1,Top*%
* - Type. Such as copper, solder mask etc.
* - Position. Specifies where the file appears in the PCB layer structure.
* Corresponding position substring:
* Copper layer: L1, L2, L3...to indicate the layer position followed by Top, Inr or
* Bot. L1 is always the top copper layer. E.g. L2,Inr.
* Extra layer, e.g. solder mask: Top or Bot – defines the attachment of the layer.
* Drill/rout layer: E.g. 1,4 – where 1 is the start and 4 is the end copper layer. The
* pair 1,4 defines the span of the drill/rout file
* Optional index. This can be used in instances where for example there are two solder
* masks on the same side. The index counts from the PCB surface outwards.
*/
class X2_ATTRIBUTE_FILEFUNCTION : public X2_ATTRIBUTE
{
int m_z_order; // the z order of the layer for a board
int m_z_sub_order; // the z sub_order of the copper layer for a board
public:
X2_ATTRIBUTE_FILEFUNCTION( X2_ATTRIBUTE& aAttributeBase );
const wxString& GetFileType(); ///< the type of layer (Copper , Soldermask ... )
const wxString& GetBrdLayerId(); ///< the brd layer identifier: Top, Bot, Ln
const wxString& GetLabel(); ///< the filefunction label, if any
int GetZOrder() { return m_z_order; } ///< the Order of the bdr layer, from front (Top side) to back side
int GetZSubOrder() { return m_z_sub_order; } ///< the Order of the bdr copper layer, from front (Top side) to back side
private:
/**
* Initialize the z order priority of the current file, from its attributes
*/
void set_Z_Order();
};
#endif // _CLASS_X2_GERBER_ATTRIBUTE_H_
...@@ -33,11 +33,14 @@ ...@@ -33,11 +33,14 @@
#include <colors_selection.h> #include <colors_selection.h>
#include <layers_id_colors_and_visibility.h> #include <layers_id_colors_and_visibility.h>
#include <gerbview_frame.h> #include <gerbview_frame.h>
#include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
#include <class_gbr_layer_box_selector.h> #include <class_gbr_layer_box_selector.h>
void GBR_LAYER_BOX_SELECTOR::Resync() void GBR_LAYER_BOX_SELECTOR::Resync()
{ {
Freeze();
Clear(); Clear();
for( int layerid = 0; layerid < GERBER_DRAWLAYERS_COUNT; ++layerid ) for( int layerid = 0; layerid < GERBER_DRAWLAYERS_COUNT; ++layerid )
...@@ -55,6 +58,8 @@ void GBR_LAYER_BOX_SELECTOR::Resync() ...@@ -55,6 +58,8 @@ void GBR_LAYER_BOX_SELECTOR::Resync()
Append( layername, layerbmp, (void*)(intptr_t) layerid ); Append( layername, layerbmp, (void*)(intptr_t) layerid );
} }
Thaw();
} }
...@@ -70,7 +75,7 @@ EDA_COLOR_T GBR_LAYER_BOX_SELECTOR::GetLayerColor( int aLayer ) const ...@@ -70,7 +75,7 @@ EDA_COLOR_T GBR_LAYER_BOX_SELECTOR::GetLayerColor( int aLayer ) const
// Returns the name of the layer id // Returns the name of the layer id
wxString GBR_LAYER_BOX_SELECTOR::GetLayerName( int aLayer ) const wxString GBR_LAYER_BOX_SELECTOR::GetLayerName( int aLayer ) const
{ {
wxString name; wxString name = g_GERBER_List.GetDisplayName( aLayer );
name.Printf( _( "Layer %d" ), aLayer + 1 );
return name; return name;
} }
...@@ -39,7 +39,6 @@ GBR_LAYOUT::GBR_LAYOUT() ...@@ -39,7 +39,6 @@ GBR_LAYOUT::GBR_LAYOUT()
PAGE_INFO pageInfo( wxT( "GERBER" ) ); PAGE_INFO pageInfo( wxT( "GERBER" ) );
SetPageSettings( pageInfo ); SetPageSettings( pageInfo );
// no m_printLayersMask = -1;
m_printLayersMask.set(); m_printLayersMask.set();
} }
......
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
/** /**
* @file class_gbr_layout.h * @file class_gbr_layout.h
* @brief Class CLASS_GBR_LAYOUT to handle a board. * @brief Class CLASS_GBR_LAYOUT to handle info to draw/print loaded Gerber images
* and page frame reference
*/ */
#ifndef CLASS_GBR_LAYOUT_H #ifndef CLASS_GBR_LAYOUT_H
...@@ -55,7 +56,7 @@ private: ...@@ -55,7 +56,7 @@ private:
std::bitset <GERBER_DRAWLAYERS_COUNT> m_printLayersMask; // When printing: the list of layers to print std::bitset <GERBER_DRAWLAYERS_COUNT> m_printLayersMask; // When printing: the list of layers to print
public: public:
DLIST<GERBER_DRAW_ITEM> m_Drawings; // linked list of Gerber Items DLIST<GERBER_DRAW_ITEM> m_Drawings; // linked list of Gerber Items to draw
GBR_LAYOUT(); GBR_LAYOUT();
~GBR_LAYOUT(); ~GBR_LAYOUT();
......
...@@ -225,7 +225,9 @@ D_CODE* GERBER_DRAW_ITEM::GetDcodeDescr() ...@@ -225,7 +225,9 @@ D_CODE* GERBER_DRAW_ITEM::GetDcodeDescr()
{ {
if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) ) if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
return NULL; return NULL;
GERBER_IMAGE* gerber = g_GERBER_List[m_Layer];
GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( m_Layer );
if( gerber == NULL ) if( gerber == NULL )
return NULL; return NULL;
......
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2004-2010 Jean-Pierre Charras, jean-pierre.charras@gpisa-lab.inpg.fr * Copyright (C) 2004-2010 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
* *
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <class_GERBER.h> #include <class_GERBER.h>
#include <layer_widget.h> #include <layer_widget.h>
#include <class_gerbview_layer_widget.h> #include <class_gerbview_layer_widget.h>
#include <class_X2_gerber_attributes.h>
/* /*
...@@ -70,7 +71,7 @@ GERBER_LAYER_WIDGET::GERBER_LAYER_WIDGET( GERBVIEW_FRAME* aParent, wxWindow* aFo ...@@ -70,7 +71,7 @@ GERBER_LAYER_WIDGET::GERBER_LAYER_WIDGET( GERBVIEW_FRAME* aParent, wxWindow* aFo
// since Popupmenu() calls this->ProcessEvent() we must call this->Connect() // since Popupmenu() calls this->ProcessEvent() we must call this->Connect()
// and not m_LayerScrolledWindow->Connect() // and not m_LayerScrolledWindow->Connect()
Connect( ID_SHOW_ALL_LAYERS, ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE, Connect( ID_LAYER_MANAGER_START, ID_LAYER_MANAGER_END,
wxEVT_COMMAND_MENU_SELECTED, wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler( GERBER_LAYER_WIDGET::onPopupSelection ), NULL, this ); wxCommandEventHandler( GERBER_LAYER_WIDGET::onPopupSelection ), NULL, this );
...@@ -146,8 +147,7 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event ) ...@@ -146,8 +147,7 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event )
{ {
wxMenu menu; wxMenu menu;
// menu text is capitalized: // Remember: menu text is capitalized (see our rules_for_capitalization_in_Kicad_UI.txt)
// http://library.gnome.org/devel/hig-book/2.20/design-text-labels.html.en#layout-capitalization
menu.Append( new wxMenuItem( &menu, ID_SHOW_ALL_LAYERS, menu.Append( new wxMenuItem( &menu, ID_SHOW_ALL_LAYERS,
_("Show All Layers") ) ); _("Show All Layers") ) );
...@@ -160,6 +160,9 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event ) ...@@ -160,6 +160,9 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event )
menu.Append( new wxMenuItem( &menu, ID_SHOW_NO_LAYERS, menu.Append( new wxMenuItem( &menu, ID_SHOW_NO_LAYERS,
_( "Hide All Layers" ) ) ); _( "Hide All Layers" ) ) );
menu.AppendSeparator();
menu.Append( new wxMenuItem( &menu, ID_SORT_GBR_LAYERS,
_( "Sort Layers if X2 Mode" ) ) );
PopupMenu( &menu ); PopupMenu( &menu );
passOnFocus(); passOnFocus();
...@@ -204,6 +207,13 @@ void GERBER_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event ) ...@@ -204,6 +207,13 @@ void GERBER_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event )
myframe->SetVisibleLayers( visibleLayers ); myframe->SetVisibleLayers( visibleLayers );
myframe->GetCanvas()->Refresh(); myframe->GetCanvas()->Refresh();
break; break;
case ID_SORT_GBR_LAYERS:
g_GERBER_List.SortImagesByZOrder( myframe->GetItemsList() );
myframe->ReFillLayerWidget();
myframe->syncLayerBox();
myframe->GetCanvas()->Refresh();
break;
} }
} }
...@@ -212,7 +222,7 @@ bool GERBER_LAYER_WIDGET::OnLayerSelected() ...@@ -212,7 +222,7 @@ bool GERBER_LAYER_WIDGET::OnLayerSelected()
if( !m_alwaysShowActiveLayer ) if( !m_alwaysShowActiveLayer )
return false; return false;
// postprocess after an active layer selection // postprocess after active layer selection
// ensure active layer visible // ensure active layer visible
wxCommandEvent event; wxCommandEvent event;
event.SetId( ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE ); event.SetId( ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE );
...@@ -223,16 +233,20 @@ bool GERBER_LAYER_WIDGET::OnLayerSelected() ...@@ -223,16 +233,20 @@ bool GERBER_LAYER_WIDGET::OnLayerSelected()
void GERBER_LAYER_WIDGET::ReFill() void GERBER_LAYER_WIDGET::ReFill()
{ {
Freeze();
ClearLayerRows(); ClearLayerRows();
for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer ) for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
{ {
wxString msg; wxString msg = g_GERBER_List.GetDisplayName( layer );
msg.Printf( _("Layer %d"), layer+1 );
AppendLayerRow( LAYER_WIDGET::ROW( msg, layer, AppendLayerRow( LAYER_WIDGET::ROW( msg, layer,
myframe->GetLayerColor( layer ), wxEmptyString, true ) ); myframe->GetLayerColor( layer ), wxEmptyString, true ) );
} }
Thaw();
installRightLayerClickHandler(); installRightLayerClickHandler();
} }
...@@ -298,17 +312,10 @@ void GERBER_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled ) ...@@ -298,17 +312,10 @@ void GERBER_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled )
*/ */
bool GERBER_LAYER_WIDGET::useAlternateBitmap(int aRow) bool GERBER_LAYER_WIDGET::useAlternateBitmap(int aRow)
{ {
bool inUse = false; return g_GERBER_List.IsUsed( aRow );
GERBER_IMAGE* gerber = g_GERBER_List[aRow];
if( gerber != NULL && gerber->m_InUse )
inUse = true;
return inUse;
} }
/** /*
* Function UpdateLayerIcons
* Update the layer manager icons (layers only) * Update the layer manager icons (layers only)
* Useful when loading a file or clearing a layer because they change * Useful when loading a file or clearing a layer because they change
*/ */
...@@ -322,7 +329,8 @@ void GERBER_LAYER_WIDGET::UpdateLayerIcons() ...@@ -322,7 +329,8 @@ void GERBER_LAYER_WIDGET::UpdateLayerIcons()
continue; continue;
if( row == m_CurrentRow ) if( row == m_CurrentRow )
bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap : *m_RightArrowBitmap ); bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap :
*m_RightArrowBitmap );
else else
bm->SetBitmap( useAlternateBitmap(row) ? *m_BlankAlternateBitmap : *m_BlankBitmap ); bm->SetBitmap( useAlternateBitmap(row) ? *m_BlankAlternateBitmap : *m_BlankBitmap );
} }
......
...@@ -33,6 +33,18 @@ ...@@ -33,6 +33,18 @@
#include <layer_widget.h> #include <layer_widget.h>
// popup menu ids. in layer manager
enum LAYER_MANAGER
{
ID_LAYER_MANAGER_START = wxID_HIGHEST+1,
ID_SHOW_ALL_LAYERS = ID_LAYER_MANAGER_START,
ID_SHOW_NO_LAYERS,
ID_SHOW_NO_LAYERS_BUT_ACTIVE,
ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE,
ID_SORT_GBR_LAYERS,
ID_LAYER_MANAGER_END = ID_SORT_GBR_LAYERS,
};
/** /**
* Class GERBER_LAYER_WIDGET * Class GERBER_LAYER_WIDGET
* is here to implement the abtract functions of LAYER_WIDGET so they * is here to implement the abtract functions of LAYER_WIDGET so they
...@@ -45,11 +57,6 @@ class GERBER_LAYER_WIDGET : public LAYER_WIDGET ...@@ -45,11 +57,6 @@ class GERBER_LAYER_WIDGET : public LAYER_WIDGET
bool m_alwaysShowActiveLayer; // If true: Only shows the current active layer bool m_alwaysShowActiveLayer; // If true: Only shows the current active layer
// even if it is changed // even if it is changed
// popup menu ids.
#define ID_SHOW_ALL_LAYERS wxID_HIGHEST
#define ID_SHOW_NO_LAYERS (wxID_HIGHEST+1)
#define ID_SHOW_NO_LAYERS_BUT_ACTIVE (wxID_HIGHEST+2)
#define ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE (wxID_HIGHEST+3)
/** /**
* Function OnRightDownLayers * Function OnRightDownLayers
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <gerbview.h> #include <gerbview.h>
#include <gerbview_frame.h> #include <gerbview_frame.h>
#include <class_GERBER.h>
#include <pcbplot.h> #include <pcbplot.h>
static double s_ScaleList[] = static double s_ScaleList[] =
...@@ -163,7 +164,7 @@ void DIALOG_PRINT_USING_PRINTER::InitValues( ) ...@@ -163,7 +164,7 @@ void DIALOG_PRINT_USING_PRINTER::InitValues( )
msg << wxT( " " ) << ii + 1; msg << wxT( " " ) << ii + 1;
m_BoxSelectLayer[ii] = new wxCheckBox( this, -1, msg ); m_BoxSelectLayer[ii] = new wxCheckBox( this, -1, msg );
if( g_GERBER_List[ii] == NULL ) // Nothing loaded on this draw layer if( g_GERBER_List.GetGbrImage( ii ) == NULL ) // Nothing loaded on this draw layer
m_BoxSelectLayer[ii]->Enable( false ); m_BoxSelectLayer[ii]->Enable( false );
if( ii < 16 ) if( ii < 16 )
......
...@@ -214,14 +214,16 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode, ...@@ -214,14 +214,16 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
bool end = false; bool end = false;
for( int layer = 0; !end; ++layer ) // Draw layers from bottom to top, and active layer last
// in non transparent modes, the last layer drawn mask mask previously drawn layer
for( int layer = GERBER_DRAWLAYERS_COUNT-1; !end; --layer )
{ {
int active_layer = gerbFrame->getActiveLayer(); int active_layer = gerbFrame->getActiveLayer();
if( layer == active_layer ) // active layer will be drawn after other layers if( layer == active_layer ) // active layer will be drawn after other layers
continue; continue;
if( layer == GERBER_DRAWLAYERS_COUNT ) // last loop: draw active layer if( layer < 0 ) // last loop: draw active layer
{ {
end = true; end = true;
layer = active_layer; layer = active_layer;
...@@ -230,7 +232,7 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode, ...@@ -230,7 +232,7 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
if( !gerbFrame->IsLayerVisible( layer ) ) if( !gerbFrame->IsLayerVisible( layer ) )
continue; continue;
GERBER_IMAGE* gerber = g_GERBER_List[layer]; GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
if( gerber == NULL ) // Graphic layer not yet used if( gerber == NULL ) // Graphic layer not yet used
continue; continue;
......
...@@ -234,7 +234,7 @@ void GERBVIEW_FRAME::Process_Special_Functions( wxCommandEvent& event ) ...@@ -234,7 +234,7 @@ void GERBVIEW_FRAME::Process_Special_Functions( wxCommandEvent& event )
void GERBVIEW_FRAME::OnSelectActiveDCode( wxCommandEvent& event ) void GERBVIEW_FRAME::OnSelectActiveDCode( wxCommandEvent& event )
{ {
GERBER_IMAGE* gerber_image = g_GERBER_List[getActiveLayer()]; GERBER_IMAGE* gerber_image = g_GERBER_List.GetGbrImage( getActiveLayer() );
if( gerber_image ) if( gerber_image )
{ {
...@@ -266,7 +266,7 @@ void GERBVIEW_FRAME::OnSelectActiveLayer( wxCommandEvent& event ) ...@@ -266,7 +266,7 @@ void GERBVIEW_FRAME::OnSelectActiveLayer( wxCommandEvent& event )
void GERBVIEW_FRAME::OnShowGerberSourceFile( wxCommandEvent& event ) void GERBVIEW_FRAME::OnShowGerberSourceFile( wxCommandEvent& event )
{ {
int layer = getActiveLayer(); int layer = getActiveLayer();
GERBER_IMAGE* gerber_layer = g_GERBER_List[layer]; GERBER_IMAGE* gerber_layer = g_GERBER_List.GetGbrImage( layer );
if( gerber_layer ) if( gerber_layer )
{ {
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 1992-2011 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr> * Copyright (C) 1992-2014 Jean-Pierre Charras <jp.charras at wanadoo.fr>
* Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 1992-2014 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
#include <class_GERBER.h> #include <class_GERBER.h>
#include <class_excellon.h> #include <class_excellon.h>
#include <kicad_string.h> #include <kicad_string.h>
#include <class_X2_gerber_attributes.h>
#include <cmath> #include <cmath>
...@@ -105,6 +106,12 @@ void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem, ...@@ -105,6 +106,12 @@ void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
wxSize aPenSize, wxSize aPenSize,
bool aLayerNegative ); bool aLayerNegative );
// Getber X2 files have a file attribute which specify the type of image
// (copper, solder paste ... and sides tpo, bottom or inner copper layers)
// Excellon drill files do not have attributes, so, just to identify the image
// In gerbview, we add this attribute, like a Gerber drill file
static const char file_attribute[] = ".FileFunction,Other,Drill*";
static EXCELLON_CMD excellonHeaderCmdList[] = static EXCELLON_CMD excellonHeaderCmdList[] =
{ {
{ "M0", DRILL_M_END, -1 }, // End of Program - No Rewind { "M0", DRILL_M_END, -1 }, // End of Program - No Rewind
...@@ -168,14 +175,21 @@ static EXCELLON_CMD excellon_G_CmdList[] = ...@@ -168,14 +175,21 @@ static EXCELLON_CMD excellon_G_CmdList[] =
bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName ) bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
{ {
wxString msg; wxString msg;
int layer = getActiveLayer(); // current layer used in GerbView int layerId = getActiveLayer(); // current layer used in GerbView
EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List.GetGbrImage( layerId );
if( drill_Layer == NULL )
{
drill_Layer = new EXCELLON_IMAGE( this, layerId );
layerId = g_GERBER_List.AddGbrImage( drill_Layer, layerId );
}
if( g_GERBER_List[layer] == NULL ) if( layerId < 0 )
{ {
g_GERBER_List[layer] = new EXCELLON_IMAGE( this, layer ); DisplayError( this, _( "No room to load file" ) );
return false;
} }
EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List[layer];
ClearMessageList(); ClearMessageList();
/* Read the gerber file */ /* Read the gerber file */
...@@ -183,7 +197,7 @@ bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName ) ...@@ -183,7 +197,7 @@ bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
if( file == NULL ) if( file == NULL )
{ {
msg.Printf( _( "File %s not found" ), GetChars( aFullFileName ) ); msg.Printf( _( "File %s not found" ), GetChars( aFullFileName ) );
DisplayError( this, msg, 10 ); DisplayError( this, msg );
return false; return false;
} }
...@@ -213,7 +227,7 @@ bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile, ...@@ -213,7 +227,7 @@ bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile,
m_FileName = aFullFileName; m_FileName = aFullFileName;
m_Current_File = aFile; m_Current_File = aFile;
SetLocaleTo_C_standard(); LOCALE_IO toggleIo;
// FILE_LINE_READER will close the file. // FILE_LINE_READER will close the file.
if( m_Current_File == NULL ) if( m_Current_File == NULL )
...@@ -282,7 +296,16 @@ bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile, ...@@ -282,7 +296,16 @@ bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile,
} // End switch } // End switch
} }
} }
SetLocaleTo_Default();
// Add our file attribute, to identify the drill file
X2_ATTRIBUTE dummy;
char* text = (char*)file_attribute;
dummy.ParseAttribCmd( m_Current_File, NULL, 0, text );
delete m_FileFunction;
m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
m_InUse = true;
return true; return true;
} }
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <gerbview.h> #include <gerbview.h>
#include <gerbview_frame.h> #include <gerbview_frame.h>
#include <class_gerber_draw_item.h> #include <class_gerber_draw_item.h>
#include <class_GERBER.h>
#include <select_layers_to_pcb.h> #include <select_layers_to_pcb.h>
#include <build_version.h> #include <build_version.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
...@@ -159,7 +160,7 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event ) ...@@ -159,7 +160,7 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event )
// Count the Gerber layers which are actually currently used // Count the Gerber layers which are actually currently used
for( LAYER_NUM ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii ) for( LAYER_NUM ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
{ {
if( g_GERBER_List[ii] != NULL ) if( g_GERBER_List.GetGbrImage( ii ) )
layercount++; layercount++;
} }
......
...@@ -84,6 +84,7 @@ void GERBVIEW_FRAME::Files_io( wxCommandEvent& event ) ...@@ -84,6 +84,7 @@ void GERBVIEW_FRAME::Files_io( wxCommandEvent& event )
Zoom_Automatique( false ); Zoom_Automatique( false );
m_canvas->Refresh(); m_canvas->Refresh();
ClearMsgPanel(); ClearMsgPanel();
ReFillLayerWidget();
break; break;
case ID_GERBVIEW_LOAD_DRILL_FILE: case ID_GERBVIEW_LOAD_DRILL_FILE:
...@@ -200,6 +201,7 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName ) ...@@ -200,6 +201,7 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName )
Zoom_Automatique( false ); Zoom_Automatique( false );
// Synchronize layers tools with actual active layer: // Synchronize layers tools with actual active layer:
ReFillLayerWidget();
setActiveLayer( getActiveLayer() ); setActiveLayer( getActiveLayer() );
m_LayersManager->UpdateLayerIcons(); m_LayersManager->UpdateLayerIcons();
syncLayerBox(); syncLayerBox();
...@@ -282,6 +284,7 @@ bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFullFileName ) ...@@ -282,6 +284,7 @@ bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFullFileName )
Zoom_Automatique( false ); Zoom_Automatique( false );
// Synchronize layers tools with actual active layer: // Synchronize layers tools with actual active layer:
ReFillLayerWidget();
setActiveLayer( getActiveLayer() ); setActiveLayer( getActiveLayer() );
m_LayersManager->UpdateLayerIcons(); m_LayersManager->UpdateLayerIcons();
syncLayerBox(); syncLayerBox();
......
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
// Colors for layers and items // Colors for layers and items
COLORS_DESIGN_SETTINGS g_ColorsSettings; COLORS_DESIGN_SETTINGS g_ColorsSettings;
int g_Default_GERBER_Format;
const wxChar* g_GerberPageSizeList[] = { const wxChar* g_GerberPageSizeList[] = {
...@@ -60,9 +59,6 @@ const wxChar* g_GerberPageSizeList[] = { ...@@ -60,9 +59,6 @@ const wxChar* g_GerberPageSizeList[] = {
}; };
GERBER_IMAGE* g_GERBER_List[32];
namespace GERBV { namespace GERBV {
static struct IFACE : public KIFACE_I static struct IFACE : public KIFACE_I
......
...@@ -109,6 +109,4 @@ enum Gerb_Analyse_Cmd ...@@ -109,6 +109,4 @@ enum Gerb_Analyse_Cmd
ENTER_RS274X_CMD ENTER_RS274X_CMD
}; };
extern GERBER_IMAGE* g_GERBER_List[GERBER_DRAWLAYERS_COUNT];
#endif // ifndef GERBVIEW_H #endif // ifndef GERBVIEW_H
...@@ -348,7 +348,7 @@ int GERBVIEW_FRAME::getNextAvailableLayer( int aLayer ) const ...@@ -348,7 +348,7 @@ int GERBVIEW_FRAME::getNextAvailableLayer( int aLayer ) const
for( int i = 0; i < GERBER_DRAWLAYERS_COUNT; ++i ) for( int i = 0; i < GERBER_DRAWLAYERS_COUNT; ++i )
{ {
GERBER_IMAGE* gerber = g_GERBER_List[ layer ]; GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
if( gerber == NULL || gerber->m_FileName.IsEmpty() ) if( gerber == NULL || gerber->m_FileName.IsEmpty() )
return layer; return layer;
...@@ -378,9 +378,11 @@ void GERBVIEW_FRAME::syncLayerWidget() ...@@ -378,9 +378,11 @@ void GERBVIEW_FRAME::syncLayerWidget()
*/ */
void GERBVIEW_FRAME::syncLayerBox() void GERBVIEW_FRAME::syncLayerBox()
{ {
m_SelLayerBox->Resync();
m_SelLayerBox->SetSelection( getActiveLayer() ); m_SelLayerBox->SetSelection( getActiveLayer() );
int dcodeSelected = -1; int dcodeSelected = -1;
GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer()]; GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
if( gerber ) if( gerber )
dcodeSelected = gerber->m_Selected_Tool; dcodeSelected = gerber->m_Selected_Tool;
...@@ -406,7 +408,7 @@ void GERBVIEW_FRAME::Liste_D_Codes() ...@@ -406,7 +408,7 @@ void GERBVIEW_FRAME::Liste_D_Codes()
for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer ) for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
{ {
GERBER_IMAGE* gerber = g_GERBER_List[layer]; GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
if( gerber == NULL ) if( gerber == NULL )
continue; continue;
...@@ -474,7 +476,7 @@ void GERBVIEW_FRAME::Liste_D_Codes() ...@@ -474,7 +476,7 @@ void GERBVIEW_FRAME::Liste_D_Codes()
*/ */
void GERBVIEW_FRAME::UpdateTitleAndInfo() void GERBVIEW_FRAME::UpdateTitleAndInfo()
{ {
GERBER_IMAGE* gerber = g_GERBER_List[ getActiveLayer() ]; GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
wxString text; wxString text;
// Display the gerber filename // Display the gerber filename
...@@ -491,6 +493,8 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo() ...@@ -491,6 +493,8 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo()
text = _( "File:" ); text = _( "File:" );
text << wxT( " " ) << gerber->m_FileName; text << wxT( " " ) << gerber->m_FileName;
if( gerber->m_IsX2_file )
text << wxT( " " ) << _( "(with X2 Attributes)" );
SetTitle( text ); SetTitle( text );
gerber->DisplayImageInfo(); gerber->DisplayImageInfo();
...@@ -508,7 +512,13 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo() ...@@ -508,7 +512,13 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo()
gerber->m_FmtLen.y - gerber->m_FmtScale.y, gerber->m_FmtScale.y, gerber->m_FmtLen.y - gerber->m_FmtScale.y, gerber->m_FmtScale.y,
gerber->m_NoTrailingZeros ? 'T' : 'L' ); gerber->m_NoTrailingZeros ? 'T' : 'L' );
if( gerber->m_IsX2_file )
text << wxT(" ") << _( "X2 attr" );
m_TextInfo->SetValue( text ); m_TextInfo->SetValue( text );
if( EnsureTextCtrlWidth( m_TextInfo, &text ) ) // Resized
m_auimgr.Update();
} }
/* /*
......
...@@ -40,8 +40,6 @@ ...@@ -40,8 +40,6 @@
bool GERBVIEW_FRAME::Clear_DrawLayers( bool query ) bool GERBVIEW_FRAME::Clear_DrawLayers( bool query )
{ {
int layer;
if( GetGerberLayout() == NULL ) if( GetGerberLayout() == NULL )
return false; return false;
...@@ -53,14 +51,7 @@ bool GERBVIEW_FRAME::Clear_DrawLayers( bool query ) ...@@ -53,14 +51,7 @@ bool GERBVIEW_FRAME::Clear_DrawLayers( bool query )
GetGerberLayout()->m_Drawings.DeleteAll(); GetGerberLayout()->m_Drawings.DeleteAll();
for( layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer ) g_GERBER_List.ClearList();
{
if( g_GERBER_List[layer] )
{
g_GERBER_List[layer]->InitToolTable();
g_GERBER_List[layer]->ResetDefaultValues();
}
}
GetGerberLayout()->SetBoundingBox( EDA_RECT() ); GetGerberLayout()->SetBoundingBox( EDA_RECT() );
...@@ -98,11 +89,7 @@ void GERBVIEW_FRAME::Erase_Current_DrawLayer( bool query ) ...@@ -98,11 +89,7 @@ void GERBVIEW_FRAME::Erase_Current_DrawLayer( bool query )
item->DeleteStructure(); item->DeleteStructure();
} }
if( g_GERBER_List[layer] ) g_GERBER_List.ClearImage( layer );
{
g_GERBER_List[layer]->InitToolTable();
g_GERBER_List[layer]->ResetDefaultValues();
}
GetScreen()->SetModify(); GetScreen()->SetModify();
m_canvas->Refresh(); m_canvas->Refresh();
......
...@@ -56,7 +56,7 @@ void GERBVIEW_FRAME::OnLeftClick( wxDC* DC, const wxPoint& aPosition ) ...@@ -56,7 +56,7 @@ void GERBVIEW_FRAME::OnLeftClick( wxDC* DC, const wxPoint& aPosition )
GetScreen()->SetCurItem( DrawStruct ); GetScreen()->SetCurItem( DrawStruct );
if( DrawStruct == NULL ) if( DrawStruct == NULL )
{ {
GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer() ]; GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
if( gerber ) if( gerber )
gerber->DisplayImageInfo( ); gerber->DisplayImageInfo( );
} }
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include <html_messagebox.h> #include <html_messagebox.h>
#include <macros.h> #include <macros.h>
/* Read a gerber file, RS274D or RS274X format. /* Read a gerber file, RS274D, RS274X or RS274X2 format.
*/ */
bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName, bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
const wxString& D_Code_FullFileName ) const wxString& D_Code_FullFileName )
...@@ -49,13 +49,14 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName, ...@@ -49,13 +49,14 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
int layer; // current layer used in GerbView int layer; // current layer used in GerbView
layer = getActiveLayer(); layer = getActiveLayer();
GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
if( g_GERBER_List[layer] == NULL ) if( gerber == NULL )
{ {
g_GERBER_List[layer] = new GERBER_IMAGE( this, layer ); gerber = new GERBER_IMAGE( this, layer );
g_GERBER_List.AddGbrImage( gerber, layer );
} }
GERBER_IMAGE* gerber = g_GERBER_List[layer];
ClearMessageList( ); ClearMessageList( );
/* Set the gerber scale: */ /* Set the gerber scale: */
...@@ -76,7 +77,7 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName, ...@@ -76,7 +77,7 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
if( path != wxEmptyString ) if( path != wxEmptyString )
wxSetWorkingDirectory( path ); wxSetWorkingDirectory( path );
SetLocaleTo_C_standard(); LOCALE_IO toggleIo;
while( true ) while( true )
{ {
...@@ -170,8 +171,8 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName, ...@@ -170,8 +171,8 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
} }
} }
} }
fclose( gerber->m_Current_File ); fclose( gerber->m_Current_File );
SetLocaleTo_Default();
gerber->m_InUse = true; gerber->m_InUse = true;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <macros.h> #include <macros.h>
#include <class_gerber_draw_item.h> #include <class_gerber_draw_item.h>
#include <class_GERBER.h> #include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
#include <cmath> #include <cmath>
...@@ -43,7 +44,8 @@ ...@@ -43,7 +44,8 @@
* G01 linear interpolation (right trace) * G01 linear interpolation (right trace)
* G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise) * G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise)
* G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise) * G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise)
* G04 = comment * G04 = comment. Since Sept 2014, file attributes can be found here
* if the line starts by G04 #@!
* G06 parabolic interpolation * G06 parabolic interpolation
* G07 Cubic Interpolation * G07 Cubic Interpolation
* G10 linear interpolation (scale x10) * G10 linear interpolation (scale x10)
...@@ -473,7 +475,20 @@ bool GERBER_IMAGE::Execute_G_Command( char*& text, int G_command ) ...@@ -473,7 +475,20 @@ bool GERBER_IMAGE::Execute_G_Command( char*& text, int G_command )
break; break;
case GC_COMMENT: case GC_COMMENT:
// Skip comment // Skip comment, but only if the line does not start by "G04 #@! TF"
// which is a metadata
if( strncmp( text, " #@! TF", 7 ) == 0 )
{
text += 7;
X2_ATTRIBUTE dummy;
dummy.ParseAttribCmd( m_Current_File, NULL, 0, text );
if( dummy.IsFileFunction() )
{
delete m_FileFunction;
m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
}
}
while ( *text && (*text != '*') ) while ( *text && (*text != '*') )
text++; text++;
break; break;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <gerbview.h> #include <gerbview.h>
#include <class_GERBER.h> #include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
extern int ReadInt( char*& text, bool aSkipSeparator = true ); extern int ReadInt( char*& text, bool aSkipSeparator = true );
extern double ReadDouble( char*& text, bool aSkipSeparator = true ); extern double ReadDouble( char*& text, bool aSkipSeparator = true );
...@@ -78,6 +79,13 @@ enum RS274X_PARAMETERS { ...@@ -78,6 +79,13 @@ enum RS274X_PARAMETERS {
AP_DEFINITION = CODE( 'A', 'D' ), AP_DEFINITION = CODE( 'A', 'D' ),
AP_MACRO = CODE( 'A', 'M' ), AP_MACRO = CODE( 'A', 'M' ),
// X2 extention attribute commands
// Mainly are found standard attributes and user attributes
// standard attributes commands are:
// TF (file attribute)
// TA (aperture attribute) and TD (delete aperture attribute)
FILE_ATTRIBUTE = CODE( 'T', 'F' ),
// Layer specific parameters // Layer specific parameters
// May be used singly or may be layer specfic // May be used singly or may be layer specfic
// theses parameters are at the beginning of the file or layer // theses parameters are at the beginning of the file or layer
...@@ -307,7 +315,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command, ...@@ -307,7 +315,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
m_SwapAxis = true; m_SwapAxis = true;
break; break;
case MIRROR_IMAGE: // commanf %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*% case MIRROR_IMAGE: // command %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
m_MirrorA = m_MirrorB = 0; m_MirrorA = m_MirrorB = 0;
while( *text && *text != '*' ) while( *text && *text != '*' )
{ {
...@@ -341,6 +349,27 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command, ...@@ -341,6 +349,27 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS; conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS;
break; break;
case FILE_ATTRIBUTE: // Command %TF ...
m_IsX2_file = true;
{
X2_ATTRIBUTE dummy;
dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
if( dummy.IsFileFunction() )
{
delete m_FileFunction;
m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
}
else if( dummy.IsFileMD5() )
{
m_MD5_value = dummy.GetPrm( 1 );
}
else if( dummy.IsFilePart() )
{
m_PartString = dummy.GetPrm( 1 );
}
}
break;
case OFFSET: // command: OFAnnBnn (nn = float number) = layer Offset case OFFSET: // command: OFAnnBnn (nn = float number) = layer Offset
m_Offset.x = m_Offset.y = 0; m_Offset.x = m_Offset.y = 0;
while( *text != '*' ) while( *text != '*' )
......
...@@ -121,7 +121,7 @@ void LAYERS_MAP_DIALOG::initDialog() ...@@ -121,7 +121,7 @@ void LAYERS_MAP_DIALOG::initDialog()
m_gerberActiveLayersCount = 0; m_gerberActiveLayersCount = 0;
for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii ) for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
{ {
if( g_GERBER_List[ii] == NULL ) if( g_GERBER_List.GetGbrImage( ii ) == NULL )
break; break;
if( (pcb_layer_num == m_exportBoardCopperLayersCount - 1) if( (pcb_layer_num == m_exportBoardCopperLayersCount - 1)
...@@ -189,7 +189,7 @@ void LAYERS_MAP_DIALOG::initDialog() ...@@ -189,7 +189,7 @@ void LAYERS_MAP_DIALOG::initDialog()
wxRIGHT | wxLEFT, 5 ); wxRIGHT | wxLEFT, 5 );
/* Add file name and extension without path. */ /* Add file name and extension without path. */
wxFileName fn( g_GERBER_List[ii]->m_FileName ); wxFileName fn( g_GERBER_List.GetGbrImage( ii )->m_FileName );
label = new wxStaticText( this, wxID_STATIC, fn.GetFullName(), label = new wxStaticText( this, wxID_STATIC, fn.GetFullName(),
wxDefaultPosition, wxDefaultSize ); wxDefaultPosition, wxDefaultSize );
flexColumnBoxSizer->Add( label, 0, flexColumnBoxSizer->Add( label, 0,
......
...@@ -294,7 +294,7 @@ void GERBVIEW_FRAME::OnUpdateShowLayerManager( wxUpdateUIEvent& aEvent ) ...@@ -294,7 +294,7 @@ void GERBVIEW_FRAME::OnUpdateShowLayerManager( wxUpdateUIEvent& aEvent )
void GERBVIEW_FRAME::OnUpdateSelectDCode( wxUpdateUIEvent& aEvent ) void GERBVIEW_FRAME::OnUpdateSelectDCode( wxUpdateUIEvent& aEvent )
{ {
int layer = getActiveLayer(); int layer = getActiveLayer();
GERBER_IMAGE* gerber = g_GERBER_List[layer]; GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
int selected = ( gerber ) ? gerber->m_Selected_Tool : 0; int selected = ( gerber ) ? gerber->m_Selected_Tool : 0;
if( m_DCodeSelector && m_DCodeSelector->GetSelectedDCodeId() != selected ) if( m_DCodeSelector && m_DCodeSelector->GetSelectedDCodeId() != selected )
......
...@@ -333,7 +333,7 @@ PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindow ...@@ -333,7 +333,7 @@ PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindow
bSizeRight = new wxBoxSizer( wxVERTICAL ); bSizeRight = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizerTW_Result; wxStaticBoxSizer* sbSizerTW_Result;
sbSizerTW_Result = new wxStaticBoxSizer( new wxStaticBox( m_panelTrackWidth, wxID_ANY, _("Tracks Caracteristics (External Layers):") ), wxVERTICAL ); sbSizerTW_Result = new wxStaticBoxSizer( new wxStaticBox( m_panelTrackWidth, wxID_ANY, _("Track Characteristics (External Layers):") ), wxVERTICAL );
wxFlexGridSizer* fgSizerTW_Results; wxFlexGridSizer* fgSizerTW_Results;
fgSizerTW_Results = new wxFlexGridSizer( 5, 3, 0, 0 ); fgSizerTW_Results = new wxFlexGridSizer( 5, 3, 0, 0 );
...@@ -409,7 +409,7 @@ PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindow ...@@ -409,7 +409,7 @@ PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindow
bSizeRight->Add( sbSizerTW_Result, 1, wxEXPAND|wxALL, 5 ); bSizeRight->Add( sbSizerTW_Result, 1, wxEXPAND|wxALL, 5 );
wxStaticBoxSizer* sbSizerTW_Result1; wxStaticBoxSizer* sbSizerTW_Result1;
sbSizerTW_Result1 = new wxStaticBoxSizer( new wxStaticBox( m_panelTrackWidth, wxID_ANY, _("Tracks Caracteristics (Internal Layers):") ), wxVERTICAL ); sbSizerTW_Result1 = new wxStaticBoxSizer( new wxStaticBox( m_panelTrackWidth, wxID_ANY, _("Track Characteristics (Internal Layers):") ), wxVERTICAL );
wxFlexGridSizer* fgSizerTW_Results1; wxFlexGridSizer* fgSizerTW_Results1;
fgSizerTW_Results1 = new wxFlexGridSizer( 6, 3, 0, 0 ); fgSizerTW_Results1 = new wxFlexGridSizer( 6, 3, 0, 0 );
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
<property name="size">670,489</property> <property name="size">670,489</property>
<property name="style">wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER</property> <property name="style">wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER</property>
<property name="subclass">KIWAY_PLAYER; kiway_player.h</property> <property name="subclass">KIWAY_PLAYER; kiway_player.h</property>
<property name="title">Pcb Calculator</property> <property name="title">PCB Calculator</property>
<property name="tooltip"></property> <property name="tooltip"></property>
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
...@@ -4687,7 +4687,7 @@ ...@@ -4687,7 +4687,7 @@
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="0"> <object class="wxStaticBoxSizer" expanded="0">
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">Tracks Caracteristics (External Layers):</property> <property name="label">Track Characteristics (External Layers):</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">sbSizerTW_Result</property> <property name="name">sbSizerTW_Result</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
...@@ -6009,7 +6009,7 @@ ...@@ -6009,7 +6009,7 @@
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="0"> <object class="wxStaticBoxSizer" expanded="0">
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">Tracks Caracteristics (Internal Layers):</property> <property name="label">Track Characteristics (Internal Layers):</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">sbSizerTW_Result1</property> <property name="name">sbSizerTW_Result1</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
...@@ -293,7 +293,7 @@ class PCB_CALCULATOR_FRAME_BASE : public KIWAY_PLAYER ...@@ -293,7 +293,7 @@ class PCB_CALCULATOR_FRAME_BASE : public KIWAY_PLAYER
public: public:
PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Pcb Calculator"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 670,489 ), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL ); PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("PCB Calculator"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 670,489 ), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL );
~PCB_CALCULATOR_FRAME_BASE(); ~PCB_CALCULATOR_FRAME_BASE();
......
...@@ -223,12 +223,12 @@ void PCB_CALCULATOR_FRAME::OnDataFileSelection( wxCommandEvent& event ) ...@@ -223,12 +223,12 @@ void PCB_CALCULATOR_FRAME::OnDataFileSelection( wxCommandEvent& event )
wxString fullfilename = GetDataFilename(); wxString fullfilename = GetDataFilename();
wxString wildcard; wxString wildcard;
wildcard.Printf( _("Pcb Calculator data file (*.%s)|*.%s"), wildcard.Printf( _("PCB Calculator data file (*.%s)|*.%s"),
GetChars( DataFileNameExt ), GetChars( DataFileNameExt ),
GetChars( DataFileNameExt ) ); GetChars( DataFileNameExt ) );
wxFileDialog dlg( m_panelRegulators, wxFileDialog dlg( m_panelRegulators,
_("Select a Pcb Calculator data file"), _("Select a PCB Calculator data file"),
wxEmptyString, fullfilename, wxEmptyString, fullfilename,
wildcard, wxFD_OPEN ); wildcard, wxFD_OPEN );
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
* @brief function to convert shapes of items ( pads, tracks... ) to polygons * @brief function to convert shapes of items ( pads, tracks... ) to polygons
*/ */
/* Function to convert pads and tranck shapes to polygons /* Function to convert pad and track shapes to polygons
* Used to fill zones areas * Used to fill zones areas and in 3D viewer
*/ */
#include <vector> #include <vector>
...@@ -520,22 +520,19 @@ void TRACK:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer ...@@ -520,22 +520,19 @@ void TRACK:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
* clearance when the circle is approximated by segment bigger or equal * clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0) * to the real clearance value (usually near from 1.0)
*/ */
#include <clipper.hpp>
void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer, void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
int aClearanceValue, int aClearanceValue,
int aCircleToSegmentsCount, int aCircleToSegmentsCount,
double aCorrectionFactor ) const double aCorrectionFactor ) const
{ {
wxPoint corner_position; wxPoint corner_position;
double angle; double angle = m_Orient;
int dx = (m_Size.x / 2) + aClearanceValue; int dx = (m_Size.x / 2) + aClearanceValue;
int dy = (m_Size.y / 2) + aClearanceValue; int dy = (m_Size.y / 2) + aClearanceValue;
double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree
wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset, wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */ * the pad position is NOT the shape position */
wxSize psize = m_Size; /* pad size unsed in RECT and TRAPEZOIDAL pads
* trapezoidal pads are considered as rect
* pad shape having they boudary box size */
switch( GetShape() ) switch( GetShape() )
{ {
...@@ -547,7 +544,6 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer ...@@ -547,7 +544,6 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
case PAD_OVAL: case PAD_OVAL:
// An oval pad has the same shape as a segment with rounded ends // An oval pad has the same shape as a segment with rounded ends
angle = m_Orient;
{ {
int width; int width;
wxPoint shape_offset; wxPoint shape_offset;
...@@ -573,77 +569,51 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer ...@@ -573,77 +569,51 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
break; break;
case PAD_TRAPEZOID: case PAD_TRAPEZOID:
psize.x += std::abs( m_DeltaSize.y );
psize.y += std::abs( m_DeltaSize.x );
// fall through
case PAD_RECT: case PAD_RECT:
// Easy implementation for rectangular cutouts with rounded corners
angle = m_Orient;
// Corner rounding radius
int rounding_radius = KiROUND( aClearanceValue * aCorrectionFactor );
double angle_pg; // Polygon increment angle
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
{ {
corner_position = wxPoint( 0, -rounding_radius ); wxPoint corners[4];
RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); BuildPadPolygon( corners, wxSize( 0, 0 ), angle );
// Start at half increment offset
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
// Rounding vector rotation
corner_position -= psize / 2; // Rounding vector + Pad corner offset
RotatePoint( &corner_position, angle );
// Rotate according to module orientation
corner_position += PadShapePos; // Shift origin to position
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.Append( polypoint );
}
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
{
corner_position = wxPoint( -rounding_radius, 0 );
RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) );
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
corner_position -= wxPoint( psize.x / 2, -psize.y / 2 );
RotatePoint( &corner_position, angle );
corner_position += PadShapePos;
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.Append( polypoint );
}
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) // We are using ClipperLib to inflate the polygon shape, using
{ // arcs to connect moved segments.
corner_position = wxPoint( 0, rounding_radius ); ClipperLib::Path outline;
RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); ClipperLib::Paths shapeWithClearance;
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
corner_position += psize / 2;
RotatePoint( &corner_position, angle );
corner_position += PadShapePos;
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.Append( polypoint );
}
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) for( int ii = 0; ii < 4; ii++ )
outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y );
ClipperLib::ClipperOffset offset_engine;
// Prepare an offset (inflate) transform, with edges connected by arcs
offset_engine.AddPath( outline, ClipperLib::jtRound, ClipperLib::etClosedPolygon );
// Clipper approximates arcs by segments
// It uses a value called ArcTolerance which is the max error between the arc
// and segments created to approximate this arc
// the number of segm per circle is:
// n = PI / acos(1 - arc_tolerance / (arc radius))
// the arc radius is aClearanceValue
// because arc_tolerance is << aClearanceValue and aClearanceValue >= 0
// n = PI / (arc_tolerance / aClearanceValue )
offset_engine.ArcTolerance = (double)aClearanceValue / 3.14 / aCircleToSegmentsCount;
double rounding_radius = aClearanceValue * aCorrectionFactor;
offset_engine.Execute( shapeWithClearance, rounding_radius );
// get new outline (only one polygon is expected)
// For info, ClipperLib uses long long to handle integer coordinates
ClipperLib::Path& polygon = shapeWithClearance[0];
for( unsigned jj = 0; jj < polygon.size(); jj++ )
{ {
corner_position = wxPoint( rounding_radius, 0 ); corner_position.x = int( polygon[jj].X );
RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) ); corner_position.y = int( polygon[jj].Y );
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
corner_position -= wxPoint( -psize.x / 2, psize.y / 2 );
RotatePoint( &corner_position, angle );
corner_position += PadShapePos; corner_position += PadShapePos;
CPolyPt polypoint( corner_position.x, corner_position.y ); CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.Append( polypoint ); aCornerBuffer.Append( polypoint );
} }
aCornerBuffer.CloseLastContour(); aCornerBuffer.CloseLastContour();
}
break; break;
} }
} }
...@@ -1090,9 +1060,89 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer, ...@@ -1090,9 +1060,89 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
aCornerBuffer.CloseLastContour(); aCornerBuffer.CloseLastContour();
angle = AddAngles( angle, 1800 ); angle = AddAngles( angle, 1800 );
} }
}
break;
case PAD_TRAPEZOID:
{
CPOLYGONS_LIST cbuffer;
// We need a length to build the stubs of the thermal reliefs
// the value is not very important. The pad bounding box gives a reasonable value
EDA_RECT bbox = aPad.GetBoundingBox();
int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() );
aPad.TransformShapeWithClearanceToPolygon( cbuffer, aThermalGap,
aCircleToSegmentsCount, aCorrectionFactor );
// We are using ClipperLib to substract stubs to clearance area (antipad area).
ClipperLib::Path antipad; // The full antipad area
ClipperLib::Path stub; // A basic stub ( a rectangle)
ClipperLib::Paths stubs; // the full stubs shape
ClipperLib::Paths thermalShape; // the holes in copper zone
// cbuffer is expected to contain only one polygon, which is
// area of the pad + the thermal gap (the antipad)
for( unsigned ii = 0; ii < cbuffer.GetCornersCount(); ii++ )
antipad << ClipperLib::IntPoint( cbuffer.GetPos(ii).x, cbuffer.GetPos(ii).y );
// We now substract the stubs (connections to the copper zone)
ClipperLib::Clipper clip_engine;
// Prepare a clipping transform
clip_engine.AddPath( antipad, ClipperLib::ptSubject, true );
// Create stubs and add them to clipper engine
wxPoint stubBuffer[4];
stubBuffer[0].x = stub_len;
stubBuffer[0].y = copper_thickness.y/2;
stubBuffer[1] = stubBuffer[0];
stubBuffer[1].y = -copper_thickness.y/2;
stubBuffer[2] = stubBuffer[1];
stubBuffer[2].x = -stub_len;
stubBuffer[3] = stubBuffer[2];
stubBuffer[3].y = copper_thickness.y/2;
for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
{
wxPoint cpos = stubBuffer[ii];
RotatePoint( &cpos, aPad.GetOrientation() );
cpos += PadShapePos;
stub << ClipperLib::IntPoint( cpos.x, cpos.y );
} }
ClipperLib::Clipper stubs_engine;
stubs_engine.AddPath( stub, ClipperLib::ptSubject, true );
stubBuffer[0].y = stub_len;
stubBuffer[0].x = copper_thickness.x/2;
stubBuffer[1] = stubBuffer[0];
stubBuffer[1].x = -copper_thickness.x/2;
stubBuffer[2] = stubBuffer[1];
stubBuffer[2].y = -stub_len;
stubBuffer[3] = stubBuffer[2];
stubBuffer[3].x = copper_thickness.x/2;
stub.clear();
for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
{
wxPoint cpos = stubBuffer[ii];
RotatePoint( &cpos, aPad.GetOrientation() );
cpos += PadShapePos;
stub << ClipperLib::IntPoint( cpos.x, cpos.y );
}
stubs_engine.AddPath( stub, ClipperLib::ptClip, true );
// Build the full stubs shape:
stubs_engine.Execute( ClipperLib::ctUnion, stubs );
// remove stubs to antipad area (i.e. add copper stubs)
clip_engine.AddPath( stubs[0], ClipperLib::ptClip, true );
clip_engine.Execute( ClipperLib::ctDifference, thermalShape );
// put thermal shapes (holes) to list:
aCornerBuffer.ImportFrom( thermalShape );
break; break;
}
default: default:
; ;
......
...@@ -1214,9 +1214,11 @@ NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const ...@@ -1214,9 +1214,11 @@ NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const
// the first valid netcode is 1 and the last is m_NetInfo.GetCount()-1. // the first valid netcode is 1 and the last is m_NetInfo.GetCount()-1.
// zero is reserved for "no connection" and is not used. // zero is reserved for "no connection" and is not used.
// NULL is returned for non valid netcodes // NULL is returned for non valid netcodes
NETINFO_ITEM* net = m_NetInfo.GetNetItem( aNetcode );
return net; if( aNetcode == NETINFO_LIST::UNCONNECTED )
return &NETINFO_LIST::ORPHANED;
else
return m_NetInfo.GetNetItem( aNetcode );
} }
......
...@@ -38,8 +38,6 @@ BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ...@@ -38,8 +38,6 @@ BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype
BOARD_ITEM( aParent, idtype ), m_netinfo( &NETINFO_LIST::ORPHANED ), BOARD_ITEM( aParent, idtype ), m_netinfo( &NETINFO_LIST::ORPHANED ),
m_Subnet( 0 ), m_ZoneSubnet( 0 ) m_Subnet( 0 ), m_ZoneSubnet( 0 )
{ {
// The unconnected net is set only in case the item belongs to a BOARD
SetNetCode( NETINFO_LIST::UNCONNECTED );
} }
...@@ -52,20 +50,15 @@ BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( const BOARD_CONNECTED_ITEM& aItem ) ...@@ -52,20 +50,15 @@ BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( const BOARD_CONNECTED_ITEM& aItem )
void BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode ) void BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode )
{ {
assert( aNetCode >= 0 );
BOARD* board = GetBoard(); BOARD* board = GetBoard();
if( board ) if( board )
{
m_netinfo = board->FindNet( aNetCode ); m_netinfo = board->FindNet( aNetCode );
// The requested net does not exist, mark it as unconnected
if( m_netinfo == NULL )
m_netinfo = board->FindNet( NETINFO_LIST::UNCONNECTED );
}
else else
{
// There is no board that contains list of nets, the item is orphaned
m_netinfo = &NETINFO_LIST::ORPHANED; m_netinfo = &NETINFO_LIST::ORPHANED;
}
assert( m_netinfo );
} }
......
...@@ -277,9 +277,10 @@ public: ...@@ -277,9 +277,10 @@ public:
/** /**
* Function BuildFilledSolidAreasPolygons * Function BuildFilledSolidAreasPolygons
* Build the filled solid areas data from real outlines (stored in m_Poly) * Build the filled solid areas data from real outlines (stored in m_Poly)
* The solid areas can be more thna one on copper layers, and do not have holes * The solid areas can be more than one on copper layers, and do not have holes
( holes are linked by overlapping segments to the main outline) ( holes are linked by overlapping segments to the main outline)
* in order to have drawable (and plottable) filled polygons * in order to have drawable (and plottable) filled polygons
* @return true if OK, false if the solid polygons cannot be built
* @param aPcb: the current board (can be NULL for non copper zones) * @param aPcb: the current board (can be NULL for non copper zones)
* @param aCornerBuffer: A reference to a buffer to store polygon corners, or NULL * @param aCornerBuffer: A reference to a buffer to store polygon corners, or NULL
* if NULL (default: * if NULL (default:
...@@ -287,13 +288,14 @@ public: ...@@ -287,13 +288,14 @@ public:
* - on copper layers, tracks and other items shapes of other nets are * - on copper layers, tracks and other items shapes of other nets are
* removed from solid areas * removed from solid areas
* if not null: * if not null:
* Only the zone outline (with holes, if any) are stored in aCornerBuffer * Only the zone outline (with holes, if any) is stored in aOutlineBuffer
* with holes linked. Therfore only one polygon is created * with holes linked. Therefore only one polygon is created
* @return true if OK, false if the solid areas cannot be calculated *
* This function calls AddClearanceAreasPolygonsToPolysList() * When aOutlineBuffer is not null, his function calls
* to add holes for pads and tracks and other items not in net. * AddClearanceAreasPolygonsToPolysList() to add holes for pads and tracks
* and other items not in net.
*/ */
bool BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aCornerBuffer = NULL ); bool BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aOutlineBuffer = NULL );
/** /**
* Function CopyPolygonsFromKiPolygonListToFilledPolysList * Function CopyPolygonsFromKiPolygonListToFilledPolysList
......
...@@ -127,15 +127,20 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) ...@@ -127,15 +127,20 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad )
case PAD_CONN: case PAD_CONN:
{ {
LSET lmsk = aPad->GetLayerSet(); LSET lmsk = aPad->GetLayerSet();
bool is_copper = false;
for( int i = 0; i < MAX_CU_LAYERS; i++ ) for( int i = 0; i < MAX_CU_LAYERS; i++ )
{ {
if( lmsk[i] ) if( lmsk[i] )
{ {
is_copper = true;
layers = PNS_LAYERSET( i ); layers = PNS_LAYERSET( i );
break; break;
} }
} }
if( !is_copper )
return NULL;
} }
break; break;
...@@ -693,7 +698,7 @@ void PNS_ROUTER::CommitRouting( PNS_NODE* aNode ) ...@@ -693,7 +698,7 @@ void PNS_ROUTER::CommitRouting( PNS_NODE* aNode )
track->SetEnd( wxPoint( s.B.x, s.B.y ) ); track->SetEnd( wxPoint( s.B.x, s.B.y ) );
track->SetWidth( seg->Width() ); track->SetWidth( seg->Width() );
track->SetLayer( ToLAYER_ID( seg->Layers().Start() ) ); track->SetLayer( ToLAYER_ID( seg->Layers().Start() ) );
track->SetNetCode( seg->Net() ); track->SetNetCode( seg->Net() > 0 ? seg->Net() : 0 );
newBI = track; newBI = track;
break; break;
} }
...@@ -705,7 +710,7 @@ void PNS_ROUTER::CommitRouting( PNS_NODE* aNode ) ...@@ -705,7 +710,7 @@ void PNS_ROUTER::CommitRouting( PNS_NODE* aNode )
via_board->SetPosition( wxPoint( via->Pos().x, via->Pos().y ) ); via_board->SetPosition( wxPoint( via->Pos().x, via->Pos().y ) );
via_board->SetWidth( via->Diameter() ); via_board->SetWidth( via->Diameter() );
via_board->SetDrill( via->Drill() ); via_board->SetDrill( via->Drill() );
via_board->SetNetCode( via->Net() ); via_board->SetNetCode( via->Net() > 0 ? via->Net() : 0 );
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair() via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ), via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ),
ToLAYER_ID( via->Layers().End() ) ); ToLAYER_ID( via->Layers().End() ) );
......
...@@ -43,22 +43,19 @@ ...@@ -43,22 +43,19 @@
( holes are linked by overlapping segments to the main outline) ( holes are linked by overlapping segments to the main outline)
* aPcb: the current board (can be NULL for non copper zones) * aPcb: the current board (can be NULL for non copper zones)
* aCornerBuffer: A reference to a buffer to store polygon corners, or NULL * aCornerBuffer: A reference to a buffer to store polygon corners, or NULL
* if NULL: * if aCornerBuffer == NULL:
* - m_FilledPolysList is used to store solid areas polygons. * - m_FilledPolysList is used to store solid areas polygons.
* - on copper layers, tracks and other items shapes of other nets are * - on copper layers, tracks and other items shapes of other nets are
* removed from solid areas * removed from solid areas
* if not null: * if not null:
* Only the zone outline (with holes, if any) are stored in aCornerBuffer * Only the zone outline (with holes, if any) are stored in aCornerBuffer
* with holes linked. Therfore only one polygon is created * with holes linked. Therefore only one polygon is created
* This function calls AddClearanceAreasPolygonsToPolysList() * This function calls AddClearanceAreasPolygonsToPolysList()
* to add holes for pads and tracks and other items not in net. * to add holes for pads and tracks and other items not in net.
*/ */
bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aCornerBuffer ) bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aOutlineBuffer )
{ {
if( aCornerBuffer == NULL )
m_FilledPolysList.RemoveAllContours();
/* convert outlines + holes to outlines without holes (adding extra segments if necessary) /* convert outlines + holes to outlines without holes (adding extra segments if necessary)
* m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
* this zone * this zone
...@@ -90,47 +87,33 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* ...@@ -90,47 +87,33 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST*
break; break;
} }
if( aCornerBuffer ) if( aOutlineBuffer )
ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, *aCornerBuffer ); aOutlineBuffer->Append( m_smoothedPoly->m_CornersList );
else
ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, m_FilledPolysList );
/* For copper layers, we now must add holes in the Polygon list. /* For copper layers, we now must add holes in the Polygon list.
* holes are pads and tracks with their clearance area * holes are pads and tracks with their clearance area
* for non copper layers just recalculate the m_FilledPolysList * for non copper layers just recalculate the m_FilledPolysList
* with m_ZoneMinThickness taken in account * with m_ZoneMinThickness taken in account
*/ */
if( !aCornerBuffer ) else
{ {
m_FilledPolysList.RemoveAllContours();
if( IsOnCopperLayer() ) if( IsOnCopperLayer() )
AddClearanceAreasPolygonsToPolysList( aPcb ); AddClearanceAreasPolygonsToPolysList( aPcb );
else else
{ {
// This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2
KI_POLYGON_SET polyset_zone_solid_areas;
int margin = m_ZoneMinThickness / 2; int margin = m_ZoneMinThickness / 2;
m_smoothedPoly->m_CornersList.InflateOutline(m_FilledPolysList, margin, true );
/* First, creates the main polygon (i.e. the filled area using only one outline)
* to reserve a m_ZoneMinThickness/2 margin around the outlines and holes
* this margin is the room to redraw outlines with segments having a width set to
* m_ZoneMinThickness
* so m_ZoneMinThickness is the min thickness of the filled zones areas
* the polygon is stored in polyset_zone_solid_areas
*/
CopyPolygonsFromFilledPolysListToKiPolygonList( polyset_zone_solid_areas );
polyset_zone_solid_areas -= margin;
// put solid area in m_FilledPolysList:
m_FilledPolysList.RemoveAllContours();
CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas );
} }
if( m_FillMode ) // if fill mode uses segments, create them: if( m_FillMode ) // if fill mode uses segments, create them:
FillZoneAreasWithSegments(); FillZoneAreasWithSegments();
}
m_IsFilled = true; m_IsFilled = true;
}
return 1; return true;
} }
......
...@@ -138,6 +138,11 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) ...@@ -138,6 +138,11 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
*/ */
s_Correction = 1.0 / cos( M_PI / s_CircleToSegmentsCount ); s_Correction = 1.0 / cos( M_PI / s_CircleToSegmentsCount );
// this is a place to store holes (i.e. tracks, pads ... areas as polygons outlines)
// static to avoid unnecessary memory allocation when filling many zones.
static CPOLYGONS_LIST cornerBufferPolysToSubstract;
cornerBufferPolysToSubstract.RemoveAllContours();
// This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2 // This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2
KI_POLYGON_SET polyset_zone_solid_areas; KI_POLYGON_SET polyset_zone_solid_areas;
int margin = m_ZoneMinThickness / 2; int margin = m_ZoneMinThickness / 2;
...@@ -149,13 +154,35 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) ...@@ -149,13 +154,35 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
* so m_ZoneMinThickness is the min thickness of the filled zones areas * so m_ZoneMinThickness is the min thickness of the filled zones areas
* the main polygon is stored in polyset_zone_solid_areas * the main polygon is stored in polyset_zone_solid_areas
*/ */
#if 1
CopyPolygonsFromFilledPolysListToKiPolygonList( polyset_zone_solid_areas ); m_smoothedPoly->m_CornersList.ExportTo( polyset_zone_solid_areas );
polyset_zone_solid_areas -= margin;
if( polyset_zone_solid_areas.size() == 0 ) if( polyset_zone_solid_areas.size() == 0 )
return; return;
// Extract holes (cutout areas) and add them to the hole buffer
KI_POLYGON_SET outlineHoles;
while( polyset_zone_solid_areas.size() > 1 )
{
outlineHoles.push_back( polyset_zone_solid_areas.back() );
polyset_zone_solid_areas.pop_back();
}
// deflate main outline reserve room for thick outline
polyset_zone_solid_areas -= margin;
// inflate outline holes
if( outlineHoles.size() )
outlineHoles += margin;
if( outlineHoles.size() )
cornerBufferPolysToSubstract.ImportFrom( outlineHoles );
#else
CPOLYGONS_LIST tmp;
m_smoothedPoly->m_CornersList.InflateOutline( tmp, -margin, true );
tmp.ExportTo( polyset_zone_solid_areas );
#endif
/* Calculates the clearance value that meet DRC requirements /* Calculates the clearance value that meet DRC requirements
* from m_ZoneClearance and clearance from the corresponding netclass * from m_ZoneClearance and clearance from the corresponding netclass
* We have a "local" clearance in zones because most of time * We have a "local" clearance in zones because most of time
...@@ -186,10 +213,6 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) ...@@ -186,10 +213,6 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
*/ */
int item_clearance; int item_clearance;
// static to avoid unnecessary memory allocation when filling many zones.
static CPOLYGONS_LIST cornerBufferPolysToSubstract;
cornerBufferPolysToSubstract.RemoveAllContours();
/* Use a dummy pad to calculate hole clerance when a pad is not on all copper layers /* Use a dummy pad to calculate hole clerance when a pad is not on all copper layers
* and this pad has a hole * and this pad has a hole
* This dummy pad has the size and shape of the hole * This dummy pad has the size and shape of the hole
...@@ -249,11 +272,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) ...@@ -249,11 +272,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
continue; continue;
} }
if( ( GetPadConnection( pad ) == PAD_NOT_IN_ZONE ) if( GetPadConnection( pad ) == PAD_NOT_IN_ZONE )
|| ( pad->GetShape() == PAD_TRAPEZOID ) )
// PAD_TRAPEZOID shapes are not in zones because they are used in microwave apps
// and i think it is good that shapes are not changed by thermal pads or others
{ {
int gap = zone_clearance; int gap = zone_clearance;
int thermalGap = GetThermalReliefGap( pad ); int thermalGap = GetThermalReliefGap( pad );
......
...@@ -51,12 +51,13 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( ...@@ -51,12 +51,13 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
CPOLYGONS_LIST& aCornerBuffer, CPOLYGONS_LIST& aCornerBuffer,
int aClearanceValue, bool aAddClearance ) int aClearanceValue, bool aAddClearance )
{ {
// Creates the zone outlines polygon (with linked holes if any) // Creates the zone outline polygon (with linked holes if any)
CPOLYGONS_LIST zoneOutines; CPOLYGONS_LIST zoneOutline;
BuildFilledSolidAreasPolygons( NULL, &zoneOutines ); BuildFilledSolidAreasPolygons( NULL, &zoneOutline );
// add clearance to outline // add clearance to outline
int clearance = 0; int clearance = 0;
if( aAddClearance ) if( aAddClearance )
{ {
clearance = GetClearance(); clearance = GetClearance();
...@@ -64,51 +65,11 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( ...@@ -64,51 +65,11 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
clearance = aClearanceValue; clearance = aClearanceValue;
} }
// Calculate the polygon with clearance // Calculate the polygon with clearance
// holes are linked to the main outline, so only one polygon should be created. // holes are linked to the main outline, so only one polygon is created.
KI_POLYGON_SET polyset_zone_solid_areas; if( clearance )
std::vector<KI_POLY_POINT> cornerslist; zoneOutline.InflateOutline( aCornerBuffer, clearance, true );
unsigned ic = 0; else
unsigned corners_count = zoneOutines.GetCornersCount(); ConvertPolysListWithHolesToOnePolygon( zoneOutline, aCornerBuffer );
while( ic < corners_count )
{
cornerslist.clear();
KI_POLYGON poly;
{
for( ; ic < corners_count; ic++ )
{
CPolyPt* corner = &zoneOutines[ic];
cornerslist.push_back( KI_POLY_POINT( corner->x, corner->y ) );
if( corner->end_contour )
{
ic++;
break;
}
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
polyset_zone_solid_areas.push_back( poly );
}
}
polyset_zone_solid_areas += clearance;
// Put the resulting polygon in aCornerBuffer corners list
for( unsigned ii = 0; ii < polyset_zone_solid_areas.size(); ii++ )
{
KI_POLYGON& poly = polyset_zone_solid_areas[ii];
CPolyPt corner( 0, 0, false );
for( unsigned jj = 0; jj < poly.size(); jj++ )
{
KI_POLY_POINT point = *(poly.begin() + jj);
corner.x = point.x();
corner.y = point.y();
corner.end_contour = false;
aCornerBuffer.Append( corner );
}
aCornerBuffer.CloseLastContour();
}
} }
......
...@@ -1347,6 +1347,44 @@ void CPOLYGONS_LIST::ExportTo( KI_POLYGON_SET& aPolygons ) const ...@@ -1347,6 +1347,44 @@ void CPOLYGONS_LIST::ExportTo( KI_POLYGON_SET& aPolygons ) const
} }
} }
/*
* Copy all contours to a ClipperLib::Paths& aPolygons
* Each contour is copied into a ClipperLib::Path, and each ClipperLib::Path
* is append to aPolygons
*/
void CPOLYGONS_LIST::ExportTo( ClipperLib::Paths& aPolygons ) const
{
unsigned corners_count = GetCornersCount();
// Count the number of polygons in aCornersBuffer
int polycount = 0;
for( unsigned ii = 0; ii < corners_count; ii++ )
{
if( IsEndContour( ii ) )
polycount++;
}
aPolygons.reserve( polycount );
for( unsigned icnt = 0; icnt < corners_count; )
{
ClipperLib::Path poly;
unsigned ii;
for( ii = icnt; ii < corners_count; ii++ )
{
poly << ClipperLib::IntPoint( GetX( ii ), GetY( ii ) );
if( IsEndContour( ii ) )
break;
}
aPolygons.push_back( poly );
icnt = ii + 1;
}
}
/* Imports all polygons found in a KI_POLYGON_SET in list /* Imports all polygons found in a KI_POLYGON_SET in list
*/ */
...@@ -1372,6 +1410,72 @@ void CPOLYGONS_LIST::ImportFrom( KI_POLYGON_SET& aPolygons ) ...@@ -1372,6 +1410,72 @@ void CPOLYGONS_LIST::ImportFrom( KI_POLYGON_SET& aPolygons )
} }
/* Imports all polygons found in a ClipperLib::Paths in list
*/
void CPOLYGONS_LIST::ImportFrom( ClipperLib::Paths& aPolygons )
{
CPolyPt corner;
for( unsigned ii = 0; ii < aPolygons.size(); ii++ )
{
ClipperLib::Path& polygon = aPolygons[ii];
for( unsigned jj = 0; jj < polygon.size(); jj++ )
{
corner.x = int( polygon[jj].X );
corner.y = int( polygon[jj].Y );
corner.end_contour = false;
AddCorner( corner );
}
CloseLastContour();
}
}
/* Inflate the outline stored in m_cornersList.
* The first polygon is the external outline. It is inflated
* The other polygons are holes. they are deflated
* aResult = the Inflated outline
* aInflateValue = the Inflate value. when < 0, this is a deflate transform
* aLinkHoles = if true, aResult contains only one polygon,
* with holes linked by overlapping segments
*/
void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles )
{
KI_POLYGON_SET polyset_outline;
ExportTo( polyset_outline );
// Extract holes (cutout areas) and add them to the hole buffer
KI_POLYGON_SET outlineHoles;
while( polyset_outline.size() > 1 )
{
outlineHoles.push_back( polyset_outline.back() );
polyset_outline.pop_back();
}
// inflate main outline
if( polyset_outline.size() )
polyset_outline += aInflateValue;
// deflate outline holes
if( outlineHoles.size() )
outlineHoles -= aInflateValue;
// Copy modified polygons
if( !aLinkHoles )
{
aResult.ImportFrom( polyset_outline );
if( outlineHoles.size() )
aResult.ImportFrom( outlineHoles );
}
else
{
polyset_outline -= outlineHoles;
aResult.ImportFrom( polyset_outline );
}
}
/** /**
* Function ConvertPolysListWithHolesToOnePolygon * Function ConvertPolysListWithHolesToOnePolygon
...@@ -1438,26 +1542,14 @@ void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWith ...@@ -1438,26 +1542,14 @@ void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWith
polysholes.push_back( poly_tmp ); polysholes.push_back( poly_tmp );
} }
} }
mainpoly -= polysholes; mainpoly -= polysholes;
// copy polygon with no holes to destination // copy polygon with no holes to destination
// Because all holes are now linked to the main outline // Because all holes are now linked to the main outline
// by overlapping segments, we should have only one polygon in list // by overlapping segments, we should have only one polygon in list
wxASSERT( mainpoly.size() == 1 ); wxASSERT( mainpoly.size() == 1 );
aOnePolyList.ImportFrom( mainpoly );
KI_POLYGON& poly_nohole = mainpoly[0];
CPolyPt corner( 0, 0, false );
for( unsigned jj = 0; jj < poly_nohole.size(); jj++ )
{
KI_POLY_POINT point = *(poly_nohole.begin() + jj);
corner.x = point.x();
corner.y = point.y();
corner.end_contour = false;
aOnePolyList.AddCorner( corner );
}
aOnePolyList.CloseLastContour();
} }
/** /**
...@@ -1553,3 +1645,22 @@ bool CPolyLine::IsPolygonSelfIntersecting() ...@@ -1553,3 +1645,22 @@ bool CPolyLine::IsPolygonSelfIntersecting()
return false; return false;
} }
/* converts the outline aOnePolyList (only one contour,
* holes are linked by overlapping segments) to
* to one main polygon and holes (polygons inside main polygon)
* aOnePolyList = a only one polygon ( holes are linked )
* aPolysListWithHoles = the list of corners of contours
* (main outline and holes)
*/
void ConvertOnePolygonToPolysListWithHoles( const CPOLYGONS_LIST& aOnePolyList,
CPOLYGONS_LIST& aPolysListWithHoles )
{
ClipperLib::Paths initialPoly;
ClipperLib::Paths modifiedPoly;
aOnePolyList.ExportTo( initialPoly );
SimplifyPolygon(initialPoly[0], modifiedPoly );
aPolysListWithHoles.ImportFrom( modifiedPoly );
}
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <layers_id_colors_and_visibility.h> // for LAYER_NUM definition #include <layers_id_colors_and_visibility.h> // for LAYER_NUM definition
#include <class_eda_rect.h> // for EDA_RECT definition #include <class_eda_rect.h> // for EDA_RECT definition
#include <polygons_defs.h> #include <polygons_defs.h>
#include <clipper.hpp>
class CSegment class CSegment
{ {
...@@ -186,10 +187,30 @@ public: ...@@ -186,10 +187,30 @@ public:
m_cornersList.insert( m_cornersList.begin() + aPosition + 1, aItem ); m_cornersList.insert( m_cornersList.begin() + aPosition + 1, aItem );
} }
/**
* function AddCorner
* add a corner to the list
*/
void AddCorner( const CPolyPt& aCorner )
{
m_cornersList.push_back( aCorner );
}
/**
* function CloseLastContour
* Set the .end_contour member of the last corner in list to true
*/
void CloseLastContour()
{
if( m_cornersList.size() > 0 )
m_cornersList.back().end_contour = true;
}
/** /**
* Function ExportTo * Function ExportTo
* Copy all contours to a KI_POLYGON_SET * Copy all contours to a KI_POLYGON_SET, each contour is exported
* @param aPolygons = the KI_POLYGON_WITH_HOLES to populate * to a KI_POLYGON
* @param aPolygons = the KI_POLYGON_SET to populate
*/ */
void ExportTo( KI_POLYGON_SET& aPolygons ) const; void ExportTo( KI_POLYGON_SET& aPolygons ) const;
...@@ -201,6 +222,14 @@ public: ...@@ -201,6 +222,14 @@ public:
*/ */
void ExportTo( KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) const; void ExportTo( KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) const;
/**
* Function ExportTo
* Copy all contours to a ClipperLib::Paths, each contour is exported
* to a ClipperLib::Path
* @param aPolygons = the ClipperLib::Paths to populate
*/
void ExportTo( ClipperLib::Paths& aPolygons ) const;
/** /**
* Function ImportFrom * Function ImportFrom
* Copy all polygons from a KI_POLYGON_SET in list * Copy all polygons from a KI_POLYGON_SET in list
...@@ -209,23 +238,23 @@ public: ...@@ -209,23 +238,23 @@ public:
void ImportFrom( KI_POLYGON_SET& aPolygons ); void ImportFrom( KI_POLYGON_SET& aPolygons );
/** /**
* function AddCorner * Function ImportFrom
* add a corner to the list * Copy all polygons from a ClipperLib::Paths in list
* @param aPolygons = the ClipperLib::Paths to import
*/ */
void AddCorner( const CPolyPt& aCorner ) void ImportFrom( ClipperLib::Paths& aPolygons );
{
m_cornersList.push_back( aCorner );
}
/** /**
* function CloseLastContour * Function InflateOutline
* Set the .end_contour member of the last corner in list to true * Inflate the outline stored in m_cornersList.
* The first polygon is the external outline. It is inflated
* The other polygons are holes. they are deflated
* @param aResult = the Inflated outline
* @param aInflateValue = the Inflate value. when < 0, this is a deflate transform
* @param aLinkHoles = if true, aResult contains only one polygon,
* with holes linked by overlapping segments
*/ */
void CloseLastContour() void InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles );
{
if( m_cornersList.size() > 0 )
m_cornersList.back().end_contour = true;
}
}; };
class CPolyLine class CPolyLine
...@@ -489,4 +518,17 @@ public: ...@@ -489,4 +518,17 @@ public:
void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWithHoles, void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWithHoles,
CPOLYGONS_LIST& aOnePolyList ); CPOLYGONS_LIST& aOnePolyList );
/**
* Function ConvertOnePolygonToPolysListWithHoles
* converts the outline aOnePolyList (only one contour,
* holes are linked by overlapping segments) to
* to one main polygon and holes (polygons inside main polygon)
* @param aOnePolyList = a polygon with no holes
* @param aPolysListWithHoles = the list of corners of contours
* (main outline and holes)
*/
void ConvertOnePolygonToPolysListWithHoles( const CPOLYGONS_LIST& aOnePolyList,
CPOLYGONS_LIST& aPolysListWithHoles );
#endif // #ifndef POLYLINE_H #endif // #ifndef POLYLINE_H
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
# $1 wxWidgets/wxPython source folder (relative to current dir) # $1 wxWidgets/wxPython source folder (relative to current dir)
# $2 Target bin folder # $2 Target bin folder
# $3 KiCad source folder (relative to current dir) # $3 KiCad source folder (relative to current dir)
# $4 Make options (e.g., "-j4") # $4 OSX target version (e.g., "10.8")
# $5 Extra make options (e.g., "-j4")
createPaths() { createPaths() {
echo "*** Creating/wiping build and bin folder..." echo "*** Creating/wiping build and bin folder..."
...@@ -59,10 +60,8 @@ wxWidgets_configure() { ...@@ -59,10 +60,8 @@ wxWidgets_configure() {
--with-zlib=builtin \ --with-zlib=builtin \
--with-expat=builtin \ --with-expat=builtin \
--without-liblzma \ --without-liblzma \
--with-macosx-version-min=10.5 \ --with-macosx-version-min=$3 \
--enable-universal-binary=i386,x86_64 \ --enable-universal-binary=i386,x86_64 \
CPPFLAGS="-stdlib=libstdc++" \
LDFLAGS="-stdlib=libstdc++" \
CC=clang \ CC=clang \
CXX=clang++ CXX=clang++
if [ $? -ne 0 ]; if [ $? -ne 0 ];
...@@ -119,16 +118,17 @@ wxPython_buildInst() { ...@@ -119,16 +118,17 @@ wxPython_buildInst() {
# check parameters # check parameters
if [ "$#" -lt 3 ]; if [ "$#" -lt 4 ];
then then
echo "OSX wxWidgets/wxPython build script" echo "OSX wxWidgets/wxPython build script"
echo echo
echo "Usage:" echo "Usage:"
echo " osx_build_wx.sh <src> <bin> <kicad> <makeopts>" echo " osx_build_wx.sh <src> <bin> <kicad> <osxtarget> [makeopts]"
echo " <src> wxWidgets/wxPython source folder" echo " <src> wxWidgets/wxPython source folder"
echo " <bin> Destination folder" echo " <bin> Destination folder"
echo " <kicad> KiCad folder" echo " <kicad> KiCad folder"
echo " <makeopts> Optional: make options for building wxWidgets (e.g., -j4)" echo " <osxtarget> OSX target (e.g., 10.7)"
echo " [makeopts] Optional: make options for building wxWidgets (e.g., -j4)"
exit 1 exit 1
fi fi
...@@ -142,8 +142,8 @@ doPatch "$1" "$3/patches/wxwidgets-3.0.0_macosx_bug_15908.patch" ...@@ -142,8 +142,8 @@ doPatch "$1" "$3/patches/wxwidgets-3.0.0_macosx_bug_15908.patch"
doPatch "$1" "$3/patches/wxwidgets-3.0.0_macosx_soname.patch" doPatch "$1" "$3/patches/wxwidgets-3.0.0_macosx_soname.patch"
# configure and build wxWidgets # configure and build wxWidgets
wxWidgets_configure "$1" "$2" wxWidgets_configure "$1" "$2" "$4"
wxWidgets_buildInst "$4" wxWidgets_buildInst "$5"
# check if source is wxPython # check if source is wxPython
if [ -d $1/wxPython ]; if [ -d $1/wxPython ];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment