Gerbview: fixed an issue with some gerber files. Added Image Justify support (partial support).

This commit is contained in:
jean-pierre charras 2010-10-17 14:32:35 +02:00
parent a911720adf
commit de37bbad17
8 changed files with 263 additions and 64 deletions

View File

@ -151,6 +151,9 @@ 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_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
@ -271,3 +274,45 @@ void GERBER_IMAGE::StepAndRepeatItem( const GERBER_DRAW_ITEM& aItem )
}
}
}
/** Function DisplayInfo
* 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.
*/
void GERBER_IMAGE::DisplayImageInfo( void )
{
wxString msg;
m_Parent->ClearMsgPanel();
// Display Image name
m_Parent->AppendMsgPanel( _( "Image name" ), m_ImageName, BROWN );
// Display graphic layer number
msg.Printf( wxT( "%d" ), m_GraphicLayer + 1 );
m_Parent->AppendMsgPanel( _( "Graphic layer" ), msg, BROWN );
// This next info can be see as debug info, so it can be disabled
// Display rotation
msg.Printf( wxT( "%d" ), m_ImageRotation / 10 );
m_Parent->AppendMsgPanel( _( "Rotation" ), msg, CYAN );
// Display Image justification;
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, CYAN );
}

View File

@ -86,6 +86,9 @@ public:
wxString m_ImageName; // Image name, from IN <name>* command
int m_GraphicLayer; // Graphic layer Number
bool m_ImageNegative; // true = Negative image
bool m_ImageJustifyXCenter; // Image Justify Center on X axis (default = false)
bool m_ImageJustifyYCenter; // Image Justify Center on Y axis (default = false)
wxPoint m_ImageJustifyOffset; // Image Justify Offset on XY axis (default = 0,0)
bool m_GerbMetric; // false = Inches, true = metric
bool m_Relative; // false = absolute Coord, true = relative Coord
bool m_NoTrailingZeros; // true: remove tailing zeros.
@ -236,6 +239,13 @@ public:
* @param aItem = the item to repeat
*/
void StepAndRepeatItem( const GERBER_DRAW_ITEM& aItem );
/** 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.
*/
void DisplayImageInfo( void );
};

View File

@ -120,7 +120,7 @@ wxPoint GERBER_DRAW_ITEM::GetABPosition( const wxPoint& aXYPosition )
* For instance: Rotation must be made after or before mirroring ?
* Note: if something is changed here, GetYXPosition must reflect changes
*/
wxPoint abPos = aXYPosition;
wxPoint abPos = aXYPosition + m_imageParams->m_ImageJustifyOffset;
if( m_swapAxis )
EXCHG( abPos.x, abPos.y );
@ -165,7 +165,7 @@ wxPoint GERBER_DRAW_ITEM::GetXYPosition( const wxPoint& aABPosition )
xyPos -= m_layerOffset + m_imageParams->m_ImageOffset;
if( m_swapAxis )
EXCHG( xyPos.x, xyPos.y );
return xyPos;
return xyPos - m_imageParams->m_ImageJustifyOffset;
}
@ -458,7 +458,7 @@ void GERBER_DRAW_ITEM::DrawGbrPoly( EDA_Rect* aClipBox,
/** Function DisplayInfo
* 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 the track segment only, and does not calculate the full track length
* Display info about this GERBER item
* @param frame A WinEDA_DrawFrame in which to print status information.
*/
void GERBER_DRAW_ITEM::DisplayInfo( WinEDA_DrawFrame* frame )
@ -473,13 +473,6 @@ void GERBER_DRAW_ITEM::DisplayInfo( WinEDA_DrawFrame* frame )
msg.Printf( wxT( "%d" ), m_DCode );
frame->AppendMsgPanel( _( "D Code" ), msg, RED );
// Display Image name
if( m_imageParams )
{
msg = m_imageParams->m_ImageName;
frame->AppendMsgPanel( _( "Image name" ), msg, BROWN );
}
// Display graphic layer number
msg.Printf( wxT( "%d" ), GetLayer() + 1 );
frame->AppendMsgPanel( _( "Graphic layer" ), msg, BROWN );

View File

@ -209,7 +209,7 @@ public:
* has knowledge about the frame and how and where to put status information
* about this object into the frame's message panel.
* Is virtual from EDA_BaseStruct.
* Display info about the track segment and the full track length
* Display info about this GERBER item
* @param frame A WinEDA_DrawFrame in which to print status information.
*/
void DisplayInfo( WinEDA_DrawFrame* frame );

View File

@ -37,6 +37,12 @@ void WinEDA_GerberFrame::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
{
DrawStruct = GerberGeneralLocateAndDisplay();
GetScreen()->SetCurItem( DrawStruct );
if( DrawStruct == NULL )
{
GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer() ];
if( gerber )
gerber->DisplayImageInfo( );
}
}
}

View File

@ -0,0 +1,19 @@
G04 Test image justify 1*
G04 Crosshairs should be justified to the X axis *
G04 and 0.5 inches offset from Y axis *
G04 Handcoded by Julian Lamb *
%MOIN*%
%FSLAX23Y23*%
%IJB.5*%
%ADD10C,0.050*%
G04 Crosshairs *
X-1000Y0D02*
G54D10*
X1000Y0D01*
X0Y-1000D02*
G54D10*
X0Y1000D01*
M02*

View File

@ -0,0 +1,18 @@
G04 Test image offset *
G04 Crosshairs should be centered on 0,0 in final rendering*
G04 Handcoded by Julian Lamb *
%MOIN*%
%FSLAX23Y23*%
%IOA-2.0B-1.0*%
%ADD10C,0.050*%
G04 Crosshairs to be on 0,0 *
X1000Y1000D02*
G54D10*
X3000Y1000D01*
X2000Y0D02*
G54D10*
X2000Y2000D01*
M02*

View File

@ -11,6 +11,9 @@
#define CODE( x, y ) ( ( (x) << 8 ) + (y) )
// Helper function to read a primitive macro param (TODO: make it DCODE_PARAM function)
static bool ReadMacroParam( DCODE_PARAM& aParam, char*& aText );
// See rs274xrevd_e.pdf, table 1: RS-274X parameters order of entry
// in gerber files, when a coordinate is given (like X78Y600 or I0J80):
// Y and Y are logical coordinates
@ -94,14 +97,16 @@ static int ReadXCommand( char*& text )
* int, then skip over that.
* @param text A reference to a character pointer from which bytes are read
* and the pointer is advanced for each byte read.
* @param int - The int read in.
* @param aSkipSeparator = true (default) to skip comma
* @return int - The int read in.
*/
static int ReadInt( char*& text )
static int ReadInt( char*& text, bool aSkipSeparator = true )
{
int ret = (int) strtol( text, &text, 10 );
if( *text == ',' || isspace( *text ) )
++text;
if( aSkipSeparator )
++text;
return ret;
}
@ -113,14 +118,16 @@ static int ReadInt( char*& text )
* the double, then skip over that.
* @param text A reference to a character pointer from which the ASCII double
* is read from and the pointer advanced for each character read.
* @param aSkipSeparator = true (default) to skip comma
* @return double
*/
static double ReadDouble( char*& text )
static double ReadDouble( char*& text, bool aSkipSeparator = true )
{
double ret = strtod( text, &text );
if( *text == ',' || isspace( *text ) )
++text;
if( aSkipSeparator )
++text;
return ret;
}
@ -427,11 +434,68 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
}
break;
case IMAGE_JUSTIFY:
case PLOTTER_FILM:
case IMAGE_JUSTIFY: // Command IJAnBn*
m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
m_ImageJustifyOffset = wxPoint(0,0); // Image Justify Offset on XY axis (default = 0,0)
while( *text && *text != '*' )
{
// IJ command is (for A or B axis) AC or AL or A<coordinate>
switch( *text )
{
case 'A': // A axis justify
text++;
if( *text == 'C' )
{
m_ImageJustifyXCenter = true;
text++;
}
else if( *text == 'L' )
{
m_ImageJustifyXCenter = true;
text++;
}
else m_ImageJustifyOffset.x = wxRound( ReadDouble( text ) * conv_scale);
break;
case 'B': // B axis justify
text++;
if( *text == 'C' )
{
m_ImageJustifyYCenter = true;
text++;
}
else if( *text == 'L' )
{
m_ImageJustifyYCenter = true;
text++;
}
else m_ImageJustifyOffset.y = wxRound( ReadDouble( text ) * conv_scale);
break;
default:
text++;
break;
}
}
if( m_ImageJustifyXCenter )
m_ImageJustifyOffset.x = 0;
if( m_ImageJustifyYCenter )
m_ImageJustifyOffset.y = 0;
break;
case KNOCKOUT:
msg.Printf( _( "RS274X: Command \"%c%c\" ignored by Gerbview" ),
(command >> 8) & 0xFF, command & 0xFF );
msg = _( "RS274X: Command KNOCKOUT ignored by Gerbview" ) ;
ReportMessage( msg );
break;
case PLOTTER_FILM: // Command PF <string>
// This is an info about film that must be used to plot this file
// Has no meaning here. We just display this string
msg = ( "Plotter Film info:<br>" );
while( *text != '*' )
{
msg.Append( *text++ );
}
ReportMessage( msg );
break;
@ -498,10 +562,10 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
m_FilesPtr++;
break;
case AP_MACRO:
case AP_MACRO: // lines like %AMMYMACRO*
// 5,1,8,0,0,1.08239X$1,22.5*
// %
ok = ReadApertureMacro( buff, text, m_Current_File );
if( !ok )
break;
break;
case AP_DEFINITION:
@ -729,24 +793,39 @@ bool GetEndOfBlock( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file )
return FALSE;
}
static bool CheckForLineEnd( char buff[GERBER_BUFZ], char*& text, FILE* fp )
/** function GetNextLine
* test for an end of line
* if an end of line is found:
* read a new line
* @param aBuff[GERBER_BUFZ] = buffer to fill with a new line
* @param aText = pointer to the last useful char in aBuff
* on return: points the beginning of the next line.
* @param aFile = the opened GERBER file to read
* @return a pointer to the beginning of the next line or NULL if end of file
*/
static char* GetNextLine( char aBuff[GERBER_BUFZ], char* aText, FILE* aFile )
{
while( *text == '\n' || *text == '\r' || !*text )
for( ; ; )
{
if( *text == '\n' || *text == '\r' )
++text;
if( !*text )
switch (*aText )
{
if( fgets( buff, GERBER_BUFZ, fp ) == NULL )
return false;
case ' ': // skip blanks
case '\n':
case '\r': // Skip line terminators
++aText;
break;
text = buff;
case 0: // End of text found in aBuff: Read a new string
if( fgets( aBuff, GERBER_BUFZ, aFile ) == NULL )
return NULL;
aText = aBuff;
return aText;
default:
return aText;
}
}
return true;
return aText;
}
@ -769,24 +848,28 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
am.name.Append( *text++ );
}
// Read aperture macro parameters
for( ; ; )
{
AM_PRIMITIVE prim( m_GerbMetric );
if( *text == '*' )
++text;
if( !CheckForLineEnd( buff, text, gerber_file ) )
text = GetNextLine( buff, text, gerber_file ); // Get next line
if( text == NULL ) // End of File
return false;
// text points the beginning of a new line.
// Test for the last line in aperture macro lis:
// last line is % or *% sometime found.
if( *text == '*' )
++text;
if( *text == '%' )
break; // exit with text still pointing at %
prim.primitive_id = (AM_PRIMITIVE_ID) ReadInt( text );
int paramCount;
switch( prim.primitive_id )
int paramCount = 0;
int primitive_type = ReadInt( text );
switch( primitive_type )
{
case AMP_CIRCLE:
paramCount = 4;
@ -823,30 +906,26 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
break;
default:
// @todo, there needs to be a way of reporting the line number
msg.Printf( wxT( "RS274X: Invalid primitive id code %d\n" ), prim.primitive_id );
msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": Invalid primitive id code %d, line: \"%s\"" ),
GetChars(am.name), primitive_type, CONV_FROM_UTF8(buff) );
ReportMessage( msg );
return false;
}
AM_PRIMITIVE prim( m_GerbMetric );
prim.primitive_id = (AM_PRIMITIVE_ID) primitive_type;
int i;
for( i = 0; i < paramCount && *text != '*'; ++i )
for( i = 0; i < paramCount && *text && *text != '*'; ++i )
{
prim.params.push_back( DCODE_PARAM() );
DCODE_PARAM& param = prim.params.back();
if( !CheckForLineEnd( buff, text, gerber_file ) )
text = GetNextLine( buff, text, gerber_file );
if( text == NULL) // End of File
return false;
if( *text == '$' )
{
++text;
param.SetIndex( ReadInt( text ) );
}
else
param.SetValue( ReadDouble( text ) );
ReadMacroParam( param, text );
}
if( i < paramCount )
@ -856,6 +935,7 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
"RS274X: read macro descr type %d: read %d parameters, insufficient parameters\n" ),
prim.primitive_id, i );
ReportMessage( msg );
}
// there are more parameters to read if this is an AMP_OUTLINE
if( prim.primitive_id == AMP_OUTLINE )
@ -875,16 +955,10 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
DCODE_PARAM& param = prim.params.back();
if( !CheckForLineEnd( buff, text, gerber_file ) )
text = GetNextLine( buff, text, gerber_file );
if( text == NULL ) // End of File
return false;
if( *text == '$' )
{
++text;
param.SetIndex( ReadInt( text ) );
}
else
param.SetValue( ReadDouble( text ) );
ReadMacroParam( param, text );
}
}
@ -895,3 +969,37 @@ bool GERBER_IMAGE::ReadApertureMacro( char buff[GERBER_BUFZ],
return true;
}
/** Function ReadMacroParam
* Read one aperture macro parameter
* a parameter can be:
* a number
* a reference to an aperture definition parameter value: $1 ot $3 ...
* a parameter definition can be complex and have operators between numbers and/or other parameter
* like $1+3 or $2x2..
* Parameters are separated by a comma ( of finish by *)
* Return if a param is read, or false
*/
static bool ReadMacroParam( DCODE_PARAM& aParam, char*& aText )
{
bool found = false;
if( *aText == '$' ) // value defined later, in aperture description
{
++aText;
aParam.SetIndex( ReadInt( aText, false ) );
found = true;
}
else
{
aParam.SetValue( ReadDouble( aText, false ) );
found = true;
}
// Skip extra characters and separator
while( *aText && (*aText != ',') && (*aText != '*') )
aText++;
if( *aText == ',' )
aText++;
return found;
}