KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_issue22620_group_annotation.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
36
37#include <boost/test/unit_test.hpp>
38
39#include <lib_symbol.h>
40#include <refdes_tracker.h>
41#include <sch_group.h>
42#include <sch_reference_list.h>
43#include <sch_screen.h>
44#include <sch_sheet_path.h>
45#include <sch_symbol.h>
46#include <schematic.h>
48#include <tools/sch_selection.h>
49
51
52#include <wx/filename.h>
53#include <wx/stdpaths.h>
54
55
57{
60 {
61 wxString tempDir = wxStandardPaths::Get().GetTempDir();
62 wxString projectPath = tempDir + wxFileName::GetPathSeparator()
63 + wxT( "test_group_annotation.kicad_pro" );
64 m_tempFiles.push_back( projectPath );
65
66 m_settingsManager.LoadProject( projectPath.ToStdString() );
67 m_schematic = std::make_unique<SCHEMATIC>( nullptr );
69 m_schematic->SetProject( m_project );
70 }
71
73 {
74 for( const wxString& file : m_tempFiles )
75 {
76 if( wxFileExists( file ) )
77 wxRemoveFile( file );
78 }
79
80 m_schematic.reset();
81 }
82
84 std::unique_ptr<SCHEMATIC> m_schematic;
86 std::vector<wxString> m_tempFiles;
87};
88
89
90std::unordered_set<SCH_SYMBOL*> getInferredSymbols( const SCH_SELECTION& aSelection );
91
92
93BOOST_FIXTURE_TEST_SUITE( Issue22620GroupAnnotation, GROUP_ANNOTATION_FIXTURE )
94
95
96
100BOOST_AUTO_TEST_CASE( TestGroupRunOnChildrenFindsSymbols )
101{
102 m_schematic->CreateDefaultScreens();
103
104 std::vector<SCH_SHEET*> topSheets = m_schematic->GetTopLevelSheets();
105 BOOST_REQUIRE( !topSheets.empty() );
106
107 SCH_SCREEN* screen = topSheets[0]->GetScreen();
108 BOOST_REQUIRE( screen != nullptr );
109
110 // Create two simple symbols
111 SCH_SYMBOL* symbol1 = new SCH_SYMBOL();
112 symbol1->SetPosition( VECTOR2I( 0, 0 ) );
113 screen->Append( symbol1 );
114
115 SCH_SYMBOL* symbol2 = new SCH_SYMBOL();
116 symbol2->SetPosition( VECTOR2I( 1000000, 0 ) );
117 screen->Append( symbol2 );
118
119 // Create a group containing both symbols
120 SCH_GROUP* group = new SCH_GROUP( screen );
121 group->SetName( wxT( "DesignBlock" ) );
122 group->AddItem( symbol1 );
123 group->AddItem( symbol2 );
124 screen->Append( group );
125
126 // Use RunOnChildren to find symbols in the group
127 std::unordered_set<SCH_SYMBOL*> foundSymbols;
128
129 group->RunOnChildren(
130 [&foundSymbols]( SCH_ITEM* aChild )
131 {
132 if( aChild->Type() == SCH_SYMBOL_T )
133 foundSymbols.insert( static_cast<SCH_SYMBOL*>( aChild ) );
134 },
136
137 // Verify both symbols were found
138 BOOST_CHECK_EQUAL( foundSymbols.size(), 2 );
139 BOOST_CHECK( foundSymbols.count( symbol1 ) == 1 );
140 BOOST_CHECK( foundSymbols.count( symbol2 ) == 1 );
141
142 BOOST_TEST_MESSAGE( "Test passed: RunOnChildren correctly finds symbols in groups" );
143}
144
145
149BOOST_AUTO_TEST_CASE( TestGroupRunOnChildrenWithNestedGroups )
150{
151 m_schematic->CreateDefaultScreens();
152
153 std::vector<SCH_SHEET*> topSheets = m_schematic->GetTopLevelSheets();
154 BOOST_REQUIRE( !topSheets.empty() );
155
156 SCH_SCREEN* screen = topSheets[0]->GetScreen();
157 BOOST_REQUIRE( screen != nullptr );
158
159 // Create symbols
160 SCH_SYMBOL* symbol1 = new SCH_SYMBOL();
161 symbol1->SetPosition( VECTOR2I( 0, 0 ) );
162 screen->Append( symbol1 );
163
164 SCH_SYMBOL* symbol2 = new SCH_SYMBOL();
165 symbol2->SetPosition( VECTOR2I( 1000000, 0 ) );
166 screen->Append( symbol2 );
167
168 SCH_SYMBOL* symbol3 = new SCH_SYMBOL();
169 symbol3->SetPosition( VECTOR2I( 2000000, 0 ) );
170 screen->Append( symbol3 );
171
172 // Create an inner group with symbol1
173 SCH_GROUP* innerGroup = new SCH_GROUP( screen );
174 innerGroup->SetName( wxT( "InnerGroup" ) );
175 innerGroup->AddItem( symbol1 );
176 screen->Append( innerGroup );
177
178 // Create an outer group containing the inner group and symbol2
179 SCH_GROUP* outerGroup = new SCH_GROUP( screen );
180 outerGroup->SetName( wxT( "OuterGroup" ) );
181 outerGroup->AddItem( innerGroup );
182 outerGroup->AddItem( symbol2 );
183 screen->Append( outerGroup );
184
185 // Use RunOnChildren with RECURSE to find all symbols in nested groups
186 std::unordered_set<SCH_SYMBOL*> foundSymbols;
187
188 outerGroup->RunOnChildren(
189 [&foundSymbols]( SCH_ITEM* aChild )
190 {
191 if( aChild->Type() == SCH_SYMBOL_T )
192 foundSymbols.insert( static_cast<SCH_SYMBOL*>( aChild ) );
193 },
195
196 // Verify both symbol1 (in nested group) and symbol2 were found
197 BOOST_CHECK_EQUAL( foundSymbols.size(), 2 );
198 BOOST_CHECK( foundSymbols.count( symbol1 ) == 1 );
199 BOOST_CHECK( foundSymbols.count( symbol2 ) == 1 );
200 BOOST_CHECK( foundSymbols.count( symbol3 ) == 0 ); // symbol3 is not in any group
201
202 BOOST_TEST_MESSAGE( "Test passed: RunOnChildren correctly handles nested groups" );
203}
204
205
219BOOST_AUTO_TEST_CASE( Issue23519_GroupSelectionReannotatesPowerSymbols )
220{
221 m_schematic->CreateDefaultScreens();
222 m_schematic->Settings().m_refDesTracker = std::make_shared<REFDES_TRACKER>( false );
223
224 std::vector<SCH_SHEET*> topSheets = m_schematic->GetTopLevelSheets();
225 BOOST_REQUIRE( !topSheets.empty() );
226
227 SCH_SHEET* rootSheet = topSheets[0];
228 SCH_SCREEN* screen = rootSheet->GetScreen();
229 BOOST_REQUIRE( screen != nullptr );
230
231 SCH_SHEET_PATH sheetPath;
232 sheetPath.push_back( rootSheet );
233
234 LIB_SYMBOL powerLib( wxT( "PWR" ), nullptr );
235 powerLib.SetGlobalPower();
236
237 SCH_SYMBOL* existingPowerSymbol =
238 new SCH_SYMBOL( powerLib, powerLib.GetLibId(), &sheetPath, 0, 0, VECTOR2I( -1000000, 0 ) );
239 existingPowerSymbol->SetRef( &sheetPath, wxT( "#PWR01" ) );
240 existingPowerSymbol->SetValueFieldText( wxT( "+3V3" ), &sheetPath );
241 screen->Append( existingPowerSymbol );
242
243 LIB_SYMBOL normalLib( wxT( "R" ), nullptr );
244 SCH_SYMBOL* normalSymbol = new SCH_SYMBOL( normalLib, normalLib.GetLibId(), &sheetPath, 0, 0, VECTOR2I( 0, 0 ) );
245 normalSymbol->SetRef( &sheetPath, wxT( "R123" ) );
246 normalSymbol->SetValueFieldText( wxT( "10k" ), &sheetPath );
247 screen->Append( normalSymbol );
248
249 SCH_SYMBOL* powerSymbol = new SCH_SYMBOL( powerLib, powerLib.GetLibId(), &sheetPath, 0, 0, VECTOR2I( 1000000, 0 ) );
250 powerSymbol->SetRef( &sheetPath, wxT( "#PWR01" ) );
251 powerSymbol->SetValueFieldText( wxT( "+5V" ), &sheetPath );
252 screen->Append( powerSymbol );
253
254 SCH_GROUP* group = new SCH_GROUP( screen );
255 group->SetName( wxT( "DesignBlock" ) );
256 group->AddItem( normalSymbol );
257 group->AddItem( powerSymbol );
258 screen->Append( group );
259
260 SCH_SELECTION selection( screen );
261 selection.Add( group );
262
263 std::unordered_set<SCH_SYMBOL*> selectedSymbols = getInferredSymbols( selection );
264
265 BOOST_REQUIRE_EQUAL( selectedSymbols.size(), 2 );
266
267 SCH_REFERENCE_LIST references;
268 SCH_REFERENCE_LIST allReferences;
269 SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
270
271 // Mirror the design-block placement flow when normal symbol annotation is skipped:
272 // only the power-only selection pass runs.
273 for( SCH_SYMBOL* symbol : selectedSymbols )
274 sheetPath.AppendSymbol( references, symbol, SYMBOL_FILTER_POWER, true );
275
276 SCH_REFERENCE_LIST additionalRefs;
277
278 sheetPath.GetSymbols( allReferences, SYMBOL_FILTER_ALL );
279
280 for( unsigned i = 0; i < allReferences.GetCount(); ++i )
281 {
282 if( !references.Contains( allReferences[i] ) )
283 additionalRefs.AddItem( allReferences[i] );
284 }
285
286 references.RemoveAnnotation();
287 references.SetRefDesTracker( m_schematic->Settings().m_refDesTracker );
288 references.SplitReferences();
289 references.Annotate( false, 0, 0, lockedSymbols, additionalRefs );
290 references.UpdateAnnotation();
291
292 BOOST_CHECK_EQUAL( references.GetCount(), 1u );
293 BOOST_CHECK_EQUAL( normalSymbol->GetRef( &sheetPath ), wxT( "R123" ) );
294 BOOST_CHECK_EQUAL( existingPowerSymbol->GetRef( &sheetPath ), wxT( "#PWR01" ) );
295 BOOST_CHECK_EQUAL( powerSymbol->GetRef( &sheetPath ), wxT( "#PWR02" ) );
296}
297
298
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition eda_group.cpp:27
void SetName(const wxString &aName)
Definition eda_group.h:52
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
Define a library symbol object.
Definition lib_symbol.h:83
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:152
void SetGlobalPower()
Container for project specific data.
Definition project.h:66
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:52
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
bool Contains(const SCH_REFERENCE &aItem) const
Return true if aItem exists in this list.
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, const SCH_MULTI_UNIT_REFERENCE_MAP &aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent=false)
Set the reference designators in the list that have not been annotated.
void SetRefDesTracker(std::shared_ptr< REFDES_TRACKER > aTracker)
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
void RemoveAnnotation()
Treat all symbols in this list as non-annotated.
void AddItem(const SCH_REFERENCE &aItem)
void UpdateAnnotation()
Update the symbol references for the schematic project (or the current sheet).
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void AppendSymbol(SCH_REFERENCE_LIST &aReferences, SCH_SYMBOL *aSymbol, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Append a SCH_REFERENCE object to aReferences based on aSymbol.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Adds SCH_REFERENCE object to aReferences for each symbol in the sheet.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:143
Schematic symbol object.
Definition sch_symbol.h:76
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_symbol.h:872
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
virtual void Add(EDA_ITEM *aItem)
Definition selection.cpp:42
@ RECURSE
Definition eda_item.h:53
Class to handle a set of SCH_ITEMs.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
@ SYMBOL_FILTER_ALL
@ SYMBOL_FILTER_POWER
std::unique_ptr< SCHEMATIC > m_schematic
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(TestGroupRunOnChildrenFindsSymbols)
Test that SCH_GROUP::RunOnChildren correctly finds symbols inside a group.
std::unordered_set< SCH_SYMBOL * > getInferredSymbols(const SCH_SELECTION &aSelection)
Definition annotate.cpp:183
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:173
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687