2013-05-26 04:36:44 +00:00
|
|
|
/**
|
2016-05-25 14:48:38 +00:00
|
|
|
* @file class_gerber_file_image.cpp
|
2013-05-26 04:36:44 +00:00
|
|
|
* 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.
|
|
|
|
*
|
2016-05-24 15:56:52 +00:00
|
|
|
* Copyright (C) 1992-2016 Jean-Pierre Charras jp.charras at wanadoo.fr
|
|
|
|
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
2013-05-26 04:36:44 +00:00
|
|
|
*
|
|
|
|
* 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 <macros.h>
|
2016-06-05 12:26:39 +00:00
|
|
|
#include <convert_to_biu.h>
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
#include <gerbview.h>
|
2014-06-27 17:07:42 +00:00
|
|
|
#include <gerbview_frame.h>
|
2016-05-25 14:48:38 +00:00
|
|
|
#include <class_gerber_file_image.h>
|
2014-11-22 11:52:57 +00:00
|
|
|
#include <class_X2_gerber_attributes.h>
|
|
|
|
|
|
|
|
#include <algorithm>
|
2016-05-28 16:46:29 +00:00
|
|
|
#include <map>
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-05 12:26:39 +00:00
|
|
|
GERBER_FILE_IMAGE::GERBER_FILE_IMAGE( int aLayer )
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
2014-11-22 11:52:57 +00:00
|
|
|
m_GraphicLayer = aLayer; // Graphic layer Number
|
2016-06-02 09:30:39 +00:00
|
|
|
m_IsVisible = true; // must be drawn
|
|
|
|
m_PositiveDrawColor = WHITE; // The color used to draw positive items for this image
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
m_Selected_Tool = FIRST_DCODE;
|
2014-11-22 11:52:57 +00:00
|
|
|
m_FileFunction = NULL; // file function parameters
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
ResetDefaultValues();
|
|
|
|
|
|
|
|
for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
|
|
|
|
m_Aperture_List[ii] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
GERBER_FILE_IMAGE::~GERBER_FILE_IMAGE()
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
2016-06-15 08:26:41 +00:00
|
|
|
m_Drawings.DeleteAll();
|
|
|
|
|
2013-05-26 04:36:44 +00:00
|
|
|
for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
|
|
|
|
{
|
|
|
|
delete m_Aperture_List[ii];
|
|
|
|
}
|
2014-11-22 11:52:57 +00:00
|
|
|
|
|
|
|
delete m_FileFunction;
|
2013-05-26 04:36:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function GetItemsList
|
|
|
|
* returns the first GERBER_DRAW_ITEM * item of the items list
|
|
|
|
*/
|
2016-05-25 14:48:38 +00:00
|
|
|
GERBER_DRAW_ITEM * GERBER_FILE_IMAGE::GetItemsList()
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
2016-05-26 11:57:43 +00:00
|
|
|
return m_Drawings;
|
2013-05-26 04:36:44 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
D_CODE* GERBER_FILE_IMAGE::GetDCODE( int aDCODE, bool aCreateIfNoExist )
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
unsigned ndx = aDCODE - FIRST_DCODE;
|
|
|
|
|
|
|
|
if( ndx < (unsigned) DIM( m_Aperture_List ) )
|
|
|
|
{
|
|
|
|
// lazily create the D_CODE if it does not exist.
|
2016-05-24 15:56:52 +00:00
|
|
|
if( aCreateIfNoExist )
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
if( m_Aperture_List[ndx] == NULL )
|
|
|
|
m_Aperture_List[ndx] = new D_CODE( ndx + FIRST_DCODE );
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_Aperture_List[ndx];
|
|
|
|
}
|
2016-05-24 15:56:52 +00:00
|
|
|
|
2013-05-26 04:36:44 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
APERTURE_MACRO* GERBER_FILE_IMAGE::FindApertureMacro( const APERTURE_MACRO& aLookup )
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
void GERBER_FILE_IMAGE::ResetDefaultValues()
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
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
|
2014-11-22 11:52:57 +00:00
|
|
|
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
|
2013-05-26 04:36:44 +00:00
|
|
|
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
|
2015-02-26 10:33:15 +00:00
|
|
|
m_Current_File = NULL; // Gerber file to read
|
2013-05-26 04:36:44 +00:00
|
|
|
m_FilesPtr = 0;
|
|
|
|
m_PolygonFillMode = false;
|
|
|
|
m_PolygonFillModeState = 0;
|
|
|
|
m_Selected_Tool = FIRST_DCODE;
|
2015-02-26 10:33:15 +00:00
|
|
|
m_Last_Pen_Command = 0;
|
|
|
|
m_Exposure = false;
|
|
|
|
|
|
|
|
for( unsigned ii = 0; ii < DIM( m_FilesList ); ii++ )
|
|
|
|
m_FilesList[ii] = NULL;
|
2013-05-26 04:36:44 +00:00
|
|
|
}
|
|
|
|
|
2016-06-05 12:26:39 +00:00
|
|
|
|
2013-05-26 04:36:44 +00:00
|
|
|
/* Function HasNegativeItems
|
|
|
|
* return true if at least one item must be drawn in background color
|
|
|
|
* used to optimize screen refresh
|
|
|
|
*/
|
2016-05-25 14:48:38 +00:00
|
|
|
bool GERBER_FILE_IMAGE::HasNegativeItems()
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-06-05 12:26:39 +00:00
|
|
|
int GERBER_FILE_IMAGE::GetDcodesCount()
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
void GERBER_FILE_IMAGE::InitToolTable()
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
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 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
|
|
|
|
*/
|
2016-05-25 14:48:38 +00:00
|
|
|
void GERBER_FILE_IMAGE::StepAndRepeatItem( const GERBER_DRAW_ITEM& aItem )
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
if( GetLayerParams().m_XRepeatCount < 2 &&
|
|
|
|
GetLayerParams().m_YRepeatCount < 2 )
|
|
|
|
return; // Nothing to repeat
|
2016-05-25 09:45:55 +00:00
|
|
|
|
2013-05-26 04:36:44 +00:00
|
|
|
// Duplicate item:
|
|
|
|
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 );
|
2016-05-26 11:57:43 +00:00
|
|
|
m_Drawings.Append( dupItem );
|
2013-05-26 04:36:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
*/
|
2016-06-05 12:26:39 +00:00
|
|
|
void GERBER_FILE_IMAGE::DisplayImageInfo( GERBVIEW_FRAME* aMainFrame )
|
2013-05-26 04:36:44 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
2016-06-05 12:26:39 +00:00
|
|
|
aMainFrame->ClearMsgPanel();
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
// Display Image name (Image specific)
|
2016-06-05 12:26:39 +00:00
|
|
|
aMainFrame->AppendMsgPanel( _( "Image name" ), m_ImageName, CYAN );
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
// 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 );
|
2016-06-05 12:26:39 +00:00
|
|
|
aMainFrame->AppendMsgPanel( _( "Graphic layer" ), msg, BROWN );
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
// Display Image rotation (Image specific)
|
|
|
|
msg.Printf( wxT( "%d" ), m_ImageRotation );
|
2016-06-05 12:26:39 +00:00
|
|
|
aMainFrame->AppendMsgPanel( _( "Img Rot." ), msg, CYAN );
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
// Display Image polarity (Image specific)
|
|
|
|
msg = m_ImageNegative ? _("Negative") : _("Normal");
|
2016-06-05 12:26:39 +00:00
|
|
|
aMainFrame->AppendMsgPanel( _( "Polarity" ), msg, BROWN );
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
// Display Image justification and offset for justification (Image specific)
|
|
|
|
msg = m_ImageJustifyXCenter ? _("Center") : _("Normal");
|
2016-06-05 12:26:39 +00:00
|
|
|
aMainFrame->AppendMsgPanel( _( "X Justify" ), msg, DARKRED );
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
msg = m_ImageJustifyYCenter ? _("Center") : _("Normal");
|
2016-06-05 12:26:39 +00:00
|
|
|
aMainFrame->AppendMsgPanel( _( "Y Justify" ), msg, DARKRED );
|
2013-05-26 04:36:44 +00:00
|
|
|
|
|
|
|
if( g_UserUnit == INCHES )
|
2016-06-05 12:26:39 +00:00
|
|
|
msg.Printf( wxT( "X=%f Y=%f" ), Iu2Mils( m_ImageJustifyOffset.x ) / 1000.0,
|
|
|
|
Iu2Mils( m_ImageJustifyOffset.y ) / 1000.0 );
|
2013-05-26 04:36:44 +00:00
|
|
|
else
|
2016-06-05 12:26:39 +00:00
|
|
|
msg.Printf( wxT( "X=%f Y=%f" ), Iu2Millimeter( m_ImageJustifyOffset.x ),
|
|
|
|
Iu2Millimeter( m_ImageJustifyOffset.y ) );
|
|
|
|
|
|
|
|
aMainFrame->AppendMsgPanel( _( "Image Justify Offset" ), msg, DARKRED );
|
2013-05-26 04:36:44 +00:00
|
|
|
}
|