From 6e78a592f20d0651df53bcf0f9dbbc31fff823e3 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Thu, 24 May 2012 10:00:59 -0500 Subject: [PATCH] more amazing free eagle_plugin work --- pcbnew/class_module.cpp | 10 +- pcbnew/class_pad.h | 4 +- pcbnew/eagle_plugin.cpp | 434 ++++++++++++++++++++++++++------------- pcbnew/eagle_plugin.h | 27 ++- pcbnew/legacy_plugin.cpp | 4 +- 5 files changed, 331 insertions(+), 148 deletions(-) diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index e8020e4682..51ee5ce91b 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -84,8 +84,6 @@ MODULE::MODULE( BOARD* parent ) : MODULE::MODULE( const MODULE& aModule ) : BOARD_ITEM( aModule ) { - BOARD_ITEM* newItem; - m_Pos = aModule.m_Pos; m_LibRef = aModule.m_LibRef; m_Layer = aModule.m_Layer; @@ -116,7 +114,7 @@ MODULE::MODULE( const MODULE& aModule ) : m_Value->SetParent( this ); // Copy auxiliary data: Pads - m_Pads.DeleteAll(); + // m_Pads.DeleteAll(); for( D_PAD* pad = aModule.m_Pads; pad; pad = pad->Next() ) { @@ -126,10 +124,12 @@ MODULE::MODULE( const MODULE& aModule ) : } // Copy auxiliary data: Drawings - m_Drawings.DeleteAll(); + // m_Drawings.DeleteAll(); for( BOARD_ITEM* item = aModule.m_Drawings; item; item = item->Next() ) { + BOARD_ITEM* newItem; + switch( item->Type() ) { case PCB_MODULE_TEXT_T: @@ -146,7 +146,7 @@ MODULE::MODULE( const MODULE& aModule ) : } // Copy auxiliary data: 3D_Drawings info - m_3D_Drawings.DeleteAll(); + // m_3D_Drawings.DeleteAll(); for( S3D_MASTER* item = aModule.m_3D_Drawings; item; item = item->Next() ) { diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 46413578c1..719cfd9ccf 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -100,6 +100,7 @@ public: D_PAD( MODULE* parent ); // Do not create a copy constructor. The one generated by the compiler is adequate. + // D_PAD( const D_PAD& o ); void Copy( D_PAD* source ); @@ -478,7 +479,8 @@ private: double m_LocalSolderPasteMarginRatio; ///< Local solder mask margin ratio value of pad size ///< The final margin is the sum of these 2 values ZoneConnection m_ZoneConnection; - int m_ThermalWidth, m_ThermalGap; + int m_ThermalWidth; + int m_ThermalGap; }; #endif // PAD_H_ diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 11d8bb23e0..503adcc2ac 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -50,12 +50,12 @@ Load() TODO's *) finish xpath support *) set layer counts, types and names into BOARD +*) footprint placement on board back +*) eagle "mirroring" does not mean put on board back *) fix text twisting and final location issues. -*) net info *) netclass info? *) code factoring, for polygon at least - */ #include @@ -127,7 +127,6 @@ struct ECIRCLE int layer; }; - /// Eagle XML rectangle in binary struct ERECT { @@ -138,7 +137,6 @@ struct ERECT int layer; }; - /// Eagle rotation struct EROT { @@ -149,7 +147,6 @@ struct EROT typedef boost::optional opt_erot; - /// Eagle "attribute" XML element, no foolin'. struct EATTR { @@ -191,7 +188,7 @@ struct ETEXT TOP_LEFT, TOP_RIGHT, - // opposites are -1 * above: + // opposites are -1 x above, used by code tricks in here CENTER_RIGHT = -CENTER_LEFT, BOTTOM_CENTER = -TOP_CENTER, BOTTOM_LEFT = -TOP_RIGHT, @@ -200,11 +197,11 @@ struct ETEXT }; -/// Assemble a MODULE factory key as a simple concatonation of library name and -/// package name, using '\x02' as a separator. -static inline std::string makePkgKey( const std::string& aLibName, const std::string& aPkgName ) +/// Assemble a two part key as a simple concatonation of aFirst and aSecond parts, +/// using '\x02' as a separator. +static inline std::string makeKey( const std::string& aFirst, const std::string& aSecond ) { - std::string key = aLibName + '\x02' + aPkgName; + std::string key = aFirst + '\x02' + aSecond; return key; } @@ -295,13 +292,9 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, PROPE } -void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties ) -{ -} - - void EAGLE_PLUGIN::init( PROPERTIES* aProperties ) { + m_pads_to_nets.clear(); m_templates.clear(); m_board = NULL; @@ -311,41 +304,6 @@ void EAGLE_PLUGIN::init( PROPERTIES* aProperties ) biu_per_mm = IU_PER_MM; } -/* -int EAGLE_PLUGIN::biuSprintf( char* buf, BIU aValue ) const -{ - double engUnits = mm_per_biu * aValue; - int len; - - if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 ) - { - // printf( "f: " ); - len = sprintf( buf, "%.10f", engUnits ); - - while( --len > 0 && buf[len] == '0' ) - buf[len] = '\0'; - - ++len; - } - else - { - // printf( "g: " ); - len = sprintf( buf, "%.10g", engUnits ); - } - return len; -} - - -std::string EAGLE_PLUGIN::fmtBIU( BIU aValue ) const -{ - char temp[50]; - - int len = biuSprintf( temp, aValue ); - - return std::string( temp, len ); -} - -*/ void EAGLE_PLUGIN::loadAllSections( CPTREE& aEagleBoard, const std::string& aXpath, bool aAppendToMe ) { @@ -357,6 +315,12 @@ void EAGLE_PLUGIN::loadAllSections( CPTREE& aEagleBoard, const std::string& aXpa loadPlain( plain, xpath ); } + { + xpath = aXpath + '.' + "signals"; + CPTREE& signals = aEagleBoard.get_child( "signals" ); + loadSignals( signals, xpath ); + } + { xpath = aXpath + '.' + "libraries"; CPTREE& libs = aEagleBoard.get_child( "libraries" ); @@ -368,12 +332,6 @@ void EAGLE_PLUGIN::loadAllSections( CPTREE& aEagleBoard, const std::string& aXpa CPTREE& elems = aEagleBoard.get_child( "elements" ); loadElements( elems, xpath ); } - - { - xpath = aXpath + '.' + "signals"; - CPTREE& signals = aEagleBoard.get_child( "signals" ); - loadSignals( signals, xpath ); - } } @@ -507,7 +465,6 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics, const std::string& aXpath ) // hope the angle of rotation is zero. - // might be better off making this into a ZONE: if( IsValidCopperLayerIndex( layer ) ) @@ -530,6 +487,7 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics, const std::string& aXpath ) m_board->Add( dseg.release(), ADD_APPEND ); } #elif 0 + // use a "netcode = 0" type ZONE: auto_ptr zone = new ZONE_CONTAINER( m_board ); ; @@ -538,12 +496,15 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics, const std::string& aXpath ) } else if( !gr->first.compare( "hole" ) ) { + // there's a hole here } else if( !gr->first.compare( "frame" ) ) { + // picture this } else if( !gr->first.compare( "polygon" ) ) { + // step up, be a man } } } @@ -574,7 +535,7 @@ void EAGLE_PLUGIN::loadLibraries( CPTREE& aLibs, const std::string& aXpath ) } #endif - std::string key = makePkgKey( lib_name, pack_name ); + std::string key = makeKey( lib_name, pack_name ); MODULE* m = makeModule( package->second, pack_name ); @@ -643,7 +604,7 @@ void EAGLE_PLUGIN::loadElements( CPTREE& aElements, const std::string& aXpath ) opt_string rot = attrs.get_optional( "rot" ); - std::string key = makePkgKey( library, package ); + std::string key = makeKey( library, package ); MODULE_CITER mi = m_templates.find( key ); @@ -655,10 +616,35 @@ void EAGLE_PLUGIN::loadElements( CPTREE& aElements, const std::string& aXpath ) THROW_IO_ERROR( emsg ); } +#if defined(DEBUG) + if( !name.compare( "IC3" ) ) + { + int breakhere = 1; + (void) breakhere; + } +#endif + // copy constructor to clone the template MODULE* m = new MODULE( *mi->second ); m_board->Add( m, ADD_APPEND ); + for( D_PAD* pad = m->m_Pads; pad; pad = pad->Next() ) + { + const ENET& enet = m_pads_to_nets[ makeKey( name, TO_UTF8( pad->GetPadName())) ]; + + D(printf( "refname:'%s' pad:'%s' netcode:%d netname:'%s'\n", + name.c_str(), TO_UTF8( pad->GetPadName() ), + enet.netcode, + enet.netname.c_str() + );) + + if( enet.netname.size() ) + { + pad->SetNetname( FROM_UTF8( enet.netname.c_str() ) ); + pad->SetNet( enet.netcode ); + } + } + m->SetPosition( wxPoint( kicad_x( x ), kicad_y( y ) ) ); m->SetReference( FROM_UTF8( name.c_str() ) ); m->SetValue( FROM_UTF8( value.c_str() ) ); @@ -1052,6 +1038,8 @@ void EAGLE_PLUGIN::packagePad( MODULE* aModule, CPTREE& aTree ) const aModule->m_Pads.PushBack( pad ); // the DTD says these must be present, throw exception if not found + const std::string& name = attrs.get( "name" ); + double x = attrs.get( "x" ); double y = attrs.get( "y" ); double drill = attrs.get( "drill" ); @@ -1059,6 +1047,8 @@ void EAGLE_PLUGIN::packagePad( MODULE* aModule, CPTREE& aTree ) const // pad's "Position" is not relative to the module's, // whereas Pos0 is relative to the module's but is the unrotated coordinate. + pad->SetPadName( FROM_UTF8( name.c_str() ) ); + wxPoint padpos( kicad_x( x ), kicad_y( y ) ); pad->SetPos0( padpos ); @@ -1075,9 +1065,11 @@ void EAGLE_PLUGIN::packagePad( MODULE* aModule, CPTREE& aTree ) const opt_double diameter = attrs.get_optional( "diameter" ); opt_string shape = attrs.get_optional( "shape" ); opt_string rot = attrs.get_optional( "rot" ); + /* opt_string stop = attrs.get_optional( "stop" ); opt_string thermals = attrs.get_optional( "thermals" ); opt_string first = attrs.get_optional( "first" ); + */ if( diameter ) { @@ -1263,19 +1255,27 @@ void EAGLE_PLUGIN::packageSMD( MODULE* aModule, CPTREE& aTree ) const > */ - D_PAD* pad = new D_PAD( aModule ); - aModule->m_Pads.PushBack( pad ); - - pad->SetShape( PAD_RECT ); - pad->SetAttribute( PAD_SMD ); - // the DTD says these must be present, throw exception if not found + const std::string& name = attrs.get( "name" ); double x = attrs.get( "x" ); double y = attrs.get( "y" ); double dx = attrs.get( "dx" ); double dy = attrs.get( "dy" ); int layer = attrs.get( "layer" ); + if( !IsValidCopperLayerIndex( layer ) ) + { + return; + } + + D_PAD* pad = new D_PAD( aModule ); + aModule->m_Pads.PushBack( pad ); + + + pad->SetPadName( FROM_UTF8( name.c_str() ) ); + pad->SetShape( PAD_RECT ); + pad->SetAttribute( PAD_SMD ); + // pad's "Position" is not relative to the module's, // whereas Pos0 is relative to the module's but is the unrotated coordinate. @@ -1326,7 +1326,8 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals, const std::string& aXpath ) for( CITER net = aSignals.begin(); net != aSignals.end(); ++net, ++netCode ) { - wxString netName = FROM_UTF8( net->second.get( ".name" ).c_str() ); + const std::string& nname = net->second.get( ".name" ); + wxString netName = FROM_UTF8( nname.c_str() ); m_board->AppendNet( new NETINFO_ITEM( m_board, netName, netCode ) ); @@ -1336,18 +1337,27 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals, const std::string& aXpath ) if( !it->first.compare( "wire" ) ) { EWIRE w = ewire( it->second ); - TRACK* t = new TRACK( m_board ); + int layer = kicad_layer( w.layer ); - t->SetTimeStamp( timeStamp( it->second )); + if( IsValidCopperLayerIndex( layer ) ) + { + TRACK* t = new TRACK( m_board ); - t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) ); - t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) ); + t->SetTimeStamp( timeStamp( it->second ) ); - t->SetWidth( kicad( w.width ) ); - t->SetLayer( kicad_layer( w.layer ) ); - t->SetNet( netCode ); + t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) ); + t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) ); - m_board->m_Track.Insert( t, NULL ); + t->SetWidth( kicad( w.width ) ); + t->SetLayer( layer ); + t->SetNet( netCode ); + + m_board->m_Track.Insert( t, NULL ); + } + else + { + // put non copper wires where the sun don't shine. + } } else if( !it->first.compare( "via" ) ) @@ -1356,39 +1366,57 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals, const std::string& aXpath ) int layer_start = kicad_layer( v.layer_start ); int layer_end = kicad_layer( v.layer_end ); - int drill = kicad( v.drill ); - SEGVIA* via = new SEGVIA( m_board ); - - via->SetLayerPair( layer_start, layer_end ); - - if( v.diam ) + if( IsValidCopperLayerIndex( layer_start ) && + IsValidCopperLayerIndex( layer_end ) ) { - int kidiam = kicad( *v.diam ); - via->SetWidth( kidiam ); + int drill = kicad( v.drill ); + + SEGVIA* via = new SEGVIA( m_board ); + + via->SetLayerPair( layer_start, layer_end ); + + // via diameters are externally controllable, not usually in a board: + // http://www.eaglecentral.ca/forums/index.php/mv/msg/34704/119478/ + if( v.diam ) + { + int kidiam = kicad( *v.diam ); + via->SetWidth( kidiam ); + } + else + via->SetWidth( drill * 3 ); + + via->SetDrill( drill ); + + via->SetTimeStamp( timeStamp( it->second ) ); + + wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) ); + + via->SetPosition( pos ); + via->SetEnd( pos ); + + via->SetNet( netCode ); + + via->SetShape( S_CIRCLE ); // @todo should be in SEGVIA constructor + + m_board->m_Track.Insert( via, NULL ); } - - via->SetDrill( drill ); - - via->SetTimeStamp( timeStamp( it->second ) ); - - wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) ); - - via->SetPosition( pos ); - via->SetEnd( pos ); - - // via->SetWidth( width ); - // via->SetShape( shape ); - via->SetNet( netCode ); - // via->SetState( flags, ON ); - - via->SetShape( S_SEGMENT ); - - m_board->m_Track.Insert( via, NULL ); } else if( !it->first.compare( "contactref" ) ) { + // + CPTREE& attribs = it->second.get_child( "" ); + + const std::string& reference = attribs.get( "element" ); + const std::string& pad = attribs.get( "pad" ); + + std::string key = makeKey( reference, pad ) ; + + D(printf( "adding refname:'%s' pad:'%s' netcode:%d netname:'%s'\n", + reference.c_str(), pad.c_str(), netCode, nname.c_str() );) + + m_pads_to_nets[ key ] = ENET( netCode, nname ); } else if( !it->first.compare( "polygon" ) ) @@ -1399,49 +1427,178 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals, const std::string& aXpath ) } -int EAGLE_PLUGIN::kicad_layer( int aLayer ) +int EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) { - int ret; + /* will assume this is a valid mapping for all eagle boards until I get paid more: - switch( aLayer ) // translate eagle layer to pcbnew layer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */ + + + int kiLayer; + + // eagle copper layer: + if( aEagleLayer >=1 && aEagleLayer <= 16 ) { - case 1: ret = 15; break; // Top copper - case 2: ret = 14; break; - case 3: ret = 13; break; - case 4: ret = 12; break; - case 5: ret = 11; break; - case 6: ret = 10; break; - case 7: ret = 9; break; - case 8: ret = 8; break; - case 9: ret = 7; break; - case 10: ret = 6; break; - case 11: ret = 5; break; - case 12: ret = 4; break; - case 13: ret = 3; break; - case 14: ret = 2; break; - case 15: ret = 1; break; - case 16: ret = 0; break; // Bottom Copper - case 20: ret = 28; break; // Edge Layer - case 21: ret = 21; break; // Top Silk Screen - case 22: ret = 20; break; // Bottom Silk Screen - case 25: ret = 25; break; // Misc Comment Layers - case 26: ret = 25; break; - case 27: ret = 26; break; - case 28: ret = 26; break; - case 29: ret = 23; break; - case 30: ret = 22; break; - case 31: ret = 19; break; - case 32: ret = 18; break; - case 35: ret = 17; break; - case 36: ret = 16; break; - case 51: ret = 26; break; - case 52: ret = 27; break; - case 95: ret = 26; break; - case 96: ret = 27; break; - default: ret = -1; break; // our eagle understanding is incomplete + kiLayer = LAYER_N_FRONT - ( aEagleLayer - 1 ); } - return ret; + else + { +/* +#define FIRST_NO_COPPER_LAYER 16 +#define ADHESIVE_N_BACK 16 +#define ADHESIVE_N_FRONT 17 +#define SOLDERPASTE_N_BACK 18 +#define SOLDERPASTE_N_FRONT 19 +#define SILKSCREEN_N_BACK 20 +#define SILKSCREEN_N_FRONT 21 +#define SOLDERMASK_N_BACK 22 +#define SOLDERMASK_N_FRONT 23 +#define DRAW_N 24 +#define COMMENT_N 25 +#define ECO1_N 26 +#define ECO2_N 27 +#define EDGE_N 28 +#define LAST_NO_COPPER_LAYER 28 +#define UNUSED_LAYER_29 29 +#define UNUSED_LAYER_30 30 +#define UNUSED_LAYER_31 31 +*/ + // translate non-copper eagle layer to pcbnew layer + switch( aEagleLayer ) + { + case 20: kiLayer = EDGE_N; break; // eagle says "Dimension" layer, but it's for board perimeter + case 21: kiLayer = SILKSCREEN_N_FRONT; break; + case 22: kiLayer = SILKSCREEN_N_BACK; break; + case 25: kiLayer = SILKSCREEN_N_FRONT; break; + case 26: kiLayer = SILKSCREEN_N_BACK; break; + case 27: kiLayer = SILKSCREEN_N_FRONT; break; + case 28: kiLayer = SILKSCREEN_N_BACK; break; + case 29: kiLayer = SOLDERMASK_N_FRONT; break; + case 30: kiLayer = SOLDERMASK_N_BACK; break; + case 31: kiLayer = SOLDERPASTE_N_FRONT; break; + case 32: kiLayer = SOLDERPASTE_N_BACK; break; + case 33: kiLayer = SOLDERMASK_N_FRONT; break; + case 34: kiLayer = SOLDERMASK_N_BACK; break; + case 35: kiLayer = ADHESIVE_N_FRONT; break; + case 36: kiLayer = ADHESIVE_N_BACK; break; + case 49: kiLayer = COMMENT_N; break; + case 50: kiLayer = COMMENT_N; break; + case 51: kiLayer = ECO1_N; break; + case 52: kiLayer = ECO2_N; break; + case 95: kiLayer = ECO1_N; break; + case 96: kiLayer = ECO2_N; break; + default: + D( printf( "unexpected eagle layer: %d\n", aEagleLayer );) + kiLayer = -1; break; // our eagle understanding is incomplete + } + } + + return kiLayer; +} + + +/* +void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties ) +{ + // Eagle lovers apply here. +} + + +int EAGLE_PLUGIN::biuSprintf( char* buf, BIU aValue ) const +{ + double engUnits = mm_per_biu * aValue; + int len; + + if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 ) + { + // printf( "f: " ); + len = sprintf( buf, "%.10f", engUnits ); + + while( --len > 0 && buf[len] == '0' ) + buf[len] = '\0'; + + ++len; + } + else + { + // printf( "g: " ); + len = sprintf( buf, "%.10g", engUnits ); + } + return len; +} + + +std::string EAGLE_PLUGIN::fmtBIU( BIU aValue ) const +{ + char temp[50]; + + int len = biuSprintf( temp, aValue ); + + return std::string( temp, len ); } @@ -1482,3 +1639,4 @@ bool EAGLE_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath ) return true; } +*/ \ No newline at end of file diff --git a/pcbnew/eagle_plugin.h b/pcbnew/eagle_plugin.h index f70a0965ac..032fd6952e 100644 --- a/pcbnew/eagle_plugin.h +++ b/pcbnew/eagle_plugin.h @@ -34,13 +34,30 @@ #include #include -#include +#include class MODULE; typedef boost::ptr_map< std::string, MODULE > MODULE_MAP; +struct ENET +{ + int netcode; + std::string netname; + + ENET( int aNetCode, const std::string& aNetName ) : + netcode( aNetCode ), + netname( aNetName ) + {} + + ENET() : + netcode( 0 ) + {} +}; + +typedef std::map< std::string, ENET > NET_MAP; + /* #include namespace boost { @@ -79,6 +96,9 @@ public: BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, PROPERTIES* aProperties = NULL ); + const wxString& GetFileExtension() const; + +/* void Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties = NULL ); wxArrayString FootprintEnumerate( const wxString& aLibraryPath, PROPERTIES* aProperties = NULL); @@ -94,8 +114,7 @@ public: void FootprintLibDelete( const wxString& aLibraryPath, PROPERTIES* aProperties = NULL ); bool IsFootprintLibWritable( const wxString& aLibraryPath ); - - const wxString& GetFileExtension() const; +*/ //------------------------------------------------------ @@ -106,6 +125,8 @@ public: private: + NET_MAP m_pads_to_nets; + MODULE_MAP m_templates; ///< is part of a MODULE factory that operates ///< using copy construction. ///< lookup key is libname.packagename diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 55658c1366..0fce1c79d4 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -1892,7 +1892,8 @@ void LEGACY_PLUGIN::loadTrackList( TRACK* aInsertBeforeMe, int aStructType ) { // read two lines per loop iteration, each loop is one TRACK or VIA // example first line: - // "Po 0 23994 28800 24400 28800 150 -1\r\n" + // e.g. "Po 0 23994 28800 24400 28800 150 -1" for a track + // e.g. "Po 3 21086 17586 21086 17586 180 -1" for a via (uses sames start and end) const char* data; char* line = m_reader->Line(); @@ -1943,6 +1944,7 @@ void LEGACY_PLUGIN::loadTrackList( TRACK* aInsertBeforeMe, int aStructType ) int layer, type, flags, net_code; // parse the 2nd line to determine the type of object + // e.g. "De 15 1 7 0 0" for a via sscanf( line + SZ( "De" ), " %d %d %d %lX %X", &layer, &type, &net_code, &timeStamp, &flags ); if( aStructType==PCB_TRACE_T && type==1 )