void LEGACY_NETLIST_READER::loadNet( char* aText, COMPONENT* aComponent ) throw( PARSE_ERROR ) { wxString msg; char* p; char line[256]; strncpy( line, aText, sizeof( line ) ); line[ sizeof(line) - 1 ] = '\0'; if( ( p = strtok( line, " ()\t\n" ) ) == NULL ) { msg = _( "Cannot parse pin name in component net section of netlist." ); THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), line, m_lineReader->LineNumber(), m_lineReader->Length() ); } wxString pinName = FROM_UTF8( p ); if( ( p = strtok( NULL, " ()\t\n" ) ) == NULL ) { msg = _( "Cannot parse net name in component net section of netlist." ); THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), line, m_lineReader->LineNumber(), m_lineReader->Length() ); } wxString netName = FROM_UTF8( p ); if( (char) netName[0] == '?' ) // ? indicates no net connected to pin. netName = wxEmptyString; aComponent->AddNet( pinName, netName ); }
void DSNLEXER::Duplicate( int aTok ) throw( IO_ERROR ) { wxString errText; errText.Printf( _("%s is a duplicate"), GetTokenString( aTok ).GetData() ); THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); }
UTF8 FPID::Format( const UTF8& aLogicalLib, const UTF8& aFootprintName, const UTF8& aRevision ) throw( PARSE_ERROR ) { UTF8 ret; int offset; if( aLogicalLib.size() ) { offset = okLogical( aLogicalLib ); if( offset != -1 ) { THROW_PARSE_ERROR( _( "Illegal character found in logical library name" ), wxString::FromUTF8( aLogicalLib.c_str() ), aLogicalLib.c_str(), 0, offset ); } ret += aLogicalLib; ret += ':'; } if( aRevision.size() ) { offset = okRevision( aRevision ); if( offset != -1 ) { THROW_PARSE_ERROR( _( "Illegal character found in revision" ), wxString::FromUTF8( aRevision.c_str() ), aRevision.c_str(), 0, offset ); } ret += '/'; ret += aRevision; } return ret; }
int DSNLEXER::NeedNUMBER( const char* aExpectation ) throw( IO_ERROR ) { int tok = NextTok(); if( tok != DSN_NUMBER ) { wxString errText; errText.Printf( _("need a NUMBER for '%s'"), wxString::FromUTF8( aExpectation ).GetData() ); THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } return tok; }
FPID::FPID( const std::string& aId ) throw( PARSE_ERROR ) { int offset = Parse( aId ); if( offset != -1 ) { THROW_PARSE_ERROR( _( "Illegal character found in FPID string" ), wxString::FromUTF8( aId.c_str() ), aId.c_str(), 0, offset ); } }
void LEGACY_NETLIST_READER::loadFootprintFilters() throw( IO_ERROR, PARSE_ERROR ) { wxArrayString filters; wxString cmpRef; char* line; COMPONENT* component = NULL; // Suppress compil warning while( ( line = m_lineReader->ReadLine() ) != NULL ) { if( strnicmp( line, "$endlist", 8 ) == 0 ) // end of list for the current component { wxASSERT( component != NULL ); component->SetFootprintFilters( filters ); component = NULL; filters.Clear(); continue; } if( strnicmp( line, "$endfootprintlist", 4 ) == 0 ) // End of this section return; if( strnicmp( line, "$component", 10 ) == 0 ) // New component reference found { cmpRef = FROM_UTF8( line + 11 ); cmpRef.Trim( true ); cmpRef.Trim( false ); component = m_netlist->GetComponentByReference( cmpRef ); // Cannot happen if the netlist is valid. if( component == NULL ) { wxString msg; msg.Printf( _( "Cannot find component \'%s\' in footprint filter section " "of netlist." ), GetChars( cmpRef ) ); THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), line, m_lineReader->LineNumber(), m_lineReader->Length() ); } } else { // Add new filter to list wxString fp = FROM_UTF8( line + 1 ); fp.Trim( false ); fp.Trim( true ); filters.Add( fp ); } } }
FPID::FPID( const wxString& aId ) throw( PARSE_ERROR ) { UTF8 id = aId; int offset = Parse( id ); if( offset != -1 ) { THROW_PARSE_ERROR( _( "Illegal character found in FPID string" ), aId, id.c_str(), 0, offset ); } }
int DSNLEXER::NextTok() throw( IO_ERROR ) { const char* cur = next; const char* head = cur; prevTok = curTok; if( curTok != DSN_EOF ) { if( cur >= limit ) { L_read: // blank lines are returned as "\n" and will have a len of 1. // EOF will have a len of 0 and so is detectable. int len = readLine(); if( len == 0 ) { cur = start; // after readLine(), since start can change, set cur offset to start curTok = DSN_EOF; goto exit; } cur = start; // after readLine() since start can change. // skip leading whitespace while( cur<limit && isSpace(*cur) ) ++cur; // If the first non-blank character is #, this line is a comment. // Comments cannot follow any other token on the same line. if( cur<limit && *cur=='#' ) { if( commentsAreTokens ) { // save the entire line, including new line as the current token. // the '#' character may not be at offset zero. curText = start; // entire line is the token cur = start; // ensure a good curOffset below curTok = DSN_COMMENT; head = limit; // do a readLine() on next call in here. goto exit; } else goto L_read; } } else { // skip leading whitespace while( cur<limit && isSpace(*cur) ) ++cur; } if( cur >= limit ) goto L_read; // switching the string_quote character if( prevTok == DSN_STRING_QUOTE ) { static const wxString errtxt( _("String delimiter must be a single character of ', \", or $")); char cc = *cur; switch( cc ) { case '\'': case '$': case '"': break; default: THROW_PARSE_ERROR( errtxt, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } curText = cc; head = cur+1; if( head<limit && *head!=')' && *head!='(' && !isSpace(*head) ) { THROW_PARSE_ERROR( errtxt, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } curTok = DSN_QUOTE_DEF; goto exit; } if( *cur == '(' ) { curText = *cur; curTok = DSN_LEFT; head = cur+1; goto exit; } if( *cur == ')' ) { curText = *cur; curTok = DSN_RIGHT; head = cur+1; goto exit; } /* get the dash out of a <pin_reference> which is embedded for example like: U2-14 or "U2"-"14" This is detectable by a non-space immediately preceeding the dash. */ if( *cur == '-' && cur>start && !isSpace( cur[-1] ) ) { curText = '-'; curTok = DSN_DASH; head = cur+1; goto exit; } // handle DSN_NUMBER if( strchr( "+-.0123456789", *cur ) ) { head = cur+1; while( head<limit && strchr( ".0123456789", *head ) ) ++head; if( (head<limit && isSpace(*head)) || *head==')' || *head=='(' || head==limit ) { curText.clear(); curText.append( cur, head ); curTok = DSN_NUMBER; goto exit; } // else it was something like +5V, fall through below } // a quoted string, will return DSN_STRING if( *cur == stringDelimiter ) { // Non-specctraMode, understands and deciphers escaped \, \r, \n, and \". // Strips off leading and trailing double quotes if( !specctraMode ) { // copy the token, character by character so we can remove doubled up quotes. curText.clear(); ++cur; // skip over the leading delimiter, which is always " in non-specctraMode head = cur; while( head<limit ) { // ESCAPE SEQUENCES: if( *head =='\\' ) { char tbuf[8]; char c; int i; if( ++head >= limit ) break; // throw exception at L_unterminated switch( *head++ ) { case '"': case '\\': c = head[-1]; break; case 'a': c = '\x07'; break; case 'b': c = '\x08'; break; case 'f': c = '\x0c'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\x09'; break; case 'v': c = '\x0b'; break; case 'x': // 1 or 2 byte hex escape sequence for( i=0; i<2; ++i ) { if( !isxdigit( head[i] ) ) break; tbuf[i] = head[i]; } tbuf[i] = '\0'; if( i > 0 ) c = (char) strtoul( tbuf, NULL, 16 ); else c = 'x'; // a goofed hex escape sequence, interpret as 'x' head += i; break; default: // 1-3 byte octal escape sequence --head; for( i=0; i<3; ++i ) { if( head[i] < '0' || head[i] > '7' ) break; tbuf[i] = head[i]; } tbuf[i] = '\0'; if( i > 0 ) c = (char) strtoul( tbuf, NULL, 8 ); else c = '\\'; // a goofed octal escape sequence, interpret as '\' head += i; break; } curText += c; } else if( *head == '"' ) // end of the non-specctraMode DSN_STRING { curTok = DSN_STRING; ++head; // omit this trailing double quote goto exit; } else curText += *head++; } // while // L_unterminated: wxString errtxt(_("Un-terminated delimited string") ); THROW_PARSE_ERROR( errtxt, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } else // specctraMode DSN_STRING { ++cur; // skip over the leading delimiter: ",', or $ head = cur; while( head<limit && !isStringTerminator( *head ) ) ++head; if( head >= limit ) { wxString errtxt(_("Un-terminated delimited string") ); THROW_PARSE_ERROR( errtxt, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } curText.clear(); curText.append( cur, head ); ++head; // skip over the trailing delimiter curTok = DSN_STRING; goto exit; } } // Maybe it is a token we will find in the token table. // If not, then call it a DSN_SYMBOL. { head = cur+1; while( head<limit && !isSpace( *head ) && *head!=')' && *head!='(' ) ++head; curText.clear(); curText.append( cur, head ); int found = findToken( curText ); if( found != -1 ) curTok = found; else if( 0 == curText.compare( "string_quote" ) ) curTok = DSN_STRING_QUOTE; else // unrecogized token, call it a symbol curTok = DSN_SYMBOL; } } exit: // single point of exit, no returns elsewhere please. curOffset = cur - start; next = head; // printf("tok:\"%s\"\n", curText.c_str() ); return curTok; }
void DSNLEXER::Unexpected( const char* text ) throw( IO_ERROR ) { wxString errText( _("Unexpected") ); errText << wxT(" '") << wxString::FromUTF8( text ) << wxT("'"); THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); }
void DSNLEXER::Unexpected( int aTok ) throw( IO_ERROR ) { wxString errText( _("Unexpected") ); errText << wxT(" ") << GetTokenString( aTok ); THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); }
COMPONENT* LEGACY_NETLIST_READER::loadComponent( char* aText ) throw( PARSE_ERROR, boost::bad_pointer ) { char* text; wxString msg; wxString timeStamp; // the full time stamp read from netlist wxString footprintName; // the footprint name read from netlist wxString value; // the component value read from netlist wxString reference; // the component schematic reference designator read from netlist wxString name; // the name of component that was placed in the schematic char line[1024]; strcpy( line, aText ); value = wxT( "~" ); // Sample component line: /40C08647 $noname R20 4.7K {Lib=R} // Read time stamp (first word) if( ( text = strtok( line, " ()\t\n" ) ) == NULL ) { msg = _( "Cannot parse time stamp in component section of netlist." ); THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), line, m_lineReader->LineNumber(), m_lineReader->Length() ); } timeStamp = FROM_UTF8( text ); // Read footprint name (second word) if( ( text = strtok( NULL, " ()\t\n" ) ) == NULL ) { msg = _( "Cannot parse footprint name in component section of netlist." ); THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), aText, m_lineReader->LineNumber(), m_lineReader->Length() ); } footprintName = FROM_UTF8( text ); // The footprint name will have to be looked up in the *.cmp file. if( footprintName == wxT( "$noname" ) ) footprintName = wxEmptyString; // Read schematic reference designator (third word) if( ( text = strtok( NULL, " ()\t\n" ) ) == NULL ) { msg = _( "Cannot parse reference designator in component section of netlist." ); THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), aText, m_lineReader->LineNumber(), m_lineReader->Length() ); } reference = FROM_UTF8( text ); // Read schematic value (forth word) if( ( text = strtok( NULL, " ()\t\n" ) ) == NULL ) { msg = _( "Cannot parse value in component section of netlist." ); THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), aText, m_lineReader->LineNumber(), m_lineReader->Length() ); } value = FROM_UTF8( text ); // Read component name (fifth word) {Lib=C} // This is an optional field (a comment), which does not always exists if( ( text = strtok( NULL, " ()\t\n" ) ) != NULL ) { name = FROM_UTF8( text ).AfterFirst( wxChar( '=' ) ).BeforeLast( wxChar( '}' ) ); } FPID fpid; if( !footprintName.IsEmpty() ) fpid.SetFootprintName( footprintName ); COMPONENT* component = new COMPONENT( fpid, reference, value, timeStamp ); component->SetName( name ); m_netlist->AddComponent( component ); return component; }
MODULE* GPCB_FPL_CACHE::parseMODULE( LINE_READER* aLineReader ) throw( IO_ERROR, PARSE_ERROR ) { #define TEXT_DEFAULT_SIZE ( 40*IU_PER_MILS ) #define OLD_GPCB_UNIT_CONV IU_PER_MILS // Old version unit = 1 mil, so conv_unit is 10 or 0.1 #define NEW_GPCB_UNIT_CONV ( 0.01*IU_PER_MILS ) int paramCnt; double conv_unit = NEW_GPCB_UNIT_CONV; // GPCB unit = 0.01 mils and Pcbnew 0.1 wxPoint textPos; wxString msg; wxArrayString parameters; std::auto_ptr<MODULE> module( new MODULE( NULL ) ); if( aLineReader->ReadLine() == NULL ) THROW_IO_ERROR( "unexpected end of file" ); parameters.Clear(); parseParameters( parameters, aLineReader ); paramCnt = parameters.GetCount(); /* From the Geda PCB documentation, valid Element definitions: * Element [SFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TSFlags] * Element (NFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TNFlags) * Element (NFlags "Desc" "Name" "Value" TX TY TDir TScale TNFlags) * Element (NFlags "Desc" "Name" TX TY TDir TScale TNFlags) * Element ("Desc" "Name" TX TY TDir TScale TNFlags) */ if( parameters[0].CmpNoCase( wxT( "Element" ) ) != 0 ) { msg.Printf( _( "unknown token \"%s\"" ), GetChars( parameters[0] ) ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } if( paramCnt < 10 || paramCnt > 14 ) { msg.Printf( _( "Element token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } // Test symbol after "Element": if [ units = 0.01 mils, and if ( units = 1 mil if( parameters[1] == wxT( "(" ) ) conv_unit = OLD_GPCB_UNIT_CONV; if( paramCnt > 10 ) { module->SetDescription( parameters[3] ); module->SetReference( parameters[4] ); } else { module->SetDescription( parameters[2] ); module->SetReference( parameters[3] ); } // Read value if( paramCnt > 10 ) module->SetValue( parameters[5] ); // With gEDA/pcb, value is meaningful after instantiation, only, so it's // often empty in bare footprints. if( module->Value().GetText().IsEmpty() ) module->Value().SetText( wxT( "Val**" ) ); if( paramCnt == 14 ) { textPos = wxPoint( parseInt( parameters[8], conv_unit ), parseInt( parameters[9], conv_unit ) ); } else { textPos = wxPoint( parseInt( parameters[6], conv_unit ), parseInt( parameters[7], conv_unit ) ); } int orientation = parseInt( parameters[paramCnt-4], 1.0 ); module->Reference().SetOrientation( (orientation % 2) ? 900 : 0 ); // Calculate size: default height is 40 mils, width 30 mil. // real size is: default * ibuf[idx+3] / 100 (size in gpcb is given in percent of default size int thsize = parseInt( parameters[paramCnt-3], TEXT_DEFAULT_SIZE ) / 100; thsize = std::max( (int)( 5 * IU_PER_MILS ), thsize ); // Ensure a minimal size = 5 mils int twsize = thsize * 30 / 40; int thickness = thsize / 8; // gEDA/pcb aligns top/left, not pcbnew's default, center/center. // Compensate for this by shifting the insertion point instead of the // aligment, because alignment isn't changeable in the GUI. textPos.x = textPos.x + twsize * module->GetReference().Len() / 2; textPos.y += thsize / 2; // gEDA/pcb draws a bit too low/left, while pcbnew draws a bit too // high/right. Compensate for similar appearance. textPos.x -= thsize / 10; textPos.y += thsize / 2; module->Reference().SetTextPosition( textPos ); module->Reference().SetPos0( textPos ); module->Reference().SetSize( wxSize( twsize, thsize ) ); module->Reference().SetThickness( thickness ); // gEDA/pcb shows only one of value/reference/description at a time. Which // one is selectable by a global menu setting. pcbnew needs reference as // well as value visible, so place the value right below the reference. module->Value().SetOrientation( module->Reference().GetOrientation() ); module->Value().SetSize( module->Reference().GetSize() ); module->Value().SetThickness( module->Reference().GetThickness() ); textPos.y += thsize * 13 / 10; // 130% line height module->Value().SetTextPosition( textPos ); module->Value().SetPos0( textPos ); while( aLineReader->ReadLine() ) { parameters.Clear(); parseParameters( parameters, aLineReader ); if( parameters.IsEmpty() || parameters[0] == wxT( "(" ) ) continue; if( parameters[0] == wxT( ")" ) ) break; paramCnt = parameters.GetCount(); // Test units value for a string line param (more than 3 parameters : ident [ xx ] ) if( paramCnt > 3 ) { if( parameters[1] == wxT( "(" ) ) conv_unit = OLD_GPCB_UNIT_CONV; else conv_unit = NEW_GPCB_UNIT_CONV; } wxLogTrace( traceFootprintLibrary, wxT( "%s parameter count = %d." ), GetChars( parameters[0] ), paramCnt ); // Parse a line with format: ElementLine [X1 Y1 X2 Y2 Thickness] if( parameters[0].CmpNoCase( wxT( "ElementLine" ) ) == 0 ) { if( paramCnt != 8 ) { msg.Printf( wxT( "ElementLine token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } EDGE_MODULE* drawSeg = new EDGE_MODULE( module.get() ); drawSeg->SetLayer( F_SilkS ); drawSeg->SetShape( S_SEGMENT ); drawSeg->SetStart0( wxPoint( parseInt( parameters[2], conv_unit ), parseInt( parameters[3], conv_unit ) ) ); drawSeg->SetEnd0( wxPoint( parseInt( parameters[4], conv_unit ), parseInt( parameters[5], conv_unit ) ) ); drawSeg->SetWidth( parseInt( parameters[6], conv_unit ) ); drawSeg->SetDrawCoord(); module->GraphicalItems().PushBack( drawSeg ); continue; } // Parse an arc with format: ElementArc [X Y Width Height StartAngle DeltaAngle Thickness] if( parameters[0].CmpNoCase( wxT( "ElementArc" ) ) == 0 ) { if( paramCnt != 10 ) { msg.Printf( wxT( "ElementArc token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } // Pcbnew does know ellipse so we must have Width = Height EDGE_MODULE* drawSeg = new EDGE_MODULE( module.get() ); drawSeg->SetLayer( F_SilkS ); drawSeg->SetShape( S_ARC ); module->GraphicalItems().PushBack( drawSeg ); // for and arc: ibuf[3] = ibuf[4]. Pcbnew does not know ellipses int radius = ( parseInt( parameters[4], conv_unit ) + parseInt( parameters[5], conv_unit ) ) / 2; wxPoint centre( parseInt( parameters[2], conv_unit ), parseInt( parameters[3], conv_unit ) ); drawSeg->SetStart0( centre ); // Pcbnew start angles are inverted and 180 degrees from Geda PCB angles. double start_angle = parseInt( parameters[6], -10.0 ) + 1800.0; // Pcbnew delta angle direction is the opposite of Geda PCB delta angles. double sweep_angle = parseInt( parameters[7], -10.0 ); // Geda PCB does not support circles. if( sweep_angle == -3600.0 ) drawSeg->SetShape( S_CIRCLE ); // Angle value is clockwise in gpcb and Pcbnew. drawSeg->SetAngle( sweep_angle ); drawSeg->SetEnd0( wxPoint( radius, 0 ) ); // Calculate start point coordinate of arc wxPoint arcStart( drawSeg->GetEnd0() ); RotatePoint( &arcStart, -start_angle ); drawSeg->SetEnd0( centre + arcStart ); drawSeg->SetWidth( parseInt( parameters[8], conv_unit ) ); drawSeg->SetDrawCoord(); continue; } // Parse a Pad with no hole with format: // Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags] // Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags) // Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags) // Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags) if( parameters[0].CmpNoCase( wxT( "Pad" ) ) == 0 ) { if( paramCnt < 10 || paramCnt > 13 ) { msg.Printf( wxT( "Pad token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } D_PAD* pad = new D_PAD( module.get() ); static const LSET pad_front( 3, F_Cu, F_Mask, F_Paste ); static const LSET pad_back( 3, B_Cu, B_Mask, B_Paste ); pad->SetShape( PAD_SHAPE_RECT ); pad->SetAttribute( PAD_ATTRIB_SMD ); pad->SetLayerSet( pad_front ); if( testFlags( parameters[paramCnt-2], 0x0080, wxT( "onsolder" ) ) ) pad->SetLayerSet( pad_back ); // Set the pad name: // Pcbnew pad name is used for electrical connection calculations. // Accordingly it should be mapped to gEDA's pin/pad number, // which is used for the same purpose. // gEDA also features a pin/pad "name", which is an arbitrary string // and set to the pin name of the netlist on instantiation. Many gEDA // bare footprints use identical strings for name and number, so this // can be a bit confusing. pad->SetPadName( parameters[paramCnt-3] ); int x1 = parseInt( parameters[2], conv_unit ); int x2 = parseInt( parameters[4], conv_unit ); int y1 = parseInt( parameters[3], conv_unit ); int y2 = parseInt( parameters[5], conv_unit ); int width = parseInt( parameters[6], conv_unit ); wxPoint delta( x2 - x1, y2 - y1 ); double angle = atan2( (double)delta.y, (double)delta.x ); // Get the pad clearance and the solder mask clearance. if( paramCnt == 13 ) { int clearance = parseInt( parameters[7], conv_unit ); // One of gEDA's oddities is that clearance between pad and polygon // is given as the gap on both sides of the pad together, so for // KiCad it has to halfed. pad->SetLocalClearance( clearance / 2 ); // In GEDA, the mask value is the size of the hole in this // solder mask. In Pcbnew, it is a margin, therefore the distance // between the copper and the mask int maskMargin = parseInt( parameters[8], conv_unit ); maskMargin = ( maskMargin - width ) / 2; pad->SetLocalSolderMaskMargin( maskMargin ); } // Negate angle (due to Y reversed axis) and convert it to internal units angle = - RAD2DECIDEG( angle ); pad->SetOrientation( KiROUND( angle ) ); wxPoint padPos( (x1 + x2) / 2, (y1 + y2) / 2 ); pad->SetSize( wxSize( KiROUND( EuclideanNorm( delta ) ) + width, width ) ); padPos += module->GetPosition(); pad->SetPos0( padPos ); pad->SetPosition( padPos ); if( !testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) ) { if( pad->GetSize().x == pad->GetSize().y ) pad->SetShape( PAD_SHAPE_CIRCLE ); else pad->SetShape( PAD_SHAPE_OVAL ); } module->Add( pad ); continue; } // Parse a Pin with through hole with format: // Pin [rX rY Thickness Clearance Mask Drill "Name" "Number" SFlags] // Pin (rX rY Thickness Clearance Mask Drill "Name" "Number" NFlags) // Pin (aX aY Thickness Drill "Name" "Number" NFlags) // Pin (aX aY Thickness Drill "Name" NFlags) // Pin (aX aY Thickness "Name" NFlags) if( parameters[0].CmpNoCase( wxT( "Pin" ) ) == 0 ) { if( paramCnt < 8 || paramCnt > 12 ) { msg.Printf( wxT( "Pin token contains %d parameters." ), paramCnt ); THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader, aLineReader->LineNumber(), 0 ); } D_PAD* pad = new D_PAD( module.get() ); pad->SetShape( PAD_SHAPE_CIRCLE ); static const LSET pad_set = LSET::AllCuMask() | LSET( 3, F_SilkS, F_Mask, B_Mask ); pad->SetLayerSet( pad_set ); if( testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) ) pad->SetShape( PAD_SHAPE_RECT ); // Set the pad name: // Pcbnew pad name is used for electrical connection calculations. // Accordingly it should be mapped to gEDA's pin/pad number, // which is used for the same purpose. pad->SetPadName( parameters[paramCnt-3] ); wxPoint padPos( parseInt( parameters[2], conv_unit ), parseInt( parameters[3], conv_unit ) ); int padSize = parseInt( parameters[4], conv_unit ); pad->SetSize( wxSize( padSize, padSize ) ); int drillSize = 0; // Get the pad clearance, solder mask clearance, and drill size. if( paramCnt == 12 ) { int clearance = parseInt( parameters[5], conv_unit ); // One of gEDA's oddities is that clearance between pad and polygon // is given as the gap on both sides of the pad together, so for // KiCad it has to halfed. pad->SetLocalClearance( clearance / 2 ); // In GEDA, the mask value is the size of the hole in this // solder mask. In Pcbnew, it is a margin, therefore the distance // between the copper and the mask int maskMargin = parseInt( parameters[6], conv_unit ); maskMargin = ( maskMargin - padSize ) / 2; pad->SetLocalSolderMaskMargin( maskMargin ); drillSize = parseInt( parameters[7], conv_unit ); } else { drillSize = parseInt( parameters[5], conv_unit ); } pad->SetDrillSize( wxSize( drillSize, drillSize ) ); padPos += module->GetPosition(); pad->SetPos0( padPos ); pad->SetPosition( padPos ); if( pad->GetShape() == PAD_SHAPE_CIRCLE && pad->GetSize().x != pad->GetSize().y ) pad->SetShape( PAD_SHAPE_OVAL ); module->Add( pad ); continue; } } // Recalculate the bounding box module->CalculateBoundingBox(); return module.release(); }