summaryrefslogtreecommitdiff
path: root/gerbview/class_GERBER.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gerbview/class_GERBER.cpp')
-rw-r--r--gerbview/class_GERBER.cpp557
1 files changed, 557 insertions, 0 deletions
diff --git a/gerbview/class_GERBER.cpp b/gerbview/class_GERBER.cpp
new file mode 100644
index 0000000..59d7615
--- /dev/null
+++ b/gerbview/class_GERBER.cpp
@@ -0,0 +1,557 @@
+/**
+ * @file class_GERBER.cpp
+ * a GERBER class handle for a given layer info about used D_CODES and how the layer is drawn
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2013 Jean-Pierre Charras jp.charras at wanadoo.fr
+ * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <fctsys.h>
+#include <common.h>
+#include <class_drawpanel.h>
+#include <confirm.h>
+#include <macros.h>
+
+#include <gerbview.h>
+#include <gerbview_frame.h>
+#include <class_GERBER.h>
+#include <class_X2_gerber_attributes.h>
+
+#include <algorithm>
+
+
+/**
+ * Function scaletoIU
+ * converts a distance given in floating point to our internal units
+ */
+extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordiantes.cpp
+
+/* Format Gerber: NOTES:
+ * Tools and D_CODES
+ * tool number (identification of shapes)
+ * 1 to 999
+ *
+ * D_CODES:
+ * D01 ... D9 = action codes:
+ * D01 = activating light (lower pen) when di placement
+ * D02 = light extinction (lift pen) when di placement
+ * D03 Flash
+ * D09 = VAPE Flash
+ * D10 ... = Indentification Tool (Opening)
+ *
+ * For tools:
+ * DCode min = D10
+ * DCode max = 999
+ */
+
+
+GERBER_LAYER::GERBER_LAYER()
+{
+ ResetDefaultValues();
+}
+
+
+GERBER_LAYER::~GERBER_LAYER()
+{
+}
+
+
+void GERBER_LAYER::ResetDefaultValues()
+{
+ m_LayerName = wxT( "no name" ); // Layer name from the LN command
+ m_LayerNegative = false; // true = Negative Layer
+ m_StepForRepeat.x = m_StepForRepeat.y = 0; // X and Y offsets for Step and Repeat command
+ m_XRepeatCount = 1; // The repeat count on X axis
+ m_YRepeatCount = 1; // The repeat count on Y axis
+ m_StepForRepeatMetric = false; // false = Inches, true = metric
+}
+
+
+GERBER_IMAGE::GERBER_IMAGE( GERBVIEW_FRAME* aParent, int aLayer )
+{
+ m_Parent = aParent;
+ m_GraphicLayer = aLayer; // Graphic layer Number
+
+ m_Selected_Tool = FIRST_DCODE;
+ m_FileFunction = NULL; // file function parameters
+
+ ResetDefaultValues();
+
+ for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
+ m_Aperture_List[ii] = 0;
+}
+
+
+GERBER_IMAGE::~GERBER_IMAGE()
+{
+ for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
+ {
+ delete m_Aperture_List[ii];
+ }
+
+ delete m_FileFunction;
+}
+
+/*
+ * Function GetItemsList
+ * returns the first GERBER_DRAW_ITEM * item of the items list
+ */
+GERBER_DRAW_ITEM * GERBER_IMAGE::GetItemsList()
+{
+ return m_Parent->GetItemsList();
+}
+
+D_CODE* GERBER_IMAGE::GetDCODE( int aDCODE, bool create )
+{
+ unsigned ndx = aDCODE - FIRST_DCODE;
+
+ if( ndx < (unsigned) DIM( m_Aperture_List ) )
+ {
+ // lazily create the D_CODE if it does not exist.
+ if( create )
+ {
+ if( m_Aperture_List[ndx] == NULL )
+ m_Aperture_List[ndx] = new D_CODE( ndx + FIRST_DCODE );
+ }
+
+ return m_Aperture_List[ndx];
+ }
+ return NULL;
+}
+
+
+APERTURE_MACRO* GERBER_IMAGE::FindApertureMacro( const APERTURE_MACRO& aLookup )
+{
+ APERTURE_MACRO_SET::iterator iter = m_aperture_macros.find( aLookup );
+
+ if( iter != m_aperture_macros.end() )
+ {
+ APERTURE_MACRO* pam = (APERTURE_MACRO*) &(*iter);
+ return pam;
+ }
+
+ return NULL; // not found
+}
+
+
+void GERBER_IMAGE::ResetDefaultValues()
+{
+ m_InUse = false;
+ m_GBRLayerParams.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)
+ m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
+ m_GerbMetric = false; // false = Inches (default), true = metric
+ m_Relative = false; // false = absolute Coord,
+ // true = relative Coord
+ m_NoTrailingZeros = false; // true: trailing zeros deleted
+ m_DecimalFormat = false; // true: use floating point notations for coordinates
+ m_ImageOffset.x = m_ImageOffset.y = 0; // Coord Offset, from IO command
+ m_ImageRotation = 0; // Allowed 0, 90, 180, 270 (in degree)
+ m_LocalRotation = 0.0; // Layer totation from RO command (in 0.1 degree)
+ m_Offset.x = 0;
+ m_Offset.y = 0; // Coord Offset, from OF command
+ m_Scale.x = m_Scale.y = 1.0; // scale (A and B) this layer
+ m_MirrorA = false; // true: miror / axe A (default = X)
+ m_MirrorB = false; // true: miror / axe B (default = Y)
+ m_SwapAxis = false; // false if A = X, B = Y; true if A =Y, B = Y
+ m_Has_DCode = false; // true = DCodes in file
+ // false = no DCode->
+ // search for separate DCode file
+ m_FmtScale.x = m_FmtScale.y = 4; // Initialize default format to 3.4 => 4
+ m_FmtLen.x = m_FmtLen.y = 3 + 4; // Initialize default format len = 3+4
+
+ m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Linear, 90 arc, Circ.
+ m_360Arc_enbl = false; // 360 deg circular
+ // interpolation disable
+ m_Current_Tool = 0; // Current Dcode selected
+ m_CommandState = 0; // State of the current command
+ m_CurrentPos.x = m_CurrentPos.y = 0; // current specified coord
+ m_PreviousPos.x = m_PreviousPos.y = 0; // last specified coord
+ m_IJPos.x = m_IJPos.y = 0; // current centre coord for
+ // plot arcs & circles
+ m_Current_File = NULL; // Gerber file to read
+ m_FilesPtr = 0;
+ m_PolygonFillMode = false;
+ m_PolygonFillModeState = 0;
+ m_Selected_Tool = FIRST_DCODE;
+ m_Last_Pen_Command = 0;
+ m_Exposure = false;
+
+ for( unsigned ii = 0; ii < DIM( m_FilesList ); ii++ )
+ m_FilesList[ii] = NULL;
+}
+
+/* Function HasNegativeItems
+ * return true if at least one item must be drawn in background color
+ * used to optimize screen refresh
+ */
+bool GERBER_IMAGE::HasNegativeItems()
+{
+ if( m_hasNegativeItems < 0 ) // negative items are not yet searched: find them if any
+ {
+ if( m_ImageNegative ) // A negative layer is expected having always negative objects.
+ m_hasNegativeItems = 1;
+ else
+ {
+ m_hasNegativeItems = 0;
+ for( GERBER_DRAW_ITEM* item = GetItemsList(); item; item = item->Next() )
+ {
+ if( item->GetLayer() != m_GraphicLayer )
+ continue;
+ if( item->HasNegativeItems() )
+ {
+ m_hasNegativeItems = 1;
+ break;
+ }
+ }
+ }
+ }
+ return m_hasNegativeItems == 1;
+}
+
+int GERBER_IMAGE::UsedDcodeNumber()
+{
+ int count = 0;
+
+ for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
+ {
+ if( m_Aperture_List[ii] )
+ if( m_Aperture_List[ii]->m_InUse || m_Aperture_List[ii]->m_Defined )
+ ++count;
+ }
+
+ return count;
+}
+
+
+void GERBER_IMAGE::InitToolTable()
+{
+ for( int count = 0; count < TOOLS_MAX_COUNT; count++ )
+ {
+ if( m_Aperture_List[count] == NULL )
+ continue;
+
+ m_Aperture_List[count]->m_Num_Dcode = count + FIRST_DCODE;
+ m_Aperture_List[count]->Clear_D_CODE_Data();
+ }
+
+ m_aperture_macros.clear();
+}
+
+
+/**
+ * Function ReportMessage
+ * Add a message (a string) in message list
+ * for instance when reading a Gerber file
+ * @param aMessage = the straing to add in list
+ */
+void GERBER_IMAGE::ReportMessage( const wxString aMessage )
+{
+ m_Parent->ReportMessage( aMessage );
+}
+
+
+/**
+ * Function ClearMessageList
+ * Clear the message list
+ * Call it before reading a Gerber file
+ */
+void GERBER_IMAGE::ClearMessageList()
+{
+ m_Parent->ClearMessageList();
+}
+
+
+/**
+ * Function StepAndRepeatItem
+ * Gerber format has a command Step an Repeat
+ * This function must be called when reading a gerber file and
+ * after creating a new gerber item that must be repeated
+ * (i.e when m_XRepeatCount or m_YRepeatCount are > 1)
+ * @param aItem = the item to repeat
+ */
+void GERBER_IMAGE::StepAndRepeatItem( const GERBER_DRAW_ITEM& aItem )
+{
+ if( GetLayerParams().m_XRepeatCount < 2 &&
+ GetLayerParams().m_YRepeatCount < 2 )
+ return; // Nothing to repeat
+ // Duplicate item:
+ wxString msg;
+ for( int ii = 0; ii < GetLayerParams().m_XRepeatCount; ii++ )
+ {
+ for( int jj = 0; jj < GetLayerParams().m_YRepeatCount; jj++ )
+ {
+ // the first gerber item already exists (this is the template)
+ // create duplicate only if ii or jj > 0
+ if( jj == 0 && ii == 0 )
+ continue;
+ GERBER_DRAW_ITEM* dupItem = new GERBER_DRAW_ITEM( aItem );
+ wxPoint move_vector;
+ move_vector.x = scaletoIU( ii * GetLayerParams().m_StepForRepeat.x,
+ GetLayerParams().m_StepForRepeatMetric );
+ move_vector.y = scaletoIU( jj * GetLayerParams().m_StepForRepeat.y,
+ GetLayerParams().m_StepForRepeatMetric );
+ dupItem->MoveXY( move_vector );
+ m_Parent->GetGerberLayout()->m_Drawings.Append( dupItem );
+ }
+ }
+}
+
+
+/**
+ * Function DisplayImageInfo
+ * has knowledge about the frame and how and where to put status information
+ * about this object into the frame's message panel.
+ * Display info about Image Parameters.
+ * These parameters are valid for the entire file, and must set only once
+ * (If more than once, only the last value is used)
+ */
+void GERBER_IMAGE::DisplayImageInfo( void )
+{
+ wxString msg;
+
+ m_Parent->ClearMsgPanel();
+
+ // Display Image name (Image specific)
+ m_Parent->AppendMsgPanel( _( "Image name" ), m_ImageName, CYAN );
+
+ // Display graphic layer number used to draw this Image
+ // (not a Gerber parameter but is also image specific)
+ msg.Printf( wxT( "%d" ), m_GraphicLayer + 1 );
+ m_Parent->AppendMsgPanel( _( "Graphic layer" ), msg, BROWN );
+
+ // Display Image rotation (Image specific)
+ msg.Printf( wxT( "%d" ), m_ImageRotation );
+ m_Parent->AppendMsgPanel( _( "Img Rot." ), msg, CYAN );
+
+ // Display Image polarity (Image specific)
+ msg = m_ImageNegative ? _("Negative") : _("Normal");
+ m_Parent->AppendMsgPanel( _( "Polarity" ), msg, BROWN );
+
+ // Display Image justification and offset for justification (Image specific)
+ msg = m_ImageJustifyXCenter ? _("Center") : _("Normal");
+ m_Parent->AppendMsgPanel( _( "X Justify" ), msg, DARKRED );
+
+ msg = m_ImageJustifyYCenter ? _("Center") : _("Normal");
+ m_Parent->AppendMsgPanel( _( "Y Justify" ), msg, DARKRED );
+
+ if( g_UserUnit == INCHES )
+ msg.Printf( wxT( "X=%f Y=%f" ), (double) m_ImageJustifyOffset.x/10000,
+ (double) m_ImageJustifyOffset.y/10000 );
+ else
+ msg.Printf( wxT( "X=%f Y=%f" ), (double) m_ImageJustifyOffset.x*2.54/1000,
+ (double) m_ImageJustifyOffset.y*2.54/1000 );
+ 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( gerber && IsUsed(aIdx ) )
+ {
+ if( gerber->m_FileFunction )
+ {
+ if( gerber->m_FileFunction->IsCopper() )
+ {
+ name.Printf( _( "Layer %d (%s, %s, %s)" ), aIdx + 1,
+ GetChars( gerber->m_FileFunction->GetFileType() ),
+ GetChars( gerber->m_FileFunction->GetBrdLayerId() ),
+ GetChars( gerber->m_FileFunction->GetBrdLayerSide() ) );
+ }
+ else
+ {
+ 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;