Merge trunk @ 5308

This commit is contained in:
Garth Corral 2014-11-30 10:35:24 -08:00
commit 0cf91f466f
48 changed files with 1303 additions and 395 deletions

View File

@ -226,8 +226,8 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
if( APPLE )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__ASSERTMACROS__ -mmacosx-version-min=10.5" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_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__" )
# Allows .dylib relocation in the future - needed by fixbundle
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" )
EXEC_PROGRAM( wx-config ARGS --cxx OUTPUT_VARIABLE CMAKE_CXX_COMPILER )
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( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )

View File

@ -140,11 +140,8 @@ endif()
if( APPLE )
# I set this to being compatible with wxWidgets
# wxWidgets still using libstdc++ (gcc), meanwhile OSX
# 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_CXXFLAGS "cxxflags=-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -fno-common" )
set( BOOST_LINKFLAGS "linkflags=-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -fno-common" )
set( BOOST_TOOLSET "toolset=darwin" )
if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )

View File

@ -1,9 +1,9 @@
Compiling KiCad on Apple Mac OS X
=================================
Building on OSX 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.
See general documentation on non-OSX specific KiCad build switches, etc.
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 OS X specific things.
See general documentation on non OS X specific KiCad build switches, etc.
Prerequisites
@ -24,6 +24,7 @@ Mandatory library dependencies needed to compile KiCad:
OR
wxPython - A blending of the wxWidgets C++ class library with the Python
programming language
* SWIG - Interface compiler (only needed for scripting/wxPython builds)
Optional library dependencies, depends on used KiCad features
* OpenSSL - The Open Source toolkit for SSL/TLS
@ -31,7 +32,7 @@ Optional library dependencies, depends on used KiCad features
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
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
dependencies may have to be installed (usually something like <pkg>-dev or
<pkg>-devel).
@ -44,7 +45,7 @@ automatically by KiCad build process.
IMPORTANT:
At the moment you *must not* use a wxWidgets/wxPython version installed by any
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.
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
@ -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
the patching/configuring/compiling of wxWidgets or wxPython for you.
Go to your working root "KiCad" and run:
# kicad/scripts/osx_build_wx.sh wx-src wx-bin kicad "-j4"
Go to your working root "KiCad" and for example run:
# 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
target folder for compiled binaries, third parameter is the kicad folder, and
the last optional parameter are make options used during the build (in this
case for building with 4 jobs in parallel).
target folder for compiled binaries, and third parameter is the kicad folder.
The fourth parameter is the minimum OS X version you are building for (see the
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.
NOTE: All paths are assumed to be relative to the current directory, i.e., the
working root you are in.
@ -137,10 +140,8 @@ work:
--with-zlib=builtin \
--with-expat=builtin \
--without-liblzma \
--with-macosx-version-min=10.5 \
--with-macosx-version-min=<osxtarget> \
--enable-universal-binary=i386,x86_64 \
CPPFLAGS="-stdlib=libstdc++" \
LDFLAGS="-stdlib=libstdc++" \
CC=clang \
CXX=clang++
If you know what you are doing, you can of course use different settings.
@ -157,6 +158,7 @@ Now, configure KiCad without scripting support:
# cmake ../kicad \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \
-DwxWidgets_CONFIG_EXECUTABLE=../wx-bin/bin/wx-config \
-DKICAD_SCRIPTING=OFF \
-DKICAD_SCRIPTING_MODULES=OFF \
@ -168,6 +170,7 @@ or, configure KiCad with scripting support:
# cmake ../kicad \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \
-DwxWidgets_CONFIG_EXECUTABLE=../wx-bin/bin/wx-config \
-DPYTHON_EXECUTABLE=`which python` \
-DPYTHON_SITE_PACKAGE_PATH=`pwd`/../wx-bin/lib/python2.7/site-packages \
@ -182,7 +185,19 @@ 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
`which python` (this one will just detect/use you default python).
Now KiCad is configured using default features/build-switches. To add Magic
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
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
available when compiling KiCad.

View File

@ -548,6 +548,9 @@ int EDA_BASE_FRAME::ReadHotkeyConfigFile( const wxString& aFilename,
{
wxFile cfgfile( aFilename );
if( !cfgfile.IsOpened() ) // There is a problem to open file
return 0;
// get length
cfgfile.SeekEnd();
wxFileOffset size = cfgfile.Tell();

View File

@ -86,7 +86,7 @@ public:
wxBoxSizer* m_RightBoxSizer;
wxBoxSizer* m_RightOptionsBoxSizer;
wxBoxSizer* m_LowBoxSizer;
wxRadioBox* m_NetOption;
private:
wxString m_pageNetFmtName;
@ -104,14 +104,12 @@ public:
/**
* function GetPageNetFmtName
* @return the name of the netlist format for this page
* This is usually 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
* This is also the page label.
*/
const wxString GetPageNetFmtName();
void SetPageNetFmtName( const wxString &aName ) { m_pageNetFmtName = aName; }
const wxString GetPageNetFmtName()
{
return m_pageNetFmtName;
}
};
@ -242,9 +240,6 @@ enum id_netlist {
#define NETLIST_USE_DEFAULT_NETNAME wxT( "NetlistUseDefaultNetname" )
#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 )
EVT_BUTTON( ID_CREATE_NETLIST, NETLIST_DIALOG::GenNetlist )
@ -269,23 +264,15 @@ NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent,
m_AddSubPrefix = NULL;
m_SpiceUseNetcodeAsNetname = NULL;
m_ButtonCancel = NULL;
m_NetOption = NULL;
wxString netfmtName = ((NETLIST_DIALOG*)parent->GetParent())->m_NetFmtName;
int fmtOption = 1; // Default Pcbnew netlist fmt is advanced fmt
bool selected = m_pageNetFmtName == netfmtName;
// PCBNEW Format is a special type:
if( id_NetType == NET_TYPE_PCBNEW )
{
if( netfmtName.IsEmpty() || netfmtName == NETLIST_PCBNEW_NEWFMT )
selected = true;
if( netfmtName == NETLIST_PCBNEW_LEGACY )
{
selected = true;
fmtOption = 0;
}
selected = true;
}
@ -312,34 +299,9 @@ NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent,
_( "Default format" ) );
m_LeftBoxSizer->Add( m_IsCurrentFormat, 0, wxGROW | wxALL, 5 );
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_BASE( parent )
@ -599,8 +561,7 @@ void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event )
break;
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;
case NET_TYPE_ORCADPCB2:

View File

@ -146,7 +146,7 @@ void SCH_EDIT_FRAME::ReCreateHToolbar()
HELP_ANNOTATE );
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 ),
_( "Generate netlist" ) );

View File

@ -40,6 +40,7 @@ set( GERBVIEW_SRCS
class_gerber_draw_item.cpp
class_gerbview_layer_widget.cpp
class_gbr_layer_box_selector.cpp
class_X2_gerber_attributes.cpp
controle.cpp
dcode.cpp
draw_gerber_screen.cpp

View File

@ -36,6 +36,9 @@
#include <gerbview.h>
#include <gerbview_frame.h>
#include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
#include <algorithm>
/**
@ -88,9 +91,10 @@ void GERBER_LAYER::ResetDefaultValues()
GERBER_IMAGE::GERBER_IMAGE( GERBVIEW_FRAME* aParent, int aLayer )
{
m_Parent = aParent;
m_GraphicLayer = aLayer; // Graphic layer Number
m_GraphicLayer = aLayer; // Graphic layer Number
m_Selected_Tool = FIRST_DCODE;
m_FileFunction = NULL; // file function parameters
ResetDefaultValues();
@ -104,9 +108,9 @@ GERBER_IMAGE::~GERBER_IMAGE()
for( unsigned ii = 0; ii < DIM( 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()
m_FileName.Empty();
m_ImageName = wxT( "no name" ); // Image name from the IN command
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_ImageJustifyOffset = wxPoint(0,0); // Image justify Offset
m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
@ -361,3 +370,171 @@ void GERBER_IMAGE::DisplayImageInfo( void )
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;

View File

@ -61,6 +61,7 @@ class D_CODE;
*/
class GERBER_IMAGE;
class X2_ATTRIBUTE_FILEFUNCTION;
class GERBER_LAYER
{
@ -104,6 +105,11 @@ public:
// (a file is loaded in it)
wxString m_FileName; // Full File Name for this layer
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
bool m_ImageNegative; // true = Negative image
bool m_ImageJustifyXCenter; // Image Justify Center on X axis (default = false)
@ -306,5 +312,67 @@ public:
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_

View File

@ -0,0 +1,253 @@
/*
* 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 files 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;
}
}

View File

@ -0,0 +1,171 @@
/*
* 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 files 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_

View File

@ -33,11 +33,14 @@
#include <colors_selection.h>
#include <layers_id_colors_and_visibility.h>
#include <gerbview_frame.h>
#include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
#include <class_gbr_layer_box_selector.h>
void GBR_LAYER_BOX_SELECTOR::Resync()
{
Freeze();
Clear();
for( int layerid = 0; layerid < GERBER_DRAWLAYERS_COUNT; ++layerid )
@ -55,6 +58,8 @@ void GBR_LAYER_BOX_SELECTOR::Resync()
Append( layername, layerbmp, (void*)(intptr_t) layerid );
}
Thaw();
}
@ -70,7 +75,7 @@ EDA_COLOR_T GBR_LAYER_BOX_SELECTOR::GetLayerColor( int aLayer ) const
// Returns the name of the layer id
wxString GBR_LAYER_BOX_SELECTOR::GetLayerName( int aLayer ) const
{
wxString name;
name.Printf( _( "Layer %d" ), aLayer + 1 );
wxString name = g_GERBER_List.GetDisplayName( aLayer );
return name;
}

View File

@ -39,7 +39,6 @@ GBR_LAYOUT::GBR_LAYOUT()
PAGE_INFO pageInfo( wxT( "GERBER" ) );
SetPageSettings( pageInfo );
// no m_printLayersMask = -1;
m_printLayersMask.set();
}

View File

@ -24,7 +24,8 @@
/**
* @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
@ -55,7 +56,7 @@ private:
std::bitset <GERBER_DRAWLAYERS_COUNT> m_printLayersMask; // When printing: the list of layers to print
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();

View File

@ -225,7 +225,9 @@ D_CODE* GERBER_DRAW_ITEM::GetDcodeDescr()
{
if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
return NULL;
GERBER_IMAGE* gerber = g_GERBER_List[m_Layer];
GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( m_Layer );
if( gerber == NULL )
return NULL;

View File

@ -1,7 +1,7 @@
/*
* 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 KiCad Developers, see change_log.txt for contributors.
*
@ -41,6 +41,7 @@
#include <class_GERBER.h>
#include <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
// since Popupmenu() calls this->ProcessEvent() we must call this->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,
wxCommandEventHandler( GERBER_LAYER_WIDGET::onPopupSelection ), NULL, this );
@ -146,8 +147,7 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event )
{
wxMenu menu;
// menu text is capitalized:
// http://library.gnome.org/devel/hig-book/2.20/design-text-labels.html.en#layout-capitalization
// Remember: menu text is capitalized (see our rules_for_capitalization_in_Kicad_UI.txt)
menu.Append( new wxMenuItem( &menu, ID_SHOW_ALL_LAYERS,
_("Show All Layers") ) );
@ -160,6 +160,9 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event )
menu.Append( new wxMenuItem( &menu, ID_SHOW_NO_LAYERS,
_( "Hide All Layers" ) ) );
menu.AppendSeparator();
menu.Append( new wxMenuItem( &menu, ID_SORT_GBR_LAYERS,
_( "Sort Layers if X2 Mode" ) ) );
PopupMenu( &menu );
passOnFocus();
@ -204,6 +207,13 @@ void GERBER_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event )
myframe->SetVisibleLayers( visibleLayers );
myframe->GetCanvas()->Refresh();
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()
if( !m_alwaysShowActiveLayer )
return false;
// postprocess after an active layer selection
// postprocess after active layer selection
// ensure active layer visible
wxCommandEvent event;
event.SetId( ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE );
@ -223,16 +233,20 @@ bool GERBER_LAYER_WIDGET::OnLayerSelected()
void GERBER_LAYER_WIDGET::ReFill()
{
Freeze();
ClearLayerRows();
for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
{
wxString msg;
msg.Printf( _("Layer %d"), layer+1 );
wxString msg = g_GERBER_List.GetDisplayName( layer );
AppendLayerRow( LAYER_WIDGET::ROW( msg, layer,
myframe->GetLayerColor( layer ), wxEmptyString, true ) );
}
Thaw();
installRightLayerClickHandler();
}
@ -298,17 +312,10 @@ void GERBER_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled )
*/
bool GERBER_LAYER_WIDGET::useAlternateBitmap(int aRow)
{
bool inUse = false;
GERBER_IMAGE* gerber = g_GERBER_List[aRow];
if( gerber != NULL && gerber->m_InUse )
inUse = true;
return inUse;
return g_GERBER_List.IsUsed( aRow );
}
/**
* Function UpdateLayerIcons
/*
* Update the layer manager icons (layers only)
* Useful when loading a file or clearing a layer because they change
*/
@ -322,7 +329,8 @@ void GERBER_LAYER_WIDGET::UpdateLayerIcons()
continue;
if( row == m_CurrentRow )
bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap : *m_RightArrowBitmap );
bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap :
*m_RightArrowBitmap );
else
bm->SetBitmap( useAlternateBitmap(row) ? *m_BlankAlternateBitmap : *m_BlankBitmap );
}

View File

@ -33,6 +33,18 @@
#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
* is here to implement the abtract functions of LAYER_WIDGET so they
@ -45,11 +57,6 @@ class GERBER_LAYER_WIDGET : public LAYER_WIDGET
bool m_alwaysShowActiveLayer; // If true: Only shows the current active layer
// 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

View File

@ -37,6 +37,7 @@
#include <gerbview.h>
#include <gerbview_frame.h>
#include <class_GERBER.h>
#include <pcbplot.h>
static double s_ScaleList[] =
@ -163,7 +164,7 @@ void DIALOG_PRINT_USING_PRINTER::InitValues( )
msg << wxT( " " ) << ii + 1;
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 );
if( ii < 16 )

View File

@ -214,14 +214,16 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
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();
if( layer == active_layer ) // active layer will be drawn after other layers
continue;
if( layer == GERBER_DRAWLAYERS_COUNT ) // last loop: draw active layer
if( layer < 0 ) // last loop: draw active layer
{
end = true;
layer = active_layer;
@ -230,7 +232,7 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
if( !gerbFrame->IsLayerVisible( layer ) )
continue;
GERBER_IMAGE* gerber = g_GERBER_List[layer];
GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
if( gerber == NULL ) // Graphic layer not yet used
continue;

View File

@ -234,7 +234,7 @@ void GERBVIEW_FRAME::Process_Special_Functions( 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 )
{
@ -266,7 +266,7 @@ void GERBVIEW_FRAME::OnSelectActiveLayer( wxCommandEvent& event )
void GERBVIEW_FRAME::OnShowGerberSourceFile( wxCommandEvent& event )
{
int layer = getActiveLayer();
GERBER_IMAGE* gerber_layer = g_GERBER_List[layer];
GERBER_IMAGE* gerber_layer = g_GERBER_List.GetGbrImage( layer );
if( gerber_layer )
{

View File

@ -8,8 +8,8 @@
/*
* 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-2011 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 1992-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
@ -75,6 +75,7 @@
#include <class_GERBER.h>
#include <class_excellon.h>
#include <kicad_string.h>
#include <class_X2_gerber_attributes.h>
#include <cmath>
@ -93,18 +94,24 @@ extern double ReadDouble( char*& text, bool aSkipSeparator = true );
extern void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
APERTURE_T aAperture,
int Dcode_index,
int aLayer,
int aLayer,
const wxPoint& aPos,
wxSize aSize,
bool aLayerNegative );
void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
int Dcode_index,
int aLayer,
int aLayer,
const wxPoint& aStart,
const wxPoint& aEnd,
wxSize aPenSize,
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[] =
{
{ "M0", DRILL_M_END, -1 }, // End of Program - No Rewind
@ -168,14 +175,21 @@ static EXCELLON_CMD excellon_G_CmdList[] =
bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
{
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( g_GERBER_List[layer] == NULL )
if( drill_Layer == NULL )
{
g_GERBER_List[layer] = new EXCELLON_IMAGE( this, layer );
drill_Layer = new EXCELLON_IMAGE( this, layerId );
layerId = g_GERBER_List.AddGbrImage( drill_Layer, layerId );
}
if( layerId < 0 )
{
DisplayError( this, _( "No room to load file" ) );
return false;
}
EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List[layer];
ClearMessageList();
/* Read the gerber file */
@ -183,7 +197,7 @@ bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
if( file == NULL )
{
msg.Printf( _( "File %s not found" ), GetChars( aFullFileName ) );
DisplayError( this, msg, 10 );
DisplayError( this, msg );
return false;
}
@ -213,7 +227,7 @@ bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile,
m_FileName = aFullFileName;
m_Current_File = aFile;
SetLocaleTo_C_standard();
LOCALE_IO toggleIo;
// FILE_LINE_READER will close the file.
if( m_Current_File == NULL )
@ -282,7 +296,16 @@ bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile,
} // 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;
}

View File

@ -39,6 +39,7 @@
#include <gerbview.h>
#include <gerbview_frame.h>
#include <class_gerber_draw_item.h>
#include <class_GERBER.h>
#include <select_layers_to_pcb.h>
#include <build_version.h>
#include <wildcards_and_files_ext.h>
@ -159,7 +160,7 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event )
// Count the Gerber layers which are actually currently used
for( LAYER_NUM ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
{
if( g_GERBER_List[ii] != NULL )
if( g_GERBER_List.GetGbrImage( ii ) )
layercount++;
}

View File

@ -84,6 +84,7 @@ void GERBVIEW_FRAME::Files_io( wxCommandEvent& event )
Zoom_Automatique( false );
m_canvas->Refresh();
ClearMsgPanel();
ReFillLayerWidget();
break;
case ID_GERBVIEW_LOAD_DRILL_FILE:
@ -200,6 +201,7 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName )
Zoom_Automatique( false );
// Synchronize layers tools with actual active layer:
ReFillLayerWidget();
setActiveLayer( getActiveLayer() );
m_LayersManager->UpdateLayerIcons();
syncLayerBox();
@ -282,6 +284,7 @@ bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFullFileName )
Zoom_Automatique( false );
// Synchronize layers tools with actual active layer:
ReFillLayerWidget();
setActiveLayer( getActiveLayer() );
m_LayersManager->UpdateLayerIcons();
syncLayerBox();

View File

@ -45,7 +45,6 @@
// Colors for layers and items
COLORS_DESIGN_SETTINGS g_ColorsSettings;
int g_Default_GERBER_Format;
const wxChar* g_GerberPageSizeList[] = {
@ -60,9 +59,6 @@ const wxChar* g_GerberPageSizeList[] = {
};
GERBER_IMAGE* g_GERBER_List[32];
namespace GERBV {
static struct IFACE : public KIFACE_I

View File

@ -109,6 +109,4 @@ enum Gerb_Analyse_Cmd
ENTER_RS274X_CMD
};
extern GERBER_IMAGE* g_GERBER_List[GERBER_DRAWLAYERS_COUNT];
#endif // ifndef GERBVIEW_H

View File

@ -348,7 +348,7 @@ int GERBVIEW_FRAME::getNextAvailableLayer( int aLayer ) const
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() )
return layer;
@ -378,9 +378,11 @@ void GERBVIEW_FRAME::syncLayerWidget()
*/
void GERBVIEW_FRAME::syncLayerBox()
{
m_SelLayerBox->Resync();
m_SelLayerBox->SetSelection( getActiveLayer() );
int dcodeSelected = -1;
GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer()];
GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
if( gerber )
dcodeSelected = gerber->m_Selected_Tool;
@ -406,7 +408,7 @@ void GERBVIEW_FRAME::Liste_D_Codes()
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 )
continue;
@ -474,7 +476,7 @@ void GERBVIEW_FRAME::Liste_D_Codes()
*/
void GERBVIEW_FRAME::UpdateTitleAndInfo()
{
GERBER_IMAGE* gerber = g_GERBER_List[ getActiveLayer() ];
GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
wxString text;
// Display the gerber filename
@ -491,6 +493,8 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo()
text = _( "File:" );
text << wxT( " " ) << gerber->m_FileName;
if( gerber->m_IsX2_file )
text << wxT( " " ) << _( "(with X2 Attributes)" );
SetTitle( text );
gerber->DisplayImageInfo();
@ -508,7 +512,13 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo()
gerber->m_FmtLen.y - gerber->m_FmtScale.y, gerber->m_FmtScale.y,
gerber->m_NoTrailingZeros ? 'T' : 'L' );
if( gerber->m_IsX2_file )
text << wxT(" ") << _( "X2 attr" );
m_TextInfo->SetValue( text );
if( EnsureTextCtrlWidth( m_TextInfo, &text ) ) // Resized
m_auimgr.Update();
}
/*

View File

@ -40,8 +40,6 @@
bool GERBVIEW_FRAME::Clear_DrawLayers( bool query )
{
int layer;
if( GetGerberLayout() == NULL )
return false;
@ -53,14 +51,7 @@ bool GERBVIEW_FRAME::Clear_DrawLayers( bool query )
GetGerberLayout()->m_Drawings.DeleteAll();
for( layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
{
if( g_GERBER_List[layer] )
{
g_GERBER_List[layer]->InitToolTable();
g_GERBER_List[layer]->ResetDefaultValues();
}
}
g_GERBER_List.ClearList();
GetGerberLayout()->SetBoundingBox( EDA_RECT() );
@ -98,11 +89,7 @@ void GERBVIEW_FRAME::Erase_Current_DrawLayer( bool query )
item->DeleteStructure();
}
if( g_GERBER_List[layer] )
{
g_GERBER_List[layer]->InitToolTable();
g_GERBER_List[layer]->ResetDefaultValues();
}
g_GERBER_List.ClearImage( layer );
GetScreen()->SetModify();
m_canvas->Refresh();

View File

@ -56,7 +56,7 @@ void GERBVIEW_FRAME::OnLeftClick( wxDC* DC, const wxPoint& aPosition )
GetScreen()->SetCurItem( DrawStruct );
if( DrawStruct == NULL )
{
GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer() ];
GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
if( gerber )
gerber->DisplayImageInfo( );
}

View File

@ -34,7 +34,7 @@
#include <html_messagebox.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,
const wxString& D_Code_FullFileName )
@ -49,13 +49,14 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
int layer; // current layer used in GerbView
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( );
/* Set the gerber scale: */
@ -76,7 +77,7 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
if( path != wxEmptyString )
wxSetWorkingDirectory( path );
SetLocaleTo_C_standard();
LOCALE_IO toggleIo;
while( true )
{
@ -170,8 +171,8 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
}
}
}
fclose( gerber->m_Current_File );
SetLocaleTo_Default();
gerber->m_InUse = true;

View File

@ -35,6 +35,7 @@
#include <macros.h>
#include <class_gerber_draw_item.h>
#include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
#include <cmath>
@ -43,7 +44,8 @@
* G01 linear interpolation (right trace)
* G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise)
* 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
* G07 Cubic Interpolation
* G10 linear interpolation (scale x10)
@ -473,9 +475,22 @@ bool GERBER_IMAGE::Execute_G_Command( char*& text, int G_command )
break;
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 != '*') )
text++;
text++;
break;
case GC_LINEAR_INTERPOL_10X:

View File

@ -33,6 +33,7 @@
#include <gerbview.h>
#include <class_GERBER.h>
#include <class_X2_gerber_attributes.h>
extern int ReadInt( char*& text, bool aSkipSeparator = true );
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
@ -78,6 +79,13 @@ enum RS274X_PARAMETERS {
AP_DEFINITION = CODE( 'A', 'D' ),
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
// May be used singly or may be layer specfic
// theses parameters are at the beginning of the file or layer
@ -307,7 +315,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
m_SwapAxis = true;
break;
case MIRROR_IMAGE: // commanf %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
case MIRROR_IMAGE: // command %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
m_MirrorA = m_MirrorB = 0;
while( *text && *text != '*' )
{
@ -341,6 +349,27 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS;
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
m_Offset.x = m_Offset.y = 0;
while( *text != '*' )

View File

@ -121,7 +121,7 @@ void LAYERS_MAP_DIALOG::initDialog()
m_gerberActiveLayersCount = 0;
for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
{
if( g_GERBER_List[ii] == NULL )
if( g_GERBER_List.GetGbrImage( ii ) == NULL )
break;
if( (pcb_layer_num == m_exportBoardCopperLayersCount - 1)
@ -189,7 +189,7 @@ void LAYERS_MAP_DIALOG::initDialog()
wxRIGHT | wxLEFT, 5 );
/* 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(),
wxDefaultPosition, wxDefaultSize );
flexColumnBoxSizer->Add( label, 0,

View File

@ -294,7 +294,7 @@ void GERBVIEW_FRAME::OnUpdateShowLayerManager( wxUpdateUIEvent& aEvent )
void GERBVIEW_FRAME::OnUpdateSelectDCode( wxUpdateUIEvent& aEvent )
{
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;
if( m_DCodeSelector && m_DCodeSelector->GetSelectedDCodeId() != selected )

View File

@ -333,7 +333,7 @@ PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindow
bSizeRight = new wxBoxSizer( wxVERTICAL );
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;
fgSizerTW_Results = new wxFlexGridSizer( 5, 3, 0, 0 );
@ -409,7 +409,7 @@ PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindow
bSizeRight->Add( sbSizerTW_Result, 1, wxEXPAND|wxALL, 5 );
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;
fgSizerTW_Results1 = new wxFlexGridSizer( 6, 3, 0, 0 );

View File

@ -47,7 +47,7 @@
<property name="size">670,489</property>
<property name="style">wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER</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="window_extra_style"></property>
<property name="window_name"></property>
@ -4687,7 +4687,7 @@
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="0">
<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="name">sbSizerTW_Result</property>
<property name="orient">wxVERTICAL</property>
@ -6009,7 +6009,7 @@
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="0">
<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="name">sbSizerTW_Result1</property>
<property name="orient">wxVERTICAL</property>

View File

@ -293,7 +293,7 @@ class PCB_CALCULATOR_FRAME_BASE : public KIWAY_PLAYER
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();

View File

@ -223,12 +223,12 @@ void PCB_CALCULATOR_FRAME::OnDataFileSelection( wxCommandEvent& event )
wxString fullfilename = GetDataFilename();
wxString wildcard;
wildcard.Printf( _("Pcb Calculator data file (*.%s)|*.%s"),
wildcard.Printf( _("PCB Calculator data file (*.%s)|*.%s"),
GetChars( DataFileNameExt ),
GetChars( DataFileNameExt ) );
wxFileDialog dlg( m_panelRegulators,
_("Select a Pcb Calculator data file"),
_("Select a PCB Calculator data file"),
wxEmptyString, fullfilename,
wildcard, wxFD_OPEN );

View File

@ -27,8 +27,8 @@
* @brief function to convert shapes of items ( pads, tracks... ) to polygons
*/
/* Function to convert pads and tranck shapes to polygons
* Used to fill zones areas
/* Function to convert pad and track shapes to polygons
* Used to fill zones areas and in 3D viewer
*/
#include <vector>
@ -520,22 +520,19 @@ void TRACK:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
#include <clipper.hpp>
void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
{
wxPoint corner_position;
double angle;
double angle = m_Orient;
int dx = (m_Size.x / 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 */
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() )
{
@ -547,7 +544,6 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
case PAD_OVAL:
// An oval pad has the same shape as a segment with rounded ends
angle = m_Orient;
{
int width;
wxPoint shape_offset;
@ -573,77 +569,51 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
break;
case PAD_TRAPEZOID:
psize.x += std::abs( m_DeltaSize.y );
psize.y += std::abs( m_DeltaSize.x );
// fall through
case PAD_RECT:
// Easy implementation for rectangular cutouts with rounded corners
angle = m_Orient;
{
wxPoint corners[4];
BuildPadPolygon( corners, wxSize( 0, 0 ), angle );
// Corner rounding radius
int rounding_radius = KiROUND( aClearanceValue * aCorrectionFactor );
double angle_pg; // Polygon increment angle
// We are using ClipperLib to inflate the polygon shape, using
// arcs to connect moved segments.
ClipperLib::Path outline;
ClipperLib::Paths shapeWithClearance;
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( 0, -rounding_radius );
RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) );
// 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++ )
{
corner_position = wxPoint( 0, rounding_radius );
RotatePoint( &corner_position, (1800.0 / aCircleToSegmentsCount) );
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++ )
{
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.x = int( polygon[jj].X );
corner_position.y = int( polygon[jj].Y );
corner_position += PadShapePos;
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.Append( polypoint );
}
aCornerBuffer.CloseLastContour();
}
break;
}
}
@ -1090,10 +1060,90 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
aCornerBuffer.CloseLastContour();
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;
}
default:
;
}

View File

@ -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.
// zero is reserved for "no connection" and is not used.
// 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 );
}

View File

@ -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 ),
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 )
void BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode )
{
assert( aNetCode >= 0 );
BOARD* board = GetBoard();
if( board )
{
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 );
}
if( board )
m_netinfo = board->FindNet( aNetCode );
else
{
// There is no board that contains list of nets, the item is orphaned
m_netinfo = &NETINFO_LIST::ORPHANED;
}
assert( m_netinfo );
}

View File

@ -272,14 +272,15 @@ public:
* keep arc radius when approximated by segments
*/
void TransformSolidAreasShapesToPolygonSet( CPOLYGONS_LIST& aCornerBuffer,
int aCircleToSegmentsCount,
double aCorrectionFactor );
int aCircleToSegmentsCount,
double aCorrectionFactor );
/**
* Function BuildFilledSolidAreasPolygons
* 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)
* 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 aCornerBuffer: A reference to a buffer to store polygon corners, or NULL
* if NULL (default:
@ -287,13 +288,14 @@ public:
* - on copper layers, tracks and other items shapes of other nets are
* removed from solid areas
* if not null:
* Only the zone outline (with holes, if any) are stored in aCornerBuffer
* with holes linked. Therfore only one polygon is created
* @return true if OK, false if the solid areas cannot be calculated
* This function calls AddClearanceAreasPolygonsToPolysList()
* to add holes for pads and tracks and other items not in net.
* Only the zone outline (with holes, if any) is stored in aOutlineBuffer
* with holes linked. Therefore only one polygon is created
*
* When aOutlineBuffer is not null, his function calls
* 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

View File

@ -127,15 +127,20 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad )
case PAD_CONN:
{
LSET lmsk = aPad->GetLayerSet();
bool is_copper = false;
for( int i = 0; i < MAX_CU_LAYERS; i++ )
{
if( lmsk[i] )
{
is_copper = true;
layers = PNS_LAYERSET( i );
break;
}
}
if( !is_copper )
return NULL;
}
break;
@ -693,7 +698,7 @@ void PNS_ROUTER::CommitRouting( PNS_NODE* aNode )
track->SetEnd( wxPoint( s.B.x, s.B.y ) );
track->SetWidth( seg->Width() );
track->SetLayer( ToLAYER_ID( seg->Layers().Start() ) );
track->SetNetCode( seg->Net() );
track->SetNetCode( seg->Net() > 0 ? seg->Net() : 0 );
newBI = track;
break;
}
@ -705,7 +710,7 @@ void PNS_ROUTER::CommitRouting( PNS_NODE* aNode )
via_board->SetPosition( wxPoint( via->Pos().x, via->Pos().y ) );
via_board->SetWidth( via->Diameter() );
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->SetLayerPair( ToLAYER_ID( via->Layers().Start() ),
ToLAYER_ID( via->Layers().End() ) );

View File

@ -43,22 +43,19 @@
( holes are linked by overlapping segments to the main outline)
* aPcb: the current board (can be NULL for non copper zones)
* 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.
* - on copper layers, tracks and other items shapes of other nets are
* removed from solid areas
* if not null:
* 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()
* 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)
* m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
* this zone
@ -90,47 +87,33 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST*
break;
}
if( aCornerBuffer )
ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, *aCornerBuffer );
else
ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, m_FilledPolysList );
if( aOutlineBuffer )
aOutlineBuffer->Append( m_smoothedPoly->m_CornersList );
/* For copper layers, we now must add holes in the Polygon list.
* holes are pads and tracks with their clearance area
* for non copper layers just recalculate the m_FilledPolysList
* with m_ZoneMinThickness taken in account
*/
if( !aCornerBuffer )
else
{
m_FilledPolysList.RemoveAllContours();
if( IsOnCopperLayer() )
AddClearanceAreasPolygonsToPolysList( aPcb );
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;
/* 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 );
m_smoothedPoly->m_CornersList.InflateOutline(m_FilledPolysList, margin, true );
}
if( m_FillMode ) // if fill mode uses segments, create them:
FillZoneAreasWithSegments();
m_IsFilled = true;
}
m_IsFilled = true;
return 1;
return true;
}

View File

@ -138,6 +138,11 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
*/
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
KI_POLYGON_SET polyset_zone_solid_areas;
int margin = m_ZoneMinThickness / 2;
@ -149,13 +154,35 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
* so m_ZoneMinThickness is the min thickness of the filled zones areas
* the main polygon is stored in polyset_zone_solid_areas
*/
CopyPolygonsFromFilledPolysListToKiPolygonList( polyset_zone_solid_areas );
polyset_zone_solid_areas -= margin;
#if 1
m_smoothedPoly->m_CornersList.ExportTo( polyset_zone_solid_areas );
if( polyset_zone_solid_areas.size() == 0 )
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
* from m_ZoneClearance and clearance from the corresponding netclass
* We have a "local" clearance in zones because most of time
@ -186,10 +213,6 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
*/
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
* and this pad has a hole
* This dummy pad has the size and shape of the hole
@ -249,11 +272,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
continue;
}
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
if( GetPadConnection( pad ) == PAD_NOT_IN_ZONE )
{
int gap = zone_clearance;
int thermalGap = GetThermalReliefGap( pad );

View File

@ -51,12 +51,13 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
CPOLYGONS_LIST& aCornerBuffer,
int aClearanceValue, bool aAddClearance )
{
// Creates the zone outlines polygon (with linked holes if any)
CPOLYGONS_LIST zoneOutines;
BuildFilledSolidAreasPolygons( NULL, &zoneOutines );
// Creates the zone outline polygon (with linked holes if any)
CPOLYGONS_LIST zoneOutline;
BuildFilledSolidAreasPolygons( NULL, &zoneOutline );
// add clearance to outline
int clearance = 0;
if( aAddClearance )
{
clearance = GetClearance();
@ -64,51 +65,11 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
clearance = aClearanceValue;
}
// Calculate the polygon with clearance
// holes are linked to the main outline, so only one polygon should be created.
KI_POLYGON_SET polyset_zone_solid_areas;
std::vector<KI_POLY_POINT> cornerslist;
unsigned ic = 0;
unsigned corners_count = zoneOutines.GetCornersCount();
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();
}
// holes are linked to the main outline, so only one polygon is created.
if( clearance )
zoneOutline.InflateOutline( aCornerBuffer, clearance, true );
else
ConvertPolysListWithHolesToOnePolygon( zoneOutline, aCornerBuffer );
}

View File

@ -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
*/
@ -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
@ -1438,26 +1542,14 @@ void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWith
polysholes.push_back( poly_tmp );
}
}
mainpoly -= polysholes;
// copy polygon with no holes to destination
// Because all holes are now linked to the main outline
// by overlapping segments, we should have only one polygon in list
wxASSERT( mainpoly.size() == 1 );
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();
aOnePolyList.ImportFrom( mainpoly );
}
/**
@ -1553,3 +1645,22 @@ bool CPolyLine::IsPolygonSelfIntersecting()
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 );
}

View File

@ -54,6 +54,7 @@
#include <layers_id_colors_and_visibility.h> // for LAYER_NUM definition
#include <class_eda_rect.h> // for EDA_RECT definition
#include <polygons_defs.h>
#include <clipper.hpp>
class CSegment
{
@ -186,28 +187,6 @@ public:
m_cornersList.insert( m_cornersList.begin() + aPosition + 1, aItem );
}
/**
* Function ExportTo
* Copy all contours to a KI_POLYGON_SET
* @param aPolygons = the KI_POLYGON_WITH_HOLES to populate
*/
void ExportTo( KI_POLYGON_SET& aPolygons ) const;
/**
* Function ExportTo
* Copy the contours to a KI_POLYGON_WITH_HOLES
* The first contour is the main outline, others are holes
* @param aPolygoneWithHole = the KI_POLYGON_WITH_HOLES to populate
*/
void ExportTo( KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) const;
/**
* Function ImportFrom
* Copy all polygons from a KI_POLYGON_SET in list
* @param aPolygons = the KI_POLYGON_SET to import
*/
void ImportFrom( KI_POLYGON_SET& aPolygons );
/**
* function AddCorner
* add a corner to the list
@ -226,6 +205,56 @@ public:
if( m_cornersList.size() > 0 )
m_cornersList.back().end_contour = true;
}
/**
* Function ExportTo
* Copy all contours to a KI_POLYGON_SET, each contour is exported
* to a KI_POLYGON
* @param aPolygons = the KI_POLYGON_SET to populate
*/
void ExportTo( KI_POLYGON_SET& aPolygons ) const;
/**
* Function ExportTo
* Copy the contours to a KI_POLYGON_WITH_HOLES
* The first contour is the main outline, others are holes
* @param aPolygoneWithHole = the KI_POLYGON_WITH_HOLES to populate
*/
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
* Copy all polygons from a KI_POLYGON_SET in list
* @param aPolygons = the KI_POLYGON_SET to import
*/
void ImportFrom( KI_POLYGON_SET& aPolygons );
/**
* Function ImportFrom
* Copy all polygons from a ClipperLib::Paths in list
* @param aPolygons = the ClipperLib::Paths to import
*/
void ImportFrom( ClipperLib::Paths& aPolygons );
/**
* Function InflateOutline
* 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 InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles );
};
class CPolyLine
@ -489,4 +518,17 @@ public:
void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWithHoles,
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

View File

@ -6,7 +6,8 @@
# $1 wxWidgets/wxPython source folder (relative to current dir)
# $2 Target bin folder
# $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() {
echo "*** Creating/wiping build and bin folder..."
@ -59,10 +60,8 @@ wxWidgets_configure() {
--with-zlib=builtin \
--with-expat=builtin \
--without-liblzma \
--with-macosx-version-min=10.5 \
--with-macosx-version-min=$3 \
--enable-universal-binary=i386,x86_64 \
CPPFLAGS="-stdlib=libstdc++" \
LDFLAGS="-stdlib=libstdc++" \
CC=clang \
CXX=clang++
if [ $? -ne 0 ];
@ -119,16 +118,17 @@ wxPython_buildInst() {
# check parameters
if [ "$#" -lt 3 ];
if [ "$#" -lt 4 ];
then
echo "OSX wxWidgets/wxPython build script"
echo
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 " <bin> Destination 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
fi
@ -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"
# configure and build wxWidgets
wxWidgets_configure "$1" "$2"
wxWidgets_buildInst "$4"
wxWidgets_configure "$1" "$2" "$4"
wxWidgets_buildInst "$5"
# check if source is wxPython
if [ -d $1/wxPython ];