Eeschema: Eagle schematic plugin parser improvements.

* Fix multi line text alignment.
* Parse schematic frame objects and convert them to lines.
* Make implicit global labels normal size so they can easily be seen.
* Move sheet fields to a more sensible position.
* Parse schematic symbol instances before wires so that the implicit power
  connections can properly be tested.  This will be used at a later time.
* Scale label text size down to allow for differences in label offset and
  graphical items.
This commit is contained in:
Wayne Stambaugh 2021-02-15 16:44:58 -05:00
parent d93ba0a06a
commit 089b7afacf
4 changed files with 276 additions and 88 deletions

View File

@ -2,8 +2,9 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012-2020 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 CERN. * Copyright (C) 2017 CERN.
*
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -59,17 +60,21 @@ OPTIONAL_XML_ATTRIBUTE<wxString>::OPTIONAL_XML_ATTRIBUTE( wxString aData )
ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit ) ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
{ {
// this array is used to adjust the fraction part value basing on the number of digits in the fraction // This array is used to adjust the fraction part value basing on the number of digits
// in the fraction.
constexpr int DIVIDERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; constexpr int DIVIDERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
constexpr unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1; constexpr unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1;
int integer, fraction, pre_fraction, post_fraction; int integer, fraction, pre_fraction, post_fraction;
// the following check is needed to handle correctly negative fractions where the integer part == 0 // The following check is needed to handle correctly negative fractions where the integer
// part == 0.
bool negative = ( aValue[0] == '-' ); bool negative = ( aValue[0] == '-' );
// %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3 digits // %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3
int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction, &post_fraction ); // digits.
int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction,
&post_fraction );
if( ret == 0 ) if( ret == 0 )
throw XML_PARSER_ERROR( "Invalid coordinate" ); throw XML_PARSER_ERROR( "Invalid coordinate" );
@ -82,7 +87,8 @@ ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
{ {
int digits = post_fraction - pre_fraction; int digits = post_fraction - pre_fraction;
// adjust the number of digits if necessary as we cannot handle anything smaller than nanometers (rounding) // adjust the number of digits if necessary as we cannot handle anything smaller than
// nanometers (rounding).
if( (unsigned) digits > DIVIDERS_MAX_IDX ) if( (unsigned) digits > DIVIDERS_MAX_IDX )
{ {
int diff = digits - DIVIDERS_MAX_IDX; int diff = digits - DIVIDERS_MAX_IDX;
@ -204,8 +210,8 @@ ECOORD Convert<ECOORD>( const wxString& aCoord )
/** /**
* Function parseRequiredAttribute * Parse \a aAttribute of the XML node \a aNode.
* parsese the aAttribute of the XML node aNode. *
* @param aNode is the node whose attribute will be parsed. * @param aNode is the node whose attribute will be parsed.
* @param aAttribute is the attribute that will be parsed. * @param aAttribute is the attribute that will be parsed.
* @throw XML_PARSER_ERROR - exception thrown if the required attribute is missing * @throw XML_PARSER_ERROR - exception thrown if the required attribute is missing
@ -224,8 +230,8 @@ T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
/** /**
* Function parseOptionalAttribute * Parse option \a aAttribute of the XML node \a aNode.
* parses the aAttribute of the XML node aNode. *
* @param aNode is the node whose attribute will be parsed. * @param aNode is the node whose attribute will be parsed.
* @param aAttribute is the attribute that will be parsed. * @param aAttribute is the attribute that will be parsed.
* @return OPTIONAL_XML_ATTRIBUTE<T> - an optional XML attribute, parsed as the specified type if * @return OPTIONAL_XML_ATTRIBUTE<T> - an optional XML attribute, parsed as the specified type if
@ -610,6 +616,43 @@ wxSize ETEXT::ConvertSize() const
} }
EFRAME::EFRAME( wxXmlNode* aFrameNode )
{
/*
* <!ELEMENT frame EMPTY>
* <!ATTLIST frame
* x1 %Coord; #REQUIRED
* y1 %Coord; #REQUIRED
* x2 %Coord; #REQUIRED
* y2 %Coord; #REQUIRED
* columns %Int; #REQUIRED
* rows %Int; #REQUIRED
* layer %Layer; #REQUIRED
* border-left %Bool; "yes"
* border-top %Bool; "yes"
* border-right %Bool; "yes"
* border-bottom %Bool; "yes"
* >
*/
border_left = true;
border_top = true;
border_right = true;
border_bottom = true;
x1 = parseRequiredAttribute<ECOORD>( aFrameNode, "x1" );
y1 = parseRequiredAttribute<ECOORD>( aFrameNode, "y1" );
x2 = parseRequiredAttribute<ECOORD>( aFrameNode, "x2" );
y2 = parseRequiredAttribute<ECOORD>( aFrameNode, "y2" );
columns = parseRequiredAttribute<int>( aFrameNode, "columns" );
rows = parseRequiredAttribute<int>( aFrameNode, "rows" );
layer = parseRequiredAttribute<int>( aFrameNode, "layer" );
border_left = parseOptionalAttribute<bool>( aFrameNode, "border-left" );
border_top = parseOptionalAttribute<bool>( aFrameNode, "border-top" );
border_right = parseOptionalAttribute<bool>( aFrameNode, "border-right" );
border_bottom = parseOptionalAttribute<bool>( aFrameNode, "border-bottom" );
}
EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad ) EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad )
{ {
// #REQUIRED says DTD, throw exception if not found // #REQUIRED says DTD, throw exception if not found
@ -753,7 +796,8 @@ EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
isolate %Dimension; #IMPLIED -- only in <signal> or <package> context -- isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
orphans %Bool; "no" -- only in <signal> context -- orphans %Bool; "no" -- only in <signal> context --
thermals %Bool; "yes" -- only in <signal> context -- thermals %Bool; "yes" -- only in <signal> context --
rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in <package> context -- rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in
<package> context --
> >
*/ */

View File

@ -4,6 +4,7 @@
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 CERN * Copyright (C) 2017 CERN
*
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -69,9 +70,9 @@ static inline wxXmlNode* getChildrenNodes( NODE_MAP& aMap, const wxString& aName
struct XML_PARSER_ERROR : std::runtime_error struct XML_PARSER_ERROR : std::runtime_error
{ {
/** /**
* Constructor XML_PARSER_ERROR * Build an XML error by just calling its parent class constructor, std::runtime_error, with
* build an XML error by just calling its parent class constructor, std::runtime_error, with
* the passed message. * the passed message.
*
* @param aMessage is an explanatory error message. * @param aMessage is an explanatory error message.
*/ */
XML_PARSER_ERROR( const wxString& aMessage ) noexcept : XML_PARSER_ERROR( const wxString& aMessage ) noexcept :
@ -669,6 +670,27 @@ struct ETEXT
}; };
/**
* Parse an Eagle frame element.
*/
struct EFRAME
{
ECOORD x1;
ECOORD y1;
ECOORD x2;
ECOORD y2;
int columns;
int rows;
int layer;
opt_bool border_left;
opt_bool border_top;
opt_bool border_right;
opt_bool border_bottom;
EFRAME( wxXmlNode* aFrameNode );
};
/// Structure holding common properties for through-hole and SMD pads /// Structure holding common properties for through-hole and SMD pads
struct EPAD_COMMON struct EPAD_COMMON
{ {
@ -997,11 +1019,11 @@ struct ECONNECT
struct EDEVICE struct EDEVICE
{ {
/* /*
<!ELEMENT device (connects?, technologies?)> * <!ELEMENT device (connects?, technologies?)>
<!ATTLIST device * <!ATTLIST device
name %String; "" * name %String; ""
package %String; #IMPLIED * package %String; #IMPLIED
> * >
*/ */
wxString name; wxString name;
opt_wxString package; opt_wxString package;

View File

@ -195,7 +195,6 @@ void SCH_EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
* </layers> * </layers>
*/ */
if( elayer.name == "Nets" ) if( elayer.name == "Nets" )
{ {
m_layerMap[elayer.number] = LAYER_WIRE; m_layerMap[elayer.number] = LAYER_WIRE;
@ -515,13 +514,14 @@ void SCH_EAGLE_PLUGIN::countNets( wxXmlNode* aSchematicNode )
{ {
// Map all children into a readable dictionary // Map all children into a readable dictionary
NODE_MAP schematicChildren = MapChildren( aSchematicNode ); NODE_MAP schematicChildren = MapChildren( aSchematicNode );
// Loop through all the sheets
// Loop through all the sheets
wxXmlNode* sheetNode = getChildrenNodes( schematicChildren, "sheets" ); wxXmlNode* sheetNode = getChildrenNodes( schematicChildren, "sheets" );
while( sheetNode ) while( sheetNode )
{ {
NODE_MAP sheetChildren = MapChildren( sheetNode ); NODE_MAP sheetChildren = MapChildren( sheetNode );
// Loop through all nets // Loop through all nets
// From the DTD: "Net is an electrical connection in a schematic." // From the DTD: "Net is an electrical connection in a schematic."
wxXmlNode* netNode = getChildrenNodes( sheetChildren, "nets" ); wxXmlNode* netNode = getChildrenNodes( sheetChildren, "nets" );
@ -548,9 +548,9 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
{ {
// Map all children into a readable dictionary // Map all children into a readable dictionary
NODE_MAP schematicChildren = MapChildren( aSchematicNode ); NODE_MAP schematicChildren = MapChildren( aSchematicNode );
auto partNode = getChildrenNodes( schematicChildren, "parts" ); wxXmlNode* partNode = getChildrenNodes( schematicChildren, "parts" );
auto libraryNode = getChildrenNodes( schematicChildren, "libraries" ); wxXmlNode* libraryNode = getChildrenNodes( schematicChildren, "libraries" );
auto sheetNode = getChildrenNodes( schematicChildren, "sheets" ); wxXmlNode* sheetNode = getChildrenNodes( schematicChildren, "sheets" );
if( !partNode || !libraryNode || !sheetNode ) if( !partNode || !libraryNode || !sheetNode )
return; return;
@ -630,7 +630,6 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
} }
} }
// Handle the missing component units that need to be instantiated // Handle the missing component units that need to be instantiated
// to create the missing implicit connections // to create the missing implicit connections
@ -716,6 +715,17 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
filenameField.SetText( fn ); filenameField.SetText( fn );
wxFileName fileName( fn ); wxFileName fileName( fn );
m_currentSheet->GetScreen()->SetFileName( fileName.GetFullPath() ); m_currentSheet->GetScreen()->SetFileName( fileName.GetFullPath() );
m_currentSheet->AutoplaceFields( m_currentSheet->GetScreen(), true );
// Loop through all of the symbol instances.
wxXmlNode* instanceNode = getChildrenNodes( sheetChildren, "instances" );
while( instanceNode )
{
loadInstance( instanceNode );
instanceNode = instanceNode->GetNext();
}
// Loop through all buses // Loop through all buses
// From the DTD: "Buses receive names which determine which signals they include. // From the DTD: "Buses receive names which determine which signals they include.
@ -755,15 +765,6 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
adjustNetLabels(); // needs to be called before addBusEntries() adjustNetLabels(); // needs to be called before addBusEntries()
addBusEntries(); addBusEntries();
// Loop through all instances
wxXmlNode* instanceNode = getChildrenNodes( sheetChildren, "instances" );
while( instanceNode )
{
loadInstance( instanceNode );
instanceNode = instanceNode->GetNext();
}
/* moduleinst is a design block definition and is an EagleCad 8 feature, /* moduleinst is a design block definition and is an EagleCad 8 feature,
* *
* // Loop through all moduleinsts * // Loop through all moduleinsts
@ -790,6 +791,15 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
{ {
m_currentSheet->GetScreen()->Append( loadWire( plainNode ) ); m_currentSheet->GetScreen()->Append( loadWire( plainNode ) );
} }
else if( nodeName == "frame" )
{
std::vector<SCH_LINE*> lines;
loadFrame( plainNode, lines );
for( SCH_LINE* line : lines )
m_currentSheet->GetScreen()->Append( line );
}
plainNode = plainNode->GetNext(); plainNode = plainNode->GetNext();
} }
@ -845,6 +855,41 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
} }
void SCH_EAGLE_PLUGIN::loadFrame( wxXmlNode* aFrameNode, std::vector<SCH_LINE*>& aLines )
{
EFRAME eframe( aFrameNode );
wxPoint corner1( eframe.x1.ToSchUnits(), -eframe.y1.ToSchUnits() );
wxPoint corner3( eframe.x2.ToSchUnits(), -eframe.y2.ToSchUnits() );
wxPoint corner2( corner3.x, corner1.y );
wxPoint corner4( corner1.x, corner3.y );
SCH_LINE* line = new SCH_LINE();
line->SetLineStyle( PLOT_DASH_TYPE::SOLID );
line->SetStartPoint( corner1 );
line->SetEndPoint( corner2 );
aLines.push_back( line );
line = new SCH_LINE();
line->SetLineStyle( PLOT_DASH_TYPE::SOLID );
line->SetStartPoint( corner2 );
line->SetEndPoint( corner3 );
aLines.push_back( line );
line = new SCH_LINE();
line->SetLineStyle( PLOT_DASH_TYPE::SOLID );
line->SetStartPoint( corner3 );
line->SetEndPoint( corner4 );
aLines.push_back( line );
line = new SCH_LINE();
line->SetLineStyle( PLOT_DASH_TYPE::SOLID );
line->SetStartPoint( corner4 );
line->SetEndPoint( corner1 );
aLines.push_back( line );
}
void SCH_EAGLE_PLUGIN::loadSegments( void SCH_EAGLE_PLUGIN::loadSegments(
wxXmlNode* aSegmentsNode, const wxString& netName, const wxString& aNetClass ) wxXmlNode* aSegmentsNode, const wxString& netName, const wxString& aNetClass )
{ {
@ -937,8 +982,9 @@ void SCH_EAGLE_PLUGIN::loadSegments(
segmentAttribute = segmentAttribute->GetNext(); segmentAttribute = segmentAttribute->GetNext();
} }
// Add a small label to the net segment if it hasn't been labeled already // Add a small label to the net segment if it hasn't been labeled already or is not
// this preserves the named net feature of Eagle schematics. // connect to a power symbol with a pin on the same net. This preserves the named net
// feature of Eagle schematics.
if( !labelled && firstWire ) if( !labelled && firstWire )
{ {
std::unique_ptr<SCH_TEXT> label; std::unique_ptr<SCH_TEXT> label;
@ -953,7 +999,7 @@ void SCH_EAGLE_PLUGIN::loadSegments(
{ {
label->SetPosition( firstWire->GetStartPoint() ); label->SetPosition( firstWire->GetStartPoint() );
label->SetText( escapeName( netName ) ); label->SetText( escapeName( netName ) );
label->SetTextSize( wxSize( Mils2iu( 10 ), Mils2iu( 10 ) ) ); label->SetTextSize( wxSize( Mils2iu( 40 ), Mils2iu( 40 ) ) );
label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT ); label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
screen->Append( label.release() ); screen->Append( label.release() );
} }
@ -1012,14 +1058,24 @@ SCH_TEXT* SCH_EAGLE_PLUGIN::loadLabel( wxXmlNode* aLabelNode, const wxString& aN
bool global = m_netCounts[aNetName] > 1; bool global = m_netCounts[aNetName] > 1;
std::unique_ptr<SCH_TEXT> label; std::unique_ptr<SCH_TEXT> label;
wxSize textSize;
if( global ) if( global )
{
label = std::make_unique<SCH_GLOBALLABEL>(); label = std::make_unique<SCH_GLOBALLABEL>();
textSize = wxSize( KiROUND( elabel.size.ToSchUnits() * 0.75 ),
KiROUND( elabel.size.ToSchUnits() * 0.75 ) );
}
else else
{
label = std::make_unique<SCH_LABEL>(); label = std::make_unique<SCH_LABEL>();
textSize = wxSize( KiROUND( elabel.size.ToSchUnits() * 0.85 ),
KiROUND( elabel.size.ToSchUnits() * 0.85 ) );
}
label->SetPosition( elabelpos ); label->SetPosition( elabelpos );
label->SetText( escapeName( elabel.netname ) ); label->SetText( escapeName( elabel.netname ) );
label->SetTextSize( wxSize( elabel.size.ToSchUnits(), elabel.size.ToSchUnits() ) ); label->SetTextSize( textSize );
label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT ); label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
if( elabel.rot ) if( elabel.rot )
@ -1514,6 +1570,18 @@ bool SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_P
{ {
aPart->AddDrawItem( loadSymbolWire( aPart, currentNode, aGateNumber ) ); aPart->AddDrawItem( loadSymbolWire( aPart, currentNode, aGateNumber ) );
} }
else if( nodeName == "frame" )
{
std::vector<LIB_ITEM*> frameItems;
loadFrame( currentNode, frameItems );
for( LIB_ITEM* item : frameItems )
{
item->SetParent( aPart.get() );
aPart->AddDrawItem( item );
}
}
/* /*
* else if( nodeName == "description" ) * else if( nodeName == "description" )
@ -1522,9 +1590,6 @@ bool SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_P
* else if( nodeName == "dimension" ) * else if( nodeName == "dimension" )
* { * {
* } * }
* else if( nodeName == "frame" )
* {
* }
*/ */
currentNode = currentNode->GetNext(); currentNode = currentNode->GetNext();
@ -1568,6 +1633,7 @@ LIB_RECTANGLE* SCH_EAGLE_PLUGIN::loadSymbolRectangle(
rectangle->SetEnd( wxPoint( rect.x2.ToSchUnits(), rect.y2.ToSchUnits() ) ); rectangle->SetEnd( wxPoint( rect.x2.ToSchUnits(), rect.y2.ToSchUnits() ) );
rectangle->SetUnit( aGateNumber ); rectangle->SetUnit( aGateNumber );
// Eagle rectangles are filled by definition. // Eagle rectangles are filled by definition.
rectangle->SetFillMode( FILL_TYPE::FILLED_SHAPE ); rectangle->SetFillMode( FILL_TYPE::FILLED_SHAPE );
@ -1667,8 +1733,6 @@ LIB_POLYLINE* SCH_EAGLE_PLUGIN::loadSymbolPolyLine(
EPOLYGON epoly( aPolygonNode ); EPOLYGON epoly( aPolygonNode );
wxXmlNode* vertex = aPolygonNode->GetChildren(); wxXmlNode* vertex = aPolygonNode->GetChildren();
wxPoint pt; wxPoint pt;
while( vertex ) while( vertex )
@ -1723,27 +1787,21 @@ LIB_PIN* SCH_EAGLE_PLUGIN::loadPin(
break; break;
} }
pin->SetLength( Mils2iu( 300 ) ); // Default pin length when not defined.
if( aEPin->length ) if( aEPin->length )
{ {
wxString length = aEPin->length.Get(); wxString length = aEPin->length.Get();
if( length == "short" ) if( length == "short" )
{
pin->SetLength( Mils2iu( 100 ) ); pin->SetLength( Mils2iu( 100 ) );
}
else if( length == "middle" ) else if( length == "middle" )
{
pin->SetLength( Mils2iu( 200 ) ); pin->SetLength( Mils2iu( 200 ) );
}
else if( length == "long" ) else if( length == "long" )
{
pin->SetLength( Mils2iu( 300 ) ); pin->SetLength( Mils2iu( 300 ) );
}
else if( length == "point" ) else if( length == "point" )
{
pin->SetLength( Mils2iu( 0 ) ); pin->SetLength( Mils2iu( 0 ) );
} }
}
// emulate the visibility of pin elements // emulate the visibility of pin elements
if( aEPin->visible ) if( aEPin->visible )
@ -1818,13 +1876,49 @@ LIB_TEXT* SCH_EAGLE_PLUGIN::loadSymbolText(
} }
void SCH_EAGLE_PLUGIN::loadFrame( wxXmlNode* aFrameNode, std::vector<LIB_ITEM*>& aItems )
{
EFRAME eframe( aFrameNode );
wxPoint corner1( eframe.x1.ToSchUnits(), eframe.y1.ToSchUnits() );
wxPoint corner3( eframe.x2.ToSchUnits(), eframe.y2.ToSchUnits() );
wxPoint corner2( corner3.x, corner1.y );
wxPoint corner4( corner1.x, corner3.y );
LIB_POLYLINE* lines = new LIB_POLYLINE( nullptr );
lines->AddPoint( corner1 );
lines->AddPoint( corner2 );
lines->AddPoint( corner3 );
lines->AddPoint( corner4 );
lines->AddPoint( corner1 );
aItems.push_back( lines );
}
SCH_TEXT* SCH_EAGLE_PLUGIN::loadPlainText( wxXmlNode* aSchText ) SCH_TEXT* SCH_EAGLE_PLUGIN::loadPlainText( wxXmlNode* aSchText )
{ {
std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>(); std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
ETEXT etext = ETEXT( aSchText ); ETEXT etext = ETEXT( aSchText );
const wxString& thetext = aSchText->GetNodeContent(); const wxString& thetext = aSchText->GetNodeContent();
schtext->SetText( thetext.IsEmpty() ? "\" \"" : escapeName( thetext ) );
wxString adjustedText;
wxStringTokenizer tokenizer( thetext, "\r\n" );
// Strip the whitespace from both ends of each line.
while( tokenizer.HasMoreTokens() )
{
wxString tmp = tokenizer.GetNextToken().Trim();
tmp = tmp.Trim( false );
if( tokenizer.HasMoreTokens() )
tmp += wxT( "\n" );
adjustedText += tmp;
}
schtext->SetText( adjustedText.IsEmpty() ? "\" \"" : escapeName( adjustedText ) );
schtext->SetPosition( wxPoint( etext.x.ToSchUnits(), -etext.y.ToSchUnits() ) ); schtext->SetPosition( wxPoint( etext.x.ToSchUnits(), -etext.y.ToSchUnits() ) );
loadTextAttributes( schtext.get(), etext ); loadTextAttributes( schtext.get(), etext );
schtext->SetItalic( false ); schtext->SetItalic( false );
@ -1876,8 +1970,11 @@ void SCH_EAGLE_PLUGIN::adjustNetLabels()
// Sort the intersection points to speed up the search process // Sort the intersection points to speed up the search process
std::sort( m_wireIntersections.begin(), m_wireIntersections.end() ); std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
auto onIntersection = [&]( const VECTOR2I& aPos ) { auto onIntersection =
return std::binary_search( m_wireIntersections.begin(), m_wireIntersections.end(), aPos ); [&]( const VECTOR2I& aPos )
{
return std::binary_search( m_wireIntersections.begin(),
m_wireIntersections.end(), aPos );
}; };
for( auto& segDesc : m_segments ) for( auto& segDesc : m_segments )
@ -1948,6 +2045,7 @@ bool SCH_EAGLE_PLUGIN::CheckHeader( const wxString& aFileName )
tempFile.Open( aFileName ); tempFile.Open( aFileName );
wxString firstline; wxString firstline;
// read the first line // read the first line
firstline = tempFile.GetFirstLine(); firstline = tempFile.GetFirstLine();
wxString secondline = tempFile.GetNextLine(); wxString secondline = tempFile.GetNextLine();
@ -1992,12 +2090,12 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
if( bus->GetLayer() != LAYER_BUS ) if( bus->GetLayer() != LAYER_BUS )
continue; continue;
wxPoint busstart = bus->GetStartPoint(); wxPoint busstart = bus->GetStartPoint();
wxPoint busend = bus->GetEndPoint(); wxPoint busend = bus->GetEndPoint();
auto it2 = it1; auto it2 = it1;
++it2; ++it2;
for( ; it2 != m_currentSheet->GetScreen()->Items().end(); ++it2 ) for( ; it2 != m_currentSheet->GetScreen()->Items().end(); ++it2 )
{ {
SCH_LINE* line = static_cast<SCH_LINE*>( *it2 ); SCH_LINE* line = static_cast<SCH_LINE*>( *it2 );
@ -2117,7 +2215,8 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
lineend + wxPoint( 0, -100 ), busstart, busend, 0 ) ) lineend + wxPoint( 0, -100 ), busstart, busend, 0 ) )
{ {
SCH_BUS_WIRE_ENTRY* busEntry = SCH_BUS_WIRE_ENTRY* busEntry =
new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ), true ); new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ),
true );
busEntry->SetFlags( IS_NEW ); busEntry->SetFlags( IS_NEW );
m_currentSheet->GetScreen()->Append( busEntry ); m_currentSheet->GetScreen()->Append( busEntry );
moveLabels( line, lineend + wxPoint( -100, 0 ) ); moveLabels( line, lineend + wxPoint( -100, 0 ) );
@ -2257,7 +2356,8 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
lineend + wxPoint( -100, 0 ), busstart, busend, 0 ) ) lineend + wxPoint( -100, 0 ), busstart, busend, 0 ) )
{ {
SCH_BUS_WIRE_ENTRY* busEntry = SCH_BUS_WIRE_ENTRY* busEntry =
new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ), true ); new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ),
true );
busEntry->SetFlags( IS_NEW ); busEntry->SetFlags( IS_NEW );
m_currentSheet->GetScreen()->Append( busEntry ); m_currentSheet->GetScreen()->Append( busEntry );
moveLabels( line, lineend + wxPoint( 0, -100 ) ); moveLabels( line, lineend + wxPoint( 0, -100 ) );
@ -2371,7 +2471,8 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
{ {
if( wirevector.y > 0 ) if( wirevector.y > 0 )
{ {
SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart, true ); SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart,
true );
busEntry->SetFlags( IS_NEW ); busEntry->SetFlags( IS_NEW );
m_currentSheet->GetScreen()->Append( busEntry ); m_currentSheet->GetScreen()->Append( busEntry );
@ -2552,18 +2653,20 @@ void SCH_EAGLE_PLUGIN::addImplicitConnections(
bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
// Create a global net label only if there are no other wires/pins attached // Create a global net label only if there are no other wires/pins attached
if( pinInUnit && !checkConnections( aComponent, pin ) ) if( pinInUnit )
{
if( !checkConnections( aComponent, pin ) )
{ {
// Create a net label to force the net name on the pin // Create a net label to force the net name on the pin
SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL; SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) ); netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) );
netLabel->SetText( extractNetName( pin->GetName() ) ); netLabel->SetText( extractNetName( pin->GetName() ) );
netLabel->SetTextSize( wxSize( Mils2iu( 10 ), Mils2iu( 10 ) ) ); netLabel->SetTextSize( wxSize( Mils2iu( 40 ), Mils2iu( 40 ) ) );
netLabel->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT ); netLabel->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
aScreen->Append( netLabel ); aScreen->Append( netLabel );
} }
}
else if( !pinInUnit && aUpdateSet ) else if( aUpdateSet )
{ {
// Found a pin creating implicit connection information in another unit. // Found a pin creating implicit connection information in another unit.
// Such units will be instantiated if they do not appear in another sheet and // Such units will be instantiated if they do not appear in another sheet and
@ -2574,25 +2677,37 @@ void SCH_EAGLE_PLUGIN::addImplicitConnections(
} }
} }
if( aUpdateSet ) if( aUpdateSet && aComponent->GetPartRef()->GetUnitCount() > 1 )
{ {
auto cmpIt = m_missingCmps.find( reference ); auto cmpIt = m_missingCmps.find( reference );
// Set the flag indicating this unit has been processed // The first unit found has always already been processed.
if( cmpIt != m_missingCmps.end() ) if( cmpIt == m_missingCmps.end() )
{
EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
entry.cmp = aComponent;
entry.units.emplace( unit, false );
}
else
{
// Set the flag indicating this unit has been processed.
cmpIt->second.units[unit] = false; cmpIt->second.units[unit] = false;
}
// Save the units that need later processing if( !missingUnits.empty() ) // Save the units that need later processing
else if( !missingUnits.empty() )
{ {
EAGLE_MISSING_CMP& entry = m_missingCmps[reference]; EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
entry.cmp = aComponent; entry.cmp = aComponent;
// Add units that haven't already been processed.
for( int i : missingUnits ) for( int i : missingUnits )
{
if( entry.units.find( i ) != entry.units.end() )
entry.units.emplace( i, true ); entry.units.emplace( i, true );
} }
} }
} }
}
wxString SCH_EAGLE_PLUGIN::fixSymbolName( const wxString& aName ) wxString SCH_EAGLE_PLUGIN::fixSymbolName( const wxString& aName )

View File

@ -127,6 +127,7 @@ private:
SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName ); SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName );
SCH_JUNCTION* loadJunction( wxXmlNode* aJunction ); SCH_JUNCTION* loadJunction( wxXmlNode* aJunction );
SCH_TEXT* loadPlainText( wxXmlNode* aSchText ); SCH_TEXT* loadPlainText( wxXmlNode* aSchText );
void loadFrame( wxXmlNode* aFrameNode, std::vector<SCH_LINE*>& aLines );
bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_PART>& aPart, bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_PART>& aPart,
EDEVICE* aDevice, int aGateNumber, const wxString& aGateName ); EDEVICE* aDevice, int aGateNumber, const wxString& aGateName );
@ -142,6 +143,7 @@ private:
int aGateNumber ); int aGateNumber );
LIB_TEXT* loadSymbolText( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aLibText, LIB_TEXT* loadSymbolText( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aLibText,
int aGateNumber ); int aGateNumber );
void loadFrame( wxXmlNode* aFrameNode, std::vector<LIB_ITEM*>& aLines );
void loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const; void loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const;
void loadFieldAttributes( LIB_FIELD* aField, const LIB_TEXT* aText ) const; void loadFieldAttributes( LIB_FIELD* aField, const LIB_TEXT* aText ) const;
@ -179,6 +181,8 @@ private:
*/ */
void addImplicitConnections( SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen, bool aUpdateSet ); void addImplicitConnections( SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen, bool aUpdateSet );
bool netHasPowerDriver( SCH_LINE* aLine, const wxString& aNetName ) const;
/** /**
* Fix invalid characters in Eagle symbol names. * Fix invalid characters in Eagle symbol names.
* *
@ -244,6 +248,9 @@ private:
///< Segments representing wires for intersection checking ///< Segments representing wires for intersection checking
std::vector<SEG_DESC> m_segments; std::vector<SEG_DESC> m_segments;
///< Nets as defined in the <nets> sections of an Eagle schematic file.
std::map<wxString, ENET> m_nets;
///< Positions of pins and wire endings mapped to its parent ///< Positions of pins and wire endings mapped to its parent
std::map<wxPoint, std::set<const EDA_ITEM*>> m_connPoints; std::map<wxPoint, std::set<const EDA_ITEM*>> m_connPoints;
}; };