KiCad PCB EDA Suite
Loading...
Searching...
No Matches
variant_symbol_utils.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <lib_symbol.h>
27#include <span>
28#include <pin_type.h>
29#include <sch_pin.h>
30
31#include <algorithm>
32
33
34bool VariantSymbolPinsMatch( const SCH_PIN& aBase, const SCH_PIN& aCandidate )
35{
36 return aBase.GetNumber() == aCandidate.GetNumber()
37 && aBase.GetUnit() == aCandidate.GetUnit()
38 && aBase.GetBodyStyle() == aCandidate.GetBodyStyle()
39 && aBase.GetPosition() == aCandidate.GetPosition();
40}
41
42
43static std::vector<VARIANT_COMPAT_RESULT> validateCompatibility(
44 int aBaseUnits, int aBaseBodyStyles, std::span<const PIN_COMPARISON_DATA> basePins,
45 int aCandidateUnits, int aCandidateBodyStyles, std::span<const PIN_COMPARISON_DATA> candidatePins )
46{
47 std::vector<VARIANT_COMPAT_RESULT> results;
48
49 int baseUnits = std::max( aBaseUnits, 1 );
50 int candUnits = std::max( aCandidateUnits, 1 );
51
52 if( candUnits < baseUnits )
53 {
56 result.detail = wxString::Format( _( "Candidate has %d unit(s), base requires %d" ),
57 candUnits, baseUnits );
58 results.push_back( result );
59 }
60
61 int baseBodyStyles = aBaseBodyStyles;
62
63 if( baseBodyStyles > 1 && aCandidateBodyStyles < baseBodyStyles )
64 {
67 result.detail = wxString::Format( _( "Candidate has %d body style(s), base requires %d" ),
68 aCandidateBodyStyles, baseBodyStyles );
69 results.push_back( result );
70 }
71
72 // Library pins without a concrete type resolve to unspecified, as with SCH_PIN::GetType().
73 const auto type = []( const PIN_COMPARISON_DATA& pin )
74 {
76 };
77
78 std::vector<bool> matched( candidatePins.size(), false );
79
80 for( const PIN_COMPARISON_DATA& basePin : basePins )
81 {
82 auto sameSlot = [&]( const PIN_COMPARISON_DATA& aCandidatePin )
83 {
84 return basePin.number == aCandidatePin.number
85 && basePin.unit == aCandidatePin.unit
86 && basePin.bodyStyle == aCandidatePin.bodyStyle;
87 };
88
89 auto findCandidate = [&]( bool aRequirePosition, bool aRequireType )
90 {
91 for( size_t i = 0; i < candidatePins.size(); ++i )
92 {
93 if( matched[i] || !sameSlot( candidatePins[i] ) )
94 continue;
95
96 if( aRequirePosition && candidatePins[i].position != basePin.position )
97 continue;
98
99 if( aRequireType && type( candidatePins[i] ) != type( basePin ) )
100 continue;
101
102 return i;
103 }
104
105 return candidatePins.size();
106 };
107
108 size_t candidateIndex = findCandidate( true, true );
109
110 if( candidateIndex == candidatePins.size() )
111 candidateIndex = findCandidate( true, false );
112
113 if( candidateIndex == candidatePins.size() )
114 candidateIndex = findCandidate( false, false );
115
116 if( candidateIndex == candidatePins.size() )
117 {
120 result.pinNumber = basePin.number;
121 result.unit = basePin.unit;
122 result.bodyStyle = basePin.bodyStyle;
123 result.detail = wxString::Format(
124 _( "Unit %d, body style %d: pin '%s' not found in candidate" ),
125 result.unit, result.bodyStyle, result.pinNumber );
126 results.push_back( result );
127 continue;
128 }
129
130 matched[candidateIndex] = true;
131 const auto& candidatePin = candidatePins[candidateIndex];
132
133 if( candidatePin.position != basePin.position )
134 {
137 result.pinNumber = basePin.number;
138 result.unit = basePin.unit;
139 result.bodyStyle = basePin.bodyStyle;
140 result.detail = wxString::Format(
141 _( "Unit %d, body style %d: pin '%s' position mismatch "
142 "(%d,%d) vs (%d,%d)" ),
143 result.unit, result.bodyStyle, result.pinNumber,
144 basePin.position.x, basePin.position.y,
145 candidatePin.position.x, candidatePin.position.y );
146 results.push_back( result );
147 }
148
149 if( type( candidatePin ) != type( basePin ) )
150 {
153 result.pinNumber = basePin.number;
154 result.unit = basePin.unit;
155 result.bodyStyle = basePin.bodyStyle;
156 result.detail = wxString::Format(
157 _( "Unit %d, body style %d: pin '%s' type mismatch ('%s' vs '%s')" ),
158 result.unit, result.bodyStyle, result.pinNumber,
159 GetCanonicalElectricalTypeName( type( basePin ) ),
160 GetCanonicalElectricalTypeName( type( candidatePin ) ) );
161 results.push_back( result );
162 }
163 }
164
165 for( size_t i = 0; i < candidatePins.size(); ++i )
166 {
167 if( !matched[i] )
168 {
169 const auto& candidatePin = candidatePins[i];
172 result.pinNumber = candidatePin.number;
173 result.unit = candidatePin.unit;
174 result.bodyStyle = candidatePin.bodyStyle;
175 result.detail = wxString::Format(
176 _( "Unit %d, body style %d: candidate has extra pin '%s'" ),
177 result.unit, result.bodyStyle, result.pinNumber );
178 results.push_back( result );
179 }
180 }
181
182 return results;
183}
184
185
186static std::vector<PIN_COMPARISON_DATA> variantPins( const LIB_SYMBOL& aSymbol )
187{
188 std::vector<PIN_COMPARISON_DATA> result;
189
190 for( const SCH_PIN* pin : aSymbol.GetGraphicalPins() )
191 result.push_back( pin->ComparisonData() );
192
193 return result;
194}
195
196
197std::vector<VARIANT_COMPAT_RESULT> ValidateVariantSymbolCompatibility( const LIB_SYMBOL& aBase,
198 const LIB_SYMBOL& aCandidate )
199{
200 return validateCompatibility( aBase.GetUnitCount(), aBase.GetBodyStyleCount(), variantPins( aBase ),
201 aCandidate.GetUnitCount(), aCandidate.GetBodyStyleCount(), variantPins( aCandidate ) );
202}
Define a library symbol object.
Definition lib_symbol.h:119
std::vector< const SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
int GetBodyStyleCount() const override
The body styles are a property of the drawings, which a derived symbol inherits from its root symbol ...
int GetUnitCount() const override
int GetBodyStyle() const
Definition sch_item.h:247
int GetUnit() const
Definition sch_item.h:237
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:354
const wxString & GetNumber() const
Definition sch_pin.h:142
#define _(s)
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:41
wxString GetCanonicalElectricalTypeName(ELECTRICAL_PINTYPE aType)
Definition pin_type.h:54
Owned library-pin inputs; no parent, layout cache or schematic pointers.
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.
std::vector< VARIANT_COMPAT_RESULT > ValidateVariantSymbolCompatibility(const LIB_SYMBOL &aBase, const LIB_SYMBOL &aCandidate)
Check whether aCandidate can be used as a variant symbol override for aBase.
bool VariantSymbolPinsMatch(const SCH_PIN &aBase, const SCH_PIN &aCandidate)
Check whether two graphical pins occupy the same variant-symbol connection slot.
static std::vector< PIN_COMPARISON_DATA > variantPins(const LIB_SYMBOL &aSymbol)
static std::vector< VARIANT_COMPAT_RESULT > validateCompatibility(int aBaseUnits, int aBaseBodyStyles, std::span< const PIN_COMPARISON_DATA > basePins, int aCandidateUnits, int aCandidateBodyStyles, std::span< const PIN_COMPARISON_DATA > candidatePins)
@ PIN_POSITION_MISMATCH
A matching pin number has a different position in library coordinates.
@ PIN_TYPE_MISMATCH
A matching pin number has a different electrical type.
@ EXTRA_PIN_NUMBER
Candidate has a pin occurrence that is absent from the base.
@ MISSING_BODY_STYLE
Base uses alternate body styles but candidate does not.
@ MISSING_PIN_NUMBER
A base pin number is absent from the candidate for a given unit/body style.
@ INSUFFICIENT_UNITS
Candidate has fewer units than the base.