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.
*
* 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.
*
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
*
* 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 )
{
// 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 unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1;
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] == '-' );
// %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3 digits
int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction, &post_fraction );
// %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3
// digits.
int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction,
&post_fraction );
if( ret == 0 )
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;
// 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 )
{
int diff = digits - DIVIDERS_MAX_IDX;
@ -204,8 +210,8 @@ ECOORD Convert<ECOORD>( const wxString& aCoord )
/**
* Function parseRequiredAttribute
* parsese the aAttribute of the XML node aNode.
* Parse \a aAttribute of the XML node \a aNode.
*
* @param aNode is the node whose attribute will be parsed.
* @param aAttribute is the attribute that will be parsed.
* @throw XML_PARSER_ERROR - exception thrown if the required attribute is missing
@ -224,12 +230,12 @@ T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
/**
* Function parseOptionalAttribute
* parses the aAttribute of the XML node aNode.
* Parse option \a aAttribute of the XML node \a aNode.
*
* @param aNode is the node whose attribute 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
* found.
* found.
*/
template<typename T>
OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute )
@ -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 )
{
// #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 --
orphans %Bool; "no" -- 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 --
>
*/
@ -996,12 +1040,12 @@ ECONNECT::ECONNECT( wxXmlNode* aConnect )
EDEVICE::EDEVICE( wxXmlNode* aDevice )
{
/*
<!ELEMENT device (connects?, technologies?)>
<!ATTLIST device
name %String; ""
package %String; #IMPLIED
>
*/
<!ELEMENT device (connects?, technologies?)>
<!ATTLIST device
name %String; ""
package %String; #IMPLIED
>
*/
name = parseRequiredAttribute<wxString>( aDevice, "name" );
opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
@ -1026,13 +1070,13 @@ EDEVICE::EDEVICE( wxXmlNode* aDevice )
EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
{
/*
<!ELEMENT deviceset (description?, gates, devices)>
<!ATTLIST deviceset
<!ELEMENT deviceset (description?, gates, devices)>
<!ATTLIST deviceset
name %String; #REQUIRED
prefix %String; ""
uservalue %Bool; "no"
>
*/
*/
name = parseRequiredAttribute<wxString>(aDeviceSet, "name");
prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );

View File

@ -4,6 +4,7 @@
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 CERN
*
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
*
* 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
{
/**
* 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.
*
* @param aMessage is an explanatory error message.
*/
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
struct EPAD_COMMON
{
@ -997,12 +1019,12 @@ struct ECONNECT
struct EDEVICE
{
/*
<!ELEMENT device (connects?, technologies?)>
<!ATTLIST device
name %String; ""
package %String; #IMPLIED
>
*/
* <!ELEMENT device (connects?, technologies?)>
* <!ATTLIST device
* name %String; ""
* package %String; #IMPLIED
* >
*/
wxString name;
opt_wxString package;

View File

@ -195,7 +195,6 @@ void SCH_EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
* </layers>
*/
if( elayer.name == "Nets" )
{
m_layerMap[elayer.number] = LAYER_WIRE;
@ -515,13 +514,14 @@ void SCH_EAGLE_PLUGIN::countNets( wxXmlNode* aSchematicNode )
{
// Map all children into a readable dictionary
NODE_MAP schematicChildren = MapChildren( aSchematicNode );
// Loop through all the sheets
// Loop through all the sheets
wxXmlNode* sheetNode = getChildrenNodes( schematicChildren, "sheets" );
while( sheetNode )
{
NODE_MAP sheetChildren = MapChildren( sheetNode );
// Loop through all nets
// From the DTD: "Net is an electrical connection in a schematic."
wxXmlNode* netNode = getChildrenNodes( sheetChildren, "nets" );
@ -547,10 +547,10 @@ void SCH_EAGLE_PLUGIN::countNets( wxXmlNode* aSchematicNode )
void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
{
// Map all children into a readable dictionary
NODE_MAP schematicChildren = MapChildren( aSchematicNode );
auto partNode = getChildrenNodes( schematicChildren, "parts" );
auto libraryNode = getChildrenNodes( schematicChildren, "libraries" );
auto sheetNode = getChildrenNodes( schematicChildren, "sheets" );
NODE_MAP schematicChildren = MapChildren( aSchematicNode );
wxXmlNode* partNode = getChildrenNodes( schematicChildren, "parts" );
wxXmlNode* libraryNode = getChildrenNodes( schematicChildren, "libraries" );
wxXmlNode* sheetNode = getChildrenNodes( schematicChildren, "sheets" );
if( !partNode || !libraryNode || !sheetNode )
return;
@ -630,7 +630,6 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
}
}
// Handle the missing component units that need to be instantiated
// to create the missing implicit connections
@ -716,6 +715,17 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
filenameField.SetText( fn );
wxFileName fileName( fn );
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
// 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()
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,
*
* // Loop through all moduleinsts
@ -790,6 +791,15 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
{
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();
}
@ -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(
wxXmlNode* aSegmentsNode, const wxString& netName, const wxString& aNetClass )
{
@ -937,8 +982,9 @@ void SCH_EAGLE_PLUGIN::loadSegments(
segmentAttribute = segmentAttribute->GetNext();
}
// Add a small label to the net segment if it hasn't been labeled already
// this preserves the named net feature of Eagle schematics.
// Add a small label to the net segment if it hasn't been labeled already or is not
// connect to a power symbol with a pin on the same net. This preserves the named net
// feature of Eagle schematics.
if( !labelled && firstWire )
{
std::unique_ptr<SCH_TEXT> label;
@ -953,7 +999,7 @@ void SCH_EAGLE_PLUGIN::loadSegments(
{
label->SetPosition( firstWire->GetStartPoint() );
label->SetText( escapeName( netName ) );
label->SetTextSize( wxSize( Mils2iu( 10 ), Mils2iu( 10 ) ) );
label->SetTextSize( wxSize( Mils2iu( 40 ), Mils2iu( 40 ) ) );
label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
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;
std::unique_ptr<SCH_TEXT> label;
wxSize textSize;
if( global )
{
label = std::make_unique<SCH_GLOBALLABEL>();
textSize = wxSize( KiROUND( elabel.size.ToSchUnits() * 0.75 ),
KiROUND( elabel.size.ToSchUnits() * 0.75 ) );
}
else
{
label = std::make_unique<SCH_LABEL>();
textSize = wxSize( KiROUND( elabel.size.ToSchUnits() * 0.85 ),
KiROUND( elabel.size.ToSchUnits() * 0.85 ) );
}
label->SetPosition( elabelpos );
label->SetText( escapeName( elabel.netname ) );
label->SetTextSize( wxSize( elabel.size.ToSchUnits(), elabel.size.ToSchUnits() ) );
label->SetTextSize( textSize );
label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
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 ) );
}
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" )
@ -1522,9 +1590,6 @@ bool SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_P
* else if( nodeName == "dimension" )
* {
* }
* else if( nodeName == "frame" )
* {
* }
*/
currentNode = currentNode->GetNext();
@ -1568,6 +1633,7 @@ LIB_RECTANGLE* SCH_EAGLE_PLUGIN::loadSymbolRectangle(
rectangle->SetEnd( wxPoint( rect.x2.ToSchUnits(), rect.y2.ToSchUnits() ) );
rectangle->SetUnit( aGateNumber );
// Eagle rectangles are filled by definition.
rectangle->SetFillMode( FILL_TYPE::FILLED_SHAPE );
@ -1667,9 +1733,7 @@ LIB_POLYLINE* SCH_EAGLE_PLUGIN::loadSymbolPolyLine(
EPOLYGON epoly( aPolygonNode );
wxXmlNode* vertex = aPolygonNode->GetChildren();
wxPoint pt;
wxPoint pt;
while( vertex )
{
@ -1723,26 +1787,20 @@ LIB_PIN* SCH_EAGLE_PLUGIN::loadPin(
break;
}
pin->SetLength( Mils2iu( 300 ) ); // Default pin length when not defined.
if( aEPin->length )
{
wxString length = aEPin->length.Get();
if( length == "short" )
{
pin->SetLength( Mils2iu( 100 ) );
}
else if( length == "middle" )
{
pin->SetLength( Mils2iu( 200 ) );
}
else if( length == "long" )
{
pin->SetLength( Mils2iu( 300 ) );
}
else if( length == "point" )
{
pin->SetLength( Mils2iu( 0 ) );
}
}
// emulate the visibility of pin elements
@ -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 )
{
std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
ETEXT etext = ETEXT( aSchText );
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() ) );
loadTextAttributes( schtext.get(), etext );
schtext->SetItalic( false );
@ -1876,9 +1970,12 @@ void SCH_EAGLE_PLUGIN::adjustNetLabels()
// Sort the intersection points to speed up the search process
std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
auto onIntersection = [&]( const VECTOR2I& aPos ) {
return std::binary_search( m_wireIntersections.begin(), m_wireIntersections.end(), aPos );
};
auto onIntersection =
[&]( const VECTOR2I& aPos )
{
return std::binary_search( m_wireIntersections.begin(),
m_wireIntersections.end(), aPos );
};
for( auto& segDesc : m_segments )
{
@ -1948,6 +2045,7 @@ bool SCH_EAGLE_PLUGIN::CheckHeader( const wxString& aFileName )
tempFile.Open( aFileName );
wxString firstline;
// read the first line
firstline = tempFile.GetFirstLine();
wxString secondline = tempFile.GetNextLine();
@ -1992,12 +2090,12 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
if( bus->GetLayer() != LAYER_BUS )
continue;
wxPoint busstart = bus->GetStartPoint();
wxPoint busend = bus->GetEndPoint();
auto it2 = it1;
++it2;
for( ; it2 != m_currentSheet->GetScreen()->Items().end(); ++it2 )
{
SCH_LINE* line = static_cast<SCH_LINE*>( *it2 );
@ -2009,7 +2107,7 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
wxPoint linestart = line->GetStartPoint();
wxPoint lineend = line->GetEndPoint();
// Test for horizontal wire and vertical bus
// Test for horizontal wire and vertical bus
if( linestart.y == lineend.y && busstart.x == busend.x )
{
if( TestSegmentHit( linestart, busstart, busend, 0 ) )
@ -2117,7 +2215,8 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
lineend + wxPoint( 0, -100 ), busstart, busend, 0 ) )
{
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 );
m_currentSheet->GetScreen()->Append( busEntry );
moveLabels( line, lineend + wxPoint( -100, 0 ) );
@ -2257,7 +2356,8 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
lineend + wxPoint( -100, 0 ), busstart, busend, 0 ) )
{
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 );
m_currentSheet->GetScreen()->Append( busEntry );
moveLabels( line, lineend + wxPoint( 0, -100 ) );
@ -2371,7 +2471,8 @@ void SCH_EAGLE_PLUGIN::addBusEntries()
{
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 );
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
// Create a global net label only if there are no other wires/pins attached
if( pinInUnit && !checkConnections( aComponent, pin ) )
if( pinInUnit )
{
// Create a net label to force the net name on the pin
SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) );
netLabel->SetText( extractNetName( pin->GetName() ) );
netLabel->SetTextSize( wxSize( Mils2iu( 10 ), Mils2iu( 10 ) ) );
netLabel->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
aScreen->Append( netLabel );
if( !checkConnections( aComponent, pin ) )
{
// Create a net label to force the net name on the pin
SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) );
netLabel->SetText( extractNetName( pin->GetName() ) );
netLabel->SetTextSize( wxSize( Mils2iu( 40 ), Mils2iu( 40 ) ) );
netLabel->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
aScreen->Append( netLabel );
}
}
else if( !pinInUnit && aUpdateSet )
else if( aUpdateSet )
{
// Found a pin creating implicit connection information in another unit.
// Such units will be instantiated if they do not appear in another sheet and
@ -2574,22 +2677,34 @@ void SCH_EAGLE_PLUGIN::addImplicitConnections(
}
}
if( aUpdateSet )
if( aUpdateSet && aComponent->GetPartRef()->GetUnitCount() > 1 )
{
auto cmpIt = m_missingCmps.find( reference );
// Set the flag indicating this unit has been processed
if( cmpIt != m_missingCmps.end() )
// The first unit found has always already been processed.
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;
}
// Save the units that need later processing
else if( !missingUnits.empty() )
if( !missingUnits.empty() ) // Save the units that need later processing
{
EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
entry.cmp = aComponent;
// Add units that haven't already been processed.
for( int i : missingUnits )
entry.units.emplace( i, true );
{
if( entry.units.find( i ) != entry.units.end() )
entry.units.emplace( i, true );
}
}
}
}

View File

@ -127,6 +127,7 @@ private:
SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName );
SCH_JUNCTION* loadJunction( wxXmlNode* aJunction );
SCH_TEXT* loadPlainText( wxXmlNode* aSchText );
void loadFrame( wxXmlNode* aFrameNode, std::vector<SCH_LINE*>& aLines );
bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_PART>& aPart,
EDEVICE* aDevice, int aGateNumber, const wxString& aGateName );
@ -142,6 +143,7 @@ private:
int aGateNumber );
LIB_TEXT* loadSymbolText( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aLibText,
int aGateNumber );
void loadFrame( wxXmlNode* aFrameNode, std::vector<LIB_ITEM*>& aLines );
void loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) 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 );
bool netHasPowerDriver( SCH_LINE* aLine, const wxString& aNetName ) const;
/**
* Fix invalid characters in Eagle symbol names.
*
@ -244,6 +248,9 @@ private:
///< Segments representing wires for intersection checking
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
std::map<wxPoint, std::set<const EDA_ITEM*>> m_connPoints;
};