KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_erc_off_grid.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 3
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, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <advanced_config.h>
24#include <erc/erc.h>
25#include <erc/erc_exclusion.h>
26#include <locale_io.h>
27#include <sch_bus_entry.h>
28#include <sch_line.h>
29#include <sch_marker.h>
30#include <schematic.h>
32#include <scoped_set_reset.h>
33#include <set>
34
35
36BOOST_AUTO_TEST_CASE( ERCOffGridLinesAndEntriesKeepCapturedEndpoints )
37{
38 LOCALE_IO locale;
39 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
40 SCOPED_SET_RESET restore( enabled, enabled );
41
42 for( bool backend : { false, true } )
43 {
44 BOOST_TEST_CONTEXT( "new engine=" << backend )
45 {
46 enabled = backend;
47 SETTINGS_MANAGER settings;
48 std::unique_ptr<SCHEMATIC> schematic;
49 KI_TEST::LoadSchematic( settings, "unconnected_bus_entry_qa", schematic );
50 SCH_SCREEN* screen = schematic->Hierarchy().front().LastScreen();
51 const int grid = schematic->Settings().m_ConnectionGridSize;
52 BOOST_REQUIRE_GT( grid, 1 );
53 const auto onGrid = [grid]( const VECTOR2I& point )
54 {
55 return point.x % grid == 0 && point.y % grid == 0;
56 };
57 SCH_LINE* wire = nullptr;
58 SCH_BUS_WIRE_ENTRY* entry = nullptr;
59
60 for( SCH_ITEM* item : screen->Items() )
61 {
62 if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
63 {
64 auto* candidate = static_cast<SCH_LINE*>( item );
65
66 if( onGrid( candidate->GetStartPoint() ) && onGrid( candidate->GetEndPoint() ) )
67 wire = candidate;
68 }
69 else if( item->Type() == SCH_BUS_WIRE_ENTRY_T )
70 {
71 auto* candidate = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
72
73 if( onGrid( candidate->GetPosition() ) && onGrid( candidate->GetEnd() ) )
74 entry = candidate;
75 }
76 }
77
78 BOOST_REQUIRE( wire );
79 BOOST_REQUIRE( entry );
80 const VECTOR2I start = wire->GetStartPoint();
81 const VECTOR2I end = wire->GetEndPoint();
82 const VECTOR2I entryStart = entry->GetPosition();
83 const VECTOR2I entryEnd = entry->GetEnd();
84 const VECTOR2I offset( 1, 1 );
85 using POSITIONS = std::multiset<std::pair<int, int>>;
86 const auto position = []( const VECTOR2I& point ) { return std::pair{ point.x, point.y }; };
87 ERC_TESTER tester( schematic.get() );
88 const auto check = [&]( const POSITIONS& wirePositions, const POSITIONS& entryPositions )
89 {
90 tester.TestOffGridEndpoints();
91 POSITIONS actualWire;
92 POSITIONS actualEntry;
93 std::vector<SCH_ITEM*> markers;
94
95 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
96 {
97 auto* marker = static_cast<SCH_MARKER*>( item );
98 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
99
100 if( error->GetErrorCode() != ERCE_ENDPOINT_OFF_GRID )
101 continue;
102
103 const KIID& id = error->GetMainItemID();
104
105 if( id == wire->m_Uuid || id == entry->m_Uuid )
106 {
107 ( id == wire->m_Uuid ? actualWire : actualEntry ).insert( position( marker->GetPosition() ) );
108 }
109
110 markers.push_back( marker );
111 }
112
113 BOOST_CHECK( actualWire == wirePositions );
114 BOOST_CHECK( actualEntry == entryPositions );
115
116 for( SCH_ITEM* marker : markers )
117 screen->DeleteItem( marker );
118 };
119
120 for( bool startOffGrid : { true, false } )
121 {
122 wire->SetStartPoint( start + ( startOffGrid ? offset : VECTOR2I() ) );
123 wire->SetEndPoint( end + offset );
124 entry->SetPosition( entryStart + offset );
125 screen->Update( wire, false );
126 screen->Update( entry, false );
127 schematic->RebuildConnectivity();
128 const POSITIONS wirePositions{ position( ( startOffGrid ? start : end ) + offset ) };
129 const POSITIONS entryPositions{ position( entryStart + offset ), position( entryEnd + offset ) };
130 check( wirePositions, entryPositions );
131 wire->SetStartPoint( start );
132 wire->SetEndPoint( end );
133 entry->SetPosition( entryStart );
134 screen->Update( wire, false );
135 screen->Update( entry, false );
136 schematic->RebuildConnectivity();
137 check( {}, {} );
138 }
139 }
140 }
141}
142
143
144BOOST_AUTO_TEST_CASE( ERCOffGridExclusionsSurviveEngineChange )
145{
146 LOCALE_IO locale;
147 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
148 SCOPED_SET_RESET restore( enabled, false );
149 SETTINGS_MANAGER settings;
150 std::unique_ptr<SCHEMATIC> schematic;
151 KI_TEST::LoadSchematic( settings, "legacy_hierarchy/legacy_hierarchy", schematic );
152 std::vector<SCH_SHEET_PATH> paths;
153
154 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
155 {
156 if( path.LastScreen()->GetFileName().EndsWith( "ampli_ht.kicad_sch" ) )
157 paths.push_back( path );
158 }
159
160 BOOST_REQUIRE_EQUAL( paths.size(), 2 );
161 SCH_SCREEN* screen = paths[0].LastScreen();
162 BOOST_REQUIRE( screen == paths[1].LastScreen() );
163 SCH_LINE* wire = nullptr;
164
165 for( SCH_ITEM* item : screen->Items().OfType( SCH_LINE_T ) )
166 {
167 if( item->IsConnectable() )
168 {
169 wire = static_cast<SCH_LINE*>( item );
170 break;
171 }
172 }
173
174 BOOST_REQUIRE( wire );
175 const int grid = schematic->Settings().m_ConnectionGridSize;
176 BOOST_REQUIRE_GT( grid, 1 );
177 VECTOR2I start = wire->GetStartPoint();
178 start.x += start.x % grid == 0 ? 1 : 0;
179 wire->SetStartPoint( start );
180 screen->Update( wire, false );
181 schematic->RebuildConnectivity();
182 ERC_TESTER tester( schematic.get() );
183 const auto markers = [&]()
184 {
185 std::vector<SCH_MARKER*> result;
186
187 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
188 {
189 auto* marker = static_cast<SCH_MARKER*>( item );
190 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
191
192 if( error->GetErrorCode() == ERCE_ENDPOINT_OFF_GRID && error->GetMainItemID() == wire->m_Uuid )
193 result.push_back( marker );
194 }
195
196 return result;
197 };
198 tester.TestOffGridEndpoints();
199 BOOST_REQUIRE_EQUAL( markers().size(), 1 );
200 auto exclusion = ERC_EXCLUSION::FromMarker( *markers().front() );
201 exclusion.SetComment( "Saved by legacy" );
202 schematic->ErcSettings().m_ErcExclusions.insert( exclusion );
203
204 for( SCH_MARKER* marker : markers() )
205 screen->DeleteItem( marker );
206
207 enabled = true;
208 schematic->RebuildConnectivity();
209 tester.TestOffGridEndpoints();
210 schematic->ResolveERCExclusionsPostUpdate();
211 BOOST_CHECK_EQUAL( markers().size(), 1 );
212
213 for( SCH_MARKER* marker : markers() )
214 {
215 BOOST_CHECK( marker->IsExcluded() );
216 BOOST_CHECK_EQUAL( marker->GetComment(), wxString( "Saved by legacy" ) );
217 }
218}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
const KIID m_Uuid
Definition eda_item.h:597
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
static ERC_EXCLUSION FromMarker(const SCH_MARKER &aMarker)
Runs the electrical rules checks and adds a SCH_MARKER for each violation.
Definition erc.h:60
int TestOffGridEndpoints()
Test pins and wire ends for being off grid.
Definition erc.cpp:2981
Definition kiid.h:46
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
VECTOR2I GetPosition() const override
void SetPosition(const VECTOR2I &aPosition) override
VECTOR2I GetEnd() const
Class for a wire to bus entry.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
void SetStartPoint(const VECTOR2I &aPosition)
Definition sch_line.h:137
VECTOR2I GetEndPoint() const
Definition sch_line.h:145
VECTOR2I GetStartPoint() const
Definition sch_line.h:136
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:146
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Refresh a changed item in the tree and invalidate connectivity.
void DeleteItem(SCH_ITEM *aItem)
Remove aItem from the linked list and deletes the object.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
RAII class that sets an value at construction and resets it to the original value at destruction.
@ ERCE_ENDPOINT_OFF_GRID
Pin or wire-end off grid.
@ LAYER_WIRE
Definition layer_ids.h:474
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
BOOST_AUTO_TEST_CASE(ERCOffGridLinesAndEntriesKeepCapturedEndpoints)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
std::string path
VECTOR2I end
BOOST_TEST_CONTEXT("Test Clearance")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_MARKER_T
Definition typeinfo.h:154
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:157
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683